zou 0.20.39__tar.gz → 0.20.40__tar.gz

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 (457) hide show
  1. {zou-0.20.39/zou.egg-info → zou-0.20.40}/PKG-INFO +2 -1
  2. {zou-0.20.39 → zou-0.20.40}/setup.cfg +1 -0
  3. zou-0.20.40/zou/__init__.py +1 -0
  4. {zou-0.20.39 → zou-0.20.40}/zou/app/api.py +18 -14
  5. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/__init__.py +4 -0
  6. zou-0.20.40/zou/app/services/plugins_service.py +169 -0
  7. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/commands.py +51 -1
  8. zou-0.20.40/zou/app/utils/plugins.py +88 -0
  9. {zou-0.20.39 → zou-0.20.40}/zou/cli.py +64 -4
  10. {zou-0.20.39 → zou-0.20.40/zou.egg-info}/PKG-INFO +2 -1
  11. {zou-0.20.39 → zou-0.20.40}/zou.egg-info/SOURCES.txt +2 -1
  12. {zou-0.20.39 → zou-0.20.40}/zou.egg-info/requires.txt +1 -0
  13. zou-0.20.39/zou/__init__.py +0 -1
  14. zou-0.20.39/zou/app/services/plugin_service.py +0 -195
  15. {zou-0.20.39 → zou-0.20.40}/LICENSE +0 -0
  16. {zou-0.20.39 → zou-0.20.40}/README.rst +0 -0
  17. {zou-0.20.39 → zou-0.20.40}/pyproject.toml +0 -0
  18. {zou-0.20.39 → zou-0.20.40}/setup.py +0 -0
  19. {zou-0.20.39 → zou-0.20.40}/zou/app/__init__.py +0 -0
  20. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/__init__.py +0 -0
  21. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/assets/__init__.py +0 -0
  22. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/assets/resources.py +0 -0
  23. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/auth/__init__.py +0 -0
  24. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/auth/resources.py +0 -0
  25. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/breakdown/__init__.py +0 -0
  26. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/breakdown/resources.py +0 -0
  27. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/chats/__init__.py +0 -0
  28. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/chats/resources.py +0 -0
  29. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/comments/__init__.py +0 -0
  30. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/comments/resources.py +0 -0
  31. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/concepts/__init__.py +0 -0
  32. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/concepts/resources.py +0 -0
  33. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/asset_instance.py +0 -0
  34. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/attachment_file.py +0 -0
  35. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/base.py +0 -0
  36. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/budget.py +0 -0
  37. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/budget_entry.py +0 -0
  38. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/chat.py +0 -0
  39. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/chat_message.py +0 -0
  40. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/comments.py +0 -0
  41. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/custom_action.py +0 -0
  42. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/day_off.py +0 -0
  43. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/department.py +0 -0
  44. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/entity.py +0 -0
  45. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/entity_link.py +0 -0
  46. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/entity_type.py +0 -0
  47. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/event.py +0 -0
  48. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/file_status.py +0 -0
  49. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/metadata_descriptor.py +0 -0
  50. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/milestone.py +0 -0
  51. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/news.py +0 -0
  52. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/notification.py +0 -0
  53. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/organisation.py +0 -0
  54. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/output_file.py +0 -0
  55. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/output_type.py +0 -0
  56. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/person.py +0 -0
  57. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/playlist.py +0 -0
  58. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/plugin.py +0 -0
  59. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/preview_background_file.py +0 -0
  60. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/preview_file.py +0 -0
  61. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/project.py +0 -0
  62. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/project_status.py +0 -0
  63. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/salary_scale.py +0 -0
  64. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/schedule_item.py +0 -0
  65. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/search_filter.py +0 -0
  66. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/search_filter_group.py +0 -0
  67. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/software.py +0 -0
  68. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/status_automation.py +0 -0
  69. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/studio.py +0 -0
  70. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/subscription.py +0 -0
  71. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/task.py +0 -0
  72. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/task_status.py +0 -0
  73. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/task_type.py +0 -0
  74. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/time_spent.py +0 -0
  75. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/crud/working_file.py +0 -0
  76. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/edits/__init__.py +0 -0
  77. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/edits/resources.py +0 -0
  78. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/entities/__init__.py +0 -0
  79. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/entities/resources.py +0 -0
  80. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/events/__init__.py +0 -0
  81. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/events/resources.py +0 -0
  82. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/export/__init__.py +0 -0
  83. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/export/csv/__init__.py +0 -0
  84. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/export/csv/assets.py +0 -0
  85. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/export/csv/base.py +0 -0
  86. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/export/csv/casting.py +0 -0
  87. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/export/csv/edits.py +0 -0
  88. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/export/csv/persons.py +0 -0
  89. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/export/csv/playlists.py +0 -0
  90. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/export/csv/projects.py +0 -0
  91. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/export/csv/shots.py +0 -0
  92. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/export/csv/task_types.py +0 -0
  93. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/export/csv/tasks.py +0 -0
  94. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/export/csv/time_spents.py +0 -0
  95. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/files/__init__.py +0 -0
  96. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/files/resources.py +0 -0
  97. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/index/__init__.py +0 -0
  98. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/index/resources.py +0 -0
  99. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/news/__init__.py +0 -0
  100. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/news/resources.py +0 -0
  101. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/persons/__init__.py +0 -0
  102. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/persons/resources.py +0 -0
  103. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/playlists/__init__.py +0 -0
  104. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/playlists/resources.py +0 -0
  105. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/previews/__init__.py +0 -0
  106. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/previews/resources.py +0 -0
  107. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/projects/__init__.py +0 -0
  108. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/projects/resources.py +0 -0
  109. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/search/__init__.py +0 -0
  110. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/search/resources.py +0 -0
  111. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/shots/__init__.py +0 -0
  112. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/shots/resources.py +0 -0
  113. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/__init__.py +0 -0
  114. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/csv/__init__.py +0 -0
  115. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/csv/assets.py +0 -0
  116. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/csv/base.py +0 -0
  117. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/csv/casting.py +0 -0
  118. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/csv/edits.py +0 -0
  119. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/csv/persons.py +0 -0
  120. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/csv/shots.py +0 -0
  121. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/csv/task_type_estimations.py +0 -0
  122. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/kitsu.py +0 -0
  123. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/otio.py +0 -0
  124. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/__init__.py +0 -0
  125. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/assets.py +0 -0
  126. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/base.py +0 -0
  127. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/episode.py +0 -0
  128. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/exception.py +0 -0
  129. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/import_errors.py +0 -0
  130. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/notes.py +0 -0
  131. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/person.py +0 -0
  132. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/project.py +0 -0
  133. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/scene.py +0 -0
  134. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/sequence.py +0 -0
  135. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/shot.py +0 -0
  136. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/status.py +0 -0
  137. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/steps.py +0 -0
  138. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/tasks.py +0 -0
  139. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/team.py +0 -0
  140. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/source/shotgun/versions.py +0 -0
  141. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/tasks/__init__.py +0 -0
  142. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/tasks/resources.py +0 -0
  143. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/user/__init__.py +0 -0
  144. {zou-0.20.39 → zou-0.20.40}/zou/app/blueprints/user/resources.py +0 -0
  145. {zou-0.20.39 → zou-0.20.40}/zou/app/config.py +0 -0
  146. {zou-0.20.39 → zou-0.20.40}/zou/app/file_trees/default.json +0 -0
  147. {zou-0.20.39 → zou-0.20.40}/zou/app/file_trees/simple.json +0 -0
  148. {zou-0.20.39 → zou-0.20.40}/zou/app/indexer/__init__.py +0 -0
  149. {zou-0.20.39 → zou-0.20.40}/zou/app/indexer/indexing.py +0 -0
  150. {zou-0.20.39 → zou-0.20.40}/zou/app/mixin.py +0 -0
  151. {zou-0.20.39 → zou-0.20.40}/zou/app/models/__init__.py +0 -0
  152. {zou-0.20.39 → zou-0.20.40}/zou/app/models/asset_instance.py +0 -0
  153. {zou-0.20.39 → zou-0.20.40}/zou/app/models/attachment_file.py +0 -0
  154. {zou-0.20.39 → zou-0.20.40}/zou/app/models/base.py +0 -0
  155. {zou-0.20.39 → zou-0.20.40}/zou/app/models/budget.py +0 -0
  156. {zou-0.20.39 → zou-0.20.40}/zou/app/models/budget_entry.py +0 -0
  157. {zou-0.20.39 → zou-0.20.40}/zou/app/models/build_job.py +0 -0
  158. {zou-0.20.39 → zou-0.20.40}/zou/app/models/chat.py +0 -0
  159. {zou-0.20.39 → zou-0.20.40}/zou/app/models/chat_message.py +0 -0
  160. {zou-0.20.39 → zou-0.20.40}/zou/app/models/comment.py +0 -0
  161. {zou-0.20.39 → zou-0.20.40}/zou/app/models/custom_action.py +0 -0
  162. {zou-0.20.39 → zou-0.20.40}/zou/app/models/data_import_error.py +0 -0
  163. {zou-0.20.39 → zou-0.20.40}/zou/app/models/day_off.py +0 -0
  164. {zou-0.20.39 → zou-0.20.40}/zou/app/models/department.py +0 -0
  165. {zou-0.20.39 → zou-0.20.40}/zou/app/models/desktop_login_log.py +0 -0
  166. {zou-0.20.39 → zou-0.20.40}/zou/app/models/entity.py +0 -0
  167. {zou-0.20.39 → zou-0.20.40}/zou/app/models/entity_type.py +0 -0
  168. {zou-0.20.39 → zou-0.20.40}/zou/app/models/event.py +0 -0
  169. {zou-0.20.39 → zou-0.20.40}/zou/app/models/file_status.py +0 -0
  170. {zou-0.20.39 → zou-0.20.40}/zou/app/models/login_log.py +0 -0
  171. {zou-0.20.39 → zou-0.20.40}/zou/app/models/metadata_descriptor.py +0 -0
  172. {zou-0.20.39 → zou-0.20.40}/zou/app/models/milestone.py +0 -0
  173. {zou-0.20.39 → zou-0.20.40}/zou/app/models/news.py +0 -0
  174. {zou-0.20.39 → zou-0.20.40}/zou/app/models/notification.py +0 -0
  175. {zou-0.20.39 → zou-0.20.40}/zou/app/models/organisation.py +0 -0
  176. {zou-0.20.39 → zou-0.20.40}/zou/app/models/output_file.py +0 -0
  177. {zou-0.20.39 → zou-0.20.40}/zou/app/models/output_type.py +0 -0
  178. {zou-0.20.39 → zou-0.20.40}/zou/app/models/person.py +0 -0
  179. {zou-0.20.39 → zou-0.20.40}/zou/app/models/playlist.py +0 -0
  180. {zou-0.20.39 → zou-0.20.40}/zou/app/models/plugin.py +0 -0
  181. {zou-0.20.39 → zou-0.20.40}/zou/app/models/preview_background_file.py +0 -0
  182. {zou-0.20.39 → zou-0.20.40}/zou/app/models/preview_file.py +0 -0
  183. {zou-0.20.39 → zou-0.20.40}/zou/app/models/project.py +0 -0
  184. {zou-0.20.39 → zou-0.20.40}/zou/app/models/project_status.py +0 -0
  185. {zou-0.20.39 → zou-0.20.40}/zou/app/models/salary_scale.py +0 -0
  186. {zou-0.20.39 → zou-0.20.40}/zou/app/models/schedule_item.py +0 -0
  187. {zou-0.20.39 → zou-0.20.40}/zou/app/models/search_filter.py +0 -0
  188. {zou-0.20.39 → zou-0.20.40}/zou/app/models/search_filter_group.py +0 -0
  189. {zou-0.20.39 → zou-0.20.40}/zou/app/models/serializer.py +0 -0
  190. {zou-0.20.39 → zou-0.20.40}/zou/app/models/software.py +0 -0
  191. {zou-0.20.39 → zou-0.20.40}/zou/app/models/status_automation.py +0 -0
  192. {zou-0.20.39 → zou-0.20.40}/zou/app/models/studio.py +0 -0
  193. {zou-0.20.39 → zou-0.20.40}/zou/app/models/subscription.py +0 -0
  194. {zou-0.20.39 → zou-0.20.40}/zou/app/models/task.py +0 -0
  195. {zou-0.20.39 → zou-0.20.40}/zou/app/models/task_status.py +0 -0
  196. {zou-0.20.39 → zou-0.20.40}/zou/app/models/task_type.py +0 -0
  197. {zou-0.20.39 → zou-0.20.40}/zou/app/models/time_spent.py +0 -0
  198. {zou-0.20.39 → zou-0.20.40}/zou/app/models/working_file.py +0 -0
  199. {zou-0.20.39 → zou-0.20.40}/zou/app/services/__init__.py +0 -0
  200. {zou-0.20.39 → zou-0.20.40}/zou/app/services/assets_service.py +0 -0
  201. {zou-0.20.39 → zou-0.20.40}/zou/app/services/auth_service.py +0 -0
  202. {zou-0.20.39 → zou-0.20.40}/zou/app/services/backup_service.py +0 -0
  203. {zou-0.20.39 → zou-0.20.40}/zou/app/services/base_service.py +0 -0
  204. {zou-0.20.39 → zou-0.20.40}/zou/app/services/breakdown_service.py +0 -0
  205. {zou-0.20.39 → zou-0.20.40}/zou/app/services/budget_service.py +0 -0
  206. {zou-0.20.39 → zou-0.20.40}/zou/app/services/chats_service.py +0 -0
  207. {zou-0.20.39 → zou-0.20.40}/zou/app/services/comments_service.py +0 -0
  208. {zou-0.20.39 → zou-0.20.40}/zou/app/services/concepts_service.py +0 -0
  209. {zou-0.20.39 → zou-0.20.40}/zou/app/services/custom_actions_service.py +0 -0
  210. {zou-0.20.39 → zou-0.20.40}/zou/app/services/deletion_service.py +0 -0
  211. {zou-0.20.39 → zou-0.20.40}/zou/app/services/edits_service.py +0 -0
  212. {zou-0.20.39 → zou-0.20.40}/zou/app/services/emails_service.py +0 -0
  213. {zou-0.20.39 → zou-0.20.40}/zou/app/services/entities_service.py +0 -0
  214. {zou-0.20.39 → zou-0.20.40}/zou/app/services/events_service.py +0 -0
  215. {zou-0.20.39 → zou-0.20.40}/zou/app/services/exception.py +0 -0
  216. {zou-0.20.39 → zou-0.20.40}/zou/app/services/file_tree_service.py +0 -0
  217. {zou-0.20.39 → zou-0.20.40}/zou/app/services/files_service.py +0 -0
  218. {zou-0.20.39 → zou-0.20.40}/zou/app/services/index_service.py +0 -0
  219. {zou-0.20.39 → zou-0.20.40}/zou/app/services/names_service.py +0 -0
  220. {zou-0.20.39 → zou-0.20.40}/zou/app/services/news_service.py +0 -0
  221. {zou-0.20.39 → zou-0.20.40}/zou/app/services/notifications_service.py +0 -0
  222. {zou-0.20.39 → zou-0.20.40}/zou/app/services/persons_service.py +0 -0
  223. {zou-0.20.39 → zou-0.20.40}/zou/app/services/playlists_service.py +0 -0
  224. {zou-0.20.39 → zou-0.20.40}/zou/app/services/preview_files_service.py +0 -0
  225. {zou-0.20.39 → zou-0.20.40}/zou/app/services/projects_service.py +0 -0
  226. {zou-0.20.39 → zou-0.20.40}/zou/app/services/scenes_service.py +0 -0
  227. {zou-0.20.39 → zou-0.20.40}/zou/app/services/schedule_service.py +0 -0
  228. {zou-0.20.39 → zou-0.20.40}/zou/app/services/shots_service.py +0 -0
  229. {zou-0.20.39 → zou-0.20.40}/zou/app/services/stats_service.py +0 -0
  230. {zou-0.20.39 → zou-0.20.40}/zou/app/services/status_automations_service.py +0 -0
  231. {zou-0.20.39 → zou-0.20.40}/zou/app/services/sync_service.py +0 -0
  232. {zou-0.20.39 → zou-0.20.40}/zou/app/services/tasks_service.py +0 -0
  233. {zou-0.20.39 → zou-0.20.40}/zou/app/services/telemetry_services.py +0 -0
  234. {zou-0.20.39 → zou-0.20.40}/zou/app/services/time_spents_service.py +0 -0
  235. {zou-0.20.39 → zou-0.20.40}/zou/app/services/user_service.py +0 -0
  236. {zou-0.20.39 → zou-0.20.40}/zou/app/stores/__init__.py +0 -0
  237. {zou-0.20.39 → zou-0.20.40}/zou/app/stores/auth_tokens_store.py +0 -0
  238. {zou-0.20.39 → zou-0.20.40}/zou/app/stores/file_store.py +0 -0
  239. {zou-0.20.39 → zou-0.20.40}/zou/app/stores/publisher_store.py +0 -0
  240. {zou-0.20.39 → zou-0.20.40}/zou/app/stores/queue_store.py +0 -0
  241. {zou-0.20.39 → zou-0.20.40}/zou/app/swagger.py +0 -0
  242. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/__init__.py +0 -0
  243. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/api.py +0 -0
  244. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/auth.py +0 -0
  245. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/cache.py +0 -0
  246. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/chats.py +0 -0
  247. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/colors.py +0 -0
  248. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/csv_utils.py +0 -0
  249. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/date_helpers.py +0 -0
  250. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/dbhelpers.py +0 -0
  251. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/emails.py +0 -0
  252. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/env.py +0 -0
  253. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/events.py +0 -0
  254. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/fido.py +0 -0
  255. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/fields.py +0 -0
  256. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/flask.py +0 -0
  257. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/fs.py +0 -0
  258. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/git.py +0 -0
  259. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/logs.py +0 -0
  260. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/monitoring.py +0 -0
  261. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/permissions.py +0 -0
  262. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/query.py +0 -0
  263. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/redis.py +0 -0
  264. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/remote_job.py +0 -0
  265. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/saml.py +0 -0
  266. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/shell.py +0 -0
  267. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/string.py +0 -0
  268. {zou-0.20.39 → zou-0.20.40}/zou/app/utils/thumbnail.py +0 -0
  269. {zou-0.20.39 → zou-0.20.40}/zou/debug.py +0 -0
  270. {zou-0.20.39 → zou-0.20.40}/zou/event_stream.py +0 -0
  271. {zou-0.20.39 → zou-0.20.40}/zou/job_settings.py +0 -0
  272. {zou-0.20.39 → zou-0.20.40}/zou/migrations/README +0 -0
  273. {zou-0.20.39 → zou-0.20.40}/zou/migrations/__init__.py +0 -0
  274. {zou-0.20.39 → zou-0.20.40}/zou/migrations/alembic.ini +0 -0
  275. {zou-0.20.39 → zou-0.20.40}/zou/migrations/env.py +0 -0
  276. {zou-0.20.39 → zou-0.20.40}/zou/migrations/script.py.mako +0 -0
  277. {zou-0.20.39 → zou-0.20.40}/zou/migrations/utils/__init__.py +0 -0
  278. {zou-0.20.39 → zou-0.20.40}/zou/migrations/utils/base.py +0 -0
  279. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/003be8a91001_add_start_and_end_dates_to_projects.py +0 -0
  280. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/0596674df51d_add_department_mentions_to_comments.py +0 -0
  281. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/05ac7e8caa21_remove_unique_constraint_for_taskstatus_.py +0 -0
  282. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/05b7dc79a416_add_archived_fields_to_main_tables.py +0 -0
  283. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/06552e22f9e7_add_comment_updated_by.py +0 -0
  284. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/0cf5e0e035fa_drop_column_tasktype_for_shots.py +0 -0
  285. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/0ec3762a745d_add_attachment_table.py +0 -0
  286. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/0ef6416a507b_.py +0 -0
  287. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/10cf267d95c9_fix_schedule_item.py +0 -0
  288. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/16328eae4b5f_add_new_constraint_for_timespent.py +0 -0
  289. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/16df47d76c64_add_some_indexes.py +0 -0
  290. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/17ef8f7be758_disallow_null_choicetype.py +0 -0
  291. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/1bb55759146f_add_table_studio.py +0 -0
  292. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/1cb44194db49_add_file_size_field_to_preview_file.py +0 -0
  293. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/1e150c2cea4d_add_nb_entities_out.py +0 -0
  294. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/1e2d77a2f0c4_add_hd_by_default_column.py +0 -0
  295. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/1fab8c420678_add_attachments_to_message_chats.py +0 -0
  296. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/20a8ad264659_tasktypeassettypelink_.py +0 -0
  297. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/20dfeb36142b_add_projecttaskstatuslink_roles_for_.py +0 -0
  298. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/23122f290ca2_add_entity_chat_models.py +0 -0
  299. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/269d41bfb73f_add_entity_entity_links.py +0 -0
  300. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/2762a797f1f9_add_people_salary_information.py +0 -0
  301. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/29df910f04a4_create_unique_constraint_project_id_.py +0 -0
  302. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/29fe01a6c9eb_add_status_automation_field.py +0 -0
  303. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/2adc020885fa_.py +0 -0
  304. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/2baede80b111_add_entity_status_field.py +0 -0
  305. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/306266361f4f_.py +0 -0
  306. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/307edd8c639d_change_comment_updated_by_in_comment_.py +0 -0
  307. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/328fd44c6347_add_entity_created_by.py +0 -0
  308. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/32f134ff1201_add_is_shared_flag_to_filters.py +0 -0
  309. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/346250b5304c_add_position_to_preview_files.py +0 -0
  310. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/3476e147e632_add_acks_to_comments.py +0 -0
  311. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/389cfb9de776_.py +0 -0
  312. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/38baa9a23b3d_.py +0 -0
  313. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/398150912a3f_validation_status_preview.py +0 -0
  314. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/3b0d1321079e_.py +0 -0
  315. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/3d5c93bafb9d_.py +0 -0
  316. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/3e0538ddf80f_.py +0 -0
  317. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/3fee3bd10f9d_.py +0 -0
  318. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/4095103c7d01_add_is_clients_isolated_flag_to_projects.py +0 -0
  319. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/40dea9555940_.py +0 -0
  320. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/42ec83db6a01_change_person_preferred_two_factor_.py +0 -0
  321. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/43d0cf0ed5e7_.py +0 -0
  322. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/443d1e78a932_.py +0 -0
  323. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/45c2de366e66_.py +0 -0
  324. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/45dafbb3f4e1_for_person_contract_type_disallow_null.py +0 -0
  325. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/45f739ef962a_add_people_salary_scale_table.py +0 -0
  326. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/4715c2586036_add_last_preview_file_fields.py +0 -0
  327. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/4aab1f84ad72_introduce_plugin_table.py +0 -0
  328. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/4e3738cdc34c_.py +0 -0
  329. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/4f2398ebcd49_.py +0 -0
  330. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/523ee9647bee_.py +0 -0
  331. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/539a3a00c417_for_departmentlink_index_person_id_.py +0 -0
  332. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/54ee0d1d60ba_add_build_job_model.py +0 -0
  333. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/556526e47daa_.py +0 -0
  334. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/57222395f2be_add_statusautomation_import_last_revision.py +0 -0
  335. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/5798d2c9020b_change_person_role_to_choicetype.py +0 -0
  336. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/590aa1ffe731_add_notifications_enabled_flag.py +0 -0
  337. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/59a7445a966c_add_entity_is_shared.py +0 -0
  338. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/5a291251823c_add_max_retake_parameter.py +0 -0
  339. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/5ab9d7a75887_.py +0 -0
  340. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/5b0fcbb94f24_.py +0 -0
  341. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/5b7fa3e51701_add_is_client_allowed_flag_to_task_.py +0 -0
  342. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/5b980f0dc365_add_comment_links.py +0 -0
  343. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/5b9fd9ddfe43_add_homepage_and_contract_fields.py +0 -0
  344. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/5c0498e264bc_add_slack_fields.py +0 -0
  345. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/5e2ce62632a6_add_workflow_to_project.py +0 -0
  346. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/680c64565f9d_for_searchfiltergroup_is_shared.py +0 -0
  347. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/693cc511d28d_add_taskstatus_priority.py +0 -0
  348. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/6aa446ee4072_add_is_for_all_flage_to_playlists.py +0 -0
  349. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/6bd3b102d61b_.py +0 -0
  350. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/6c597e842afa_add_task_type_field_to_playlists.py +0 -0
  351. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/6d1b2c60f58b_add_milestone_model.py +0 -0
  352. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/6d7fa5a8e9a5_add_timesheets_locked_field_to_org.py +0 -0
  353. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/6eeaff945706_add_data_field_on_entity_links.py +0 -0
  354. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/6f6049877105_.py +0 -0
  355. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/7417c8eb70d8_add_for_entity_field_to_playlists.py +0 -0
  356. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/772a5e43f05b_.py +0 -0
  357. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/7748d3d22925_add_columns_to_searchfilter_table_to_.py +0 -0
  358. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/77d6820f494f_add_reply_to_notif.py +0 -0
  359. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/7a16258f2fab_add_currency_field_to_budgets.py +0 -0
  360. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/7b1f765677d8_.py +0 -0
  361. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/7bc746997e8d_add_slack_token_field_to_organisation.py +0 -0
  362. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/7dc79d4ed7cd_.py +0 -0
  363. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/818f7bda2528_.py +0 -0
  364. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/82e7f7a95e84_add_project_id_to_events.py +0 -0
  365. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/82ee682204ab_add_is_generated_from_ldap_column_to_.py +0 -0
  366. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/83e2f33a9b14_add_project_bugdet_table.py +0 -0
  367. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/8588f254d6b8_add_archived_fields.py +0 -0
  368. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/8739ae9fa28b_add_for_client_field.py +0 -0
  369. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/87efceb6745b_add_ready_for_to_entity.py +0 -0
  370. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/892b264937ec_.py +0 -0
  371. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/8a1b4a1b7f4a_add_totp_columns_for_person.py +0 -0
  372. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/8ab98c178903_add_budget_entry_table.py +0 -0
  373. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/8e4f39e321f4_add_day_off_table.py +0 -0
  374. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/8e67c183bed7_add_preference_fields.py +0 -0
  375. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/8fbd40afbe5f_allow_to_set_float_values_for_.py +0 -0
  376. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/9010a64e5a2d_add_indices.py +0 -0
  377. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/9060dd4f6116_notification_uc.py +0 -0
  378. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/925771029620_.py +0 -0
  379. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/92b40d79ad3f_allow_message_attachments.py +0 -0
  380. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/92bdfe07e5f5_discord_integration.py +0 -0
  381. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/956659992419_add_columns_for_person_to_store_fido_.py +0 -0
  382. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/96c79d31e648_add_mail_otp_columns_for_person.py +0 -0
  383. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/96f58a4a2a58_person_partial_index_for_email_only_.py +0 -0
  384. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/971dbf5a0faf_add_short_name_for_asset_type_entity_.py +0 -0
  385. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/98c90621cf58_add_for_client_flag_to_playlist.py +0 -0
  386. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/99825b9cc778_.py +0 -0
  387. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/9a09467f9b2c_.py +0 -0
  388. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/9b85c14fa8a7_add_day_off_new_columns.py +0 -0
  389. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/9bd17364fc18_.py +0 -0
  390. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/9d3bb33c6fc6_add_department_keys_to_filter_models.py +0 -0
  391. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/9e5b3a9b0cee_add_new_column_metadatadescriptor_data_type_.py +0 -0
  392. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/9f8445f9b42c_add_man_days_fields.py +0 -0
  393. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/a23682ccc1f1_.py +0 -0
  394. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/a252a094e977_add_descriptions_for_entities_tasks_and_.py +0 -0
  395. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/a519c710877c_.py +0 -0
  396. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/a65bdadbae2f_.py +0 -0
  397. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/a66508788c53_add_nb_assets_ready.py +0 -0
  398. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/a6c25eed3ea1_add_login_failed_attemps_and_last_login_.py +0 -0
  399. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/a7c43f3fbc76_add_duration_column_to_the_preview_file.py +0 -0
  400. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/aa0a60033106_feedback_request.py +0 -0
  401. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/addbad59c706_allow_to_manage_drawings_instead_of_.py +0 -0
  402. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/addbbefa7028_add_departments_link_to_metadata_.py +0 -0
  403. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/ae0127f2fc56_add_previewfile_width_and_previewfile_.py +0 -0
  404. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/af1790868e2c_.py +0 -0
  405. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/b45cb782bb9c_.py +0 -0
  406. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/b4dd0add5f79_.py +0 -0
  407. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/b8c0a0f9d054_drop_task_status_is_reviewable.py +0 -0
  408. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/b8ed0fb263f8_add_person_jti_and_jti_expiration_date.py +0 -0
  409. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/b97a71306fc8_add_is_casting_standby_column_to_entity.py +0 -0
  410. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/be56dc0fb760_for_is_shared_disallow_nullable.py +0 -0
  411. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/bf1347acdee2_.py +0 -0
  412. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/c49e41f1298b_add_previewbackground.py +0 -0
  413. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/c68c2a62cfac_add_mimetype_column_to_attachment.py +0 -0
  414. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/c726b98be194_.py +0 -0
  415. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/c81f3e83bdb5_.py +0 -0
  416. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/ca28796a2a62_add_is_done_field_to_the_task_model.py +0 -0
  417. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/cf3d365de164_add_entity_version_model.py +0 -0
  418. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/cf6cec6d6bf5_add_status_field_to_preview_file.py +0 -0
  419. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/d25118cddcaa_modify_salary_scale_model.py +0 -0
  420. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/d80267806131_task_status_new_column_is_default.py +0 -0
  421. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/d8dcd5196d57_add_casting_label.py +0 -0
  422. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/de8a3de227ef_.py +0 -0
  423. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/deeacd38d373_for_projecttaskstatuslink_set_default_.py +0 -0
  424. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/df1834485f57_.py +0 -0
  425. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/df9f8a147e80_change_file_size_to_big_integer.py +0 -0
  426. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/e1ef93f40d3d_.py +0 -0
  427. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/e29638428dfd_add_schedule_item_table.py +0 -0
  428. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/e3f6db74cc1e_.py +0 -0
  429. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/e839d6603c09_add_person_id_to_shot_history.py +0 -0
  430. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/ee2373fbe3a4_.py +0 -0
  431. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/f0567e8d0c62_.py +0 -0
  432. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/f0c6cbb61869_add_production_style_field.py +0 -0
  433. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/f344b867a911_for_description_of_entity_task_working_.py +0 -0
  434. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/f4ff5a73d283_add_person_ldap_uid.py +0 -0
  435. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/f5b113876a49_add_preferred_two_factor_authentication_.py +0 -0
  436. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/f5bdca075cdc_add_preview_download_flag_to_projects.py +0 -0
  437. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/f874ad5e898a_add_link_entity_type_task_type.py +0 -0
  438. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/f995b28fb749_.py +0 -0
  439. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/fb6b6f188497_.py +0 -0
  440. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/fb87feaaa094_add_missing_unique_constraints.py +0 -0
  441. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/fba149993140_add_missing_index.py +0 -0
  442. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/fc322f908695_.py +0 -0
  443. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/fee7c696166e_.py +0 -0
  444. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/feffd3c5b806_introduce_concepts.py +0 -0
  445. {zou-0.20.39 → zou-0.20.40}/zou/migrations/versions/ffeed4956ab1_add_more_details_to_projects.py +0 -0
  446. {zou-0.20.39 → zou-0.20.40}/zou/plugin_template/__init__.py +0 -0
  447. {zou-0.20.39 → zou-0.20.40}/zou/plugin_template/routes.py +0 -0
  448. {zou-0.20.39 → zou-0.20.40}/zou/remote/__init__.py +0 -0
  449. {zou-0.20.39 → zou-0.20.40}/zou/remote/config_payload.py +0 -0
  450. {zou-0.20.39 → zou-0.20.40}/zou/remote/normalize_movie.py +0 -0
  451. {zou-0.20.39 → zou-0.20.40}/zou/remote/playlist.py +0 -0
  452. {zou-0.20.39 → zou-0.20.40}/zou/utils/__init__.py +0 -0
  453. {zou-0.20.39 → zou-0.20.40}/zou/utils/movie.py +0 -0
  454. {zou-0.20.39 → zou-0.20.40}/zou.egg-info/dependency_links.txt +0 -0
  455. {zou-0.20.39 → zou-0.20.40}/zou.egg-info/entry_points.txt +0 -0
  456. {zou-0.20.39 → zou-0.20.40}/zou.egg-info/not-zip-safe +0 -0
  457. {zou-0.20.39 → zou-0.20.40}/zou.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zou
3
- Version: 0.20.39
3
+ Version: 0.20.40
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
@@ -73,6 +73,7 @@ Requires-Dist: slackclient==2.9.4
73
73
  Requires-Dist: spdx-license-list==3.26.0
74
74
  Requires-Dist: sqlalchemy_utils==0.41.2
75
75
  Requires-Dist: sqlalchemy==2.0.40
76
+ Requires-Dist: tabulate==0.9.0
76
77
  Requires-Dist: tomlkit==0.13.2
77
78
  Requires-Dist: ua-parser==1.0.1
78
79
  Requires-Dist: werkzeug==3.1.3
@@ -79,6 +79,7 @@ install_requires =
79
79
  spdx-license-list==3.26.0
80
80
  sqlalchemy_utils==0.41.2
81
81
  sqlalchemy==2.0.40
82
+ tabulate==0.9.0
82
83
  tomlkit==0.13.2
83
84
  ua-parser==1.0.1
84
85
  werkzeug==3.1.3
@@ -0,0 +1 @@
1
+ __version__ = "0.20.40"
@@ -1,13 +1,10 @@
1
1
  import os
2
2
  import sys
3
- import tomlkit
4
3
  import importlib
5
4
  import traceback
6
5
 
7
- from zou.app.utils import events
8
6
  from pathlib import Path
9
7
 
10
-
11
8
  from zou.app.blueprints.assets import blueprint as assets_blueprint
12
9
  from zou.app.blueprints.auth import blueprint as auth_blueprint
13
10
  from zou.app.blueprints.breakdown import blueprint as breakdown_blueprint
@@ -32,6 +29,9 @@ from zou.app.blueprints.user import blueprint as user_blueprint
32
29
  from zou.app.blueprints.edits import blueprint as edits_blueprint
33
30
  from zou.app.blueprints.concepts import blueprint as concepts_blueprint
34
31
 
32
+ from zou.app.utils.plugins import PluginManifest
33
+ from zou.app.utils import events
34
+
35
35
 
36
36
  def configure(app):
37
37
  """
@@ -98,30 +98,34 @@ def load_plugins(app):
98
98
  """
99
99
  Load plugins from the plugin folder.
100
100
  """
101
- abs_plugin_path = os.path.abspath(app.config["PLUGIN_FOLDER"])
101
+ plugin_folder = app.config["PLUGIN_FOLDER"]
102
+ abs_plugin_path = os.path.abspath(plugin_folder)
102
103
  if abs_plugin_path not in sys.path:
103
104
  sys.path.insert(0, abs_plugin_path)
104
105
 
105
- if os.path.exists(app.config["PLUGIN_FOLDER"]):
106
- for plugin_id in os.listdir(app.config["PLUGIN_FOLDER"]):
106
+ if os.path.exists(plugin_folder):
107
+ for plugin_id in os.listdir(plugin_folder):
107
108
  try:
108
109
  load_plugin(app, plugin_id)
109
110
  app.logger.info(f"Plugin {plugin_id} loaded.")
110
- except:
111
- app.logger.error(f"Plugin {plugin_id} fails to load:")
112
- app.logger.error(traceback.format_exc())
111
+ except ImportError as e:
112
+ app.logger.error(f"Plugin {plugin_id} failed to import: {e}")
113
+ except Exception as e:
114
+ app.logger.error(
115
+ f"Plugin {plugin_id} failed to initialize: {e}"
116
+ )
117
+ app.logger.debug(traceback.format_exc())
113
118
 
114
119
  if abs_plugin_path in sys.path:
115
120
  sys.path.remove(abs_plugin_path)
116
121
 
117
122
 
118
123
  def load_plugin(app, plugin_id):
119
- with open(
120
- Path(app.config["PLUGIN_FOLDER"]).joinpath(plugin_id, "manifest.toml"),
121
- "rb",
122
- ) as manifest_file:
123
- manifest = tomlkit.load(manifest_file)
124
+ plugin_path = Path(app.config["PLUGIN_FOLDER"]) / plugin_id
125
+ manifest = PluginManifest.from_file(plugin_path / "manifest.toml")
126
+
124
127
  plugin_module = importlib.import_module(plugin_id)
125
128
  if hasattr(plugin_module, "init_plugin"):
126
129
  plugin_module.init_plugin(app, manifest)
130
+
127
131
  return plugin_module
@@ -134,6 +134,8 @@ from zou.app.blueprints.crud.salary_scale import (
134
134
  SalaryScaleResource,
135
135
  )
136
136
 
137
+ from zou.app.blueprints.crud.plugin import PluginResource, PluginsResource
138
+
137
139
  routes = [
138
140
  ("/data/persons", PersonsResource),
139
141
  ("/data/persons/<instance_id>", PersonResource),
@@ -218,6 +220,8 @@ routes = [
218
220
  ("/data/studios/<instance_id>", StudioResource),
219
221
  ("/data/salary-scales", SalaryScalesResource),
220
222
  ("/data/salary-scales/<instance_id>", SalaryScaleResource),
223
+ ("/data/plugins/<instance_id>", PluginResource),
224
+ ("/data/plugins", PluginsResource),
221
225
  ]
222
226
 
223
227
  blueprint = Blueprint("/data", "data")
@@ -0,0 +1,169 @@
1
+ import zipfile
2
+ import semver
3
+ import shutil
4
+ from pathlib import Path
5
+
6
+ from zou.app import config, db
7
+ from zou.app.models.plugin import Plugin
8
+ from zou.app.utils.plugins import PluginManifest
9
+
10
+
11
+ def install_plugin(path, force=False):
12
+ """
13
+ Install a plugin.
14
+ """
15
+ path = Path(path)
16
+ if not path.exists():
17
+ raise FileNotFoundError(f"Plugin path '{path}' does not exist.")
18
+
19
+ manifest = PluginManifest.from_plugin_path(path)
20
+ plugin = Plugin.query.filter_by(plugin_id=manifest.id).one_or_none()
21
+
22
+ try:
23
+ already_installed = False
24
+ if plugin:
25
+ current = semver.Version.parse(plugin.version)
26
+ new = semver.Version.parse(str(manifest.version))
27
+ if not force and new <= current:
28
+ raise ValueError(
29
+ f"Plugin version {new} is not newer than {current}."
30
+ )
31
+ plugin.update_no_commit(manifest.to_model_dict())
32
+ already_installed = True
33
+ else:
34
+ plugin = Plugin.create_no_commit(**manifest.to_model_dict())
35
+
36
+ install_plugin_files(manifest.id, path, already_installed)
37
+ except Exception:
38
+ uninstall_plugin_files(manifest.id)
39
+ db.session.rollback()
40
+ db.session.remove()
41
+ raise
42
+
43
+ Plugin.commit()
44
+ return plugin.serialize()
45
+
46
+
47
+ def install_plugin_files(plugin_id, path, already_installed=False):
48
+ """
49
+ Install plugin files.
50
+ """
51
+ path = Path(path)
52
+ plugin_path = Path(config.PLUGIN_FOLDER) / plugin_id
53
+ if already_installed and plugin_path.exists():
54
+ shutil.rmtree(plugin_path)
55
+
56
+ plugin_path.mkdir(parents=True, exist_ok=True)
57
+
58
+ if path.is_dir():
59
+ shutil.copytree(path, plugin_path, dirs_exist_ok=True)
60
+ elif zipfile.is_zipfile(path):
61
+ shutil.unpack_archive(path, plugin_path, format="zip")
62
+ else:
63
+ raise ValueError(
64
+ f"Plugin path '{path}' is not a valid zip file or a directory."
65
+ )
66
+
67
+ return plugin_path
68
+
69
+
70
+ def uninstall_plugin_files(plugin_id):
71
+ """
72
+ Uninstall plugin files.
73
+ """
74
+ plugin_path = Path(config.PLUGIN_FOLDER) / plugin_id
75
+ if plugin_path.exists():
76
+ shutil.rmtree(plugin_path)
77
+ return True
78
+ return False
79
+
80
+
81
+ def uninstall_plugin(plugin_id):
82
+ """
83
+ Uninstall a plugin.
84
+ """
85
+ installed = uninstall_plugin_files(plugin_id)
86
+ plugin = Plugin.query.filter_by(plugin_id=plugin_id).one_or_none()
87
+ if plugin is not None:
88
+ installed = True
89
+ plugin.delete()
90
+
91
+ if not installed:
92
+ raise ValueError(f"Plugin '{plugin_id}' is not installed.")
93
+ return True
94
+
95
+
96
+ def create_plugin_skeleton(
97
+ path,
98
+ id,
99
+ name,
100
+ description=None,
101
+ version=None,
102
+ maintainer=None,
103
+ website=None,
104
+ license=None,
105
+ force=False,
106
+ ):
107
+ plugin_template_path = (
108
+ Path(__file__).parent.parent.parent / "plugin_template"
109
+ )
110
+ plugin_path = Path(path) / id
111
+
112
+ if plugin_path.exists():
113
+ if force:
114
+ shutil.rmtree(plugin_path)
115
+ else:
116
+ raise FileExistsError(
117
+ f"Plugin '{id}' already exists in {plugin_path}."
118
+ )
119
+
120
+ shutil.copytree(plugin_template_path, plugin_path)
121
+
122
+ manifest = PluginManifest.from_file(plugin_path / "manifest.toml")
123
+
124
+ manifest.id = id
125
+ manifest.name = name
126
+ if description:
127
+ manifest.description = description
128
+ if version:
129
+ manifest.version = version
130
+ if maintainer:
131
+ manifest.maintainer = maintainer
132
+ if website:
133
+ manifest.website = website
134
+ if license:
135
+ manifest.license = license
136
+
137
+ manifest.validate()
138
+ manifest.write_to_path(plugin_path)
139
+
140
+ return plugin_path
141
+
142
+
143
+ def create_plugin_package(path, output_path, force=False):
144
+ """
145
+ Create a plugin package.
146
+ """
147
+ path = Path(path)
148
+ if not path.exists():
149
+ raise FileNotFoundError(f"Plugin path '{path}' does not exist.")
150
+
151
+ manifest = PluginManifest.from_plugin_path(path)
152
+
153
+ output_path = Path(output_path)
154
+ if not output_path.suffix == ".zip":
155
+ output_path /= f"{manifest.id}-{manifest.version}.zip"
156
+ if output_path.exists():
157
+ if force:
158
+ output_path.unlink()
159
+ else:
160
+ raise FileExistsError(
161
+ f"Output path '{output_path}' already exists."
162
+ )
163
+
164
+ output_path = shutil.make_archive(
165
+ output_path.with_suffix(""),
166
+ "zip",
167
+ path,
168
+ )
169
+ return output_path
@@ -5,8 +5,10 @@ import datetime
5
5
  import tempfile
6
6
  import sys
7
7
  import shutil
8
+ import click
9
+ import orjson as json
8
10
 
9
-
11
+ from tabulate import tabulate
10
12
  from ldap3 import Server, Connection, ALL, NTLM, SIMPLE
11
13
  from zou.app.utils import thumbnail as thumbnail_utils, auth
12
14
  from zou.app.stores import auth_tokens_store, file_store, queue_store
@@ -27,6 +29,7 @@ from zou.app.services import (
27
29
  from zou.app.models.person import Person
28
30
  from zou.app.models.preview_file import PreviewFile
29
31
  from zou.app.models.task import Task
32
+ from zou.app.models.plugin import Plugin
30
33
  from sqlalchemy.sql.expression import not_
31
34
 
32
35
  from zou.app.services.exception import (
@@ -823,3 +826,50 @@ def renormalize_movie_preview_files(
823
826
  f"Renormalization of preview file {preview_file_id} failed: {e}"
824
827
  )
825
828
  continue
829
+
830
+
831
+ def list_plugins(output_format, verbose, filter_field, filter_value):
832
+ with app.app_context():
833
+ query = Plugin.query
834
+
835
+ # Apply filter if needed
836
+ if filter_field and filter_value:
837
+ if filter_field == "maintainer":
838
+ query = query.filter(
839
+ Plugin.maintainer_name.ilike(f"%{filter_value}%")
840
+ )
841
+ else:
842
+ model_field = getattr(Plugin, filter_field)
843
+ query = query.filter(model_field.ilike(f"%{filter_value}%"))
844
+
845
+ plugins = query.order_by(Plugin.name).all()
846
+
847
+ if not plugins:
848
+ click.echo("No plugins found matching the criteria.")
849
+ return
850
+
851
+ plugin_list = []
852
+ for plugin in plugins:
853
+ maintainer = (
854
+ f"{plugin.maintainer_name} <{plugin.maintainer_email}>"
855
+ if plugin.maintainer_email
856
+ else plugin.maintainer_name
857
+ )
858
+ plugin_data = {
859
+ "Plugin ID": plugin.plugin_id,
860
+ "Name": plugin.name,
861
+ "Version": plugin.version,
862
+ "Maintainer": maintainer,
863
+ "License": plugin.license,
864
+ }
865
+ if verbose:
866
+ plugin_data["Description"] = plugin.description or "-"
867
+ plugin_data["Website"] = plugin.website or "-"
868
+ plugin_list.append(plugin_data)
869
+
870
+ if output_format == "table":
871
+ headers = plugin_list[0].keys()
872
+ rows = [p.values() for p in plugin_list]
873
+ click.echo(tabulate(rows, headers, tablefmt="fancy_grid"))
874
+ elif output_format == "json":
875
+ click.echo(json.dumps(plugin_list, indent=2, ensure_ascii=False))
@@ -0,0 +1,88 @@
1
+ import tomlkit
2
+ import semver
3
+ import email.utils
4
+ import spdx_license_list
5
+ import zipfile
6
+
7
+ from pathlib import Path
8
+ from collections.abc import MutableMapping
9
+
10
+
11
+ class PluginManifest(MutableMapping):
12
+ def __init__(self, data):
13
+ super().__setattr__("data", data)
14
+ self.validate()
15
+
16
+ @classmethod
17
+ def from_plugin_path(cls, path):
18
+ path = Path(path)
19
+ if path.is_dir():
20
+ return cls.from_file(path / "manifest.toml")
21
+ elif zipfile.is_zipfile(path):
22
+ with zipfile.ZipFile(path) as z:
23
+ with z.open("manifest.toml") as f:
24
+ data = tomlkit.load(f)
25
+ return cls(data)
26
+ else:
27
+ raise ValueError(f"Invalid plugin path: {path}")
28
+
29
+ @classmethod
30
+ def from_file(cls, path):
31
+ with open(path, "rb") as f:
32
+ data = tomlkit.load(f)
33
+ return cls(data)
34
+
35
+ def write_to_path(self, path):
36
+ path = Path(path)
37
+ with open(path / "manifest.toml", "w", encoding="utf-8") as f:
38
+ tomlkit.dump(self.data, f)
39
+
40
+ def validate(self):
41
+ semver.Version.parse(str(self.data["version"]))
42
+ spdx_license_list.LICENSES[self.data["license"]]
43
+ if "maintainer" in self.data:
44
+ name, email_addr = email.utils.parseaddr(self.data["maintainer"])
45
+ self.data["maintainer_name"] = name
46
+ self.data["maintainer_email"] = email_addr
47
+
48
+ def to_model_dict(self):
49
+ return {
50
+ "plugin_id": self.data["id"],
51
+ "name": self.data["name"],
52
+ "description": self.data.get("description"),
53
+ "version": str(self.data["version"]),
54
+ "maintainer_name": self.data.get("maintainer_name"),
55
+ "maintainer_email": self.data.get("maintainer_email"),
56
+ "website": self.data.get("website"),
57
+ "license": self.data["license"],
58
+ }
59
+
60
+ def __getitem__(self, key):
61
+ return self.data[key]
62
+
63
+ def __setitem__(self, key, value):
64
+ self.data[key] = value
65
+
66
+ def __delitem__(self, key):
67
+ del self.data[key]
68
+
69
+ def __iter__(self):
70
+ return iter(self.data)
71
+
72
+ def __len__(self):
73
+ return len(self.data)
74
+
75
+ def __repr__(self):
76
+ return f"<PluginManifest {self.data!r}>"
77
+
78
+ def __getattr__(self, attr):
79
+ try:
80
+ return self.data[attr]
81
+ except KeyError:
82
+ raise AttributeError(f"'PluginManifest' has no attribute '{attr}'")
83
+
84
+ def __setattr__(self, attr, value):
85
+ if attr == "data":
86
+ super().__setattr__(attr, value)
87
+ else:
88
+ self.data[attr] = value
@@ -9,12 +9,13 @@ import traceback
9
9
  from sqlalchemy.exc import IntegrityError
10
10
 
11
11
  from zou.app.utils import dbhelpers, auth, commands
12
- from zou.app.services import persons_service, auth_service, plugin_service
12
+ from zou.app.services import persons_service, auth_service, plugins_service
13
13
  from zou.app.services.exception import (
14
14
  IsUserLimitReachedException,
15
15
  PersonNotFoundException,
16
16
  TwoFactorAuthenticationNotEnabledException,
17
17
  )
18
+
18
19
  from zou.app import app, config
19
20
 
20
21
  from zou import __file__ as root_path
@@ -659,7 +660,7 @@ def install_plugin(path, force=False):
659
660
  Install a plugin.
660
661
  """
661
662
  with app.app_context():
662
- plugin_service.install_plugin(path, force)
663
+ plugins_service.install_plugin(path, force)
663
664
  print(f"Plugin {path} installed. Restart the server to apply changes.")
664
665
 
665
666
 
@@ -673,7 +674,7 @@ def uninstall_plugin(id):
673
674
  Uninstall a plugin.
674
675
  """
675
676
  with app.app_context():
676
- plugin_service.uninstall_plugin(id)
677
+ plugins_service.uninstall_plugin(id)
677
678
  print(f"Plugin {id} uninstalled.")
678
679
 
679
680
 
@@ -737,7 +738,7 @@ def create_plugin_skeleton(
737
738
  """
738
739
  Create a plugin skeleton.
739
740
  """
740
- plugin_path = plugin_service.create_plugin_skeleton(
741
+ plugin_path = plugins_service.create_plugin_skeleton(
741
742
  path,
742
743
  id,
743
744
  name,
@@ -751,5 +752,64 @@ def create_plugin_skeleton(
751
752
  print(f"Plugin skeleton created in '{plugin_path}'.")
752
753
 
753
754
 
755
+ @cli.command()
756
+ @click.option(
757
+ "--path",
758
+ required=True,
759
+ )
760
+ @click.option(
761
+ "--output-path",
762
+ required=True,
763
+ )
764
+ @click.option(
765
+ "--force",
766
+ is_flag=True,
767
+ default=False,
768
+ show_default=True,
769
+ )
770
+ def create_plugin_package(
771
+ path,
772
+ output_path,
773
+ force=False,
774
+ ):
775
+ """
776
+ Create a plugin package.
777
+ """
778
+ plugin_path = plugins_service.create_plugin_package(
779
+ path, output_path, force
780
+ )
781
+ print(f"Plugin package created in '{plugin_path}'.")
782
+
783
+
784
+ @cli.command()
785
+ @click.option(
786
+ "--format",
787
+ "output_format",
788
+ type=click.Choice(["table", "json"], case_sensitive=False),
789
+ default="table",
790
+ show_default=True,
791
+ help="Output format: table or json.",
792
+ )
793
+ @click.option(
794
+ "--verbose",
795
+ is_flag=True,
796
+ default=False,
797
+ help="Show more plugin information.",
798
+ )
799
+ @click.option(
800
+ "--filter-field",
801
+ type=click.Choice(
802
+ ["plugin_id", "name", "maintainer", "license"], case_sensitive=False
803
+ ),
804
+ help="Field to filter by.",
805
+ )
806
+ @click.option("--filter-value", type=str, help="Value to search in the field.")
807
+ def list_plugins(output_format, verbose, filter_field, filter_value):
808
+ """
809
+ List installed plugins.
810
+ """
811
+ commands.list_plugins(output_format, verbose, filter_field, filter_value)
812
+
813
+
754
814
  if __name__ == "__main__":
755
815
  cli()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zou
3
- Version: 0.20.39
3
+ Version: 0.20.40
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
@@ -73,6 +73,7 @@ Requires-Dist: slackclient==2.9.4
73
73
  Requires-Dist: spdx-license-list==3.26.0
74
74
  Requires-Dist: sqlalchemy_utils==0.41.2
75
75
  Requires-Dist: sqlalchemy==2.0.40
76
+ Requires-Dist: tabulate==0.9.0
76
77
  Requires-Dist: tomlkit==0.13.2
77
78
  Requires-Dist: ua-parser==1.0.1
78
79
  Requires-Dist: werkzeug==3.1.3
@@ -223,7 +223,7 @@ zou/app/services/news_service.py
223
223
  zou/app/services/notifications_service.py
224
224
  zou/app/services/persons_service.py
225
225
  zou/app/services/playlists_service.py
226
- zou/app/services/plugin_service.py
226
+ zou/app/services/plugins_service.py
227
227
  zou/app/services/preview_files_service.py
228
228
  zou/app/services/projects_service.py
229
229
  zou/app/services/scenes_service.py
@@ -262,6 +262,7 @@ zou/app/utils/git.py
262
262
  zou/app/utils/logs.py
263
263
  zou/app/utils/monitoring.py
264
264
  zou/app/utils/permissions.py
265
+ zou/app/utils/plugins.py
265
266
  zou/app/utils/query.py
266
267
  zou/app/utils/redis.py
267
268
  zou/app/utils/remote_job.py
@@ -48,6 +48,7 @@ slackclient==2.9.4
48
48
  spdx-license-list==3.26.0
49
49
  sqlalchemy_utils==0.41.2
50
50
  sqlalchemy==2.0.40
51
+ tabulate==0.9.0
51
52
  tomlkit==0.13.2
52
53
  ua-parser==1.0.1
53
54
  werkzeug==3.1.3
@@ -1 +0,0 @@
1
- __version__ = "0.20.39"