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
|
@@ -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,25 +40,26 @@ mapping_substitutions_to_regex = {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
|
|
43
|
-
class
|
|
43
|
+
class OTIOBaseResource(Resource, ArgsMixin):
|
|
44
|
+
@jwt_required()
|
|
44
45
|
def post(self, project_id, episode_id=None):
|
|
45
46
|
args = self.post_args()
|
|
46
47
|
user_service.check_manager_project_access(project_id)
|
|
47
48
|
uploaded_file = request.files["file"]
|
|
48
|
-
file_name =
|
|
49
|
+
file_name = uploaded_file.filename
|
|
49
50
|
file_path = os.path.join(config.TMP_DIR, file_name)
|
|
50
51
|
uploaded_file.save(file_path)
|
|
51
|
-
self.prepare_import(
|
|
52
|
-
project_id,
|
|
53
|
-
episode_id,
|
|
54
|
-
args["naming_convention"],
|
|
55
|
-
args["match_case"],
|
|
56
|
-
)
|
|
57
52
|
try:
|
|
58
|
-
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
|
+
)
|
|
59
60
|
except Exception as e:
|
|
60
61
|
current_app.logger.error(
|
|
61
|
-
f"Import
|
|
62
|
+
f"Import OTIO failed: {type(e).__name__}: {str(e)}"
|
|
62
63
|
)
|
|
63
64
|
return {
|
|
64
65
|
"error": True,
|
|
@@ -120,25 +121,50 @@ class EDLBaseResource(Resource, ArgsMixin):
|
|
|
120
121
|
key = key.lower()
|
|
121
122
|
self.shot_map[key] = shot["id"]
|
|
122
123
|
|
|
123
|
-
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
|
+
):
|
|
124
132
|
result = {"updated_shots": [], "created_shots": []}
|
|
125
133
|
try:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
timeline = otio.adapters.read_from_file(
|
|
132
|
-
file_path,
|
|
133
|
-
rate=projects_service.get_project_fps(project_id),
|
|
134
|
-
ignore_timecode_mismatch=True,
|
|
135
|
-
)
|
|
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)
|
|
136
140
|
except Exception as e:
|
|
137
|
-
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
|
+
)
|
|
138
149
|
for video_track in timeline.video_tracks():
|
|
139
150
|
for track in video_track:
|
|
140
151
|
if isinstance(track, otio.schema.Clip):
|
|
141
|
-
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]
|
|
142
168
|
name_to_search = name if self.match_case else name.lower()
|
|
143
169
|
if name_to_search in self.shot_map:
|
|
144
170
|
shot_id = self.shot_map[name_to_search]
|
|
@@ -183,19 +209,31 @@ class EDLBaseResource(Resource, ArgsMixin):
|
|
|
183
209
|
|
|
184
210
|
data = future_shot_values["data"] or {}
|
|
185
211
|
try:
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
+
)
|
|
189
220
|
except Exception as e:
|
|
190
221
|
current_app.logger.error(
|
|
191
222
|
f"Parsing frame_in failed: {type(e).__name__}: {str(e)}"
|
|
192
223
|
)
|
|
193
224
|
try:
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
+
)
|
|
199
237
|
except Exception as e:
|
|
200
238
|
current_app.logger.error(
|
|
201
239
|
f"Parsing frame_out failed: {type(e).__name__}: {str(e)}"
|
|
@@ -230,11 +268,13 @@ class EDLBaseResource(Resource, ArgsMixin):
|
|
|
230
268
|
return result
|
|
231
269
|
|
|
232
270
|
|
|
233
|
-
class
|
|
271
|
+
class OTIOImportResource(OTIOBaseResource):
|
|
234
272
|
@jwt_required()
|
|
235
273
|
def post(self, **kwargs):
|
|
236
274
|
"""
|
|
237
|
-
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
|
+
).
|
|
238
278
|
---
|
|
239
279
|
tags:
|
|
240
280
|
- Import
|
|
@@ -255,7 +295,7 @@ class EDLImportResource(EDLBaseResource):
|
|
|
255
295
|
201:
|
|
256
296
|
description: .
|
|
257
297
|
400:
|
|
258
|
-
description: The .
|
|
298
|
+
description: The .otio file is not properly formatted.
|
|
259
299
|
"""
|
|
260
300
|
return super().post(**kwargs)
|
|
261
301
|
|
|
@@ -268,15 +308,18 @@ class EDLImportResource(EDLBaseResource):
|
|
|
268
308
|
False,
|
|
269
309
|
str,
|
|
270
310
|
),
|
|
271
|
-
("match_case", True, False,
|
|
311
|
+
("match_case", True, False, inputs.boolean),
|
|
272
312
|
]
|
|
273
313
|
)
|
|
274
314
|
|
|
275
315
|
|
|
276
|
-
class
|
|
316
|
+
class OTIOImportEpisodeResource(OTIOBaseResource):
|
|
317
|
+
@jwt_required()
|
|
277
318
|
def post(self, **kwargs):
|
|
278
319
|
"""
|
|
279
|
-
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
|
+
).
|
|
280
323
|
---
|
|
281
324
|
tags:
|
|
282
325
|
- Import
|
|
@@ -303,7 +346,7 @@ class EDLImportEpisodeResource(EDLBaseResource):
|
|
|
303
346
|
201:
|
|
304
347
|
description: .
|
|
305
348
|
400:
|
|
306
|
-
description: The .
|
|
349
|
+
description: The .otio file is not properly formatted.
|
|
307
350
|
"""
|
|
308
351
|
return super().post(**kwargs)
|
|
309
352
|
|
|
@@ -316,6 +359,6 @@ class EDLImportEpisodeResource(EDLBaseResource):
|
|
|
316
359
|
False,
|
|
317
360
|
str,
|
|
318
361
|
),
|
|
319
|
-
("match_case", True, False,
|
|
362
|
+
("match_case", True, False, inputs.boolean),
|
|
320
363
|
]
|
|
321
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),
|