zou 0.19.14__py3-none-any.whl → 0.20.11__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) 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} +84 -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/flask.py +1 -0
  130. zou/app/utils/query.py +54 -6
  131. zou/app/utils/redis.py +11 -0
  132. zou/app/utils/saml.py +51 -0
  133. zou/app/utils/string.py +2 -0
  134. zou/app/utils/thumbnail.py +4 -2
  135. zou/cli.py +76 -18
  136. zou/debug.py +4 -2
  137. zou/event_stream.py +122 -165
  138. zou/job_settings.py +1 -0
  139. zou/migrations/env.py +0 -0
  140. zou/migrations/utils/base.py +6 -6
  141. zou/migrations/versions/1bb55759146f_add_table_studio.py +67 -0
  142. zou/migrations/versions/1fab8c420678_add_attachments_to_message_chats.py +56 -0
  143. zou/migrations/versions/23122f290ca2_add_entity_chat_models.py +149 -0
  144. zou/migrations/versions/32f134ff1201_add_is_shared_flag_to_filters.py +33 -0
  145. zou/migrations/versions/57222395f2be_add_statusautomation_import_last_revision.py +41 -0
  146. zou/migrations/versions/59a7445a966c_add_entity_is_shared.py +41 -0
  147. zou/migrations/versions/5b980f0dc365_add_comment_links.py +35 -0
  148. zou/migrations/versions/680c64565f9d_for_searchfiltergroup_is_shared.py +35 -0
  149. zou/migrations/versions/8e67c183bed7_add_preference_fields.py +71 -0
  150. zou/migrations/versions/92b40d79ad3f_allow_message_attachments.py +38 -0
  151. zou/migrations/versions/971dbf5a0faf_add_short_name_for_asset_type_entity_.py +33 -0
  152. zou/migrations/versions/9b85c14fa8a7_add_day_off_new_columns.py +68 -0
  153. zou/migrations/versions/9d3bb33c6fc6_add_department_keys_to_filter_models.py +73 -0
  154. zou/migrations/versions/a252a094e977_add_descriptions_for_entities_tasks_and_.py +40 -0
  155. zou/migrations/versions/be56dc0fb760_for_is_shared_disallow_nullable.py +102 -0
  156. zou/migrations/versions/ca28796a2a62_add_is_done_field_to_the_task_model.py +108 -0
  157. zou/migrations/versions/f344b867a911_for_description_of_entity_task_working_.py +75 -0
  158. zou/remote/config_payload.py +2 -1
  159. zou/utils/movie.py +14 -4
  160. {zou-0.19.14.dist-info → zou-0.20.11.dist-info}/METADATA +75 -69
  161. {zou-0.19.14.dist-info → zou-0.20.11.dist-info}/RECORD +164 -135
  162. {zou-0.19.14.dist-info → zou-0.20.11.dist-info}/WHEEL +1 -1
  163. {zou-0.19.14.dist-info → zou-0.20.11.dist-info}/LICENSE +0 -0
  164. {zou-0.19.14.dist-info → zou-0.20.11.dist-info}/entry_points.txt +0 -0
  165. {zou-0.19.14.dist-info → zou-0.20.11.dist-info}/top_level.txt +0 -0
@@ -15,120 +15,27 @@ from zou.app.services import (
15
15
  shots_service,
16
16
  user_service,
17
17
  )
18
- from zou.app.utils import permissions, csv_utils, auth, emails, fields
18
+ from zou.app.utils import (
19
+ permissions,
20
+ csv_utils,
21
+ auth,
22
+ emails,
23
+ fields,
24
+ date_helpers,
25
+ )
19
26
  from zou.app.services.exception import (
20
27
  DepartmentNotFoundException,
21
28
  WrongDateFormatException,
22
29
  WrongParameterException,
23
30
  UnactiveUserException,
24
31
  TwoFactorAuthenticationNotEnabledException,
32
+ PersonInProtectedAccounts,
25
33
  )
26
34
  from zou.app.services.auth_service import (
27
35
  disable_two_factor_authentication_for_person,
28
36
  )
29
37
 
30
38
 
31
- class NewPersonResource(Resource, ArgsMixin):
32
- """
33
- Create a new user in the database.
34
- """
35
-
36
- # TODO: Remove this route in the future.
37
- @jwt_required()
38
- @permissions.require_admin
39
- def post(self):
40
- """
41
- Create a new user in the database.
42
- This route will be removed in the future.
43
- Please use POST /data/persons instead.
44
- ---
45
- tags:
46
- - Persons
47
- description: Set password to None if not provided.
48
- User role can be set but only admins can create admin users.
49
- parameters:
50
- - in: formData
51
- name: email
52
- required: True
53
- type: string
54
- format: email
55
- x-example: admin@example.com
56
- - in: formData
57
- name: phone
58
- required: False
59
- type: integer
60
- x-example: 06 12 34 56 78
61
- - in: formData
62
- name: role
63
- required: False
64
- type: string
65
- x-example: user
66
- - in: formData
67
- name: first_name
68
- required: True
69
- type: string
70
- - in: formData
71
- name: last_name
72
- required: False
73
- type: string
74
- responses:
75
- 201:
76
- description: User created
77
- """
78
- data = self.get_arguments()
79
-
80
- if not data["is_bot"] and persons_service.is_user_limit_reached():
81
- return {
82
- "error": True,
83
- "message": "User limit reached.",
84
- "limit": config.USER_LIMIT,
85
- }, 400
86
- else:
87
- if data["password"] is not None:
88
- data["password"] = auth.encrypt_password(data["password"])
89
- person = persons_service.create_person(
90
- data["email"],
91
- data["password"],
92
- data["first_name"],
93
- data["last_name"],
94
- data["phone"],
95
- role=data["role"],
96
- desktop_login=data["desktop_login"],
97
- departments=data["departments"],
98
- is_bot=data["is_bot"],
99
- expiration_date=data["expiration_date"],
100
- active=data["active"],
101
- )
102
- return person, 201
103
-
104
- def get_arguments(self):
105
- args = self.get_args(
106
- [
107
- {
108
- "name": "email",
109
- "help": "The email is required.",
110
- "required": True,
111
- },
112
- {
113
- "name": "first_name",
114
- "help": "The first name is required.",
115
- "required": True,
116
- },
117
- ("last_name", ""),
118
- ("phone", ""),
119
- ("role", "user"),
120
- ("desktop_login", ""),
121
- {"name": "departments", "action": "append"},
122
- "password",
123
- {"name": "is_bot", "default": False, "type": bool},
124
- {"name": "expiration_date", "default": None, "type": str},
125
- {"name": "active", "default": True, "type": bool},
126
- ]
127
- )
128
-
129
- return args
130
-
131
-
132
39
  class DesktopLoginsResource(Resource, ArgsMixin):
133
40
  """
134
41
  Allow to create and retrieve desktop login logs. Desktop login logs can only
@@ -189,7 +96,7 @@ class DesktopLoginsResource(Resource, ArgsMixin):
189
96
  201:
190
97
  description: Desktop login log entry created.
191
98
  """
192
- args = self.get_args([("date", datetime.datetime.utcnow())])
99
+ args = self.get_args([("date", date_helpers.get_utc_now_datetime())])
193
100
 
194
101
  current_user = persons_service.get_current_user()
195
102
  if (
@@ -400,7 +307,7 @@ class PersonDurationTimeSpentsResource(Resource, ArgsMixin):
400
307
  raise permissions.PermissionDenied
401
308
  if permissions.has_supervisor_permissions():
402
309
  department_ids = persons_service.get_current_user(
403
- True
310
+ relations=True
404
311
  )["departments"]
405
312
  else:
406
313
  raise permissions.PermissionDenied
@@ -625,7 +532,24 @@ class PersonDayTimeSpentsResource(PersonDurationTimeSpentsResource):
625
532
  abort(404)
626
533
 
627
534
 
628
- class PersonMonthQuotaShotsResource(Resource, ArgsMixin):
535
+ class PersonQuotaMixin:
536
+
537
+ def get_quota_arguments(self):
538
+ project_id = self.get_project_id()
539
+ task_type_id = self.get_task_type_id()
540
+ count_mode = self.get_text_parameter("count_mode", default="weigthed")
541
+ if count_mode not in ["weighted", "weighteddone", "feedback", "done"]:
542
+ raise WrongParameterException(
543
+ "count_mode must be equal to weighted, weigtheddone, feedback"
544
+ ", or done"
545
+ )
546
+ feedback = "done" not in count_mode
547
+ weighted = "weighted" in count_mode
548
+
549
+ return (project_id, task_type_id, count_mode, feedback, weighted)
550
+
551
+
552
+ class PersonMonthQuotaShotsResource(Resource, ArgsMixin, PersonQuotaMixin):
629
553
  """
630
554
  Get ended shots used for quota calculation of this month.
631
555
  """
@@ -656,6 +580,12 @@ class PersonMonthQuotaShotsResource(Resource, ArgsMixin):
656
580
  x-example: 07
657
581
  minimum: 1
658
582
  maximum: 12
583
+ - in: query
584
+ name: count_mode
585
+ required: True
586
+ type: string
587
+ enum: [weighted, weigtheddone, feedback, done]
588
+ x-example: weighted
659
589
  responses:
660
590
  200:
661
591
  description: Ended shots used for quota calculation of this month
@@ -663,10 +593,11 @@ class PersonMonthQuotaShotsResource(Resource, ArgsMixin):
663
593
  description: Wrong date format
664
594
  """
665
595
  user_service.check_person_is_not_bot(person_id)
666
- project_id = self.get_project_id()
667
- task_type_id = self.get_task_type_id()
668
596
  user_service.check_person_access(person_id)
669
- weighted = self.get_bool_parameter("weighted", default="true")
597
+ (project_id, task_type_id, count_mode, feedback, weighted) = (
598
+ self.get_quota_arguments()
599
+ )
600
+
670
601
  try:
671
602
  return shots_service.get_month_quota_shots(
672
603
  person_id,
@@ -675,12 +606,13 @@ class PersonMonthQuotaShotsResource(Resource, ArgsMixin):
675
606
  project_id=project_id,
676
607
  task_type_id=task_type_id,
677
608
  weighted=weighted,
609
+ feedback=feedback,
678
610
  )
679
611
  except WrongDateFormatException:
680
612
  abort(404)
681
613
 
682
614
 
683
- class PersonWeekQuotaShotsResource(Resource, ArgsMixin):
615
+ class PersonWeekQuotaShotsResource(Resource, ArgsMixin, PersonQuotaMixin):
684
616
  """
685
617
  Get ended shots used for quota calculation of this week.
686
618
  """
@@ -711,6 +643,12 @@ class PersonWeekQuotaShotsResource(Resource, ArgsMixin):
711
643
  x-example: 35
712
644
  minimum: 1
713
645
  maximum: 52
646
+ - in: query
647
+ name: count_mode
648
+ required: True
649
+ type: string
650
+ enum: [weighted, weigtheddone, feedback, done]
651
+ x-example: weighted
714
652
  responses:
715
653
  200:
716
654
  description: Ended shots used for quota calculation of this week
@@ -718,10 +656,11 @@ class PersonWeekQuotaShotsResource(Resource, ArgsMixin):
718
656
  description: Wrong date format
719
657
  """
720
658
  user_service.check_person_is_not_bot(person_id)
721
- project_id = self.get_project_id()
722
- task_type_id = self.get_task_type_id()
723
659
  user_service.check_person_access(person_id)
724
- weighted = self.get_bool_parameter("weighted", default="true")
660
+ (project_id, task_type_id, count_mode, feedback, weighted) = (
661
+ self.get_quota_arguments()
662
+ )
663
+
725
664
  try:
726
665
  return shots_service.get_week_quota_shots(
727
666
  person_id,
@@ -730,12 +669,13 @@ class PersonWeekQuotaShotsResource(Resource, ArgsMixin):
730
669
  project_id=project_id,
731
670
  task_type_id=task_type_id,
732
671
  weighted=weighted,
672
+ feedback=feedback,
733
673
  )
734
674
  except WrongDateFormatException:
735
675
  abort(404)
736
676
 
737
677
 
738
- class PersonDayQuotaShotsResource(Resource, ArgsMixin):
678
+ class PersonDayQuotaShotsResource(Resource, ArgsMixin, PersonQuotaMixin):
739
679
  """
740
680
  Get ended shots used for quota calculation of this day.
741
681
  """
@@ -773,6 +713,12 @@ class PersonDayQuotaShotsResource(Resource, ArgsMixin):
773
713
  x-example: 12
774
714
  minimum: 1
775
715
  maximum: 31
716
+ - in: query
717
+ name: count_mode
718
+ required: True
719
+ type: string
720
+ enum: [weighted, weigtheddone, feedback, done]
721
+ x-example: weighted
776
722
  responses:
777
723
  200:
778
724
  description: Ended shots used for quota calculation of this day
@@ -780,10 +726,11 @@ class PersonDayQuotaShotsResource(Resource, ArgsMixin):
780
726
  description: Wrong date format
781
727
  """
782
728
  user_service.check_person_is_not_bot(person_id)
783
- project_id = self.get_project_id()
784
- task_type_id = self.get_task_type_id()
785
729
  user_service.check_person_access(person_id)
786
- weighted = self.get_bool_parameter("weighted", default="true")
730
+ (project_id, task_type_id, count_mode, feedback, weighted) = (
731
+ self.get_quota_arguments()
732
+ )
733
+
787
734
  try:
788
735
  return shots_service.get_day_quota_shots(
789
736
  person_id,
@@ -793,6 +740,7 @@ class PersonDayQuotaShotsResource(Resource, ArgsMixin):
793
740
  project_id=project_id,
794
741
  task_type_id=task_type_id,
795
742
  weighted=weighted,
743
+ feedback=feedback,
796
744
  )
797
745
  except WrongDateFormatException:
798
746
  abort(404)
@@ -806,7 +754,12 @@ class TimeSpentDurationResource(Resource, ArgsMixin):
806
754
  def get_person_project_department_arguments(self):
807
755
  project_id = self.get_project_id()
808
756
  person_id = None
809
- department_ids = None
757
+ department_id = self.get_text_parameter("department_id")
758
+ if department_id is not None:
759
+ department_ids = [department_id]
760
+ else:
761
+ department_ids = None
762
+ studio_id = self.get_text_parameter("studio_id")
810
763
  if not permissions.has_admin_permissions():
811
764
  if (
812
765
  permissions.has_manager_permissions()
@@ -820,9 +773,16 @@ class TimeSpentDurationResource(Resource, ArgsMixin):
820
773
  elif project_id not in project_ids:
821
774
  raise permissions.PermissionDenied
822
775
  if permissions.has_supervisor_permissions():
823
- department_ids = persons_service.get_current_user(
776
+ persons_departments = persons_service.get_current_user(
824
777
  relations=True
825
778
  )["departments"]
779
+ if department_id is not None:
780
+ if department_id not in persons_departments:
781
+ raise WrongParameterException(
782
+ "Supervisor not allowed to access this department"
783
+ )
784
+ else:
785
+ department_ids = persons_departments
826
786
  else:
827
787
  person_id = persons_service.get_current_user()["id"]
828
788
 
@@ -830,6 +790,7 @@ class TimeSpentDurationResource(Resource, ArgsMixin):
830
790
  "person_id": person_id,
831
791
  "project_id": project_id,
832
792
  "department_ids": department_ids,
793
+ "studio_id": studio_id,
833
794
  }
834
795
 
835
796
 
@@ -1136,6 +1097,38 @@ class PersonYearDayOffResource(Resource, ArgsMixin):
1136
1097
  )
1137
1098
 
1138
1099
 
1100
+ class PersonDayOffResource(Resource, ArgsMixin):
1101
+ """
1102
+ Return all day offs recorded for given and person.
1103
+ """
1104
+
1105
+ @jwt_required()
1106
+ def get(self, person_id):
1107
+ """
1108
+ Return all day offs recorded for given and person.
1109
+ ---
1110
+ tags:
1111
+ - Persons
1112
+ parameters:
1113
+ - in: path
1114
+ name: person_id
1115
+ required: True
1116
+ type: string
1117
+ format: UUID
1118
+ x-example: a24a6ea4-ce75-4665-a070-57453082c25
1119
+ responses:
1120
+ 200:
1121
+ description: All day off recorded for given person.
1122
+ """
1123
+ user_service.check_person_is_not_bot(person_id)
1124
+ user_id = persons_service.get_current_user()["id"]
1125
+ if person_id != user_id:
1126
+ permissions.check_admin_permissions()
1127
+ return time_spents_service.get_day_offs_between(
1128
+ person_id=person_id,
1129
+ )
1130
+
1131
+
1139
1132
  class AddToDepartmentResource(Resource, ArgsMixin):
1140
1133
  """
1141
1134
  Add a user to given department.
@@ -1261,6 +1254,11 @@ class ChangePasswordForPersonResource(Resource, ArgsMixin):
1261
1254
  permissions.check_admin_permissions()
1262
1255
  try:
1263
1256
  person = persons_service.get_person(person_id)
1257
+ if (
1258
+ person["email"] in config.PROTECTED_ACCOUNTS
1259
+ and person["id"] != persons_service.get_current_user()["id"]
1260
+ ):
1261
+ raise PersonInProtectedAccounts()
1264
1262
  current_user = persons_service.get_current_user()
1265
1263
  auth.validate_password(password, password_2)
1266
1264
  password = auth.encrypt_password(password)
@@ -1271,7 +1269,7 @@ class ChangePasswordForPersonResource(Resource, ArgsMixin):
1271
1269
  )
1272
1270
  organisation = persons_service.get_organisation()
1273
1271
  time_string = format_datetime(
1274
- datetime.datetime.utcnow(),
1272
+ date_helpers.get_utc_now_datetime(),
1275
1273
  tzinfo=person["timezone"],
1276
1274
  locale=person["locale"],
1277
1275
  )
@@ -1304,6 +1302,14 @@ Thank you and see you soon on Kitsu,
1304
1302
  return {"error": True, "message": "Password is too short."}, 400
1305
1303
  except UnactiveUserException:
1306
1304
  return {"error": True, "message": "User is unactive."}, 400
1305
+ except PersonInProtectedAccounts:
1306
+ return (
1307
+ {
1308
+ "error": True,
1309
+ "message": "This user is in protected accounts.",
1310
+ },
1311
+ 400,
1312
+ )
1307
1313
 
1308
1314
  def get_arguments(self):
1309
1315
  args = self.get_args(
@@ -1365,7 +1371,7 @@ class DisableTwoFactorAuthenticationPersonResource(Resource, ArgsMixin):
1365
1371
  )
1366
1372
  organisation = persons_service.get_organisation()
1367
1373
  time_string = format_datetime(
1368
- datetime.datetime.utcnow(),
1374
+ date_helpers.get_utc_now_datetime(),
1369
1375
  tzinfo=person["timezone"],
1370
1376
  locale=person["locale"],
1371
1377
  )
@@ -2,6 +2,9 @@ from flask import Blueprint
2
2
  from zou.app.utils.api import configure_api_from_blueprint
3
3
 
4
4
  from zou.app.blueprints.previews.resources import (
5
+ AddTaskBatchCommentResource,
6
+ AddTasksBatchCommentResource,
7
+ AttachmentThumbnailResource,
5
8
  CreatePreviewFilePictureResource,
6
9
  PreviewFileLowMovieResource,
7
10
  PreviewFileMovieResource,
@@ -13,14 +16,13 @@ from zou.app.blueprints.previews.resources import (
13
16
  PreviewFilePreviewResource,
14
17
  PreviewFileOriginalResource,
15
18
  PreviewFileTileResource,
16
- CreateOrganisationThumbnailResource,
17
19
  OrganisationThumbnailResource,
18
- CreateProjectThumbnailResource,
20
+ CreateOrganisationThumbnailResource,
19
21
  ProjectThumbnailResource,
20
- CreatePersonThumbnailResource,
22
+ CreateProjectThumbnailResource,
21
23
  PersonThumbnailResource,
24
+ CreatePersonThumbnailResource,
22
25
  RunningPreviewFiles,
23
- LegacySetMainPreviewResource,
24
26
  SetMainPreviewResource,
25
27
  UpdateAnnotationsResource,
26
28
  UpdatePreviewPositionResource,
@@ -37,6 +39,14 @@ routes = [
37
39
  "/pictures/preview-files/<instance_id>",
38
40
  CreatePreviewFilePictureResource,
39
41
  ),
42
+ (
43
+ "/actions/tasks/<task_id>/batch-comment",
44
+ AddTaskBatchCommentResource,
45
+ ),
46
+ (
47
+ "/actions/tasks/batch-comment",
48
+ AddTasksBatchCommentResource,
49
+ ),
40
50
  (
41
51
  "/movies/originals/preview-files/<instance_id>.mp4",
42
52
  PreviewFileMovieResource,
@@ -53,6 +63,10 @@ routes = [
53
63
  "/pictures/thumbnails/preview-files/<instance_id>.png",
54
64
  PreviewFileThumbnailResource,
55
65
  ),
66
+ (
67
+ "/pictures/thumbnails/attachment-files/<attachment_file_id>.png",
68
+ AttachmentThumbnailResource,
69
+ ),
56
70
  (
57
71
  "/pictures/thumbnails-square/preview-files/<instance_id>.png",
58
72
  PreviewFileThumbnailSquareResource,
@@ -113,10 +127,6 @@ routes = [
113
127
  "/pictures/preview-background-files/<instance_id>.<extension>",
114
128
  PreviewBackgroundFileResource,
115
129
  ),
116
- (
117
- "/actions/entities/<entity_id>/set-main-preview/<preview_file_id>",
118
- LegacySetMainPreviewResource,
119
- ),
120
130
  (
121
131
  "/actions/preview-files/<preview_file_id>/set-main-preview",
122
132
  SetMainPreviewResource,