zou 0.19.14__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} +84 -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/flask.py +1 -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.14.dist-info → zou-0.20.11.dist-info}/METADATA +75 -69
- {zou-0.19.14.dist-info → zou-0.20.11.dist-info}/RECORD +164 -135
- {zou-0.19.14.dist-info → zou-0.20.11.dist-info}/WHEEL +1 -1
- {zou-0.19.14.dist-info → zou-0.20.11.dist-info}/LICENSE +0 -0
- {zou-0.19.14.dist-info → zou-0.20.11.dist-info}/entry_points.txt +0 -0
- {zou-0.19.14.dist-info → zou-0.20.11.dist-info}/top_level.txt +0 -0
|
@@ -2,7 +2,7 @@ import datetime
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
from flask import abort, request
|
|
5
|
-
from flask_restful import Resource
|
|
5
|
+
from flask_restful import Resource, inputs
|
|
6
6
|
from flask_jwt_extended import jwt_required
|
|
7
7
|
|
|
8
8
|
from zou.app.services.exception import (
|
|
@@ -28,7 +28,7 @@ from zou.app.services import (
|
|
|
28
28
|
user_service,
|
|
29
29
|
concepts_service,
|
|
30
30
|
)
|
|
31
|
-
from zou.app.utils import events, query, permissions
|
|
31
|
+
from zou.app.utils import events, query, permissions, date_helpers
|
|
32
32
|
from zou.app.mixin import ArgsMixin
|
|
33
33
|
|
|
34
34
|
|
|
@@ -69,13 +69,8 @@ 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
|
-
tasks_service.clear_comment_cache(comment_id)
|
|
77
|
-
comment = tasks_service.get_comment(comment_id)
|
|
78
|
-
tasks_service.get_task_status(comment["task_status_id"])
|
|
79
74
|
person = persons_service.get_current_user()
|
|
80
75
|
preview_file = tasks_service.add_preview_file_to_comment(
|
|
81
76
|
comment_id, person["id"], task_id, args["revision"]
|
|
@@ -122,9 +117,7 @@ class AddExtraPreviewResource(Resource):
|
|
|
122
117
|
201:
|
|
123
118
|
description: Preview added to given comment
|
|
124
119
|
"""
|
|
125
|
-
|
|
126
|
-
user_service.check_project_access(task["project_id"])
|
|
127
|
-
user_service.check_entity_access(task["entity_id"])
|
|
120
|
+
user_service.check_task_access(task_id)
|
|
128
121
|
tasks_service.get_comment(comment_id)
|
|
129
122
|
|
|
130
123
|
person = persons_service.get_current_user()
|
|
@@ -194,9 +187,7 @@ class TaskPreviewsResource(Resource):
|
|
|
194
187
|
200:
|
|
195
188
|
description: Previews linked to given task
|
|
196
189
|
"""
|
|
197
|
-
|
|
198
|
-
user_service.check_project_access(task["project_id"])
|
|
199
|
-
user_service.check_entity_access(task["entity_id"])
|
|
190
|
+
user_service.check_task_access(task_id)
|
|
200
191
|
return files_service.get_preview_files_for_task(task_id)
|
|
201
192
|
|
|
202
193
|
|
|
@@ -223,9 +214,7 @@ class TaskCommentsResource(Resource):
|
|
|
223
214
|
200:
|
|
224
215
|
description: Comments linked to given task
|
|
225
216
|
"""
|
|
226
|
-
|
|
227
|
-
user_service.check_project_access(task["project_id"])
|
|
228
|
-
user_service.check_entity_access(task["entity_id"])
|
|
217
|
+
user_service.check_task_access(task_id)
|
|
229
218
|
is_client = permissions.has_client_permissions()
|
|
230
219
|
is_manager = permissions.has_manager_permissions()
|
|
231
220
|
is_supervisor = permissions.has_supervisor_permissions()
|
|
@@ -756,7 +745,7 @@ class ToReviewResource(Resource, ArgsMixin):
|
|
|
756
745
|
try:
|
|
757
746
|
task = tasks_service.get_task(task_id)
|
|
758
747
|
user_service.check_project_access(task["project_id"])
|
|
759
|
-
user_service.check_entity_access(task["
|
|
748
|
+
user_service.check_entity_access(task["entity_id"])
|
|
760
749
|
|
|
761
750
|
if person_id is not None:
|
|
762
751
|
person = persons_service.get_person(person_id)
|
|
@@ -766,7 +755,7 @@ class ToReviewResource(Resource, ArgsMixin):
|
|
|
766
755
|
preview_path = self.get_preview_path(task, name, revision)
|
|
767
756
|
|
|
768
757
|
task = tasks_service.task_to_review(
|
|
769
|
-
|
|
758
|
+
task_id, person, comment, preview_path, change_status
|
|
770
759
|
)
|
|
771
760
|
except PersonNotFoundException:
|
|
772
761
|
return {"error": True, "message": "Cannot find given person."}, 400
|
|
@@ -793,7 +782,11 @@ class ToReviewResource(Resource, ArgsMixin):
|
|
|
793
782
|
("comment", ""),
|
|
794
783
|
("name", "main"),
|
|
795
784
|
{"name": "revision", "default": 1, "type": int},
|
|
796
|
-
{
|
|
785
|
+
{
|
|
786
|
+
"name": "change_status",
|
|
787
|
+
"default": True,
|
|
788
|
+
"type": inputs.boolean,
|
|
789
|
+
},
|
|
797
790
|
]
|
|
798
791
|
)
|
|
799
792
|
|
|
@@ -844,7 +837,7 @@ class ClearAssignationResource(Resource, ArgsMixin):
|
|
|
844
837
|
tasks = []
|
|
845
838
|
for task_id in task_ids:
|
|
846
839
|
try:
|
|
847
|
-
user_service.
|
|
840
|
+
user_service.check_task_department_access_for_unassign(
|
|
848
841
|
task_id, person_id
|
|
849
842
|
)
|
|
850
843
|
tasks_service.clear_assignation(task_id, person_id=person_id)
|
|
@@ -909,7 +902,6 @@ class TasksAssignResource(Resource, ArgsMixin):
|
|
|
909
902
|
200:
|
|
910
903
|
description: Given tasks lists assigned to given person
|
|
911
904
|
"""
|
|
912
|
-
user_service.check_person_is_not_bot(person_id)
|
|
913
905
|
args = self.get_args(
|
|
914
906
|
[
|
|
915
907
|
{
|
|
@@ -925,11 +917,14 @@ class TasksAssignResource(Resource, ArgsMixin):
|
|
|
925
917
|
current_user = persons_service.get_current_user()
|
|
926
918
|
for task_id in args["task_ids"]:
|
|
927
919
|
try:
|
|
928
|
-
user_service.
|
|
929
|
-
|
|
930
|
-
|
|
920
|
+
user_service.check_person_is_not_bot(person_id)
|
|
921
|
+
user_service.check_task_department_access(task_id, person_id)
|
|
922
|
+
task = tasks_service.assign_task(
|
|
931
923
|
task_id, person_id, current_user["id"]
|
|
932
924
|
)
|
|
925
|
+
notifications_service.create_assignation_notification(
|
|
926
|
+
task_id, person_id
|
|
927
|
+
)
|
|
933
928
|
tasks.append(task)
|
|
934
929
|
except TaskNotFoundException:
|
|
935
930
|
pass
|
|
@@ -942,9 +937,6 @@ class TasksAssignResource(Resource, ArgsMixin):
|
|
|
942
937
|
|
|
943
938
|
return tasks
|
|
944
939
|
|
|
945
|
-
def assign_task(self, task_id, person_id, assigner_id):
|
|
946
|
-
return tasks_service.assign_task(task_id, person_id, assigner_id)
|
|
947
|
-
|
|
948
940
|
|
|
949
941
|
class TaskAssignResource(Resource, ArgsMixin):
|
|
950
942
|
"""
|
|
@@ -993,11 +985,13 @@ class TaskAssignResource(Resource, ArgsMixin):
|
|
|
993
985
|
]
|
|
994
986
|
)
|
|
995
987
|
person_id = args["person_id"]
|
|
988
|
+
current_user = persons_service.get_current_user()
|
|
996
989
|
try:
|
|
997
990
|
user_service.check_person_is_not_bot(person_id)
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
991
|
+
user_service.check_task_department_access(task_id, person_id)
|
|
992
|
+
task = tasks_service.assign_task(
|
|
993
|
+
task_id, person_id, current_user["id"]
|
|
994
|
+
)
|
|
1001
995
|
notifications_service.create_assignation_notification(
|
|
1002
996
|
task_id, person_id
|
|
1003
997
|
)
|
|
@@ -1007,9 +1001,6 @@ class TaskAssignResource(Resource, ArgsMixin):
|
|
|
1007
1001
|
|
|
1008
1002
|
return task
|
|
1009
1003
|
|
|
1010
|
-
def assign_task(self, task_id, person_id):
|
|
1011
|
-
return tasks_service.assign_task(task_id, person_id)
|
|
1012
|
-
|
|
1013
1004
|
|
|
1014
1005
|
class TaskFullResource(Resource):
|
|
1015
1006
|
"""
|
|
@@ -1134,7 +1125,7 @@ class SetTimeSpentResource(Resource, ArgsMixin):
|
|
|
1134
1125
|
time_spent = tasks_service.create_or_update_time_spent(
|
|
1135
1126
|
task_id,
|
|
1136
1127
|
person_id,
|
|
1137
|
-
|
|
1128
|
+
date_helpers.get_date_from_string(date),
|
|
1138
1129
|
args["duration"],
|
|
1139
1130
|
)
|
|
1140
1131
|
return time_spent, 201
|
|
@@ -1275,9 +1266,7 @@ class GetTimeSpentResource(Resource):
|
|
|
1275
1266
|
404:
|
|
1276
1267
|
description: Wrong date format
|
|
1277
1268
|
"""
|
|
1278
|
-
|
|
1279
|
-
user_service.check_project_access(task["project_id"])
|
|
1280
|
-
user_service.check_entity_access(task["entity_id"])
|
|
1269
|
+
user_service.check_task_access(task_id)
|
|
1281
1270
|
return tasks_service.get_time_spents(task_id)
|
|
1282
1271
|
|
|
1283
1272
|
|
|
@@ -1313,9 +1302,7 @@ class GetTimeSpentDateResource(Resource):
|
|
|
1313
1302
|
description: Wrong date format
|
|
1314
1303
|
"""
|
|
1315
1304
|
try:
|
|
1316
|
-
|
|
1317
|
-
user_service.check_project_access(task["project_id"])
|
|
1318
|
-
user_service.check_entity_access(task["entity_id"])
|
|
1305
|
+
user_service.check_task_access(task_id)
|
|
1319
1306
|
return tasks_service.get_time_spents(task_id, date)
|
|
1320
1307
|
except WrongDateFormatException:
|
|
1321
1308
|
abort(404)
|
|
@@ -1465,7 +1452,6 @@ class ProjectTasksResource(Resource, ArgsMixin):
|
|
|
1465
1452
|
"""
|
|
1466
1453
|
|
|
1467
1454
|
@jwt_required()
|
|
1468
|
-
@permissions.require_admin
|
|
1469
1455
|
def get(self, project_id):
|
|
1470
1456
|
"""
|
|
1471
1457
|
Retrieve all tasks related to given project.
|
|
@@ -1480,13 +1466,34 @@ class ProjectTasksResource(Resource, ArgsMixin):
|
|
|
1480
1466
|
type: string
|
|
1481
1467
|
format: UUID
|
|
1482
1468
|
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1469
|
+
- in: query
|
|
1470
|
+
name: page
|
|
1471
|
+
required: False
|
|
1472
|
+
type: integer
|
|
1473
|
+
x-example: 1
|
|
1474
|
+
- in: query
|
|
1475
|
+
name: task_type_id
|
|
1476
|
+
required: False
|
|
1477
|
+
type: string
|
|
1478
|
+
format: UUID
|
|
1479
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1480
|
+
- in: query
|
|
1481
|
+
name: episode_id
|
|
1482
|
+
required: False
|
|
1483
|
+
type: string
|
|
1484
|
+
format: UUID
|
|
1485
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1483
1486
|
responses:
|
|
1484
1487
|
200:
|
|
1485
1488
|
description: All tasks related to given project
|
|
1486
1489
|
"""
|
|
1487
1490
|
projects_service.get_project(project_id)
|
|
1488
1491
|
page = self.get_page()
|
|
1489
|
-
|
|
1492
|
+
task_type_id = self.get_task_type_id()
|
|
1493
|
+
episode_id = self.get_episode_id()
|
|
1494
|
+
return tasks_service.get_tasks_for_project(
|
|
1495
|
+
project_id, page, task_type_id=task_type_id, episode_id=episode_id
|
|
1496
|
+
)
|
|
1490
1497
|
|
|
1491
1498
|
|
|
1492
1499
|
class ProjectCommentsResource(Resource, ArgsMixin):
|
|
@@ -1496,7 +1503,6 @@ class ProjectCommentsResource(Resource, ArgsMixin):
|
|
|
1496
1503
|
"""
|
|
1497
1504
|
|
|
1498
1505
|
@jwt_required()
|
|
1499
|
-
@permissions.require_admin
|
|
1500
1506
|
def get(self, project_id):
|
|
1501
1507
|
"""
|
|
1502
1508
|
Retrieve all comments to tasks related to given project.
|
|
@@ -1511,13 +1517,25 @@ class ProjectCommentsResource(Resource, ArgsMixin):
|
|
|
1511
1517
|
type: string
|
|
1512
1518
|
format: UUID
|
|
1513
1519
|
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1520
|
+
- in: query
|
|
1521
|
+
name: limit
|
|
1522
|
+
type: integer
|
|
1523
|
+
default: 100
|
|
1524
|
+
x-example: 100
|
|
1514
1525
|
responses:
|
|
1515
1526
|
200:
|
|
1516
1527
|
description: All comments to tasks related to given project
|
|
1517
1528
|
"""
|
|
1518
1529
|
projects_service.get_project(project_id)
|
|
1530
|
+
user_service.check_project_access(project_id)
|
|
1531
|
+
if (
|
|
1532
|
+
permissions.has_vendor_permissions()
|
|
1533
|
+
or permissions.has_client_permissions()
|
|
1534
|
+
):
|
|
1535
|
+
raise permissions.PermissionDenied
|
|
1519
1536
|
page = self.get_page()
|
|
1520
|
-
|
|
1537
|
+
limit = self.get_limit()
|
|
1538
|
+
return tasks_service.get_comments_for_project(project_id, page, limit)
|
|
1521
1539
|
|
|
1522
1540
|
|
|
1523
1541
|
class ProjectPreviewFilesResource(Resource, ArgsMixin):
|
|
@@ -1576,16 +1594,10 @@ class SetTaskMainPreviewResource(Resource):
|
|
|
1576
1594
|
preview_file = preview_files_service.get_last_preview_file_for_task(
|
|
1577
1595
|
task_id
|
|
1578
1596
|
)
|
|
1579
|
-
entity = entities_service.get_entity(task["entity_id"])
|
|
1580
1597
|
if preview_file is not None:
|
|
1581
|
-
entities_service.update_entity_preview(
|
|
1598
|
+
entity = entities_service.update_entity_preview(
|
|
1582
1599
|
task["entity_id"], preview_file["id"]
|
|
1583
1600
|
)
|
|
1584
|
-
assets_service.clear_asset_cache(entity["id"])
|
|
1585
|
-
shots_service.clear_shot_cache(entity["id"])
|
|
1586
|
-
edits_service.clear_edit_cache(entity["id"])
|
|
1587
|
-
shots_service.clear_episode_cache(entity["id"])
|
|
1588
|
-
shots_service.clear_sequence_cache(entity["id"])
|
|
1589
1601
|
return entity
|
|
1590
1602
|
|
|
1591
1603
|
|
|
@@ -1739,3 +1751,22 @@ class OpenTasksResource(Resource, ArgsMixin):
|
|
|
1739
1751
|
page=args["page"],
|
|
1740
1752
|
limit=args["limit"],
|
|
1741
1753
|
)
|
|
1754
|
+
|
|
1755
|
+
|
|
1756
|
+
class OpenTasksStatsResource(Resource, ArgsMixin):
|
|
1757
|
+
|
|
1758
|
+
@jwt_required()
|
|
1759
|
+
def get(self):
|
|
1760
|
+
"""
|
|
1761
|
+
Return task amount, task done amount, total estimation, total duration
|
|
1762
|
+
by status by task type by project for open projects. It aggregates the
|
|
1763
|
+
result at the project level.
|
|
1764
|
+
---
|
|
1765
|
+
tags:
|
|
1766
|
+
- Tasks
|
|
1767
|
+
responses:
|
|
1768
|
+
200:
|
|
1769
|
+
description: A dict organized by project that contains
|
|
1770
|
+
the results for each task type and status pairs.
|
|
1771
|
+
"""
|
|
1772
|
+
return tasks_service.get_open_tasks_stats()
|
|
@@ -11,6 +11,8 @@ from zou.app.blueprints.user.resources import (
|
|
|
11
11
|
ContextResource,
|
|
12
12
|
DateTimeSpentsResource,
|
|
13
13
|
DayOffResource,
|
|
14
|
+
ChatsResource,
|
|
15
|
+
JoinChatResource,
|
|
14
16
|
OpenProjectsResource,
|
|
15
17
|
ProjectEpisodesResource,
|
|
16
18
|
ProjectSequencesResource,
|
|
@@ -31,6 +33,7 @@ from zou.app.blueprints.user.resources import (
|
|
|
31
33
|
FilterGroupResource,
|
|
32
34
|
FilterGroupsResource,
|
|
33
35
|
DesktopLoginLogsResource,
|
|
36
|
+
MarkAllNotificationsAsReadResource,
|
|
34
37
|
NotificationsResource,
|
|
35
38
|
NotificationResource,
|
|
36
39
|
HasTaskSubscribedResource,
|
|
@@ -85,6 +88,8 @@ routes = [
|
|
|
85
88
|
("/data/user/notifications", NotificationsResource),
|
|
86
89
|
("/data/user/notifications/<notification_id>", NotificationResource),
|
|
87
90
|
("/data/user/tasks/<task_id>/subscribed", HasTaskSubscribedResource),
|
|
91
|
+
("/data/user/chats", ChatsResource),
|
|
92
|
+
("/actions/user/chats/<entity_id>/join", JoinChatResource),
|
|
88
93
|
("/actions/user/tasks/<task_id>/subscribe", TaskSubscribeResource),
|
|
89
94
|
("/actions/user/tasks/<task_id>/unsubscribe", TaskUnsubscribeResource),
|
|
90
95
|
("/actions/user/clear-avatar", ClearAvatarResource),
|
|
@@ -104,6 +109,10 @@ routes = [
|
|
|
104
109
|
"/actions/user/sequences/<sequence_id>/task-types/<task_type_id>/unsubscribe",
|
|
105
110
|
SequenceUnsubscribeResource,
|
|
106
111
|
),
|
|
112
|
+
(
|
|
113
|
+
"/actions/user/notifications/mark-all-as-read",
|
|
114
|
+
MarkAllNotificationsAsReadResource,
|
|
115
|
+
),
|
|
107
116
|
]
|
|
108
117
|
|
|
109
118
|
blueprint = Blueprint("user", "user")
|
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
from flask import abort
|
|
4
|
-
from flask_restful import Resource
|
|
1
|
+
from flask import abort, request
|
|
2
|
+
from flask_restful import Resource, inputs
|
|
5
3
|
|
|
6
4
|
from zou.app.mixin import ArgsMixin
|
|
7
|
-
|
|
8
5
|
from zou.app.services import (
|
|
9
6
|
assets_service,
|
|
7
|
+
chats_service,
|
|
8
|
+
entities_service,
|
|
10
9
|
persons_service,
|
|
11
10
|
projects_service,
|
|
12
11
|
shots_service,
|
|
13
12
|
time_spents_service,
|
|
14
13
|
user_service,
|
|
15
14
|
)
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
from zou.app.utils import date_helpers
|
|
18
16
|
from zou.app.services.exception import WrongDateFormatException
|
|
19
17
|
|
|
20
18
|
|
|
@@ -544,6 +542,9 @@ class FiltersResource(Resource, ArgsMixin):
|
|
|
544
542
|
arguments["query"],
|
|
545
543
|
arguments["project_id"],
|
|
546
544
|
arguments["entity_type"],
|
|
545
|
+
arguments["is_shared"],
|
|
546
|
+
arguments["search_filter_group_id"],
|
|
547
|
+
department_id=arguments["department_id"],
|
|
547
548
|
),
|
|
548
549
|
201,
|
|
549
550
|
)
|
|
@@ -556,6 +557,9 @@ class FiltersResource(Resource, ArgsMixin):
|
|
|
556
557
|
("list_type", "todo", True),
|
|
557
558
|
("project_id", None, False),
|
|
558
559
|
("entity_type", None, False),
|
|
560
|
+
("is_shared", False, False, inputs.boolean),
|
|
561
|
+
("search_filter_group_id", None, False),
|
|
562
|
+
("department_id", None, False),
|
|
559
563
|
]
|
|
560
564
|
)
|
|
561
565
|
|
|
@@ -587,6 +591,9 @@ class FilterResource(Resource, ArgsMixin):
|
|
|
587
591
|
("name", None, False),
|
|
588
592
|
("search_query", None, False),
|
|
589
593
|
("search_filter_group_id", None, False),
|
|
594
|
+
("is_shared", None, False, inputs.boolean),
|
|
595
|
+
("project_id", None, None),
|
|
596
|
+
("department_id", None, None),
|
|
590
597
|
]
|
|
591
598
|
)
|
|
592
599
|
data = self.clear_empty_fields(
|
|
@@ -659,19 +666,27 @@ class FilterGroupsResource(Resource, ArgsMixin):
|
|
|
659
666
|
name: entity_type
|
|
660
667
|
required: False
|
|
661
668
|
type: string
|
|
669
|
+
- in: formData
|
|
670
|
+
name: is_shared
|
|
671
|
+
required: False
|
|
672
|
+
type: boolean
|
|
662
673
|
- in: formData
|
|
663
674
|
name: project_id
|
|
664
675
|
required: True
|
|
665
676
|
type: string
|
|
666
677
|
format: UUID
|
|
667
678
|
example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
679
|
+
- in: formData
|
|
680
|
+
name: department_id
|
|
681
|
+
required: False
|
|
682
|
+
format: UUID
|
|
683
|
+
example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
668
684
|
responses:
|
|
669
685
|
201:
|
|
670
686
|
description: Filter groups for the current user and only for
|
|
671
687
|
open projects created.
|
|
672
688
|
"""
|
|
673
689
|
arguments = self.get_arguments()
|
|
674
|
-
|
|
675
690
|
return (
|
|
676
691
|
user_service.create_filter_group(
|
|
677
692
|
arguments["list_type"],
|
|
@@ -679,6 +694,8 @@ class FilterGroupsResource(Resource, ArgsMixin):
|
|
|
679
694
|
arguments["color"],
|
|
680
695
|
arguments["project_id"],
|
|
681
696
|
arguments["entity_type"],
|
|
697
|
+
arguments["is_shared"],
|
|
698
|
+
arguments["department_id"],
|
|
682
699
|
),
|
|
683
700
|
201,
|
|
684
701
|
)
|
|
@@ -690,7 +707,9 @@ class FilterGroupsResource(Resource, ArgsMixin):
|
|
|
690
707
|
("color", "", True),
|
|
691
708
|
("list_type", "todo", True),
|
|
692
709
|
("project_id", None, False),
|
|
710
|
+
("is_shared", False, False, inputs.boolean),
|
|
693
711
|
("entity_type", None, False),
|
|
712
|
+
("department_id", None, False),
|
|
694
713
|
]
|
|
695
714
|
)
|
|
696
715
|
|
|
@@ -727,6 +746,28 @@ class FilterGroupResource(Resource, ArgsMixin):
|
|
|
727
746
|
type: string
|
|
728
747
|
format: UUID
|
|
729
748
|
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
749
|
+
- in: formData
|
|
750
|
+
name: name
|
|
751
|
+
type: string
|
|
752
|
+
x-example: Name of the filter group
|
|
753
|
+
- in: formData
|
|
754
|
+
name: color
|
|
755
|
+
type: string
|
|
756
|
+
x-example: Color of the filter group
|
|
757
|
+
- in: formData
|
|
758
|
+
name: is_shared
|
|
759
|
+
type: boolean
|
|
760
|
+
x-example: True
|
|
761
|
+
- in: formData
|
|
762
|
+
name: project_id
|
|
763
|
+
type: string
|
|
764
|
+
format: UUID
|
|
765
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
766
|
+
- in: formData
|
|
767
|
+
name: department_id
|
|
768
|
+
type: string
|
|
769
|
+
format: UUID
|
|
770
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
730
771
|
responses:
|
|
731
772
|
200:
|
|
732
773
|
description: Given filter group with updated data
|
|
@@ -735,8 +776,12 @@ class FilterGroupResource(Resource, ArgsMixin):
|
|
|
735
776
|
[
|
|
736
777
|
("name", None, False),
|
|
737
778
|
("color", None, False),
|
|
779
|
+
("is_shared", None, False, inputs.boolean),
|
|
780
|
+
("project_id", None, None),
|
|
781
|
+
("department_id", None, None),
|
|
738
782
|
]
|
|
739
783
|
)
|
|
784
|
+
|
|
740
785
|
data = self.clear_empty_fields(data)
|
|
741
786
|
user_filter = user_service.update_filter_group(filter_group_id, data)
|
|
742
787
|
return user_filter, 200
|
|
@@ -799,7 +844,9 @@ class DesktopLoginLogsResource(Resource, ArgsMixin):
|
|
|
799
844
|
201:
|
|
800
845
|
description: Desktop login log created
|
|
801
846
|
"""
|
|
802
|
-
arguments = self.get_args(
|
|
847
|
+
arguments = self.get_args(
|
|
848
|
+
["date", date_helpers.get_utc_now_datetime()]
|
|
849
|
+
)
|
|
803
850
|
current_user = persons_service.get_current_user()
|
|
804
851
|
desktop_login_log = persons_service.create_desktop_login_logs(
|
|
805
852
|
current_user["id"], arguments["date"]
|
|
@@ -836,13 +883,22 @@ class NotificationsResource(Resource, ArgsMixin):
|
|
|
836
883
|
task_status_id,
|
|
837
884
|
notification_type,
|
|
838
885
|
) = self.get_arguments()
|
|
886
|
+
|
|
887
|
+
read = None
|
|
888
|
+
if request.args.get("read", None) is not None:
|
|
889
|
+
read = self.get_bool_parameter("read")
|
|
890
|
+
watching = None
|
|
891
|
+
if request.args.get("watching", None) is not None:
|
|
892
|
+
watching = self.get_bool_parameter("watching")
|
|
893
|
+
print("watching", watching)
|
|
839
894
|
notifications = user_service.get_last_notifications(
|
|
840
895
|
before=before,
|
|
841
896
|
task_type_id=task_type_id,
|
|
842
897
|
task_status_id=task_status_id,
|
|
843
898
|
notification_type=notification_type,
|
|
899
|
+
read=read,
|
|
900
|
+
watching=watching,
|
|
844
901
|
)
|
|
845
|
-
user_service.mark_notifications_as_read()
|
|
846
902
|
return notifications
|
|
847
903
|
|
|
848
904
|
def get_arguments(self):
|
|
@@ -855,7 +911,7 @@ class NotificationsResource(Resource, ArgsMixin):
|
|
|
855
911
|
)
|
|
856
912
|
|
|
857
913
|
|
|
858
|
-
class NotificationResource(Resource):
|
|
914
|
+
class NotificationResource(Resource, ArgsMixin):
|
|
859
915
|
"""
|
|
860
916
|
Return notification matching given id, only if it's a notification that
|
|
861
917
|
belongs to current user.
|
|
@@ -882,6 +938,42 @@ class NotificationResource(Resource):
|
|
|
882
938
|
"""
|
|
883
939
|
return user_service.get_notification(notification_id)
|
|
884
940
|
|
|
941
|
+
def put(self, notification_id):
|
|
942
|
+
"""
|
|
943
|
+
Change notification read status.
|
|
944
|
+
---
|
|
945
|
+
tags:
|
|
946
|
+
- User
|
|
947
|
+
parameters:
|
|
948
|
+
- in: path
|
|
949
|
+
name: notification_id
|
|
950
|
+
required: True
|
|
951
|
+
type: string
|
|
952
|
+
format: UUID
|
|
953
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
954
|
+
responses:
|
|
955
|
+
200:
|
|
956
|
+
description: Notification
|
|
957
|
+
"""
|
|
958
|
+
data = self.get_args([("read", None, False, inputs.boolean)])
|
|
959
|
+
return user_service.update_notification(notification_id, data["read"])
|
|
960
|
+
|
|
961
|
+
|
|
962
|
+
class MarkAllNotificationsAsReadResource(Resource):
|
|
963
|
+
|
|
964
|
+
def post(self):
|
|
965
|
+
"""
|
|
966
|
+
Mark all notifications as read for the current user.
|
|
967
|
+
---
|
|
968
|
+
tags:
|
|
969
|
+
- User
|
|
970
|
+
responses:
|
|
971
|
+
200:
|
|
972
|
+
description: All notifications marked as read
|
|
973
|
+
"""
|
|
974
|
+
user_service.mark_notifications_as_read()
|
|
975
|
+
return {"success": True}
|
|
976
|
+
|
|
885
977
|
|
|
886
978
|
class HasTaskSubscribedResource(Resource):
|
|
887
979
|
"""
|
|
@@ -893,7 +985,7 @@ class HasTaskSubscribedResource(Resource):
|
|
|
893
985
|
Return true if current user has subscribed to given task.
|
|
894
986
|
---
|
|
895
987
|
tags:
|
|
896
|
-
|
|
988
|
+
- User
|
|
897
989
|
parameters:
|
|
898
990
|
- in: path
|
|
899
991
|
name: task_id
|
|
@@ -1259,3 +1351,69 @@ class ClearAvatarResource(Resource):
|
|
|
1259
1351
|
user = persons_service.get_current_user()
|
|
1260
1352
|
persons_service.clear_avatar(user["id"])
|
|
1261
1353
|
return "", 204
|
|
1354
|
+
|
|
1355
|
+
|
|
1356
|
+
class ChatsResource(Resource):
|
|
1357
|
+
|
|
1358
|
+
def get(self):
|
|
1359
|
+
"""
|
|
1360
|
+
Return chats where user is participant.
|
|
1361
|
+
---
|
|
1362
|
+
tags:
|
|
1363
|
+
- User
|
|
1364
|
+
responses:
|
|
1365
|
+
200:
|
|
1366
|
+
description: Chats where user is participant
|
|
1367
|
+
"""
|
|
1368
|
+
user = persons_service.get_current_user()
|
|
1369
|
+
return chats_service.get_chats_for_person(user["id"])
|
|
1370
|
+
|
|
1371
|
+
|
|
1372
|
+
class JoinChatResource(Resource):
|
|
1373
|
+
|
|
1374
|
+
def post(self, entity_id):
|
|
1375
|
+
"""
|
|
1376
|
+
Join chat for given entity (be listed as participant).
|
|
1377
|
+
---
|
|
1378
|
+
tags:
|
|
1379
|
+
- User
|
|
1380
|
+
parameters:
|
|
1381
|
+
- in: path
|
|
1382
|
+
name: entity_id
|
|
1383
|
+
required: True
|
|
1384
|
+
type: string
|
|
1385
|
+
format: UUID
|
|
1386
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1387
|
+
responses:
|
|
1388
|
+
201:
|
|
1389
|
+
description: Chat joined
|
|
1390
|
+
"""
|
|
1391
|
+
entity = entities_service.get_entity(entity_id)
|
|
1392
|
+
user_service.check_project_access(entity["project_id"])
|
|
1393
|
+
user_service.check_entity_access(entity["id"])
|
|
1394
|
+
person = persons_service.get_current_user()
|
|
1395
|
+
return chats_service.join_chat(entity_id, person["id"])
|
|
1396
|
+
|
|
1397
|
+
def delete(self, entity_id):
|
|
1398
|
+
"""
|
|
1399
|
+
Leave chat for given entity (be removed from participants).
|
|
1400
|
+
---
|
|
1401
|
+
tags:
|
|
1402
|
+
- User
|
|
1403
|
+
parameters:
|
|
1404
|
+
- in: path
|
|
1405
|
+
name: entity_id
|
|
1406
|
+
required: True
|
|
1407
|
+
type: string
|
|
1408
|
+
format: UUID
|
|
1409
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1410
|
+
responses:
|
|
1411
|
+
204:
|
|
1412
|
+
description: empty response
|
|
1413
|
+
"""
|
|
1414
|
+
entity = entities_service.get_entity(entity_id)
|
|
1415
|
+
user_service.check_project_access(entity["project_id"])
|
|
1416
|
+
user_service.check_entity_access(entity["id"])
|
|
1417
|
+
person = persons_service.get_current_user()
|
|
1418
|
+
chats_service.leave_chat(entity_id, person["id"])
|
|
1419
|
+
return "", 204
|