zou 0.19.55__py3-none-any.whl → 0.19.57__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 CHANGED
@@ -1 +1 @@
1
- __version__ = "0.19.55"
1
+ __version__ = "0.19.57"
@@ -116,7 +116,9 @@ class ChatMessagesResource(Resource):
116
116
 
117
117
  chat = chats_service.get_chat(entity_id)
118
118
  if person["id"] not in chat["participants"]:
119
- raise WrongParameterException("You are not a participant of this chat")
119
+ raise WrongParameterException(
120
+ "You are not a participant of this chat"
121
+ )
120
122
 
121
123
  return (
122
124
  chats_service.create_chat_message(
@@ -21,7 +21,9 @@ class DayOffsResource(BaseModelsResource):
21
21
  if time_spents_service.get_day_offs_between(
22
22
  data["date"], data["end_date"], data["person_id"]
23
23
  ):
24
- raise WrongParameterException("Day off already exists for this period")
24
+ raise WrongParameterException(
25
+ "Day off already exists for this period"
26
+ )
25
27
  return data
26
28
 
27
29
  def post_creation(self, instance):
@@ -67,5 +69,7 @@ class DayOffResource(BaseModelResource):
67
69
  data.get("person_id", instance_dict["person_id"]),
68
70
  exclude_id=instance_dict["id"],
69
71
  ):
70
- raise WrongParameterException("Day off already exists for this period")
72
+ raise WrongParameterException(
73
+ "Day off already exists for this period"
74
+ )
71
75
  return data
@@ -7,7 +7,6 @@ from zou.app.services import entities_service, assets_service
7
7
  from zou.app.services.exception import WrongParameterException
8
8
 
9
9
 
10
-
11
10
  class EntityTypesResource(BaseModelsResource):
12
11
  def __init__(self):
13
12
  BaseModelsResource.__init__(self, EntityType)
@@ -32,11 +31,9 @@ class EntityTypesResource(BaseModelsResource):
32
31
  return instance.serialize(relations=True)
33
32
 
34
33
  def check_creation_integrity(self, data):
35
- entity_type = (
36
- EntityType.query
37
- .filter(EntityType.name.ilike(data.get("name", "")))
38
- .first()
39
- )
34
+ entity_type = EntityType.query.filter(
35
+ EntityType.name.ilike(data.get("name", ""))
36
+ ).first()
40
37
  if entity_type is not None:
41
38
  raise WrongParameterException(
42
39
  "Entity type with this name already exists"
@@ -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 WrongParameterException("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 WrongParameterException("Invalid preview_background_file_id")
136
+ raise WrongParameterException(
137
+ "Invalid preview_background_file_id"
138
+ )
135
139
 
136
140
  return data
137
141
 
@@ -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 WrongParameterException("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
 
@@ -100,7 +100,7 @@ class PlaylistCsvExport(Resource):
100
100
 
101
101
  def build_row(self, shot):
102
102
  entity = entities_service.get_entity(shot["entity_id"])
103
- name, _ = names_service.get_full_entity_name(shot["entity_id"])
103
+ name, _, _ = names_service.get_full_entity_name(shot["entity_id"])
104
104
  preview_file = files_service.get_preview_file(shot["preview_file_id"])
105
105
  task = tasks_service.get_task(preview_file["task_id"])
106
106
  task_type = self.task_type_map[task["task_type_id"]]
@@ -72,7 +72,7 @@ class TimeSpentsCsvExport(BaseCsvExport):
72
72
  person_last_name,
73
73
  ) = time_spent_row
74
74
  if entity_type_name == "Shot":
75
- entity_name, _ = names_service.get_full_entity_name(entity_id)
75
+ entity_name, _, _ = names_service.get_full_entity_name(entity_id)
76
76
 
77
77
  date = ""
78
78
  if time_spent.date is not None:
@@ -65,6 +65,7 @@ ALLOWED_FILE_EXTENSION = [
65
65
  "glb",
66
66
  "gltf",
67
67
  "hip",
68
+ "kra",
68
69
  "ma",
69
70
  "mb",
70
71
  "mp3",
@@ -73,6 +74,8 @@ ALLOWED_FILE_EXTENSION = [
73
74
  "psd",
74
75
  "psb",
75
76
  "rar",
77
+ "sai",
78
+ "sai2",
76
79
  "sbbkp",
77
80
  "svg",
78
81
  "swf",
@@ -33,6 +33,7 @@ from zou.app.blueprints.user.resources import (
33
33
  FilterGroupResource,
34
34
  FilterGroupsResource,
35
35
  DesktopLoginLogsResource,
36
+ MarkAllNotificationsAsReadResource,
36
37
  NotificationsResource,
37
38
  NotificationResource,
38
39
  HasTaskSubscribedResource,
@@ -108,6 +109,10 @@ routes = [
108
109
  "/actions/user/sequences/<sequence_id>/task-types/<task_type_id>/unsubscribe",
109
110
  SequenceUnsubscribeResource,
110
111
  ),
112
+ (
113
+ "/actions/user/notifications/mark-all-as-read",
114
+ MarkAllNotificationsAsReadResource,
115
+ ),
111
116
  ]
112
117
 
113
118
  blueprint = Blueprint("user", "user")
@@ -1,4 +1,4 @@
1
- from flask import abort
1
+ from flask import abort, request
2
2
  from flask_restful import Resource
3
3
 
4
4
  from zou.app.mixin import ArgsMixin
@@ -593,7 +593,6 @@ class FilterResource(Resource, ArgsMixin):
593
593
  ("project_id", None, None),
594
594
  ]
595
595
  )
596
-
597
596
  data = self.clear_empty_fields(
598
597
  data, ignored_fields=["search_filter_group_id"]
599
598
  )
@@ -848,13 +847,22 @@ class NotificationsResource(Resource, ArgsMixin):
848
847
  task_status_id,
849
848
  notification_type,
850
849
  ) = self.get_arguments()
850
+
851
+ read = None
852
+ if request.args.get("read", None) is not None:
853
+ read = self.get_bool_parameter("read")
854
+ watching = None
855
+ if request.args.get("watching", None) is not None:
856
+ watching = self.get_bool_parameter("watching")
857
+ print("watching", watching)
851
858
  notifications = user_service.get_last_notifications(
852
859
  before=before,
853
860
  task_type_id=task_type_id,
854
861
  task_status_id=task_status_id,
855
862
  notification_type=notification_type,
863
+ read=read,
864
+ watching=watching,
856
865
  )
857
- user_service.mark_notifications_as_read()
858
866
  return notifications
859
867
 
860
868
  def get_arguments(self):
@@ -867,7 +875,7 @@ class NotificationsResource(Resource, ArgsMixin):
867
875
  )
868
876
 
869
877
 
870
- class NotificationResource(Resource):
878
+ class NotificationResource(Resource, ArgsMixin):
871
879
  """
872
880
  Return notification matching given id, only if it's a notification that
873
881
  belongs to current user.
@@ -894,6 +902,42 @@ class NotificationResource(Resource):
894
902
  """
895
903
  return user_service.get_notification(notification_id)
896
904
 
905
+ def put(self, notification_id):
906
+ """
907
+ Change notification read status.
908
+ ---
909
+ tags:
910
+ - User
911
+ parameters:
912
+ - in: path
913
+ name: notification_id
914
+ required: True
915
+ type: string
916
+ format: UUID
917
+ x-example: a24a6ea4-ce75-4665-a070-57453082c25
918
+ responses:
919
+ 200:
920
+ description: Notification
921
+ """
922
+ data = self.get_args([("read", None, False, bool)])
923
+ return user_service.update_notification(notification_id, data["read"])
924
+
925
+
926
+ class MarkAllNotificationsAsReadResource(Resource):
927
+
928
+ def post(self):
929
+ """
930
+ Mark all notifications as read for the current user.
931
+ ---
932
+ tags:
933
+ - User
934
+ responses:
935
+ 200:
936
+ description: All notifications marked as read
937
+ """
938
+ user_service.mark_notifications_as_read()
939
+ return {"success": True}
940
+
897
941
 
898
942
  class HasTaskSubscribedResource(Resource):
899
943
  """
@@ -905,7 +949,7 @@ class HasTaskSubscribedResource(Resource):
905
949
  Return true if current user has subscribed to given task.
906
950
  ---
907
951
  tags:
908
- - User
952
+ - User
909
953
  parameters:
910
954
  - in: path
911
955
  name: task_id
@@ -14,10 +14,13 @@ class Organisation(db.Model, BaseMixin, SerializerMixin):
14
14
  has_avatar = db.Column(db.Boolean(), default=False)
15
15
  use_original_file_name = db.Column(db.Boolean(), default=False)
16
16
  timesheets_locked = db.Column(db.Boolean(), default=False)
17
+ format_duration_in_hours = db.Column(db.Boolean(), default=False)
17
18
  hd_by_default = db.Column(db.Boolean(), default=False)
18
19
  chat_token_slack = db.Column(db.String(80), default="")
19
20
  chat_webhook_mattermost = db.Column(db.String(80), default="")
20
21
  chat_token_discord = db.Column(db.String(80), default="")
22
+ dark_theme_by_default = db.Column(db.Boolean(), default=False)
23
+ format_duration_in_hours = db.Column(db.Boolean(), default=False)
21
24
 
22
25
  def present(self):
23
26
  return fields.serialize_dict(
@@ -32,6 +35,8 @@ class Organisation(db.Model, BaseMixin, SerializerMixin):
32
35
  "hd_by_default": self.hd_by_default,
33
36
  "use_original_file_name": self.use_original_file_name,
34
37
  "timesheets_locked": self.timesheets_locked,
38
+ "dark_theme_by_default": self.dark_theme_by_default,
39
+ "format_duration_in_hours": self.format_duration_in_hours,
35
40
  "updated_at": self.updated_at,
36
41
  "created_at": self.created_at,
37
42
  }
zou/app/models/project.py CHANGED
@@ -142,6 +142,9 @@ class Project(db.Model, BaseMixin, SerializerMixin):
142
142
  is_preview_download_allowed = db.Column(db.Boolean(), default=False)
143
143
  is_set_preview_automated = db.Column(db.Boolean(), default=False)
144
144
  homepage = db.Column(db.String(80), default="assets")
145
+ is_publish_default_for_artists = db.Column(db.Boolean(), default=False)
146
+ hd_bitrate_compression = db.Column(db.Integer, default=28)
147
+ ld_bitrate_compression = db.Column(db.Integer, default=6)
145
148
 
146
149
  project_status_id = db.Column(
147
150
  UUIDType(binary=False), db.ForeignKey("project_status.id"), index=True
@@ -22,10 +22,10 @@ class Subscription(db.Model, BaseMixin, SerializerMixin):
22
22
 
23
23
  entity_id = db.Column(
24
24
  UUIDType(binary=False), db.ForeignKey("entity.id"), index=True
25
- )
25
+ ) # Deprecated
26
26
  task_type_id = db.Column(
27
27
  UUIDType(binary=False), db.ForeignKey("task_type.id"), index=True
28
- )
28
+ ) # Deprecated
29
29
 
30
30
  __table_args__ = (
31
31
  db.UniqueConstraint(
zou/app/models/task.py CHANGED
@@ -33,6 +33,7 @@ class Task(db.Model, BaseMixin, SerializerMixin):
33
33
  description = db.Column(db.Text())
34
34
 
35
35
  priority = db.Column(db.Integer, default=0)
36
+ difficulty = db.Column(db.Integer, default=3, nullable=False)
36
37
  duration = db.Column(db.Float, default=0)
37
38
  estimation = db.Column(db.Float, default=0)
38
39
  completion_rate = db.Column(db.Integer, default=0)
@@ -70,6 +71,9 @@ class Task(db.Model, BaseMixin, SerializerMixin):
70
71
  db.UniqueConstraint(
71
72
  "name", "project_id", "task_type_id", "entity_id", name="task_uc"
72
73
  ),
74
+ db.CheckConstraint(
75
+ "difficulty > 0 AND difficulty < 6", name="check_difficulty"
76
+ ),
73
77
  )
74
78
 
75
79
  def assignees_as_string(self):
@@ -104,8 +104,8 @@ def get_assets(criterions={}, is_admin=False):
104
104
 
105
105
  if "is_shared" in criterions:
106
106
  if not is_admin:
107
- query = (
108
- query.join(Project).filter(user_service.build_team_filter())
107
+ query = query.join(Project).filter(
108
+ user_service.build_team_filter()
109
109
  )
110
110
 
111
111
  if episode_id is not None:
@@ -127,7 +127,7 @@ def get_assets(criterions={}, is_admin=False):
127
127
  result += [a for a in query.all() if a.source_id != episode_id]
128
128
  else:
129
129
  result = query.all()
130
- return EntityType.serialize_list(result, obj_type="Asset")
130
+ return Entity.serialize_list(result, obj_type="Asset")
131
131
 
132
132
 
133
133
  def get_all_raw_assets():
@@ -202,6 +202,7 @@ def get_assets_and_tasks(criterions={}, page=1, with_episode_ids=False):
202
202
  Task.due_date,
203
203
  Task.done_date,
204
204
  Task.last_comment_date,
205
+ Task.difficulty,
205
206
  assignees_table.columns.person,
206
207
  ).order_by(EntityType.name, Entity.name)
207
208
 
@@ -281,6 +282,7 @@ def get_assets_and_tasks(criterions={}, page=1, with_episode_ids=False):
281
282
  task_due_date,
282
283
  task_done_date,
283
284
  task_last_comment_date,
285
+ task_difficulty,
284
286
  person_id,
285
287
  ) in query_result:
286
288
  if asset.source_id is None:
@@ -338,6 +340,7 @@ def get_assets_and_tasks(criterions={}, page=1, with_episode_ids=False):
338
340
  ),
339
341
  "retake_count": task_retake_count,
340
342
  "start_date": fields.serialize_value(task_start_date),
343
+ "difficulty": task_difficulty,
341
344
  "task_status_id": str(task_status_id),
342
345
  "task_type_id": str(task_type_id),
343
346
  "assignees": [],
@@ -722,7 +725,7 @@ def set_shared_assets(
722
725
  project_id=None,
723
726
  asset_type_id=None,
724
727
  asset_ids=None,
725
- with_events=False
728
+ with_events=False,
726
729
  ):
727
730
  """
728
731
  Set all assets of a project to is_shared=True or False.
@@ -213,7 +213,7 @@ def get_chats_for_person(person_id):
213
213
  result = []
214
214
  for chat_model, project_id, preview_file_id in chats:
215
215
  chat = chat_model.present()
216
- chat["entity_name"], _ = names_service.get_full_entity_name(
216
+ chat["entity_name"], _, _ = names_service.get_full_entity_name(
217
217
  chat["object_id"]
218
218
  )
219
219
  chat["project_id"] = project_id
@@ -296,7 +296,7 @@ def get_task_descriptors(person_id, task):
296
296
  project = projects_service.get_project(task["project_id"])
297
297
  task_type = tasks_service.get_task_type(task["task_type_id"])
298
298
  entity = entities_service.get_entity(task["entity_id"])
299
- (entity_name, episode_id) = names_service.get_full_entity_name(
299
+ entity_name, episode_id, _ = names_service.get_full_entity_name(
300
300
  entity["id"]
301
301
  )
302
302
 
@@ -242,6 +242,7 @@ def get_entities_and_tasks(criterions={}):
242
242
  Task.due_date,
243
243
  Task.done_date,
244
244
  Task.last_comment_date,
245
+ Task.difficulty,
245
246
  assignees_table.columns.person,
246
247
  )
247
248
  )
@@ -272,6 +273,7 @@ def get_entities_and_tasks(criterions={}):
272
273
  task_due_date,
273
274
  task_done_date,
274
275
  task_last_comment_date,
276
+ task_difficulty,
275
277
  person_id,
276
278
  ) in query.all():
277
279
  entity_id = str(entity.id)
@@ -315,6 +317,7 @@ def get_entities_and_tasks(criterions={}):
315
317
  "real_start_date": task_real_start_date,
316
318
  "retake_count": task_retake_count,
317
319
  "start_date": task_start_date,
320
+ "difficulty": task_difficulty,
318
321
  "task_status_id": str(task_status_id),
319
322
  "task_type_id": str(task_type_id),
320
323
  "assignees": [],
@@ -52,7 +52,7 @@ def get_full_entity_name(entity_id):
52
52
  asset_type = entities_service.get_entity_type(entity["entity_type_id"])
53
53
  episode_id = entity["source_id"]
54
54
  name = "%s / %s" % (asset_type["name"], entity["name"])
55
- return (name, episode_id)
55
+ return (name, episode_id, entity["preview_file_id"])
56
56
 
57
57
 
58
58
  def get_preview_file_name(preview_file_id):
@@ -66,7 +66,7 @@ def get_preview_file_name(preview_file_id):
66
66
  task = tasks_service.get_task(preview_file["task_id"])
67
67
  task_type = tasks_service.get_task_type(task["task_type_id"])
68
68
  project = projects_service.get_project(task["project_id"])
69
- (entity_name, _) = get_full_entity_name(task["entity_id"])
69
+ (entity_name, _, _) = get_full_entity_name(task["entity_id"])
70
70
 
71
71
  if (
72
72
  organisation["use_original_file_name"]
@@ -185,7 +185,7 @@ def get_last_news_for_project(
185
185
  preview_file_annotations,
186
186
  entity_preview_file_id,
187
187
  ) in news_list:
188
- (full_entity_name, episode_id) = names_service.get_full_entity_name(
188
+ full_entity_name, episode_id, _ = names_service.get_full_entity_name(
189
189
  task_entity_id
190
190
  )
191
191
 
@@ -561,7 +561,7 @@ def get_running_preview_files():
561
561
  result = preview_file.serialize()
562
562
  result["project_id"] = fields.serialize_value(project_id)
563
563
  result["task_type_id"] = fields.serialize_value(task_type_id)
564
- (result["full_entity_name"], _) = names_service.get_full_entity_name(
564
+ result["full_entity_name"], _, _ = names_service.get_full_entity_name(
565
565
  entity_id
566
566
  )
567
567
  results.append(result)
@@ -254,6 +254,7 @@ def get_shots_and_tasks(criterions={}):
254
254
  Task.done_date,
255
255
  Task.last_comment_date,
256
256
  Task.nb_assets_ready,
257
+ Task.difficulty,
257
258
  assignees_table.columns.person,
258
259
  Project.id,
259
260
  Project.name,
@@ -304,6 +305,7 @@ def get_shots_and_tasks(criterions={}):
304
305
  task_done_date,
305
306
  task_last_comment_date,
306
307
  task_nb_assets_ready,
308
+ task_difficulty,
307
309
  person_id,
308
310
  project_id,
309
311
  project_name,
@@ -367,6 +369,7 @@ def get_shots_and_tasks(criterions={}):
367
369
  "real_start_date": task_real_start_date,
368
370
  "retake_count": task_retake_count,
369
371
  "start_date": task_start_date,
372
+ "difficulty": task_difficulty,
370
373
  "task_status_id": task_status_id,
371
374
  "task_type_id": task_type_id,
372
375
  "assignees": [],
@@ -1478,7 +1481,7 @@ def get_weighted_quota_shots_between(
1478
1481
  for entity, task_duration, duration in query_shots:
1479
1482
  shot = entity.serialize()
1480
1483
  if shot["id"] not in already_listed:
1481
- full_name, _ = names_service.get_full_entity_name(shot["id"])
1484
+ full_name, _, _ = names_service.get_full_entity_name(shot["id"])
1482
1485
  shot["full_name"] = full_name
1483
1486
  shot["weight"] = round(duration / task_duration, 2) or 0
1484
1487
  shots.append(shot)
@@ -1525,7 +1528,7 @@ def get_weighted_quota_shots_between(
1525
1528
  business_days = (
1526
1529
  date_helpers.get_business_days(task_start, task_end) + 1
1527
1530
  )
1528
- full_name, _ = names_service.get_full_entity_name(shot["id"])
1531
+ full_name, _, _ = names_service.get_full_entity_name(shot["id"])
1529
1532
  shot["full_name"] = full_name
1530
1533
  multiplicator = 1
1531
1534
  if task_start >= start and task_end <= end:
@@ -1583,7 +1586,7 @@ def get_raw_quota_shots_between(
1583
1586
 
1584
1587
  for entity in query_shots:
1585
1588
  shot = entity.serialize()
1586
- full_name, _ = names_service.get_full_entity_name(shot["id"])
1589
+ full_name, _, _ = names_service.get_full_entity_name(shot["id"])
1587
1590
  shot["full_name"] = full_name
1588
1591
  shot["weight"] = 1
1589
1592
  shots.append(shot)
@@ -9,6 +9,7 @@ from zou.app.models.notification import Notification
9
9
  from zou.app.models.person import Person
10
10
  from zou.app.models.project import Project
11
11
  from zou.app.models.project_status import ProjectStatus
12
+ from zou.app.models.subscription import Subscription
12
13
  from zou.app.models.search_filter import SearchFilter
13
14
  from zou.app.models.search_filter_group import SearchFilterGroup
14
15
  from zou.app.models.task import Task
@@ -962,6 +963,9 @@ def update_filter(search_filter_id, data):
962
963
  search_filter = SearchFilter.get_by(
963
964
  id=search_filter_id, person_id=current_user["id"]
964
965
  )
966
+ if current_user["role"] == "admin" and search_filter is None:
967
+ search_filter = SearchFilter.get_by(id=search_filter_id)
968
+
965
969
  if search_filter is None:
966
970
  raise SearchFilterNotFoundException
967
971
 
@@ -1182,6 +1186,18 @@ def get_notification(notification_id):
1182
1186
  return notifications[0]
1183
1187
 
1184
1188
 
1189
+ def update_notification(notification_id, read):
1190
+ """
1191
+ Update read status of given notification.
1192
+ """
1193
+ current_user = persons_service.get_current_user()
1194
+ notification = Notification.get_by(
1195
+ id=notification_id, person_id=current_user["id"]
1196
+ )
1197
+ notification.update({"read": read})
1198
+ return notification.serialize()
1199
+
1200
+
1185
1201
  def get_unread_notifications_count(notification_id=None):
1186
1202
  """
1187
1203
  Return the number of unread notifications.
@@ -1192,6 +1208,9 @@ def get_unread_notifications_count(notification_id=None):
1192
1208
  ).count()
1193
1209
 
1194
1210
 
1211
+ from sqlalchemy import and_, func
1212
+
1213
+
1195
1214
  def get_last_notifications(
1196
1215
  notification_id=None,
1197
1216
  after=None,
@@ -1199,6 +1218,8 @@ def get_last_notifications(
1199
1218
  task_type_id=None,
1200
1219
  task_status_id=None,
1201
1220
  notification_type=None,
1221
+ read=None,
1222
+ watching=None,
1202
1223
  ):
1203
1224
  """
1204
1225
  Return last 100 user notifications.
@@ -1213,6 +1234,13 @@ def get_last_notifications(
1213
1234
  .join(Author, Author.id == Notification.author_id)
1214
1235
  .join(Task, Task.id == Notification.task_id)
1215
1236
  .join(Project, Project.id == Task.project_id)
1237
+ .outerjoin(
1238
+ Subscription,
1239
+ and_(
1240
+ Subscription.task_id == Task.id,
1241
+ Subscription.person_id == current_user["id"],
1242
+ ),
1243
+ )
1216
1244
  .outerjoin(Comment, Comment.id == Notification.comment_id)
1217
1245
  .add_columns(
1218
1246
  Project.id,
@@ -1223,6 +1251,7 @@ def get_last_notifications(
1223
1251
  Comment.text,
1224
1252
  Comment.replies,
1225
1253
  Task.entity_id,
1254
+ Subscription.id,
1226
1255
  Author.role,
1227
1256
  )
1228
1257
  )
@@ -1251,6 +1280,16 @@ def get_last_notifications(
1251
1280
  if notification_type is not None:
1252
1281
  query = query.filter(Notification.type == notification_type)
1253
1282
 
1283
+ if read is not None:
1284
+ query = query.filter(Notification.read == read)
1285
+
1286
+ if watching is not None:
1287
+ print(watching)
1288
+ if watching:
1289
+ query = query.filter(Subscription.id != None)
1290
+ else:
1291
+ query = query.filter(Subscription.id == None)
1292
+
1254
1293
  notifications = query.limit(100).all()
1255
1294
 
1256
1295
  for (
@@ -1263,10 +1302,11 @@ def get_last_notifications(
1263
1302
  comment_text,
1264
1303
  comment_replies,
1265
1304
  task_entity_id,
1305
+ subscription_id,
1266
1306
  role,
1267
1307
  ) in notifications:
1268
- (full_entity_name, episode_id) = names_service.get_full_entity_name(
1269
- task_entity_id
1308
+ (full_entity_name, episode_id, entity_preview_file_id) = (
1309
+ names_service.get_full_entity_name(task_entity_id)
1270
1310
  )
1271
1311
  preview_file_id = None
1272
1312
  mentions = []
@@ -1326,6 +1366,8 @@ def get_last_notifications(
1326
1366
  "change": notification.change,
1327
1367
  "full_entity_name": full_entity_name,
1328
1368
  "episode_id": episode_id,
1369
+ "entity_preview_file_id": entity_preview_file_id,
1370
+ "subscription_id": subscription_id,
1329
1371
  }
1330
1372
  )
1331
1373
  )
@@ -1338,17 +1380,21 @@ def mark_notifications_as_read():
1338
1380
  Mark all recent notifications for current_user as read. It is useful
1339
1381
  to mark a list of notifications as read after an user retrieved them.
1340
1382
  """
1383
+ from sqlalchemy import update
1384
+ from zou.app import db
1385
+
1341
1386
  current_user = persons_service.get_current_user()
1342
- notifications = (
1343
- Notification.query.filter_by(person_id=current_user["id"], read=False)
1344
- .order_by(Notification.created_at)
1345
- .all()
1387
+ update_stmt = (
1388
+ update(Notification)
1389
+ .where(Notification.person_id == current_user["id"])
1390
+ .where(Notification.read == False)
1391
+ .values(read=True)
1346
1392
  )
1347
1393
 
1348
- for notification in notifications:
1349
- notification.update({"read": True})
1394
+ db.session.execute(update_stmt)
1395
+ db.session.commit()
1350
1396
 
1351
- return fields.serialize_list(notifications)
1397
+ return True
1352
1398
 
1353
1399
 
1354
1400
  def has_task_subscription(task_id):
@@ -0,0 +1,71 @@
1
+ """add prefeence fields
2
+
3
+ Revision ID: 8e67c183bed7
4
+ Revises: 59a7445a966c
5
+ Create Date: 2024-09-26 10:48:45.678791
6
+
7
+ """
8
+
9
+ from alembic import op
10
+ import sqlalchemy as sa
11
+
12
+
13
+ # revision identifiers, used by Alembic.
14
+ revision = "8e67c183bed7"
15
+ down_revision = "59a7445a966c"
16
+ branch_labels = None
17
+ depends_on = None
18
+
19
+
20
+ def upgrade():
21
+ # ### commands auto generated by Alembic - please adjust! ###
22
+ with op.batch_alter_table("organisation", schema=None) as batch_op:
23
+ batch_op.add_column(
24
+ sa.Column("dark_theme_by_default", sa.Boolean(), nullable=True)
25
+ )
26
+ batch_op.add_column(
27
+ sa.Column("format_duration_in_hours", sa.Boolean(), nullable=True)
28
+ )
29
+
30
+ with op.batch_alter_table("project", schema=None) as batch_op:
31
+ batch_op.add_column(
32
+ sa.Column(
33
+ "is_publish_default_for_artists", sa.Boolean(), nullable=True
34
+ )
35
+ )
36
+ batch_op.add_column(
37
+ sa.Column("hd_bitrate_compression", sa.Integer(), nullable=True)
38
+ )
39
+ batch_op.add_column(
40
+ sa.Column("ld_bitrate_compression", sa.Integer(), nullable=True)
41
+ )
42
+
43
+ with op.batch_alter_table("task", schema=None) as batch_op:
44
+ batch_op.add_column(
45
+ sa.Column(
46
+ "difficulty", sa.Integer(), nullable=False, server_default="3"
47
+ )
48
+ )
49
+ batch_op.create_check_constraint(
50
+ "check_difficulty", "difficulty > 0 AND difficulty < 6"
51
+ )
52
+
53
+ # ### end Alembic commands ###
54
+
55
+
56
+ def downgrade():
57
+ # ### commands auto generated by Alembic - please adjust! ###
58
+ with op.batch_alter_table("task", schema=None) as batch_op:
59
+ batch_op.drop_constraint("check_difficulty", type_="check")
60
+ batch_op.drop_column("difficulty")
61
+
62
+ with op.batch_alter_table("project", schema=None) as batch_op:
63
+ batch_op.drop_column("ld_bitrate_compression")
64
+ batch_op.drop_column("hd_bitrate_compression")
65
+ batch_op.drop_column("is_publish_default_for_artists")
66
+
67
+ with op.batch_alter_table("organisation", schema=None) as batch_op:
68
+ batch_op.drop_column("format_duration_in_hours")
69
+ batch_op.drop_column("dark_theme_by_default")
70
+
71
+ # ### end Alembic commands ###
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zou
3
- Version: 0.19.55
3
+ Version: 0.19.57
4
4
  Summary: API to store and manage the data of your animation production
5
5
  Home-page: https://zou.cg-wire.com
6
6
  Author: CG Wire
@@ -37,11 +37,11 @@ Requires-Dist: flask-sqlalchemy ==3.1.1
37
37
  Requires-Dist: flask-fs2[s3,swift] ==0.7.27
38
38
  Requires-Dist: flask-jwt-extended ==4.6.0
39
39
  Requires-Dist: flask-migrate ==4.0.7
40
- Requires-Dist: flask-socketio ==5.3.7
40
+ Requires-Dist: flask-socketio ==5.4.1
41
41
  Requires-Dist: flask ==3.0.3
42
42
  Requires-Dist: gazu ==0.10.15
43
43
  Requires-Dist: gevent-websocket ==0.10.1
44
- Requires-Dist: gevent ==24.2.1
44
+ Requires-Dist: gevent ==24.10.1
45
45
  Requires-Dist: gunicorn ==23.0.0
46
46
  Requires-Dist: isoweek ==1.3.3
47
47
  Requires-Dist: itsdangerous ==2.2.0
@@ -55,41 +55,41 @@ Requires-Dist: OpenTimelineIO-Plugins ==0.17.0
55
55
  Requires-Dist: orjson ==3.10.7
56
56
  Requires-Dist: pillow ==10.4.0
57
57
  Requires-Dist: psutil ==6.0.0
58
- Requires-Dist: psycopg[binary] ==3.2.1
58
+ Requires-Dist: psycopg[binary] ==3.2.3
59
59
  Requires-Dist: pyotp ==2.9.0
60
60
  Requires-Dist: pysaml2 ==7.5.0
61
61
  Requires-Dist: python-nomad ==2.0.1
62
62
  Requires-Dist: python-slugify ==8.0.4
63
63
  Requires-Dist: python-socketio ==5.11.4
64
- Requires-Dist: pytz ==2024.1
65
- Requires-Dist: redis ==5.0.8
64
+ Requires-Dist: pytz ==2024.2
65
+ Requires-Dist: redis ==5.1.1
66
66
  Requires-Dist: requests ==2.32.3
67
67
  Requires-Dist: rq ==1.16.2
68
68
  Requires-Dist: slackclient ==2.9.4
69
69
  Requires-Dist: sqlalchemy-utils ==0.41.2
70
- Requires-Dist: sqlalchemy ==2.0.34
70
+ Requires-Dist: sqlalchemy ==2.0.35
71
71
  Requires-Dist: ua-parser ==0.18.0
72
72
  Requires-Dist: werkzeug ==3.0.4
73
73
  Requires-Dist: numpy ==2.0.1 ; python_version == "3.9"
74
- Requires-Dist: numpy ==2.1.1 ; python_version >= "3.10"
74
+ Requires-Dist: numpy ==2.1.2 ; python_version >= "3.10"
75
75
  Provides-Extra: dev
76
76
  Requires-Dist: wheel ; extra == 'dev'
77
77
  Provides-Extra: lint
78
78
  Requires-Dist: autoflake ==2.3.1 ; extra == 'lint'
79
- Requires-Dist: black ==24.8.0 ; extra == 'lint'
80
- Requires-Dist: pre-commit ==3.8.0 ; (python_version >= "3.9") and extra == 'lint'
79
+ Requires-Dist: black ==24.10.0 ; extra == 'lint'
80
+ Requires-Dist: pre-commit ==4.0.1 ; extra == 'lint'
81
81
  Provides-Extra: monitoring
82
82
  Requires-Dist: prometheus-flask-exporter ==0.23.1 ; extra == 'monitoring'
83
83
  Requires-Dist: pygelf ==0.4.2 ; extra == 'monitoring'
84
- Requires-Dist: sentry-sdk ==2.13.0 ; extra == 'monitoring'
84
+ Requires-Dist: sentry-sdk ==2.16.0 ; extra == 'monitoring'
85
85
  Provides-Extra: prod
86
86
  Requires-Dist: gunicorn ; extra == 'prod'
87
87
  Requires-Dist: gevent ; extra == 'prod'
88
88
  Provides-Extra: test
89
- Requires-Dist: fakeredis ==2.24.1 ; extra == 'test'
89
+ Requires-Dist: fakeredis ==2.25.1 ; extra == 'test'
90
90
  Requires-Dist: mixer ==7.2.2 ; extra == 'test'
91
91
  Requires-Dist: pytest-cov ==5.0.0 ; extra == 'test'
92
- Requires-Dist: pytest ==8.3.2 ; extra == 'test'
92
+ Requires-Dist: pytest ==8.3.3 ; extra == 'test'
93
93
 
94
94
  .. figure:: https://zou.cg-wire.com/kitsu.png
95
95
  :alt: Kitsu Logo
@@ -1,4 +1,4 @@
1
- zou/__init__.py,sha256=pSNaoWHlk0o-XtsQy-8olXESh2Tu9_WLaixIhoQCwH4,24
1
+ zou/__init__.py,sha256=rW0WVpeAWKFykE01Gg9OBcVqo13Hrhi6fppDOQkDqlw,24
2
2
  zou/cli.py,sha256=DHHf4mz33Bi0gGFJ0GdRUpjrMrMSQYyVubJFppHPZlU,18914
3
3
  zou/debug.py,sha256=1fawPbkD4wn0Y9Gk0BiBFSa-CQe5agFi8R9uJYl2Uyk,520
4
4
  zou/event_stream.py,sha256=_tue9Ry3aqCniZpKGhWJaY1Eo_fd6zOAfnzPvh_mJzU,8489
@@ -16,7 +16,7 @@ zou/app/blueprints/auth/resources.py,sha256=CAqlC8Q2Mw3grjL2bU_aZJQ18huwa1Kf3ym2
16
16
  zou/app/blueprints/breakdown/__init__.py,sha256=Dp6GWSGxxWIedpyzTTEKpCRUYEo8oVNVyQhwNvTMmQM,1888
17
17
  zou/app/blueprints/breakdown/resources.py,sha256=JY3j17kv7xPKV9S-XoOxNYivpGHlfZkXI5WuGtx3_Yk,13591
18
18
  zou/app/blueprints/chats/__init__.py,sha256=YGmwGvddg3MgSYVIh-hmkX8t2em9_LblxBeJzFqFJD4,558
19
- zou/app/blueprints/chats/resources.py,sha256=pyTIMaHqErpoSKpqOogLa62syetv6Dg9mCXz_rzflN0,5920
19
+ zou/app/blueprints/chats/resources.py,sha256=4yLFermdwOsnBLs9nx8yxuHWLar24uQWQy0XgsUNDD0,5950
20
20
  zou/app/blueprints/comments/__init__.py,sha256=WqpJ7-_dK1cInGTFJAxQ7syZtPCotwq2oO20UEnk1h4,1532
21
21
  zou/app/blueprints/comments/resources.py,sha256=_WoAnnv2uRLbc_fzg6XCeXF06_KNFS08r84YVN858Mc,19423
22
22
  zou/app/blueprints/concepts/__init__.py,sha256=sP_P4mfYvfMcgeE6MHZYP3eD0Lz0Lwit5-CFuVnA-Jg,894
@@ -29,11 +29,11 @@ zou/app/blueprints/crud/chat.py,sha256=Sq1r0y9ANjS113PUpwgAhnjYsxxLKMCM-a7DJ_icF
29
29
  zou/app/blueprints/crud/chat_message.py,sha256=bEEUoV0sNzu5sntNS6fpLh5NC6wWiycWCXtTE-t4yG4,387
30
30
  zou/app/blueprints/crud/comments.py,sha256=YH4cllfGloPMcIq1tgpT5pSvKTwNJ1zpkUssrK_OjiU,8334
31
31
  zou/app/blueprints/crud/custom_action.py,sha256=Nf6S6YBxePg4-nfaPTroIYZGWt9fJEHC719DOKJ8R98,978
32
- zou/app/blueprints/crud/day_off.py,sha256=ZjTNBUMH5gJrQ7xWjcAnnOxATi_YJ3or6IqLkO2PQlo,2511
32
+ zou/app/blueprints/crud/day_off.py,sha256=hr_cSBG-r7i_an2AkRmgTPtzbwojaI6el_JDUHgBBx4,2571
33
33
  zou/app/blueprints/crud/department.py,sha256=AAN_qxZDQGS-mR1kRS_2qGx1D7PKT3h_Ke3IXtJ_F90,973
34
34
  zou/app/blueprints/crud/entity.py,sha256=WdAmVoK1nwo_JmzVKls-DV-rK6miu3y9wZELGDo3Fqw,9731
35
35
  zou/app/blueprints/crud/entity_link.py,sha256=PlHGy3RPDUVdwWtOpQegz-wZCcxe9FZw_80nUVBy1Ac,819
36
- zou/app/blueprints/crud/entity_type.py,sha256=LT25rqkD--X0LzQdzwTMLmDYqRLepARvTSRD-sjeNfw,2361
36
+ zou/app/blueprints/crud/entity_type.py,sha256=Q32S4FCVHYGCcymjETEmjmNOCyWhtw1TpW1gznyY6m8,2332
37
37
  zou/app/blueprints/crud/event.py,sha256=bay2ggg5Oa69lOxNYGkHVQdSKuMxGhk2wqWP7QApKUg,589
38
38
  zou/app/blueprints/crud/file_status.py,sha256=g2YM_0pscO0GAd-VOzTnl7EF57BS_7zbAwCt1WlNujs,509
39
39
  zou/app/blueprints/crud/metadata_descriptor.py,sha256=Dc9_HOPCroqI7XDPiO6nrbmLfzaRIR0pFgg41Lq2sj0,2063
@@ -47,9 +47,9 @@ zou/app/blueprints/crud/person.py,sha256=qKgko2ZlGCHj_7SC9NW9hFHrjblk18khS_7bGKh
47
47
  zou/app/blueprints/crud/playlist.py,sha256=ZXaz-hHPej6XYKo_RUfJ2QnGOh2W8-y9hTkPZCUp7Zk,1876
48
48
  zou/app/blueprints/crud/preview_background_file.py,sha256=WzOfag5qhz5B3-XDObYRC8TO4X-kIo1sHOnMCV62IEo,2437
49
49
  zou/app/blueprints/crud/preview_file.py,sha256=252EDEdF-wQaL9ZhqQv5j9z_JKK5WeYwidJfFafArjo,3831
50
- zou/app/blueprints/crud/project.py,sha256=rU79oZm-awKMC0k-qNpn-k2D498avge4vxYVOlrR2TQ,8196
50
+ zou/app/blueprints/crud/project.py,sha256=YqBJsWCZsNVE93H2xN0wCXozz7iHBi9vs7cgwb8DTI8,8272
51
51
  zou/app/blueprints/crud/project_status.py,sha256=7q78eGCJAg4ZofqBJWBeHsLVpmtxfP9Blpg8-ZYduC8,526
52
- zou/app/blueprints/crud/schedule_item.py,sha256=qrUJxkK0ib8iocwjQ0iPd3GaZzy-kdx4_uJcLZnJMQY,1370
52
+ zou/app/blueprints/crud/schedule_item.py,sha256=1dbNKbftNG3if38Hzh1uslCAu3BE4jOqWhLV0590A90,1400
53
53
  zou/app/blueprints/crud/search_filter.py,sha256=qR0crZFfaOd2YxFcPMKhAj1SXCc-YW9Wk4UA07dDgMQ,393
54
54
  zou/app/blueprints/crud/search_filter_group.py,sha256=bdCLP1EmSatSNQXW8qYjqXQ1_dqluxUeEe7wEpcP_R0,424
55
55
  zou/app/blueprints/crud/software.py,sha256=8UmSPMX-V210nlX0k_RafV930tYqPayt2mBOyDSsqNQ,1960
@@ -74,12 +74,12 @@ zou/app/blueprints/export/csv/base.py,sha256=AlNvzpozHAqs76tWGju0PGhX4CthDRDkwI8
74
74
  zou/app/blueprints/export/csv/casting.py,sha256=0e4Z9TzpGfAuWx84qbMAJo74CacsRFofpWChZQ8UNC0,14153
75
75
  zou/app/blueprints/export/csv/edits.py,sha256=mEtIoHQ8iD9mWWgvtspFau_JjPGI6PwAWq6n1Q9W9OM,5408
76
76
  zou/app/blueprints/export/csv/persons.py,sha256=z8B6wlGqTYP5gKKpXSh36ez03wWNY129wNVzwvt6AGY,964
77
- zou/app/blueprints/export/csv/playlists.py,sha256=WjkgzI7rDacSrLi2U-zSBngffWHZUriiYfmirNK7bPc,4827
77
+ zou/app/blueprints/export/csv/playlists.py,sha256=AIrMrGMjbdFaPiRw02KZPznaYc6Zp56KUDaIj9RafwY,4830
78
78
  zou/app/blueprints/export/csv/projects.py,sha256=n_266BxGfYHz-3RbgZ-OuFnJellbP4lXuElRAPFzlHc,740
79
79
  zou/app/blueprints/export/csv/shots.py,sha256=JSJjqyCJPoIXpAmmPnappUQbYau0AA03c_wh8pmQCls,6005
80
80
  zou/app/blueprints/export/csv/task_types.py,sha256=PCEEhOQcdOJv_38i-KNxbkGeNzmQ8Qe01k8YnhRybzo,765
81
81
  zou/app/blueprints/export/csv/tasks.py,sha256=CHFcs9S3eLIz6psE6Q6mZ-OSur_GrpBeLn98Nh9NNcA,4121
82
- zou/app/blueprints/export/csv/time_spents.py,sha256=WHdy9Wf2e-kvviYbNyUFr7xgg49h9f-Di12KIZx5ssk,2981
82
+ zou/app/blueprints/export/csv/time_spents.py,sha256=yYPtilOxfQD5mBwyh9h-PbTQBpab-vMrec35tYUw4fQ,2984
83
83
  zou/app/blueprints/files/__init__.py,sha256=7Wty30JW2OXIn-tBFXOWWmPuHnsnxPpH3jNtHvvr9tY,3987
84
84
  zou/app/blueprints/files/resources.py,sha256=8SIV8kaqv3dxyL8nyqG3QiZmk5ZYIvUxw6k1ic-jhBs,69786
85
85
  zou/app/blueprints/index/__init__.py,sha256=Dh3oQiirpg8RCkfVOuk3irIjSvUvuRf0jPxE6oGubz0,828
@@ -91,7 +91,7 @@ zou/app/blueprints/persons/resources.py,sha256=RsN8ix67zRU7NNeMY7uFCXkU2ntJlmKF6
91
91
  zou/app/blueprints/playlists/__init__.py,sha256=vuEk1F3hFHsmuKWhdepMoLyOzmNKDn1YrjjfcaIz0lQ,1596
92
92
  zou/app/blueprints/playlists/resources.py,sha256=alRlMHypUFErXLsEYxpFK84cdjFJ3YWwamZtW0KcwLY,17211
93
93
  zou/app/blueprints/previews/__init__.py,sha256=qGohO6LRNZKXBAegINcUXuZlrtxobJKQg84-rQ1L3AU,4202
94
- zou/app/blueprints/previews/resources.py,sha256=OO6hQxyYo941ANtSapl9DGYpSuto8NeE8jtvx1Hcbek,48028
94
+ zou/app/blueprints/previews/resources.py,sha256=Mg2FVVJdb5_Fqr8OAWl2i46qgSASe9b4lzYnFjGeFRQ,48062
95
95
  zou/app/blueprints/projects/__init__.py,sha256=Pn3fA5bpNFEPBzxTKJ2foV6osZFflXXSM2l2uZh3ktM,3927
96
96
  zou/app/blueprints/projects/resources.py,sha256=E91Vj9EzId2pxiL50JRfrThiyif1PmzWS1oPeMThzQI,31544
97
97
  zou/app/blueprints/search/__init__.py,sha256=QCjQIY_85l_orhdEiqav_GifjReuwsjZggN3V0GeUVY,356
@@ -128,8 +128,8 @@ zou/app/blueprints/source/shotgun/team.py,sha256=GF7y2BwDeFJCiidtG68icfCi-uV1-b9
128
128
  zou/app/blueprints/source/shotgun/versions.py,sha256=8Mb35e5p3FLbbiu6AZb9tJErDKz2pPRBdIYu80Ayj7w,2292
129
129
  zou/app/blueprints/tasks/__init__.py,sha256=pNUqVEVX1KVu1IzRRJNsziPkhWKXqgyvQsNp7LbmIxo,4342
130
130
  zou/app/blueprints/tasks/resources.py,sha256=RTMvVbVC-BBnGnIVuHioaMqMKf2PwgZMXqydOC_axus,55923
131
- zou/app/blueprints/user/__init__.py,sha256=dhNMmwLvlFqehC7-DPyjCNNkru1gmhPu4WEopHwIabI,4433
132
- zou/app/blueprints/user/resources.py,sha256=YoPoPt0G4qZhbZFiBCbZ7e3nT3Xf6jgN8FITHPDV2P0,37305
131
+ zou/app/blueprints/user/__init__.py,sha256=H9zCHcVobC6jq6dTToXKAjnZmDA0a9gChHiIP3BcZsc,4586
132
+ zou/app/blueprints/user/resources.py,sha256=ulA3TK54BCIs1Z5yAH2d1144L-0xoO_YMykgnUoQ_tQ,38588
133
133
  zou/app/file_trees/default.json,sha256=ryUrEmQYE8B_WkzCoQLgmem3N9yNwMIWx9G8p3HfG9o,2310
134
134
  zou/app/file_trees/simple.json,sha256=VBI43Z3rjQxtTpVCq3ktUgS0UB8x-aTowKL9LXuXCFI,3149
135
135
  zou/app/indexer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -156,14 +156,14 @@ zou/app/models/metadata_descriptor.py,sha256=LRCJ7NKsy771kMSLeZDrCON7jRk76J-JTFW
156
156
  zou/app/models/milestone.py,sha256=ZwJ7_PbXT_LeUZKv3l5DLPM7ByFQEccpEeWFq4-IM-Q,927
157
157
  zou/app/models/news.py,sha256=UPX0ojWF-leAGZNKqlo7KL0s0lp2tbKMJl4N5lGbouo,1583
158
158
  zou/app/models/notification.py,sha256=1ODOymGPeB4oxgX_3WhOgIL_Lsz-JR7miDkBS6W8t_s,2563
159
- zou/app/models/organisation.py,sha256=3nUJq9TBJsBs1t3h4OHFBUrvn_FGOnBsiofcdH3tdzk,1587
159
+ zou/app/models/organisation.py,sha256=jVDsS3C3ani0NYeKKMnsnkGzeeQor9jMU1qkHxkSa9c,1938
160
160
  zou/app/models/output_file.py,sha256=hyLGrpsgrk0aisDXppRQrB7ItCwyuyw-X0ZwVAHabsA,2569
161
161
  zou/app/models/output_type.py,sha256=us_lCUCEvuP4vi_XmmOcEl1J2MtZhMX5ZheBqEFCgWA,381
162
162
  zou/app/models/person.py,sha256=-JpYBpzqZ3LDD6HW1YgjrD7szhWSxQ0ti4GrrGvja2w,7466
163
163
  zou/app/models/playlist.py,sha256=YGgAk84u0_fdIEY02Dal4kfk8APVZvWFwWYV74qvrio,1503
164
164
  zou/app/models/preview_background_file.py,sha256=j8LgRmY7INnlB07hFwwB-8ssQrRC8vsb8VcpsTbt6tA,559
165
165
  zou/app/models/preview_file.py,sha256=Ur45Wau2X3qyKULh04EUcMbnBmaQc8y4IMs5NgELiAQ,3134
166
- zou/app/models/project.py,sha256=qj5IR17Og6rioW2CoQOp7f76HZ2wcXOkq4bp9OXoeIo,8699
166
+ zou/app/models/project.py,sha256=T2gTImmbd5O-U5GySWSwzkR0r_cY2RDr1niwSfOPqeA,8900
167
167
  zou/app/models/project_status.py,sha256=pExaHH7x4Eu8xOqD3_mRRbMzjT2jJZ8rm-9jo7yUGXA,390
168
168
  zou/app/models/schedule_item.py,sha256=coY5uDDuBoctaMICnfCzx4zT5om2E1uu4iq5MDWAPlY,1444
169
169
  zou/app/models/search_filter.py,sha256=3xcFemJ9poIBAHNd50pv9U9eP_n74xJCxW2JBDcRuNo,1133
@@ -172,48 +172,48 @@ zou/app/models/serializer.py,sha256=VKN5hHJ6M_jsvrbKe5SonnTeg5dxXSYqb_4JDVWIQwA,
172
172
  zou/app/models/software.py,sha256=3y9xEOS8BBxqgTaRrCaSYHaB6uOdJ88uU5i-cACoCSk,517
173
173
  zou/app/models/status_automation.py,sha256=95c0lmOetujyGWViLd_qsR4GWPhrmlvi9ZfkC0x1NuM,1391
174
174
  zou/app/models/studio.py,sha256=cXnYFh-8m5Kw05QawYcCr59eeLp25NDI0VIb77oqUOs,384
175
- zou/app/models/subscription.py,sha256=0GDQTHUThnydD4VwZg6YW2daC31zsu16j3ik4Im8d6g,1026
176
- zou/app/models/task.py,sha256=DiDCXdAOuKwR6LO8_ECZHunuZ5a19GVqRC5SA-8cdcs,3437
175
+ zou/app/models/subscription.py,sha256=kMfPPe8uFJMDWB4B9MpWaXZD86FFZlj7ty0FkVyqE_4,1054
176
+ zou/app/models/task.py,sha256=kC0ufy82n9Vj5f9r_pbx74szSJMM0LPIlrWIlAnTkD8,3615
177
177
  zou/app/models/task_status.py,sha256=J7mNWIFd9KMWfUOLHjmuxIupjs59iSh8aQ_9LEFXqH4,1227
178
178
  zou/app/models/task_type.py,sha256=IsixVAfz3pyMf0eQw8x-uFNM9OHNkZpsPLEz_VNQ0hA,1005
179
179
  zou/app/models/time_spent.py,sha256=n7i3FO9g1eE_zATkItoCgrGVqq3iMSfdlKSveEZPloc,795
180
180
  zou/app/models/working_file.py,sha256=q0LM3s1ziw_9AmmPDCkwyf1-TJkWTBMgo2LdHyVRwxg,1509
181
181
  zou/app/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
182
- zou/app/services/assets_service.py,sha256=VCfXtl8OzPgLV7sHGDfVifv9unZ4wtY6oYs4ndkcPDY,23620
182
+ zou/app/services/assets_service.py,sha256=J7o1ewK2bevJNjeXyaGp99PH0G5Yxbm2edxfX90R3W0,23716
183
183
  zou/app/services/auth_service.py,sha256=hQpNb21xlr5EiTrXnzpFb4W4GDtglubqA2z_-YIBfnk,22897
184
184
  zou/app/services/backup_service.py,sha256=_ZtZp6wkcVYnHxBosziwLGdrTvsUttXGphiydq53iy8,4840
185
185
  zou/app/services/base_service.py,sha256=OZd0STFh-DyBBdwsmA7DMMnrwv4C8wJUbShvZ1isndU,1383
186
186
  zou/app/services/breakdown_service.py,sha256=n6xLoFGSEH2JXUKiXKq2NGVZZg_AIORtA05d5D4uaB4,27480
187
- zou/app/services/chats_service.py,sha256=V1RmQeQnsH1xvtbs6wcjEpudQS547eJBM7bgJr9-qYM,8270
187
+ zou/app/services/chats_service.py,sha256=9jw8Rh9PEovpYu_cxxYicTFQFQhc-ObGlteFQwQCC-M,8273
188
188
  zou/app/services/comments_service.py,sha256=CUr0CZGkR95OrHDRJnhAZAikBLtWhM-5uLIoxI4gNtA,18589
189
189
  zou/app/services/concepts_service.py,sha256=KGvk6lF5udj3SWn40X9KE8OAigrLCZUKEz9_CW7EMgQ,11440
190
190
  zou/app/services/custom_actions_service.py,sha256=fWISEOOdthadrxeHuacEel5Xj6msn0yWXJQDG1gzvsY,297
191
191
  zou/app/services/deletion_service.py,sha256=GdPWmw60_EmWxJohvqQ9KRcION7_PIdQgbl7nr2g2mY,17429
192
192
  zou/app/services/edits_service.py,sha256=KTk5KUJx1yB-mRka8rQXMgQLIcWq4mNYZfnVhVlKwyQ,12122
193
- zou/app/services/emails_service.py,sha256=ZSwfL3iO9mIyHttqH61vI4WA-DTVdBk7lo6t9zbvfDA,11922
194
- zou/app/services/entities_service.py,sha256=j_dyMHUVISqXFkxm2ydqvAo0nbcEE7_5v9jFauZhSe4,16327
193
+ zou/app/services/emails_service.py,sha256=HaSdDzNLU-s_fxoH-YQi-3VFX1YwdYm64kMhJFGa3AM,11923
194
+ zou/app/services/entities_service.py,sha256=HDl_KqS5aZEUyAkrgsQ11qqYiaFFy0VcD2BrSaOrxJg,16436
195
195
  zou/app/services/events_service.py,sha256=_gU19herxiAo47WRxVNhvl7v-RKhp-8wZ3gAiHKpOzI,2716
196
196
  zou/app/services/exception.py,sha256=mcDVjWGICMIlOi4nsN2EQ7nc3V70rAC-iCmXt6kOXbA,4240
197
197
  zou/app/services/file_tree_service.py,sha256=8JNBDgnXtV-AmSJ3gnUGB4oSwLjPgi1WYyL0Kc98JRE,33875
198
198
  zou/app/services/files_service.py,sha256=df1_9v-vwE5HVi9XjtilTPWHuiWunvrwPyQh_IXupNM,28517
199
199
  zou/app/services/index_service.py,sha256=1w8rGJ7ArYC13B43hD4JOPtVhaRsbseJVVY-GnU_3tA,9874
200
- zou/app/services/names_service.py,sha256=IvwQxlvFpcreVQ1bpy20uIlzEzS8PJayx-sMFuOBots,2917
201
- zou/app/services/news_service.py,sha256=ltMVObZiNpSat4qze4z6W5zoy9IdPXiIfsqSr2awdWk,8767
200
+ zou/app/services/names_service.py,sha256=TOSrintROmxcAlcFQE0i2E3PBLnw81GAztNselpTn18,2947
201
+ zou/app/services/news_service.py,sha256=g-QlITBbEvhvm-pLv7GtGACKX4uBPa-IKxfNOgMgaHo,8768
202
202
  zou/app/services/notifications_service.py,sha256=7GDRio_mGaRYV5BHOAdpxBZjA_LLYUfVpbwZqy1n9pI,15685
203
203
  zou/app/services/persons_service.py,sha256=06CyF--QnGVkjvZPkAYIBz8V-P_Nbb4Iv1lkHQWqh4k,16310
204
204
  zou/app/services/playlists_service.py,sha256=pAlPHET4jNdST5jsmJrFUkf1SVhfSoML9zdNpZ_88l4,32439
205
- zou/app/services/preview_files_service.py,sha256=C3085NjeCoqA8-3tkogFHYWxZ1BJHzKqjZUyd7K_S_Y,35608
205
+ zou/app/services/preview_files_service.py,sha256=M1kXryARUKwCDXsr0hOfUUyGn75y-qXIVIwlMOKWWHs,35609
206
206
  zou/app/services/projects_service.py,sha256=_J8hIHy3MX5MsdEMRIKNfbyewwhxtMEcc_ymeHBsF38,21434
207
207
  zou/app/services/scenes_service.py,sha256=iXN19HU4njPF5VtZXuUrVJ-W23ZQuQNPC3ADXltbWtU,992
208
208
  zou/app/services/schedule_service.py,sha256=E99HKYsXgnK2sw58fw-NNHXWBgVJiA60upztjkNSCaM,6989
209
- zou/app/services/shots_service.py,sha256=Y1oTewc2TNxwPzU5CZFfEhjJznjR54a9GTirFZxBhv4,52078
209
+ zou/app/services/shots_service.py,sha256=dJGG6_8P8_RwqT7r2kv776xXzgNPyJ-RqLyFQuwgAnY,52196
210
210
  zou/app/services/stats_service.py,sha256=cAlc92i9d6eYtsuwe3hYHYwdytg8KEMi1-TADfysJwM,11733
211
211
  zou/app/services/status_automations_service.py,sha256=tVio7Sj7inhvKS4UOyRhcdpwr_KNP96hT1o0X7XcGF4,715
212
212
  zou/app/services/sync_service.py,sha256=EunfXlma_IIb7011A_xLQLVQGAi-MteKgm2Y2NAxvMs,41586
213
213
  zou/app/services/tasks_service.py,sha256=IoogHBoZhbJegnl5SYGgOaBp2YVqrL22Gccjfp8dPn8,69335
214
214
  zou/app/services/telemetry_services.py,sha256=xQm1h1t_JxSFW59zQGf4NuNdUi1UfMa_6pQ-ytRbmGA,1029
215
215
  zou/app/services/time_spents_service.py,sha256=H9X-60s6oqtY9rtU-K2jKwUSljfkdGlf_9wMr3iVfIA,15158
216
- zou/app/services/user_service.py,sha256=BiOhPV7O-vowet7jOksjXk2V4yxZkdqsIyNboJ-Oz_A,46595
216
+ zou/app/services/user_service.py,sha256=rI1eLdccb4PpD6tqjQnQtu_sY5h3T9FMbk5GZ6RReg4,47916
217
217
  zou/app/stores/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
218
218
  zou/app/stores/auth_tokens_store.py,sha256=-qOJPybLHvnMOq3PWk073OW9HJwOHGhFLZeOIlX1UVw,1290
219
219
  zou/app/stores/file_store.py,sha256=yLQDM6mNbj9oe0vsWdBqun7D8Dw-eSjD1yHCCftX0OI,4045
@@ -338,6 +338,7 @@ zou/migrations/versions/87efceb6745b_add_ready_for_to_entity.py,sha256=YDRS-cthq
338
338
  zou/migrations/versions/892b264937ec_.py,sha256=6T6WZ68teGuuI3s-GA7om9XQhbTQ70opSnGtRqBuu3E,3287
339
339
  zou/migrations/versions/8a1b4a1b7f4a_add_totp_columns_for_person.py,sha256=ZcLUDhvtE2yxqEdcmE0zwDY3hfJzzi-M377Mokzhcv4,1076
340
340
  zou/migrations/versions/8e4f39e321f4_add_day_off_table.py,sha256=Mc7lEtTBhR0ZNGfxBjzFe5kxVOeG3cPLEjGDfbsjMp0,1584
341
+ zou/migrations/versions/8e67c183bed7_add_preference_fields.py,sha256=x04wpTsjRZLEKSwQ9fw-Y5-KmtONkXRaxy6pf9z0BY4,2244
341
342
  zou/migrations/versions/8fbd40afbe5f_allow_to_set_float_values_for_.py,sha256=aJI7O6yOpuMUwZ5O2cid1hIbuBSbbiWI10aRofOLdH4,1933
342
343
  zou/migrations/versions/9010a64e5a2d_add_indices.py,sha256=MPDeO2VXx38ehHBPomIDccifS9lDrNl5edH6OXBxopY,1669
343
344
  zou/migrations/versions/9060dd4f6116_notification_uc.py,sha256=FQHjH1AqTcMl37OwrTMtS6efMlfoTI2X8yaCAfBPSMc,992
@@ -411,9 +412,9 @@ zou/remote/normalize_movie.py,sha256=zNfEY3N1UbAHZfddGONTg2Sff3ieLVWd4dfZa1dpnes
411
412
  zou/remote/playlist.py,sha256=AsDo0bgYhDcd6DfNRV6r6Jj3URWwavE2ZN3VkKRPbLU,3293
412
413
  zou/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
413
414
  zou/utils/movie.py,sha256=u9LCEOvmkxwm-KiZ6jKNdB9LSC6XXUDwJpVx8LkDwJg,16416
414
- zou-0.19.55.dist-info/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
415
- zou-0.19.55.dist-info/METADATA,sha256=TGCMqLcTAkCtOyUVfeWMXRJHhn_IXxV-LPjylqW-0YM,6704
416
- zou-0.19.55.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
417
- zou-0.19.55.dist-info/entry_points.txt,sha256=PelQoIx3qhQ_Tmne7wrLY-1m2izuzgpwokoURwSohy4,130
418
- zou-0.19.55.dist-info/top_level.txt,sha256=4S7G_jk4MzpToeDItHGjPhHx_fRdX52zJZWTD4SL54g,4
419
- zou-0.19.55.dist-info/RECORD,,
415
+ zou-0.19.57.dist-info/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
416
+ zou-0.19.57.dist-info/METADATA,sha256=Po8xxdXHbXGs4VsQYZkq04hrh7fJJLHqTh8tNJTMI1Y,6676
417
+ zou-0.19.57.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
418
+ zou-0.19.57.dist-info/entry_points.txt,sha256=PelQoIx3qhQ_Tmne7wrLY-1m2izuzgpwokoURwSohy4,130
419
+ zou-0.19.57.dist-info/top_level.txt,sha256=4S7G_jk4MzpToeDItHGjPhHx_fRdX52zJZWTD4SL54g,4
420
+ zou-0.19.57.dist-info/RECORD,,
File without changes
File without changes