[WEB-5044] fix: ruff lint and format errors (#7868)

* fix: lint errors

* fix: file formatting

* fix: code refactor
This commit is contained in:
sriram veeraghanta 2025-09-29 19:15:32 +05:30 committed by GitHub
parent 1fb22bd252
commit 9237f568dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
261 changed files with 2199 additions and 6378 deletions

View file

@ -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(

View file

@ -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"],

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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": [

View file

@ -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()

View file

@ -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
(

View file

@ -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",

View file

@ -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,

View file

@ -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)

View file

@ -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

View file

@ -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:

View file

@ -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)

View file

@ -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()

View file

@ -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:

View file

@ -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(

View file

@ -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)

View file

@ -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()
)

View file

@ -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

View file

@ -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:

View file

@ -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)

View file

@ -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