zou 0.19.15__py3-none-any.whl → 0.20.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zou/__init__.py +1 -1
- zou/app/__init__.py +10 -2
- zou/app/api.py +2 -0
- zou/app/blueprints/assets/__init__.py +22 -0
- zou/app/blueprints/assets/resources.py +241 -4
- zou/app/blueprints/auth/__init__.py +4 -0
- zou/app/blueprints/auth/resources.py +154 -22
- zou/app/blueprints/breakdown/resources.py +4 -4
- zou/app/blueprints/chats/__init__.py +22 -0
- zou/app/blueprints/chats/resources.py +199 -0
- zou/app/blueprints/comments/resources.py +36 -19
- zou/app/blueprints/crud/__init__.py +12 -0
- zou/app/blueprints/crud/attachment_file.py +14 -5
- zou/app/blueprints/crud/base.py +29 -28
- zou/app/blueprints/crud/chat.py +13 -0
- zou/app/blueprints/crud/chat_message.py +13 -0
- zou/app/blueprints/crud/comments.py +85 -29
- zou/app/blueprints/crud/custom_action.py +1 -1
- zou/app/blueprints/crud/day_off.py +47 -9
- zou/app/blueprints/crud/department.py +1 -25
- zou/app/blueprints/crud/entity.py +46 -5
- zou/app/blueprints/crud/entity_type.py +13 -1
- zou/app/blueprints/crud/event.py +1 -1
- zou/app/blueprints/crud/file_status.py +1 -1
- zou/app/blueprints/crud/metadata_descriptor.py +24 -10
- zou/app/blueprints/crud/organisation.py +22 -5
- zou/app/blueprints/crud/output_file.py +1 -1
- zou/app/blueprints/crud/output_type.py +1 -1
- zou/app/blueprints/crud/person.py +32 -24
- zou/app/blueprints/crud/playlist.py +1 -1
- zou/app/blueprints/crud/preview_background_file.py +6 -7
- zou/app/blueprints/crud/preview_file.py +1 -1
- zou/app/blueprints/crud/project.py +14 -6
- zou/app/blueprints/crud/project_status.py +1 -1
- zou/app/blueprints/crud/schedule_item.py +4 -2
- zou/app/blueprints/crud/software.py +1 -1
- zou/app/blueprints/crud/status_automation.py +1 -1
- zou/app/blueprints/crud/studio.py +33 -0
- zou/app/blueprints/crud/task.py +47 -3
- zou/app/blueprints/crud/task_status.py +1 -1
- zou/app/blueprints/crud/task_type.py +4 -4
- zou/app/blueprints/crud/working_file.py +4 -8
- zou/app/blueprints/events/resources.py +13 -12
- zou/app/blueprints/export/csv/assets.py +15 -6
- zou/app/blueprints/export/csv/edits.py +15 -5
- zou/app/blueprints/export/csv/playlists.py +1 -1
- zou/app/blueprints/export/csv/shots.py +15 -5
- zou/app/blueprints/export/csv/time_spents.py +1 -1
- zou/app/blueprints/files/resources.py +22 -23
- zou/app/blueprints/index/resources.py +38 -29
- zou/app/blueprints/news/resources.py +25 -11
- zou/app/blueprints/persons/__init__.py +5 -2
- zou/app/blueprints/persons/resources.py +126 -120
- zou/app/blueprints/previews/__init__.py +18 -8
- zou/app/blueprints/previews/resources.py +569 -328
- zou/app/blueprints/projects/resources.py +1 -1
- zou/app/blueprints/search/resources.py +18 -6
- zou/app/blueprints/shots/__init__.py +5 -0
- zou/app/blueprints/shots/resources.py +134 -4
- zou/app/blueprints/source/__init__.py +6 -6
- zou/app/blueprints/source/csv/assets.py +10 -3
- zou/app/blueprints/source/csv/base.py +1 -1
- zou/app/blueprints/source/csv/edits.py +10 -3
- zou/app/blueprints/source/csv/shots.py +10 -3
- zou/app/blueprints/source/{edl.py → otio.py} +82 -41
- zou/app/blueprints/tasks/__init__.py +3 -2
- zou/app/blueprints/tasks/resources.py +83 -52
- zou/app/blueprints/user/__init__.py +9 -0
- zou/app/blueprints/user/resources.py +170 -12
- zou/app/config.py +10 -0
- zou/app/mixin.py +6 -5
- zou/app/models/attachment_file.py +10 -4
- zou/app/models/base.py +18 -13
- zou/app/models/build_job.py +7 -4
- zou/app/models/chat.py +44 -0
- zou/app/models/chat_message.py +37 -0
- zou/app/models/comment.py +1 -0
- zou/app/models/day_off.py +3 -0
- zou/app/models/entity.py +4 -6
- zou/app/models/entity_type.py +2 -0
- zou/app/models/organisation.py +14 -15
- zou/app/models/person.py +6 -1
- zou/app/models/project.py +3 -0
- zou/app/models/search_filter.py +11 -0
- zou/app/models/search_filter_group.py +10 -0
- zou/app/models/serializer.py +17 -17
- zou/app/models/status_automation.py +2 -0
- zou/app/models/studio.py +13 -0
- zou/app/models/subscription.py +2 -2
- zou/app/models/task.py +6 -1
- zou/app/models/task_status.py +1 -0
- zou/app/models/task_type.py +1 -0
- zou/app/models/working_file.py +1 -1
- zou/app/services/assets_service.py +101 -14
- zou/app/services/auth_service.py +17 -44
- zou/app/services/breakdown_service.py +37 -5
- zou/app/services/chats_service.py +279 -0
- zou/app/services/comments_service.py +110 -65
- zou/app/services/concepts_service.py +4 -12
- zou/app/services/deletion_service.py +43 -30
- zou/app/services/edits_service.py +5 -11
- zou/app/services/emails_service.py +4 -4
- zou/app/services/entities_service.py +17 -2
- zou/app/services/events_service.py +12 -4
- zou/app/services/exception.py +5 -5
- zou/app/services/names_service.py +7 -2
- zou/app/services/news_service.py +17 -9
- zou/app/services/persons_service.py +38 -21
- zou/app/services/playlists_service.py +8 -7
- zou/app/services/preview_files_service.py +137 -10
- zou/app/services/projects_service.py +5 -14
- zou/app/services/shots_service.py +221 -49
- zou/app/services/sync_service.py +46 -42
- zou/app/services/tasks_service.py +185 -46
- zou/app/services/time_spents_service.py +67 -20
- zou/app/services/user_service.py +350 -107
- zou/app/stores/auth_tokens_store.py +2 -1
- zou/app/stores/file_store.py +18 -0
- zou/app/stores/publisher_store.py +7 -7
- zou/app/stores/queue_store.py +1 -0
- zou/app/swagger.py +36 -20
- zou/app/utils/cache.py +2 -0
- zou/app/utils/commands.py +104 -7
- zou/app/utils/csv_utils.py +1 -4
- zou/app/utils/date_helpers.py +33 -17
- zou/app/utils/dbhelpers.py +14 -1
- zou/app/utils/emails.py +2 -2
- zou/app/utils/fido.py +22 -0
- zou/app/utils/query.py +54 -6
- zou/app/utils/redis.py +11 -0
- zou/app/utils/saml.py +51 -0
- zou/app/utils/string.py +2 -0
- zou/app/utils/thumbnail.py +4 -2
- zou/cli.py +76 -18
- zou/debug.py +4 -2
- zou/event_stream.py +122 -165
- zou/job_settings.py +1 -0
- zou/migrations/env.py +0 -0
- zou/migrations/utils/base.py +6 -6
- zou/migrations/versions/1bb55759146f_add_table_studio.py +67 -0
- zou/migrations/versions/1fab8c420678_add_attachments_to_message_chats.py +56 -0
- zou/migrations/versions/23122f290ca2_add_entity_chat_models.py +149 -0
- zou/migrations/versions/32f134ff1201_add_is_shared_flag_to_filters.py +33 -0
- zou/migrations/versions/57222395f2be_add_statusautomation_import_last_revision.py +41 -0
- zou/migrations/versions/59a7445a966c_add_entity_is_shared.py +41 -0
- zou/migrations/versions/5b980f0dc365_add_comment_links.py +35 -0
- zou/migrations/versions/680c64565f9d_for_searchfiltergroup_is_shared.py +35 -0
- zou/migrations/versions/8e67c183bed7_add_preference_fields.py +71 -0
- zou/migrations/versions/92b40d79ad3f_allow_message_attachments.py +38 -0
- zou/migrations/versions/971dbf5a0faf_add_short_name_for_asset_type_entity_.py +33 -0
- zou/migrations/versions/9b85c14fa8a7_add_day_off_new_columns.py +68 -0
- zou/migrations/versions/9d3bb33c6fc6_add_department_keys_to_filter_models.py +73 -0
- zou/migrations/versions/a252a094e977_add_descriptions_for_entities_tasks_and_.py +40 -0
- zou/migrations/versions/be56dc0fb760_for_is_shared_disallow_nullable.py +102 -0
- zou/migrations/versions/ca28796a2a62_add_is_done_field_to_the_task_model.py +108 -0
- zou/migrations/versions/f344b867a911_for_description_of_entity_task_working_.py +75 -0
- zou/remote/config_payload.py +2 -1
- zou/utils/movie.py +14 -4
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/METADATA +75 -69
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/RECORD +163 -134
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/WHEEL +1 -1
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/LICENSE +0 -0
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/entry_points.txt +0 -0
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/top_level.txt +0 -0
|
@@ -659,7 +659,7 @@ class ProductionMetadataDescriptorsResource(Resource, ArgsMixin):
|
|
|
659
659
|
200:
|
|
660
660
|
description: All metadata descriptors
|
|
661
661
|
"""
|
|
662
|
-
user_service.
|
|
662
|
+
user_service.check_project_access(project_id)
|
|
663
663
|
for_client = permissions.has_client_permissions()
|
|
664
664
|
return projects_service.get_metadata_descriptors(
|
|
665
665
|
project_id, for_client
|
|
@@ -78,12 +78,24 @@ class SearchResource(Resource, ArgsMixin):
|
|
|
78
78
|
query, limit=limit, offset=offset
|
|
79
79
|
)
|
|
80
80
|
if "assets" in index_names:
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
if (
|
|
82
|
+
len(project_ids) == 0
|
|
83
|
+
and not permissions.has_admin_permissions()
|
|
84
|
+
):
|
|
85
|
+
results["assets"] = []
|
|
86
|
+
else:
|
|
87
|
+
results["assets"] = index_service.search_assets(
|
|
88
|
+
query, project_ids, limit=limit, offset=offset
|
|
89
|
+
)
|
|
84
90
|
if "shots" in index_names:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
if (
|
|
92
|
+
len(project_ids) == 0
|
|
93
|
+
and not permissions.has_admin_permissions()
|
|
94
|
+
):
|
|
95
|
+
results["shots"] = []
|
|
96
|
+
else:
|
|
97
|
+
results["shots"] = index_service.search_shots(
|
|
98
|
+
query, project_ids, limit=limit, offset=offset
|
|
99
|
+
)
|
|
88
100
|
|
|
89
101
|
return results
|
|
@@ -42,6 +42,7 @@ from zou.app.blueprints.shots.resources import (
|
|
|
42
42
|
EpisodeAssetTasksResource,
|
|
43
43
|
SequenceShotTasksResource,
|
|
44
44
|
ProjectQuotasResource,
|
|
45
|
+
SetShotsFramesResource,
|
|
45
46
|
)
|
|
46
47
|
|
|
47
48
|
routes = [
|
|
@@ -94,6 +95,10 @@ routes = [
|
|
|
94
95
|
"/data/projects/<project_id>/quotas/<task_type_id>",
|
|
95
96
|
ProjectQuotasResource,
|
|
96
97
|
),
|
|
98
|
+
(
|
|
99
|
+
"/actions/projects/<project_id>/task-types/<task_type_id>/set-shot-nb-frames",
|
|
100
|
+
SetShotsFramesResource,
|
|
101
|
+
),
|
|
97
102
|
]
|
|
98
103
|
|
|
99
104
|
|
|
@@ -18,6 +18,9 @@ from zou.app.services import (
|
|
|
18
18
|
|
|
19
19
|
from zou.app.mixin import ArgsMixin
|
|
20
20
|
from zou.app.utils import fields, query, permissions
|
|
21
|
+
from zou.app.services.exception import (
|
|
22
|
+
WrongParameterException,
|
|
23
|
+
)
|
|
21
24
|
|
|
22
25
|
|
|
23
26
|
class ShotResource(Resource, ArgsMixin):
|
|
@@ -47,6 +50,52 @@ class ShotResource(Resource, ArgsMixin):
|
|
|
47
50
|
user_service.check_entity_access(shot["id"])
|
|
48
51
|
return shot
|
|
49
52
|
|
|
53
|
+
@jwt_required()
|
|
54
|
+
def put(self, shot_id):
|
|
55
|
+
"""
|
|
56
|
+
Update given shot.
|
|
57
|
+
---
|
|
58
|
+
tags:
|
|
59
|
+
- Shots
|
|
60
|
+
parameters:
|
|
61
|
+
- in: path
|
|
62
|
+
name: shot_id
|
|
63
|
+
required: True
|
|
64
|
+
type: string
|
|
65
|
+
format: UUID
|
|
66
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
67
|
+
- in: body
|
|
68
|
+
name: data
|
|
69
|
+
required: True
|
|
70
|
+
type: object
|
|
71
|
+
responses:
|
|
72
|
+
200:
|
|
73
|
+
description: Update given shot
|
|
74
|
+
"""
|
|
75
|
+
shot = shots_service.get_shot(shot_id)
|
|
76
|
+
user_service.check_manager_project_access(shot["project_id"])
|
|
77
|
+
data = request.json
|
|
78
|
+
if data is None:
|
|
79
|
+
raise WrongParameterException(
|
|
80
|
+
"Data are empty. Please verify that you sent JSON data and"
|
|
81
|
+
" that you set the right headers."
|
|
82
|
+
)
|
|
83
|
+
for field in [
|
|
84
|
+
"id",
|
|
85
|
+
"created_at",
|
|
86
|
+
"updated_at",
|
|
87
|
+
"instance_casting",
|
|
88
|
+
"project_id",
|
|
89
|
+
"entities_in",
|
|
90
|
+
"entities_out",
|
|
91
|
+
"type",
|
|
92
|
+
"shotgun_id",
|
|
93
|
+
"created_by",
|
|
94
|
+
]:
|
|
95
|
+
data.pop(field, None)
|
|
96
|
+
|
|
97
|
+
return shots_service.update_shot(shot_id, data)
|
|
98
|
+
|
|
50
99
|
@jwt_required()
|
|
51
100
|
def delete(self, shot_id):
|
|
52
101
|
"""
|
|
@@ -1506,19 +1555,100 @@ class ProjectQuotasResource(Resource, ArgsMixin):
|
|
|
1506
1555
|
type: string
|
|
1507
1556
|
format: UUID
|
|
1508
1557
|
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1558
|
+
- in: query
|
|
1559
|
+
name: count_mode
|
|
1560
|
+
required: True
|
|
1561
|
+
type: string
|
|
1562
|
+
enum: [weighted, weigtheddone, feedback, done]
|
|
1563
|
+
x-example: weighted
|
|
1564
|
+
- in: query
|
|
1565
|
+
name: studio_id
|
|
1566
|
+
required: False
|
|
1567
|
+
type: string
|
|
1568
|
+
format: UUID
|
|
1569
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1509
1570
|
responses:
|
|
1510
1571
|
200:
|
|
1511
1572
|
description: Quotas statistics for shots
|
|
1512
1573
|
"""
|
|
1513
1574
|
projects_service.get_project(project_id)
|
|
1514
1575
|
user_service.check_project_access(project_id)
|
|
1515
|
-
|
|
1516
|
-
|
|
1576
|
+
args = self.get_args(
|
|
1577
|
+
[
|
|
1578
|
+
("count_mode", "weighted", False, str),
|
|
1579
|
+
("studio_id", None, False, str),
|
|
1580
|
+
]
|
|
1581
|
+
)
|
|
1582
|
+
count_mode = args["count_mode"]
|
|
1583
|
+
studio_id = args["studio_id"]
|
|
1584
|
+
|
|
1585
|
+
if count_mode not in ["weighted", "weighteddone", "feedback", "done"]:
|
|
1586
|
+
raise WrongParameterException(
|
|
1587
|
+
"count_mode must be equal to weighted, weigtheddone, feedback"
|
|
1588
|
+
", or done"
|
|
1589
|
+
)
|
|
1590
|
+
|
|
1591
|
+
feedback = "done" not in count_mode
|
|
1592
|
+
weighted = "weighted" in count_mode
|
|
1593
|
+
|
|
1517
1594
|
if weighted:
|
|
1518
1595
|
return shots_service.get_weighted_quotas(
|
|
1519
|
-
project_id,
|
|
1596
|
+
project_id,
|
|
1597
|
+
task_type_id,
|
|
1598
|
+
feedback=feedback,
|
|
1599
|
+
studio_id=studio_id,
|
|
1520
1600
|
)
|
|
1521
1601
|
else:
|
|
1522
1602
|
return shots_service.get_raw_quotas(
|
|
1523
|
-
project_id,
|
|
1603
|
+
project_id,
|
|
1604
|
+
task_type_id,
|
|
1605
|
+
feedback=feedback,
|
|
1606
|
+
studio_id=studio_id,
|
|
1524
1607
|
)
|
|
1608
|
+
|
|
1609
|
+
|
|
1610
|
+
class SetShotsFramesResource(Resource, ArgsMixin):
|
|
1611
|
+
@jwt_required()
|
|
1612
|
+
def post(self, project_id, task_type_id):
|
|
1613
|
+
"""
|
|
1614
|
+
Set frames for given shots.
|
|
1615
|
+
---
|
|
1616
|
+
tags:
|
|
1617
|
+
- Shots
|
|
1618
|
+
parameters:
|
|
1619
|
+
- in: formData
|
|
1620
|
+
name: shots
|
|
1621
|
+
required: True
|
|
1622
|
+
type: array
|
|
1623
|
+
items:
|
|
1624
|
+
type: object
|
|
1625
|
+
properties:
|
|
1626
|
+
shot_id:
|
|
1627
|
+
type: string
|
|
1628
|
+
format: UUID
|
|
1629
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1630
|
+
nb_frames:
|
|
1631
|
+
type: integer
|
|
1632
|
+
x-example: 24
|
|
1633
|
+
responses:
|
|
1634
|
+
200:
|
|
1635
|
+
description: Frames set for given shots
|
|
1636
|
+
"""
|
|
1637
|
+
user_service.check_manager_project_access(project_id)
|
|
1638
|
+
if not fields.is_valid_id(task_type_id) or not fields.is_valid_id(
|
|
1639
|
+
project_id
|
|
1640
|
+
):
|
|
1641
|
+
raise WrongParameterException("Invalid project or task type id")
|
|
1642
|
+
|
|
1643
|
+
episode_id = self.get_episode_id()
|
|
1644
|
+
if not episode_id in ["", None] and not fields.is_valid_id(episode_id):
|
|
1645
|
+
raise WrongParameterException("Invalid episode id")
|
|
1646
|
+
|
|
1647
|
+
if episode_id == "":
|
|
1648
|
+
episode_id = None
|
|
1649
|
+
|
|
1650
|
+
return shots_service.set_frames_from_task_type_preview_files(
|
|
1651
|
+
project_id,
|
|
1652
|
+
task_type_id,
|
|
1653
|
+
episode_id=episode_id,
|
|
1654
|
+
)
|
|
@@ -80,9 +80,9 @@ from zou.app.blueprints.source.kitsu import (
|
|
|
80
80
|
ImportKitsuTasksResource,
|
|
81
81
|
)
|
|
82
82
|
|
|
83
|
-
from zou.app.blueprints.source.
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
from zou.app.blueprints.source.otio import (
|
|
84
|
+
OTIOImportResource,
|
|
85
|
+
OTIOImportEpisodeResource,
|
|
86
86
|
)
|
|
87
87
|
|
|
88
88
|
routes = [
|
|
@@ -133,10 +133,10 @@ routes = [
|
|
|
133
133
|
"/import/csv/projects/<project_id>/episodes/<episode_id>/task-types/<task_type_id>/estimations",
|
|
134
134
|
TaskTypeEstimationsEpisodeCsvImportResource,
|
|
135
135
|
),
|
|
136
|
-
("/import/
|
|
136
|
+
("/import/otio/projects/<project_id>", OTIOImportResource),
|
|
137
137
|
(
|
|
138
|
-
"/import/
|
|
139
|
-
|
|
138
|
+
"/import/otio/projects/<project_id>/episodes/<episode_id>",
|
|
139
|
+
OTIOImportEpisodeResource,
|
|
140
140
|
),
|
|
141
141
|
("/import/kitsu/comments", ImportKitsuCommentsResource),
|
|
142
142
|
("/import/kitsu/entities", ImportKitsuEntitiesResource),
|
|
@@ -16,7 +16,7 @@ from zou.app.services import (
|
|
|
16
16
|
)
|
|
17
17
|
from zou.app.models.entity import Entity
|
|
18
18
|
from zou.app.services.exception import WrongParameterException
|
|
19
|
-
from zou.app.utils import events, cache
|
|
19
|
+
from zou.app.utils import events, cache, string
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class AssetsCsvImportResource(BaseCsvProjectImportResource):
|
|
@@ -209,9 +209,16 @@ class AssetsCsvImportResource(BaseCsvProjectImportResource):
|
|
|
209
209
|
else:
|
|
210
210
|
asset_new_values["data"] = entity.data.copy()
|
|
211
211
|
|
|
212
|
-
for name,
|
|
212
|
+
for name, descriptor in self.descriptor_fields.items():
|
|
213
213
|
if name in row:
|
|
214
|
-
|
|
214
|
+
if descriptor["data_type"] == "boolean":
|
|
215
|
+
asset_new_values["data"][descriptor["field_name"]] = (
|
|
216
|
+
"true" if string.strtobool(row[name]) else "false"
|
|
217
|
+
)
|
|
218
|
+
else:
|
|
219
|
+
asset_new_values["data"][descriptor["field_name"]] = row[
|
|
220
|
+
name
|
|
221
|
+
]
|
|
215
222
|
|
|
216
223
|
ready_for = row.get("Ready for", None)
|
|
217
224
|
if ready_for is not None:
|
|
@@ -131,5 +131,5 @@ class BaseCsvProjectImportResource(BaseCsvImportResource, ArgsMixin):
|
|
|
131
131
|
descriptors = projects_service.get_metadata_descriptors(project_id)
|
|
132
132
|
for descriptor in descriptors:
|
|
133
133
|
if descriptor["entity_type"] == entity_type:
|
|
134
|
-
descriptor_map[descriptor["name"]] = descriptor
|
|
134
|
+
descriptor_map[descriptor["name"]] = descriptor
|
|
135
135
|
return descriptor_map
|
|
@@ -21,7 +21,7 @@ from zou.app.services.tasks_service import (
|
|
|
21
21
|
)
|
|
22
22
|
from zou.app.services.comments_service import create_comment
|
|
23
23
|
from zou.app.services.exception import WrongParameterException
|
|
24
|
-
from zou.app.utils import events
|
|
24
|
+
from zou.app.utils import events, string
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
class EditsCsvImportResource(BaseCsvProjectImportResource):
|
|
@@ -192,9 +192,16 @@ class EditsCsvImportResource(BaseCsvProjectImportResource):
|
|
|
192
192
|
else:
|
|
193
193
|
edit_new_values["data"] = entity.data.copy()
|
|
194
194
|
|
|
195
|
-
for name,
|
|
195
|
+
for name, descriptor in self.descriptor_fields.items():
|
|
196
196
|
if name in row:
|
|
197
|
-
|
|
197
|
+
if descriptor["data_type"] == "boolean":
|
|
198
|
+
edit_new_values["data"][descriptor["field_name"]] = (
|
|
199
|
+
"true" if string.strtobool(row[name]) else "false"
|
|
200
|
+
)
|
|
201
|
+
else:
|
|
202
|
+
edit_new_values["data"][descriptor["field_name"]] = row[
|
|
203
|
+
name
|
|
204
|
+
]
|
|
198
205
|
|
|
199
206
|
tasks_update = self.get_tasks_update(row)
|
|
200
207
|
|
|
@@ -21,7 +21,7 @@ from zou.app.services.tasks_service import (
|
|
|
21
21
|
)
|
|
22
22
|
from zou.app.services.comments_service import create_comment
|
|
23
23
|
from zou.app.services.exception import WrongParameterException
|
|
24
|
-
from zou.app.utils import events
|
|
24
|
+
from zou.app.utils import events, string
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
class ShotsCsvImportResource(BaseCsvProjectImportResource):
|
|
@@ -229,9 +229,16 @@ class ShotsCsvImportResource(BaseCsvProjectImportResource):
|
|
|
229
229
|
if fps is not None:
|
|
230
230
|
shot_new_values["data"]["fps"] = fps
|
|
231
231
|
|
|
232
|
-
for name,
|
|
232
|
+
for name, descriptor in self.descriptor_fields.items():
|
|
233
233
|
if name in row:
|
|
234
|
-
|
|
234
|
+
if descriptor["data_type"] == "boolean":
|
|
235
|
+
shot_new_values["data"][descriptor["field_name"]] = (
|
|
236
|
+
"true" if string.strtobool(row[name]) else "false"
|
|
237
|
+
)
|
|
238
|
+
else:
|
|
239
|
+
shot_new_values["data"][descriptor["field_name"]] = row[
|
|
240
|
+
name
|
|
241
|
+
]
|
|
235
242
|
|
|
236
243
|
tasks_update = self.get_tasks_update(row)
|
|
237
244
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import os
|
|
2
|
-
import
|
|
2
|
+
import pathlib
|
|
3
3
|
import opentimelineio as otio
|
|
4
4
|
import re
|
|
5
5
|
|
|
6
6
|
from string import Template
|
|
7
7
|
|
|
8
8
|
from flask import request, current_app
|
|
9
|
-
from flask_restful import Resource
|
|
9
|
+
from flask_restful import Resource, inputs
|
|
10
10
|
from flask_jwt_extended import jwt_required
|
|
11
11
|
|
|
12
12
|
from zou.app import config
|
|
@@ -40,26 +40,26 @@ mapping_substitutions_to_regex = {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
|
|
43
|
-
class
|
|
43
|
+
class OTIOBaseResource(Resource, ArgsMixin):
|
|
44
44
|
@jwt_required()
|
|
45
45
|
def post(self, project_id, episode_id=None):
|
|
46
46
|
args = self.post_args()
|
|
47
47
|
user_service.check_manager_project_access(project_id)
|
|
48
48
|
uploaded_file = request.files["file"]
|
|
49
|
-
file_name =
|
|
49
|
+
file_name = uploaded_file.filename
|
|
50
50
|
file_path = os.path.join(config.TMP_DIR, file_name)
|
|
51
51
|
uploaded_file.save(file_path)
|
|
52
|
-
self.prepare_import(
|
|
53
|
-
project_id,
|
|
54
|
-
episode_id,
|
|
55
|
-
args["naming_convention"],
|
|
56
|
-
args["match_case"],
|
|
57
|
-
)
|
|
58
52
|
try:
|
|
59
|
-
result = self.run_import(
|
|
53
|
+
result = self.run_import(
|
|
54
|
+
file_path,
|
|
55
|
+
project_id,
|
|
56
|
+
episode_id,
|
|
57
|
+
args["naming_convention"],
|
|
58
|
+
args["match_case"],
|
|
59
|
+
)
|
|
60
60
|
except Exception as e:
|
|
61
61
|
current_app.logger.error(
|
|
62
|
-
f"Import
|
|
62
|
+
f"Import OTIO failed: {type(e).__name__}: {str(e)}"
|
|
63
63
|
)
|
|
64
64
|
return {
|
|
65
65
|
"error": True,
|
|
@@ -121,25 +121,50 @@ class EDLBaseResource(Resource, ArgsMixin):
|
|
|
121
121
|
key = key.lower()
|
|
122
122
|
self.shot_map[key] = shot["id"]
|
|
123
123
|
|
|
124
|
-
def run_import(
|
|
124
|
+
def run_import(
|
|
125
|
+
self,
|
|
126
|
+
file_path,
|
|
127
|
+
project_id,
|
|
128
|
+
episode_id,
|
|
129
|
+
naming_convention,
|
|
130
|
+
match_case,
|
|
131
|
+
):
|
|
125
132
|
result = {"updated_shots": [], "created_shots": []}
|
|
126
133
|
try:
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
timeline = otio.adapters.read_from_file(
|
|
133
|
-
file_path,
|
|
134
|
-
rate=projects_service.get_project_fps(project_id),
|
|
135
|
-
ignore_timecode_mismatch=True,
|
|
136
|
-
)
|
|
134
|
+
kwargs = {}
|
|
135
|
+
extension = pathlib.Path(file_path).suffix
|
|
136
|
+
if extension == ".edl":
|
|
137
|
+
kwargs["rate"] = projects_service.get_project_fps(project_id)
|
|
138
|
+
kwargs["ignore_timecode_mismatch"] = True
|
|
139
|
+
timeline = otio.adapters.read_from_file(file_path, **kwargs)
|
|
137
140
|
except Exception as e:
|
|
138
|
-
raise Exception("Failed to parse
|
|
141
|
+
raise Exception(f"Failed to parse OTIO file: {str(e)}")
|
|
142
|
+
|
|
143
|
+
self.prepare_import(
|
|
144
|
+
project_id,
|
|
145
|
+
episode_id,
|
|
146
|
+
naming_convention,
|
|
147
|
+
match_case,
|
|
148
|
+
)
|
|
139
149
|
for video_track in timeline.video_tracks():
|
|
140
150
|
for track in video_track:
|
|
141
151
|
if isinstance(track, otio.schema.Clip):
|
|
142
|
-
name
|
|
152
|
+
name = os.path.splitext(track.name)[0]
|
|
153
|
+
if not name:
|
|
154
|
+
if getattr(track.media_reference, "name_prefix", None):
|
|
155
|
+
name = track.media_reference.name_prefix
|
|
156
|
+
elif getattr(track.media_reference, "name", None):
|
|
157
|
+
name, _ = os.path.splitext(
|
|
158
|
+
track.media_reference.name
|
|
159
|
+
)[0]
|
|
160
|
+
elif getattr(
|
|
161
|
+
track.media_reference, "target_url", None
|
|
162
|
+
):
|
|
163
|
+
name, _ = os.path.splitext(
|
|
164
|
+
os.path.basename(
|
|
165
|
+
track.media_reference.target_url
|
|
166
|
+
)
|
|
167
|
+
)[0]
|
|
143
168
|
name_to_search = name if self.match_case else name.lower()
|
|
144
169
|
if name_to_search in self.shot_map:
|
|
145
170
|
shot_id = self.shot_map[name_to_search]
|
|
@@ -184,19 +209,31 @@ class EDLBaseResource(Resource, ArgsMixin):
|
|
|
184
209
|
|
|
185
210
|
data = future_shot_values["data"] or {}
|
|
186
211
|
try:
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
212
|
+
try:
|
|
213
|
+
data["frame_in"] = (
|
|
214
|
+
track.trimmed_range_in_parent().start_time.to_frames()
|
|
215
|
+
)
|
|
216
|
+
except:
|
|
217
|
+
data["frame_in"] = (
|
|
218
|
+
track.trimmed_range().start_time.to_frames()
|
|
219
|
+
)
|
|
190
220
|
except Exception as e:
|
|
191
221
|
current_app.logger.error(
|
|
192
222
|
f"Parsing frame_in failed: {type(e).__name__}: {str(e)}"
|
|
193
223
|
)
|
|
194
224
|
try:
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
225
|
+
try:
|
|
226
|
+
data["frame_out"] = (
|
|
227
|
+
track.trimmed_range_in_parent()
|
|
228
|
+
.end_time_inclusive()
|
|
229
|
+
.to_frames()
|
|
230
|
+
)
|
|
231
|
+
except:
|
|
232
|
+
data["frame_out"] = (
|
|
233
|
+
track.trimmed_range()
|
|
234
|
+
.end_time_inclusive()
|
|
235
|
+
.to_frames()
|
|
236
|
+
)
|
|
200
237
|
except Exception as e:
|
|
201
238
|
current_app.logger.error(
|
|
202
239
|
f"Parsing frame_out failed: {type(e).__name__}: {str(e)}"
|
|
@@ -231,11 +268,13 @@ class EDLBaseResource(Resource, ArgsMixin):
|
|
|
231
268
|
return result
|
|
232
269
|
|
|
233
270
|
|
|
234
|
-
class
|
|
271
|
+
class OTIOImportResource(OTIOBaseResource):
|
|
235
272
|
@jwt_required()
|
|
236
273
|
def post(self, **kwargs):
|
|
237
274
|
"""
|
|
238
|
-
Import an
|
|
275
|
+
Import an OTIO file to enter frame_in / frame_out / nb_frames (it can
|
|
276
|
+
be every adapter supported by OpenTimelineIO, for example: EDL, OTIO...
|
|
277
|
+
).
|
|
239
278
|
---
|
|
240
279
|
tags:
|
|
241
280
|
- Import
|
|
@@ -256,7 +295,7 @@ class EDLImportResource(EDLBaseResource):
|
|
|
256
295
|
201:
|
|
257
296
|
description: .
|
|
258
297
|
400:
|
|
259
|
-
description: The .
|
|
298
|
+
description: The .otio file is not properly formatted.
|
|
260
299
|
"""
|
|
261
300
|
return super().post(**kwargs)
|
|
262
301
|
|
|
@@ -269,16 +308,18 @@ class EDLImportResource(EDLBaseResource):
|
|
|
269
308
|
False,
|
|
270
309
|
str,
|
|
271
310
|
),
|
|
272
|
-
("match_case", True, False,
|
|
311
|
+
("match_case", True, False, inputs.boolean),
|
|
273
312
|
]
|
|
274
313
|
)
|
|
275
314
|
|
|
276
315
|
|
|
277
|
-
class
|
|
316
|
+
class OTIOImportEpisodeResource(OTIOBaseResource):
|
|
278
317
|
@jwt_required()
|
|
279
318
|
def post(self, **kwargs):
|
|
280
319
|
"""
|
|
281
|
-
Import an
|
|
320
|
+
Import an OTIO file to enter frame_in / frame_out / nb_frames (it can
|
|
321
|
+
be every adapter supported by OpenTimelineIO, for example: edl, otio...
|
|
322
|
+
).
|
|
282
323
|
---
|
|
283
324
|
tags:
|
|
284
325
|
- Import
|
|
@@ -305,7 +346,7 @@ class EDLImportEpisodeResource(EDLBaseResource):
|
|
|
305
346
|
201:
|
|
306
347
|
description: .
|
|
307
348
|
400:
|
|
308
|
-
description: The .
|
|
349
|
+
description: The .otio file is not properly formatted.
|
|
309
350
|
"""
|
|
310
351
|
return super().post(**kwargs)
|
|
311
352
|
|
|
@@ -318,6 +359,6 @@ class EDLImportEpisodeResource(EDLBaseResource):
|
|
|
318
359
|
False,
|
|
319
360
|
str,
|
|
320
361
|
),
|
|
321
|
-
("match_case", True, False,
|
|
362
|
+
("match_case", True, False, inputs.boolean),
|
|
322
363
|
]
|
|
323
364
|
)
|
|
@@ -35,11 +35,13 @@ from zou.app.blueprints.tasks.resources import (
|
|
|
35
35
|
SetTaskMainPreviewResource,
|
|
36
36
|
PersonsTasksDatesResource,
|
|
37
37
|
CreateConceptTasksResource,
|
|
38
|
+
OpenTasksStatsResource,
|
|
38
39
|
)
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
routes = [
|
|
42
43
|
("/data/tasks/open-tasks", OpenTasksResource),
|
|
44
|
+
("/data/tasks/open-tasks/stats", OpenTasksStatsResource),
|
|
43
45
|
("/data/tasks/<task_id>/comments", TaskCommentsResource),
|
|
44
46
|
("/data/tasks/<task_id>/comments/<comment_id>", TaskCommentResource),
|
|
45
47
|
("/data/tasks/<task_id>/previews", TaskPreviewsResource),
|
|
@@ -92,8 +94,7 @@ routes = [
|
|
|
92
94
|
AddPreviewResource,
|
|
93
95
|
),
|
|
94
96
|
(
|
|
95
|
-
"/actions/tasks/<task_id>/comments/<comment_id>/preview-files
|
|
96
|
-
"<preview_file_id>",
|
|
97
|
+
"/actions/tasks/<task_id>/comments/<comment_id>/preview-files/<preview_file_id>",
|
|
97
98
|
AddExtraPreviewResource,
|
|
98
99
|
),
|
|
99
100
|
("/actions/tasks/<task_id>/to-review", ToReviewResource),
|