zou 0.20.61__py3-none-any.whl → 0.20.62__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 (58) hide show
  1. zou/__init__.py +1 -1
  2. zou/app/api.py +2 -0
  3. zou/app/blueprints/crud/__init__.py +25 -1
  4. zou/app/blueprints/crud/hardware_item.py +12 -0
  5. zou/app/blueprints/crud/notification.py +0 -4
  6. zou/app/blueprints/crud/production_schedule_version.py +114 -0
  7. zou/app/blueprints/departments/__init__.py +35 -0
  8. zou/app/blueprints/departments/resources.py +262 -0
  9. zou/app/blueprints/index/resources.py +2 -9
  10. zou/app/blueprints/persons/resources.py +1 -3
  11. zou/app/blueprints/projects/__init__.py +20 -0
  12. zou/app/blueprints/projects/resources.py +200 -0
  13. zou/app/blueprints/tasks/resources.py +5 -2
  14. zou/app/blueprints/user/resources.py +1 -3
  15. zou/app/models/base.py +15 -4
  16. zou/app/models/department.py +62 -0
  17. zou/app/models/entity.py +3 -3
  18. zou/app/models/hardware_item.py +15 -0
  19. zou/app/models/person.py +1 -1
  20. zou/app/models/production_schedule_version.py +81 -0
  21. zou/app/models/project.py +17 -6
  22. zou/app/models/software.py +5 -1
  23. zou/app/models/task.py +7 -10
  24. zou/app/services/assets_service.py +5 -6
  25. zou/app/services/concepts_service.py +3 -4
  26. zou/app/services/deletion_service.py +10 -18
  27. zou/app/services/departments_service.py +153 -0
  28. zou/app/services/edits_service.py +3 -4
  29. zou/app/services/entities_service.py +5 -6
  30. zou/app/services/exception.py +8 -0
  31. zou/app/services/file_tree_service.py +2 -2
  32. zou/app/services/preview_files_service.py +6 -2
  33. zou/app/services/schedule_service.py +243 -1
  34. zou/app/services/shots_service.py +3 -4
  35. zou/app/services/tasks_service.py +5 -1
  36. zou/app/services/user_service.py +57 -23
  37. zou/migrations/alembic.ini +1 -1
  38. zou/migrations/versions/0bd1e89f2a6f_add_productionscheduleversiontasklink_uc.py +58 -0
  39. zou/migrations/versions/26f96f65cfa3_add_productionversionschedule_uc.py +40 -0
  40. zou/migrations/versions/3d8e68dffeee_fix_task_person_link.py +56 -0
  41. zou/migrations/versions/4368137b44e1_productionscheduleversion_add_on_delete_.py +188 -0
  42. zou/migrations/versions/4bd9bfb73f11_add_fields_to_the_software_table.py +49 -0
  43. zou/migrations/versions/5f715f2b6348_add_new_table_productionscheduleversion.py +128 -0
  44. zou/migrations/versions/7a16258f2fab_add_currency_field_to_budgets.py +2 -4
  45. zou/migrations/versions/9683bd840dee_add_archived_field_to_software.py +33 -0
  46. zou/migrations/versions/9af2df17a9d5_add_hardware_table.py +48 -0
  47. zou/migrations/versions/ce7f46f445dc_add_column_estimation_for_.py +37 -0
  48. zou/migrations/versions/d5665dca188b_add_version_field_to_software.py +35 -0
  49. zou/migrations/versions/d97f2730bf7b_add_.py +101 -0
  50. zou/migrations/versions/dde6be40f54f_add_departement_links_tables_for_.py +151 -0
  51. zou/migrations/versions/e4b48ca33539_add_project_production_schedule_version_.py +56 -0
  52. zou/migrations/versions/e8bc24998b34_remove_on_delete_cascade_for_.py +59 -0
  53. {zou-0.20.61.dist-info → zou-0.20.62.dist-info}/METADATA +1 -1
  54. {zou-0.20.61.dist-info → zou-0.20.62.dist-info}/RECORD +58 -37
  55. {zou-0.20.61.dist-info → zou-0.20.62.dist-info}/WHEEL +0 -0
  56. {zou-0.20.61.dist-info → zou-0.20.62.dist-info}/entry_points.txt +0 -0
  57. {zou-0.20.61.dist-info → zou-0.20.62.dist-info}/licenses/LICENSE +0 -0
  58. {zou-0.20.61.dist-info → zou-0.20.62.dist-info}/top_level.txt +0 -0
@@ -1526,3 +1526,203 @@ class ProductionMonthTimeSpentsResource(Resource, ArgsMixin):
1526
1526
  return time_spents_service.get_project_month_time_spents(
1527
1527
  project_id, user["timezone"]
1528
1528
  )
1529
+
1530
+
1531
+ class ProductionScheduleVersionTaskLinksResource(Resource, ArgsMixin):
1532
+
1533
+ @jwt_required()
1534
+ def get(self, production_schedule_version_id):
1535
+ """
1536
+ Get task links for given production schedule version.
1537
+ ---
1538
+ tags:
1539
+ - Projects
1540
+ parameters:
1541
+ - in: path
1542
+ name: production_schedule_version_id
1543
+ required: True
1544
+ type: string
1545
+ format: UUID
1546
+ x-example: a24a6ea4-ce75-4665-a070-57453082c25
1547
+ - in: query
1548
+ name: task_type_id
1549
+ required: false
1550
+ type: string
1551
+ format: UUID
1552
+ x-example: a24a6ea4-ce75-4665-a070-57453082c25
1553
+ responses:
1554
+ 200:
1555
+ description: Task links for given production schedule version.
1556
+ 400:
1557
+ description: Wrong ID format
1558
+ """
1559
+ production_schedule_version = (
1560
+ schedule_service.get_production_schedule_version(
1561
+ production_schedule_version_id
1562
+ )
1563
+ )
1564
+ if (
1565
+ permissions.has_vendor_permissions()
1566
+ or permissions.has_client_permissions()
1567
+ ):
1568
+ raise permissions.PermissionDenied
1569
+ user_service.check_project_access(
1570
+ production_schedule_version["project_id"]
1571
+ )
1572
+
1573
+ args = self.get_args(
1574
+ [
1575
+ ("task_type_id", None, False),
1576
+ ]
1577
+ )
1578
+
1579
+ relations = self.get_relations()
1580
+
1581
+ return schedule_service.get_production_schedule_version_task_links(
1582
+ production_schedule_version_id,
1583
+ task_type_id=args["task_type_id"],
1584
+ relations=relations,
1585
+ )
1586
+
1587
+
1588
+ class ProductionScheduleVersionSetTaskLinksFromTasksResource(
1589
+ Resource, ArgsMixin
1590
+ ):
1591
+
1592
+ @jwt_required()
1593
+ def post(self, production_schedule_version_id):
1594
+ """
1595
+ Set task links for given production schedule version from tasks.
1596
+ ---
1597
+ tags:
1598
+ - Projects
1599
+ parameters:
1600
+ - in: path
1601
+ name: production_schedule_version_id
1602
+ required: True
1603
+ type: string
1604
+ format: UUID
1605
+ x-example: a24a6ea4-ce75-4665-a070-57453082c25
1606
+ responses:
1607
+ 200:
1608
+ description: Task links created.
1609
+ 400:
1610
+ description: Wrong ID format
1611
+ """
1612
+ production_schedule_version = (
1613
+ schedule_service.get_production_schedule_version(
1614
+ production_schedule_version_id
1615
+ )
1616
+ )
1617
+ user_service.check_manager_project_access(
1618
+ production_schedule_version["project_id"]
1619
+ )
1620
+
1621
+ return schedule_service.set_production_schedule_version_task_links_from_production(
1622
+ production_schedule_version_id
1623
+ )
1624
+
1625
+
1626
+ class ProductionScheduleVersionApplyToProductionResource(Resource, ArgsMixin):
1627
+
1628
+ @jwt_required()
1629
+ def post(self, production_schedule_version_id):
1630
+ """
1631
+ Apply production schedule version to production.
1632
+ ---
1633
+ tags:
1634
+ - Projects
1635
+ parameters:
1636
+ - in: path
1637
+ name: production_schedule_version_id
1638
+ required: True
1639
+ type: string
1640
+ format: UUID
1641
+ x-example: a24a6ea4-ce75-4665-a070-57453082c25
1642
+ responses:
1643
+ 200:
1644
+ description: Task links created.
1645
+ 400:
1646
+ description: Wrong ID format
1647
+ """
1648
+ production_schedule_version = (
1649
+ schedule_service.get_production_schedule_version(
1650
+ production_schedule_version_id
1651
+ )
1652
+ )
1653
+ user_service.check_manager_project_access(
1654
+ production_schedule_version["project_id"]
1655
+ )
1656
+
1657
+ return (
1658
+ schedule_service.apply_production_schedule_version_to_production(
1659
+ production_schedule_version_id,
1660
+ )
1661
+ )
1662
+
1663
+
1664
+ class ProductionScheduleVersionSetTaskLinksFromProductionScheduleVersionResource(
1665
+ Resource, ArgsMixin
1666
+ ):
1667
+
1668
+ @jwt_required()
1669
+ def post(self, production_schedule_version_id):
1670
+ """
1671
+ Set task links for given production schedule version from another production schedule version.
1672
+ ---
1673
+ tags:
1674
+ - Projects
1675
+ parameters:
1676
+ - in: path
1677
+ name: production_schedule_version_id
1678
+ required: True
1679
+ type: string
1680
+ format: UUID
1681
+ x-example: a24a6ea4-ce75-4665-a070-57453082c25
1682
+ - in: formData
1683
+ name: production_schedule_version_id
1684
+ required: True
1685
+ type: string
1686
+ format: UUID
1687
+ x-example: a24a6ea4-ce75-4665-a070-57453082c25
1688
+ responses:
1689
+ 200:
1690
+ description: Task links created.
1691
+ 400:
1692
+ description: Wrong ID format
1693
+ """
1694
+ production_schedule_version = (
1695
+ schedule_service.get_production_schedule_version(
1696
+ production_schedule_version_id
1697
+ )
1698
+ )
1699
+ user_service.check_manager_project_access(
1700
+ production_schedule_version["project_id"]
1701
+ )
1702
+
1703
+ args = self.get_args(
1704
+ [
1705
+ ("production_schedule_version_id", None, True),
1706
+ ]
1707
+ )
1708
+
1709
+ other_production_schedule_version = (
1710
+ schedule_service.get_production_schedule_version(
1711
+ args["production_schedule_version_id"]
1712
+ )
1713
+ )
1714
+
1715
+ if (
1716
+ production_schedule_version["project_id"]
1717
+ != other_production_schedule_version["project_id"]
1718
+ ):
1719
+ raise WrongParameterException(
1720
+ "Production schedule versions must belong to the same project."
1721
+ )
1722
+
1723
+ return schedule_service.set_production_schedule_version_task_links_from_production_schedule_version(
1724
+ production_schedule_version_id,
1725
+ other_production_schedule_version_id=other_production_schedule_version[
1726
+ "id"
1727
+ ],
1728
+ )
@@ -1603,7 +1603,7 @@ class SetTaskMainPreviewResource(Resource):
1603
1603
  return entity
1604
1604
 
1605
1605
 
1606
- class PersonsTasksDatesResource(Resource):
1606
+ class PersonsTasksDatesResource(Resource, ArgsMixin):
1607
1607
  @jwt_required()
1608
1608
  @permissions.require_admin
1609
1609
  def get(self):
@@ -1625,7 +1625,10 @@ class PersonsTasksDatesResource(Resource):
1625
1625
  description: For each person, the first start date of all tasks of assigned to this person and the last end date.
1626
1626
  """
1627
1627
  permissions.check_admin_permissions()
1628
- return tasks_service.get_persons_tasks_dates()
1628
+ args = self.get_args([("project_id", None, True, str)])
1629
+ return tasks_service.get_persons_tasks_dates(
1630
+ project_id=args["project_id"]
1631
+ )
1629
1632
 
1630
1633
 
1631
1634
  class OpenTasksResource(Resource, ArgsMixin):
@@ -1229,9 +1229,7 @@ class TimeSpentsResource(Resource):
1229
1229
  except WrongDateFormatException:
1230
1230
  abort(
1231
1231
  400,
1232
- "Wrong date format for {} and/or {}".format(
1233
- start_date, end_date
1234
- ),
1232
+ f"Wrong date format for {start_date} and/or {end_date}",
1235
1233
  )
1236
1234
 
1237
1235
 
zou/app/models/base.py CHANGED
@@ -1,13 +1,14 @@
1
1
  from sqlalchemy_utils import UUIDType
2
- from sqlalchemy import func
3
- from sqlalchemy import orm
2
+ from sqlalchemy import func, orm
4
3
  from zou.app import db
5
- from zou.app.utils import fields, date_helpers
4
+ from zou.app.utils import date_helpers, fields
6
5
 
7
6
 
8
7
  class BaseMixin(object):
9
8
  id = db.Column(
10
- UUIDType(binary=False), primary_key=True, default=fields.gen_uuid
9
+ UUIDType(binary=False),
10
+ primary_key=True,
11
+ default=fields.gen_uuid,
11
12
  )
12
13
 
13
14
  # Audit fields
@@ -78,6 +79,16 @@ class BaseMixin(object):
78
79
  """
79
80
  return cls.query.filter_by(**kw).all()
80
81
 
82
+ @classmethod
83
+ def get_or_create(cls, **kw):
84
+ """
85
+ Shorthand to retrieve data by using filters.
86
+ """
87
+ instance = cls.get_by(**kw)
88
+ if instance is None:
89
+ instance = cls.create(**kw)
90
+ return instance
91
+
81
92
  @classmethod
82
93
  def create(cls, **kw):
83
94
  """
@@ -2,6 +2,68 @@ from zou.app import db
2
2
  from zou.app.models.serializer import SerializerMixin
3
3
  from zou.app.models.base import BaseMixin
4
4
 
5
+ from sqlalchemy_utils import UUIDType
6
+
7
+
8
+ class HardwareItemDepartmentLink(db.Model, BaseMixin, SerializerMixin):
9
+ """
10
+ Uses a many-to-many relationship to link hardware items with departments.
11
+ It can be used to track which hardware items are used by which departments in
12
+ order to set budget forecasting.
13
+ """
14
+
15
+ __tablename__ = "hardware_item_department_link"
16
+ department_id = db.Column(
17
+ UUIDType(binary=False),
18
+ db.ForeignKey("department.id"),
19
+ primary_key=True,
20
+ index=True,
21
+ )
22
+ hardware_item_id = db.Column(
23
+ UUIDType(binary=False),
24
+ db.ForeignKey("hardware_item.id"),
25
+ primary_key=True,
26
+ index=True,
27
+ )
28
+
29
+ __table_args__ = (
30
+ db.UniqueConstraint(
31
+ "hardware_item_id",
32
+ "department_id",
33
+ name="hardware_item_department_link_uc",
34
+ ),
35
+ )
36
+
37
+
38
+ class SoftwareDepartmentLink(db.Model, BaseMixin, SerializerMixin):
39
+ """
40
+ Uses a many-to-many relationship to link software with departments.
41
+ It can be used to track which software is used by which departments in
42
+ order to set budget forecasting.
43
+ """
44
+
45
+ __tablename__ = "software_department_link"
46
+ department_id = db.Column(
47
+ UUIDType(binary=False),
48
+ db.ForeignKey("department.id"),
49
+ primary_key=True,
50
+ index=True,
51
+ )
52
+ software_id = db.Column(
53
+ UUIDType(binary=False),
54
+ db.ForeignKey("software.id"),
55
+ primary_key=True,
56
+ index=True,
57
+ )
58
+
59
+ __table_args__ = (
60
+ db.UniqueConstraint(
61
+ "department_id",
62
+ "software_id",
63
+ name="software_department_link_uc",
64
+ ),
65
+ )
66
+
5
67
 
6
68
  class Department(db.Model, BaseMixin, SerializerMixin):
7
69
  """
zou/app/models/entity.py CHANGED
@@ -149,7 +149,7 @@ class Entity(db.Model, BaseMixin, SerializerMixin):
149
149
 
150
150
  entities_out = db.relationship(
151
151
  "Entity",
152
- secondary="entity_link",
152
+ secondary=EntityLink.__table__,
153
153
  primaryjoin=(id == EntityLink.entity_in_id),
154
154
  secondaryjoin=(id == EntityLink.entity_out_id),
155
155
  backref="entities_in",
@@ -157,14 +157,14 @@ class Entity(db.Model, BaseMixin, SerializerMixin):
157
157
 
158
158
  entity_concept_links = db.relationship(
159
159
  "Entity",
160
- secondary="entity_concept_link",
160
+ secondary=EntityConceptLink.__table__,
161
161
  primaryjoin=(id == EntityConceptLink.entity_in_id),
162
162
  secondaryjoin=(id == EntityConceptLink.entity_out_id),
163
163
  lazy="joined",
164
164
  )
165
165
 
166
166
  instance_casting = db.relationship(
167
- "AssetInstance", secondary="asset_instance_link", backref="shots"
167
+ "AssetInstance", secondary=AssetInstanceLink.__table__, backref="shots"
168
168
  )
169
169
 
170
170
  __table_args__ = (
@@ -0,0 +1,15 @@
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 HardwareItem(db.Model, BaseMixin, SerializerMixin):
7
+ """
8
+ Describes hardware items available in the studio.
9
+ """
10
+
11
+ name = db.Column(db.String(40), unique=True, nullable=False)
12
+ short_name = db.Column(db.String(20), nullable=False)
13
+ archived = db.Column(db.Boolean, default=False)
14
+ monthly_cost = db.Column(db.Integer, default=0)
15
+ inventory_amount = db.Column(db.Integer, default=0)
zou/app/models/person.py CHANGED
@@ -138,7 +138,7 @@ class Person(db.Model, BaseMixin, SerializerMixin):
138
138
  expiration_date = db.Column(db.Date(), nullable=True)
139
139
 
140
140
  departments = db.relationship(
141
- "Department", secondary="department_link", lazy="joined"
141
+ "Department", secondary=DepartmentLink.__table__, lazy="joined"
142
142
  )
143
143
  studio_id = db.Column(
144
144
  UUIDType(binary=False), db.ForeignKey("studio.id"), index=True
@@ -0,0 +1,81 @@
1
+ from zou.app import db
2
+ from zou.app.models.serializer import SerializerMixin
3
+ from zou.app.models.base import BaseMixin
4
+
5
+ from sqlalchemy_utils import UUIDType
6
+
7
+
8
+ class ProductionScheduleVersion(db.Model, BaseMixin, SerializerMixin):
9
+ """
10
+ Describe a production schedule.
11
+ """
12
+
13
+ name = db.Column(db.String(80), nullable=False)
14
+ project_id = db.Column(
15
+ UUIDType(binary=False),
16
+ db.ForeignKey("project.id", ondelete="CASCADE"),
17
+ index=True,
18
+ nullable=False,
19
+ )
20
+ production_schedule_from = db.Column(
21
+ UUIDType(binary=False),
22
+ db.ForeignKey("production_schedule_version.id"),
23
+ index=True,
24
+ nullable=True,
25
+ )
26
+ locked = db.Column(db.Boolean(), default=False)
27
+ canceled = db.Column(db.Boolean(), default=False)
28
+ __table_args__ = (
29
+ db.UniqueConstraint(
30
+ "name", "project_id", name="production_schedule_version_uc"
31
+ ),
32
+ )
33
+
34
+
35
+ class ProductionScheduleVersionTaskLinkPersonLink(db.Model):
36
+ __tablename__ = "production_schedule_version_task_link_person_link"
37
+ production_schedule_version_task_link_id = db.Column(
38
+ UUIDType(binary=False),
39
+ db.ForeignKey(
40
+ "production_schedule_version_task_link.id", ondelete="CASCADE"
41
+ ),
42
+ primary_key=True,
43
+ )
44
+ person_id = db.Column(
45
+ UUIDType(binary=False),
46
+ db.ForeignKey("person.id", ondelete="CASCADE"),
47
+ primary_key=True,
48
+ )
49
+
50
+
51
+ class ProductionScheduleVersionTaskLink(db.Model, BaseMixin, SerializerMixin):
52
+ """
53
+ Link a task to a production schedule version.
54
+ """
55
+
56
+ production_schedule_version_id = db.Column(
57
+ UUIDType(binary=False),
58
+ db.ForeignKey("production_schedule_version.id", ondelete="CASCADE"),
59
+ index=True,
60
+ nullable=False,
61
+ )
62
+ task_id = db.Column(
63
+ UUIDType(binary=False),
64
+ db.ForeignKey("task.id", ondelete="CASCADE"),
65
+ index=True,
66
+ nullable=False,
67
+ )
68
+ start_date = db.Column(db.DateTime)
69
+ due_date = db.Column(db.DateTime)
70
+ estimation = db.Column(db.Float, default=0)
71
+ assignees = db.relationship(
72
+ "Person",
73
+ secondary=ProductionScheduleVersionTaskLinkPersonLink.__table__,
74
+ )
75
+ __table_args__ = (
76
+ db.UniqueConstraint(
77
+ "production_schedule_version_id",
78
+ "task_id",
79
+ name="production_schedule_version_task_link_uc",
80
+ ),
81
+ )
zou/app/models/project.py CHANGED
@@ -178,22 +178,33 @@ class Project(db.Model, BaseMixin, SerializerMixin):
178
178
  index=True,
179
179
  )
180
180
 
181
- team = db.relationship("Person", secondary="project_person_link")
181
+ from_schedule_version_id = db.Column(
182
+ UUIDType(binary=False),
183
+ db.ForeignKey(
184
+ "production_schedule_version.id",
185
+ name="project_from_schedule_version_id_fkey",
186
+ use_alter=True,
187
+ ),
188
+ index=True,
189
+ nullable=True,
190
+ )
191
+
192
+ team = db.relationship("Person", secondary=ProjectPersonLink.__table__)
182
193
  asset_types = db.relationship(
183
- "EntityType", secondary="project_asset_type_link"
194
+ "EntityType", secondary=ProjectAssetTypeLink.__table__
184
195
  )
185
196
  task_statuses = db.relationship(
186
- "TaskStatus", secondary="project_task_status_link"
197
+ "TaskStatus", secondary=ProjectTaskStatusLink.__table__
187
198
  )
188
199
  task_types = db.relationship(
189
- "TaskType", secondary="project_task_type_link"
200
+ "TaskType", secondary=ProjectTaskTypeLink.__table__
190
201
  )
191
202
  status_automations = db.relationship(
192
- "StatusAutomation", secondary="project_status_automation_link"
203
+ "StatusAutomation", secondary=ProjectStatusAutomationLink.__table__
193
204
  )
194
205
  preview_background_files = db.relationship(
195
206
  "PreviewBackgroundFile",
196
- secondary="project_preview_background_file_link",
207
+ secondary=ProjectPreviewBackgroundFileLink.__table__,
197
208
  )
198
209
 
199
210
  def set_team(self, person_ids):
@@ -7,10 +7,14 @@ from sqlalchemy.dialects.postgresql import JSONB
7
7
 
8
8
  class Software(db.Model, BaseMixin, SerializerMixin):
9
9
  """
10
- Describes software used by working files.
10
+ Describes software used in the studio.
11
11
  """
12
12
 
13
13
  name = db.Column(db.String(40), unique=True, nullable=False)
14
14
  short_name = db.Column(db.String(20), nullable=False)
15
+ archived = db.Column(db.Boolean, default=False)
16
+ version = db.Column(db.String(20), nullable=True)
15
17
  file_extension = db.Column(db.String(20), nullable=False)
16
18
  secondary_extensions = db.Column(JSONB)
19
+ monthly_cost = db.Column(db.Integer, default=0)
20
+ inventory_amount = db.Column(db.Integer, default=0)
zou/app/models/task.py CHANGED
@@ -5,21 +5,18 @@ from zou.app.models.serializer import SerializerMixin
5
5
  from zou.app.models.base import BaseMixin
6
6
 
7
7
 
8
- assignees_table = db.Table(
9
- "assignations",
10
- db.Column(
11
- "task",
8
+ class TaskPersonLink(db.Model):
9
+ __tablename__ = "task_person_link"
10
+ task_id = db.Column(
12
11
  UUIDType(binary=False),
13
12
  db.ForeignKey("task.id"),
14
13
  primary_key=True,
15
- ),
16
- db.Column(
17
- "person",
14
+ )
15
+ person_id = db.Column(
18
16
  UUIDType(binary=False),
19
17
  db.ForeignKey("person.id"),
20
18
  primary_key=True,
21
- ),
22
- )
19
+ )
23
20
 
24
21
 
25
22
  class Task(db.Model, BaseMixin, SerializerMixin):
@@ -67,7 +64,7 @@ class Task(db.Model, BaseMixin, SerializerMixin):
67
64
  assigner_id = db.Column(
68
65
  UUIDType(binary=False), db.ForeignKey("person.id"), index=True
69
66
  )
70
- assignees = db.relationship("Person", secondary=assignees_table)
67
+ assignees = db.relationship("Person", secondary=TaskPersonLink.__table__)
71
68
 
72
69
  __table_args__ = (
73
70
  db.UniqueConstraint(
@@ -14,9 +14,8 @@ from zou.app.models.entity import (
14
14
  from zou.app.models.entity_type import EntityType
15
15
  from zou.app.models.subscription import Subscription
16
16
  from zou.app.models.project import Project
17
- from zou.app.models.task import Task
17
+ from zou.app.models.task import Task, TaskPersonLink
18
18
  from zou.app.models.asset_instance import AssetInstance
19
- from zou.app.models.task import assignees_table
20
19
 
21
20
  from zou.app.services import (
22
21
  base_service,
@@ -184,7 +183,7 @@ def get_assets_and_tasks(criterions={}, with_episode_ids=False):
184
183
  Entity.query.filter(build_asset_type_filter())
185
184
  .join(EntityType, Entity.entity_type_id == EntityType.id)
186
185
  .outerjoin(Task)
187
- .outerjoin(assignees_table)
186
+ .outerjoin(TaskPersonLink)
188
187
  )
189
188
 
190
189
  tasks_query = query.add_columns(
@@ -204,7 +203,7 @@ def get_assets_and_tasks(criterions={}, with_episode_ids=False):
204
203
  Task.last_comment_date,
205
204
  Task.last_preview_file_id,
206
205
  Task.difficulty,
207
- assignees_table.columns.person,
206
+ TaskPersonLink.person_id,
208
207
  ).order_by(EntityType.name, Entity.name)
209
208
 
210
209
  if "id" in criterions:
@@ -656,8 +655,6 @@ def remove_asset(asset_id, force=False):
656
655
  for task in tasks:
657
656
  deletion_service.remove_task(task.id, force=True)
658
657
  tasks_service.clear_task_cache(str(task.id))
659
- asset.delete()
660
- clear_asset_cache(str(asset_id))
661
658
  index_service.remove_asset_index(str(asset_id))
662
659
  events.emit(
663
660
  "asset:delete",
@@ -670,6 +667,8 @@ def remove_asset(asset_id, force=False):
670
667
  EntityLink.delete_all_by(entity_out_id=asset_id)
671
668
  EntityConceptLink.delete_all_by(entity_in_id=asset_id)
672
669
  EntityConceptLink.delete_all_by(entity_out_id=asset_id)
670
+ asset.delete()
671
+ clear_asset_cache(str(asset_id))
673
672
  deleted_asset = asset.serialize(obj_type="Asset")
674
673
  return deleted_asset
675
674
 
@@ -15,8 +15,7 @@ from zou.app.models.entity import (
15
15
  )
16
16
  from zou.app.models.project import Project
17
17
  from zou.app.models.subscription import Subscription
18
- from zou.app.models.task import Task
19
- from zou.app.models.task import assignees_table
18
+ from zou.app.models.task import Task, TaskPersonLink
20
19
 
21
20
  from zou.app.services import (
22
21
  deletion_service,
@@ -177,7 +176,7 @@ def get_concepts_and_tasks(criterions={}):
177
176
  query = (
178
177
  Entity.query.join(Project, Project.id == Entity.project_id)
179
178
  .outerjoin(Task, Task.entity_id == Entity.id)
180
- .outerjoin(assignees_table)
179
+ .outerjoin(TaskPersonLink)
181
180
  .add_columns(
182
181
  Task.id,
183
182
  Task.task_type_id,
@@ -192,7 +191,7 @@ def get_concepts_and_tasks(criterions={}):
192
191
  Task.due_date,
193
192
  Task.last_comment_date,
194
193
  Task.nb_assets_ready,
195
- assignees_table.columns.person,
194
+ TaskPersonLink.person_id,
196
195
  Project.id,
197
196
  Project.name,
198
197
  )
@@ -342,20 +342,13 @@ def remove_project(project_id):
342
342
  for task in tasks:
343
343
  remove_task(task.id, force=True)
344
344
 
345
- query = EntityLink.query.join(
346
- Entity, EntityLink.entity_in_id == Entity.id
347
- ).filter(Entity.project_id == project_id)
348
- for link in query:
349
- link.delete_no_commit()
350
- EntityLink.commit()
351
-
352
- query = EntityVersion.query.join(
353
- Entity, EntityVersion.entity_id == Entity.id
354
- ).filter(Entity.project_id == project_id)
355
- for version in query:
356
- version.delete_no_commit()
357
- EntityLink.commit()
358
-
345
+ EntityLink.query.filter(
346
+ EntityLink.entity_in_id == Entity.id,
347
+ Entity.project_id == project_id,
348
+ ).delete()
349
+ EntityVersion.query.filter(
350
+ EntityVersion.entity_id == Entity.id, Entity.project_id == project_id
351
+ ).delete()
359
352
  playlists = Playlist.query.filter_by(project_id=project_id)
360
353
  for playlist in playlists:
361
354
  playlists_service.remove_playlist(playlist.id)
@@ -372,10 +365,9 @@ def remove_project(project_id):
372
365
  ScheduleItem.delete_all_by(project_id=project_id)
373
366
  SearchFilterGroup.delete_all_by(project_id=project_id)
374
367
  SearchFilter.delete_all_by(project_id=project_id)
375
-
376
- for news in News.query.join(Task).filter_by(project_id=project_id).all():
377
- news.delete_no_commit()
378
- News.commit()
368
+ News.query.filter(
369
+ News.task_id == Task.id, Task.project_id == project_id
370
+ ).delete()
379
371
  project = Project.get(project_id)
380
372
  project.delete()
381
373
  events.emit("project:delete", {"project_id": project.id})