|
3 | 3 | import uuid |
4 | 4 | from typing import Collection |
5 | 5 |
|
6 | | -from pydantic import parse_obj_as |
| 6 | +from pydantic import PositiveInt, parse_obj_as |
7 | 7 | from sqlalchemy import ( |
8 | 8 | Text, |
9 | 9 | and_, |
|
37 | 37 | UserAnswerItemData, |
38 | 38 | Version, |
39 | 39 | ) |
40 | | -from apps.answers.errors import AnswerNotFoundError |
| 40 | +from apps.answers.errors import AnswerNotFoundError, AnswerRetentionType |
41 | 41 | from apps.applets.db.schemas import AppletHistorySchema |
42 | 42 | from apps.shared.filtering import Comparisons, FilterField, Filtering |
43 | 43 | from apps.shared.paging import paging |
| 44 | +from apps.workspaces.domain.constants import DataRetention |
44 | 45 | from infrastructure.database.crud import BaseCRUD |
45 | 46 |
|
46 | 47 |
|
@@ -206,6 +207,8 @@ async def get_applet_answers( |
206 | 207 | ) |
207 | 208 | .where( |
208 | 209 | AnswerSchema.applet_id == applet_id, |
| 210 | + AnswerSchema.soft_exists(), |
| 211 | + AnswerItemSchema.soft_exists(), |
209 | 212 | *filter_clauses, |
210 | 213 | ) |
211 | 214 | ) |
@@ -567,6 +570,53 @@ async def get_applet_user_answer_items( |
567 | 570 |
|
568 | 571 | return parse_obj_as(list[UserAnswerItemData], db_result.all()) |
569 | 572 |
|
| 573 | + async def removing_outdated_answers( |
| 574 | + self, |
| 575 | + applet_id: uuid.UUID, |
| 576 | + retention_period: PositiveInt, |
| 577 | + retention_type: DataRetention, |
| 578 | + ): |
| 579 | + hours_in_day = 24 |
| 580 | + hours_in_week = hours_in_day * 7 |
| 581 | + hours_in_month = hours_in_day * 30 |
| 582 | + hours_in_year = hours_in_day * 365 |
| 583 | + |
| 584 | + if retention_type == DataRetention.DAYS: |
| 585 | + retention_time = datetime.timedelta( |
| 586 | + hours=retention_period * hours_in_day |
| 587 | + ) |
| 588 | + elif retention_type == DataRetention.WEEKS: |
| 589 | + retention_time = datetime.timedelta( |
| 590 | + hours=retention_period * hours_in_week |
| 591 | + ) |
| 592 | + elif retention_type == DataRetention.MONTHS: |
| 593 | + retention_time = datetime.timedelta( |
| 594 | + hours=retention_period * hours_in_month |
| 595 | + ) |
| 596 | + elif retention_type == DataRetention.YEARS: |
| 597 | + retention_time = datetime.timedelta( |
| 598 | + hours=retention_period * hours_in_year |
| 599 | + ) |
| 600 | + else: |
| 601 | + raise AnswerRetentionType() |
| 602 | + border_datetime = datetime.datetime.utcnow() - retention_time |
| 603 | + |
| 604 | + query = update(AnswerSchema) |
| 605 | + query = query.where(AnswerSchema.applet_id == applet_id) |
| 606 | + query = query.where(AnswerSchema.created_at < border_datetime) |
| 607 | + query = query.where(AnswerSchema.soft_exists()) |
| 608 | + query = query.values(is_deleted=True) |
| 609 | + query = query.returning(column("id")) |
| 610 | + deleted_answer_ids: list[uuid.UUID] = [ |
| 611 | + x[0] for x in await self._execute(query) |
| 612 | + ] |
| 613 | + |
| 614 | + query = update(AnswerItemSchema) |
| 615 | + query = query.where(AnswerItemSchema.answer_id.in_(deleted_answer_ids)) |
| 616 | + query = query.where(AnswerSchema.soft_exists()) |
| 617 | + query = query.values(is_deleted=True) |
| 618 | + await self._execute(query) |
| 619 | + |
570 | 620 | async def update_encrypted_fields( |
571 | 621 | self, user_public_key: str, data: list[AnswerItemDataEncrypted] |
572 | 622 | ): |
|
0 commit comments