[WEB-5044] fix: ruff lint and format errors (#7868)
* fix: lint errors * fix: file formatting * fix: code refactor
This commit is contained in:
parent
1fb22bd252
commit
9237f568dd
261 changed files with 2199 additions and 6378 deletions
|
|
@ -87,10 +87,7 @@ def get_assignee_details(slug, filters):
|
|||
"""Fetch assignee details if required."""
|
||||
return (
|
||||
Issue.issue_objects.filter(
|
||||
Q(
|
||||
Q(assignees__avatar__isnull=False)
|
||||
| Q(assignees__avatar_asset__isnull=False)
|
||||
),
|
||||
Q(Q(assignees__avatar__isnull=False) | Q(assignees__avatar_asset__isnull=False)),
|
||||
workspace__slug=slug,
|
||||
**filters,
|
||||
)
|
||||
|
|
@ -195,11 +192,7 @@ def generate_segmented_rows(
|
|||
cycle_details,
|
||||
module_details,
|
||||
):
|
||||
segment_zero = list(
|
||||
set(
|
||||
item.get("segment") for sublist in distribution.values() for item in sublist
|
||||
)
|
||||
)
|
||||
segment_zero = list(set(item.get("segment") for sublist in distribution.values() for item in sublist))
|
||||
|
||||
segmented = segment
|
||||
|
||||
|
|
@ -221,38 +214,26 @@ def generate_segmented_rows(
|
|||
|
||||
if x_axis == ASSIGNEE_ID:
|
||||
assignee = next(
|
||||
(
|
||||
user
|
||||
for user in assignee_details
|
||||
if str(user[ASSIGNEE_ID]) == str(item)
|
||||
),
|
||||
(user for user in assignee_details if str(user[ASSIGNEE_ID]) == str(item)),
|
||||
None,
|
||||
)
|
||||
if assignee:
|
||||
generated_row[0] = (
|
||||
f"{assignee['assignees__first_name']} {assignee['assignees__last_name']}"
|
||||
)
|
||||
generated_row[0] = f"{assignee['assignees__first_name']} {assignee['assignees__last_name']}"
|
||||
|
||||
if x_axis == LABEL_ID:
|
||||
label = next(
|
||||
(lab for lab in label_details if str(lab[LABEL_ID]) == str(item)), None
|
||||
)
|
||||
label = next((lab for lab in label_details if str(lab[LABEL_ID]) == str(item)), None)
|
||||
|
||||
if label:
|
||||
generated_row[0] = f"{label['labels__name']}"
|
||||
|
||||
if x_axis == STATE_ID:
|
||||
state = next(
|
||||
(sta for sta in state_details if str(sta[STATE_ID]) == str(item)), None
|
||||
)
|
||||
state = next((sta for sta in state_details if str(sta[STATE_ID]) == str(item)), None)
|
||||
|
||||
if state:
|
||||
generated_row[0] = f"{state['state__name']}"
|
||||
|
||||
if x_axis == CYCLE_ID:
|
||||
cycle = next(
|
||||
(cyc for cyc in cycle_details if str(cyc[CYCLE_ID]) == str(item)), None
|
||||
)
|
||||
cycle = next((cyc for cyc in cycle_details if str(cyc[CYCLE_ID]) == str(item)), None)
|
||||
|
||||
if cycle:
|
||||
generated_row[0] = f"{cycle['issue_cycle__cycle__name']}"
|
||||
|
|
@ -271,47 +252,33 @@ def generate_segmented_rows(
|
|||
if segmented == ASSIGNEE_ID:
|
||||
for index, segm in enumerate(row_zero[2:]):
|
||||
assignee = next(
|
||||
(
|
||||
user
|
||||
for user in assignee_details
|
||||
if str(user[ASSIGNEE_ID]) == str(segm)
|
||||
),
|
||||
(user for user in assignee_details if str(user[ASSIGNEE_ID]) == str(segm)),
|
||||
None,
|
||||
)
|
||||
if assignee:
|
||||
row_zero[index + 2] = (
|
||||
f"{assignee['assignees__first_name']} {assignee['assignees__last_name']}"
|
||||
)
|
||||
row_zero[index + 2] = f"{assignee['assignees__first_name']} {assignee['assignees__last_name']}"
|
||||
|
||||
if segmented == LABEL_ID:
|
||||
for index, segm in enumerate(row_zero[2:]):
|
||||
label = next(
|
||||
(lab for lab in label_details if str(lab[LABEL_ID]) == str(segm)), None
|
||||
)
|
||||
label = next((lab for lab in label_details if str(lab[LABEL_ID]) == str(segm)), None)
|
||||
if label:
|
||||
row_zero[index + 2] = label["labels__name"]
|
||||
|
||||
if segmented == STATE_ID:
|
||||
for index, segm in enumerate(row_zero[2:]):
|
||||
state = next(
|
||||
(sta for sta in state_details if str(sta[STATE_ID]) == str(segm)), None
|
||||
)
|
||||
state = next((sta for sta in state_details if str(sta[STATE_ID]) == str(segm)), None)
|
||||
if state:
|
||||
row_zero[index + 2] = state["state__name"]
|
||||
|
||||
if segmented == MODULE_ID:
|
||||
for index, segm in enumerate(row_zero[2:]):
|
||||
module = next(
|
||||
(mod for mod in label_details if str(mod[MODULE_ID]) == str(segm)), None
|
||||
)
|
||||
module = next((mod for mod in label_details if str(mod[MODULE_ID]) == str(segm)), None)
|
||||
if module:
|
||||
row_zero[index + 2] = module["issue_module__module__name"]
|
||||
|
||||
if segmented == CYCLE_ID:
|
||||
for index, segm in enumerate(row_zero[2:]):
|
||||
cycle = next(
|
||||
(cyc for cyc in cycle_details if str(cyc[CYCLE_ID]) == str(segm)), None
|
||||
)
|
||||
cycle = next((cyc for cyc in cycle_details if str(cyc[CYCLE_ID]) == str(segm)), None)
|
||||
if cycle:
|
||||
row_zero[index + 2] = cycle["issue_cycle__cycle__name"]
|
||||
|
||||
|
|
@ -335,38 +302,26 @@ def generate_non_segmented_rows(
|
|||
|
||||
if x_axis == ASSIGNEE_ID:
|
||||
assignee = next(
|
||||
(
|
||||
user
|
||||
for user in assignee_details
|
||||
if str(user[ASSIGNEE_ID]) == str(item)
|
||||
),
|
||||
(user for user in assignee_details if str(user[ASSIGNEE_ID]) == str(item)),
|
||||
None,
|
||||
)
|
||||
if assignee:
|
||||
row[0] = (
|
||||
f"{assignee['assignees__first_name']} {assignee['assignees__last_name']}"
|
||||
)
|
||||
row[0] = f"{assignee['assignees__first_name']} {assignee['assignees__last_name']}"
|
||||
|
||||
if x_axis == LABEL_ID:
|
||||
label = next(
|
||||
(lab for lab in label_details if str(lab[LABEL_ID]) == str(item)), None
|
||||
)
|
||||
label = next((lab for lab in label_details if str(lab[LABEL_ID]) == str(item)), None)
|
||||
|
||||
if label:
|
||||
row[0] = f"{label['labels__name']}"
|
||||
|
||||
if x_axis == STATE_ID:
|
||||
state = next(
|
||||
(sta for sta in state_details if str(sta[STATE_ID]) == str(item)), None
|
||||
)
|
||||
state = next((sta for sta in state_details if str(sta[STATE_ID]) == str(item)), None)
|
||||
|
||||
if state:
|
||||
row[0] = f"{state['state__name']}"
|
||||
|
||||
if x_axis == CYCLE_ID:
|
||||
cycle = next(
|
||||
(cyc for cyc in cycle_details if str(cyc[CYCLE_ID]) == str(item)), None
|
||||
)
|
||||
cycle = next((cyc for cyc in cycle_details if str(cyc[CYCLE_ID]) == str(item)), None)
|
||||
|
||||
if cycle:
|
||||
row[0] = f"{cycle['issue_cycle__cycle__name']}"
|
||||
|
|
@ -396,40 +351,20 @@ def analytic_export_task(email, data, slug):
|
|||
y_axis = data.get("y_axis", False)
|
||||
segment = data.get("segment", False)
|
||||
|
||||
distribution = build_graph_plot(
|
||||
queryset, x_axis=x_axis, y_axis=y_axis, segment=segment
|
||||
)
|
||||
distribution = build_graph_plot(queryset, x_axis=x_axis, y_axis=y_axis, segment=segment)
|
||||
key = "count" if y_axis == "issue_count" else "estimate"
|
||||
|
||||
assignee_details = (
|
||||
get_assignee_details(slug, filters)
|
||||
if x_axis == ASSIGNEE_ID or segment == ASSIGNEE_ID
|
||||
else {}
|
||||
get_assignee_details(slug, filters) if x_axis == ASSIGNEE_ID or segment == ASSIGNEE_ID else {}
|
||||
)
|
||||
|
||||
label_details = (
|
||||
get_label_details(slug, filters)
|
||||
if x_axis == LABEL_ID or segment == LABEL_ID
|
||||
else {}
|
||||
)
|
||||
label_details = get_label_details(slug, filters) if x_axis == LABEL_ID or segment == LABEL_ID else {}
|
||||
|
||||
state_details = (
|
||||
get_state_details(slug, filters)
|
||||
if x_axis == STATE_ID or segment == STATE_ID
|
||||
else {}
|
||||
)
|
||||
state_details = get_state_details(slug, filters) if x_axis == STATE_ID or segment == STATE_ID else {}
|
||||
|
||||
cycle_details = (
|
||||
get_cycle_details(slug, filters)
|
||||
if x_axis == CYCLE_ID or segment == CYCLE_ID
|
||||
else {}
|
||||
)
|
||||
cycle_details = get_cycle_details(slug, filters) if x_axis == CYCLE_ID or segment == CYCLE_ID else {}
|
||||
|
||||
module_details = (
|
||||
get_module_details(slug, filters)
|
||||
if x_axis == MODULE_ID or segment == MODULE_ID
|
||||
else {}
|
||||
)
|
||||
module_details = get_module_details(slug, filters) if x_axis == MODULE_ID or segment == MODULE_ID else {}
|
||||
|
||||
if segment:
|
||||
rows = generate_segmented_rows(
|
||||
|
|
|
|||
|
|
@ -61,9 +61,7 @@ def flush_to_mongo_and_delete(
|
|||
logger.debug("No records to flush - buffer is empty")
|
||||
return
|
||||
|
||||
logger.info(
|
||||
f"Starting batch flush: {len(buffer)} records, {len(ids_to_delete)} IDs to delete"
|
||||
)
|
||||
logger.info(f"Starting batch flush: {len(buffer)} records, {len(ids_to_delete)} IDs to delete")
|
||||
|
||||
mongo_archival_failed = False
|
||||
|
||||
|
|
@ -83,9 +81,7 @@ def flush_to_mongo_and_delete(
|
|||
|
||||
# Delete from PostgreSQL - delete() returns (count, {model: count})
|
||||
delete_result = model.all_objects.filter(id__in=ids_to_delete).delete()
|
||||
deleted_count = (
|
||||
delete_result[0] if delete_result and isinstance(delete_result, tuple) else 0
|
||||
)
|
||||
deleted_count = delete_result[0] if delete_result and isinstance(delete_result, tuple) else 0
|
||||
logger.info(f"Batch flush completed: {deleted_count} records deleted")
|
||||
|
||||
|
||||
|
|
@ -193,9 +189,7 @@ def transform_email_log(record: Dict) -> Dict:
|
|||
"entity_identifier": str(record["entity_identifier"]),
|
||||
"entity_name": record["entity_name"],
|
||||
"data": record["data"],
|
||||
"processed_at": (
|
||||
str(record["processed_at"]) if record.get("processed_at") else None
|
||||
),
|
||||
"processed_at": (str(record["processed_at"]) if record.get("processed_at") else None),
|
||||
"sent_at": str(record["sent_at"]) if record.get("sent_at") else None,
|
||||
"entity": record["entity"],
|
||||
"old_value": str(record["old_value"]),
|
||||
|
|
@ -220,9 +214,7 @@ def transform_page_version(record: Dict) -> Dict:
|
|||
"created_by_id": str(record["created_by_id"]),
|
||||
"updated_by_id": str(record["updated_by_id"]),
|
||||
"deleted_at": str(record["deleted_at"]) if record.get("deleted_at") else None,
|
||||
"last_saved_at": (
|
||||
str(record["last_saved_at"]) if record.get("last_saved_at") else None
|
||||
),
|
||||
"last_saved_at": (str(record["last_saved_at"]) if record.get("last_saved_at") else None),
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -237,9 +229,7 @@ def transform_issue_description_version(record: Dict) -> Dict:
|
|||
"created_by_id": str(record["created_by_id"]),
|
||||
"updated_by_id": str(record["updated_by_id"]),
|
||||
"owned_by_id": str(record["owned_by_id"]),
|
||||
"last_saved_at": (
|
||||
str(record["last_saved_at"]) if record.get("last_saved_at") else None
|
||||
),
|
||||
"last_saved_at": (str(record["last_saved_at"]) if record.get("last_saved_at") else None),
|
||||
"description_binary": record["description_binary"],
|
||||
"description_html": record["description_html"],
|
||||
"description_stripped": record["description_stripped"],
|
||||
|
|
|
|||
|
|
@ -25,9 +25,7 @@ def get_entity_id_field(entity_type, entity_id):
|
|||
FileAsset.EntityTypeContext.ISSUE_DESCRIPTION: {"issue_id": entity_id},
|
||||
FileAsset.EntityTypeContext.PAGE_DESCRIPTION: {"page_id": entity_id},
|
||||
FileAsset.EntityTypeContext.COMMENT_DESCRIPTION: {"comment_id": entity_id},
|
||||
FileAsset.EntityTypeContext.DRAFT_ISSUE_DESCRIPTION: {
|
||||
"draft_issue_id": entity_id
|
||||
},
|
||||
FileAsset.EntityTypeContext.DRAFT_ISSUE_DESCRIPTION: {"draft_issue_id": entity_id},
|
||||
}
|
||||
return entity_mapping.get(entity_type, {})
|
||||
|
||||
|
|
@ -87,14 +85,10 @@ def copy_assets(entity, entity_identifier, project_id, asset_ids, user_id):
|
|||
duplicated_assets = []
|
||||
workspace = entity.workspace
|
||||
storage = S3Storage()
|
||||
original_assets = FileAsset.objects.filter(
|
||||
workspace=workspace, project_id=project_id, id__in=asset_ids
|
||||
)
|
||||
original_assets = FileAsset.objects.filter(workspace=workspace, project_id=project_id, id__in=asset_ids)
|
||||
|
||||
for original_asset in original_assets:
|
||||
destination_key = (
|
||||
f"{workspace.id}/{uuid.uuid4().hex}-{original_asset.attributes.get('name')}"
|
||||
)
|
||||
destination_key = f"{workspace.id}/{uuid.uuid4().hex}-{original_asset.attributes.get('name')}"
|
||||
duplicated_asset = FileAsset.objects.create(
|
||||
attributes={
|
||||
"name": original_asset.attributes.get("name"),
|
||||
|
|
@ -118,17 +112,13 @@ def copy_assets(entity, entity_identifier, project_id, asset_ids, user_id):
|
|||
}
|
||||
)
|
||||
if duplicated_assets:
|
||||
FileAsset.objects.filter(
|
||||
pk__in=[item["new_asset_id"] for item in duplicated_assets]
|
||||
).update(is_uploaded=True)
|
||||
FileAsset.objects.filter(pk__in=[item["new_asset_id"] for item in duplicated_assets]).update(is_uploaded=True)
|
||||
|
||||
return duplicated_assets
|
||||
|
||||
|
||||
@shared_task
|
||||
def copy_s3_objects_of_description_and_assets(
|
||||
entity_name, entity_identifier, project_id, slug, user_id
|
||||
):
|
||||
def copy_s3_objects_of_description_and_assets(entity_name, entity_identifier, project_id, slug, user_id):
|
||||
"""
|
||||
Step 1: Extract asset ids from the description_html of the entity
|
||||
Step 2: Duplicate the assets
|
||||
|
|
@ -144,9 +134,7 @@ def copy_s3_objects_of_description_and_assets(
|
|||
entity = model_class.objects.get(id=entity_identifier)
|
||||
asset_ids = extract_asset_ids(entity.description_html, "image-component")
|
||||
|
||||
duplicated_assets = copy_assets(
|
||||
entity, entity_identifier, project_id, asset_ids, user_id
|
||||
)
|
||||
duplicated_assets = copy_assets(entity, entity_identifier, project_id, asset_ids, user_id)
|
||||
|
||||
updated_html = update_description(entity, duplicated_assets, "image-component")
|
||||
|
||||
|
|
@ -154,9 +142,7 @@ def copy_s3_objects_of_description_and_assets(
|
|||
|
||||
if external_data:
|
||||
entity.description = external_data.get("description")
|
||||
entity.description_binary = base64.b64decode(
|
||||
external_data.get("description_binary")
|
||||
)
|
||||
entity.description_binary = base64.b64decode(external_data.get("description_binary"))
|
||||
entity.save()
|
||||
|
||||
return
|
||||
|
|
|
|||
|
|
@ -26,9 +26,7 @@ def soft_delete_related_objects(app_label, model_name, instance_pk, using=None):
|
|||
|
||||
# Get all related fields that are reverse relationships
|
||||
all_related = [
|
||||
f
|
||||
for f in instance._meta.get_fields()
|
||||
if (f.one_to_many or f.one_to_one) and f.auto_created and not f.concrete
|
||||
f for f in instance._meta.get_fields() if (f.one_to_many or f.one_to_one) and f.auto_created and not f.concrete
|
||||
]
|
||||
|
||||
# Handle each related field
|
||||
|
|
@ -40,11 +38,7 @@ def soft_delete_related_objects(app_label, model_name, instance_pk, using=None):
|
|||
continue
|
||||
|
||||
# Get the on_delete behavior name
|
||||
on_delete_name = (
|
||||
relation.on_delete.__name__
|
||||
if hasattr(relation.on_delete, "__name__")
|
||||
else ""
|
||||
)
|
||||
on_delete_name = relation.on_delete.__name__ if hasattr(relation.on_delete, "__name__") else ""
|
||||
|
||||
if on_delete_name == "DO_NOTHING":
|
||||
continue
|
||||
|
|
@ -82,9 +76,7 @@ def soft_delete_related_objects(app_label, model_name, instance_pk, using=None):
|
|||
)
|
||||
else:
|
||||
# Handle other relationships
|
||||
related_queryset = getattr(instance, related_name)(
|
||||
manager="objects"
|
||||
).all()
|
||||
related_queryset = getattr(instance, related_name)(manager="objects").all()
|
||||
|
||||
for related_obj in related_queryset:
|
||||
if hasattr(related_obj, "deleted_at"):
|
||||
|
|
@ -139,85 +131,49 @@ def hard_delete():
|
|||
|
||||
days = settings.HARD_DELETE_AFTER_DAYS
|
||||
# check delete workspace
|
||||
_ = Workspace.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = Workspace.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
# check delete project
|
||||
_ = Project.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = Project.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
# check delete cycle
|
||||
_ = Cycle.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = Cycle.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
# check delete module
|
||||
_ = Module.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = Module.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
# check delete issue
|
||||
_ = Issue.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = Issue.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
# check delete page
|
||||
_ = Page.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = Page.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
# check delete view
|
||||
_ = IssueView.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = IssueView.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
# check delete label
|
||||
_ = Label.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = Label.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
# check delete state
|
||||
_ = State.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = State.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
_ = IssueActivity.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = IssueActivity.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
_ = IssueComment.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = IssueComment.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
_ = IssueLink.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = IssueLink.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
_ = IssueReaction.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = IssueReaction.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
_ = UserFavorite.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = UserFavorite.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
_ = ModuleIssue.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = ModuleIssue.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
_ = CycleIssue.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = CycleIssue.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
_ = Estimate.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = Estimate.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
_ = EstimatePoint.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = EstimatePoint.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
# at last, check for every thing which ever is left and delete it
|
||||
# Get all Django models
|
||||
|
|
@ -228,8 +184,6 @@ def hard_delete():
|
|||
# Check if the model has a 'deleted_at' field
|
||||
if hasattr(model, "deleted_at"):
|
||||
# Get all instances where 'deleted_at' is greater than 30 days ago
|
||||
_ = model.all_objects.filter(
|
||||
deleted_at__lt=timezone.now() - timezone.timedelta(days=days)
|
||||
).delete()
|
||||
_ = model.all_objects.filter(deleted_at__lt=timezone.now() - timezone.timedelta(days=days)).delete()
|
||||
|
||||
return
|
||||
|
|
|
|||
|
|
@ -44,9 +44,7 @@ def create_project(workspace, user_id):
|
|||
project = Project.objects.create(
|
||||
workspace=workspace,
|
||||
name=f"{name}_{unique_id}",
|
||||
identifier=name[
|
||||
: random.randint(2, 12 if len(name) - 1 >= 12 else len(name) - 1)
|
||||
].upper(),
|
||||
identifier=name[: random.randint(2, 12 if len(name) - 1 >= 12 else len(name) - 1)].upper(),
|
||||
created_by_id=user_id,
|
||||
intake_view=True,
|
||||
)
|
||||
|
|
@ -163,17 +161,11 @@ def create_cycles(workspace, project, user_id, cycle_count):
|
|||
)
|
||||
|
||||
# Ensure end_date is strictly after start_date if start_date is not None
|
||||
while start_date is not None and (
|
||||
end_date <= start_date or (start_date, end_date) in used_date_ranges
|
||||
):
|
||||
while start_date is not None and (end_date <= start_date or (start_date, end_date) in used_date_ranges):
|
||||
end_date = fake.date_this_year()
|
||||
|
||||
# Add the unique date range to the set
|
||||
(
|
||||
used_date_ranges.add((start_date, end_date))
|
||||
if (end_date is not None and start_date is not None)
|
||||
else None
|
||||
)
|
||||
(used_date_ranges.add((start_date, end_date)) if (end_date is not None and start_date is not None) else None)
|
||||
|
||||
# Append the cycle with unique date range
|
||||
cycles.append(
|
||||
|
|
@ -244,10 +236,7 @@ def create_pages(workspace, project, user_id, pages_count):
|
|||
pages = Page.objects.bulk_create(pages, ignore_conflicts=True)
|
||||
# Add Page to project
|
||||
ProjectPage.objects.bulk_create(
|
||||
[
|
||||
ProjectPage(page=page, project=project, workspace=workspace)
|
||||
for page in pages
|
||||
],
|
||||
[ProjectPage(page=page, project=project, workspace=workspace) for page in pages],
|
||||
batch_size=1000,
|
||||
)
|
||||
|
||||
|
|
@ -264,14 +253,10 @@ def create_page_labels(workspace, project, user_id, pages_count):
|
|||
bulk_page_labels = []
|
||||
for page in pages:
|
||||
for label in random.sample(list(labels), random.randint(0, len(labels) - 1)):
|
||||
bulk_page_labels.append(
|
||||
PageLabel(page_id=page, label_id=label, workspace=workspace)
|
||||
)
|
||||
bulk_page_labels.append(PageLabel(page_id=page, label_id=label, workspace=workspace))
|
||||
|
||||
# Page labels
|
||||
PageLabel.objects.bulk_create(
|
||||
bulk_page_labels, batch_size=1000, ignore_conflicts=True
|
||||
)
|
||||
PageLabel.objects.bulk_create(bulk_page_labels, batch_size=1000, ignore_conflicts=True)
|
||||
|
||||
|
||||
def create_issues(workspace, project, user_id, issue_count):
|
||||
|
|
@ -279,20 +264,14 @@ def create_issues(workspace, project, user_id, issue_count):
|
|||
Faker.seed(0)
|
||||
|
||||
states = (
|
||||
State.objects.filter(workspace=workspace, project=project)
|
||||
.exclude(group="Triage")
|
||||
.values_list("id", flat=True)
|
||||
State.objects.filter(workspace=workspace, project=project).exclude(group="Triage").values_list("id", flat=True)
|
||||
)
|
||||
creators = ProjectMember.objects.filter(
|
||||
workspace=workspace, project=project
|
||||
).values_list("member_id", flat=True)
|
||||
creators = ProjectMember.objects.filter(workspace=workspace, project=project).values_list("member_id", flat=True)
|
||||
|
||||
issues = []
|
||||
|
||||
# Get the maximum sequence_id
|
||||
last_id = IssueSequence.objects.filter(project=project).aggregate(
|
||||
largest=Max("sequence")
|
||||
)["largest"]
|
||||
last_id = IssueSequence.objects.filter(project=project).aggregate(largest=Max("sequence"))["largest"]
|
||||
|
||||
last_id = 1 if last_id is None else last_id + 1
|
||||
|
||||
|
|
@ -301,9 +280,7 @@ def create_issues(workspace, project, user_id, issue_count):
|
|||
project=project, state_id=states[random.randint(0, len(states) - 1)]
|
||||
).aggregate(largest=Max("sort_order"))["largest"]
|
||||
|
||||
largest_sort_order = (
|
||||
65535 if largest_sort_order is None else largest_sort_order + 10000
|
||||
)
|
||||
largest_sort_order = 65535 if largest_sort_order is None else largest_sort_order + 10000
|
||||
|
||||
for _ in range(0, issue_count):
|
||||
start_date = [None, fake.date_this_year()][random.randint(0, 1)]
|
||||
|
|
@ -329,9 +306,7 @@ def create_issues(workspace, project, user_id, issue_count):
|
|||
sort_order=largest_sort_order,
|
||||
start_date=start_date,
|
||||
target_date=end_date,
|
||||
priority=["urgent", "high", "medium", "low", "none"][
|
||||
random.randint(0, 4)
|
||||
],
|
||||
priority=["urgent", "high", "medium", "low", "none"][random.randint(0, 4)],
|
||||
created_by_id=creators[random.randint(0, len(creators) - 1)],
|
||||
)
|
||||
)
|
||||
|
|
@ -375,20 +350,14 @@ def create_issues(workspace, project, user_id, issue_count):
|
|||
|
||||
def create_intake_issues(workspace, project, user_id, intake_issue_count):
|
||||
issues = create_issues(workspace, project, user_id, intake_issue_count)
|
||||
intake, create = Intake.objects.get_or_create(
|
||||
name="Intake", project=project, is_default=True
|
||||
)
|
||||
intake, create = Intake.objects.get_or_create(name="Intake", project=project, is_default=True)
|
||||
IntakeIssue.objects.bulk_create(
|
||||
[
|
||||
IntakeIssue(
|
||||
issue=issue,
|
||||
intake=intake,
|
||||
status=(status := [-2, -1, 0, 1, 2][random.randint(0, 4)]),
|
||||
snoozed_till=(
|
||||
datetime.now() + timedelta(days=random.randint(1, 30))
|
||||
if status == 0
|
||||
else None
|
||||
),
|
||||
snoozed_till=(datetime.now() + timedelta(days=random.randint(1, 30)) if status == 0 else None),
|
||||
source=SourceType.IN_APP,
|
||||
workspace=workspace,
|
||||
project=project,
|
||||
|
|
@ -402,12 +371,8 @@ def create_intake_issues(workspace, project, user_id, intake_issue_count):
|
|||
def create_issue_parent(workspace, project, user_id, issue_count):
|
||||
parent_count = issue_count / 4
|
||||
|
||||
parent_issues = Issue.objects.filter(project=project).values_list("id", flat=True)[
|
||||
: int(parent_count)
|
||||
]
|
||||
sub_issues = Issue.objects.filter(project=project).exclude(pk__in=parent_issues)[
|
||||
: int(issue_count / 2)
|
||||
]
|
||||
parent_issues = Issue.objects.filter(project=project).values_list("id", flat=True)[: int(parent_count)]
|
||||
sub_issues = Issue.objects.filter(project=project).exclude(pk__in=parent_issues)[: int(issue_count / 2)]
|
||||
|
||||
bulk_sub_issues = []
|
||||
for sub_issue in sub_issues:
|
||||
|
|
@ -418,9 +383,7 @@ def create_issue_parent(workspace, project, user_id, issue_count):
|
|||
|
||||
def create_issue_assignees(workspace, project, user_id, issue_count):
|
||||
# assignees
|
||||
assignees = ProjectMember.objects.filter(project=project).values_list(
|
||||
"member_id", flat=True
|
||||
)
|
||||
assignees = ProjectMember.objects.filter(project=project).values_list("member_id", flat=True)
|
||||
issues = random.sample(
|
||||
list(Issue.objects.filter(project=project).values_list("id", flat=True)),
|
||||
int(issue_count / 2),
|
||||
|
|
@ -429,9 +392,7 @@ def create_issue_assignees(workspace, project, user_id, issue_count):
|
|||
# Bulk issue
|
||||
bulk_issue_assignees = []
|
||||
for issue in issues:
|
||||
for assignee in random.sample(
|
||||
list(assignees), random.randint(0, len(assignees) - 1)
|
||||
):
|
||||
for assignee in random.sample(list(assignees), random.randint(0, len(assignees) - 1)):
|
||||
bulk_issue_assignees.append(
|
||||
IssueAssignee(
|
||||
issue_id=issue,
|
||||
|
|
@ -442,9 +403,7 @@ def create_issue_assignees(workspace, project, user_id, issue_count):
|
|||
)
|
||||
|
||||
# Issue assignees
|
||||
IssueAssignee.objects.bulk_create(
|
||||
bulk_issue_assignees, batch_size=1000, ignore_conflicts=True
|
||||
)
|
||||
IssueAssignee.objects.bulk_create(bulk_issue_assignees, batch_size=1000, ignore_conflicts=True)
|
||||
|
||||
|
||||
def create_issue_labels(workspace, project, user_id, issue_count):
|
||||
|
|
@ -464,16 +423,10 @@ def create_issue_labels(workspace, project, user_id, issue_count):
|
|||
for issue in issues:
|
||||
random.shuffle(shuffled_labels)
|
||||
for label in random.sample(shuffled_labels, random.randint(0, 5)):
|
||||
bulk_issue_labels.append(
|
||||
IssueLabel(
|
||||
issue_id=issue, label_id=label, project=project, workspace=workspace
|
||||
)
|
||||
)
|
||||
bulk_issue_labels.append(IssueLabel(issue_id=issue, label_id=label, project=project, workspace=workspace))
|
||||
|
||||
# Issue labels
|
||||
IssueLabel.objects.bulk_create(
|
||||
bulk_issue_labels, batch_size=1000, ignore_conflicts=True
|
||||
)
|
||||
IssueLabel.objects.bulk_create(bulk_issue_labels, batch_size=1000, ignore_conflicts=True)
|
||||
|
||||
|
||||
def create_cycle_issues(workspace, project, user_id, issue_count):
|
||||
|
|
@ -488,16 +441,10 @@ def create_cycle_issues(workspace, project, user_id, issue_count):
|
|||
bulk_cycle_issues = []
|
||||
for issue in issues:
|
||||
cycle = cycles[random.randint(0, len(cycles) - 1)]
|
||||
bulk_cycle_issues.append(
|
||||
CycleIssue(
|
||||
cycle_id=cycle, issue_id=issue, project=project, workspace=workspace
|
||||
)
|
||||
)
|
||||
bulk_cycle_issues.append(CycleIssue(cycle_id=cycle, issue_id=issue, project=project, workspace=workspace))
|
||||
|
||||
# Issue assignees
|
||||
CycleIssue.objects.bulk_create(
|
||||
bulk_cycle_issues, batch_size=1000, ignore_conflicts=True
|
||||
)
|
||||
CycleIssue.objects.bulk_create(bulk_cycle_issues, batch_size=1000, ignore_conflicts=True)
|
||||
|
||||
|
||||
def create_module_issues(workspace, project, user_id, issue_count):
|
||||
|
|
@ -527,9 +474,7 @@ def create_module_issues(workspace, project, user_id, issue_count):
|
|||
)
|
||||
)
|
||||
# Issue assignees
|
||||
ModuleIssue.objects.bulk_create(
|
||||
bulk_module_issues, batch_size=1000, ignore_conflicts=True
|
||||
)
|
||||
ModuleIssue.objects.bulk_create(bulk_module_issues, batch_size=1000, ignore_conflicts=True)
|
||||
|
||||
|
||||
@shared_task
|
||||
|
|
@ -561,29 +506,19 @@ def create_dummy_data(
|
|||
create_labels(workspace=workspace, project=project, user_id=user_id)
|
||||
|
||||
# create cycles
|
||||
create_cycles(
|
||||
workspace=workspace, project=project, user_id=user_id, cycle_count=cycle_count
|
||||
)
|
||||
create_cycles(workspace=workspace, project=project, user_id=user_id, cycle_count=cycle_count)
|
||||
|
||||
# create modules
|
||||
create_modules(
|
||||
workspace=workspace, project=project, user_id=user_id, module_count=module_count
|
||||
)
|
||||
create_modules(workspace=workspace, project=project, user_id=user_id, module_count=module_count)
|
||||
|
||||
# create pages
|
||||
create_pages(
|
||||
workspace=workspace, project=project, user_id=user_id, pages_count=pages_count
|
||||
)
|
||||
create_pages(workspace=workspace, project=project, user_id=user_id, pages_count=pages_count)
|
||||
|
||||
# create page labels
|
||||
create_page_labels(
|
||||
workspace=workspace, project=project, user_id=user_id, pages_count=pages_count
|
||||
)
|
||||
create_page_labels(workspace=workspace, project=project, user_id=user_id, pages_count=pages_count)
|
||||
|
||||
# create issues
|
||||
create_issues(
|
||||
workspace=workspace, project=project, user_id=user_id, issue_count=issue_count
|
||||
)
|
||||
create_issues(workspace=workspace, project=project, user_id=user_id, issue_count=issue_count)
|
||||
|
||||
# create intake issues
|
||||
create_intake_issues(
|
||||
|
|
@ -594,28 +529,18 @@ def create_dummy_data(
|
|||
)
|
||||
|
||||
# create issue parent
|
||||
create_issue_parent(
|
||||
workspace=workspace, project=project, user_id=user_id, issue_count=issue_count
|
||||
)
|
||||
create_issue_parent(workspace=workspace, project=project, user_id=user_id, issue_count=issue_count)
|
||||
|
||||
# create issue assignees
|
||||
create_issue_assignees(
|
||||
workspace=workspace, project=project, user_id=user_id, issue_count=issue_count
|
||||
)
|
||||
create_issue_assignees(workspace=workspace, project=project, user_id=user_id, issue_count=issue_count)
|
||||
|
||||
# create issue labels
|
||||
create_issue_labels(
|
||||
workspace=workspace, project=project, user_id=user_id, issue_count=issue_count
|
||||
)
|
||||
create_issue_labels(workspace=workspace, project=project, user_id=user_id, issue_count=issue_count)
|
||||
|
||||
# create cycle issues
|
||||
create_cycle_issues(
|
||||
workspace=workspace, project=project, user_id=user_id, issue_count=issue_count
|
||||
)
|
||||
create_cycle_issues(workspace=workspace, project=project, user_id=user_id, issue_count=issue_count)
|
||||
|
||||
# create module issues
|
||||
create_module_issues(
|
||||
workspace=workspace, project=project, user_id=user_id, issue_count=issue_count
|
||||
)
|
||||
create_module_issues(workspace=workspace, project=project, user_id=user_id, issue_count=issue_count)
|
||||
|
||||
return
|
||||
|
|
|
|||
|
|
@ -42,42 +42,27 @@ def release_lock(lock_id):
|
|||
@shared_task
|
||||
def stack_email_notification():
|
||||
# get all email notifications
|
||||
email_notifications = (
|
||||
EmailNotificationLog.objects.filter(processed_at__isnull=True)
|
||||
.order_by("receiver")
|
||||
.values()
|
||||
)
|
||||
email_notifications = EmailNotificationLog.objects.filter(processed_at__isnull=True).order_by("receiver").values()
|
||||
|
||||
# Create the below format for each of the issues
|
||||
# {"issue_id" : { "actor_id1": [ { data }, { data } ], "actor_id2": [ { data }, { data } ] }}
|
||||
|
||||
# Convert to unique receivers list
|
||||
receivers = list(
|
||||
set(
|
||||
[
|
||||
str(notification.get("receiver_id"))
|
||||
for notification in email_notifications
|
||||
]
|
||||
)
|
||||
)
|
||||
receivers = list(set([str(notification.get("receiver_id")) for notification in email_notifications]))
|
||||
processed_notifications = []
|
||||
# Loop through all the issues to create the emails
|
||||
for receiver_id in receivers:
|
||||
# Notification triggered for the receiver
|
||||
receiver_notifications = [
|
||||
notification
|
||||
for notification in email_notifications
|
||||
if str(notification.get("receiver_id")) == receiver_id
|
||||
notification for notification in email_notifications if str(notification.get("receiver_id")) == receiver_id
|
||||
]
|
||||
# create payload for all issues
|
||||
payload = {}
|
||||
email_notification_ids = []
|
||||
for receiver_notification in receiver_notifications:
|
||||
payload.setdefault(
|
||||
receiver_notification.get("entity_identifier"), {}
|
||||
).setdefault(str(receiver_notification.get("triggered_by_id")), []).append(
|
||||
receiver_notification.get("data")
|
||||
)
|
||||
payload.setdefault(receiver_notification.get("entity_identifier"), {}).setdefault(
|
||||
str(receiver_notification.get("triggered_by_id")), []
|
||||
).append(receiver_notification.get("data"))
|
||||
# append processed notifications
|
||||
processed_notifications.append(receiver_notification.get("id"))
|
||||
email_notification_ids.append(receiver_notification.get("id"))
|
||||
|
|
@ -92,9 +77,7 @@ def stack_email_notification():
|
|||
)
|
||||
|
||||
# Update the email notification log
|
||||
EmailNotificationLog.objects.filter(pk__in=processed_notifications).update(
|
||||
processed_at=timezone.now()
|
||||
)
|
||||
EmailNotificationLog.objects.filter(pk__in=processed_notifications).update(processed_at=timezone.now())
|
||||
|
||||
|
||||
def create_payload(notification_data):
|
||||
|
|
@ -115,10 +98,7 @@ def create_payload(notification_data):
|
|||
.setdefault(field, {})
|
||||
.setdefault("old_value", [])
|
||||
.append(old_value)
|
||||
if old_value
|
||||
not in data.setdefault(actor_id, {})
|
||||
.setdefault(field, {})
|
||||
.get("old_value", [])
|
||||
if old_value not in data.setdefault(actor_id, {}).setdefault(field, {}).get("old_value", [])
|
||||
else None
|
||||
)
|
||||
|
||||
|
|
@ -129,18 +109,15 @@ def create_payload(notification_data):
|
|||
.setdefault(field, {})
|
||||
.setdefault("new_value", [])
|
||||
.append(new_value)
|
||||
if new_value
|
||||
not in data.setdefault(actor_id, {})
|
||||
.setdefault(field, {})
|
||||
.get("new_value", [])
|
||||
if new_value not in data.setdefault(actor_id, {}).setdefault(field, {}).get("new_value", [])
|
||||
else None
|
||||
)
|
||||
|
||||
if not data.get("actor_id", {}).get("activity_time", False):
|
||||
data[actor_id]["activity_time"] = str(
|
||||
datetime.fromisoformat(
|
||||
issue_activity.get("activity_time").rstrip("Z")
|
||||
).strftime("%Y-%m-%d %H:%M:%S")
|
||||
datetime.fromisoformat(issue_activity.get("activity_time").rstrip("Z")).strftime(
|
||||
"%Y-%m-%d %H:%M:%S"
|
||||
)
|
||||
)
|
||||
|
||||
return data
|
||||
|
|
@ -169,9 +146,7 @@ def process_html_content(content):
|
|||
|
||||
|
||||
@shared_task
|
||||
def send_email_notification(
|
||||
issue_id, notification_data, receiver_id, email_notification_ids
|
||||
):
|
||||
def send_email_notification(issue_id, notification_data, receiver_id, email_notification_ids):
|
||||
# Convert UUIDs to a sorted, concatenated string
|
||||
sorted_ids = sorted(email_notification_ids)
|
||||
ids_str = "_".join(str(id) for id in sorted_ids)
|
||||
|
|
@ -225,12 +200,8 @@ def send_email_notification(
|
|||
}
|
||||
)
|
||||
if mention:
|
||||
mention["new_value"] = process_html_content(
|
||||
mention.get("new_value")
|
||||
)
|
||||
mention["old_value"] = process_html_content(
|
||||
mention.get("old_value")
|
||||
)
|
||||
mention["new_value"] = process_html_content(mention.get("new_value"))
|
||||
mention["old_value"] = process_html_content(mention.get("old_value"))
|
||||
comments.append(
|
||||
{
|
||||
"actor_comments": mention,
|
||||
|
|
@ -243,9 +214,7 @@ def send_email_notification(
|
|||
)
|
||||
activity_time = changes.pop("activity_time")
|
||||
# Parse the input string into a datetime object
|
||||
formatted_time = datetime.strptime(
|
||||
activity_time, "%Y-%m-%d %H:%M:%S"
|
||||
).strftime("%H:%M %p")
|
||||
formatted_time = datetime.strptime(activity_time, "%Y-%m-%d %H:%M:%S").strftime("%H:%M %p")
|
||||
|
||||
if changes:
|
||||
template_data.append(
|
||||
|
|
@ -275,20 +244,18 @@ def send_email_notification(
|
|||
"issue": {
|
||||
"issue_identifier": f"{str(issue.project.identifier)}-{str(issue.sequence_id)}",
|
||||
"name": issue.name,
|
||||
"issue_url": f"{base_api}/{str(issue.project.workspace.slug)}/projects/{str(issue.project.id)}/issues/{str(issue.id)}",
|
||||
"issue_url": f"{base_api}/{str(issue.project.workspace.slug)}/projects/{str(issue.project.id)}/issues/{str(issue.id)}", # noqa: E501
|
||||
},
|
||||
"receiver": {"email": receiver.email},
|
||||
"issue_url": f"{base_api}/{str(issue.project.workspace.slug)}/projects/{str(issue.project.id)}/issues/{str(issue.id)}",
|
||||
"project_url": f"{base_api}/{str(issue.project.workspace.slug)}/projects/{str(issue.project.id)}/issues/",
|
||||
"issue_url": f"{base_api}/{str(issue.project.workspace.slug)}/projects/{str(issue.project.id)}/issues/{str(issue.id)}", # noqa: E501
|
||||
"project_url": f"{base_api}/{str(issue.project.workspace.slug)}/projects/{str(issue.project.id)}/issues/", # noqa: E501
|
||||
"workspace": str(issue.project.workspace.slug),
|
||||
"project": str(issue.project.name),
|
||||
"user_preference": f"{base_api}/{str(issue.project.workspace.slug)}/settings/account/notifications/",
|
||||
"comments": comments,
|
||||
"entity_type": "issue",
|
||||
}
|
||||
html_content = render_to_string(
|
||||
"emails/notifications/issue-updates.html", context
|
||||
)
|
||||
html_content = render_to_string("emails/notifications/issue-updates.html", context)
|
||||
text_content = strip_tags(html_content)
|
||||
|
||||
try:
|
||||
|
|
@ -313,9 +280,7 @@ def send_email_notification(
|
|||
logging.getLogger("plane.worker").info("Email Sent Successfully")
|
||||
|
||||
# Update the logs
|
||||
EmailNotificationLog.objects.filter(
|
||||
pk__in=email_notification_ids
|
||||
).update(sent_at=timezone.now())
|
||||
EmailNotificationLog.objects.filter(pk__in=email_notification_ids).update(sent_at=timezone.now())
|
||||
|
||||
# release the lock
|
||||
release_lock(lock_id=lock_id)
|
||||
|
|
|
|||
|
|
@ -93,15 +93,11 @@ def create_zip_file(files: List[tuple[str, str | bytes]]) -> io.BytesIO:
|
|||
|
||||
|
||||
# TODO: Change the upload_to_s3 function to use the new storage method with entry in file asset table
|
||||
def upload_to_s3(
|
||||
zip_file: io.BytesIO, workspace_id: UUID, token_id: str, slug: str
|
||||
) -> None:
|
||||
def upload_to_s3(zip_file: io.BytesIO, workspace_id: UUID, token_id: str, slug: str) -> None:
|
||||
"""
|
||||
Upload a ZIP file to S3 and generate a presigned URL.
|
||||
"""
|
||||
file_name = (
|
||||
f"{workspace_id}/export-{slug}-{token_id[:6]}-{str(timezone.now().date())}.zip"
|
||||
)
|
||||
file_name = f"{workspace_id}/export-{slug}-{token_id[:6]}-{str(timezone.now().date())}.zip"
|
||||
expires_in = 7 * 24 * 60 * 60
|
||||
|
||||
if settings.USE_MINIO:
|
||||
|
|
@ -122,7 +118,7 @@ def upload_to_s3(
|
|||
# Generate presigned url for the uploaded file with different base
|
||||
presign_s3 = boto3.client(
|
||||
"s3",
|
||||
endpoint_url=f"{settings.AWS_S3_URL_PROTOCOL}//{str(settings.AWS_S3_CUSTOM_DOMAIN).replace('/uploads', '')}/",
|
||||
endpoint_url=f"{settings.AWS_S3_URL_PROTOCOL}//{str(settings.AWS_S3_CUSTOM_DOMAIN).replace('/uploads', '')}/", # noqa: E501
|
||||
aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
|
||||
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
|
||||
config=Config(signature_version="s3v4"),
|
||||
|
|
@ -260,11 +256,7 @@ def update_json_row(rows: List[dict], row: dict) -> None:
|
|||
Update the json row with the new assignee and label.
|
||||
"""
|
||||
matched_index = next(
|
||||
(
|
||||
index
|
||||
for index, existing_row in enumerate(rows)
|
||||
if existing_row["ID"] == row["ID"]
|
||||
),
|
||||
(index for index, existing_row in enumerate(rows) if existing_row["ID"] == row["ID"]),
|
||||
None,
|
||||
)
|
||||
|
||||
|
|
@ -275,13 +267,9 @@ def update_json_row(rows: List[dict], row: dict) -> None:
|
|||
)
|
||||
assignee, label = row["Assignee"], row["Labels"]
|
||||
|
||||
if assignee is not None and (
|
||||
existing_assignees is None or label not in existing_assignees
|
||||
):
|
||||
if assignee is not None and (existing_assignees is None or label not in existing_assignees):
|
||||
rows[matched_index]["Assignee"] += f", {assignee}"
|
||||
if label is not None and (
|
||||
existing_labels is None or label not in existing_labels
|
||||
):
|
||||
if label is not None and (existing_labels is None or label not in existing_labels):
|
||||
rows[matched_index]["Labels"] += f", {label}"
|
||||
else:
|
||||
rows.append(row)
|
||||
|
|
@ -300,13 +288,9 @@ def update_table_row(rows: List[List[str]], row: List[str]) -> None:
|
|||
existing_assignees, existing_labels = rows[matched_index][7:9]
|
||||
assignee, label = row[7:9]
|
||||
|
||||
if assignee is not None and (
|
||||
existing_assignees is None or label not in existing_assignees
|
||||
):
|
||||
if assignee is not None and (existing_assignees is None or label not in existing_assignees):
|
||||
rows[matched_index][8] += f", {assignee}"
|
||||
if label is not None and (
|
||||
existing_labels is None or label not in existing_labels
|
||||
):
|
||||
if label is not None and (existing_labels is None or label not in existing_labels):
|
||||
rows[matched_index][8] += f", {label}"
|
||||
else:
|
||||
rows.append(row)
|
||||
|
|
@ -465,9 +449,7 @@ def issue_export_task(
|
|||
"updated_at": issue.updated_at,
|
||||
"completed_at": issue.completed_at,
|
||||
"archived_at": issue.archived_at,
|
||||
"module_name": [
|
||||
module.module.name for module in issue.issue_module.all()
|
||||
],
|
||||
"module_name": [module.module.name for module in issue.issue_module.all()],
|
||||
"created_by": get_created_by(issue),
|
||||
"labels": [label.name for label in issue.label_details],
|
||||
"comments": [
|
||||
|
|
@ -478,14 +460,9 @@ def issue_export_task(
|
|||
}
|
||||
for comment in issue.issue_comments.all()
|
||||
],
|
||||
"estimate": issue.estimate_point.value
|
||||
if issue.estimate_point and issue.estimate_point.value
|
||||
else "",
|
||||
"estimate": issue.estimate_point.value if issue.estimate_point and issue.estimate_point.value else "",
|
||||
"link": [link.url for link in issue.issue_link.all()],
|
||||
"assignees": [
|
||||
f"{assignee.first_name} {assignee.last_name}"
|
||||
for assignee in issue.assignee_details
|
||||
],
|
||||
"assignees": [f"{assignee.first_name} {assignee.last_name}" for assignee in issue.assignee_details],
|
||||
"subscribers_count": issue.issue_subscribers.count(),
|
||||
"attachment_count": len(attachments),
|
||||
"attachment_links": [
|
||||
|
|
|
|||
|
|
@ -17,9 +17,6 @@ from plane.db.models import FileAsset
|
|||
def delete_unuploaded_file_asset():
|
||||
"""This task deletes unuploaded file assets older than a certain number of days."""
|
||||
FileAsset.objects.filter(
|
||||
Q(
|
||||
created_at__lt=timezone.now()
|
||||
- timedelta(days=int(os.environ.get("UNUPLOADED_ASSET_DELETE_DAYS", "7")))
|
||||
)
|
||||
Q(created_at__lt=timezone.now() - timedelta(days=int(os.environ.get("UNUPLOADED_ASSET_DELETE_DAYS", "7"))))
|
||||
& Q(is_uploaded=False)
|
||||
).delete()
|
||||
|
|
|
|||
|
|
@ -18,9 +18,7 @@ from plane.utils.exception_logger import log_exception
|
|||
@shared_task
|
||||
def forgot_password(first_name, email, uidb64, token, current_site):
|
||||
try:
|
||||
relative_link = (
|
||||
f"/accounts/reset-password/?uidb64={uidb64}&token={token}&email={email}"
|
||||
)
|
||||
relative_link = f"/accounts/reset-password/?uidb64={uidb64}&token={token}&email={email}"
|
||||
abs_url = str(current_site) + relative_link
|
||||
|
||||
(
|
||||
|
|
|
|||
|
|
@ -81,14 +81,8 @@ def track_description(
|
|||
issue_activities,
|
||||
epoch,
|
||||
):
|
||||
if current_instance.get("description_html") != requested_data.get(
|
||||
"description_html"
|
||||
):
|
||||
last_activity = (
|
||||
IssueActivity.objects.filter(issue_id=issue_id)
|
||||
.order_by("-created_at")
|
||||
.first()
|
||||
)
|
||||
if current_instance.get("description_html") != requested_data.get("description_html"):
|
||||
last_activity = IssueActivity.objects.filter(issue_id=issue_id).order_by("-created_at").first()
|
||||
if (
|
||||
last_activity is not None
|
||||
and last_activity.field == "description"
|
||||
|
|
@ -124,12 +118,8 @@ def track_parent(
|
|||
issue_activities,
|
||||
epoch,
|
||||
):
|
||||
current_parent_id = current_instance.get("parent_id") or current_instance.get(
|
||||
"parent"
|
||||
)
|
||||
requested_parent_id = requested_data.get("parent_id") or requested_data.get(
|
||||
"parent"
|
||||
)
|
||||
current_parent_id = current_instance.get("parent_id") or current_instance.get("parent")
|
||||
requested_parent_id = requested_data.get("parent_id") or requested_data.get("parent")
|
||||
|
||||
# Validate UUIDs before database queries
|
||||
if current_parent_id is not None and not is_valid_uuid(current_parent_id):
|
||||
|
|
@ -138,17 +128,8 @@ def track_parent(
|
|||
return
|
||||
|
||||
if current_parent_id != requested_parent_id:
|
||||
old_parent = (
|
||||
Issue.objects.filter(pk=current_parent_id).first()
|
||||
if current_parent_id is not None
|
||||
else None
|
||||
)
|
||||
new_parent = (
|
||||
Issue.objects.filter(pk=requested_parent_id).first()
|
||||
if requested_parent_id is not None
|
||||
else None
|
||||
)
|
||||
|
||||
old_parent = Issue.objects.filter(pk=current_parent_id).first() if current_parent_id is not None else None
|
||||
new_parent = Issue.objects.filter(pk=requested_parent_id).first() if requested_parent_id is not None else None
|
||||
|
||||
issue_activities.append(
|
||||
IssueActivity(
|
||||
|
|
@ -156,14 +137,10 @@ def track_parent(
|
|||
actor_id=actor_id,
|
||||
verb="updated",
|
||||
old_value=(
|
||||
f"{old_parent.project.identifier}-{old_parent.sequence_id}"
|
||||
if old_parent is not None
|
||||
else ""
|
||||
f"{old_parent.project.identifier}-{old_parent.sequence_id}" if old_parent is not None else ""
|
||||
),
|
||||
new_value=(
|
||||
f"{new_parent.project.identifier}-{new_parent.sequence_id}"
|
||||
if new_parent is not None
|
||||
else ""
|
||||
f"{new_parent.project.identifier}-{new_parent.sequence_id}" if new_parent is not None else ""
|
||||
),
|
||||
field="parent",
|
||||
project_id=project_id,
|
||||
|
|
@ -263,15 +240,9 @@ def track_target_date(
|
|||
actor_id=actor_id,
|
||||
verb="updated",
|
||||
old_value=(
|
||||
current_instance.get("target_date")
|
||||
if current_instance.get("target_date") is not None
|
||||
else ""
|
||||
),
|
||||
new_value=(
|
||||
requested_data.get("target_date")
|
||||
if requested_data.get("target_date") is not None
|
||||
else ""
|
||||
current_instance.get("target_date") if current_instance.get("target_date") is not None else ""
|
||||
),
|
||||
new_value=(requested_data.get("target_date") if requested_data.get("target_date") is not None else ""),
|
||||
field="target_date",
|
||||
project_id=project_id,
|
||||
workspace_id=workspace_id,
|
||||
|
|
@ -299,15 +270,9 @@ def track_start_date(
|
|||
actor_id=actor_id,
|
||||
verb="updated",
|
||||
old_value=(
|
||||
current_instance.get("start_date")
|
||||
if current_instance.get("start_date") is not None
|
||||
else ""
|
||||
),
|
||||
new_value=(
|
||||
requested_data.get("start_date")
|
||||
if requested_data.get("start_date") is not None
|
||||
else ""
|
||||
current_instance.get("start_date") if current_instance.get("start_date") is not None else ""
|
||||
),
|
||||
new_value=(requested_data.get("start_date") if requested_data.get("start_date") is not None else ""),
|
||||
field="start_date",
|
||||
project_id=project_id,
|
||||
workspace_id=workspace_id,
|
||||
|
|
@ -328,7 +293,6 @@ def track_labels(
|
|||
issue_activities,
|
||||
epoch,
|
||||
):
|
||||
|
||||
# Labels
|
||||
requested_labels = extract_ids(requested_data, "label_ids", "labels")
|
||||
current_labels = extract_ids(current_instance, "label_ids", "labels")
|
||||
|
|
@ -437,9 +401,7 @@ def track_assignees(
|
|||
)
|
||||
|
||||
# Create assignees subscribers to the issue and ignore if already
|
||||
IssueSubscriber.objects.bulk_create(
|
||||
bulk_subscribers, batch_size=10, ignore_conflicts=True
|
||||
)
|
||||
IssueSubscriber.objects.bulk_create(bulk_subscribers, batch_size=10, ignore_conflicts=True)
|
||||
|
||||
for dropped_assignee in dropped_assginees:
|
||||
# validate uuids
|
||||
|
|
@ -476,16 +438,12 @@ def track_estimate_points(
|
|||
):
|
||||
if current_instance.get("estimate_point") != requested_data.get("estimate_point"):
|
||||
old_estimate = (
|
||||
EstimatePoint.objects.filter(
|
||||
pk=current_instance.get("estimate_point")
|
||||
).first()
|
||||
EstimatePoint.objects.filter(pk=current_instance.get("estimate_point")).first()
|
||||
if current_instance.get("estimate_point") is not None
|
||||
else None
|
||||
)
|
||||
new_estimate = (
|
||||
EstimatePoint.objects.filter(
|
||||
pk=requested_data.get("estimate_point")
|
||||
).first()
|
||||
EstimatePoint.objects.filter(pk=requested_data.get("estimate_point")).first()
|
||||
if requested_data.get("estimate_point") is not None
|
||||
else None
|
||||
)
|
||||
|
|
@ -500,9 +458,7 @@ def track_estimate_points(
|
|||
else None
|
||||
),
|
||||
new_identifier=(
|
||||
requested_data.get("estimate_point")
|
||||
if requested_data.get("estimate_point") is not None
|
||||
else None
|
||||
requested_data.get("estimate_point") if requested_data.get("estimate_point") is not None else None
|
||||
),
|
||||
old_value=old_estimate.value if old_estimate else None,
|
||||
new_value=new_estimate.value if new_estimate else None,
|
||||
|
|
@ -575,9 +531,7 @@ def track_closed_to(
|
|||
epoch,
|
||||
):
|
||||
if requested_data.get("closed_to") is not None:
|
||||
updated_state = State.objects.get(
|
||||
pk=requested_data.get("closed_to"), project_id=project_id
|
||||
)
|
||||
updated_state = State.objects.get(pk=requested_data.get("closed_to"), project_id=project_id)
|
||||
issue_activities.append(
|
||||
IssueActivity(
|
||||
issue_id=issue_id,
|
||||
|
|
@ -664,9 +618,7 @@ def update_issue_activity(
|
|||
}
|
||||
|
||||
requested_data = json.loads(requested_data) if requested_data is not None else None
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
|
||||
for key in requested_data:
|
||||
func = ISSUE_ACTIVITY_MAPPER.get(key)
|
||||
|
|
@ -718,9 +670,7 @@ def create_comment_activity(
|
|||
epoch,
|
||||
):
|
||||
requested_data = json.loads(requested_data) if requested_data is not None else None
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
|
||||
issue_activities.append(
|
||||
IssueActivity(
|
||||
|
|
@ -750,9 +700,7 @@ def update_comment_activity(
|
|||
epoch,
|
||||
):
|
||||
requested_data = json.loads(requested_data) if requested_data is not None else None
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
|
||||
if current_instance.get("comment_html") != requested_data.get("comment_html"):
|
||||
issue_activities.append(
|
||||
|
|
@ -811,21 +759,15 @@ def create_cycle_issue_activity(
|
|||
epoch,
|
||||
):
|
||||
requested_data = json.loads(requested_data) if requested_data is not None else None
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
|
||||
# Updated Records:
|
||||
updated_records = current_instance.get("updated_cycle_issues", [])
|
||||
created_records = json.loads(current_instance.get("created_cycle_issues", []))
|
||||
|
||||
for updated_record in updated_records:
|
||||
old_cycle = Cycle.objects.filter(
|
||||
pk=updated_record.get("old_cycle_id", None)
|
||||
).first()
|
||||
new_cycle = Cycle.objects.filter(
|
||||
pk=updated_record.get("new_cycle_id", None)
|
||||
).first()
|
||||
old_cycle = Cycle.objects.filter(pk=updated_record.get("old_cycle_id", None)).first()
|
||||
new_cycle = Cycle.objects.filter(pk=updated_record.get("new_cycle_id", None)).first()
|
||||
issue = Issue.objects.filter(pk=updated_record.get("issue_id")).first()
|
||||
if issue:
|
||||
issue.updated_at = timezone.now()
|
||||
|
|
@ -850,12 +792,8 @@ def create_cycle_issue_activity(
|
|||
)
|
||||
|
||||
for created_record in created_records:
|
||||
cycle = Cycle.objects.filter(
|
||||
pk=created_record.get("fields").get("cycle")
|
||||
).first()
|
||||
issue = Issue.objects.filter(
|
||||
pk=created_record.get("fields").get("issue")
|
||||
).first()
|
||||
cycle = Cycle.objects.filter(pk=created_record.get("fields").get("cycle")).first()
|
||||
issue = Issue.objects.filter(pk=created_record.get("fields").get("issue")).first()
|
||||
if issue:
|
||||
issue.updated_at = timezone.now()
|
||||
issue.save(update_fields=["updated_at"])
|
||||
|
|
@ -888,9 +826,7 @@ def delete_cycle_issue_activity(
|
|||
epoch,
|
||||
):
|
||||
requested_data = json.loads(requested_data) if requested_data is not None else None
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
|
||||
cycle_id = requested_data.get("cycle_id", "")
|
||||
cycle_name = requested_data.get("cycle_name", "")
|
||||
|
|
@ -962,9 +898,7 @@ def delete_module_issue_activity(
|
|||
epoch,
|
||||
):
|
||||
requested_data = json.loads(requested_data) if requested_data is not None else None
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
module_name = current_instance.get("module_name")
|
||||
current_issue = Issue.objects.filter(pk=issue_id).first()
|
||||
if current_issue:
|
||||
|
|
@ -981,11 +915,7 @@ def delete_module_issue_activity(
|
|||
project_id=project_id,
|
||||
workspace_id=workspace_id,
|
||||
comment=f"removed this issue from {module_name}",
|
||||
old_identifier=(
|
||||
requested_data.get("module_id")
|
||||
if requested_data.get("module_id") is not None
|
||||
else None
|
||||
),
|
||||
old_identifier=(requested_data.get("module_id") if requested_data.get("module_id") is not None else None),
|
||||
epoch=epoch,
|
||||
)
|
||||
)
|
||||
|
|
@ -1002,9 +932,7 @@ def create_link_activity(
|
|||
epoch,
|
||||
):
|
||||
requested_data = json.loads(requested_data) if requested_data is not None else None
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
|
||||
issue_activities.append(
|
||||
IssueActivity(
|
||||
|
|
@ -1033,9 +961,7 @@ def update_link_activity(
|
|||
epoch,
|
||||
):
|
||||
requested_data = json.loads(requested_data) if requested_data is not None else None
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
|
||||
if current_instance.get("url") != requested_data.get("url"):
|
||||
issue_activities.append(
|
||||
|
|
@ -1066,9 +992,7 @@ def delete_link_activity(
|
|||
issue_activities,
|
||||
epoch,
|
||||
):
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
|
||||
issue_activities.append(
|
||||
IssueActivity(
|
||||
|
|
@ -1097,9 +1021,7 @@ def create_attachment_activity(
|
|||
epoch,
|
||||
):
|
||||
requested_data = json.loads(requested_data) if requested_data is not None else None
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
|
||||
issue_activities.append(
|
||||
IssueActivity(
|
||||
|
|
@ -1191,9 +1113,7 @@ def delete_issue_reaction_activity(
|
|||
issue_activities,
|
||||
epoch,
|
||||
):
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
if current_instance and current_instance.get("reaction") is not None:
|
||||
issue_activities.append(
|
||||
IssueActivity(
|
||||
|
|
@ -1235,11 +1155,7 @@ def create_comment_reaction_activity(
|
|||
.first()
|
||||
)
|
||||
comment = IssueComment.objects.get(pk=comment_id, project_id=project_id)
|
||||
if (
|
||||
comment is not None
|
||||
and comment_reaction_id is not None
|
||||
and comment_id is not None
|
||||
):
|
||||
if comment is not None and comment_reaction_id is not None and comment_id is not None:
|
||||
issue_activities.append(
|
||||
IssueActivity(
|
||||
issue_id=comment.issue_id,
|
||||
|
|
@ -1268,14 +1184,10 @@ def delete_comment_reaction_activity(
|
|||
issue_activities,
|
||||
epoch,
|
||||
):
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
if current_instance and current_instance.get("reaction") is not None:
|
||||
issue_id = (
|
||||
IssueComment.objects.filter(
|
||||
pk=current_instance.get("comment_id"), project_id=project_id
|
||||
)
|
||||
IssueComment.objects.filter(pk=current_instance.get("comment_id"), project_id=project_id)
|
||||
.values_list("issue_id", flat=True)
|
||||
.first()
|
||||
)
|
||||
|
|
@ -1338,9 +1250,7 @@ def delete_issue_vote_activity(
|
|||
issue_activities,
|
||||
epoch,
|
||||
):
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
if current_instance and current_instance.get("vote") is not None:
|
||||
issue_activities.append(
|
||||
IssueActivity(
|
||||
|
|
@ -1371,9 +1281,7 @@ def create_issue_relation_activity(
|
|||
epoch,
|
||||
):
|
||||
requested_data = json.loads(requested_data) if requested_data is not None else None
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
if current_instance is None and requested_data.get("issues") is not None:
|
||||
for related_issue in requested_data.get("issues"):
|
||||
issue = Issue.objects.get(pk=related_issue)
|
||||
|
|
@ -1422,9 +1330,7 @@ def delete_issue_relation_activity(
|
|||
epoch,
|
||||
):
|
||||
requested_data = json.loads(requested_data) if requested_data is not None else None
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
issue = Issue.objects.get(pk=requested_data.get("related_issue"))
|
||||
issue_activities.append(
|
||||
IssueActivity(
|
||||
|
|
@ -1502,13 +1408,8 @@ def update_draft_issue_activity(
|
|||
epoch,
|
||||
):
|
||||
requested_data = json.loads(requested_data) if requested_data is not None else None
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
if (
|
||||
requested_data.get("is_draft") is not None
|
||||
and requested_data.get("is_draft") is False
|
||||
):
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
if requested_data.get("is_draft") is not None and requested_data.get("is_draft") is False:
|
||||
issue_activities.append(
|
||||
IssueActivity(
|
||||
issue_id=issue_id,
|
||||
|
|
@ -1569,9 +1470,7 @@ def create_intake_activity(
|
|||
epoch,
|
||||
):
|
||||
requested_data = json.loads(requested_data) if requested_data is not None else None
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
status_dict = {
|
||||
-2: "Pending",
|
||||
-1: "Rejected",
|
||||
|
|
|
|||
|
|
@ -39,15 +39,9 @@ def archive_old_issues():
|
|||
state__group__in=["completed", "cancelled"],
|
||||
),
|
||||
Q(issue_cycle__isnull=True)
|
||||
| (
|
||||
Q(issue_cycle__cycle__end_date__lt=timezone.now())
|
||||
& Q(issue_cycle__isnull=False)
|
||||
),
|
||||
| (Q(issue_cycle__cycle__end_date__lt=timezone.now()) & Q(issue_cycle__isnull=False)),
|
||||
Q(issue_module__isnull=True)
|
||||
| (
|
||||
Q(issue_module__module__target_date__lt=timezone.now())
|
||||
& Q(issue_module__isnull=False)
|
||||
),
|
||||
| (Q(issue_module__module__target_date__lt=timezone.now()) & Q(issue_module__isnull=False)),
|
||||
).filter(
|
||||
Q(issue_intake__status=1)
|
||||
| Q(issue_intake__status=-1)
|
||||
|
|
@ -67,15 +61,11 @@ def archive_old_issues():
|
|||
|
||||
# Bulk Update the issues and log the activity
|
||||
if issues_to_update:
|
||||
Issue.objects.bulk_update(
|
||||
issues_to_update, ["archived_at"], batch_size=100
|
||||
)
|
||||
Issue.objects.bulk_update(issues_to_update, ["archived_at"], batch_size=100)
|
||||
_ = [
|
||||
issue_activity.delay(
|
||||
type="issue.activity.updated",
|
||||
requested_data=json.dumps(
|
||||
{"archived_at": str(archive_at), "automation": True}
|
||||
),
|
||||
requested_data=json.dumps({"archived_at": str(archive_at), "automation": True}),
|
||||
actor_id=str(project.created_by_id),
|
||||
issue_id=issue.id,
|
||||
project_id=project_id,
|
||||
|
|
@ -95,9 +85,7 @@ def archive_old_issues():
|
|||
def close_old_issues():
|
||||
try:
|
||||
# Get all the projects whose close_in is greater than 0
|
||||
projects = Project.objects.filter(close_in__gt=0).select_related(
|
||||
"default_state"
|
||||
)
|
||||
projects = Project.objects.filter(close_in__gt=0).select_related("default_state")
|
||||
|
||||
for project in projects:
|
||||
project_id = project.id
|
||||
|
|
@ -112,15 +100,9 @@ def close_old_issues():
|
|||
state__group__in=["backlog", "unstarted", "started"],
|
||||
),
|
||||
Q(issue_cycle__isnull=True)
|
||||
| (
|
||||
Q(issue_cycle__cycle__end_date__lt=timezone.now())
|
||||
& Q(issue_cycle__isnull=False)
|
||||
),
|
||||
| (Q(issue_cycle__cycle__end_date__lt=timezone.now()) & Q(issue_cycle__isnull=False)),
|
||||
Q(issue_module__isnull=True)
|
||||
| (
|
||||
Q(issue_module__module__target_date__lt=timezone.now())
|
||||
& Q(issue_module__isnull=False)
|
||||
),
|
||||
| (Q(issue_module__module__target_date__lt=timezone.now()) & Q(issue_module__isnull=False)),
|
||||
).filter(
|
||||
Q(issue_intake__status=1)
|
||||
| Q(issue_intake__status=-1)
|
||||
|
|
@ -142,15 +124,11 @@ def close_old_issues():
|
|||
|
||||
# Bulk Update the issues and log the activity
|
||||
if issues_to_update:
|
||||
Issue.objects.bulk_update(
|
||||
issues_to_update, ["state"], batch_size=100
|
||||
)
|
||||
Issue.objects.bulk_update(issues_to_update, ["state"], batch_size=100)
|
||||
[
|
||||
issue_activity.delay(
|
||||
type="issue.activity.updated",
|
||||
requested_data=json.dumps(
|
||||
{"closed_to": str(issue.state_id)}
|
||||
),
|
||||
requested_data=json.dumps({"closed_to": str(issue.state_id)}),
|
||||
actor_id=str(project.created_by_id),
|
||||
issue_id=issue.id,
|
||||
project_id=project_id,
|
||||
|
|
|
|||
|
|
@ -70,9 +70,7 @@ def sync_issue_description_version(batch_size=5000, offset=0, countdown=300):
|
|||
for issue in issues_batch:
|
||||
# Validate required fields
|
||||
if not issue.workspace_id or not issue.project_id:
|
||||
logging.warning(
|
||||
f"Skipping {issue.id} - missing workspace_id or project_id"
|
||||
)
|
||||
logging.warning(f"Skipping {issue.id} - missing workspace_id or project_id")
|
||||
continue
|
||||
|
||||
# Determine owned_by_id
|
||||
|
|
@ -120,6 +118,4 @@ def sync_issue_description_version(batch_size=5000, offset=0, countdown=300):
|
|||
|
||||
@shared_task
|
||||
def schedule_issue_description_version(batch_size=5000, countdown=300):
|
||||
sync_issue_description_version.delay(
|
||||
batch_size=int(batch_size), countdown=countdown
|
||||
)
|
||||
sync_issue_description_version.delay(batch_size=int(batch_size), countdown=countdown)
|
||||
|
|
|
|||
|
|
@ -15,10 +15,7 @@ def should_update_existing_version(
|
|||
return
|
||||
|
||||
time_difference = (timezone.now() - version.last_saved_at).total_seconds()
|
||||
return (
|
||||
str(version.owned_by_id) == str(user_id)
|
||||
and time_difference <= max_time_difference
|
||||
)
|
||||
return str(version.owned_by_id) == str(user_id) and time_difference <= max_time_difference
|
||||
|
||||
|
||||
def update_existing_version(version: IssueDescriptionVersion, issue) -> None:
|
||||
|
|
@ -40,9 +37,7 @@ def update_existing_version(version: IssueDescriptionVersion, issue) -> None:
|
|||
|
||||
|
||||
@shared_task
|
||||
def issue_description_version_task(
|
||||
updated_issue, issue_id, user_id, is_creating=False
|
||||
) -> Optional[bool]:
|
||||
def issue_description_version_task(updated_issue, issue_id, user_id, is_creating=False) -> Optional[bool]:
|
||||
try:
|
||||
# Parse updated issue data
|
||||
current_issue: Dict = json.loads(updated_issue) if updated_issue else {}
|
||||
|
|
@ -51,18 +46,13 @@ def issue_description_version_task(
|
|||
issue = Issue.objects.get(id=issue_id)
|
||||
|
||||
# Check if description has changed
|
||||
if (
|
||||
current_issue.get("description_html") == issue.description_html
|
||||
and not is_creating
|
||||
):
|
||||
if current_issue.get("description_html") == issue.description_html and not is_creating:
|
||||
return
|
||||
|
||||
with transaction.atomic():
|
||||
# Get latest version
|
||||
latest_version = (
|
||||
IssueDescriptionVersion.objects.filter(issue_id=issue_id)
|
||||
.order_by("-last_saved_at")
|
||||
.first()
|
||||
IssueDescriptionVersion.objects.filter(issue_id=issue_id).order_by("-last_saved_at").first()
|
||||
)
|
||||
|
||||
# Determine whether to update existing or create new version
|
||||
|
|
|
|||
|
|
@ -38,24 +38,17 @@ def issue_task(updated_issue, issue_id, user_id):
|
|||
updated_current_issue[key] = value
|
||||
|
||||
if updated_current_issue:
|
||||
issue_version = (
|
||||
IssueVersion.objects.filter(issue_id=issue_id)
|
||||
.order_by("-last_saved_at")
|
||||
.first()
|
||||
)
|
||||
issue_version = IssueVersion.objects.filter(issue_id=issue_id).order_by("-last_saved_at").first()
|
||||
|
||||
if (
|
||||
issue_version
|
||||
and str(issue_version.owned_by) == str(user_id)
|
||||
and (timezone.now() - issue_version.last_saved_at).total_seconds()
|
||||
<= 600
|
||||
and (timezone.now() - issue_version.last_saved_at).total_seconds() <= 600
|
||||
):
|
||||
for key, value in updated_current_issue.items():
|
||||
setattr(issue_version, key, value)
|
||||
issue_version.last_saved_at = timezone.now()
|
||||
issue_version.save(
|
||||
update_fields=list(updated_current_issue.keys()) + ["last_saved_at"]
|
||||
)
|
||||
issue_version.save(update_fields=list(updated_current_issue.keys()) + ["last_saved_at"])
|
||||
else:
|
||||
IssueVersion.log_issue_version(issue, user_id)
|
||||
|
||||
|
|
@ -88,16 +81,11 @@ def get_owner_id(issue: Issue) -> Optional[int]:
|
|||
def get_related_data(issue_ids: List[UUID]) -> Dict:
|
||||
"""Get related data for the given issue IDs"""
|
||||
|
||||
cycle_issues = {
|
||||
ci.issue_id: ci.cycle_id
|
||||
for ci in CycleIssue.objects.filter(issue_id__in=issue_ids)
|
||||
}
|
||||
cycle_issues = {ci.issue_id: ci.cycle_id for ci in CycleIssue.objects.filter(issue_id__in=issue_ids)}
|
||||
|
||||
# Get assignees with proper grouping
|
||||
assignee_records = list(
|
||||
IssueAssignee.objects.filter(issue_id__in=issue_ids)
|
||||
.values_list("issue_id", "assignee_id")
|
||||
.order_by("issue_id")
|
||||
IssueAssignee.objects.filter(issue_id__in=issue_ids).values_list("issue_id", "assignee_id").order_by("issue_id")
|
||||
)
|
||||
assignees = {}
|
||||
for issue_id, group in groupby(assignee_records, key=lambda x: x[0]):
|
||||
|
|
@ -105,9 +93,7 @@ def get_related_data(issue_ids: List[UUID]) -> Dict:
|
|||
|
||||
# Get labels with proper grouping
|
||||
label_records = list(
|
||||
IssueLabel.objects.filter(issue_id__in=issue_ids)
|
||||
.values_list("issue_id", "label_id")
|
||||
.order_by("issue_id")
|
||||
IssueLabel.objects.filter(issue_id__in=issue_ids).values_list("issue_id", "label_id").order_by("issue_id")
|
||||
)
|
||||
labels = {}
|
||||
for issue_id, group in groupby(label_records, key=lambda x: x[0]):
|
||||
|
|
@ -115,9 +101,7 @@ def get_related_data(issue_ids: List[UUID]) -> Dict:
|
|||
|
||||
# Get modules with proper grouping
|
||||
module_records = list(
|
||||
ModuleIssue.objects.filter(issue_id__in=issue_ids)
|
||||
.values_list("issue_id", "module_id")
|
||||
.order_by("issue_id")
|
||||
ModuleIssue.objects.filter(issue_id__in=issue_ids).values_list("issue_id", "module_id").order_by("issue_id")
|
||||
)
|
||||
modules = {}
|
||||
for issue_id, group in groupby(module_records, key=lambda x: x[0]):
|
||||
|
|
@ -125,9 +109,7 @@ def get_related_data(issue_ids: List[UUID]) -> Dict:
|
|||
|
||||
# Get latest activities
|
||||
latest_activities = {}
|
||||
activities = IssueActivity.objects.filter(issue_id__in=issue_ids).order_by(
|
||||
"issue_id", "-created_at"
|
||||
)
|
||||
activities = IssueActivity.objects.filter(issue_id__in=issue_ids).order_by("issue_id", "-created_at")
|
||||
for issue_id, activities_group in groupby(activities, key=lambda x: x.issue_id):
|
||||
first_activity = next(activities_group, None)
|
||||
if first_activity:
|
||||
|
|
@ -147,9 +129,7 @@ def create_issue_version(issue: Issue, related_data: Dict) -> Optional[IssueVers
|
|||
|
||||
try:
|
||||
if not issue.workspace_id or not issue.project_id:
|
||||
logging.warning(
|
||||
f"Skipping issue {issue.id} - missing workspace_id or project_id"
|
||||
)
|
||||
logging.warning(f"Skipping issue {issue.id} - missing workspace_id or project_id")
|
||||
return None
|
||||
|
||||
owned_by_id = get_owner_id(issue)
|
||||
|
|
@ -209,9 +189,7 @@ def sync_issue_version(batch_size=5000, offset=0, countdown=300):
|
|||
|
||||
# Get issues batch with optimized queries
|
||||
issues_batch = list(
|
||||
base_query.order_by("created_at")
|
||||
.select_related("workspace", "project")
|
||||
.all()[offset:end_offset]
|
||||
base_query.order_by("created_at").select_related("workspace", "project").all()[offset:end_offset]
|
||||
)
|
||||
|
||||
if not issues_batch:
|
||||
|
|
|
|||
|
|
@ -56,9 +56,7 @@ def get_new_mentions(requested_instance, current_instance):
|
|||
mentions_newer = extract_mentions(requested_instance)
|
||||
|
||||
# Getting Set Difference from mentions_newer
|
||||
new_mentions = [
|
||||
mention for mention in mentions_newer if mention not in mentions_older
|
||||
]
|
||||
new_mentions = [mention for mention in mentions_newer if mention not in mentions_older]
|
||||
|
||||
return new_mentions
|
||||
|
||||
|
|
@ -73,9 +71,7 @@ def get_removed_mentions(requested_instance, current_instance):
|
|||
mentions_newer = extract_mentions(requested_instance)
|
||||
|
||||
# Getting Set Difference from mentions_newer
|
||||
removed_mentions = [
|
||||
mention for mention in mentions_older if mention not in mentions_newer
|
||||
]
|
||||
removed_mentions = [mention for mention in mentions_older if mention not in mentions_newer]
|
||||
|
||||
return removed_mentions
|
||||
|
||||
|
|
@ -87,7 +83,7 @@ def extract_mentions_as_subscribers(project_id, issue_id, mentions):
|
|||
bulk_mention_subscribers = []
|
||||
|
||||
for mention_id in mentions:
|
||||
# If the particular mention has not already been subscribed to the issue, he must be sent the mentioned notification
|
||||
# If the particular mention has not already been subscribed to the issue, he must be sent the mentioned notification # noqa: E501
|
||||
if (
|
||||
not IssueSubscriber.objects.filter(
|
||||
issue_id=issue_id, subscriber_id=mention_id, project_id=project_id
|
||||
|
|
@ -95,12 +91,8 @@ def extract_mentions_as_subscribers(project_id, issue_id, mentions):
|
|||
and not IssueAssignee.objects.filter(
|
||||
project_id=project_id, issue_id=issue_id, assignee_id=mention_id
|
||||
).exists()
|
||||
and not Issue.objects.filter(
|
||||
project_id=project_id, pk=issue_id, created_by_id=mention_id
|
||||
).exists()
|
||||
and ProjectMember.objects.filter(
|
||||
project_id=project_id, member_id=mention_id, is_active=True
|
||||
).exists()
|
||||
and not Issue.objects.filter(project_id=project_id, pk=issue_id, created_by_id=mention_id).exists()
|
||||
and ProjectMember.objects.filter(project_id=project_id, member_id=mention_id, is_active=True).exists()
|
||||
):
|
||||
project = Project.objects.get(pk=project_id)
|
||||
|
||||
|
|
@ -118,15 +110,13 @@ def extract_mentions_as_subscribers(project_id, issue_id, mentions):
|
|||
# Parse Issue Description & extracts mentions
|
||||
def extract_mentions(issue_instance):
|
||||
try:
|
||||
# issue_instance has to be a dictionary passed, containing the description_html and other set of activity data.
|
||||
# issue_instance has to be a dictionary passed, containing the description_html and other set of activity data. # noqa: E501
|
||||
mentions = []
|
||||
# Convert string to dictionary
|
||||
data = json.loads(issue_instance)
|
||||
html = data.get("description_html")
|
||||
soup = BeautifulSoup(html, "html.parser")
|
||||
mention_tags = soup.find_all(
|
||||
"mention-component", attrs={"entity_name": "user_mention"}
|
||||
)
|
||||
mention_tags = soup.find_all("mention-component", attrs={"entity_name": "user_mention"})
|
||||
|
||||
mentions = [mention_tag["entity_identifier"] for mention_tag in mention_tags]
|
||||
|
||||
|
|
@ -140,9 +130,7 @@ def extract_comment_mentions(comment_value):
|
|||
try:
|
||||
mentions = []
|
||||
soup = BeautifulSoup(comment_value, "html.parser")
|
||||
mentions_tags = soup.find_all(
|
||||
"mention-component", attrs={"entity_name": "user_mention"}
|
||||
)
|
||||
mentions_tags = soup.find_all("mention-component", attrs={"entity_name": "user_mention"})
|
||||
for mention_tag in mentions_tags:
|
||||
mentions.append(mention_tag["entity_identifier"])
|
||||
return list(set(mentions))
|
||||
|
|
@ -157,16 +145,12 @@ def get_new_comment_mentions(new_value, old_value):
|
|||
|
||||
mentions_older = extract_comment_mentions(old_value)
|
||||
# Getting Set Difference from mentions_newer
|
||||
new_mentions = [
|
||||
mention for mention in mentions_newer if mention not in mentions_older
|
||||
]
|
||||
new_mentions = [mention for mention in mentions_newer if mention not in mentions_older]
|
||||
|
||||
return new_mentions
|
||||
|
||||
|
||||
def create_mention_notification(
|
||||
project, notification_comment, issue, actor_id, mention_id, issue_id, activity
|
||||
):
|
||||
def create_mention_notification(project, notification_comment, issue, actor_id, mention_id, issue_id, activity):
|
||||
return Notification(
|
||||
workspace=project.workspace,
|
||||
sender="in_app:issue_activities:mentioned",
|
||||
|
|
@ -192,16 +176,8 @@ def create_mention_notification(
|
|||
"actor": str(activity.get("actor_id")),
|
||||
"new_value": str(activity.get("new_value")),
|
||||
"old_value": str(activity.get("old_value")),
|
||||
"old_identifier": (
|
||||
str(activity.get("old_identifier"))
|
||||
if activity.get("old_identifier")
|
||||
else None
|
||||
),
|
||||
"new_identifier": (
|
||||
str(activity.get("new_identifier"))
|
||||
if activity.get("new_identifier")
|
||||
else None
|
||||
),
|
||||
"old_identifier": (str(activity.get("old_identifier")) if activity.get("old_identifier") else None),
|
||||
"new_identifier": (str(activity.get("new_identifier")) if activity.get("new_identifier") else None),
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
@ -220,9 +196,7 @@ def notifications(
|
|||
):
|
||||
try:
|
||||
issue_activities_created = (
|
||||
json.loads(issue_activities_created)
|
||||
if issue_activities_created is not None
|
||||
else None
|
||||
json.loads(issue_activities_created) if issue_activities_created is not None else None
|
||||
)
|
||||
if type not in [
|
||||
"cycle.activity.created",
|
||||
|
|
@ -250,20 +224,14 @@ def notifications(
|
|||
"""
|
||||
|
||||
# get the list of active project members
|
||||
project_members = ProjectMember.objects.filter(
|
||||
project_id=project_id, is_active=True
|
||||
).values_list("member_id", flat=True)
|
||||
project_members = ProjectMember.objects.filter(project_id=project_id, is_active=True).values_list(
|
||||
"member_id", flat=True
|
||||
)
|
||||
|
||||
# Get new mentions from the newer instance
|
||||
new_mentions = get_new_mentions(
|
||||
requested_instance=requested_data, current_instance=current_instance
|
||||
)
|
||||
new_mentions = list(
|
||||
set(new_mentions) & {str(member) for member in project_members}
|
||||
)
|
||||
removed_mention = get_removed_mentions(
|
||||
requested_instance=requested_data, current_instance=current_instance
|
||||
)
|
||||
new_mentions = get_new_mentions(requested_instance=requested_data, current_instance=current_instance)
|
||||
new_mentions = list(set(new_mentions) & {str(member) for member in project_members})
|
||||
removed_mention = get_removed_mentions(requested_instance=requested_data, current_instance=current_instance)
|
||||
|
||||
comment_mentions = []
|
||||
all_comment_mentions = []
|
||||
|
|
@ -281,10 +249,7 @@ def notifications(
|
|||
if issue_comment is not None:
|
||||
# TODO: Maybe save the comment mentions, so that in future, we can filter out the issues based on comment mentions as well.
|
||||
|
||||
all_comment_mentions = (
|
||||
all_comment_mentions
|
||||
+ extract_comment_mentions(issue_comment_new_value)
|
||||
)
|
||||
all_comment_mentions = all_comment_mentions + extract_comment_mentions(issue_comment_new_value)
|
||||
|
||||
new_comment_mentions = get_new_comment_mentions(
|
||||
old_value=issue_comment_old_value,
|
||||
|
|
@ -292,9 +257,7 @@ def notifications(
|
|||
)
|
||||
comment_mentions = comment_mentions + new_comment_mentions
|
||||
comment_mentions = [
|
||||
mention
|
||||
for mention in comment_mentions
|
||||
if UUID(mention) in set(project_members)
|
||||
mention for mention in comment_mentions if UUID(mention) in set(project_members)
|
||||
]
|
||||
|
||||
comment_mention_subscribers = extract_mentions_as_subscribers(
|
||||
|
|
@ -303,20 +266,20 @@ def notifications(
|
|||
"""
|
||||
We will not send subscription activity notification to the below mentioned user sets
|
||||
- Those who have been newly mentioned in the issue description, we will send mention notification to them.
|
||||
- When the activity is a comment_created and there exist a mention in the comment, then we have to send the "mention_in_comment" notification
|
||||
- When the activity is a comment_updated and there exist a mention change, then also we have to send the "mention_in_comment" notification
|
||||
- When the activity is a comment_created and there exist a mention in the comment,
|
||||
then we have to send the "mention_in_comment" notification
|
||||
- When the activity is a comment_updated and there exist a mention change,
|
||||
then also we have to send the "mention_in_comment" notification
|
||||
"""
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- #
|
||||
# ---------------------------------------------------------------------------------------------------------
|
||||
issue_subscribers = list(
|
||||
IssueSubscriber.objects.filter(
|
||||
project_id=project_id,
|
||||
issue_id=issue_id,
|
||||
subscriber__in=Subquery(project_members),
|
||||
)
|
||||
.exclude(
|
||||
subscriber_id__in=list(new_mentions + comment_mentions + [actor_id])
|
||||
)
|
||||
.exclude(subscriber_id__in=list(new_mentions + comment_mentions + [actor_id]))
|
||||
.values_list("subscriber", flat=True)
|
||||
)
|
||||
|
||||
|
|
@ -344,10 +307,7 @@ def notifications(
|
|||
for subscriber in issue_subscribers:
|
||||
if issue.created_by_id and issue.created_by_id == subscriber:
|
||||
sender = "in_app:issue_activities:created"
|
||||
elif (
|
||||
subscriber in issue_assignees
|
||||
and issue.created_by_id not in issue_assignees
|
||||
):
|
||||
elif subscriber in issue_assignees and issue.created_by_id not in issue_assignees:
|
||||
sender = "in_app:issue_activities:assigned"
|
||||
else:
|
||||
sender = "in_app:issue_activities:subscribed"
|
||||
|
|
@ -365,10 +325,7 @@ def notifications(
|
|||
|
||||
# Check if the value should be sent or not
|
||||
send_email = False
|
||||
if (
|
||||
issue_activity.get("field") == "state"
|
||||
and preference.state_change
|
||||
):
|
||||
if issue_activity.get("field") == "state" and preference.state_change:
|
||||
send_email = True
|
||||
elif (
|
||||
issue_activity.get("field") == "state"
|
||||
|
|
@ -380,9 +337,7 @@ def notifications(
|
|||
).exists()
|
||||
):
|
||||
send_email = True
|
||||
elif (
|
||||
issue_activity.get("field") == "comment" and preference.comment
|
||||
):
|
||||
elif issue_activity.get("field") == "comment" and preference.comment:
|
||||
send_email = True
|
||||
elif preference.property_change:
|
||||
send_email = True
|
||||
|
|
@ -429,9 +384,7 @@ def notifications(
|
|||
"new_value": str(issue_activity.get("new_value")),
|
||||
"old_value": str(issue_activity.get("old_value")),
|
||||
"issue_comment": str(
|
||||
issue_comment.comment_stripped
|
||||
if issue_comment is not None
|
||||
else ""
|
||||
issue_comment.comment_stripped if issue_comment is not None else ""
|
||||
),
|
||||
"old_identifier": (
|
||||
str(issue_activity.get("old_identifier"))
|
||||
|
|
@ -461,9 +414,7 @@ def notifications(
|
|||
"name": str(issue.name),
|
||||
"identifier": str(issue.project.identifier),
|
||||
"project_id": str(issue.project.id),
|
||||
"workspace_slug": str(
|
||||
issue.project.workspace.slug
|
||||
),
|
||||
"workspace_slug": str(issue.project.workspace.slug),
|
||||
"sequence_id": issue.sequence_id,
|
||||
"state_name": issue.state.name,
|
||||
"state_group": issue.state.group,
|
||||
|
|
@ -473,16 +424,10 @@ def notifications(
|
|||
"verb": str(issue_activity.get("verb")),
|
||||
"field": str(issue_activity.get("field")),
|
||||
"actor": str(issue_activity.get("actor_id")),
|
||||
"new_value": str(
|
||||
issue_activity.get("new_value")
|
||||
),
|
||||
"old_value": str(
|
||||
issue_activity.get("old_value")
|
||||
),
|
||||
"new_value": str(issue_activity.get("new_value")),
|
||||
"old_value": str(issue_activity.get("old_value")),
|
||||
"issue_comment": str(
|
||||
issue_comment.comment_stripped
|
||||
if issue_comment is not None
|
||||
else ""
|
||||
issue_comment.comment_stripped if issue_comment is not None else ""
|
||||
),
|
||||
"old_identifier": (
|
||||
str(issue_activity.get("old_identifier"))
|
||||
|
|
@ -494,15 +439,13 @@ def notifications(
|
|||
if issue_activity.get("new_identifier")
|
||||
else None
|
||||
),
|
||||
"activity_time": issue_activity.get(
|
||||
"created_at"
|
||||
),
|
||||
"activity_time": issue_activity.get("created_at"),
|
||||
},
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------- #
|
||||
# -------------------------------------------------------------------------------------------------------- #
|
||||
|
||||
# Add Mentioned as Issue Subscribers
|
||||
IssueSubscriber.objects.bulk_create(
|
||||
|
|
@ -511,24 +454,18 @@ def notifications(
|
|||
ignore_conflicts=True,
|
||||
)
|
||||
|
||||
last_activity = (
|
||||
IssueActivity.objects.filter(issue_id=issue_id)
|
||||
.order_by("-created_at")
|
||||
.first()
|
||||
)
|
||||
last_activity = IssueActivity.objects.filter(issue_id=issue_id).order_by("-created_at").first()
|
||||
|
||||
actor = User.objects.get(pk=actor_id)
|
||||
|
||||
for mention_id in comment_mentions:
|
||||
if mention_id != actor_id:
|
||||
preference = UserNotificationPreference.objects.get(
|
||||
user_id=mention_id
|
||||
)
|
||||
preference = UserNotificationPreference.objects.get(user_id=mention_id)
|
||||
for issue_activity in issue_activities_created:
|
||||
notification = create_mention_notification(
|
||||
project=project,
|
||||
issue=issue,
|
||||
notification_comment=f"{actor.display_name} has mentioned you in a comment in issue {issue.name}",
|
||||
notification_comment=f"{actor.display_name} has mentioned you in a comment in issue {issue.name}", # noqa: E501
|
||||
actor_id=actor_id,
|
||||
mention_id=mention_id,
|
||||
issue_id=issue_id,
|
||||
|
|
@ -552,40 +489,26 @@ def notifications(
|
|||
"state_name": issue.state.name,
|
||||
"state_group": issue.state.group,
|
||||
"project_id": str(issue.project.id),
|
||||
"workspace_slug": str(
|
||||
issue.project.workspace.slug
|
||||
),
|
||||
"workspace_slug": str(issue.project.workspace.slug),
|
||||
},
|
||||
"issue_activity": {
|
||||
"id": str(issue_activity.get("id")),
|
||||
"verb": str(issue_activity.get("verb")),
|
||||
"field": str("mention"),
|
||||
"actor": str(
|
||||
issue_activity.get("actor_id")
|
||||
),
|
||||
"new_value": str(
|
||||
issue_activity.get("new_value")
|
||||
),
|
||||
"old_value": str(
|
||||
issue_activity.get("old_value")
|
||||
),
|
||||
"actor": str(issue_activity.get("actor_id")),
|
||||
"new_value": str(issue_activity.get("new_value")),
|
||||
"old_value": str(issue_activity.get("old_value")),
|
||||
"old_identifier": (
|
||||
str(
|
||||
issue_activity.get("old_identifier")
|
||||
)
|
||||
str(issue_activity.get("old_identifier"))
|
||||
if issue_activity.get("old_identifier")
|
||||
else None
|
||||
),
|
||||
"new_identifier": (
|
||||
str(
|
||||
issue_activity.get("new_identifier")
|
||||
)
|
||||
str(issue_activity.get("new_identifier"))
|
||||
if issue_activity.get("new_identifier")
|
||||
else None
|
||||
),
|
||||
"activity_time": issue_activity.get(
|
||||
"created_at"
|
||||
),
|
||||
"activity_time": issue_activity.get("created_at"),
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
@ -594,9 +517,7 @@ def notifications(
|
|||
|
||||
for mention_id in new_mentions:
|
||||
if mention_id != actor_id:
|
||||
preference = UserNotificationPreference.objects.get(
|
||||
user_id=mention_id
|
||||
)
|
||||
preference = UserNotificationPreference.objects.get(user_id=mention_id)
|
||||
if (
|
||||
last_activity is not None
|
||||
and last_activity.field == "description"
|
||||
|
|
@ -621,9 +542,7 @@ def notifications(
|
|||
"state_name": issue.state.name,
|
||||
"state_group": issue.state.group,
|
||||
"project_id": str(issue.project.id),
|
||||
"workspace_slug": str(
|
||||
issue.project.workspace.slug
|
||||
),
|
||||
"workspace_slug": str(issue.project.workspace.slug),
|
||||
},
|
||||
"issue_activity": {
|
||||
"id": str(last_activity.id),
|
||||
|
|
@ -670,22 +589,16 @@ def notifications(
|
|||
"new_value": str(last_activity.new_value),
|
||||
"old_value": str(last_activity.old_value),
|
||||
"old_identifier": (
|
||||
str(
|
||||
issue_activity.get("old_identifier")
|
||||
)
|
||||
str(issue_activity.get("old_identifier"))
|
||||
if issue_activity.get("old_identifier")
|
||||
else None
|
||||
),
|
||||
"new_identifier": (
|
||||
str(
|
||||
issue_activity.get("new_identifier")
|
||||
)
|
||||
str(issue_activity.get("new_identifier"))
|
||||
if issue_activity.get("new_identifier")
|
||||
else None
|
||||
),
|
||||
"activity_time": str(
|
||||
last_activity.created_at
|
||||
),
|
||||
"activity_time": str(last_activity.created_at),
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
@ -712,9 +625,7 @@ def notifications(
|
|||
"issue": {
|
||||
"id": str(issue_id),
|
||||
"name": str(issue.name),
|
||||
"identifier": str(
|
||||
issue.project.identifier
|
||||
),
|
||||
"identifier": str(issue.project.identifier),
|
||||
"sequence_id": issue.sequence_id,
|
||||
"state_name": issue.state.name,
|
||||
"state_group": issue.state.group,
|
||||
|
|
@ -723,47 +634,27 @@ def notifications(
|
|||
"id": str(issue_activity.get("id")),
|
||||
"verb": str(issue_activity.get("verb")),
|
||||
"field": str("mention"),
|
||||
"actor": str(
|
||||
issue_activity.get("actor_id")
|
||||
),
|
||||
"new_value": str(
|
||||
issue_activity.get("new_value")
|
||||
),
|
||||
"old_value": str(
|
||||
issue_activity.get("old_value")
|
||||
),
|
||||
"actor": str(issue_activity.get("actor_id")),
|
||||
"new_value": str(issue_activity.get("new_value")),
|
||||
"old_value": str(issue_activity.get("old_value")),
|
||||
"old_identifier": (
|
||||
str(
|
||||
issue_activity.get(
|
||||
"old_identifier"
|
||||
)
|
||||
)
|
||||
if issue_activity.get(
|
||||
"old_identifier"
|
||||
)
|
||||
str(issue_activity.get("old_identifier"))
|
||||
if issue_activity.get("old_identifier")
|
||||
else None
|
||||
),
|
||||
"new_identifier": (
|
||||
str(
|
||||
issue_activity.get(
|
||||
"new_identifier"
|
||||
)
|
||||
)
|
||||
if issue_activity.get(
|
||||
"new_identifier"
|
||||
)
|
||||
str(issue_activity.get("new_identifier"))
|
||||
if issue_activity.get("new_identifier")
|
||||
else None
|
||||
),
|
||||
"activity_time": issue_activity.get(
|
||||
"created_at"
|
||||
),
|
||||
"activity_time": issue_activity.get("created_at"),
|
||||
},
|
||||
},
|
||||
)
|
||||
)
|
||||
bulk_notifications.append(notification)
|
||||
|
||||
# save new mentions for the particular issue and remove the mentions that has been deleted from the description
|
||||
# save new mentions for the particular issue and remove the mentions that has been deleted from the description # noqa: E501
|
||||
update_mentions_for_issue(
|
||||
issue=issue,
|
||||
project=project,
|
||||
|
|
@ -772,9 +663,7 @@ def notifications(
|
|||
)
|
||||
# Bulk create notifications
|
||||
Notification.objects.bulk_create(bulk_notifications, batch_size=100)
|
||||
EmailNotificationLog.objects.bulk_create(
|
||||
bulk_email_logs, batch_size=100, ignore_conflicts=True
|
||||
)
|
||||
EmailNotificationLog.objects.bulk_create(bulk_email_logs, batch_size=100, ignore_conflicts=True)
|
||||
return
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
|
|
|||
|
|
@ -69,9 +69,7 @@ def page_transaction(new_value, old_value, page_id):
|
|||
)
|
||||
|
||||
# Create new PageLog objects for new transactions
|
||||
PageLog.objects.bulk_create(
|
||||
new_transactions, batch_size=10, ignore_conflicts=True
|
||||
)
|
||||
PageLog.objects.bulk_create(new_transactions, batch_size=10, ignore_conflicts=True)
|
||||
|
||||
# Delete the removed transactions
|
||||
PageLog.objects.filter(transaction__in=deleted_transaction_ids).delete()
|
||||
|
|
|
|||
|
|
@ -16,9 +16,7 @@ def page_version(page_id, existing_instance, user_id):
|
|||
page = Page.objects.get(id=page_id)
|
||||
|
||||
# Get the current instance
|
||||
current_instance = (
|
||||
json.loads(existing_instance) if existing_instance is not None else {}
|
||||
)
|
||||
current_instance = json.loads(existing_instance) if existing_instance is not None else {}
|
||||
|
||||
# Create a version if description_html is updated
|
||||
if current_instance.get("description_html") != page.description_html:
|
||||
|
|
@ -37,9 +35,7 @@ def page_version(page_id, existing_instance, user_id):
|
|||
# If page versions are greater than 20 delete the oldest one
|
||||
if PageVersion.objects.filter(page_id=page_id).count() > 20:
|
||||
# Delete the old page version
|
||||
PageVersion.objects.filter(page_id=page_id).order_by(
|
||||
"last_saved_at"
|
||||
).first().delete()
|
||||
PageVersion.objects.filter(page_id=page_id).order_by("last_saved_at").first().delete()
|
||||
|
||||
return
|
||||
except Page.DoesNotExist:
|
||||
|
|
|
|||
|
|
@ -54,9 +54,7 @@ def project_add_user_email(current_site, project_member_id, invitor_id):
|
|||
subject = "You have been invited to a Plane project"
|
||||
|
||||
# Render the email template
|
||||
html_content = render_to_string(
|
||||
"emails/notifications/project_addition.html", context
|
||||
)
|
||||
html_content = render_to_string("emails/notifications/project_addition.html", context)
|
||||
text_content = strip_tags(html_content)
|
||||
# Initialize the connection
|
||||
connection = get_connection(
|
||||
|
|
|
|||
|
|
@ -21,11 +21,9 @@ def project_invitation(email, project_id, token, current_site, invitor):
|
|||
try:
|
||||
user = User.objects.get(email=invitor)
|
||||
project = Project.objects.get(pk=project_id)
|
||||
project_member_invite = ProjectMemberInvite.objects.get(
|
||||
token=token, email=email
|
||||
)
|
||||
project_member_invite = ProjectMemberInvite.objects.get(token=token, email=email)
|
||||
|
||||
relativelink = f"/project-invitations/?invitation_id={project_member_invite.id}&email={email}&slug={project.workspace.slug}&project_id={str(project_id)}"
|
||||
relativelink = f"/project-invitations/?invitation_id={project_member_invite.id}&email={email}&slug={project.workspace.slug}&project_id={str(project_id)}" # noqa: E501
|
||||
abs_url = current_site + relativelink
|
||||
|
||||
subject = f"{user.first_name or user.display_name or user.email} invited you to join {project.name} on Plane"
|
||||
|
|
@ -37,9 +35,7 @@ def project_invitation(email, project_id, token, current_site, invitor):
|
|||
"invitation_url": abs_url,
|
||||
}
|
||||
|
||||
html_content = render_to_string(
|
||||
"emails/invitations/project_invitation.html", context
|
||||
)
|
||||
html_content = render_to_string("emails/invitations/project_invitation.html", context)
|
||||
|
||||
text_content = strip_tags(html_content)
|
||||
|
||||
|
|
|
|||
|
|
@ -30,14 +30,10 @@ def recent_visited_task(entity_name, entity_identifier, user_id, project_id, slu
|
|||
except DatabaseError:
|
||||
pass
|
||||
else:
|
||||
recent_visited_count = UserRecentVisit.objects.filter(
|
||||
user_id=user_id, workspace_id=workspace.id
|
||||
).count()
|
||||
recent_visited_count = UserRecentVisit.objects.filter(user_id=user_id, workspace_id=workspace.id).count()
|
||||
if recent_visited_count == 20:
|
||||
recent_visited = (
|
||||
UserRecentVisit.objects.filter(
|
||||
user_id=user_id, workspace_id=workspace.id
|
||||
)
|
||||
UserRecentVisit.objects.filter(user_id=user_id, workspace_id=workspace.id)
|
||||
.order_by("created_at")
|
||||
.first()
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,9 +15,7 @@ def get_asset_object_metadata(asset_id):
|
|||
# Create an instance of the S3 storage
|
||||
storage = S3Storage()
|
||||
# Get the storage
|
||||
asset.storage_metadata = storage.get_object_metadata(
|
||||
object_name=asset.asset.name
|
||||
)
|
||||
asset.storage_metadata = storage.get_object_metadata(object_name=asset.asset.name)
|
||||
# Save the asset
|
||||
asset.save(update_fields=["storage_metadata"])
|
||||
return
|
||||
|
|
|
|||
|
|
@ -80,15 +80,11 @@ logger = logging.getLogger("plane.worker")
|
|||
def get_issue_prefetches():
|
||||
return [
|
||||
Prefetch("label_issue", queryset=IssueLabel.objects.select_related("label")),
|
||||
Prefetch(
|
||||
"issue_assignee", queryset=IssueAssignee.objects.select_related("assignee")
|
||||
),
|
||||
Prefetch("issue_assignee", queryset=IssueAssignee.objects.select_related("assignee")),
|
||||
]
|
||||
|
||||
|
||||
def get_model_data(
|
||||
event: str, event_id: Union[str, List[str]], many: bool = False
|
||||
) -> Dict[str, Any]:
|
||||
def get_model_data(event: str, event_id: Union[str, List[str]], many: bool = False) -> Dict[str, Any]:
|
||||
"""
|
||||
Retrieve and serialize model data based on the event type.
|
||||
|
||||
|
|
@ -125,15 +121,9 @@ def get_model_data(
|
|||
queryset = queryset.prefetch_related(*issue_prefetches)
|
||||
else:
|
||||
issue_id = queryset.id
|
||||
queryset = (
|
||||
model.objects.filter(pk=issue_id)
|
||||
.prefetch_related(*issue_prefetches)
|
||||
.first()
|
||||
)
|
||||
queryset = model.objects.filter(pk=issue_id).prefetch_related(*issue_prefetches).first()
|
||||
|
||||
return serializer(
|
||||
queryset, many=many, context={"expand": ["labels", "assignees"]}
|
||||
).data
|
||||
return serializer(queryset, many=many, context={"expand": ["labels", "assignees"]}).data
|
||||
else:
|
||||
return serializer(queryset, many=many).data
|
||||
except ObjectDoesNotExist:
|
||||
|
|
@ -141,9 +131,7 @@ def get_model_data(
|
|||
|
||||
|
||||
@shared_task
|
||||
def send_webhook_deactivation_email(
|
||||
webhook_id: str, receiver_id: str, current_site: str, reason: str
|
||||
) -> None:
|
||||
def send_webhook_deactivation_email(webhook_id: str, receiver_id: str, current_site: str, reason: str) -> None:
|
||||
"""
|
||||
Send an email notification when a webhook is deactivated.
|
||||
|
||||
|
|
@ -177,9 +165,7 @@ def send_webhook_deactivation_email(
|
|||
"message": message,
|
||||
"webhook_url": f"{current_site}/{str(webhook.workspace.slug)}/settings/webhooks/{str(webhook.id)}",
|
||||
}
|
||||
html_content = render_to_string(
|
||||
"emails/notifications/webhook-deactivate.html", context
|
||||
)
|
||||
html_content = render_to_string("emails/notifications/webhook-deactivate.html", context)
|
||||
text_content = strip_tags(html_content)
|
||||
|
||||
# Set the email connection
|
||||
|
|
@ -248,17 +234,9 @@ def webhook_send_task(
|
|||
}
|
||||
|
||||
# # Your secret key
|
||||
event_data = (
|
||||
json.loads(json.dumps(event_data, cls=DjangoJSONEncoder))
|
||||
if event_data is not None
|
||||
else None
|
||||
)
|
||||
event_data = json.loads(json.dumps(event_data, cls=DjangoJSONEncoder)) if event_data is not None else None
|
||||
|
||||
activity = (
|
||||
json.loads(json.dumps(activity, cls=DjangoJSONEncoder))
|
||||
if activity is not None
|
||||
else None
|
||||
)
|
||||
activity = json.loads(json.dumps(activity, cls=DjangoJSONEncoder)) if activity is not None else None
|
||||
|
||||
action = {
|
||||
"POST": "create",
|
||||
|
|
@ -405,11 +383,7 @@ def webhook_activity(
|
|||
webhook_id=webhook.id,
|
||||
slug=slug,
|
||||
event=event,
|
||||
event_data=(
|
||||
{"id": event_id}
|
||||
if verb == "deleted"
|
||||
else get_model_data(event=event, event_id=event_id)
|
||||
),
|
||||
event_data=({"id": event_id} if verb == "deleted" else get_model_data(event=event, event_id=event_id)),
|
||||
action=verb,
|
||||
current_site=current_site,
|
||||
activity={
|
||||
|
|
@ -433,9 +407,7 @@ def webhook_activity(
|
|||
|
||||
|
||||
@shared_task
|
||||
def model_activity(
|
||||
model_name, model_id, requested_data, current_instance, actor_id, slug, origin=None
|
||||
):
|
||||
def model_activity(model_name, model_id, requested_data, current_instance, actor_id, slug, origin=None):
|
||||
"""Function takes in two json and computes differences between keys of both the json"""
|
||||
if current_instance is None:
|
||||
webhook_activity.delay(
|
||||
|
|
@ -454,9 +426,7 @@ def model_activity(
|
|||
return
|
||||
|
||||
# Load the current instance
|
||||
current_instance = (
|
||||
json.loads(current_instance) if current_instance is not None else None
|
||||
)
|
||||
current_instance = json.loads(current_instance) if current_instance is not None else None
|
||||
|
||||
# Loop through all keys in requested data and check the current value and requested value
|
||||
for key in requested_data:
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@ def workspace_invitation(email, workspace_id, token, current_site, inviter):
|
|||
user = User.objects.get(email=inviter)
|
||||
|
||||
workspace = Workspace.objects.get(pk=workspace_id)
|
||||
workspace_member_invite = WorkspaceMemberInvite.objects.get(
|
||||
token=token, email=email
|
||||
)
|
||||
workspace_member_invite = WorkspaceMemberInvite.objects.get(token=token, email=email)
|
||||
|
||||
# Relative link
|
||||
relative_link = f"/workspace-invitations/?invitation_id={workspace_member_invite.id}&email={email}&slug={workspace.slug}" # noqa: E501
|
||||
relative_link = (
|
||||
f"/workspace-invitations/?invitation_id={workspace_member_invite.id}&email={email}&slug={workspace.slug}" # noqa: E501
|
||||
)
|
||||
|
||||
# The complete url including the domain
|
||||
abs_url = str(current_site) + relative_link
|
||||
|
|
@ -51,9 +51,7 @@ def workspace_invitation(email, workspace_id, token, current_site, inviter):
|
|||
"abs_url": abs_url,
|
||||
}
|
||||
|
||||
html_content = render_to_string(
|
||||
"emails/invitations/workspace_invitation.html", context
|
||||
)
|
||||
html_content = render_to_string("emails/invitations/workspace_invitation.html", context)
|
||||
|
||||
text_content = strip_tags(html_content)
|
||||
|
||||
|
|
|
|||
|
|
@ -68,16 +68,12 @@ def create_project_and_member(workspace: Workspace) -> Dict[int, uuid.UUID]:
|
|||
project_identifier = "".join(ch for ch in workspace.name if ch.isalnum())[:5]
|
||||
|
||||
# Create members
|
||||
workspace_members = WorkspaceMember.objects.filter(workspace=workspace).values(
|
||||
"member_id", "role"
|
||||
)
|
||||
workspace_members = WorkspaceMember.objects.filter(workspace=workspace).values("member_id", "role")
|
||||
|
||||
projects_map: Dict[int, uuid.UUID] = {}
|
||||
|
||||
if not project_seeds:
|
||||
logger.warning(
|
||||
"Task: workspace_seed_task -> No project seeds found. Skipping project creation."
|
||||
)
|
||||
logger.warning("Task: workspace_seed_task -> No project seeds found. Skipping project creation.")
|
||||
return projects_map
|
||||
|
||||
for project_seed in project_seeds:
|
||||
|
|
@ -140,9 +136,7 @@ def create_project_and_member(workspace: Workspace) -> Dict[int, uuid.UUID]:
|
|||
return projects_map
|
||||
|
||||
|
||||
def create_project_states(
|
||||
workspace: Workspace, project_map: Dict[int, uuid.UUID]
|
||||
) -> Dict[int, uuid.UUID]:
|
||||
def create_project_states(workspace: Workspace, project_map: Dict[int, uuid.UUID]) -> Dict[int, uuid.UUID]:
|
||||
"""Creates states for each project in the workspace.
|
||||
|
||||
Args:
|
||||
|
|
@ -175,9 +169,7 @@ def create_project_states(
|
|||
return state_map
|
||||
|
||||
|
||||
def create_project_labels(
|
||||
workspace: Workspace, project_map: Dict[int, uuid.UUID]
|
||||
) -> Dict[int, uuid.UUID]:
|
||||
def create_project_labels(workspace: Workspace, project_map: Dict[int, uuid.UUID]) -> Dict[int, uuid.UUID]:
|
||||
"""Creates labels for each project in the workspace.
|
||||
|
||||
Args:
|
||||
|
|
@ -234,9 +226,7 @@ def create_project_issues(
|
|||
# get the values
|
||||
for field in required_fields:
|
||||
if field not in issue_seed:
|
||||
logger.error(
|
||||
f"Task: workspace_seed_task -> Required field '{field}' missing in issue seed"
|
||||
)
|
||||
logger.error(f"Task: workspace_seed_task -> Required field '{field}' missing in issue seed")
|
||||
continue
|
||||
|
||||
# get the values
|
||||
|
|
@ -312,12 +302,8 @@ def workspace_seed(workspace_id: uuid.UUID) -> None:
|
|||
# create project issues
|
||||
create_project_issues(workspace, project_map, state_map, label_map)
|
||||
|
||||
logger.info(
|
||||
f"Task: workspace_seed_task -> Workspace {workspace_id} seeded successfully"
|
||||
)
|
||||
logger.info(f"Task: workspace_seed_task -> Workspace {workspace_id} seeded successfully")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Task: workspace_seed_task -> Failed to seed workspace {workspace_id}: {str(e)}"
|
||||
)
|
||||
logger.error(f"Task: workspace_seed_task -> Failed to seed workspace {workspace_id}: {str(e)}")
|
||||
raise e
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue