# Python imports import csv import io # Django imports from django.core.mail import EmailMultiAlternatives from django.template.loader import render_to_string from django.utils.html import strip_tags from django.conf import settings # Third party imports from celery import shared_task from sentry_sdk import capture_exception # Module imports from plane.db.models import Issue from plane.utils.analytics_plot import build_graph_plot from plane.utils.issue_filters import issue_filters row_mapping = { "state__name": "State", "state__group": "State Group", "labels__name": "Label", "assignees__email": "Assignee Name", "start_date": "Start Date", "target_date": "Due Date", "completed_at": "Completed At", "created_at": "Created At", "issue_count": "Issue Count", "priority": "Priority", "estimate": "Estimate", } @shared_task def analytic_export_task(email, data, slug): try: filters = issue_filters(data, "POST") queryset = Issue.objects.filter(**filters, workspace__slug=slug) x_axis = data.get("x_axis", False) y_axis = data.get("y_axis", False) segment = data.get("segment", False) distribution = build_graph_plot( queryset=queryset, x_axis=x_axis, y_axis=y_axis, segment=segment ) key = "count" if y_axis == "issue_count" else "estimate" segmented = segment assignee_details = {} if x_axis in ["assignees__email"] or segment in ["assignees__email"]: assignee_details = ( Issue.objects.filter(workspace__slug=slug, **filters, assignees__avatar__isnull=False) .order_by("assignees__id") .distinct("assignees__id") .values("assignees__avatar", "assignees__email", "assignees__first_name", "assignees__last_name") ) if segment: segment_zero = [] for item in distribution: current_dict = distribution.get(item) for current in current_dict: segment_zero.append(current.get("segment")) segment_zero = list(set(segment_zero)) row_zero = ( [ row_mapping.get(x_axis, "X-Axis"), ] + [ row_mapping.get(y_axis, "Y-Axis"), ] + segment_zero ) rows = [] for item in distribution: generated_row = [ item, ] data = distribution.get(item) # Add y axis values generated_row.append(sum(obj.get(key) for obj in data if obj.get(key, None) is not None)) for segment in segment_zero: value = [x for x in data if x.get("segment") == segment] if len(value): generated_row.append(value[0].get(key)) else: generated_row.append("0") # x-axis replacement for names if x_axis in ["assignees__email"]: assignee = [user for user in assignee_details if str(user.get("assignees__email")) == str(item)] if len(assignee): generated_row[0] = str(assignee[0].get("assignees__first_name")) + " " + str(assignee[0].get("assignees__last_name")) rows.append(tuple(generated_row)) # If segment is ["assignees__email"] then replace segment_zero rows with first and last names if segmented in ["assignees__email"]: for index, segm in enumerate(row_zero[2:]): # find the name of the user assignee = [user for user in assignee_details if str(user.get("assignees__email")) == str(segm)] if len(assignee): row_zero[index] = str(assignee[0].get("assignees__first_name")) + " " + str(assignee[0].get("assignees__last_name")) rows = [tuple(row_zero)] + rows csv_buffer = io.StringIO() writer = csv.writer(csv_buffer, delimiter=",", quoting=csv.QUOTE_ALL) # Write CSV data to the buffer for row in rows: writer.writerow(row) subject = "Your Export is ready" html_content = render_to_string("emails/exports/analytics.html", {}) text_content = strip_tags(html_content) csv_buffer.seek(0) msg = EmailMultiAlternatives( subject, text_content, settings.EMAIL_FROM, [email] ) msg.attach(f"{slug}-analytics.csv", csv_buffer.read()) msg.send(fail_silently=False) else: row_zero = [ row_mapping.get(x_axis, "X-Axis"), row_mapping.get(y_axis, "Y-Axis"), ] rows = [] for item in distribution: row = [ item, distribution.get(item)[0].get("count") if y_axis == "issue_count" else distribution.get(item)[0].get("estimate "), ] # x-axis replacement to names if x_axis in ["assignees__email"]: assignee = [user for user in assignee_details if str(user.get("assignees__email")) == str(item)] if len(assignee): row[0] = str(assignee[0].get("assignees__first_name")) + " " + str(assignee[0].get("assignees__last_name")) rows.append(tuple(row)) rows = [tuple(row_zero)] + rows csv_buffer = io.StringIO() writer = csv.writer(csv_buffer, delimiter=",", quoting=csv.QUOTE_ALL) # Write CSV data to the buffer for row in rows: writer.writerow(row) subject = "Your Export is ready" html_content = render_to_string("emails/exports/analytics.html", {}) text_content = strip_tags(html_content) csv_buffer.seek(0) msg = EmailMultiAlternatives( subject, text_content, settings.EMAIL_FROM, [email] ) msg.attach(f"{slug}-analytics.csv", csv_buffer.read()) msg.send(fail_silently=False) except Exception as e: print(e) capture_exception(e) return