zou 0.19.15__py3-none-any.whl → 0.20.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zou/__init__.py +1 -1
- zou/app/__init__.py +10 -2
- zou/app/api.py +2 -0
- zou/app/blueprints/assets/__init__.py +22 -0
- zou/app/blueprints/assets/resources.py +241 -4
- zou/app/blueprints/auth/__init__.py +4 -0
- zou/app/blueprints/auth/resources.py +154 -22
- zou/app/blueprints/breakdown/resources.py +4 -4
- zou/app/blueprints/chats/__init__.py +22 -0
- zou/app/blueprints/chats/resources.py +199 -0
- zou/app/blueprints/comments/resources.py +36 -19
- zou/app/blueprints/crud/__init__.py +12 -0
- zou/app/blueprints/crud/attachment_file.py +14 -5
- zou/app/blueprints/crud/base.py +29 -28
- zou/app/blueprints/crud/chat.py +13 -0
- zou/app/blueprints/crud/chat_message.py +13 -0
- zou/app/blueprints/crud/comments.py +85 -29
- zou/app/blueprints/crud/custom_action.py +1 -1
- zou/app/blueprints/crud/day_off.py +47 -9
- zou/app/blueprints/crud/department.py +1 -25
- zou/app/blueprints/crud/entity.py +46 -5
- zou/app/blueprints/crud/entity_type.py +13 -1
- zou/app/blueprints/crud/event.py +1 -1
- zou/app/blueprints/crud/file_status.py +1 -1
- zou/app/blueprints/crud/metadata_descriptor.py +24 -10
- zou/app/blueprints/crud/organisation.py +22 -5
- zou/app/blueprints/crud/output_file.py +1 -1
- zou/app/blueprints/crud/output_type.py +1 -1
- zou/app/blueprints/crud/person.py +32 -24
- zou/app/blueprints/crud/playlist.py +1 -1
- zou/app/blueprints/crud/preview_background_file.py +6 -7
- zou/app/blueprints/crud/preview_file.py +1 -1
- zou/app/blueprints/crud/project.py +14 -6
- zou/app/blueprints/crud/project_status.py +1 -1
- zou/app/blueprints/crud/schedule_item.py +4 -2
- zou/app/blueprints/crud/software.py +1 -1
- zou/app/blueprints/crud/status_automation.py +1 -1
- zou/app/blueprints/crud/studio.py +33 -0
- zou/app/blueprints/crud/task.py +47 -3
- zou/app/blueprints/crud/task_status.py +1 -1
- zou/app/blueprints/crud/task_type.py +4 -4
- zou/app/blueprints/crud/working_file.py +4 -8
- zou/app/blueprints/events/resources.py +13 -12
- zou/app/blueprints/export/csv/assets.py +15 -6
- zou/app/blueprints/export/csv/edits.py +15 -5
- zou/app/blueprints/export/csv/playlists.py +1 -1
- zou/app/blueprints/export/csv/shots.py +15 -5
- zou/app/blueprints/export/csv/time_spents.py +1 -1
- zou/app/blueprints/files/resources.py +22 -23
- zou/app/blueprints/index/resources.py +38 -29
- zou/app/blueprints/news/resources.py +25 -11
- zou/app/blueprints/persons/__init__.py +5 -2
- zou/app/blueprints/persons/resources.py +126 -120
- zou/app/blueprints/previews/__init__.py +18 -8
- zou/app/blueprints/previews/resources.py +569 -328
- zou/app/blueprints/projects/resources.py +1 -1
- zou/app/blueprints/search/resources.py +18 -6
- zou/app/blueprints/shots/__init__.py +5 -0
- zou/app/blueprints/shots/resources.py +134 -4
- zou/app/blueprints/source/__init__.py +6 -6
- zou/app/blueprints/source/csv/assets.py +10 -3
- zou/app/blueprints/source/csv/base.py +1 -1
- zou/app/blueprints/source/csv/edits.py +10 -3
- zou/app/blueprints/source/csv/shots.py +10 -3
- zou/app/blueprints/source/{edl.py → otio.py} +82 -41
- zou/app/blueprints/tasks/__init__.py +3 -2
- zou/app/blueprints/tasks/resources.py +83 -52
- zou/app/blueprints/user/__init__.py +9 -0
- zou/app/blueprints/user/resources.py +170 -12
- zou/app/config.py +10 -0
- zou/app/mixin.py +6 -5
- zou/app/models/attachment_file.py +10 -4
- zou/app/models/base.py +18 -13
- zou/app/models/build_job.py +7 -4
- zou/app/models/chat.py +44 -0
- zou/app/models/chat_message.py +37 -0
- zou/app/models/comment.py +1 -0
- zou/app/models/day_off.py +3 -0
- zou/app/models/entity.py +4 -6
- zou/app/models/entity_type.py +2 -0
- zou/app/models/organisation.py +14 -15
- zou/app/models/person.py +6 -1
- zou/app/models/project.py +3 -0
- zou/app/models/search_filter.py +11 -0
- zou/app/models/search_filter_group.py +10 -0
- zou/app/models/serializer.py +17 -17
- zou/app/models/status_automation.py +2 -0
- zou/app/models/studio.py +13 -0
- zou/app/models/subscription.py +2 -2
- zou/app/models/task.py +6 -1
- zou/app/models/task_status.py +1 -0
- zou/app/models/task_type.py +1 -0
- zou/app/models/working_file.py +1 -1
- zou/app/services/assets_service.py +101 -14
- zou/app/services/auth_service.py +17 -44
- zou/app/services/breakdown_service.py +37 -5
- zou/app/services/chats_service.py +279 -0
- zou/app/services/comments_service.py +110 -65
- zou/app/services/concepts_service.py +4 -12
- zou/app/services/deletion_service.py +43 -30
- zou/app/services/edits_service.py +5 -11
- zou/app/services/emails_service.py +4 -4
- zou/app/services/entities_service.py +17 -2
- zou/app/services/events_service.py +12 -4
- zou/app/services/exception.py +5 -5
- zou/app/services/names_service.py +7 -2
- zou/app/services/news_service.py +17 -9
- zou/app/services/persons_service.py +38 -21
- zou/app/services/playlists_service.py +8 -7
- zou/app/services/preview_files_service.py +137 -10
- zou/app/services/projects_service.py +5 -14
- zou/app/services/shots_service.py +221 -49
- zou/app/services/sync_service.py +46 -42
- zou/app/services/tasks_service.py +185 -46
- zou/app/services/time_spents_service.py +67 -20
- zou/app/services/user_service.py +350 -107
- zou/app/stores/auth_tokens_store.py +2 -1
- zou/app/stores/file_store.py +18 -0
- zou/app/stores/publisher_store.py +7 -7
- zou/app/stores/queue_store.py +1 -0
- zou/app/swagger.py +36 -20
- zou/app/utils/cache.py +2 -0
- zou/app/utils/commands.py +104 -7
- zou/app/utils/csv_utils.py +1 -4
- zou/app/utils/date_helpers.py +33 -17
- zou/app/utils/dbhelpers.py +14 -1
- zou/app/utils/emails.py +2 -2
- zou/app/utils/fido.py +22 -0
- zou/app/utils/query.py +54 -6
- zou/app/utils/redis.py +11 -0
- zou/app/utils/saml.py +51 -0
- zou/app/utils/string.py +2 -0
- zou/app/utils/thumbnail.py +4 -2
- zou/cli.py +76 -18
- zou/debug.py +4 -2
- zou/event_stream.py +122 -165
- zou/job_settings.py +1 -0
- zou/migrations/env.py +0 -0
- zou/migrations/utils/base.py +6 -6
- zou/migrations/versions/1bb55759146f_add_table_studio.py +67 -0
- zou/migrations/versions/1fab8c420678_add_attachments_to_message_chats.py +56 -0
- zou/migrations/versions/23122f290ca2_add_entity_chat_models.py +149 -0
- zou/migrations/versions/32f134ff1201_add_is_shared_flag_to_filters.py +33 -0
- zou/migrations/versions/57222395f2be_add_statusautomation_import_last_revision.py +41 -0
- zou/migrations/versions/59a7445a966c_add_entity_is_shared.py +41 -0
- zou/migrations/versions/5b980f0dc365_add_comment_links.py +35 -0
- zou/migrations/versions/680c64565f9d_for_searchfiltergroup_is_shared.py +35 -0
- zou/migrations/versions/8e67c183bed7_add_preference_fields.py +71 -0
- zou/migrations/versions/92b40d79ad3f_allow_message_attachments.py +38 -0
- zou/migrations/versions/971dbf5a0faf_add_short_name_for_asset_type_entity_.py +33 -0
- zou/migrations/versions/9b85c14fa8a7_add_day_off_new_columns.py +68 -0
- zou/migrations/versions/9d3bb33c6fc6_add_department_keys_to_filter_models.py +73 -0
- zou/migrations/versions/a252a094e977_add_descriptions_for_entities_tasks_and_.py +40 -0
- zou/migrations/versions/be56dc0fb760_for_is_shared_disallow_nullable.py +102 -0
- zou/migrations/versions/ca28796a2a62_add_is_done_field_to_the_task_model.py +108 -0
- zou/migrations/versions/f344b867a911_for_description_of_entity_task_working_.py +75 -0
- zou/remote/config_payload.py +2 -1
- zou/utils/movie.py +14 -4
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/METADATA +75 -69
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/RECORD +163 -134
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/WHEEL +1 -1
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/LICENSE +0 -0
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/entry_points.txt +0 -0
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/top_level.txt +0 -0
zou/app/config.py
CHANGED
|
@@ -7,6 +7,7 @@ from zou.app.utils.env import envtobool, env_with_semicolon_to_list
|
|
|
7
7
|
|
|
8
8
|
PROPAGATE_EXCEPTIONS = True
|
|
9
9
|
DEBUG = envtobool("DEBUG", False)
|
|
10
|
+
DEBUG_HOST = os.getenv("DEBUG_HOST", "127.0.0.1")
|
|
10
11
|
DEBUG_PORT = int(os.getenv("DEBUG_PORT", 5000))
|
|
11
12
|
|
|
12
13
|
APP_NAME = "Zou"
|
|
@@ -18,6 +19,7 @@ AUTH_STRATEGY = os.getenv("AUTH_STRATEGY", "auth_local_classic")
|
|
|
18
19
|
KEY_VALUE_STORE = {
|
|
19
20
|
"host": os.getenv("KV_HOST", "localhost"),
|
|
20
21
|
"port": os.getenv("KV_PORT", "6379"),
|
|
22
|
+
"password": os.getenv("KV_PASSWORD", None),
|
|
21
23
|
}
|
|
22
24
|
AUTH_TOKEN_BLACKLIST_KV_INDEX = 0
|
|
23
25
|
MEMOIZE_DB_INDEX = 1
|
|
@@ -80,6 +82,7 @@ MAIL_PORT = os.getenv("MAIL_PORT", 25)
|
|
|
80
82
|
MAIL_USERNAME = os.getenv("MAIL_USERNAME", "")
|
|
81
83
|
MAIL_PASSWORD = os.getenv("MAIL_PASSWORD", "")
|
|
82
84
|
MAIL_DEBUG = envtobool("MAIL_DEBUG", False)
|
|
85
|
+
MAIL_DEBUG_BODY = envtobool("MAIL_DEBUG_BODY", False)
|
|
83
86
|
MAIL_USE_TLS = envtobool("MAIL_USE_TLS", False)
|
|
84
87
|
MAIL_USE_SSL = envtobool("MAIL_USE_SSL", False)
|
|
85
88
|
MAIL_DEFAULT_SENDER = os.getenv(
|
|
@@ -131,6 +134,10 @@ LDAP_IS_AD = envtobool("LDAP_IS_AD", False)
|
|
|
131
134
|
LDAP_IS_AD_SIMPLE = envtobool("LDAP_IS_AD_SIMPLE", False)
|
|
132
135
|
LDAP_SSL = envtobool("LDAP_SSL", False)
|
|
133
136
|
|
|
137
|
+
SAML_ENABLED = envtobool("SAML_ENABLED", False)
|
|
138
|
+
SAML_IDP_NAME = os.getenv("SAML_IDP_NAME", "")
|
|
139
|
+
SAML_METADATA_URL = os.getenv("SAML_METADATA_URL", "")
|
|
140
|
+
|
|
134
141
|
LOGS_MODE = os.getenv("LOGS_MODE", "default")
|
|
135
142
|
LOGS_HOST = os.getenv("LOGS_HOST", "localhost")
|
|
136
143
|
LOGS_PORT = os.getenv("LOGS_PORT", 2202)
|
|
@@ -151,6 +158,7 @@ CRISP_TOKEN = os.getenv("CRISP_TOKEN", "")
|
|
|
151
158
|
IS_SELF_HOSTED = envtobool("IS_SELF_HOSTED", True)
|
|
152
159
|
|
|
153
160
|
DEFAULT_TIMEZONE = os.getenv("DEFAULT_TIMEZONE", "Europe/Paris")
|
|
161
|
+
DEFAULT_LOCALE = os.getenv("DEFAULT_LOCALE", "en_US")
|
|
154
162
|
|
|
155
163
|
USER_LIMIT = int(os.getenv("USER_LIMIT", "100"))
|
|
156
164
|
MIN_PASSWORD_LENGTH = int(os.getenv("MIN_PASSWORD_LENGTH", 8))
|
|
@@ -161,6 +169,8 @@ TELEMETRY_URL = os.getenv(
|
|
|
161
169
|
f"{'http://localhost:8000' if DEBUG else 'https://account.cg-wire.com'}/api/selfhosted/telemetry/new/",
|
|
162
170
|
)
|
|
163
171
|
|
|
172
|
+
REMOVE_FILES = envtobool("REMOVE_FILES", False)
|
|
173
|
+
|
|
164
174
|
# Deprecated
|
|
165
175
|
TO_REVIEW_TASK_STATUS = "To review"
|
|
166
176
|
DEFAULT_FILE_STATUS = "To review"
|
zou/app/mixin.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from flask_restful import reqparse
|
|
2
2
|
from flask import request
|
|
3
3
|
|
|
4
|
-
from zou.app.utils import
|
|
4
|
+
from zou.app.utils import date_helpers
|
|
5
5
|
from zou.app.services.exception import WrongParameterException
|
|
6
6
|
|
|
7
7
|
|
|
@@ -14,6 +14,7 @@ class ArgsMixin(object):
|
|
|
14
14
|
parser = reqparse.RequestParser()
|
|
15
15
|
if location is None:
|
|
16
16
|
location = ["values", "json"] if request.is_json else ["values"]
|
|
17
|
+
|
|
17
18
|
for descriptor in descriptors:
|
|
18
19
|
action = None
|
|
19
20
|
data_type = str
|
|
@@ -121,12 +122,12 @@ class ArgsMixin(object):
|
|
|
121
122
|
"""
|
|
122
123
|
return self.get_bool_parameter("no_job")
|
|
123
124
|
|
|
124
|
-
def get_text_parameter(self, field_name):
|
|
125
|
+
def get_text_parameter(self, field_name, default=None):
|
|
125
126
|
"""
|
|
126
127
|
Returns text parameter value matching `field_name`.
|
|
127
128
|
"""
|
|
128
129
|
options = request.args
|
|
129
|
-
return options.get(field_name,
|
|
130
|
+
return options.get(field_name, default)
|
|
130
131
|
|
|
131
132
|
def get_bool_parameter(self, field_name, default="false"):
|
|
132
133
|
"""
|
|
@@ -146,10 +147,10 @@ class ArgsMixin(object):
|
|
|
146
147
|
if param is None:
|
|
147
148
|
return date
|
|
148
149
|
try:
|
|
149
|
-
date =
|
|
150
|
+
date = date_helpers.get_datetime_from_string(param)
|
|
150
151
|
except Exception:
|
|
151
152
|
try:
|
|
152
|
-
date =
|
|
153
|
+
date = date_helpers.get_date_from_string(param)
|
|
153
154
|
except Exception:
|
|
154
155
|
raise WrongParameterException(
|
|
155
156
|
"Wrong date format for before argument."
|
|
@@ -15,11 +15,16 @@ class AttachmentFile(db.Model, BaseMixin, SerializerMixin):
|
|
|
15
15
|
extension = db.Column(db.String(6))
|
|
16
16
|
mimetype = db.Column(db.String(255))
|
|
17
17
|
comment_id = db.Column(
|
|
18
|
-
UUIDType(binary=False),
|
|
18
|
+
UUIDType(binary=False),
|
|
19
|
+
db.ForeignKey("comment.id"),
|
|
20
|
+
index=True,
|
|
21
|
+
nullable=True,
|
|
19
22
|
)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
db.
|
|
23
|
+
chat_message_id = db.Column(
|
|
24
|
+
UUIDType(binary=False),
|
|
25
|
+
db.ForeignKey("chat_message.id"),
|
|
26
|
+
index=True,
|
|
27
|
+
nullable=True,
|
|
23
28
|
)
|
|
24
29
|
|
|
25
30
|
def __repr__(self):
|
|
@@ -37,6 +42,7 @@ class AttachmentFile(db.Model, BaseMixin, SerializerMixin):
|
|
|
37
42
|
def create_from_import(cls, data):
|
|
38
43
|
data.pop("type", None)
|
|
39
44
|
data.pop("comment", None)
|
|
45
|
+
data.pop("chat_message", None)
|
|
40
46
|
previous_data = cls.get(data["id"])
|
|
41
47
|
if previous_data is None:
|
|
42
48
|
return cls.create(**data)
|
zou/app/models/base.py
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import datetime
|
|
2
|
-
|
|
3
1
|
from sqlalchemy_utils import UUIDType
|
|
4
2
|
from sqlalchemy import func
|
|
5
3
|
from sqlalchemy import orm
|
|
6
4
|
from zou.app import db
|
|
7
|
-
from zou.app.utils import fields
|
|
5
|
+
from zou.app.utils import fields, date_helpers
|
|
8
6
|
|
|
9
7
|
|
|
10
8
|
class BaseMixin(object):
|
|
@@ -13,11 +11,13 @@ class BaseMixin(object):
|
|
|
13
11
|
)
|
|
14
12
|
|
|
15
13
|
# Audit fields
|
|
16
|
-
created_at = db.Column(
|
|
14
|
+
created_at = db.Column(
|
|
15
|
+
db.DateTime, default=date_helpers.get_utc_now_datetime
|
|
16
|
+
)
|
|
17
17
|
updated_at = db.Column(
|
|
18
18
|
db.DateTime,
|
|
19
|
-
default=
|
|
20
|
-
onupdate=
|
|
19
|
+
default=date_helpers.get_utc_now_datetime,
|
|
20
|
+
onupdate=date_helpers.get_utc_now_datetime,
|
|
21
21
|
)
|
|
22
22
|
|
|
23
23
|
def __repr__(self):
|
|
@@ -41,12 +41,12 @@ class BaseMixin(object):
|
|
|
41
41
|
return db.session.get(cls, id)
|
|
42
42
|
|
|
43
43
|
@classmethod
|
|
44
|
-
def get_by(cls, **kw):
|
|
44
|
+
def get_by(cls, *criterions, **kw):
|
|
45
45
|
"""
|
|
46
46
|
Shorthand to retrieve data by using filters. It returns the first
|
|
47
47
|
element of the returned data.
|
|
48
48
|
"""
|
|
49
|
-
return cls.query.filter_by(**kw).first()
|
|
49
|
+
return cls.query.filter(*criterions).filter_by(**kw).first()
|
|
50
50
|
|
|
51
51
|
@classmethod
|
|
52
52
|
def get_by_case_insensitive(cls, **kw):
|
|
@@ -126,11 +126,11 @@ class BaseMixin(object):
|
|
|
126
126
|
return instance
|
|
127
127
|
|
|
128
128
|
@classmethod
|
|
129
|
-
def delete_all_by(cls, **kw):
|
|
129
|
+
def delete_all_by(cls, *criterions, **kw):
|
|
130
130
|
"""
|
|
131
131
|
Shorthand to delete data by using filters.
|
|
132
132
|
"""
|
|
133
|
-
result = cls.query.filter_by(**kw).delete()
|
|
133
|
+
result = cls.query.filter(*criterions).filter_by(**kw).delete()
|
|
134
134
|
db.session.commit()
|
|
135
135
|
return result
|
|
136
136
|
|
|
@@ -184,7 +184,12 @@ class BaseMixin(object):
|
|
|
184
184
|
|
|
185
185
|
@classmethod
|
|
186
186
|
def commit(cls):
|
|
187
|
-
|
|
187
|
+
try:
|
|
188
|
+
db.session.commit()
|
|
189
|
+
except BaseException:
|
|
190
|
+
db.session.rollback()
|
|
191
|
+
db.session.remove()
|
|
192
|
+
raise
|
|
188
193
|
|
|
189
194
|
def save(self):
|
|
190
195
|
"""
|
|
@@ -192,7 +197,7 @@ class BaseMixin(object):
|
|
|
192
197
|
instance fields.
|
|
193
198
|
"""
|
|
194
199
|
try:
|
|
195
|
-
self.updated_at =
|
|
200
|
+
self.updated_at = date_helpers.get_utc_now_datetime()
|
|
196
201
|
db.session.add(self)
|
|
197
202
|
db.session.commit()
|
|
198
203
|
except BaseException:
|
|
@@ -239,7 +244,7 @@ class BaseMixin(object):
|
|
|
239
244
|
Shorthand to update an entry via the database session based on current
|
|
240
245
|
instance fields. It doesn't generate a commit.
|
|
241
246
|
"""
|
|
242
|
-
self.updated_at =
|
|
247
|
+
self.updated_at = date_helpers.get_utc_now_datetime()
|
|
243
248
|
for key, value in data.items():
|
|
244
249
|
if hasattr(self.__class__, key):
|
|
245
250
|
field_key = getattr(self.__class__, key)
|
zou/app/models/build_job.py
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import datetime
|
|
2
|
-
|
|
3
1
|
from sqlalchemy_utils import UUIDType, ChoiceType
|
|
4
2
|
|
|
5
3
|
from zou.app import db
|
|
6
4
|
from zou.app.models.serializer import SerializerMixin
|
|
7
5
|
from zou.app.models.base import BaseMixin
|
|
8
|
-
from zou.app.utils import fields
|
|
6
|
+
from zou.app.utils import fields, date_helpers
|
|
9
7
|
|
|
10
8
|
STATUSES = [
|
|
11
9
|
("running", "Running"),
|
|
@@ -34,7 +32,12 @@ class BuildJob(db.Model, BaseMixin, SerializerMixin):
|
|
|
34
32
|
)
|
|
35
33
|
|
|
36
34
|
def end(self, status):
|
|
37
|
-
self.update(
|
|
35
|
+
self.update(
|
|
36
|
+
{
|
|
37
|
+
"status": status,
|
|
38
|
+
"ended_at": date_helpers.get_utc_now_datetime(),
|
|
39
|
+
}
|
|
40
|
+
)
|
|
38
41
|
|
|
39
42
|
def present(self):
|
|
40
43
|
return fields.serialize_dict(
|
zou/app/models/chat.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from sqlalchemy_utils import UUIDType
|
|
2
|
+
|
|
3
|
+
from zou.app import db
|
|
4
|
+
from zou.app.models.serializer import SerializerMixin
|
|
5
|
+
from zou.app.models.base import BaseMixin
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ChatParticipant(db.Model):
|
|
9
|
+
__tablename__ = "chat_participant"
|
|
10
|
+
chat_id = db.Column(
|
|
11
|
+
UUIDType(binary=False),
|
|
12
|
+
db.ForeignKey("chat.id"),
|
|
13
|
+
primary_key=True,
|
|
14
|
+
)
|
|
15
|
+
person_id = db.Column(
|
|
16
|
+
UUIDType(binary=False),
|
|
17
|
+
db.ForeignKey("person.id"),
|
|
18
|
+
primary_key=True,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Chat(db.Model, BaseMixin, SerializerMixin):
|
|
23
|
+
"""
|
|
24
|
+
Message shared in the entity chat feeds.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
object_id = db.Column(UUIDType(binary=False), nullable=False, index=True)
|
|
28
|
+
object_type = db.Column(
|
|
29
|
+
db.String(80), nullable=False, index=True, default="entity"
|
|
30
|
+
)
|
|
31
|
+
last_message = db.Column(db.DateTime, nullable=True)
|
|
32
|
+
participants = db.relationship(
|
|
33
|
+
"Person", secondary="chat_participant", lazy="joined"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def __repr__(self):
|
|
37
|
+
return "<Message of %s>" % self.object_id
|
|
38
|
+
|
|
39
|
+
def present(self):
|
|
40
|
+
return {
|
|
41
|
+
"id": str(self.id),
|
|
42
|
+
"object_id": str(self.object_id),
|
|
43
|
+
"last_message": self.last_message,
|
|
44
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from sqlalchemy_utils import UUIDType
|
|
2
|
+
|
|
3
|
+
from zou.app import db
|
|
4
|
+
from zou.app.models.serializer import SerializerMixin
|
|
5
|
+
from zou.app.models.base import BaseMixin
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ChatMessage(db.Model, BaseMixin, SerializerMixin):
|
|
9
|
+
"""
|
|
10
|
+
Message shared in the entity chat feeds.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
chat_id = db.Column(
|
|
14
|
+
UUIDType(binary=False),
|
|
15
|
+
db.ForeignKey("chat.id"),
|
|
16
|
+
nullable=False,
|
|
17
|
+
index=True,
|
|
18
|
+
)
|
|
19
|
+
person_id = db.Column(
|
|
20
|
+
UUIDType(binary=False),
|
|
21
|
+
db.ForeignKey("person.id"),
|
|
22
|
+
nullable=False,
|
|
23
|
+
index=True,
|
|
24
|
+
)
|
|
25
|
+
text = db.Column(db.Text())
|
|
26
|
+
attachment_files = db.relationship(
|
|
27
|
+
"AttachmentFile", backref="chat_message", lazy="joined"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# TODO
|
|
31
|
+
# * mentions
|
|
32
|
+
# * reactions
|
|
33
|
+
# * concept links ?
|
|
34
|
+
# * task links ?
|
|
35
|
+
|
|
36
|
+
def __repr__(self):
|
|
37
|
+
return "<Message of %s>" % self.object_id
|
zou/app/models/comment.py
CHANGED
|
@@ -92,6 +92,7 @@ class Comment(db.Model, BaseMixin, SerializerMixin):
|
|
|
92
92
|
replies = db.Column(JSONB, default=[])
|
|
93
93
|
checklist = db.Column(JSONB)
|
|
94
94
|
pinned = db.Column(db.Boolean)
|
|
95
|
+
links = db.Column(db.ARRAY(db.String()))
|
|
95
96
|
|
|
96
97
|
task_status_id = db.Column(
|
|
97
98
|
UUIDType(binary=False), db.ForeignKey("task_status.id"), index=True
|
zou/app/models/day_off.py
CHANGED
|
@@ -10,9 +10,12 @@ class DayOff(db.Model, BaseMixin, SerializerMixin):
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
date = db.Column(db.Date, nullable=False)
|
|
13
|
+
end_date = db.Column(db.Date, nullable=False)
|
|
14
|
+
description = db.Column(db.Text)
|
|
13
15
|
person_id = db.Column(
|
|
14
16
|
UUIDType(binary=False), db.ForeignKey("person.id"), index=True
|
|
15
17
|
)
|
|
16
18
|
__table_args__ = (
|
|
17
19
|
db.UniqueConstraint("person_id", "date", name="day_off_uc"),
|
|
20
|
+
db.CheckConstraint("date <= end_date", name="day_off_date_check"),
|
|
18
21
|
)
|
zou/app/models/entity.py
CHANGED
|
@@ -3,7 +3,6 @@ from sqlalchemy_utils import UUIDType, ChoiceType
|
|
|
3
3
|
from zou.app import db
|
|
4
4
|
from zou.app.models.serializer import SerializerMixin
|
|
5
5
|
from zou.app.models.base import BaseMixin
|
|
6
|
-
from zou.app.utils import fields
|
|
7
6
|
|
|
8
7
|
from sqlalchemy.dialects.postgresql import JSONB
|
|
9
8
|
|
|
@@ -90,13 +89,10 @@ class Entity(db.Model, BaseMixin, SerializerMixin):
|
|
|
90
89
|
tasks and files.
|
|
91
90
|
"""
|
|
92
91
|
|
|
93
|
-
id =
|
|
94
|
-
UUIDType(binary=False), primary_key=True, default=fields.gen_uuid
|
|
95
|
-
)
|
|
96
|
-
|
|
92
|
+
id = BaseMixin.id
|
|
97
93
|
name = db.Column(db.String(160), nullable=False)
|
|
98
94
|
code = db.Column(db.String(160)) # To store sanitized version of name
|
|
99
|
-
description = db.Column(db.
|
|
95
|
+
description = db.Column(db.Text())
|
|
100
96
|
shotgun_id = db.Column(db.Integer)
|
|
101
97
|
canceled = db.Column(db.Boolean, default=False)
|
|
102
98
|
|
|
@@ -104,6 +100,8 @@ class Entity(db.Model, BaseMixin, SerializerMixin):
|
|
|
104
100
|
nb_entities_out = db.Column(db.Integer, default=0)
|
|
105
101
|
is_casting_standby = db.Column(db.Boolean, default=False)
|
|
106
102
|
|
|
103
|
+
is_shared = db.Column(db.Boolean, default=False, nullable=False)
|
|
104
|
+
|
|
107
105
|
status = db.Column(
|
|
108
106
|
ChoiceType(ENTITY_STATUSES), default="running", nullable=False
|
|
109
107
|
)
|
zou/app/models/entity_type.py
CHANGED
|
@@ -27,6 +27,8 @@ class EntityType(db.Model, BaseMixin, SerializerMixin):
|
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
29
|
name = db.Column(db.String(30), unique=True, nullable=False, index=True)
|
|
30
|
+
short_name = db.Column(db.String(20))
|
|
31
|
+
description = db.Column(db.Text())
|
|
30
32
|
task_types = db.relationship(
|
|
31
33
|
"TaskType", secondary=task_type_link, lazy="joined"
|
|
32
34
|
)
|
zou/app/models/organisation.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from zou.app import db
|
|
2
2
|
from zou.app.models.serializer import SerializerMixin
|
|
3
3
|
from zou.app.models.base import BaseMixin
|
|
4
|
-
from zou.app.utils import fields
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
class Organisation(db.Model, BaseMixin, SerializerMixin):
|
|
@@ -14,23 +13,23 @@ class Organisation(db.Model, BaseMixin, SerializerMixin):
|
|
|
14
13
|
has_avatar = db.Column(db.Boolean(), default=False)
|
|
15
14
|
use_original_file_name = db.Column(db.Boolean(), default=False)
|
|
16
15
|
timesheets_locked = db.Column(db.Boolean(), default=False)
|
|
16
|
+
format_duration_in_hours = db.Column(db.Boolean(), default=False)
|
|
17
17
|
hd_by_default = db.Column(db.Boolean(), default=False)
|
|
18
18
|
chat_token_slack = db.Column(db.String(80), default="")
|
|
19
19
|
chat_webhook_mattermost = db.Column(db.String(80), default="")
|
|
20
20
|
chat_token_discord = db.Column(db.String(80), default="")
|
|
21
|
+
dark_theme_by_default = db.Column(db.Boolean(), default=False)
|
|
22
|
+
format_duration_in_hours = db.Column(db.Boolean(), default=False)
|
|
21
23
|
|
|
22
|
-
def present(self):
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"use_original_file_name": self.use_original_file_name,
|
|
34
|
-
"timesheets_locked": self.timesheets_locked,
|
|
35
|
-
}
|
|
24
|
+
def present(self, sensitive=False):
|
|
25
|
+
return self.serialize(
|
|
26
|
+
ignored_attrs=(
|
|
27
|
+
[]
|
|
28
|
+
if sensitive
|
|
29
|
+
else [
|
|
30
|
+
"chat_token_slack",
|
|
31
|
+
"chat_webhook_mattermost",
|
|
32
|
+
"chat_token_discord",
|
|
33
|
+
]
|
|
34
|
+
)
|
|
36
35
|
)
|
zou/app/models/person.py
CHANGED
|
@@ -94,7 +94,7 @@ class Person(db.Model, BaseMixin, SerializerMixin):
|
|
|
94
94
|
TimezoneType(backend="pytz"),
|
|
95
95
|
default=pytz_timezone(config.DEFAULT_TIMEZONE),
|
|
96
96
|
)
|
|
97
|
-
locale = db.Column(LocaleType, default=Locale(
|
|
97
|
+
locale = db.Column(LocaleType, default=Locale(config.DEFAULT_LOCALE))
|
|
98
98
|
data = db.Column(JSONB)
|
|
99
99
|
role = db.Column(ChoiceType(ROLE_TYPES), default="user", nullable=False)
|
|
100
100
|
has_avatar = db.Column(db.Boolean(), default=False)
|
|
@@ -114,6 +114,9 @@ class Person(db.Model, BaseMixin, SerializerMixin):
|
|
|
114
114
|
departments = db.relationship(
|
|
115
115
|
"Department", secondary="department_link", lazy="joined"
|
|
116
116
|
)
|
|
117
|
+
studio_id = db.Column(
|
|
118
|
+
UUIDType(binary=False), db.ForeignKey("studio.id"), index=True
|
|
119
|
+
)
|
|
117
120
|
|
|
118
121
|
is_generated_from_ldap = db.Column(db.Boolean(), default=False)
|
|
119
122
|
ldap_uid = db.Column(db.String(60), unique=True, default=None)
|
|
@@ -179,12 +182,14 @@ class Person(db.Model, BaseMixin, SerializerMixin):
|
|
|
179
182
|
)
|
|
180
183
|
return {
|
|
181
184
|
"id": data["id"],
|
|
185
|
+
"type": data["type"],
|
|
182
186
|
"first_name": data["first_name"],
|
|
183
187
|
"last_name": data["last_name"],
|
|
184
188
|
"full_name": self.full_name,
|
|
185
189
|
"has_avatar": data["has_avatar"],
|
|
186
190
|
"active": data["active"],
|
|
187
191
|
"departments": data.get("departments", []),
|
|
192
|
+
"studio_id": data["studio_id"],
|
|
188
193
|
"role": data["role"],
|
|
189
194
|
"desktop_login": data["desktop_login"],
|
|
190
195
|
"is_bot": data["is_bot"],
|
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
|
zou/app/models/search_filter.py
CHANGED
|
@@ -3,6 +3,7 @@ from sqlalchemy_utils import UUIDType
|
|
|
3
3
|
from zou.app import db
|
|
4
4
|
from zou.app.models.serializer import SerializerMixin
|
|
5
5
|
from zou.app.models.base import BaseMixin
|
|
6
|
+
from sqlalchemy.sql import expression
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class SearchFilter(db.Model, BaseMixin, SerializerMixin):
|
|
@@ -15,7 +16,17 @@ class SearchFilter(db.Model, BaseMixin, SerializerMixin):
|
|
|
15
16
|
entity_type = db.Column(db.String(80))
|
|
16
17
|
name = db.Column(db.String(200), nullable=False, default="")
|
|
17
18
|
search_query = db.Column(db.String(500), nullable=False, default="")
|
|
19
|
+
is_shared = db.Column(
|
|
20
|
+
db.Boolean,
|
|
21
|
+
server_default=expression.false(),
|
|
22
|
+
default=False,
|
|
23
|
+
nullable=False,
|
|
24
|
+
)
|
|
18
25
|
|
|
26
|
+
department_id = db.Column(
|
|
27
|
+
UUIDType(binary=False),
|
|
28
|
+
db.ForeignKey("department.id"),
|
|
29
|
+
)
|
|
19
30
|
search_filter_group_id = db.Column(
|
|
20
31
|
UUIDType(binary=False),
|
|
21
32
|
db.ForeignKey("search_filter_group.id"),
|
|
@@ -3,6 +3,7 @@ from sqlalchemy_utils import UUIDType
|
|
|
3
3
|
from zou.app import db
|
|
4
4
|
from zou.app.models.serializer import SerializerMixin
|
|
5
5
|
from zou.app.models.base import BaseMixin
|
|
6
|
+
from sqlalchemy.sql import expression
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class SearchFilterGroup(db.Model, BaseMixin, SerializerMixin):
|
|
@@ -14,6 +15,15 @@ class SearchFilterGroup(db.Model, BaseMixin, SerializerMixin):
|
|
|
14
15
|
entity_type = db.Column(db.String(80))
|
|
15
16
|
name = db.Column(db.String(200), nullable=False, default="")
|
|
16
17
|
color = db.Column(db.String(8), nullable=False, default="")
|
|
18
|
+
is_shared = db.Column(
|
|
19
|
+
db.Boolean,
|
|
20
|
+
server_default=expression.false(),
|
|
21
|
+
default=False,
|
|
22
|
+
nullable=False,
|
|
23
|
+
)
|
|
17
24
|
|
|
18
25
|
person_id = db.Column(UUIDType(binary=False), db.ForeignKey("person.id"))
|
|
19
26
|
project_id = db.Column(UUIDType(binary=False), db.ForeignKey("project.id"))
|
|
27
|
+
department_id = db.Column(
|
|
28
|
+
UUIDType(binary=False), db.ForeignKey("department.id")
|
|
29
|
+
)
|
zou/app/models/serializer.py
CHANGED
|
@@ -14,35 +14,35 @@ class SerializerMixin(object):
|
|
|
14
14
|
orm.attributes.CollectionAttributeImpl,
|
|
15
15
|
)
|
|
16
16
|
|
|
17
|
-
def serialize(
|
|
17
|
+
def serialize(
|
|
18
|
+
self,
|
|
19
|
+
obj_type=None,
|
|
20
|
+
relations=False,
|
|
21
|
+
milliseconds=False,
|
|
22
|
+
ignored_attrs=[],
|
|
23
|
+
):
|
|
18
24
|
attrs = inspect(self.__class__).all_orm_descriptors.keys()
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
attr
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
obj_dict = {
|
|
28
|
-
attr: serialize_value(
|
|
29
|
-
getattr(self, attr), milliseconds=milliseconds
|
|
30
|
-
)
|
|
31
|
-
for attr in attrs
|
|
32
|
-
if not self.is_join(attr)
|
|
33
|
-
}
|
|
25
|
+
obj_dict = {
|
|
26
|
+
attr: serialize_value(
|
|
27
|
+
getattr(self, attr), milliseconds=milliseconds
|
|
28
|
+
)
|
|
29
|
+
for attr in attrs
|
|
30
|
+
if attr not in ignored_attrs
|
|
31
|
+
and (relations or not self.is_join(attr))
|
|
32
|
+
}
|
|
34
33
|
obj_dict["type"] = obj_type or type(self).__name__
|
|
35
34
|
return obj_dict
|
|
36
35
|
|
|
37
36
|
@staticmethod
|
|
38
37
|
def serialize_list(
|
|
39
|
-
models, obj_type=None, relations=False, milliseconds=False
|
|
38
|
+
models, obj_type=None, relations=False, milliseconds=False, **kwargs
|
|
40
39
|
):
|
|
41
40
|
return [
|
|
42
41
|
model.serialize(
|
|
43
42
|
obj_type=obj_type,
|
|
44
43
|
relations=relations,
|
|
45
44
|
milliseconds=milliseconds,
|
|
45
|
+
**kwargs
|
|
46
46
|
)
|
|
47
47
|
for model in models
|
|
48
48
|
]
|
zou/app/models/studio.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from zou.app import db
|
|
2
|
+
from zou.app.models.serializer import SerializerMixin
|
|
3
|
+
from zou.app.models.base import BaseMixin
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Studio(db.Model, BaseMixin, SerializerMixin):
|
|
7
|
+
"""
|
|
8
|
+
Describe a studio.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
name = db.Column(db.String(80), unique=True, nullable=False)
|
|
12
|
+
color = db.Column(db.String(7), nullable=False)
|
|
13
|
+
archived = db.Column(db.Boolean(), default=False)
|
zou/app/models/subscription.py
CHANGED
|
@@ -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
|
@@ -30,9 +30,10 @@ class Task(db.Model, BaseMixin, SerializerMixin):
|
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
32
|
name = db.Column(db.String(80), nullable=False)
|
|
33
|
-
description = db.Column(db.
|
|
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)
|
|
@@ -42,6 +43,7 @@ class Task(db.Model, BaseMixin, SerializerMixin):
|
|
|
42
43
|
due_date = db.Column(db.DateTime)
|
|
43
44
|
real_start_date = db.Column(db.DateTime)
|
|
44
45
|
end_date = db.Column(db.DateTime)
|
|
46
|
+
done_date = db.Column(db.DateTime)
|
|
45
47
|
last_comment_date = db.Column(db.DateTime)
|
|
46
48
|
nb_assets_ready = db.Column(db.Integer, default=0)
|
|
47
49
|
data = db.Column(JSONB)
|
|
@@ -69,6 +71,9 @@ class Task(db.Model, BaseMixin, SerializerMixin):
|
|
|
69
71
|
db.UniqueConstraint(
|
|
70
72
|
"name", "project_id", "task_type_id", "entity_id", name="task_uc"
|
|
71
73
|
),
|
|
74
|
+
db.CheckConstraint(
|
|
75
|
+
"difficulty > 0 AND difficulty < 6", name="check_difficulty"
|
|
76
|
+
),
|
|
72
77
|
)
|
|
73
78
|
|
|
74
79
|
def assignees_as_string(self):
|
zou/app/models/task_status.py
CHANGED
|
@@ -15,6 +15,7 @@ class TaskStatus(db.Model, BaseMixin, SerializerMixin):
|
|
|
15
15
|
short_name = db.Column(
|
|
16
16
|
db.String(10), unique=True, nullable=False, index=True
|
|
17
17
|
)
|
|
18
|
+
description = db.Column(db.Text())
|
|
18
19
|
color = db.Column(db.String(7), nullable=False)
|
|
19
20
|
priority = db.Column(db.Integer, default=1)
|
|
20
21
|
|
zou/app/models/task_type.py
CHANGED
|
@@ -12,6 +12,7 @@ class TaskType(db.Model, BaseMixin, SerializerMixin):
|
|
|
12
12
|
|
|
13
13
|
name = db.Column(db.String(40), nullable=False)
|
|
14
14
|
short_name = db.Column(db.String(20))
|
|
15
|
+
description = db.Column(db.Text())
|
|
15
16
|
color = db.Column(db.String(7), default="#FFFFFF")
|
|
16
17
|
priority = db.Column(db.Integer, default=1)
|
|
17
18
|
for_entity = db.Column(db.String(30), default="Asset")
|