zou 0.19.69__py3-none-any.whl → 0.19.70__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 (38) hide show
  1. zou/__init__.py +1 -1
  2. zou/app/__init__.py +1 -1
  3. zou/app/blueprints/auth/resources.py +17 -15
  4. zou/app/blueprints/breakdown/resources.py +4 -4
  5. zou/app/blueprints/crud/base.py +4 -1
  6. zou/app/blueprints/crud/comments.py +0 -13
  7. zou/app/blueprints/crud/event.py +1 -1
  8. zou/app/blueprints/crud/metadata_descriptor.py +9 -9
  9. zou/app/blueprints/crud/organisation.py +16 -1
  10. zou/app/blueprints/events/resources.py +8 -8
  11. zou/app/blueprints/export/csv/assets.py +15 -6
  12. zou/app/blueprints/export/csv/edits.py +15 -5
  13. zou/app/blueprints/export/csv/shots.py +15 -5
  14. zou/app/blueprints/index/resources.py +2 -0
  15. zou/app/blueprints/news/resources.py +6 -6
  16. zou/app/blueprints/source/csv/assets.py +10 -3
  17. zou/app/blueprints/source/csv/base.py +1 -1
  18. zou/app/blueprints/source/csv/edits.py +10 -3
  19. zou/app/blueprints/source/csv/shots.py +10 -3
  20. zou/app/blueprints/tasks/resources.py +7 -1
  21. zou/app/models/organisation.py +11 -19
  22. zou/app/models/serializer.py +17 -17
  23. zou/app/services/events_service.py +4 -4
  24. zou/app/services/news_service.py +8 -8
  25. zou/app/services/persons_service.py +5 -4
  26. zou/app/services/sync_service.py +4 -4
  27. zou/app/services/tasks_service.py +4 -2
  28. zou/app/services/user_service.py +21 -36
  29. zou/app/utils/commands.py +4 -4
  30. zou/app/utils/csv_utils.py +1 -4
  31. zou/cli.py +4 -4
  32. zou/remote/config_payload.py +2 -1
  33. {zou-0.19.69.dist-info → zou-0.19.70.dist-info}/METADATA +6 -6
  34. {zou-0.19.69.dist-info → zou-0.19.70.dist-info}/RECORD +38 -38
  35. {zou-0.19.69.dist-info → zou-0.19.70.dist-info}/LICENSE +0 -0
  36. {zou-0.19.69.dist-info → zou-0.19.70.dist-info}/WHEEL +0 -0
  37. {zou-0.19.69.dist-info → zou-0.19.70.dist-info}/entry_points.txt +0 -0
  38. {zou-0.19.69.dist-info → zou-0.19.70.dist-info}/top_level.txt +0 -0
zou/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.19.69"
1
+ __version__ = "0.19.70"
zou/app/__init__.py CHANGED
@@ -134,7 +134,7 @@ def indexer_key_error(error):
134
134
  raise error
135
135
 
136
136
 
137
- if not config.DEBUG:
137
+ if config.DEBUG:
138
138
 
139
139
  @app.errorhandler(Exception)
140
140
  def server_error(error):
@@ -78,7 +78,9 @@ class AuthenticatedResource(Resource):
78
78
  description: Person not found
79
79
  """
80
80
  person = persons_service.get_current_user(relations=True)
81
- organisation = persons_service.get_organisation()
81
+ organisation = persons_service.get_organisation(
82
+ sensitive=permissions.has_admin_permissions()
83
+ )
82
84
  return {
83
85
  "authenticated": True,
84
86
  "user": person,
@@ -227,15 +229,21 @@ class LoginResource(Resource, ArgsMixin):
227
229
  "HTTP_X_REAL_IP", request.remote_addr
228
230
  )
229
231
 
232
+ organisation = persons_service.get_organisation(
233
+ sensitive=user["role"] != "admin"
234
+ )
235
+
236
+ response = jsonify(
237
+ {
238
+ "user": user,
239
+ "organisation": organisation,
240
+ "login": True,
241
+ "access_token": access_token,
242
+ "refresh_token": refresh_token,
243
+ }
244
+ )
245
+
230
246
  if is_from_browser(request.user_agent):
231
- organisation = persons_service.get_organisation()
232
- response = jsonify(
233
- {
234
- "user": user,
235
- "organisation": organisation,
236
- "login": True,
237
- }
238
- )
239
247
  set_access_cookies(response, access_token)
240
248
  set_refresh_cookies(response, refresh_token)
241
249
  events_service.create_login_log(user["id"], ip_address, "web")
@@ -243,12 +251,6 @@ class LoginResource(Resource, ArgsMixin):
243
251
  events_service.create_login_log(
244
252
  user["id"], ip_address, "script"
245
253
  )
246
- response = {
247
- "login": True,
248
- "user": user,
249
- "access_token": access_token,
250
- "refresh_token": refresh_token,
251
- }
252
254
  current_app.logger.info(f"User {email} is logged in.")
253
255
  return response
254
256
  except WrongUserException:
@@ -398,14 +398,14 @@ class ProjectEntityLinksResource(Resource, ArgsMixin):
398
398
  type: string
399
399
  format: Number
400
400
  x-example: 2
401
- - in: limit
402
- name: page
401
+ - in: query
402
+ name: limit
403
403
  required: False
404
404
  type: string
405
405
  format: Number
406
406
  x-example: 100
407
- - in: cursor_created_at
408
- name: page
407
+ - in: query
408
+ name: cursor_created_at
409
409
  required: False
410
410
  type: string
411
411
  format: Datetime
@@ -26,7 +26,10 @@ class BaseModelsResource(Resource, ArgsMixin):
26
26
  if query is None:
27
27
  query = self.model.query
28
28
 
29
- return self.model.serialize_list(query.all(), relations=relations)
29
+ return self.serialize_list(query.all(), relations=relations)
30
+
31
+ def serialize_list(self, entries, relations=False):
32
+ return self.model.serialize_list(entries, relations=relations)
30
33
 
31
34
  def paginated_entries(self, query, page, limit=None, relations=False):
32
35
  total = query.count()
@@ -22,19 +22,6 @@ class CommentsResource(BaseModelsResource):
22
22
  def __init__(self):
23
23
  BaseModelsResource.__init__(self, Comment)
24
24
 
25
- def check_read_permissions(self, options=None):
26
- if options is not None:
27
- if "project_id" in options:
28
- user_service.check_project_access(options["project_id"])
29
- if (
30
- permissions.has_vendor_permissions()
31
- or permissions.has_client_permissions()
32
- ):
33
- raise permissions.PermissionDenied
34
- else:
35
- return True
36
- return permissions.check_admin_permissions()
37
-
38
25
 
39
26
  class CommentResource(BaseModelResource):
40
27
  def __init__(self):
@@ -11,7 +11,7 @@ class EventsResource(BaseModelsResource):
11
11
  if query is None:
12
12
  query = self.model.query
13
13
 
14
- return self.model.serialize_list(
14
+ return self.serialize_list(
15
15
  query.limit(1000).all(), relations=relations
16
16
  )
17
17
 
@@ -27,15 +27,6 @@ class MetadataDescriptorsResource(BaseModelsResource):
27
27
  )
28
28
  return query
29
29
 
30
- def all_entries(self, query=None, relations=True):
31
- if query is None:
32
- query = self.model.query
33
-
34
- return [
35
- metadata_descriptor.serialize(relations=relations)
36
- for metadata_descriptor in query.all()
37
- ]
38
-
39
30
  def check_creation_integrity(self, data):
40
31
  """
41
32
  Check if the data descriptor has a valid data_type.
@@ -46,6 +37,15 @@ class MetadataDescriptorsResource(BaseModelsResource):
46
37
  raise WrongParameterException("Invalid data_type")
47
38
  return True
48
39
 
40
+ def all_entries(self, query=None, relations=True):
41
+ if query is None:
42
+ query = self.model.query
43
+
44
+ return [
45
+ metadata_descriptor.serialize(relations=relations)
46
+ for metadata_descriptor in query.all()
47
+ ]
48
+
49
49
 
50
50
  class MetadataDescriptorResource(BaseModelResource):
51
51
 
@@ -2,6 +2,7 @@ from zou.app.models.organisation import Organisation
2
2
  from zou.app.blueprints.crud.base import BaseModelResource, BaseModelsResource
3
3
 
4
4
  from zou.app.services import persons_service
5
+ from zou.app.utils.permissions import has_admin_permissions
5
6
 
6
7
 
7
8
  class OrganisationsResource(BaseModelsResource):
@@ -24,6 +25,20 @@ class OrganisationResource(BaseModelResource):
24
25
  data["hours_by_day"] = float(data["hours_by_day"])
25
26
  return data
26
27
 
28
+ def serialize_instance(self, data, relations=True):
29
+ return data.serialize(
30
+ relations=relations,
31
+ ignored_attrs=(
32
+ []
33
+ if has_admin_permissions()
34
+ else [
35
+ "chat_token_slack",
36
+ "chat_webhook_mattermost",
37
+ "chat_token_discord",
38
+ ]
39
+ ),
40
+ )
41
+
27
42
  def post_update(self, instance_dict, data):
28
- persons_service.clear_oranisation_cache()
43
+ persons_service.clear_organisation_cache()
29
44
  return instance_dict
@@ -32,7 +32,7 @@ class EventsResource(Resource, ArgsMixin):
32
32
  type: boolean
33
33
  default: False
34
34
  - in: query
35
- name: page_size
35
+ name: limit
36
36
  type: integer
37
37
  default: 100
38
38
  x-example: 100
@@ -50,7 +50,7 @@ class EventsResource(Resource, ArgsMixin):
50
50
  ("after", None, False),
51
51
  ("before", None, False),
52
52
  ("only_files", False, False),
53
- ("page_size", 100, False),
53
+ ("limit", 100, False),
54
54
  ("project_id", None, False),
55
55
  ("name", None, False),
56
56
  ],
@@ -59,7 +59,7 @@ class EventsResource(Resource, ArgsMixin):
59
59
  permissions.check_manager_permissions()
60
60
  before = self.parse_date_parameter(args["before"])
61
61
  after = self.parse_date_parameter(args["after"])
62
- page_size = args["page_size"]
62
+ limit = args["limit"]
63
63
  only_files = args["only_files"] == "true"
64
64
  project_id = args.get("project_id", None)
65
65
  name = args["name"]
@@ -71,7 +71,7 @@ class EventsResource(Resource, ArgsMixin):
71
71
  return events_service.get_last_events(
72
72
  after=after,
73
73
  before=before,
74
- page_size=page_size,
74
+ limit=limit,
75
75
  only_files=only_files,
76
76
  project_id=project_id,
77
77
  name=name,
@@ -93,18 +93,18 @@ class LoginLogsResource(Resource, ArgsMixin):
93
93
  format: date
94
94
  x-example: "2022-07-12T00:00:00"
95
95
  - in: query
96
- name: page_size
96
+ name: limit
97
97
  type: integer
98
98
  x-example: 100
99
99
  responses:
100
100
  200:
101
101
  description: All login logs
102
102
  """
103
- args = self.get_args(["before", ("page_size", 100)])
103
+ args = self.get_args(["before", ("limit", 100)])
104
104
 
105
105
  permissions.check_manager_permissions()
106
106
  before = None
107
107
  if args["before"] is not None:
108
108
  before = date_helpers.get_datetime_from_string(args["before"])
109
- page_size = args["page_size"]
110
- return events_service.get_last_login_logs(before, page_size)
109
+ limit = args["limit"]
110
+ return events_service.get_last_login_logs(before, limit)
@@ -65,7 +65,7 @@ class AssetsCsvExport(Resource):
65
65
  def build_headers(self, metadata_infos, validation_columns):
66
66
  headers = ["Project", "Type", "Name", "Description", "Time Spent"]
67
67
 
68
- metadata_headers = [name for (name, _) in metadata_infos]
68
+ metadata_headers = [name for (name, _, _) in metadata_infos]
69
69
 
70
70
  validation_assignations_columns = []
71
71
  for validation_column in validation_columns:
@@ -97,10 +97,15 @@ class AssetsCsvExport(Resource):
97
97
  for person_id in task["assignees"]
98
98
  ]
99
99
  )
100
-
101
- for _, field_name in metadata_infos:
102
- result_metadata = result.get("data", {}) or {}
103
- row.append(result_metadata.get(field_name, ""))
100
+ result_data = result.get("data", {}) or {}
101
+ for _, field_name, data_type in metadata_infos:
102
+ result_metadata = result_data.get(field_name, "")
103
+ if data_type == "boolean":
104
+ row.append(
105
+ "true" if result_metadata.lower() == "true" else "false"
106
+ )
107
+ else:
108
+ row.append(result_metadata)
104
109
 
105
110
  for column in validation_columns:
106
111
  if column in task_map:
@@ -153,7 +158,11 @@ class AssetsCsvExport(Resource):
153
158
  ]
154
159
 
155
160
  columns = [
156
- (descriptor["name"], descriptor["field_name"])
161
+ (
162
+ descriptor["name"],
163
+ descriptor["field_name"],
164
+ descriptor["data_type"],
165
+ )
157
166
  for descriptor in descriptors
158
167
  ]
159
168
 
@@ -61,7 +61,7 @@ class EditsCsvExport(Resource):
61
61
  def build_headers(self, metadata_infos, validation_columns):
62
62
  headers = ["Project", "Episode", "Name", "Description", "Time Spent"]
63
63
 
64
- metadata_headers = [name for (name, _) in metadata_infos]
64
+ metadata_headers = [name for (name, _, _) in metadata_infos]
65
65
 
66
66
  validation_assignations_columns = []
67
67
  for validation_column in validation_columns:
@@ -94,9 +94,15 @@ class EditsCsvExport(Resource):
94
94
  ]
95
95
  )
96
96
 
97
- for _, field_name in metadata_infos:
98
- result_metadata = result.get("data", {}) or {}
99
- row.append(result_metadata.get(field_name, ""))
97
+ result_data = result.get("data", {}) or {}
98
+ for _, field_name, data_type in metadata_infos:
99
+ result_metadata = result_data.get(field_name, "")
100
+ if data_type == "boolean":
101
+ row.append(
102
+ "true" if result_metadata.lower() == "true" else "false"
103
+ )
104
+ else:
105
+ row.append(result_metadata)
100
106
 
101
107
  for column in validation_columns:
102
108
  if column in task_map:
@@ -149,7 +155,11 @@ class EditsCsvExport(Resource):
149
155
  ]
150
156
 
151
157
  columns = [
152
- (descriptor["name"], descriptor["field_name"])
158
+ (
159
+ descriptor["name"],
160
+ descriptor["field_name"],
161
+ descriptor["data_type"],
162
+ )
153
163
  for descriptor in descriptors
154
164
  ]
155
165
 
@@ -76,7 +76,7 @@ class ShotsCsvExport(Resource):
76
76
  "FPS",
77
77
  ]
78
78
 
79
- metadata_headers = [name for (name, _) in metadata_infos]
79
+ metadata_headers = [name for (name, _, _) in metadata_infos]
80
80
 
81
81
  validation_assignations_columns = []
82
82
  for validation_column in validation_columns:
@@ -123,9 +123,15 @@ class ShotsCsvExport(Resource):
123
123
  for person_id in task["assignees"]
124
124
  ]
125
125
  )
126
-
127
- for _, field_name in metadata_infos:
128
- row.append(result.get("data", {}).get(field_name, ""))
126
+ result_data = result.get("data", {}) or {}
127
+ for _, field_name, data_type in metadata_infos:
128
+ result_metadata = result_data.get(field_name, "")
129
+ if data_type == "boolean":
130
+ row.append(
131
+ "true" if result_metadata.lower() == "true" else "false"
132
+ )
133
+ else:
134
+ row.append(result_metadata)
129
135
 
130
136
  for column in validation_columns:
131
137
  if column in task_map:
@@ -171,7 +177,11 @@ class ShotsCsvExport(Resource):
171
177
  ]
172
178
 
173
179
  columns = [
174
- (descriptor["name"], descriptor["field_name"])
180
+ (
181
+ descriptor["name"],
182
+ descriptor["field_name"],
183
+ descriptor["data_type"],
184
+ )
175
185
  for descriptor in descriptors
176
186
  ]
177
187
 
@@ -297,6 +297,8 @@ class ConfigResource(Resource):
297
297
  ),
298
298
  "saml_enabled": config.SAML_ENABLED,
299
299
  "saml_idp_name": config.SAML_IDP_NAME,
300
+ "default_locale": config.DEFAULT_LOCALE,
301
+ "default_timezone": config.DEFAULT_TIMEZONE,
300
302
  }
301
303
  if config.SENTRY_KITSU_ENABLED:
302
304
  conf["sentry"] = {
@@ -21,7 +21,7 @@ class NewsMixin(ArgsMixin):
21
21
  episode_id,
22
22
  person_id,
23
23
  page,
24
- page_size,
24
+ limit,
25
25
  after,
26
26
  before,
27
27
  ) = self.get_arguments()
@@ -38,7 +38,7 @@ class NewsMixin(ArgsMixin):
38
38
  episode_id=episode_id,
39
39
  author_id=person_id,
40
40
  page=page,
41
- page_size=page_size,
41
+ limit=limit,
42
42
  after=after,
43
43
  before=before,
44
44
  current_user=current_user,
@@ -72,7 +72,7 @@ class NewsMixin(ArgsMixin):
72
72
  "project_id",
73
73
  "episode_id",
74
74
  {"name": "page", "default": 1, "type": int},
75
- {"name": "page_size", "default": 50, "type": int},
75
+ {"name": "limit", "default": 50, "type": int},
76
76
  "after",
77
77
  "before",
78
78
  ],
@@ -84,7 +84,7 @@ class NewsMixin(ArgsMixin):
84
84
  args["episode_id"],
85
85
  args["person_id"],
86
86
  args["page"],
87
- args["page_size"],
87
+ args["limit"],
88
88
  args["after"],
89
89
  args["before"],
90
90
  )
@@ -120,7 +120,7 @@ class ProjectNewsResource(Resource, NewsMixin, ArgsMixin):
120
120
  type: integer
121
121
  x-example: 1
122
122
  - in: query
123
- name: page_size
123
+ name: limit
124
124
  type: integer
125
125
  x-example: 50
126
126
  - in: query
@@ -183,7 +183,7 @@ class NewsResource(Resource, NewsMixin, ArgsMixin):
183
183
  type: integer
184
184
  x-example: 1
185
185
  - in: query
186
- name: page_size
186
+ name: limit
187
187
  type: integer
188
188
  x-example: 50
189
189
  - in: query
@@ -16,7 +16,7 @@ from zou.app.services import (
16
16
  )
17
17
  from zou.app.models.entity import Entity
18
18
  from zou.app.services.exception import WrongParameterException
19
- from zou.app.utils import events, cache
19
+ from zou.app.utils import events, cache, string
20
20
 
21
21
 
22
22
  class AssetsCsvImportResource(BaseCsvProjectImportResource):
@@ -209,9 +209,16 @@ class AssetsCsvImportResource(BaseCsvProjectImportResource):
209
209
  else:
210
210
  asset_new_values["data"] = entity.data.copy()
211
211
 
212
- for name, field_name in self.descriptor_fields.items():
212
+ for name, descriptor in self.descriptor_fields.items():
213
213
  if name in row:
214
- asset_new_values["data"][field_name] = row[name]
214
+ if descriptor["data_type"] == "boolean":
215
+ asset_new_values["data"][descriptor["field_name"]] = (
216
+ "true" if string.strtobool(row[name]) else "false"
217
+ )
218
+ else:
219
+ asset_new_values["data"][descriptor["field_name"]] = row[
220
+ name
221
+ ]
215
222
 
216
223
  ready_for = row.get("Ready for", None)
217
224
  if ready_for is not None:
@@ -131,5 +131,5 @@ class BaseCsvProjectImportResource(BaseCsvImportResource, ArgsMixin):
131
131
  descriptors = projects_service.get_metadata_descriptors(project_id)
132
132
  for descriptor in descriptors:
133
133
  if descriptor["entity_type"] == entity_type:
134
- descriptor_map[descriptor["name"]] = descriptor["field_name"]
134
+ descriptor_map[descriptor["name"]] = descriptor
135
135
  return descriptor_map
@@ -21,7 +21,7 @@ from zou.app.services.tasks_service import (
21
21
  )
22
22
  from zou.app.services.comments_service import create_comment
23
23
  from zou.app.services.exception import WrongParameterException
24
- from zou.app.utils import events
24
+ from zou.app.utils import events, string
25
25
 
26
26
 
27
27
  class EditsCsvImportResource(BaseCsvProjectImportResource):
@@ -192,9 +192,16 @@ class EditsCsvImportResource(BaseCsvProjectImportResource):
192
192
  else:
193
193
  edit_new_values["data"] = entity.data.copy()
194
194
 
195
- for name, field_name in self.descriptor_fields.items():
195
+ for name, descriptor in self.descriptor_fields.items():
196
196
  if name in row:
197
- edit_new_values["data"][field_name] = row[name]
197
+ if descriptor["data_type"] == "boolean":
198
+ edit_new_values["data"][descriptor["field_name"]] = (
199
+ "true" if string.strtobool(row[name]) else "false"
200
+ )
201
+ else:
202
+ edit_new_values["data"][descriptor["field_name"]] = row[
203
+ name
204
+ ]
198
205
 
199
206
  tasks_update = self.get_tasks_update(row)
200
207
 
@@ -21,7 +21,7 @@ from zou.app.services.tasks_service import (
21
21
  )
22
22
  from zou.app.services.comments_service import create_comment
23
23
  from zou.app.services.exception import WrongParameterException
24
- from zou.app.utils import events
24
+ from zou.app.utils import events, string
25
25
 
26
26
 
27
27
  class ShotsCsvImportResource(BaseCsvProjectImportResource):
@@ -229,9 +229,16 @@ class ShotsCsvImportResource(BaseCsvProjectImportResource):
229
229
  if fps is not None:
230
230
  shot_new_values["data"]["fps"] = fps
231
231
 
232
- for name, field_name in self.descriptor_fields.items():
232
+ for name, descriptor in self.descriptor_fields.items():
233
233
  if name in row:
234
- shot_new_values["data"][field_name] = row[name]
234
+ if descriptor["data_type"] == "boolean":
235
+ shot_new_values["data"][descriptor["field_name"]] = (
236
+ "true" if string.strtobool(row[name]) else "false"
237
+ )
238
+ else:
239
+ shot_new_values["data"][descriptor["field_name"]] = row[
240
+ name
241
+ ]
235
242
 
236
243
  tasks_update = self.get_tasks_update(row)
237
244
 
@@ -1532,6 +1532,11 @@ class ProjectCommentsResource(Resource, ArgsMixin):
1532
1532
  type: string
1533
1533
  format: UUID
1534
1534
  x-example: a24a6ea4-ce75-4665-a070-57453082c25
1535
+ - in: query
1536
+ name: limit
1537
+ type: integer
1538
+ default: 100
1539
+ x-example: 100
1535
1540
  responses:
1536
1541
  200:
1537
1542
  description: All comments to tasks related to given project
@@ -1544,7 +1549,8 @@ class ProjectCommentsResource(Resource, ArgsMixin):
1544
1549
  ):
1545
1550
  raise permissions.PermissionDenied
1546
1551
  page = self.get_page()
1547
- return tasks_service.get_comments_for_project(project_id, page)
1552
+ limit = self.get_limit()
1553
+ return tasks_service.get_comments_for_project(project_id, page, limit)
1548
1554
 
1549
1555
 
1550
1556
  class ProjectPreviewFilesResource(Resource, ArgsMixin):
@@ -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):
@@ -22,22 +21,15 @@ class Organisation(db.Model, BaseMixin, SerializerMixin):
22
21
  dark_theme_by_default = db.Column(db.Boolean(), default=False)
23
22
  format_duration_in_hours = db.Column(db.Boolean(), default=False)
24
23
 
25
- def present(self):
26
- return fields.serialize_dict(
27
- {
28
- "id": self.id,
29
- "chat_token_slack": self.chat_token_slack,
30
- "chat_webhook_mattermost": self.chat_webhook_mattermost,
31
- "chat_token_discord": self.chat_token_discord,
32
- "name": self.name,
33
- "has_avatar": self.has_avatar,
34
- "hours_by_day": self.hours_by_day,
35
- "hd_by_default": self.hd_by_default,
36
- "use_original_file_name": self.use_original_file_name,
37
- "timesheets_locked": self.timesheets_locked,
38
- "dark_theme_by_default": self.dark_theme_by_default,
39
- "format_duration_in_hours": self.format_duration_in_hours,
40
- "updated_at": self.updated_at,
41
- "created_at": self.created_at,
42
- }
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
+ )
43
35
  )
@@ -14,35 +14,35 @@ class SerializerMixin(object):
14
14
  orm.attributes.CollectionAttributeImpl,
15
15
  )
16
16
 
17
- def serialize(self, obj_type=None, relations=False, milliseconds=False):
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
- if relations:
20
- obj_dict = {
21
- attr: serialize_value(
22
- getattr(self, attr), milliseconds=milliseconds
23
- )
24
- for attr in attrs
25
- }
26
- else:
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
  ]