zou 0.19.48__py3-none-any.whl → 0.19.50__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/blueprints/persons/resources.py +54 -13
- zou/app/blueprints/shots/resources.py +34 -4
- zou/app/mixin.py +1 -0
- zou/app/models/task.py +1 -0
- zou/app/services/assets_service.py +3 -0
- zou/app/services/entities_service.py +3 -0
- zou/app/services/shots_service.py +112 -33
- zou/app/services/tasks_service.py +26 -1
- zou/migrations/versions/ca28796a2a62_add_is_done_field_to_the_task_model.py +108 -0
- {zou-0.19.48.dist-info → zou-0.19.50.dist-info}/METADATA +5 -5
- {zou-0.19.48.dist-info → zou-0.19.50.dist-info}/RECORD +16 -15
- {zou-0.19.48.dist-info → zou-0.19.50.dist-info}/WHEEL +1 -1
- {zou-0.19.48.dist-info → zou-0.19.50.dist-info}/LICENSE +0 -0
- {zou-0.19.48.dist-info → zou-0.19.50.dist-info}/entry_points.txt +0 -0
- {zou-0.19.48.dist-info → zou-0.19.50.dist-info}/top_level.txt +0 -0
zou/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.19.
|
|
1
|
+
__version__ = "0.19.50"
|
|
@@ -308,7 +308,7 @@ class PersonDurationTimeSpentsResource(Resource, ArgsMixin):
|
|
|
308
308
|
raise permissions.PermissionDenied
|
|
309
309
|
if permissions.has_supervisor_permissions():
|
|
310
310
|
department_ids = persons_service.get_current_user(
|
|
311
|
-
True
|
|
311
|
+
relations=True
|
|
312
312
|
)["departments"]
|
|
313
313
|
else:
|
|
314
314
|
raise permissions.PermissionDenied
|
|
@@ -533,7 +533,24 @@ class PersonDayTimeSpentsResource(PersonDurationTimeSpentsResource):
|
|
|
533
533
|
abort(404)
|
|
534
534
|
|
|
535
535
|
|
|
536
|
-
class
|
|
536
|
+
class PersonQuotaMixin:
|
|
537
|
+
|
|
538
|
+
def get_quota_arguments(self):
|
|
539
|
+
project_id = self.get_project_id()
|
|
540
|
+
task_type_id = self.get_task_type_id()
|
|
541
|
+
count_mode = self.get_text_parameter("count_mode", default="weigthed")
|
|
542
|
+
if count_mode not in ["weighted", "weighteddone", "feedback", "done"]:
|
|
543
|
+
raise WrongParameterException(
|
|
544
|
+
"count_mode must be equal to weighted, weigtheddone, feedback"
|
|
545
|
+
", or done"
|
|
546
|
+
)
|
|
547
|
+
feedback = "done" not in count_mode
|
|
548
|
+
weighted = "weighted" in count_mode
|
|
549
|
+
|
|
550
|
+
return (project_id, task_type_id, count_mode, feedback, weighted)
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
class PersonMonthQuotaShotsResource(Resource, ArgsMixin, PersonQuotaMixin):
|
|
537
554
|
"""
|
|
538
555
|
Get ended shots used for quota calculation of this month.
|
|
539
556
|
"""
|
|
@@ -564,6 +581,12 @@ class PersonMonthQuotaShotsResource(Resource, ArgsMixin):
|
|
|
564
581
|
x-example: 07
|
|
565
582
|
minimum: 1
|
|
566
583
|
maximum: 12
|
|
584
|
+
- in: query
|
|
585
|
+
name: count_mode
|
|
586
|
+
required: True
|
|
587
|
+
type: string
|
|
588
|
+
enum: [weighted, weigtheddone, feedback, done]
|
|
589
|
+
x-example: weighted
|
|
567
590
|
responses:
|
|
568
591
|
200:
|
|
569
592
|
description: Ended shots used for quota calculation of this month
|
|
@@ -571,10 +594,11 @@ class PersonMonthQuotaShotsResource(Resource, ArgsMixin):
|
|
|
571
594
|
description: Wrong date format
|
|
572
595
|
"""
|
|
573
596
|
user_service.check_person_is_not_bot(person_id)
|
|
574
|
-
project_id = self.get_project_id()
|
|
575
|
-
task_type_id = self.get_task_type_id()
|
|
576
597
|
user_service.check_person_access(person_id)
|
|
577
|
-
weighted =
|
|
598
|
+
(project_id, task_type_id, count_mode, feedback, weighted) = (
|
|
599
|
+
self.get_quota_arguments()
|
|
600
|
+
)
|
|
601
|
+
|
|
578
602
|
try:
|
|
579
603
|
return shots_service.get_month_quota_shots(
|
|
580
604
|
person_id,
|
|
@@ -583,12 +607,13 @@ class PersonMonthQuotaShotsResource(Resource, ArgsMixin):
|
|
|
583
607
|
project_id=project_id,
|
|
584
608
|
task_type_id=task_type_id,
|
|
585
609
|
weighted=weighted,
|
|
610
|
+
feedback=feedback,
|
|
586
611
|
)
|
|
587
612
|
except WrongDateFormatException:
|
|
588
613
|
abort(404)
|
|
589
614
|
|
|
590
615
|
|
|
591
|
-
class PersonWeekQuotaShotsResource(Resource, ArgsMixin):
|
|
616
|
+
class PersonWeekQuotaShotsResource(Resource, ArgsMixin, PersonQuotaMixin):
|
|
592
617
|
"""
|
|
593
618
|
Get ended shots used for quota calculation of this week.
|
|
594
619
|
"""
|
|
@@ -619,6 +644,12 @@ class PersonWeekQuotaShotsResource(Resource, ArgsMixin):
|
|
|
619
644
|
x-example: 35
|
|
620
645
|
minimum: 1
|
|
621
646
|
maximum: 52
|
|
647
|
+
- in: query
|
|
648
|
+
name: count_mode
|
|
649
|
+
required: True
|
|
650
|
+
type: string
|
|
651
|
+
enum: [weighted, weigtheddone, feedback, done]
|
|
652
|
+
x-example: weighted
|
|
622
653
|
responses:
|
|
623
654
|
200:
|
|
624
655
|
description: Ended shots used for quota calculation of this week
|
|
@@ -626,10 +657,11 @@ class PersonWeekQuotaShotsResource(Resource, ArgsMixin):
|
|
|
626
657
|
description: Wrong date format
|
|
627
658
|
"""
|
|
628
659
|
user_service.check_person_is_not_bot(person_id)
|
|
629
|
-
project_id = self.get_project_id()
|
|
630
|
-
task_type_id = self.get_task_type_id()
|
|
631
660
|
user_service.check_person_access(person_id)
|
|
632
|
-
weighted =
|
|
661
|
+
(project_id, task_type_id, count_mode, feedback, weighted) = (
|
|
662
|
+
self.get_quota_arguments()
|
|
663
|
+
)
|
|
664
|
+
|
|
633
665
|
try:
|
|
634
666
|
return shots_service.get_week_quota_shots(
|
|
635
667
|
person_id,
|
|
@@ -638,12 +670,13 @@ class PersonWeekQuotaShotsResource(Resource, ArgsMixin):
|
|
|
638
670
|
project_id=project_id,
|
|
639
671
|
task_type_id=task_type_id,
|
|
640
672
|
weighted=weighted,
|
|
673
|
+
feedback=feedback,
|
|
641
674
|
)
|
|
642
675
|
except WrongDateFormatException:
|
|
643
676
|
abort(404)
|
|
644
677
|
|
|
645
678
|
|
|
646
|
-
class PersonDayQuotaShotsResource(Resource, ArgsMixin):
|
|
679
|
+
class PersonDayQuotaShotsResource(Resource, ArgsMixin, PersonQuotaMixin):
|
|
647
680
|
"""
|
|
648
681
|
Get ended shots used for quota calculation of this day.
|
|
649
682
|
"""
|
|
@@ -681,6 +714,12 @@ class PersonDayQuotaShotsResource(Resource, ArgsMixin):
|
|
|
681
714
|
x-example: 12
|
|
682
715
|
minimum: 1
|
|
683
716
|
maximum: 31
|
|
717
|
+
- in: query
|
|
718
|
+
name: count_mode
|
|
719
|
+
required: True
|
|
720
|
+
type: string
|
|
721
|
+
enum: [weighted, weigtheddone, feedback, done]
|
|
722
|
+
x-example: weighted
|
|
684
723
|
responses:
|
|
685
724
|
200:
|
|
686
725
|
description: Ended shots used for quota calculation of this day
|
|
@@ -688,10 +727,11 @@ class PersonDayQuotaShotsResource(Resource, ArgsMixin):
|
|
|
688
727
|
description: Wrong date format
|
|
689
728
|
"""
|
|
690
729
|
user_service.check_person_is_not_bot(person_id)
|
|
691
|
-
project_id = self.get_project_id()
|
|
692
|
-
task_type_id = self.get_task_type_id()
|
|
693
730
|
user_service.check_person_access(person_id)
|
|
694
|
-
weighted =
|
|
731
|
+
(project_id, task_type_id, count_mode, feedback, weighted) = (
|
|
732
|
+
self.get_quota_arguments()
|
|
733
|
+
)
|
|
734
|
+
|
|
695
735
|
try:
|
|
696
736
|
return shots_service.get_day_quota_shots(
|
|
697
737
|
person_id,
|
|
@@ -701,6 +741,7 @@ class PersonDayQuotaShotsResource(Resource, ArgsMixin):
|
|
|
701
741
|
project_id=project_id,
|
|
702
742
|
task_type_id=task_type_id,
|
|
703
743
|
weighted=weighted,
|
|
744
|
+
feedback=feedback,
|
|
704
745
|
)
|
|
705
746
|
except WrongDateFormatException:
|
|
706
747
|
abort(404)
|
|
@@ -1507,6 +1507,18 @@ class ProjectQuotasResource(Resource, ArgsMixin):
|
|
|
1507
1507
|
type: string
|
|
1508
1508
|
format: UUID
|
|
1509
1509
|
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1510
|
+
- in: query
|
|
1511
|
+
name: count_mode
|
|
1512
|
+
required: True
|
|
1513
|
+
type: string
|
|
1514
|
+
enum: [weighted, weigtheddone, feedback, done]
|
|
1515
|
+
x-example: weighted
|
|
1516
|
+
- in: query
|
|
1517
|
+
name: studio_id
|
|
1518
|
+
required: False
|
|
1519
|
+
type: string
|
|
1520
|
+
format: UUID
|
|
1521
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
1510
1522
|
responses:
|
|
1511
1523
|
200:
|
|
1512
1524
|
description: Quotas statistics for shots
|
|
@@ -1515,17 +1527,35 @@ class ProjectQuotasResource(Resource, ArgsMixin):
|
|
|
1515
1527
|
user_service.check_project_access(project_id)
|
|
1516
1528
|
args = self.get_args(
|
|
1517
1529
|
[
|
|
1518
|
-
("
|
|
1530
|
+
("count_mode", "weighted", False, str),
|
|
1519
1531
|
("studio_id", None, False, str),
|
|
1520
1532
|
]
|
|
1521
1533
|
)
|
|
1522
|
-
|
|
1534
|
+
count_mode = args["count_mode"]
|
|
1535
|
+
studio_id = args["studio_id"]
|
|
1536
|
+
|
|
1537
|
+
if count_mode not in ["weighted", "weighteddone", "feedback", "done"]:
|
|
1538
|
+
raise WrongParameterException(
|
|
1539
|
+
"count_mode must be equal to weighted, weigtheddone, feedback"
|
|
1540
|
+
", or done"
|
|
1541
|
+
)
|
|
1542
|
+
|
|
1543
|
+
feedback = "done" not in count_mode
|
|
1544
|
+
weighted = "weighted" in count_mode
|
|
1545
|
+
|
|
1546
|
+
if weighted:
|
|
1523
1547
|
return shots_service.get_weighted_quotas(
|
|
1524
|
-
project_id,
|
|
1548
|
+
project_id,
|
|
1549
|
+
task_type_id,
|
|
1550
|
+
feedback=feedback,
|
|
1551
|
+
studio_id=studio_id,
|
|
1525
1552
|
)
|
|
1526
1553
|
else:
|
|
1527
1554
|
return shots_service.get_raw_quotas(
|
|
1528
|
-
project_id,
|
|
1555
|
+
project_id,
|
|
1556
|
+
task_type_id,
|
|
1557
|
+
feedback=feedback,
|
|
1558
|
+
studio_id=studio_id,
|
|
1529
1559
|
)
|
|
1530
1560
|
|
|
1531
1561
|
|
zou/app/mixin.py
CHANGED
zou/app/models/task.py
CHANGED
|
@@ -42,6 +42,7 @@ class Task(db.Model, BaseMixin, SerializerMixin):
|
|
|
42
42
|
due_date = db.Column(db.DateTime)
|
|
43
43
|
real_start_date = db.Column(db.DateTime)
|
|
44
44
|
end_date = db.Column(db.DateTime)
|
|
45
|
+
done_date = db.Column(db.DateTime)
|
|
45
46
|
last_comment_date = db.Column(db.DateTime)
|
|
46
47
|
nb_assets_ready = db.Column(db.Integer, default=0)
|
|
47
48
|
data = db.Column(JSONB)
|
|
@@ -194,6 +194,7 @@ def get_assets_and_tasks(criterions={}, page=1, with_episode_ids=False):
|
|
|
194
194
|
Task.end_date,
|
|
195
195
|
Task.start_date,
|
|
196
196
|
Task.due_date,
|
|
197
|
+
Task.done_date,
|
|
197
198
|
Task.last_comment_date,
|
|
198
199
|
assignees_table.columns.person,
|
|
199
200
|
).order_by(EntityType.name, Entity.name)
|
|
@@ -272,6 +273,7 @@ def get_assets_and_tasks(criterions={}, page=1, with_episode_ids=False):
|
|
|
272
273
|
task_end_date,
|
|
273
274
|
task_start_date,
|
|
274
275
|
task_due_date,
|
|
276
|
+
task_done_date,
|
|
275
277
|
task_last_comment_date,
|
|
276
278
|
person_id,
|
|
277
279
|
) in query_result:
|
|
@@ -314,6 +316,7 @@ def get_assets_and_tasks(criterions={}, page=1, with_episode_ids=False):
|
|
|
314
316
|
task_dict = {
|
|
315
317
|
"id": task_id,
|
|
316
318
|
"due_date": fields.serialize_value(task_due_date),
|
|
319
|
+
"done_date": fields.serialize_value(task_done_date),
|
|
317
320
|
"duration": task_duration,
|
|
318
321
|
"entity_id": asset_id,
|
|
319
322
|
"estimation": task_estimation,
|
|
@@ -240,6 +240,7 @@ def get_entities_and_tasks(criterions={}):
|
|
|
240
240
|
Task.end_date,
|
|
241
241
|
Task.start_date,
|
|
242
242
|
Task.due_date,
|
|
243
|
+
Task.done_date,
|
|
243
244
|
Task.last_comment_date,
|
|
244
245
|
assignees_table.columns.person,
|
|
245
246
|
)
|
|
@@ -269,6 +270,7 @@ def get_entities_and_tasks(criterions={}):
|
|
|
269
270
|
task_end_date,
|
|
270
271
|
task_start_date,
|
|
271
272
|
task_due_date,
|
|
273
|
+
task_done_date,
|
|
272
274
|
task_last_comment_date,
|
|
273
275
|
person_id,
|
|
274
276
|
) in query.all():
|
|
@@ -305,6 +307,7 @@ def get_entities_and_tasks(criterions={}):
|
|
|
305
307
|
"entity_id": entity_id,
|
|
306
308
|
"end_date": task_end_date,
|
|
307
309
|
"due_date": task_due_date,
|
|
310
|
+
"done_date": task_done_date,
|
|
308
311
|
"duration": task_duration,
|
|
309
312
|
"is_subscribed": subscription_map.get(task_id, False),
|
|
310
313
|
"last_comment_date": task_last_comment_date,
|
|
@@ -251,6 +251,7 @@ def get_shots_and_tasks(criterions={}):
|
|
|
251
251
|
Task.end_date,
|
|
252
252
|
Task.start_date,
|
|
253
253
|
Task.due_date,
|
|
254
|
+
Task.done_date,
|
|
254
255
|
Task.last_comment_date,
|
|
255
256
|
Task.nb_assets_ready,
|
|
256
257
|
assignees_table.columns.person,
|
|
@@ -300,6 +301,7 @@ def get_shots_and_tasks(criterions={}):
|
|
|
300
301
|
task_end_date,
|
|
301
302
|
task_start_date,
|
|
302
303
|
task_due_date,
|
|
304
|
+
task_done_date,
|
|
303
305
|
task_last_comment_date,
|
|
304
306
|
task_nb_assets_ready,
|
|
305
307
|
person_id,
|
|
@@ -355,6 +357,7 @@ def get_shots_and_tasks(criterions={}):
|
|
|
355
357
|
"duration": task_duration,
|
|
356
358
|
"due_date": task_due_date,
|
|
357
359
|
"end_date": task_end_date,
|
|
360
|
+
"done_date": task_done_date,
|
|
358
361
|
"entity_id": shot_id,
|
|
359
362
|
"estimation": task_estimation,
|
|
360
363
|
"is_subscribed": subscription_map.get(task_id, False),
|
|
@@ -1113,24 +1116,31 @@ def get_base_entity_type_name(entity_dict):
|
|
|
1113
1116
|
return type_name
|
|
1114
1117
|
|
|
1115
1118
|
|
|
1116
|
-
def get_weighted_quotas(
|
|
1119
|
+
def get_weighted_quotas(
|
|
1120
|
+
project_id, task_type_id, studio_id=None, feedback=True
|
|
1121
|
+
):
|
|
1117
1122
|
"""
|
|
1118
1123
|
Build quota statistics. It counts the number of frames done for each day.
|
|
1119
|
-
A shot is considered done at the first feedback request
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1124
|
+
A shot is considered done at the first feedback request or at last
|
|
1125
|
+
approval.
|
|
1126
|
+
|
|
1127
|
+
If time spent is filled for it, it weights the result with the frame
|
|
1128
|
+
number with the time spents. If there is no time spent, it considers that
|
|
1129
|
+
the work was done from the wip date to the feedback date (or approval date).
|
|
1123
1130
|
It computes the shot count and the number of seconds too.
|
|
1131
|
+
|
|
1132
|
+
If the `feedback` flag is set to True, it uses the feedback date
|
|
1133
|
+
(real_end_date), if feedback is set to False, it uses the approval date
|
|
1134
|
+
(done_date).
|
|
1124
1135
|
"""
|
|
1125
1136
|
fps = projects_service.get_project_fps(project_id)
|
|
1126
1137
|
timezone = user_service.get_timezone()
|
|
1127
1138
|
shot_type = get_shot_type()
|
|
1128
1139
|
quotas = {}
|
|
1129
1140
|
query = (
|
|
1130
|
-
Task.query.filter(
|
|
1131
|
-
.filter(
|
|
1141
|
+
Task.query.filter(Entity.entity_type_id == shot_type["id"])
|
|
1142
|
+
.filter(Task.project_id == project_id)
|
|
1132
1143
|
.filter(Task.task_type_id == task_type_id)
|
|
1133
|
-
.filter(Task.end_date != None)
|
|
1134
1144
|
.join(Entity, Entity.id == Task.entity_id)
|
|
1135
1145
|
.join(Project, Project.id == Task.project_id)
|
|
1136
1146
|
.join(TimeSpent, Task.id == TimeSpent.task_id)
|
|
@@ -1142,6 +1152,11 @@ def get_weighted_quotas(project_id, task_type_id, studio_id=None):
|
|
|
1142
1152
|
)
|
|
1143
1153
|
)
|
|
1144
1154
|
|
|
1155
|
+
if feedback:
|
|
1156
|
+
query = query.filter(Task.end_date != None)
|
|
1157
|
+
else:
|
|
1158
|
+
query = query.filter(Task.done_date != None)
|
|
1159
|
+
|
|
1145
1160
|
if studio_id is not None:
|
|
1146
1161
|
persons_from_studio = Person.query.filter(
|
|
1147
1162
|
Person.studio_id == studio_id
|
|
@@ -1162,7 +1177,6 @@ def get_weighted_quotas(project_id, task_type_id, studio_id=None):
|
|
|
1162
1177
|
.filter(Entity.entity_type_id == shot_type["id"])
|
|
1163
1178
|
.filter(Task.task_type_id == task_type_id)
|
|
1164
1179
|
.filter(Task.real_start_date != None)
|
|
1165
|
-
.filter(Task.end_date != None)
|
|
1166
1180
|
.filter(TimeSpent.id == None)
|
|
1167
1181
|
.join(Entity, Entity.id == Task.entity_id)
|
|
1168
1182
|
.join(Project, Project.id == Task.project_id)
|
|
@@ -1171,6 +1185,11 @@ def get_weighted_quotas(project_id, task_type_id, studio_id=None):
|
|
|
1171
1185
|
.add_columns(Entity.nb_frames, Person.id)
|
|
1172
1186
|
)
|
|
1173
1187
|
|
|
1188
|
+
if feedback:
|
|
1189
|
+
query = query.filter(Task.end_date != None)
|
|
1190
|
+
else:
|
|
1191
|
+
query = query.filter(Task.done_date != None)
|
|
1192
|
+
|
|
1174
1193
|
if studio_id is not None:
|
|
1175
1194
|
query = query.filter(
|
|
1176
1195
|
or_(*[Task.assignees.contains(p) for p in persons_from_studio])
|
|
@@ -1178,16 +1197,19 @@ def get_weighted_quotas(project_id, task_type_id, studio_id=None):
|
|
|
1178
1197
|
result = query.all()
|
|
1179
1198
|
|
|
1180
1199
|
for task, nb_frames, person_id in result:
|
|
1200
|
+
date = task.done_date
|
|
1201
|
+
if feedback:
|
|
1202
|
+
date = task.end_date
|
|
1203
|
+
|
|
1181
1204
|
business_days = (
|
|
1182
|
-
date_helpers.get_business_days(task.real_start_date,
|
|
1183
|
-
+ 1
|
|
1205
|
+
date_helpers.get_business_days(task.real_start_date, date) + 1
|
|
1184
1206
|
)
|
|
1185
1207
|
if nb_frames is not None:
|
|
1186
1208
|
nb_frames = round(nb_frames / business_days) or 0
|
|
1187
1209
|
else:
|
|
1188
1210
|
nb_frames = 0
|
|
1189
|
-
|
|
1190
|
-
for x in range((
|
|
1211
|
+
|
|
1212
|
+
for x in range((date - task.real_start_date).days + 1):
|
|
1191
1213
|
if date.weekday() < 5:
|
|
1192
1214
|
_add_quota_entry(
|
|
1193
1215
|
quotas, str(person_id), date, timezone, nb_frames, fps
|
|
@@ -1196,11 +1218,13 @@ def get_weighted_quotas(project_id, task_type_id, studio_id=None):
|
|
|
1196
1218
|
return quotas
|
|
1197
1219
|
|
|
1198
1220
|
|
|
1199
|
-
def get_raw_quotas(project_id, task_type_id, studio_id=None):
|
|
1221
|
+
def get_raw_quotas(project_id, task_type_id, studio_id=None, feedback=True):
|
|
1200
1222
|
"""
|
|
1201
1223
|
Build quota statistics in a raw way. It counts the number of frames done
|
|
1202
1224
|
for each day. A shot is considered done at the first feedback request (end
|
|
1203
|
-
date)
|
|
1225
|
+
date) or approval date (done_date).
|
|
1226
|
+
|
|
1227
|
+
It considers that all the work was done at the end date.
|
|
1204
1228
|
It computes the shot count and the number of seconds too.
|
|
1205
1229
|
"""
|
|
1206
1230
|
fps = projects_service.get_project_fps(project_id)
|
|
@@ -1211,13 +1235,17 @@ def get_raw_quotas(project_id, task_type_id, studio_id=None):
|
|
|
1211
1235
|
Task.query.filter(Task.project_id == project_id)
|
|
1212
1236
|
.filter(Entity.entity_type_id == shot_type["id"])
|
|
1213
1237
|
.filter(Task.task_type_id == task_type_id)
|
|
1214
|
-
.filter(Task.end_date != None)
|
|
1215
1238
|
.join(Entity, Entity.id == Task.entity_id)
|
|
1216
1239
|
.join(Project, Project.id == Task.project_id)
|
|
1217
1240
|
.join(Task.assignees)
|
|
1218
1241
|
.add_columns(Entity.nb_frames, Person.id)
|
|
1219
1242
|
)
|
|
1220
1243
|
|
|
1244
|
+
if feedback:
|
|
1245
|
+
query = query.filter(Task.end_date != None)
|
|
1246
|
+
else:
|
|
1247
|
+
query = query.filter(Task.done_date != None)
|
|
1248
|
+
|
|
1221
1249
|
if studio_id is not None:
|
|
1222
1250
|
persons_from_studio = Person.query.filter(
|
|
1223
1251
|
Person.studio_id == studio_id
|
|
@@ -1229,7 +1257,10 @@ def get_raw_quotas(project_id, task_type_id, studio_id=None):
|
|
|
1229
1257
|
result = query.all()
|
|
1230
1258
|
|
|
1231
1259
|
for task, nb_frames, person_id in result:
|
|
1232
|
-
date = task.
|
|
1260
|
+
date = task.done_date
|
|
1261
|
+
if feedback:
|
|
1262
|
+
date = task.end_date
|
|
1263
|
+
|
|
1233
1264
|
if nb_frames is None:
|
|
1234
1265
|
nb_frames = 0
|
|
1235
1266
|
_add_quota_entry(
|
|
@@ -1303,7 +1334,13 @@ def _init_quota_person(quotas, person_id):
|
|
|
1303
1334
|
|
|
1304
1335
|
|
|
1305
1336
|
def get_month_quota_shots(
|
|
1306
|
-
person_id,
|
|
1337
|
+
person_id,
|
|
1338
|
+
year,
|
|
1339
|
+
month,
|
|
1340
|
+
project_id=None,
|
|
1341
|
+
task_type_id=None,
|
|
1342
|
+
weighted=True,
|
|
1343
|
+
feedback=True,
|
|
1307
1344
|
):
|
|
1308
1345
|
"""
|
|
1309
1346
|
Return shots that are included in quota comptutation for given
|
|
@@ -1318,6 +1355,7 @@ def get_month_quota_shots(
|
|
|
1318
1355
|
end,
|
|
1319
1356
|
project_id=project_id,
|
|
1320
1357
|
task_type_id=task_type_id,
|
|
1358
|
+
feedback=feedback,
|
|
1321
1359
|
)
|
|
1322
1360
|
else:
|
|
1323
1361
|
return get_raw_quota_shots_between(
|
|
@@ -1326,11 +1364,18 @@ def get_month_quota_shots(
|
|
|
1326
1364
|
end,
|
|
1327
1365
|
project_id=project_id,
|
|
1328
1366
|
task_type_id=task_type_id,
|
|
1367
|
+
feedback=feedback,
|
|
1329
1368
|
)
|
|
1330
1369
|
|
|
1331
1370
|
|
|
1332
1371
|
def get_week_quota_shots(
|
|
1333
|
-
person_id,
|
|
1372
|
+
person_id,
|
|
1373
|
+
year,
|
|
1374
|
+
week,
|
|
1375
|
+
project_id=None,
|
|
1376
|
+
task_type_id=None,
|
|
1377
|
+
weighted=True,
|
|
1378
|
+
feedback=True,
|
|
1334
1379
|
):
|
|
1335
1380
|
"""
|
|
1336
1381
|
Return shots that are included in quota comptutation for given
|
|
@@ -1345,6 +1390,7 @@ def get_week_quota_shots(
|
|
|
1345
1390
|
end,
|
|
1346
1391
|
project_id=project_id,
|
|
1347
1392
|
task_type_id=task_type_id,
|
|
1393
|
+
feedback=feedback,
|
|
1348
1394
|
)
|
|
1349
1395
|
else:
|
|
1350
1396
|
return get_raw_quota_shots_between(
|
|
@@ -1353,6 +1399,7 @@ def get_week_quota_shots(
|
|
|
1353
1399
|
end,
|
|
1354
1400
|
project_id=project_id,
|
|
1355
1401
|
task_type_id=task_type_id,
|
|
1402
|
+
feedback=feedback,
|
|
1356
1403
|
)
|
|
1357
1404
|
|
|
1358
1405
|
|
|
@@ -1364,13 +1411,14 @@ def get_day_quota_shots(
|
|
|
1364
1411
|
project_id=None,
|
|
1365
1412
|
task_type_id=None,
|
|
1366
1413
|
weighted=True,
|
|
1414
|
+
feedback=True,
|
|
1367
1415
|
):
|
|
1368
1416
|
"""
|
|
1369
1417
|
Return shots that are included in quota comptutation for given
|
|
1370
1418
|
person and day.
|
|
1371
1419
|
"""
|
|
1372
1420
|
start, end = date_helpers.get_day_interval(year, month, day)
|
|
1373
|
-
start, end = _get_timezoned_interval(start, end)
|
|
1421
|
+
# start, end = _get_timezoned_interval(start, end)
|
|
1374
1422
|
if weighted:
|
|
1375
1423
|
return get_weighted_quota_shots_between(
|
|
1376
1424
|
person_id,
|
|
@@ -1378,6 +1426,7 @@ def get_day_quota_shots(
|
|
|
1378
1426
|
end,
|
|
1379
1427
|
project_id=project_id,
|
|
1380
1428
|
task_type_id=task_type_id,
|
|
1429
|
+
feedback=feedback,
|
|
1381
1430
|
)
|
|
1382
1431
|
else:
|
|
1383
1432
|
return get_raw_quota_shots_between(
|
|
@@ -1386,11 +1435,12 @@ def get_day_quota_shots(
|
|
|
1386
1435
|
end,
|
|
1387
1436
|
project_id=project_id,
|
|
1388
1437
|
task_type_id=task_type_id,
|
|
1438
|
+
feedback=feedback,
|
|
1389
1439
|
)
|
|
1390
1440
|
|
|
1391
1441
|
|
|
1392
1442
|
def get_weighted_quota_shots_between(
|
|
1393
|
-
person_id, start, end, project_id=None, task_type_id=None
|
|
1443
|
+
person_id, start, end, project_id=None, task_type_id=None, feedback=True
|
|
1394
1444
|
):
|
|
1395
1445
|
"""
|
|
1396
1446
|
Get all shots leading to a quota computation during the given period.
|
|
@@ -1410,7 +1460,6 @@ def get_weighted_quota_shots_between(
|
|
|
1410
1460
|
Entity.query.filter(Entity.entity_type_id == shot_type["id"])
|
|
1411
1461
|
.filter(Task.project_id == project_id)
|
|
1412
1462
|
.filter(Task.task_type_id == task_type_id)
|
|
1413
|
-
.filter(Task.end_date != None)
|
|
1414
1463
|
.filter(TimeSpent.person_id == person_id)
|
|
1415
1464
|
.filter(TimeSpent.date >= func.cast(start, TimeSpent.date.type))
|
|
1416
1465
|
.filter(TimeSpent.date < func.cast(end, TimeSpent.date.type))
|
|
@@ -1419,6 +1468,12 @@ def get_weighted_quota_shots_between(
|
|
|
1419
1468
|
.join(TimeSpent, Task.id == TimeSpent.task_id)
|
|
1420
1469
|
.add_columns(Task.duration, TimeSpent.duration)
|
|
1421
1470
|
)
|
|
1471
|
+
|
|
1472
|
+
if feedback:
|
|
1473
|
+
query = query.filter(Task.end_date != None)
|
|
1474
|
+
else:
|
|
1475
|
+
query = query.filter(Task.done_date != None)
|
|
1476
|
+
|
|
1422
1477
|
query_shots = query.all()
|
|
1423
1478
|
for entity, task_duration, duration in query_shots:
|
|
1424
1479
|
shot = entity.serialize()
|
|
@@ -1432,22 +1487,36 @@ def get_weighted_quota_shots_between(
|
|
|
1432
1487
|
shot = already_listed[shot["id"]]
|
|
1433
1488
|
shot["weight"] += round(duration / task_duration, 2)
|
|
1434
1489
|
|
|
1435
|
-
start
|
|
1436
|
-
|
|
1490
|
+
print(start, end)
|
|
1491
|
+
if type(start) is str:
|
|
1492
|
+
start = date_helpers.get_datetime_from_string(start)
|
|
1493
|
+
if type(end) is str:
|
|
1494
|
+
end = date_helpers.get_datetime_from_string(end)
|
|
1437
1495
|
query = (
|
|
1438
1496
|
Entity.query.filter(Entity.entity_type_id == shot_type["id"])
|
|
1439
1497
|
.filter(Task.project_id == project_id)
|
|
1440
1498
|
.filter(Task.task_type_id == task_type_id)
|
|
1441
|
-
.filter(Task.end_date != None)
|
|
1442
1499
|
.filter(Task.real_start_date != None)
|
|
1443
1500
|
.filter(Task.assignees.contains(person))
|
|
1444
|
-
.filter((Task.real_start_date <= end) & (Task.end_date >= start))
|
|
1445
1501
|
.filter(TimeSpent.id == None)
|
|
1446
1502
|
.join(Task, Entity.id == Task.entity_id)
|
|
1447
1503
|
.join(Project, Project.id == Task.project_id)
|
|
1448
1504
|
.outerjoin(TimeSpent, TimeSpent.task_id == Task.id)
|
|
1449
|
-
.add_columns(Task.real_start_date, Task.end_date)
|
|
1450
1505
|
)
|
|
1506
|
+
|
|
1507
|
+
if feedback:
|
|
1508
|
+
query = (
|
|
1509
|
+
query.filter(Task.end_date != None)
|
|
1510
|
+
.filter((Task.real_start_date <= end) & (Task.end_date >= start))
|
|
1511
|
+
.add_columns(Task.real_start_date, Task.end_date)
|
|
1512
|
+
)
|
|
1513
|
+
else:
|
|
1514
|
+
query = (
|
|
1515
|
+
query.filter(Task.done_date != None)
|
|
1516
|
+
.filter((Task.real_start_date <= end) & (Task.done_date >= start))
|
|
1517
|
+
.add_columns(Task.real_start_date, Task.done_date)
|
|
1518
|
+
)
|
|
1519
|
+
|
|
1451
1520
|
query_shots = query.all()
|
|
1452
1521
|
|
|
1453
1522
|
for entity, task_start, task_end in query_shots:
|
|
@@ -1477,7 +1546,7 @@ def get_weighted_quota_shots_between(
|
|
|
1477
1546
|
|
|
1478
1547
|
|
|
1479
1548
|
def get_raw_quota_shots_between(
|
|
1480
|
-
person_id, start, end, project_id=None, task_type_id=None
|
|
1549
|
+
person_id, start, end, project_id=None, task_type_id=None, feedback=True
|
|
1481
1550
|
):
|
|
1482
1551
|
"""
|
|
1483
1552
|
Get all shots leading to a quota computation during the given period.
|
|
@@ -1490,16 +1559,26 @@ def get_raw_quota_shots_between(
|
|
|
1490
1559
|
Entity.query.filter(Entity.entity_type_id == shot_type["id"])
|
|
1491
1560
|
.filter(Task.project_id == project_id)
|
|
1492
1561
|
.filter(Task.task_type_id == task_type_id)
|
|
1493
|
-
.filter(
|
|
1562
|
+
.filter(Task.assignees.contains(person))
|
|
1563
|
+
.join(Task, Entity.id == Task.entity_id)
|
|
1564
|
+
.join(Project, Project.id == Task.project_id)
|
|
1565
|
+
)
|
|
1566
|
+
|
|
1567
|
+
if feedback:
|
|
1568
|
+
query = query.filter(
|
|
1494
1569
|
Task.end_date.between(
|
|
1495
1570
|
func.cast(start, Task.end_date.type),
|
|
1496
1571
|
func.cast(end, Task.end_date.type),
|
|
1497
1572
|
)
|
|
1498
1573
|
)
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1574
|
+
else:
|
|
1575
|
+
query = query.filter(
|
|
1576
|
+
Task.done_date.between(
|
|
1577
|
+
func.cast(start, Task.done_date.type),
|
|
1578
|
+
func.cast(end, Task.done_date.type),
|
|
1579
|
+
)
|
|
1580
|
+
)
|
|
1581
|
+
|
|
1503
1582
|
query_shots = query.all()
|
|
1504
1583
|
|
|
1505
1584
|
for entity in query_shots:
|
|
@@ -1297,6 +1297,9 @@ def update_task(task_id, data):
|
|
|
1297
1297
|
if is_finished(task, data):
|
|
1298
1298
|
data["end_date"] = date_helpers.get_utc_now_datetime()
|
|
1299
1299
|
|
|
1300
|
+
if is_done(task, data):
|
|
1301
|
+
data["done_date"] = date_helpers.get_utc_now_datetime()
|
|
1302
|
+
|
|
1300
1303
|
task.update(data)
|
|
1301
1304
|
clear_task_cache(task_id)
|
|
1302
1305
|
events.emit(
|
|
@@ -1490,7 +1493,7 @@ def delete_time_spent(task_id, person_id, date):
|
|
|
1490
1493
|
|
|
1491
1494
|
def is_finished(task, data):
|
|
1492
1495
|
"""
|
|
1493
|
-
Return True if task status is set to
|
|
1496
|
+
Return True if task status is set to feedback request.
|
|
1494
1497
|
"""
|
|
1495
1498
|
if "task_status_id" in data:
|
|
1496
1499
|
task_status = get_task_status_raw(task.task_status_id)
|
|
@@ -1503,6 +1506,18 @@ def is_finished(task, data):
|
|
|
1503
1506
|
return False
|
|
1504
1507
|
|
|
1505
1508
|
|
|
1509
|
+
def is_done(task, data):
|
|
1510
|
+
"""
|
|
1511
|
+
Return True if task status is set to done.
|
|
1512
|
+
"""
|
|
1513
|
+
if "task_status_id" in data:
|
|
1514
|
+
task_status = get_task_status_raw(task.task_status_id)
|
|
1515
|
+
new_task_status = get_task_status_raw(data["task_status_id"])
|
|
1516
|
+
return new_task_status.id != task_status.id and new_task_status.is_done
|
|
1517
|
+
else:
|
|
1518
|
+
return False
|
|
1519
|
+
|
|
1520
|
+
|
|
1506
1521
|
def clear_assignation(task_id, person_id=None):
|
|
1507
1522
|
"""
|
|
1508
1523
|
Clear task assignation and emit a *task:unassign* event.
|
|
@@ -1758,6 +1773,7 @@ def reset_task_data(task_id):
|
|
|
1758
1773
|
real_start_date = None
|
|
1759
1774
|
last_comment_date = None
|
|
1760
1775
|
end_date = None
|
|
1776
|
+
done_date = None
|
|
1761
1777
|
entity = entities_service.get_entity(task.entity_id)
|
|
1762
1778
|
task_status_id = get_default_status(
|
|
1763
1779
|
for_concept=entity["entity_type_id"]
|
|
@@ -1770,6 +1786,7 @@ def reset_task_data(task_id):
|
|
|
1770
1786
|
.add_columns(
|
|
1771
1787
|
TaskStatus.is_retake,
|
|
1772
1788
|
TaskStatus.is_feedback_request,
|
|
1789
|
+
TaskStatus.is_done,
|
|
1773
1790
|
TaskStatus.short_name,
|
|
1774
1791
|
)
|
|
1775
1792
|
.all()
|
|
@@ -1780,6 +1797,7 @@ def reset_task_data(task_id):
|
|
|
1780
1797
|
comment,
|
|
1781
1798
|
task_status_is_retake,
|
|
1782
1799
|
task_status_is_feedback_request,
|
|
1800
|
+
task_status_is_done,
|
|
1783
1801
|
task_status_short_name,
|
|
1784
1802
|
) in comments:
|
|
1785
1803
|
if task_status_is_retake and not previous_is_retake:
|
|
@@ -1792,6 +1810,11 @@ def reset_task_data(task_id):
|
|
|
1792
1810
|
if task_status_is_feedback_request:
|
|
1793
1811
|
end_date = comment.created_at
|
|
1794
1812
|
|
|
1813
|
+
print("ok", task_status_is_done)
|
|
1814
|
+
if task_status_is_done:
|
|
1815
|
+
done_date = comment.created_at
|
|
1816
|
+
print(done_date)
|
|
1817
|
+
|
|
1795
1818
|
task_status_id = comment.task_status_id
|
|
1796
1819
|
last_comment_date = comment.created_at
|
|
1797
1820
|
|
|
@@ -1807,6 +1830,7 @@ def reset_task_data(task_id):
|
|
|
1807
1830
|
"real_start_date": real_start_date,
|
|
1808
1831
|
"last_comment_date": last_comment_date,
|
|
1809
1832
|
"end_date": end_date,
|
|
1833
|
+
"done_date": done_date,
|
|
1810
1834
|
"task_status_id": task_status_id,
|
|
1811
1835
|
}
|
|
1812
1836
|
)
|
|
@@ -2036,6 +2060,7 @@ def get_open_tasks(
|
|
|
2036
2060
|
"duration": task.duration,
|
|
2037
2061
|
"start_date": fields.serialize_value(task.start_date),
|
|
2038
2062
|
"due_date": fields.serialize_value(task.due_date),
|
|
2063
|
+
"done_date": fields.serialize_value(task.done_date),
|
|
2039
2064
|
"type_name": task_type_name,
|
|
2040
2065
|
"task_type_for_entity": task_type_for_entity,
|
|
2041
2066
|
"status_name": task_status_name,
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""add is_done field to the task model
|
|
2
|
+
|
|
3
|
+
Revision ID: ca28796a2a62
|
|
4
|
+
Revises: 971dbf5a0faf
|
|
5
|
+
Create Date: 2024-07-19 15:24:21.064991
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from alembic import op
|
|
10
|
+
import sqlalchemy as sa
|
|
11
|
+
from sqlalchemy import orm
|
|
12
|
+
from sqlalchemy.ext.declarative import declarative_base
|
|
13
|
+
from zou.migrations.utils.base import BaseMixin
|
|
14
|
+
from sqlalchemy_utils import UUIDType, ChoiceType
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# revision identifiers, used by Alembic.
|
|
18
|
+
revision = "ca28796a2a62"
|
|
19
|
+
down_revision = "971dbf5a0faf"
|
|
20
|
+
branch_labels = None
|
|
21
|
+
depends_on = None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def upgrade():
|
|
25
|
+
base = declarative_base()
|
|
26
|
+
|
|
27
|
+
TYPES = [
|
|
28
|
+
("comment", "Comment"),
|
|
29
|
+
("mention", "Mention"),
|
|
30
|
+
("assignation", "Assignation"),
|
|
31
|
+
("reply", "Reply"),
|
|
32
|
+
("reply-mention", "Reply Mention"),
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
class Notification(base, BaseMixin):
|
|
36
|
+
"""
|
|
37
|
+
A notification is stored each time a comment is posted.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
__tablename__ = "notification"
|
|
41
|
+
read = sa.Column(sa.Boolean, nullable=False, default=False)
|
|
42
|
+
change = sa.Column(sa.Boolean, nullable=False, default=False)
|
|
43
|
+
type = sa.Column(ChoiceType(TYPES), nullable=False)
|
|
44
|
+
person_id = sa.Column(
|
|
45
|
+
UUIDType(binary=False),
|
|
46
|
+
nullable=False,
|
|
47
|
+
index=True,
|
|
48
|
+
)
|
|
49
|
+
author_id = sa.Column(
|
|
50
|
+
UUIDType(binary=False),
|
|
51
|
+
nullable=False,
|
|
52
|
+
index=True,
|
|
53
|
+
)
|
|
54
|
+
comment_id = sa.Column(
|
|
55
|
+
UUIDType(binary=False),
|
|
56
|
+
nullable=True,
|
|
57
|
+
index=True,
|
|
58
|
+
)
|
|
59
|
+
task_id = sa.Column(
|
|
60
|
+
UUIDType(binary=False),
|
|
61
|
+
nullable=False,
|
|
62
|
+
index=True,
|
|
63
|
+
)
|
|
64
|
+
reply_id = sa.Column(UUIDType(binary=False), nullable=True, index=True)
|
|
65
|
+
|
|
66
|
+
__table_args__ = (
|
|
67
|
+
sa.UniqueConstraint(
|
|
68
|
+
"person_id",
|
|
69
|
+
"author_id",
|
|
70
|
+
"comment_id",
|
|
71
|
+
"reply_id",
|
|
72
|
+
"type",
|
|
73
|
+
name="notification_uc",
|
|
74
|
+
),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
bind = op.get_bind()
|
|
78
|
+
session = orm.Session(bind=bind)
|
|
79
|
+
session.query(Notification).where(Notification.type == None).update(
|
|
80
|
+
{Notification.type: "comment"}
|
|
81
|
+
)
|
|
82
|
+
session.commit()
|
|
83
|
+
|
|
84
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
85
|
+
with op.batch_alter_table("notification", schema=None) as batch_op:
|
|
86
|
+
batch_op.alter_column(
|
|
87
|
+
"type", existing_type=sa.VARCHAR(length=255), nullable=False
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
with op.batch_alter_table("task", schema=None) as batch_op:
|
|
91
|
+
batch_op.add_column(
|
|
92
|
+
sa.Column("done_date", sa.DateTime(), nullable=True)
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# ### end Alembic commands ###
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def downgrade():
|
|
99
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
100
|
+
with op.batch_alter_table("task", schema=None) as batch_op:
|
|
101
|
+
batch_op.drop_column("done_date")
|
|
102
|
+
|
|
103
|
+
with op.batch_alter_table("notification", schema=None) as batch_op:
|
|
104
|
+
batch_op.alter_column(
|
|
105
|
+
"type", existing_type=sa.VARCHAR(length=255), nullable=True
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# ### end Alembic commands ###
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: zou
|
|
3
|
-
Version: 0.19.
|
|
3
|
+
Version: 0.19.50
|
|
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
|
|
@@ -40,7 +40,7 @@ Requires-Dist: flask-jwt-extended ==4.6.0
|
|
|
40
40
|
Requires-Dist: flask-migrate ==4.0.7
|
|
41
41
|
Requires-Dist: flask-socketio ==5.3.6
|
|
42
42
|
Requires-Dist: flask ==3.0.3
|
|
43
|
-
Requires-Dist: gazu ==0.10.
|
|
43
|
+
Requires-Dist: gazu ==0.10.13
|
|
44
44
|
Requires-Dist: gevent-websocket ==0.10.1
|
|
45
45
|
Requires-Dist: gevent ==24.2.1
|
|
46
46
|
Requires-Dist: gunicorn ==22.0.0
|
|
@@ -77,11 +77,11 @@ Requires-Dist: wheel ; extra == 'dev'
|
|
|
77
77
|
Provides-Extra: lint
|
|
78
78
|
Requires-Dist: autoflake ==2.3.1 ; extra == 'lint'
|
|
79
79
|
Requires-Dist: black ==24.4.2 ; extra == 'lint'
|
|
80
|
-
Requires-Dist: pre-commit ==3.
|
|
80
|
+
Requires-Dist: pre-commit ==3.8.0 ; (python_version >= "3.9") and extra == 'lint'
|
|
81
81
|
Provides-Extra: monitoring
|
|
82
82
|
Requires-Dist: prometheus-flask-exporter ==0.23.1 ; extra == 'monitoring'
|
|
83
83
|
Requires-Dist: pygelf ==0.4.2 ; extra == 'monitoring'
|
|
84
|
-
Requires-Dist: sentry-sdk ==2.
|
|
84
|
+
Requires-Dist: sentry-sdk ==2.11.0 ; extra == 'monitoring'
|
|
85
85
|
Provides-Extra: prod
|
|
86
86
|
Requires-Dist: gunicorn ; extra == 'prod'
|
|
87
87
|
Requires-Dist: gevent ; extra == 'prod'
|
|
@@ -89,7 +89,7 @@ Provides-Extra: test
|
|
|
89
89
|
Requires-Dist: fakeredis ==2.23.3 ; extra == 'test'
|
|
90
90
|
Requires-Dist: mixer ==7.2.2 ; extra == 'test'
|
|
91
91
|
Requires-Dist: pytest-cov ==5.0.0 ; extra == 'test'
|
|
92
|
-
Requires-Dist: pytest ==8.3.
|
|
92
|
+
Requires-Dist: pytest ==8.3.2 ; extra == 'test'
|
|
93
93
|
|
|
94
94
|
.. figure:: https://zou.cg-wire.com/kitsu.png
|
|
95
95
|
:alt: Kitsu Logo
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
zou/__init__.py,sha256=
|
|
1
|
+
zou/__init__.py,sha256=_Gy_AT8DQ-udpLfSZgx_ouKt88H4OjNcTtS35Oi8b7I,24
|
|
2
2
|
zou/cli.py,sha256=2cDkbEOqp_m9hzBQf5wpxc_h0WjoH8KtxQQMNuREYlc,18201
|
|
3
3
|
zou/debug.py,sha256=1fawPbkD4wn0Y9Gk0BiBFSa-CQe5agFi8R9uJYl2Uyk,520
|
|
4
4
|
zou/event_stream.py,sha256=zgob2dZKray2lxPa11hdRNmOg8XRlKDdRcGdF80ylwg,8245
|
|
@@ -6,7 +6,7 @@ zou/job_settings.py,sha256=WB_RkYxmh4ffQHqg63_wsUDiS0zP3yxiwrxK7DhHG0g,150
|
|
|
6
6
|
zou/app/__init__.py,sha256=aWh9K5n63TpXdLDxpfFtNNoCYZVE6OV3YLCXLuygWQg,6700
|
|
7
7
|
zou/app/api.py,sha256=JTB_IMVO8EOoyqx9KdRkiIix0chOLi0yGDY-verUJXA,5127
|
|
8
8
|
zou/app/config.py,sha256=J0jmGmyvk8JqcMPAEW8KfvwP8GwEoC9BxQG8AQV9aiY,6393
|
|
9
|
-
zou/app/mixin.py,sha256=
|
|
9
|
+
zou/app/mixin.py,sha256=eYwfS_CUFvNmldaQXrjsN5mK_gX0wYrBFykfx60uUM8,4897
|
|
10
10
|
zou/app/swagger.py,sha256=UW9DSik3a8GuH1_-7F5P7EYgjZ9DA_kFjukO-6n4kgk,54682
|
|
11
11
|
zou/app/blueprints/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
12
|
zou/app/blueprints/assets/__init__.py,sha256=tSRvVrnPj732F4k_lkxoTJBJNmIUAqKXPLJDHvOtAA4,2178
|
|
@@ -87,7 +87,7 @@ zou/app/blueprints/index/resources.py,sha256=DsYpNSO_wCAxyjWOaB9QmEqOBcjn1miLiGn
|
|
|
87
87
|
zou/app/blueprints/news/__init__.py,sha256=HxBXjC15dVbotNAZ0CLf02iwUjxJr20kgf8_kT_9nwM,505
|
|
88
88
|
zou/app/blueprints/news/resources.py,sha256=6e3Ex_Q-djxWDjQQ-eD1fBcylea6XaJphO7Tl9zWKcY,7057
|
|
89
89
|
zou/app/blueprints/persons/__init__.py,sha256=0cnHHw3K_8OEMm0qOi3wKVomSAg9IJSnVjAXabMeHks,3893
|
|
90
|
-
zou/app/blueprints/persons/resources.py,sha256
|
|
90
|
+
zou/app/blueprints/persons/resources.py,sha256=wYM5xcjP7Q0-ETZTom4yjvOnTO9kYzfjYP8wEa6X030,42674
|
|
91
91
|
zou/app/blueprints/playlists/__init__.py,sha256=vuEk1F3hFHsmuKWhdepMoLyOzmNKDn1YrjjfcaIz0lQ,1596
|
|
92
92
|
zou/app/blueprints/playlists/resources.py,sha256=alRlMHypUFErXLsEYxpFK84cdjFJ3YWwamZtW0KcwLY,17211
|
|
93
93
|
zou/app/blueprints/previews/__init__.py,sha256=qGohO6LRNZKXBAegINcUXuZlrtxobJKQg84-rQ1L3AU,4202
|
|
@@ -97,7 +97,7 @@ zou/app/blueprints/projects/resources.py,sha256=v9_TLh3mujL-p7QcGkfSOJnNojzoJA15
|
|
|
97
97
|
zou/app/blueprints/search/__init__.py,sha256=QCjQIY_85l_orhdEiqav_GifjReuwsjZggN3V0GeUVY,356
|
|
98
98
|
zou/app/blueprints/search/resources.py,sha256=ni-dX8Xfib_0FonLttoXgntXBR957-xhifPSQHHnOnY,2696
|
|
99
99
|
zou/app/blueprints/shots/__init__.py,sha256=HfgLneZBYUMa2OGwIgEZTz8zrIEYFRiYmRbreBPYeYw,4076
|
|
100
|
-
zou/app/blueprints/shots/resources.py,sha256=
|
|
100
|
+
zou/app/blueprints/shots/resources.py,sha256=H9-TbHod5e7w6fO-1-C81Npk2reJkfiqTjRe7KgjaLI,48669
|
|
101
101
|
zou/app/blueprints/source/__init__.py,sha256=H7K-4TDs4pc5EJvcYTYMJBHesxyqsE5-xq7J8ckOS2g,6093
|
|
102
102
|
zou/app/blueprints/source/kitsu.py,sha256=4lWdqxaKDzwx-5POAIHIgZ6ODbDMOOVRxaSb_FOLcCk,5012
|
|
103
103
|
zou/app/blueprints/source/otio.py,sha256=WkzpKylVkNlbY_jwf6uV5-HPylrktQznOcbCs_p8TDQ,13391
|
|
@@ -173,13 +173,13 @@ zou/app/models/software.py,sha256=3y9xEOS8BBxqgTaRrCaSYHaB6uOdJ88uU5i-cACoCSk,51
|
|
|
173
173
|
zou/app/models/status_automation.py,sha256=95c0lmOetujyGWViLd_qsR4GWPhrmlvi9ZfkC0x1NuM,1391
|
|
174
174
|
zou/app/models/studio.py,sha256=cXnYFh-8m5Kw05QawYcCr59eeLp25NDI0VIb77oqUOs,384
|
|
175
175
|
zou/app/models/subscription.py,sha256=0GDQTHUThnydD4VwZg6YW2daC31zsu16j3ik4Im8d6g,1026
|
|
176
|
-
zou/app/models/task.py,sha256=
|
|
176
|
+
zou/app/models/task.py,sha256=DiDCXdAOuKwR6LO8_ECZHunuZ5a19GVqRC5SA-8cdcs,3437
|
|
177
177
|
zou/app/models/task_status.py,sha256=J7mNWIFd9KMWfUOLHjmuxIupjs59iSh8aQ_9LEFXqH4,1227
|
|
178
178
|
zou/app/models/task_type.py,sha256=IsixVAfz3pyMf0eQw8x-uFNM9OHNkZpsPLEz_VNQ0hA,1005
|
|
179
179
|
zou/app/models/time_spent.py,sha256=n7i3FO9g1eE_zATkItoCgrGVqq3iMSfdlKSveEZPloc,795
|
|
180
180
|
zou/app/models/working_file.py,sha256=q0LM3s1ziw_9AmmPDCkwyf1-TJkWTBMgo2LdHyVRwxg,1509
|
|
181
181
|
zou/app/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
182
|
-
zou/app/services/assets_service.py,sha256=
|
|
182
|
+
zou/app/services/assets_service.py,sha256=BvAi5mnvZvMJJXnxFF3bofu4JZjiPvdlPrgUyW8PuKY,21460
|
|
183
183
|
zou/app/services/auth_service.py,sha256=AxKN_THkjN2tmOHTSyFspwwFHqGBnslXuidfbav8Rxk,23224
|
|
184
184
|
zou/app/services/backup_service.py,sha256=_ZtZp6wkcVYnHxBosziwLGdrTvsUttXGphiydq53iy8,4840
|
|
185
185
|
zou/app/services/base_service.py,sha256=OZd0STFh-DyBBdwsmA7DMMnrwv4C8wJUbShvZ1isndU,1383
|
|
@@ -191,7 +191,7 @@ zou/app/services/custom_actions_service.py,sha256=fWISEOOdthadrxeHuacEel5Xj6msn0
|
|
|
191
191
|
zou/app/services/deletion_service.py,sha256=ddaup7i_CTugcJDrynczNcfhjSKgDeGhPQjQ68We_l8,17255
|
|
192
192
|
zou/app/services/edits_service.py,sha256=KTk5KUJx1yB-mRka8rQXMgQLIcWq4mNYZfnVhVlKwyQ,12122
|
|
193
193
|
zou/app/services/emails_service.py,sha256=ZSwfL3iO9mIyHttqH61vI4WA-DTVdBk7lo6t9zbvfDA,11922
|
|
194
|
-
zou/app/services/entities_service.py,sha256=
|
|
194
|
+
zou/app/services/entities_service.py,sha256=j_dyMHUVISqXFkxm2ydqvAo0nbcEE7_5v9jFauZhSe4,16327
|
|
195
195
|
zou/app/services/events_service.py,sha256=_gU19herxiAo47WRxVNhvl7v-RKhp-8wZ3gAiHKpOzI,2716
|
|
196
196
|
zou/app/services/exception.py,sha256=OBhVlLel081vNUUVywJkY4_8lJE8pFbWa-mrSKrtZuc,4288
|
|
197
197
|
zou/app/services/file_tree_service.py,sha256=8JNBDgnXtV-AmSJ3gnUGB4oSwLjPgi1WYyL0Kc98JRE,33875
|
|
@@ -206,11 +206,11 @@ zou/app/services/preview_files_service.py,sha256=SIZ_SB1bWNRE_Zm7SuEpvFWqVpHKOgf
|
|
|
206
206
|
zou/app/services/projects_service.py,sha256=_J8hIHy3MX5MsdEMRIKNfbyewwhxtMEcc_ymeHBsF38,21434
|
|
207
207
|
zou/app/services/scenes_service.py,sha256=iXN19HU4njPF5VtZXuUrVJ-W23ZQuQNPC3ADXltbWtU,992
|
|
208
208
|
zou/app/services/schedule_service.py,sha256=E99HKYsXgnK2sw58fw-NNHXWBgVJiA60upztjkNSCaM,6989
|
|
209
|
-
zou/app/services/shots_service.py,sha256=
|
|
209
|
+
zou/app/services/shots_service.py,sha256=Y1oTewc2TNxwPzU5CZFfEhjJznjR54a9GTirFZxBhv4,52078
|
|
210
210
|
zou/app/services/stats_service.py,sha256=cAlc92i9d6eYtsuwe3hYHYwdytg8KEMi1-TADfysJwM,11733
|
|
211
211
|
zou/app/services/status_automations_service.py,sha256=tVio7Sj7inhvKS4UOyRhcdpwr_KNP96hT1o0X7XcGF4,715
|
|
212
212
|
zou/app/services/sync_service.py,sha256=EunfXlma_IIb7011A_xLQLVQGAi-MteKgm2Y2NAxvMs,41586
|
|
213
|
-
zou/app/services/tasks_service.py,sha256=
|
|
213
|
+
zou/app/services/tasks_service.py,sha256=Y7VlDJon41m3wjMSOqvoxo0y7UDxlI7NuFPprRMySU0,68602
|
|
214
214
|
zou/app/services/telemetry_services.py,sha256=xQm1h1t_JxSFW59zQGf4NuNdUi1UfMa_6pQ-ytRbmGA,1029
|
|
215
215
|
zou/app/services/time_spents_service.py,sha256=TBLC1O9Dg_UbciG5Nw-dejqX2-5n6q44lACeN6OnUkQ,15206
|
|
216
216
|
zou/app/services/user_service.py,sha256=BiOhPV7O-vowet7jOksjXk2V4yxZkdqsIyNboJ-Oz_A,46595
|
|
@@ -374,6 +374,7 @@ zou/migrations/versions/c49e41f1298b_add_previewbackground.py,sha256=7TOXMsEK9YW
|
|
|
374
374
|
zou/migrations/versions/c68c2a62cfac_add_mimetype_column_to_attachment.py,sha256=cEFnRMYHurag8D9-7ycE34gnVH5TdsDfRYQqs5v_g8M,727
|
|
375
375
|
zou/migrations/versions/c726b98be194_.py,sha256=nbqWFmPg4OUCL-txrVjWyQiFm_PuuaDZeE2gOB-DM3w,701
|
|
376
376
|
zou/migrations/versions/c81f3e83bdb5_.py,sha256=eGoGIOImywjBRSqe-isbt_N_o3zK1ktrPWSo0nyAXgA,720
|
|
377
|
+
zou/migrations/versions/ca28796a2a62_add_is_done_field_to_the_task_model.py,sha256=adalMYr3AvOEpPR5V1nj6QxsVJUz-44VYaGnHM_tQyA,3046
|
|
377
378
|
zou/migrations/versions/cf3d365de164_add_entity_version_model.py,sha256=n3k3ojRQAk0tJAOBIUgDEoZbNFERx4vs3hg5hrFm7v4,1763
|
|
378
379
|
zou/migrations/versions/cf6cec6d6bf5_add_status_field_to_preview_file.py,sha256=0c8_OghAaaM0R6bKbs7MADvOkZ1sFE3SVp_nNB2ACgQ,950
|
|
379
380
|
zou/migrations/versions/d80267806131_task_status_new_column_is_default.py,sha256=7HtK0bfBUh9MrJIbpUgz6S-Ye_R_4DbHILpODMBVVwE,2610
|
|
@@ -407,9 +408,9 @@ zou/remote/normalize_movie.py,sha256=zNfEY3N1UbAHZfddGONTg2Sff3ieLVWd4dfZa1dpnes
|
|
|
407
408
|
zou/remote/playlist.py,sha256=AsDo0bgYhDcd6DfNRV6r6Jj3URWwavE2ZN3VkKRPbLU,3293
|
|
408
409
|
zou/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
409
410
|
zou/utils/movie.py,sha256=u9LCEOvmkxwm-KiZ6jKNdB9LSC6XXUDwJpVx8LkDwJg,16416
|
|
410
|
-
zou-0.19.
|
|
411
|
-
zou-0.19.
|
|
412
|
-
zou-0.19.
|
|
413
|
-
zou-0.19.
|
|
414
|
-
zou-0.19.
|
|
415
|
-
zou-0.19.
|
|
411
|
+
zou-0.19.50.dist-info/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
|
|
412
|
+
zou-0.19.50.dist-info/METADATA,sha256=QQwGEWHpVwuuwp5RgWo0k6rFY2flwv1AHlRLtDDJ4xo,6725
|
|
413
|
+
zou-0.19.50.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
|
414
|
+
zou-0.19.50.dist-info/entry_points.txt,sha256=PelQoIx3qhQ_Tmne7wrLY-1m2izuzgpwokoURwSohy4,130
|
|
415
|
+
zou-0.19.50.dist-info/top_level.txt,sha256=4S7G_jk4MzpToeDItHGjPhHx_fRdX52zJZWTD4SL54g,4
|
|
416
|
+
zou-0.19.50.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|