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.
Files changed (164) hide show
  1. zou/__init__.py +1 -1
  2. zou/app/__init__.py +10 -2
  3. zou/app/api.py +2 -0
  4. zou/app/blueprints/assets/__init__.py +22 -0
  5. zou/app/blueprints/assets/resources.py +241 -4
  6. zou/app/blueprints/auth/__init__.py +4 -0
  7. zou/app/blueprints/auth/resources.py +154 -22
  8. zou/app/blueprints/breakdown/resources.py +4 -4
  9. zou/app/blueprints/chats/__init__.py +22 -0
  10. zou/app/blueprints/chats/resources.py +199 -0
  11. zou/app/blueprints/comments/resources.py +36 -19
  12. zou/app/blueprints/crud/__init__.py +12 -0
  13. zou/app/blueprints/crud/attachment_file.py +14 -5
  14. zou/app/blueprints/crud/base.py +29 -28
  15. zou/app/blueprints/crud/chat.py +13 -0
  16. zou/app/blueprints/crud/chat_message.py +13 -0
  17. zou/app/blueprints/crud/comments.py +85 -29
  18. zou/app/blueprints/crud/custom_action.py +1 -1
  19. zou/app/blueprints/crud/day_off.py +47 -9
  20. zou/app/blueprints/crud/department.py +1 -25
  21. zou/app/blueprints/crud/entity.py +46 -5
  22. zou/app/blueprints/crud/entity_type.py +13 -1
  23. zou/app/blueprints/crud/event.py +1 -1
  24. zou/app/blueprints/crud/file_status.py +1 -1
  25. zou/app/blueprints/crud/metadata_descriptor.py +24 -10
  26. zou/app/blueprints/crud/organisation.py +22 -5
  27. zou/app/blueprints/crud/output_file.py +1 -1
  28. zou/app/blueprints/crud/output_type.py +1 -1
  29. zou/app/blueprints/crud/person.py +32 -24
  30. zou/app/blueprints/crud/playlist.py +1 -1
  31. zou/app/blueprints/crud/preview_background_file.py +6 -7
  32. zou/app/blueprints/crud/preview_file.py +1 -1
  33. zou/app/blueprints/crud/project.py +14 -6
  34. zou/app/blueprints/crud/project_status.py +1 -1
  35. zou/app/blueprints/crud/schedule_item.py +4 -2
  36. zou/app/blueprints/crud/software.py +1 -1
  37. zou/app/blueprints/crud/status_automation.py +1 -1
  38. zou/app/blueprints/crud/studio.py +33 -0
  39. zou/app/blueprints/crud/task.py +47 -3
  40. zou/app/blueprints/crud/task_status.py +1 -1
  41. zou/app/blueprints/crud/task_type.py +4 -4
  42. zou/app/blueprints/crud/working_file.py +4 -8
  43. zou/app/blueprints/events/resources.py +13 -12
  44. zou/app/blueprints/export/csv/assets.py +15 -6
  45. zou/app/blueprints/export/csv/edits.py +15 -5
  46. zou/app/blueprints/export/csv/playlists.py +1 -1
  47. zou/app/blueprints/export/csv/shots.py +15 -5
  48. zou/app/blueprints/export/csv/time_spents.py +1 -1
  49. zou/app/blueprints/files/resources.py +22 -23
  50. zou/app/blueprints/index/resources.py +38 -29
  51. zou/app/blueprints/news/resources.py +25 -11
  52. zou/app/blueprints/persons/__init__.py +5 -2
  53. zou/app/blueprints/persons/resources.py +126 -120
  54. zou/app/blueprints/previews/__init__.py +18 -8
  55. zou/app/blueprints/previews/resources.py +569 -328
  56. zou/app/blueprints/projects/resources.py +1 -1
  57. zou/app/blueprints/search/resources.py +18 -6
  58. zou/app/blueprints/shots/__init__.py +5 -0
  59. zou/app/blueprints/shots/resources.py +134 -4
  60. zou/app/blueprints/source/__init__.py +6 -6
  61. zou/app/blueprints/source/csv/assets.py +10 -3
  62. zou/app/blueprints/source/csv/base.py +1 -1
  63. zou/app/blueprints/source/csv/edits.py +10 -3
  64. zou/app/blueprints/source/csv/shots.py +10 -3
  65. zou/app/blueprints/source/{edl.py → otio.py} +82 -41
  66. zou/app/blueprints/tasks/__init__.py +3 -2
  67. zou/app/blueprints/tasks/resources.py +83 -52
  68. zou/app/blueprints/user/__init__.py +9 -0
  69. zou/app/blueprints/user/resources.py +170 -12
  70. zou/app/config.py +10 -0
  71. zou/app/mixin.py +6 -5
  72. zou/app/models/attachment_file.py +10 -4
  73. zou/app/models/base.py +18 -13
  74. zou/app/models/build_job.py +7 -4
  75. zou/app/models/chat.py +44 -0
  76. zou/app/models/chat_message.py +37 -0
  77. zou/app/models/comment.py +1 -0
  78. zou/app/models/day_off.py +3 -0
  79. zou/app/models/entity.py +4 -6
  80. zou/app/models/entity_type.py +2 -0
  81. zou/app/models/organisation.py +14 -15
  82. zou/app/models/person.py +6 -1
  83. zou/app/models/project.py +3 -0
  84. zou/app/models/search_filter.py +11 -0
  85. zou/app/models/search_filter_group.py +10 -0
  86. zou/app/models/serializer.py +17 -17
  87. zou/app/models/status_automation.py +2 -0
  88. zou/app/models/studio.py +13 -0
  89. zou/app/models/subscription.py +2 -2
  90. zou/app/models/task.py +6 -1
  91. zou/app/models/task_status.py +1 -0
  92. zou/app/models/task_type.py +1 -0
  93. zou/app/models/working_file.py +1 -1
  94. zou/app/services/assets_service.py +101 -14
  95. zou/app/services/auth_service.py +17 -44
  96. zou/app/services/breakdown_service.py +37 -5
  97. zou/app/services/chats_service.py +279 -0
  98. zou/app/services/comments_service.py +110 -65
  99. zou/app/services/concepts_service.py +4 -12
  100. zou/app/services/deletion_service.py +43 -30
  101. zou/app/services/edits_service.py +5 -11
  102. zou/app/services/emails_service.py +4 -4
  103. zou/app/services/entities_service.py +17 -2
  104. zou/app/services/events_service.py +12 -4
  105. zou/app/services/exception.py +5 -5
  106. zou/app/services/names_service.py +7 -2
  107. zou/app/services/news_service.py +17 -9
  108. zou/app/services/persons_service.py +38 -21
  109. zou/app/services/playlists_service.py +8 -7
  110. zou/app/services/preview_files_service.py +137 -10
  111. zou/app/services/projects_service.py +5 -14
  112. zou/app/services/shots_service.py +221 -49
  113. zou/app/services/sync_service.py +46 -42
  114. zou/app/services/tasks_service.py +185 -46
  115. zou/app/services/time_spents_service.py +67 -20
  116. zou/app/services/user_service.py +350 -107
  117. zou/app/stores/auth_tokens_store.py +2 -1
  118. zou/app/stores/file_store.py +18 -0
  119. zou/app/stores/publisher_store.py +7 -7
  120. zou/app/stores/queue_store.py +1 -0
  121. zou/app/swagger.py +36 -20
  122. zou/app/utils/cache.py +2 -0
  123. zou/app/utils/commands.py +104 -7
  124. zou/app/utils/csv_utils.py +1 -4
  125. zou/app/utils/date_helpers.py +33 -17
  126. zou/app/utils/dbhelpers.py +14 -1
  127. zou/app/utils/emails.py +2 -2
  128. zou/app/utils/fido.py +22 -0
  129. zou/app/utils/query.py +54 -6
  130. zou/app/utils/redis.py +11 -0
  131. zou/app/utils/saml.py +51 -0
  132. zou/app/utils/string.py +2 -0
  133. zou/app/utils/thumbnail.py +4 -2
  134. zou/cli.py +76 -18
  135. zou/debug.py +4 -2
  136. zou/event_stream.py +122 -165
  137. zou/job_settings.py +1 -0
  138. zou/migrations/env.py +0 -0
  139. zou/migrations/utils/base.py +6 -6
  140. zou/migrations/versions/1bb55759146f_add_table_studio.py +67 -0
  141. zou/migrations/versions/1fab8c420678_add_attachments_to_message_chats.py +56 -0
  142. zou/migrations/versions/23122f290ca2_add_entity_chat_models.py +149 -0
  143. zou/migrations/versions/32f134ff1201_add_is_shared_flag_to_filters.py +33 -0
  144. zou/migrations/versions/57222395f2be_add_statusautomation_import_last_revision.py +41 -0
  145. zou/migrations/versions/59a7445a966c_add_entity_is_shared.py +41 -0
  146. zou/migrations/versions/5b980f0dc365_add_comment_links.py +35 -0
  147. zou/migrations/versions/680c64565f9d_for_searchfiltergroup_is_shared.py +35 -0
  148. zou/migrations/versions/8e67c183bed7_add_preference_fields.py +71 -0
  149. zou/migrations/versions/92b40d79ad3f_allow_message_attachments.py +38 -0
  150. zou/migrations/versions/971dbf5a0faf_add_short_name_for_asset_type_entity_.py +33 -0
  151. zou/migrations/versions/9b85c14fa8a7_add_day_off_new_columns.py +68 -0
  152. zou/migrations/versions/9d3bb33c6fc6_add_department_keys_to_filter_models.py +73 -0
  153. zou/migrations/versions/a252a094e977_add_descriptions_for_entities_tasks_and_.py +40 -0
  154. zou/migrations/versions/be56dc0fb760_for_is_shared_disallow_nullable.py +102 -0
  155. zou/migrations/versions/ca28796a2a62_add_is_done_field_to_the_task_model.py +108 -0
  156. zou/migrations/versions/f344b867a911_for_description_of_entity_task_working_.py +75 -0
  157. zou/remote/config_payload.py +2 -1
  158. zou/utils/movie.py +14 -4
  159. {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/METADATA +75 -69
  160. {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/RECORD +163 -134
  161. {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/WHEEL +1 -1
  162. {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/LICENSE +0 -0
  163. {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/entry_points.txt +0 -0
  164. {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/top_level.txt +0 -0
@@ -13,14 +13,14 @@ from zou.app.services import (
13
13
  index_service,
14
14
  persons_service,
15
15
  )
16
- from zou.app.utils import permissions, auth
16
+ from zou.app.utils import permissions, auth, date_helpers
17
17
 
18
18
  from zou.app.blueprints.crud.base import BaseModelsResource, BaseModelResource
19
19
 
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
 
@@ -52,7 +52,7 @@ class PersonsResource(BaseModelsResource):
52
52
  for person in query.all()
53
53
  ]
54
54
 
55
- def check_read_permissions(self):
55
+ def check_read_permissions(self, options=None):
56
56
  return True
57
57
 
58
58
  def check_create_permissions(self, data):
@@ -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,32 +73,34 @@ 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:
93
91
  if (
94
- datetime.datetime.strptime(
95
- data["expiration_date"], "%Y-%m-%d"
92
+ date_helpers.get_date_from_string(
93
+ data["expiration_date"]
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
  )
100
+ except WrongParameterException:
101
+ raise
102
102
  except:
103
- raise ArgumentsException("Expiration date is not valid.")
103
+ raise WrongParameterException("Expiration date is not valid.")
104
104
  return data
105
105
 
106
106
  def update_data(self, data):
@@ -151,22 +151,23 @@ class PersonResource(BaseModelResource, ArgsMixin):
151
151
  data.pop("is_generated_from_ldap", None)
152
152
  data.pop("ldap_uid", None)
153
153
  data.pop("last_presence", None)
154
+ data.pop("studio_id", None)
154
155
 
155
156
  if "role" in data and data["role"] not in [
156
157
  role for role, _ in ROLE_TYPES
157
158
  ]:
158
- raise ArgumentsException("Invalid role")
159
+ raise WrongParameterException("Invalid role")
159
160
  if "contract_type" in data and data["contract_type"] not in [
160
161
  contract_type for contract_type, _ in CONTRACT_TYPES
161
162
  ]:
162
- raise ArgumentsException("Invalid contract_type")
163
+ raise WrongParameterException("Invalid contract_type")
163
164
  if "two_factor_authentication" in data and data[
164
165
  "two_factor_authentication"
165
166
  ] not in [
166
167
  two_factor_authentication
167
168
  for two_factor_authentication, _ in TWO_FACTOR_AUTHENTICATION_TYPES
168
169
  ]:
169
- raise ArgumentsException("Invalid two_factor_authentication")
170
+ raise WrongParameterException("Invalid two_factor_authentication")
170
171
 
171
172
  if "expiration_date" in data and data["expiration_date"] is not None:
172
173
  try:
@@ -176,11 +177,13 @@ class PersonResource(BaseModelResource, ArgsMixin):
176
177
  ).date()
177
178
  < datetime.date.today()
178
179
  ):
179
- raise ArgumentsException(
180
+ raise WrongParameterException(
180
181
  "Expiration date can't be in the past."
181
182
  )
183
+ except WrongParameterException:
184
+ raise
182
185
  except:
183
- raise ArgumentsException("Expiration date is not valid.")
186
+ raise WrongParameterException("Expiration date is not valid.")
184
187
  return data
185
188
 
186
189
  def check_delete_permissions(self, instance_dict):
@@ -203,14 +206,19 @@ class PersonResource(BaseModelResource, ArgsMixin):
203
206
  and not data.get("is_bot", False)
204
207
  and persons_service.is_user_limit_reached()
205
208
  ):
206
- raise ArgumentsException("User limit reached.")
209
+ raise WrongParameterException("User limit reached.")
207
210
  if (
208
- data.get("active") is False
209
- and instance_dict["email"] in config.PROTECTED_ACCOUNTS
211
+ instance_dict["email"] in config.PROTECTED_ACCOUNTS
212
+ and instance_dict["id"] != persons_service.get_current_user()["id"]
210
213
  ):
211
- raise PersonInProtectedAccounts(
212
- "Can't set this person as inactive it's a protected account."
213
- )
214
+ message = None
215
+ if data.get("active") is False:
216
+ message = "Can't set this person as inactive it's a protected account."
217
+ elif data.get("role") is not None:
218
+ message = "Can't change the role of this person it's a protected account."
219
+
220
+ if message is not None:
221
+ raise PersonInProtectedAccounts(message)
214
222
  return data
215
223
 
216
224
  def post_update(self, instance_dict, data):
@@ -9,7 +9,7 @@ class PlaylistsResource(BaseModelsResource):
9
9
  def __init__(self):
10
10
  BaseModelsResource.__init__(self, Playlist)
11
11
 
12
- def check_read_permissions(self):
12
+ def check_read_permissions(self, options=None):
13
13
  return True
14
14
 
15
15
  def check_create_permissions(self, playlist):
@@ -1,6 +1,6 @@
1
1
  from zou.app.models.preview_background_file import PreviewBackgroundFile
2
- from zou.app.services.exception import ArgumentsException
3
- from zou.app.services import files_service
2
+ from zou.app.services.exception import WrongParameterException
3
+ from zou.app.services import files_service, deletion_service
4
4
 
5
5
  from zou.app.blueprints.crud.base import BaseModelResource, BaseModelsResource
6
6
 
@@ -9,7 +9,7 @@ class PreviewBackgroundFilesResource(BaseModelsResource):
9
9
  def __init__(self):
10
10
  BaseModelsResource.__init__(self, PreviewBackgroundFile)
11
11
 
12
- def check_read_permissions(self):
12
+ def check_read_permissions(self, options=None):
13
13
  return True
14
14
 
15
15
  def update_data(self, data):
@@ -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
@@ -58,7 +58,6 @@ class PreviewBackgroundFileResource(BaseModelResource):
58
58
  return instance_dict
59
59
 
60
60
  def post_delete(self, instance_dict):
61
- # stop removing files for now
62
- # deletion_service.clear_preview_background_files(instance_dict["id"])
61
+ deletion_service.clear_preview_background_files(instance_dict["id"])
63
62
  files_service.clear_preview_background_file_cache(instance_dict["id"])
64
63
  return instance_dict
@@ -37,7 +37,7 @@ class PreviewFilesResource(BaseModelsResource):
37
37
 
38
38
  return query
39
39
 
40
- def check_read_permissions(self):
40
+ def check_read_permissions(self, options=None):
41
41
  return True
42
42
 
43
43
 
@@ -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):
@@ -31,7 +31,7 @@ class ProjectsResource(BaseModelsResource):
31
31
  else:
32
32
  return query.filter(user_service.build_related_projects_filter())
33
33
 
34
- def check_read_permissions(self):
34
+ def check_read_permissions(self, options=None):
35
35
  return True
36
36
 
37
37
  def check_creation_integrity(self, data):
@@ -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,9 @@ 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(
75
+ "Invalid preview_background_file_id"
76
+ )
75
77
  return data
76
78
 
77
79
  def post_creation(self, project):
@@ -131,7 +133,9 @@ class ProjectResource(BaseModelResource, ArgsMixin):
131
133
  data["preview_background_file_id"]
132
134
  not in preview_background_files_ids
133
135
  ):
134
- raise ArgumentsException("Invalid preview_background_file_id")
136
+ raise WrongParameterException(
137
+ "Invalid preview_background_file_id"
138
+ )
135
139
 
136
140
  return data
137
141
 
@@ -167,7 +171,7 @@ class ProjectResource(BaseModelResource, ArgsMixin):
167
171
  if data["production_style"] not in [
168
172
  type_name for type_name, _ in PROJECT_STYLES
169
173
  ]:
170
- raise ArgumentsException("Invalid production_style")
174
+ raise WrongParameterException("Invalid production_style")
171
175
  return data
172
176
 
173
177
  @jwt_required()
@@ -203,6 +207,8 @@ class ProjectTaskTypeLinksResource(Resource, ArgsMixin):
203
207
  ]
204
208
  )
205
209
 
210
+ user_service.check_manager_project_access(args["project_id"])
211
+
206
212
  task_type_link = projects_service.create_project_task_type_link(
207
213
  args["project_id"],
208
214
  args["task_type_id"],
@@ -230,6 +236,8 @@ class ProjectTaskStatusLinksResource(Resource, ArgsMixin):
230
236
  ]
231
237
  )
232
238
 
239
+ user_service.check_manager_project_access(args["project_id"])
240
+
233
241
  task_status_link = projects_service.create_project_task_status_link(
234
242
  args["project_id"],
235
243
  args["task_status_id"],
@@ -6,7 +6,7 @@ class ProjectStatussResource(BaseModelsResource):
6
6
  def __init__(self):
7
7
  BaseModelsResource.__init__(self, ProjectStatus)
8
8
 
9
- def check_read_permissions(self):
9
+ def check_read_permissions(self, options=None):
10
10
  return True
11
11
 
12
12
 
@@ -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,9 @@ 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(
21
+ "A similar schedule item already exists"
22
+ )
21
23
  return schedule_item
22
24
 
23
25
 
@@ -12,7 +12,7 @@ class SoftwaresResource(BaseModelsResource):
12
12
  def __init__(self):
13
13
  BaseModelsResource.__init__(self, Software)
14
14
 
15
- def check_read_permissions(self):
15
+ def check_read_permissions(self, options=None):
16
16
  return True
17
17
 
18
18
 
@@ -13,7 +13,7 @@ class StatusAutomationsResource(BaseModelsResource):
13
13
  def __init__(self):
14
14
  BaseModelsResource.__init__(self, StatusAutomation)
15
15
 
16
- def check_read_permissions(self):
16
+ def check_read_permissions(self, options=None):
17
17
  user_service.block_access_to_vendor()
18
18
  return True
19
19
 
@@ -0,0 +1,33 @@
1
+ from zou.app.models.studio import Studio
2
+
3
+ from zou.app.blueprints.crud.base import BaseModelsResource, BaseModelResource
4
+
5
+ from zou.app.services import tasks_service
6
+
7
+
8
+ class StudiosResource(BaseModelsResource):
9
+ def __init__(self):
10
+ BaseModelsResource.__init__(self, Studio)
11
+
12
+ def check_read_permissions(self, options=None):
13
+ return True
14
+
15
+ def post_creation(self, instance):
16
+ tasks_service.clear_studio_cache(str(instance.id))
17
+ return instance.serialize()
18
+
19
+
20
+ class StudioResource(BaseModelResource):
21
+ def __init__(self):
22
+ BaseModelResource.__init__(self, Studio)
23
+
24
+ def check_read_permissions(self, instance):
25
+ return True
26
+
27
+ def post_update(self, instance_dict, data):
28
+ tasks_service.clear_studio_cache(instance_dict["id"])
29
+ return instance_dict
30
+
31
+ def post_delete(self, instance_dict):
32
+ tasks_service.clear_studio_cache(instance_dict["id"])
33
+ return instance_dict
@@ -1,8 +1,11 @@
1
1
  from flask import request, current_app
2
2
  from flask_jwt_extended import jwt_required
3
3
 
4
+ from sqlalchemy.orm import aliased
4
5
  from sqlalchemy.exc import IntegrityError
6
+
5
7
  from zou.app.mixin import ArgsMixin
8
+ from zou.app.models.entity import Entity
6
9
  from zou.app.models.person import Person
7
10
  from zou.app.models.project import Project
8
11
  from zou.app.models.task import Task
@@ -21,11 +24,11 @@ from zou.app.services.exception import WrongTaskTypeForEntityException
21
24
  from zou.app.blueprints.crud.base import BaseModelsResource, BaseModelResource
22
25
 
23
26
 
24
- class TasksResource(BaseModelsResource):
27
+ class TasksResource(BaseModelsResource, ArgsMixin):
25
28
  def __init__(self):
26
29
  BaseModelsResource.__init__(self, Task)
27
30
 
28
- def check_read_permissions(self):
31
+ def check_read_permissions(self, options=None):
29
32
  return True
30
33
 
31
34
  def add_project_permission_filter(self, query):
@@ -37,6 +40,43 @@ class TasksResource(BaseModelsResource):
37
40
  )
38
41
  return query
39
42
 
43
+ def build_filters(self, options):
44
+ (
45
+ many_join_filter,
46
+ in_filter,
47
+ name_filter,
48
+ criterions,
49
+ ) = super().build_filters(options)
50
+ if "project_id" in criterions:
51
+ del criterions["project_id"]
52
+ if "episode_id" in criterions:
53
+ del criterions["episode_id"]
54
+ return (
55
+ many_join_filter,
56
+ in_filter,
57
+ name_filter,
58
+ criterions,
59
+ )
60
+
61
+ def apply_filters(self, query, options):
62
+ query = super().apply_filters(query, options)
63
+
64
+ project_id = options.get("project_id", None)
65
+ episode_id = options.get("episode_id", None)
66
+ if episode_id is not None:
67
+ Sequence = aliased(Entity)
68
+ query = (
69
+ query.join(Entity, Task.entity_id == Entity.id)
70
+ .join(Sequence, Entity.parent_id == Sequence.id)
71
+ .filter(Sequence.parent_id == episode_id)
72
+ )
73
+ elif project_id is not None:
74
+ query = query.join(Entity, Task.entity_id == Entity.id).filter(
75
+ Entity.project_id == project_id
76
+ )
77
+
78
+ return query
79
+
40
80
  def post(self):
41
81
  """
42
82
  Create a task with data given in the request body. JSON format is
@@ -74,8 +114,12 @@ class TasksResource(BaseModelsResource):
74
114
  if assignees is not None:
75
115
  instance.assignees = persons
76
116
  instance.save()
117
+ self.emit_create_event(instance.serialize())
77
118
 
78
- return tasks_service.get_task_with_relations(str(instance.id)), 201
119
+ return (
120
+ tasks_service.get_task(str(instance.id), relations=True),
121
+ 201,
122
+ )
79
123
 
80
124
  except TypeError as exception:
81
125
  current_app.logger.error(str(exception), exc_info=1)
@@ -7,7 +7,7 @@ class TaskStatusesResource(BaseModelsResource):
7
7
  def __init__(self):
8
8
  BaseModelsResource.__init__(self, TaskStatus)
9
9
 
10
- def check_read_permissions(self):
10
+ def check_read_permissions(self, options=None):
11
11
  return True
12
12
 
13
13
  def post_creation(self, instance):
@@ -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
@@ -9,7 +9,7 @@ class TaskTypesResource(BaseModelsResource):
9
9
  def __init__(self):
10
10
  BaseModelsResource.__init__(self, TaskType)
11
11
 
12
- def check_read_permissions(self):
12
+ def check_read_permissions(self, options=None):
13
13
  return True
14
14
 
15
15
  def update_data(self, data):
@@ -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
@@ -8,7 +8,7 @@ from zou.app.blueprints.crud.base import BaseModelsResource, BaseModelResource
8
8
  from zou.app.models.entity import Entity
9
9
  from zou.app.models.project import Project
10
10
  from zou.app.models.working_file import WorkingFile
11
- from zou.app.services import user_service, tasks_service, files_service
11
+ from zou.app.services import user_service, files_service
12
12
  from zou.app.utils import permissions
13
13
 
14
14
 
@@ -16,7 +16,7 @@ class WorkingFilesResource(BaseModelsResource):
16
16
  def __init__(self):
17
17
  BaseModelsResource.__init__(self, WorkingFile)
18
18
 
19
- def check_read_permissions(self):
19
+ def check_read_permissions(self, options=None):
20
20
  """
21
21
  Overriding so that people without admin credentials can still access
22
22
  this resource.
@@ -46,16 +46,12 @@ class WorkingFileResource(BaseModelResource):
46
46
 
47
47
  def check_read_permissions(self, instance):
48
48
  working_file = files_service.get_working_file(instance["id"])
49
- task = tasks_service.get_task(working_file["task_id"])
50
- user_service.check_project_access(task["project_id"])
51
- user_service.check_entity_access(task["entity_id"])
49
+ user_service.check_task_access(working_file["task_id"])
52
50
  return True
53
51
 
54
52
  def check_update_permissions(self, instance, data):
55
53
  working_file = files_service.get_working_file(instance["id"])
56
- task = tasks_service.get_task(working_file["task_id"])
57
- user_service.check_project_access(task["project_id"])
58
- user_service.check_entity_access(task["entity_id"])
54
+ user_service.check_task_access(working_file["task_id"])
59
55
  return True
60
56
 
61
57
  @jwt_required()
@@ -2,7 +2,7 @@ from flask_restful import Resource
2
2
  from flask_jwt_extended import jwt_required
3
3
 
4
4
  from zou.app.mixin import ArgsMixin
5
- from zou.app.utils import fields, permissions
5
+ from zou.app.utils import fields, permissions, date_helpers
6
6
 
7
7
  from zou.app.services import events_service
8
8
  from zou.app.services.exception import WrongParameterException
@@ -32,7 +32,7 @@ class EventsResource(Resource, ArgsMixin):
32
32
  type: boolean
33
33
  default: False
34
34
  - in: query
35
- name: page_size
35
+ name: limit
36
36
  type: integer
37
37
  default: 100
38
38
  x-example: 100
@@ -50,17 +50,19 @@ class EventsResource(Resource, ArgsMixin):
50
50
  ("after", None, False),
51
51
  ("before", None, False),
52
52
  ("only_files", False, False),
53
- ("page_size", 100, False),
53
+ ("limit", 100, False),
54
54
  ("project_id", None, False),
55
+ ("name", None, False),
55
56
  ],
56
57
  )
57
58
 
58
59
  permissions.check_manager_permissions()
59
60
  before = self.parse_date_parameter(args["before"])
60
61
  after = self.parse_date_parameter(args["after"])
61
- page_size = args["page_size"]
62
+ limit = args["limit"]
62
63
  only_files = args["only_files"] == "true"
63
64
  project_id = args.get("project_id", None)
65
+ name = args["name"]
64
66
  if project_id is not None and not fields.is_valid_id(project_id):
65
67
  raise WrongParameterException(
66
68
  "The project_id parameter is not a valid id"
@@ -69,9 +71,10 @@ class EventsResource(Resource, ArgsMixin):
69
71
  return events_service.get_last_events(
70
72
  after=after,
71
73
  before=before,
72
- page_size=page_size,
74
+ limit=limit,
73
75
  only_files=only_files,
74
76
  project_id=project_id,
77
+ name=name,
75
78
  )
76
79
 
77
80
 
@@ -90,20 +93,18 @@ class LoginLogsResource(Resource, ArgsMixin):
90
93
  format: date
91
94
  x-example: "2022-07-12T00:00:00"
92
95
  - in: query
93
- name: page_size
96
+ name: limit
94
97
  type: integer
95
98
  x-example: 100
96
99
  responses:
97
100
  200:
98
101
  description: All login logs
99
102
  """
100
- args = self.get_args(["before", ("page_size", 100)])
103
+ args = self.get_args(["before", ("limit", 100)])
101
104
 
102
105
  permissions.check_manager_permissions()
103
106
  before = None
104
107
  if args["before"] is not None:
105
- before = fields.get_date_object(
106
- args["before"], "%Y-%m-%dT%H:%M:%S"
107
- )
108
- page_size = args["page_size"]
109
- return events_service.get_last_login_logs(before, page_size)
108
+ before = date_helpers.get_datetime_from_string(args["before"])
109
+ limit = args["limit"]
110
+ return events_service.get_last_login_logs(before, limit)
@@ -65,7 +65,7 @@ class AssetsCsvExport(Resource):
65
65
  def build_headers(self, metadata_infos, validation_columns):
66
66
  headers = ["Project", "Type", "Name", "Description", "Time Spent"]
67
67
 
68
- metadata_headers = [name for (name, _) in metadata_infos]
68
+ metadata_headers = [name for (name, _, _) in metadata_infos]
69
69
 
70
70
  validation_assignations_columns = []
71
71
  for validation_column in validation_columns:
@@ -97,10 +97,15 @@ class AssetsCsvExport(Resource):
97
97
  for person_id in task["assignees"]
98
98
  ]
99
99
  )
100
-
101
- for _, field_name in metadata_infos:
102
- result_metadata = result.get("data", {}) or {}
103
- row.append(result_metadata.get(field_name, ""))
100
+ result_data = result.get("data", {}) or {}
101
+ for _, field_name, data_type in metadata_infos:
102
+ result_metadata = result_data.get(field_name, "")
103
+ if data_type == "boolean":
104
+ row.append(
105
+ "true" if result_metadata.lower() == "true" else "false"
106
+ )
107
+ else:
108
+ row.append(result_metadata)
104
109
 
105
110
  for column in validation_columns:
106
111
  if column in task_map:
@@ -153,7 +158,11 @@ class AssetsCsvExport(Resource):
153
158
  ]
154
159
 
155
160
  columns = [
156
- (descriptor["name"], descriptor["field_name"])
161
+ (
162
+ descriptor["name"],
163
+ descriptor["field_name"],
164
+ descriptor["data_type"],
165
+ )
157
166
  for descriptor in descriptors
158
167
  ]
159
168