Merge pull request #33 from WDI-Ideas/development

Development
This commit is contained in:
rizwanisready
2024-06-03 19:32:05 +05:30
committed by GitHub
9 changed files with 406 additions and 136 deletions

View File

@@ -1,5 +1,13 @@
from django.contrib import admin
from .models import EventCategory, EventView, Venue, EventMaster, Event, EventPrincipalInteraction
from .models import (
EventCategory,
EventShare,
EventView,
Venue,
EventMaster,
Event,
EventPrincipalInteraction,
)
# Register your models here.
@@ -78,7 +86,7 @@ class EventAdmin(admin.ModelAdmin):
},
),
)
filter_horizontal = () # Use this if there are many-to-many fields
filter_horizontal = () # if there are many-to-many fields
raw_id_fields = ("venue", "category", "event_master")
@@ -88,17 +96,24 @@ class EventPrincipalInteractionAdmin(admin.ModelAdmin):
search_fields = (
"principal__name",
"event__title",
) # Adjust these field lookups according to your models.
)
class EventViewAdmin(admin.ModelAdmin):
list_display = ('id', 'event', 'principal', 'view_date', 'location')
search_fields = ('event__title', 'principal__email', 'location')
list_filter = ('view_date', 'location', 'event__title', 'principal__email')
ordering = ('-view_date',)
readonly_fields = ('id',)
list_display = ("id", "event", "principal", "view_date", "location")
search_fields = ("event__title", "principal__email", "location")
list_filter = ("id", "view_date", "location", "event__title", "principal__email")
ordering = ("-view_date",)
readonly_fields = ("id",)
class EventShareAdmin(admin.ModelAdmin):
list_display = ("id", "event", "principal", "created_on")
search_fields = ("event__title", "principal__username")
list_filter = ("id", "event", "principal", "created_on")
admin.site.register(EventShare, EventShareAdmin)
admin.site.register(EventView, EventViewAdmin)
admin.site.register(EventPrincipalInteraction, EventPrincipalInteractionAdmin)
admin.site.register(Event, EventAdmin)

View File

@@ -117,4 +117,10 @@ urlpatterns = [
views.CaptureEventViewAPIView.as_view(),
name="capture_event_view",
),
# For counting event shares
path(
"event/<int:pk>/share/",
views.EventShareView.as_view(),
name="capture_event_share",
),
]

View File

@@ -34,6 +34,7 @@ from manage_events.models import (
EventCategory,
EventPrincipalInteraction,
EventReview,
EventShare,
EventView,
Favorites,
PrincipalPreference,
@@ -890,3 +891,30 @@ class CaptureEventViewAPIView(APIView):
errors="Event not found.",
status=status.HTTP_400_BAD_REQUEST,
)
class EventShareView(APIView):
authentication_classes = [JWTAuthentication]
permission_classes = [IsAuthenticated]
def post(self, request, pk):
try:
event = Event.objects.get(id=pk)
except Event.DoesNotExist:
return ApiResponse.error(
message=constants.FAILURE,
errors="Event not found.",
status=status.HTTP_400_BAD_REQUEST,
)
# Incrementing the social media shares count
event.increment_shares()
user = request.user # Assuming the user is authenticated
EventShare.objects.create(principal=user, event=event)
return ApiResponse.success(
message=constants.SUCCESS,
data="Event shared successfully.",
status=status.HTTP_200_OK,
)

View File

@@ -0,0 +1,33 @@
from django.core.management.base import BaseCommand
from django.core.mail import EmailMessage
from django.conf import settings
from manage_events.report import (
get_previous_month_date_range,
event_managers,
generate_event_report,
generate_event_report_pdf_three,
)
class Command(BaseCommand):
help = "Send monthly event reports to event managers"
def handle(self, *args, **kwargs):
start_date, end_date = get_previous_month_date_range()
users = event_managers()
for user in users:
report_data = generate_event_report(user.id)
if report_data:
pdf_data, filename = generate_event_report_pdf_three(user, report_data)
self.send_email_with_attachment(user.email, pdf_data, filename)
def send_email_with_attachment(self, email, pdf_data, filename):
email_message = EmailMessage(
subject="Monthly Event Report",
body="Please find the attached report for the last month.",
to=[email],
from_email=settings.EMAIL_HOST_USER,
)
email_message.attach(filename, pdf_data, "application/pdf")
email_message.send()

View File

@@ -0,0 +1,78 @@
# Generated by Django 5.0.2 on 2024-06-01 15:06
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("manage_events", "0009_eventview"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name="event",
name="social_media_shares_count",
field=models.IntegerField(default=0),
),
migrations.CreateModel(
name="EventShare",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("active", models.BooleanField(default=True)),
("deleted", models.BooleanField(default=False)),
("created_on", models.DateTimeField(auto_now_add=True)),
("modified_on", models.DateTimeField(auto_now=True)),
(
"created_by",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="%(class)s_created",
to=settings.AUTH_USER_MODEL,
),
),
(
"event",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="social_media_shares",
to="manage_events.event",
),
),
(
"modified_by",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="%(class)s_modified",
to=settings.AUTH_USER_MODEL,
),
),
(
"principal",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="event_shares",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"abstract": False,
},
),
]

View File

@@ -84,6 +84,11 @@ class Event(BaseModel):
tags = TaggableManager(blank=True)
age_group = models.CharField(max_length=100, blank=True, null=True)
draft = models.BooleanField(default=False)
social_media_shares_count = models.IntegerField(default=0)
def increment_shares(self):
self.social_media_shares_count += 1
self.save()
def __str__(self):
return self.title
@@ -187,3 +192,12 @@ class EventView(BaseModel):
def __str__(self):
return f"{self.principal.email} viewed {self.event.title} from {self.location}"
class EventShare(BaseModel):
event = models.ForeignKey(
Event, on_delete=models.CASCADE, related_name="social_media_shares"
)
principal = models.ForeignKey(
IAmPrincipal, on_delete=models.CASCADE, related_name="event_shares"
)

View File

@@ -5,13 +5,25 @@ from datetime import timedelta
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.graphics.shapes import Drawing
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.graphics.charts.piecharts import Pie
from reportlab.platypus import (
SimpleDocTemplate,
Table,
TableStyle,
Paragraph,
Spacer,
PageBreak,
)
from io import BytesIO
from django.conf import settings
from collections import defaultdict
from reportlab.graphics import renderPDF
from django.contrib.auth import get_user_model
from accounts.models import IAmPrincipalType
from goodtimes.services import EmailService
from manage_events.models import Event, EventInteractionType
from manage_events.models import Event, EventInteractionType, EventShare, EventView
User = get_user_model()
@@ -26,6 +38,10 @@ def generate_filename(email, date):
filename = f"{username}_{month_name}_report.pdf"
return filename
def event_managers():
principal_type = IAmPrincipalType.objects.filter(name="event_manager").first()
return User.objects.filter(principal_type=principal_type, is_active=True)
def get_previous_month_date_range():
today = timezone.now()
@@ -36,15 +52,11 @@ def get_previous_month_date_range():
def generate_event_report(user_id):
# Calculate the start and end dates for the previous month
start_date, end_date = get_previous_month_date_range()
# Get the user (manager)
user = User.objects.get(id=user_id)
# Filter events created by the user in the previous month
events = Event.objects.filter(
created_by=user, created_on__gte=start_date, created_on__lte=end_date
created_by=user, start_date__gte=start_date, start_date__lte=end_date
).annotate(
favorites_count=Count(
"favorites", filter=Q(favorites__active=True, favorites__deleted=False)
@@ -60,154 +72,238 @@ def generate_event_report(user_id):
reviews_count=Count(
"reviews", filter=Q(reviews__active=True, reviews__deleted=False)
),
views_count=Count("views", filter=Q(views__active=True, views__deleted=False)),
)
# print("events: ", events)
# Generate the report
report_data = []
for event in events:
views = EventView.objects.filter(event=event)
locations = defaultdict(int)
for view in views:
locations[view.location] += 1
shares = (
EventShare.objects.filter(event=event)
.values("principal")
.annotate(share_count=Count("principal"))
)
shares_data = {
User.objects.get(id=share["principal"]).get_full_name(): share[
"share_count"
]
for share in shares
}
report_data.append(
{
"event_name": event.title,
"event_type": event.category.title,
"event_date": str(event.start_date),
"favorites_count": event.favorites_count,
"interested_count": event.interested_count,
"going_count": event.going_count,
"reviews_count": event.reviews_count,
"views_count": event.views_count,
"locations": dict(locations),
"social_media_shares": event.social_media_shares_count,
"shares_data": shares_data,
}
)
# print("report_data: ", report_data)
return report_data
def generate_event_report_pdf(user, report_data):
def generate_event_report_pdf_three(user, report_data):
start_date, _ = get_previous_month_date_range()
filename = generate_filename(user.email, start_date)
buffer = BytesIO()
pdf = canvas.Canvas(buffer, pagesize=letter)
# pdf = canvas.Canvas(buffer, pagesize=letter)
pdf = SimpleDocTemplate(buffer, pagesize=letter)
width, height = letter
elements = []
# Add a title and user information
pdf.setFont("Helvetica-Bold", 16)
pdf.drawString(100, 750, "Event Report - April 2024")
styles = getSampleStyleSheet()
user_name = user.email.split("@")[0] # Use part of email before @ as username
pdf.setFont("Helvetica", 12)
pdf.drawString(100, 730, f"For Event Manager: {user_name}")
custom_style = ParagraphStyle(
name="Custom",
parent=styles["Normal"],
fontName="Helvetica",
fontSize=14,
leading=18,
spaceAfter=12,
)
# Header Section
title = Paragraph("Good Times Ltd. Monthly Report", styles["Title"])
report_for_month = Paragraph(
f"Report for the month of - {start_date.strftime('%B %Y')}", styles["Title"]
)
organiser_name = Paragraph(
f"Name of the Organiser - {user.get_full_name()}", styles["Title"]
)
contact_name = Paragraph(f"Contact Name - {user.get_full_name()}", styles["Title"])
# Add a table header
pdf.setFont("Helvetica-Bold", 10)
pdf.drawString(50, 700, "Event Name")
pdf.drawString(250, 700, "Favorites")
pdf.drawString(350, 700, "Interested")
pdf.drawString(450, 700, "Going")
pdf.drawString(550, 700, "Reviews")
# Loop through data and add table rows
y_pos = 680
for event in report_data:
pdf.drawString(50, y_pos, event["event_name"])
pdf.drawString(250, y_pos, str(event["favorites_count"]))
pdf.drawString(350, y_pos, str(event["interested_count"]))
pdf.drawString(450, y_pos, str(event["going_count"]))
pdf.drawString(550, y_pos, str(event["reviews_count"]))
y_pos -= 15 # Adjust position for next row
# Draw the pie chart
if report_data:
pie_data = [
sum(event[key] for event in report_data)
for key in ("favorites_count", "interested_count", "going_count")
elements.extend(
[
title,
Spacer(1, 12),
report_for_month,
Spacer(1, 12),
organiser_name,
Spacer(1, 12),
contact_name,
PageBreak(),
]
pie_labels = ["Favorites", "Interested", "Going"]
)
drawing = Drawing(width, height)
pie = Pie()
pie.x = 150
pie.y = 200
pie.width = 300
pie.height = 150
pie.data = pie_data
pie.labels = pie_labels
pie.slices.strokeWidth = 0.5
# Summary Section
summary_text = (
f"Number of Events added in {start_date.strftime('%B %Y')} - {len(report_data)}"
)
elements.append(Paragraph(summary_text, styles["Title"]))
elements.append(Spacer(1, 24))
drawing.add(pie)
renderPDF.draw(drawing, pdf, 150, 200)
# Close the PDF object and write the buffer content to the PDF file
pdf.save()
buffer.seek(0)
pdf_data = buffer.read()
buffer.close()
return pdf_data, filename
def generate_event_report_pdf_two(user, report_data):
start_date, _ = get_previous_month_date_range()
filename = generate_filename(user.email, start_date)
buffer = BytesIO()
pdf = canvas.Canvas(buffer, pagesize=letter)
width, height = letter
# Add a title and user information
pdf.setFont("Helvetica-Bold", 16)
pdf.drawString(100, 750, "Event Report - April 2024")
user_name = user.email.split("@")[0] # Use part of email before @ as username
pdf.setFont("Helvetica", 12)
pdf.drawString(100, 730, f"For Event Manager: {user_name}")
# Event loop with row handling
y_pos = 650 # Starting position for charts (adjust as needed)
chart_width = 250 # Width of each pie chart
chart_height = 150 # Height of each pie chart
chart_spacing = 50 # Spacing between charts in a row
for i, event in enumerate(report_data):
# Add event name as a header
pdf.setFont("Helvetica-Bold", 12)
pdf.drawString(50, y_pos + 20, event["event_name"])
# Check if this is the first event in a row
if i % 2 == 0:
x_pos = 75 # Starting position for charts in the first column
else:
x_pos = (
width - chart_width - 75
) # Starting position for charts in the second column
# Draw pie charts for the event
for key, value in [
("favorites_count", "Favorites"),
("interested_count", "Interested"),
("going_count", "Going"),
]:
pie_data = [value]
pie_labels = [value]
drawing = Drawing(chart_width, chart_height)
pie = Pie()
pie.x = 0
pie.y = 0
pie.width = chart_width
pie.height = chart_height
pie.data = pie_data
pie.labels = pie_labels
pie.slices.strokeWidth = 0.5
drawing.add(pie)
renderPDF.draw(drawing, pdf, x_pos, y_pos)
x_pos += chart_width + chart_spacing # Adjust x position for the next chart
y_pos -= (
100 # Adjust y position for the next event (adjust based on chart heights)
data = [["Sr No.", "Name of the Event", "Event Type", "Date"]]
for idx, event in enumerate(report_data, start=1):
data.append(
[
idx,
event["event_name"],
event["event_type"],
event["event_date"],
]
)
# Close the PDF object and write the buffer content to the PDF file
pdf.save()
table = Table(data, colWidths=[50, 200, 150, 100])
style = TableStyle(
[
("BACKGROUND", (0, 0), (-1, 0), colors.grey),
("TEXTCOLOR", (0, 0), (-1, 0), colors.whitesmoke),
("ALIGN", (0, 0), (-1, -1), "CENTER"),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("BOTTOMPADDING", (0, 0), (-1, 0), 12),
("BACKGROUND", (0, 1), (-1, -1), colors.beige),
("GRID", (0, 0), (-1, -1), 1, colors.black),
]
)
table.setStyle(style)
elements.append(table)
elements.append(PageBreak())
# Traffic Details Section
traffic_header = "Traffic Details for profile - Event Organisers London Ltd."
elements.append(Paragraph(traffic_header, styles["Heading2"]))
elements.append(Spacer(1, 12))
views_count = sum(event["views_count"] for event in report_data)
favorites_count = sum(event["favorites_count"] for event in report_data)
social_media_shares = sum(event["social_media_shares"] for event in report_data)
elements.append(
Paragraph(f"Number of Event Views - {views_count}", styles["Normal"])
)
elements.append(Spacer(1, 12))
elements.append(
Paragraph(f"Number of Event Favorites - {favorites_count}", styles["Normal"])
)
elements.append(Spacer(1, 12))
elements.append(
Paragraph(f"Social Media Shares - {social_media_shares}", styles["Normal"])
)
# elements.append(PageBreak())
elements.append(Spacer(1, 60))
# Top 5 Locations and Top 5 Viewed Events
all_locations = defaultdict(int)
print("all_locations: ", all_locations)
for event in report_data:
for location, count in event["locations"].items():
all_locations[location] += count
top_locations = sorted(all_locations.items(), key=lambda x: x[1], reverse=True)[:5]
print("top_locations: ", top_locations)
top_events = sorted(report_data, key=lambda x: x["views_count"], reverse=True)[:5]
print("top_events: ", top_events)
data = [
["Top 5 Locations Viewed From", "Top 5 Viewed Events"],
]
for i in range(5):
location = top_locations[i][0] if i < len(top_locations) else ""
event = top_events[i]["event_name"] if i < len(top_events) else ""
data.append([location, event])
table = Table(data, colWidths=[200, 200])
style = TableStyle(
[
("BACKGROUND", (0, 0), (-1, 0), colors.grey),
("TEXTCOLOR", (0, 0), (-1, 0), colors.whitesmoke),
("ALIGN", (0, 0), (-1, -1), "CENTER"),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("BOTTOMPADDING", (0, 0), (-1, 0), 12),
("BACKGROUND", (0, 1), (-1, -1), colors.beige),
("GRID", (0, 0), (-1, -1), 1, colors.black),
]
)
table.setStyle(style)
elements.append(table)
elements.append(PageBreak())
# Detailed Review of Each Event
for event in report_data:
elements.append(Paragraph(f"Event Name - {event['event_name']}", styles['Heading1']))
elements.append(Spacer(1, 12))
elements.append(Paragraph(f"Event Type - {event['event_type']}", custom_style))
elements.append(Paragraph(f"Event Date - {event['event_date']}", custom_style))
views = f"Number of Views - {event['views_count']}"
favorites = f"Favorites Count - {event['favorites_count']}"
interested = f"Interested in Going - {event['interested_count']}"
going = f"Going - {event['going_count']}"
reviews = f"Reviews - {event['reviews_count']}"
shares = f"Social Media Shares - {event['social_media_shares']}"
elements.append(Paragraph(views, custom_style))
elements.append(Paragraph(shares, custom_style))
elements.append(Paragraph(favorites, custom_style))
elements.append(Paragraph(interested, custom_style))
elements.append(Paragraph(going, custom_style))
elements.append(Paragraph(reviews, custom_style))
elements.append(Spacer(1, 12))
location_details = []
for location, count in event["locations"].items():
location_details.append(f"{location}: {count}")
elements.append(Paragraph("Event viewed from:", custom_style))
elements.append(Paragraph(", ".join(location_details), custom_style))
# elements.append(PageBreak())
elements.append(Spacer(1, 48))
pie_data = [
event["views_count"],
event["social_media_shares"],
event["favorites_count"],
event["interested_count"],
event["going_count"],
]
pie_labels = ["Views", "Shares", "Favorites", "Interested", "Going"]
drawing = Drawing(200, 100)
pie = Pie()
pie.data = pie_data
pie.labels = pie_labels
pie.width = 100
pie.height = 100
drawing.add(pie)
elements.append(drawing)
elements.append(PageBreak())
pdf.build(elements)
buffer.seek(0)
pdf_data = buffer.read()
buffer.close()
return pdf_data, filename

View File

@@ -481,7 +481,7 @@ class VenueDeleteView(LoginRequiredMixin, generic.View):
User = get_user_model()
from .report import generate_event_report, generate_event_report_pdf
from .report import generate_event_report, generate_event_report_pdf_three
from django.http import HttpResponse
@@ -495,10 +495,10 @@ class GenerateEventReportView(generic.View):
user = get_object_or_404(User, id=user_id)
# Generate the PDF
pdf_data, filename = generate_event_report_pdf(user, report_data)
pdf_data, filename = generate_event_report_pdf_three(user, report_data)
# Create the HttpResponse object with the PDF data
response = HttpResponse(pdf_data, content_type="application/pdf")
response["Content-Disposition"] = f'attachment; filename="{filename}"'
return response

View File

@@ -68,7 +68,7 @@ sqlparse==0.4.4
stripe==8.2.0
tqdm==4.66.2
Twisted==23.10.0
twisted-iocpsupport==1.0.4
# twisted-iocpsupport==1.0.4
txaio==23.1.1
typing_extensions==4.9.0
tzdata==2024.1