zou 0.19.51__py3-none-any.whl → 0.19.53__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.
Files changed (39) hide show
  1. zou/__init__.py +1 -1
  2. zou/app/__init__.py +1 -1
  3. zou/app/blueprints/assets/__init__.py +22 -0
  4. zou/app/blueprints/assets/resources.py +240 -3
  5. zou/app/blueprints/auth/resources.py +26 -22
  6. zou/app/blueprints/chats/resources.py +2 -2
  7. zou/app/blueprints/crud/base.py +10 -6
  8. zou/app/blueprints/crud/day_off.py +3 -3
  9. zou/app/blueprints/crud/entity.py +3 -3
  10. zou/app/blueprints/crud/entity_type.py +15 -0
  11. zou/app/blueprints/crud/metadata_descriptor.py +16 -3
  12. zou/app/blueprints/crud/person.py +13 -15
  13. zou/app/blueprints/crud/preview_background_file.py +3 -3
  14. zou/app/blueprints/crud/project.py +5 -5
  15. zou/app/blueprints/crud/schedule_item.py +2 -2
  16. zou/app/blueprints/crud/task_type.py +3 -3
  17. zou/app/blueprints/persons/resources.py +2 -2
  18. zou/app/blueprints/previews/resources.py +31 -6
  19. zou/app/blueprints/projects/resources.py +1 -1
  20. zou/app/blueprints/shots/resources.py +2 -2
  21. zou/app/models/base.py +6 -1
  22. zou/app/models/entity.py +3 -5
  23. zou/app/services/assets_service.py +74 -1
  24. zou/app/services/breakdown_service.py +33 -3
  25. zou/app/services/deletion_service.py +5 -0
  26. zou/app/services/exception.py +1 -5
  27. zou/app/services/preview_files_service.py +2 -2
  28. zou/app/services/tasks_service.py +1 -1
  29. zou/app/services/time_spents_service.py +4 -4
  30. zou/app/swagger.py +15 -20
  31. zou/app/utils/query.py +53 -5
  32. zou/event_stream.py +1 -0
  33. zou/migrations/versions/59a7445a966c_add_entity_is_shared.py +41 -0
  34. {zou-0.19.51.dist-info → zou-0.19.53.dist-info}/METADATA +6 -6
  35. {zou-0.19.51.dist-info → zou-0.19.53.dist-info}/RECORD +39 -38
  36. {zou-0.19.51.dist-info → zou-0.19.53.dist-info}/WHEEL +1 -1
  37. {zou-0.19.51.dist-info → zou-0.19.53.dist-info}/LICENSE +0 -0
  38. {zou-0.19.51.dist-info → zou-0.19.53.dist-info}/entry_points.txt +0 -0
  39. {zou-0.19.51.dist-info → zou-0.19.53.dist-info}/top_level.txt +0 -0
@@ -20,7 +20,7 @@ from zou.app.blueprints.crud.base import BaseModelsResource, BaseModelResource
20
20
  from zou.app.mixin import ArgsMixin
21
21
 
22
22
  from zou.app.services.exception import (
23
- ArgumentsException,
23
+ WrongParameterException,
24
24
  PersonInProtectedAccounts,
25
25
  )
26
26
 
@@ -61,11 +61,9 @@ class PersonsResource(BaseModelsResource):
61
61
  and data.get("active", True)
62
62
  and persons_service.is_user_limit_reached()
63
63
  ):
64
- raise ArgumentsException(
64
+ raise WrongParameterException(
65
65
  "User limit reached.",
66
66
  {
67
- "error": True,
68
- "message": "User limit reached.",
69
67
  "limit": config.USER_LIMIT,
70
68
  },
71
69
  )
@@ -75,18 +73,18 @@ class PersonsResource(BaseModelsResource):
75
73
  if "role" in data and data["role"] not in [
76
74
  role for role, _ in ROLE_TYPES
77
75
  ]:
78
- raise ArgumentsException("Invalid role")
76
+ raise WrongParameterException("Invalid role")
79
77
  if "contract_type" in data and data["contract_type"] not in [
80
78
  contract_type for contract_type, _ in CONTRACT_TYPES
81
79
  ]:
82
- raise ArgumentsException("Invalid contract_type")
80
+ raise WrongParameterException("Invalid contract_type")
83
81
  if "two_factor_authentication" in data and data[
84
82
  "two_factor_authentication"
85
83
  ] not in [
86
84
  two_factor_authentication
87
85
  for two_factor_authentication, _ in TWO_FACTOR_AUTHENTICATION_TYPES
88
86
  ]:
89
- raise ArgumentsException("Invalid two_factor_authentication")
87
+ raise WrongParameterException("Invalid two_factor_authentication")
90
88
 
91
89
  if "expiration_date" in data and data["expiration_date"] is not None:
92
90
  try:
@@ -96,11 +94,11 @@ class PersonsResource(BaseModelsResource):
96
94
  ).date()
97
95
  < datetime.date.today()
98
96
  ):
99
- raise ArgumentsException(
97
+ raise WrongParameterException(
100
98
  "Expiration date can't be in the past."
101
99
  )
102
100
  except:
103
- raise ArgumentsException("Expiration date is not valid.")
101
+ raise WrongParameterException("Expiration date is not valid.")
104
102
  return data
105
103
 
106
104
  def update_data(self, data):
@@ -156,18 +154,18 @@ class PersonResource(BaseModelResource, ArgsMixin):
156
154
  if "role" in data and data["role"] not in [
157
155
  role for role, _ in ROLE_TYPES
158
156
  ]:
159
- raise ArgumentsException("Invalid role")
157
+ raise WrongParameterException("Invalid role")
160
158
  if "contract_type" in data and data["contract_type"] not in [
161
159
  contract_type for contract_type, _ in CONTRACT_TYPES
162
160
  ]:
163
- raise ArgumentsException("Invalid contract_type")
161
+ raise WrongParameterException("Invalid contract_type")
164
162
  if "two_factor_authentication" in data and data[
165
163
  "two_factor_authentication"
166
164
  ] not in [
167
165
  two_factor_authentication
168
166
  for two_factor_authentication, _ in TWO_FACTOR_AUTHENTICATION_TYPES
169
167
  ]:
170
- raise ArgumentsException("Invalid two_factor_authentication")
168
+ raise WrongParameterException("Invalid two_factor_authentication")
171
169
 
172
170
  if "expiration_date" in data and data["expiration_date"] is not None:
173
171
  try:
@@ -177,11 +175,11 @@ class PersonResource(BaseModelResource, ArgsMixin):
177
175
  ).date()
178
176
  < datetime.date.today()
179
177
  ):
180
- raise ArgumentsException(
178
+ raise WrongParameterException(
181
179
  "Expiration date can't be in the past."
182
180
  )
183
181
  except:
184
- raise ArgumentsException("Expiration date is not valid.")
182
+ raise WrongParameterException("Expiration date is not valid.")
185
183
  return data
186
184
 
187
185
  def check_delete_permissions(self, instance_dict):
@@ -204,7 +202,7 @@ class PersonResource(BaseModelResource, ArgsMixin):
204
202
  and not data.get("is_bot", False)
205
203
  and persons_service.is_user_limit_reached()
206
204
  ):
207
- raise ArgumentsException("User limit reached.")
205
+ raise WrongParameterException("User limit reached.")
208
206
  if instance_dict["email"] in config.PROTECTED_ACCOUNTS:
209
207
  message = None
210
208
  if data.get("active") is False:
@@ -1,5 +1,5 @@
1
1
  from zou.app.models.preview_background_file import PreviewBackgroundFile
2
- from zou.app.services.exception import ArgumentsException
2
+ from zou.app.services.exception import WrongParameterException
3
3
  from zou.app.services import files_service, deletion_service
4
4
 
5
5
  from zou.app.blueprints.crud.base import BaseModelResource, BaseModelsResource
@@ -17,7 +17,7 @@ class PreviewBackgroundFilesResource(BaseModelsResource):
17
17
  name = data.get("name", None)
18
18
  preview_background_file = PreviewBackgroundFile.get_by(name=name)
19
19
  if preview_background_file is not None:
20
- raise ArgumentsException(
20
+ raise WrongParameterException(
21
21
  "A preview background file with similar name already exists"
22
22
  )
23
23
  return data
@@ -44,7 +44,7 @@ class PreviewBackgroundFileResource(BaseModelResource):
44
44
  if preview_background_file is not None and instance_id != str(
45
45
  preview_background_file.id
46
46
  ):
47
- raise ArgumentsException(
47
+ raise WrongParameterException(
48
48
  "A preview background file with similar name already exists"
49
49
  )
50
50
  return data
@@ -18,7 +18,7 @@ from zou.app.utils import events, permissions, fields
18
18
 
19
19
  from zou.app.blueprints.crud.base import BaseModelResource, BaseModelsResource
20
20
 
21
- from zou.app.services.exception import ArgumentsException
21
+ from zou.app.services.exception import WrongParameterException
22
22
 
23
23
 
24
24
  class ProjectsResource(BaseModelsResource):
@@ -44,7 +44,7 @@ class ProjectsResource(BaseModelsResource):
44
44
  if data["production_style"] not in [
45
45
  type_name for type_name, _ in PROJECT_STYLES
46
46
  ]:
47
- raise ArgumentsException("Invalid production_style")
47
+ raise WrongParameterException("Invalid production_style")
48
48
  return True
49
49
 
50
50
  def update_data(self, data):
@@ -71,7 +71,7 @@ class ProjectsResource(BaseModelsResource):
71
71
  or data["preview_background_file_id"]
72
72
  not in data["preview_background_files_ids"]
73
73
  ):
74
- raise ArgumentsException("Invalid preview_background_file_id")
74
+ raise WrongParameterException("Invalid preview_background_file_id")
75
75
  return data
76
76
 
77
77
  def post_creation(self, project):
@@ -131,7 +131,7 @@ class ProjectResource(BaseModelResource, ArgsMixin):
131
131
  data["preview_background_file_id"]
132
132
  not in preview_background_files_ids
133
133
  ):
134
- raise ArgumentsException("Invalid preview_background_file_id")
134
+ raise WrongParameterException("Invalid preview_background_file_id")
135
135
 
136
136
  return data
137
137
 
@@ -167,7 +167,7 @@ class ProjectResource(BaseModelResource, ArgsMixin):
167
167
  if data["production_style"] not in [
168
168
  type_name for type_name, _ in PROJECT_STYLES
169
169
  ]:
170
- raise ArgumentsException("Invalid production_style")
170
+ raise WrongParameterException("Invalid production_style")
171
171
  return data
172
172
 
173
173
  @jwt_required()
@@ -3,7 +3,7 @@ from zou.app.models.schedule_item import ScheduleItem
3
3
  from zou.app.blueprints.crud.base import BaseModelResource, BaseModelsResource
4
4
 
5
5
  from zou.app.services import user_service
6
- from zou.app.services.exception import ArgumentsException
6
+ from zou.app.services.exception import WrongParameterException
7
7
 
8
8
 
9
9
  class ScheduleItemsResource(BaseModelsResource):
@@ -17,7 +17,7 @@ class ScheduleItemsResource(BaseModelsResource):
17
17
  object_id=data.get("object_id", None),
18
18
  )
19
19
  if schedule_item is not None:
20
- raise ArgumentsException("A similar schedule item already exists")
20
+ raise WrongParameterException("A similar schedule item already exists")
21
21
  return schedule_item
22
22
 
23
23
 
@@ -1,5 +1,5 @@
1
1
  from zou.app.models.task_type import TaskType
2
- from zou.app.services.exception import ArgumentsException
2
+ from zou.app.services.exception import WrongParameterException
3
3
  from zou.app.services import tasks_service
4
4
 
5
5
  from zou.app.blueprints.crud.base import BaseModelResource, BaseModelsResource
@@ -17,7 +17,7 @@ class TaskTypesResource(BaseModelsResource):
17
17
  name = data.get("name", None)
18
18
  task_type = TaskType.get_by(name=name)
19
19
  if task_type is not None:
20
- raise ArgumentsException(
20
+ raise WrongParameterException(
21
21
  "A task type with similar name already exists"
22
22
  )
23
23
  return data
@@ -40,7 +40,7 @@ class TaskTypeResource(BaseModelResource):
40
40
  if name is not None:
41
41
  task_type = TaskType.get_by(name=name)
42
42
  if task_type is not None and instance_id != str(task_type.id):
43
- raise ArgumentsException(
43
+ raise WrongParameterException(
44
44
  "A task type with similar name already exists"
45
45
  )
46
46
  return data
@@ -30,7 +30,7 @@ from zou.app.services.exception import (
30
30
  UnactiveUserException,
31
31
  TwoFactorAuthenticationNotEnabledException,
32
32
  PersonInProtectedAccounts,
33
- ArgumentsException,
33
+ WrongParameterException,
34
34
  )
35
35
  from zou.app.services.auth_service import (
36
36
  disable_two_factor_authentication_for_person,
@@ -779,7 +779,7 @@ class TimeSpentDurationResource(Resource, ArgsMixin):
779
779
  )["departments"]
780
780
  if department_id is not None:
781
781
  if department_id not in persons_departments:
782
- raise ArgumentsException(
782
+ raise WrongParameterException(
783
783
  "Supervisor not allowed to access this department"
784
784
  )
785
785
  else:
@@ -35,7 +35,7 @@ from zou.app.utils import (
35
35
  date_helpers,
36
36
  )
37
37
  from zou.app.services.exception import (
38
- ArgumentsException,
38
+ WrongParameterException,
39
39
  PreviewBackgroundFileNotFoundException,
40
40
  PreviewFileReuploadNotAllowedException,
41
41
  )
@@ -813,7 +813,29 @@ class BasePreviewPictureResource(BasePreviewFileResource):
813
813
  abort(404)
814
814
 
815
815
 
816
- class PreviewFileThumbnailResource(BasePreviewPictureResource):
816
+ class BasePreviewFileThumbnailResource(BasePreviewPictureResource):
817
+ """
818
+ Base class to download a thumbnail for a preview file.
819
+ """
820
+
821
+ def is_allowed(self, preview_file_id):
822
+ self.preview_file = files_service.get_preview_file(preview_file_id)
823
+ task = tasks_service.get_task(self.preview_file["task_id"])
824
+ entity = entities_service.get_entity(task["entity_id"])
825
+ if (
826
+ entity["preview_file_id"] != preview_file_id
827
+ or not entity["is_shared"]
828
+ or permissions.has_vendor_permissions()
829
+ ):
830
+ user_service.check_project_access(task["project_id"])
831
+ user_service.check_entity_access(task["entity_id"])
832
+ self.last_modified = date_helpers.get_datetime_from_string(
833
+ self.preview_file["updated_at"]
834
+ )
835
+
836
+
837
+ class PreviewFileThumbnailResource(BasePreviewFileThumbnailResource):
838
+
817
839
  def __init__(self):
818
840
  BasePreviewPictureResource.__init__(self, "thumbnails")
819
841
 
@@ -832,12 +854,12 @@ class PreviewFilePreviewResource(BasePreviewPictureResource):
832
854
  BasePreviewPictureResource.__init__(self, "previews")
833
855
 
834
856
 
835
- class PreviewFileThumbnailSquareResource(BasePreviewPictureResource):
857
+ class PreviewFileThumbnailSquareResource(BasePreviewFileThumbnailResource):
836
858
  def __init__(self):
837
859
  BasePreviewPictureResource.__init__(self, "thumbnails-square")
838
860
 
839
861
 
840
- class PreviewFileOriginalResource(BasePreviewPictureResource):
862
+ class PreviewFileOriginalResource(BasePreviewFileThumbnailResource):
841
863
  def __init__(self):
842
864
  BasePreviewPictureResource.__init__(self, "original")
843
865
 
@@ -981,6 +1003,7 @@ class BaseThumbnailResource(Resource):
981
1003
 
982
1004
 
983
1005
  class PersonThumbnailResource(BaseThumbnailResource):
1006
+
984
1007
  def __init__(self):
985
1008
  BaseThumbnailResource.__init__(
986
1009
  self,
@@ -1028,11 +1051,13 @@ class ProjectThumbnailResource(BaseThumbnailResource):
1028
1051
  "projects",
1029
1052
  projects_service.get_project,
1030
1053
  projects_service.update_project,
1054
+ thumbnail_utils.BIG_SQUARE_SIZE,
1031
1055
  )
1032
1056
 
1033
1057
  def check_allowed_to_get(self, instance_id):
1034
1058
  super().check_allowed_to_get(instance_id)
1035
- user_service.check_project_access(instance_id)
1059
+ if not permissions.has_manager_permissions():
1060
+ user_service.check_project_access(instance_id)
1036
1061
 
1037
1062
 
1038
1063
  class CreateProjectThumbnailResource(ProjectThumbnailResource):
@@ -1072,7 +1097,7 @@ class SetMainPreviewResource(Resource, ArgsMixin):
1072
1097
  user_service.check_entity_access(task["entity_id"])
1073
1098
  if frame_number is not None:
1074
1099
  if preview_file["extension"] != "mp4":
1075
- raise ArgumentsException(
1100
+ raise WrongParameterException(
1076
1101
  "Can't use a given frame on non movie preview"
1077
1102
  )
1078
1103
  preview_files_service.replace_extracted_frame_for_preview_file(
@@ -659,7 +659,7 @@ class ProductionMetadataDescriptorsResource(Resource, ArgsMixin):
659
659
  200:
660
660
  description: All metadata descriptors
661
661
  """
662
- user_service.check_manager_project_access(project_id)
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
@@ -20,7 +20,7 @@ from zou.app.mixin import ArgsMixin
20
20
  from zou.app.utils import fields, query, permissions
21
21
  from zou.app.services.exception import (
22
22
  WrongParameterException,
23
- ArgumentsException,
23
+ WrongParameterException,
24
24
  )
25
25
 
26
26
 
@@ -77,7 +77,7 @@ class ShotResource(Resource, ArgsMixin):
77
77
  user_service.check_manager_project_access(shot["project_id"])
78
78
  data = request.json
79
79
  if data is None:
80
- raise ArgumentsException(
80
+ raise WrongParameterException(
81
81
  "Data are empty. Please verify that you sent JSON data and"
82
82
  " that you set the right headers."
83
83
  )
zou/app/models/base.py CHANGED
@@ -184,7 +184,12 @@ class BaseMixin(object):
184
184
 
185
185
  @classmethod
186
186
  def commit(cls):
187
- db.session.commit()
187
+ try:
188
+ db.session.commit()
189
+ except BaseException:
190
+ db.session.rollback()
191
+ db.session.remove()
192
+ raise
188
193
 
189
194
  def save(self):
190
195
  """
zou/app/models/entity.py CHANGED
@@ -3,7 +3,6 @@ from sqlalchemy_utils import UUIDType, ChoiceType
3
3
  from zou.app import db
4
4
  from zou.app.models.serializer import SerializerMixin
5
5
  from zou.app.models.base import BaseMixin
6
- from zou.app.utils import fields
7
6
 
8
7
  from sqlalchemy.dialects.postgresql import JSONB
9
8
 
@@ -90,10 +89,7 @@ class Entity(db.Model, BaseMixin, SerializerMixin):
90
89
  tasks and files.
91
90
  """
92
91
 
93
- id = db.Column(
94
- UUIDType(binary=False), primary_key=True, default=fields.gen_uuid
95
- )
96
-
92
+ id = BaseMixin.id
97
93
  name = db.Column(db.String(160), nullable=False)
98
94
  code = db.Column(db.String(160)) # To store sanitized version of name
99
95
  description = db.Column(db.Text())
@@ -104,6 +100,8 @@ class Entity(db.Model, BaseMixin, SerializerMixin):
104
100
  nb_entities_out = db.Column(db.Integer, default=0)
105
101
  is_casting_standby = db.Column(db.Boolean, default=False)
106
102
 
103
+ is_shared = db.Column(db.Boolean, default=False, nullable=False)
104
+
107
105
  status = db.Column(
108
106
  ChoiceType(ENTITY_STATUSES), default="running", nullable=False
109
107
  )
@@ -84,7 +84,7 @@ def build_entity_type_asset_type_filter():
84
84
  return ~EntityType.id.in_(ids_to_exclude)
85
85
 
86
86
 
87
- def get_assets(criterions={}):
87
+ def get_assets(criterions={}, is_admin=False):
88
88
  """
89
89
  Get all assets for given criterions.
90
90
  """
@@ -102,6 +102,12 @@ def get_assets(criterions={}):
102
102
  query = query.outerjoin(Task)
103
103
  query = query.filter(user_service.build_assignee_filter())
104
104
 
105
+ if "is_shared" in criterions:
106
+ if not is_admin:
107
+ query = (
108
+ query.join(Project).filter(user_service.build_team_filter())
109
+ )
110
+
105
111
  if episode_id is not None:
106
112
  # Filter based on main episode.
107
113
  query = query.filter(Entity.source_id == episode_id)
@@ -306,6 +312,7 @@ def get_assets_and_tasks(criterions={}, page=1, with_episode_ids=False):
306
312
  "episode_id": source_id,
307
313
  "casting_episode_ids": cast_in_episode_ids.get(asset_id, []),
308
314
  "is_casting_standby": asset.is_casting_standby,
315
+ "is_shared": asset.is_shared,
309
316
  "data": data,
310
317
  "tasks": [],
311
318
  }
@@ -571,6 +578,7 @@ def create_asset(
571
578
  name,
572
579
  description,
573
580
  data,
581
+ is_shared=False,
574
582
  source_id=None,
575
583
  created_by=None,
576
584
  ):
@@ -587,6 +595,7 @@ def create_asset(
587
595
  name=name,
588
596
  description=description,
589
597
  data=data,
598
+ is_shared=is_shared,
590
599
  source_id=source_id,
591
600
  created_by=created_by,
592
601
  )
@@ -706,3 +715,67 @@ def cancel_asset(asset_id, force=True):
706
715
  project_id=str(asset.project_id),
707
716
  )
708
717
  return asset_dict
718
+
719
+
720
+ def set_shared_assets(
721
+ is_shared=True,
722
+ project_id=None,
723
+ asset_type_id=None,
724
+ asset_ids=None,
725
+ ):
726
+ """
727
+ Set all assets of a project to is_shared=True or False.
728
+ """
729
+
730
+ query = Entity.query.filter(build_asset_type_filter()).filter()
731
+
732
+ if project_id is not None:
733
+ query = query.filter(Entity.project_id == project_id)
734
+
735
+ if asset_type_id is not None:
736
+ query = query.filter(Entity.entity_type_id == asset_type_id)
737
+
738
+ if asset_ids is not None:
739
+ query = query.filter(Entity.id.in_(asset_ids))
740
+
741
+ assets = query.all()
742
+
743
+ for asset in assets:
744
+ asset.update_no_commit({"is_shared": is_shared})
745
+
746
+ Entity.commit()
747
+
748
+ for asset in assets:
749
+ asset_id = str(asset.id)
750
+ clear_asset_cache(asset_id)
751
+ events.emit(
752
+ "asset:update",
753
+ {"asset_id": asset_id},
754
+ project_id=project_id,
755
+ )
756
+
757
+ return Entity.serialize_list(assets, obj_type="Asset")
758
+
759
+
760
+ def get_shared_assets_used_in_project(project_id, episode_id=None):
761
+ """
762
+ Get all shared assets used in a project.
763
+ """
764
+ Shot = aliased(Entity, name="shot")
765
+ Sequence = aliased(Entity, name="sequence")
766
+
767
+ assets = (
768
+ Entity.query.filter(build_asset_type_filter())
769
+ .filter(Entity.is_shared == True)
770
+ .join(EntityLink, EntityLink.entity_out_id == Entity.id)
771
+ .join(Shot, EntityLink.entity_in_id == Shot.id)
772
+ .join(Sequence, Shot.parent_id == Sequence.id)
773
+ .filter(Shot.project_id == project_id)
774
+ .filter(Entity.canceled != True)
775
+ .filter(Entity.project_id != project_id)
776
+ )
777
+
778
+ if episode_id is not None and episode_id not in ["main", "all"]:
779
+ assets = assets.filter(Sequence.parent_id == episode_id)
780
+
781
+ return Entity.serialize_list(assets.all(), obj_type="Asset")
@@ -50,6 +50,8 @@ def get_casting(shot_id):
50
50
  Entity.preview_file_id,
51
51
  Entity.source_id,
52
52
  Entity.ready_for,
53
+ Entity.is_shared,
54
+ Entity.project_id,
53
55
  )
54
56
  .order_by(EntityType.name, Entity.name)
55
57
  )
@@ -61,6 +63,8 @@ def get_casting(shot_id):
61
63
  entity_preview_file_id,
62
64
  episode_id,
63
65
  entity_ready_for,
66
+ entity_is_shared,
67
+ entity_project_id,
64
68
  ) in links:
65
69
  casting.append(
66
70
  {
@@ -74,6 +78,8 @@ def get_casting(shot_id):
74
78
  ),
75
79
  "nb_occurences": link.nb_occurences,
76
80
  "label": link.label,
81
+ "is_shared": entity_is_shared,
82
+ "project_id": entity_project_id,
77
83
  }
78
84
  )
79
85
  return casting
@@ -93,11 +99,27 @@ def get_production_episodes_casting(project_id):
93
99
  .join(EntityType, Entity.entity_type_id == EntityType.id)
94
100
  .filter(Episode.project_id == project_id)
95
101
  .filter(Entity.canceled != True)
96
- .add_columns(Entity.name, EntityType.name, Entity.preview_file_id)
97
- .order_by(EntityType.name, Entity.name)
102
+ .add_columns(
103
+ Entity.name,
104
+ EntityType.name,
105
+ Entity.preview_file_id,
106
+ Entity.is_shared,
107
+ Entity.project_id,
108
+ )
109
+ .order_by(
110
+ EntityType.name,
111
+ Entity.name,
112
+ )
98
113
  )
99
114
 
100
- for link, entity_name, entity_type_name, entity_preview_file_id in links:
115
+ for (
116
+ link,
117
+ entity_name,
118
+ entity_type_name,
119
+ entity_preview_file_id,
120
+ entity_is_shared,
121
+ entity_project_id,
122
+ ) in links:
101
123
  episode_id = str(link.entity_in_id)
102
124
  if episode_id not in castings:
103
125
  castings[episode_id] = []
@@ -112,6 +134,8 @@ def get_production_episodes_casting(project_id):
112
134
  ),
113
135
  "nb_occurences": link.nb_occurences,
114
136
  "label": link.label,
137
+ "is_shared": entity_is_shared,
138
+ "project_id": entity_project_id,
115
139
  }
116
140
  )
117
141
  return castings
@@ -139,6 +163,8 @@ def get_sequence_casting(sequence_id, project_id=None, episode_id=None):
139
163
  Entity.name,
140
164
  EntityType.name,
141
165
  Entity.preview_file_id,
166
+ Entity.is_shared,
167
+ Entity.project_id,
142
168
  Sequence.name,
143
169
  )
144
170
  )
@@ -163,6 +189,8 @@ def get_sequence_casting(sequence_id, project_id=None, episode_id=None):
163
189
  entity_name,
164
190
  entity_type_name,
165
191
  entity_preview_file_id,
192
+ entity_is_shared,
193
+ entity_project_id,
166
194
  sequence_name,
167
195
  ) in links:
168
196
  shot_id = str(link.entity_in_id)
@@ -180,6 +208,8 @@ def get_sequence_casting(sequence_id, project_id=None, episode_id=None):
180
208
  ),
181
209
  "nb_occurences": link.nb_occurences,
182
210
  "label": link.label,
211
+ "is_shared": entity_is_shared,
212
+ "project_id": entity_project_id,
183
213
  }
184
214
  )
185
215
  return castings
@@ -362,6 +362,11 @@ def remove_project(project_id):
362
362
 
363
363
  ApiEvent.delete_all_by(project_id=project_id)
364
364
  Entity.delete_all_by(project_id=project_id)
365
+
366
+ descriptors = MetadataDescriptor.query.filter_by(project_id=project_id)
367
+ for descriptor in descriptors:
368
+ descriptor.departments = []
369
+ descriptor.save()
365
370
  MetadataDescriptor.delete_all_by(project_id=project_id)
366
371
  Milestone.delete_all_by(project_id=project_id)
367
372
  ScheduleItem.delete_all_by(project_id=project_id)
@@ -251,7 +251,7 @@ class EntryAlreadyExistsException(Exception):
251
251
  pass
252
252
 
253
253
 
254
- class ArgumentsException(Exception):
254
+ class WrongParameterException(Exception):
255
255
  def __init__(self, message, dict=None):
256
256
  super().__init__(message)
257
257
  self.dict = dict
@@ -261,10 +261,6 @@ class WrongIdFormatException(Exception):
261
261
  pass
262
262
 
263
263
 
264
- class WrongParameterException(Exception):
265
- pass
266
-
267
-
268
264
  class ModelWithRelationsDeletionException(Exception):
269
265
  pass
270
266
 
@@ -34,7 +34,7 @@ from zou.app.utils import (
34
34
  thumbnail as thumbnail_utils,
35
35
  )
36
36
  from zou.app.services.exception import (
37
- ArgumentsException,
37
+ WrongParameterException,
38
38
  PreviewFileNotFoundException,
39
39
  ProjectNotFoundException,
40
40
  EpisodeNotFoundException,
@@ -650,7 +650,7 @@ def extract_tile_from_preview_file(preview_file):
650
650
  extracted_tile_path = movie.generate_tile(preview_file_path)
651
651
  return extracted_tile_path
652
652
  else:
653
- return ArgumentsException("Preview file is not a movie")
653
+ return WrongParameterException("Preview file is not a movie")
654
654
 
655
655
 
656
656
  def reset_movie_files_metadata():
@@ -1082,7 +1082,7 @@ def get_person_tasks_to_check(project_ids=None, department_ids=None):
1082
1082
  else:
1083
1083
  query = query.filter(user_service.build_open_project_filter())
1084
1084
 
1085
- if department_ids is not None:
1085
+ if department_ids:
1086
1086
  query = query.filter(TaskType.department_id.in_(department_ids))
1087
1087
  tasks = []
1088
1088
  for (