Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions corpus/newsletter/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class Meta:
"name",
"sigs",
"description",
"details",
"start_date",
"end_date",
"page_link",
Expand Down
2 changes: 2 additions & 0 deletions corpus/newsletter/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from django.core.exceptions import ValidationError
from django.db import models
from django.utils import timezone
from ckeditor_uploader.fields import RichTextUploadingField

# Create your models here.

Expand All @@ -13,6 +14,7 @@ class Event(models.Model):
start_date = models.DateField()
end_date = models.DateField()
description = models.TextField(verbose_name="Description", null=True, blank=True)
details = RichTextUploadingField(blank=True, null=True)
archive_event = models.BooleanField(default=False)
show_in_recent = models.BooleanField(default=False)
thumbnail = models.ImageField(
Expand Down
11 changes: 11 additions & 0 deletions corpus/newsletter/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,21 @@
views.edit_announcement,
name="newsletter_edit_announcement",
),
path(
"announcement/toggle/<int:pk>",
views.toggle_announcement,
name="newsletter_toggle_announcement",
),
path(
"announcement/delete/<int:pk>",
views.delete_announcement,
name="newsletter_delete_announcement",
),
path("calendar/", views.calendar_view, name="newsletter_calendar"),
path(
"archive/<int:pk>/",
views.archived_event_detail,
name="newsletter_archived_event_detail"
),
path("archive/", views.archived_events_view, name="newsletter_archived_events"),
]
76 changes: 68 additions & 8 deletions corpus/newsletter/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
from corpus.decorators import ensure_group_membership
from corpus.decorators import module_enabled

from django.urls import reverse
from django.contrib import messages

# Create your views here.
def _daterange(start_date, end_date):
for n in range(int((end_date - start_date).days) + 1):
Expand All @@ -41,8 +44,7 @@ def calendar_view(request):
first_day_in_grid = raw_all_days[0]
last_day_in_grid = raw_all_days[-1]
events_qs = (
Event.objects.filter(archive_event=False)
.filter(
Event.objects.filter(
Q(start_date__lte=last_day_in_grid) & Q(end_date__gte=first_day_in_grid)
)
.prefetch_related("sigs")
Expand Down Expand Up @@ -115,6 +117,54 @@ def calendar_view(request):
}
return render(request, "newsletter/calendar.html", ctx)

@module_enabled(module_name="newsletter")
def archived_events_view(request):
events_qs = Event.objects.filter(archive_event=True).order_by("-start_date")
is_admin = request.user.groups.filter(name="newsletter_admin").exists()
available_years = (
Event.objects.filter(archive_event=True)
.values_list("start_date__year", flat=True)
.distinct()
.order_by("-start_date__year")
)
all_sigs = SIG.objects.all().order_by("name")
selected_year = request.GET.get("year")
selected_sig_id = request.GET.get("sig")
if selected_year:
try:
year = int(selected_year)
events_qs = events_qs.filter(start_date__year=year)
except ValueError:
selected_year = None
if selected_sig_id:
try:
sig_id = int(selected_sig_id)
events_qs = events_qs.filter(sigs__id=sig_id)
except ValueError:
selected_sig_id = None
context = {
"events": events_qs.prefetch_related("sigs"),
"available_years": available_years,
"all_sigs": all_sigs,
"selected_year": selected_year,
"selected_sig_id": selected_sig_id,
"is_admin" : is_admin,
}
return render(request, "newsletter/archived_events.html", context)

@module_enabled(module_name="newsletter")
def archived_event_detail(request, pk):
event = get_object_or_404(
Event.objects.prefetch_related('sigs'),
pk=pk,
archive_event=True
)

context = {
"event": event,
}

return render(request, "newsletter/archived_event_detail.html", context)

@module_enabled(module_name="newsletter")
def home(request):
Expand Down Expand Up @@ -160,10 +210,10 @@ def new_announcement(request):
if form.is_valid():
form.save()
messages.success(request, "Announcement created successfully")
return redirect("newsletter_home")
return redirect("newsletter_manage_announcements")
else:
messages.error(request, "Failed to create announcement")
return redirect("newsletter_home")
return redirect("newsletter_manage_announcements")

form = EventForm()
context = {"form": form}
Expand All @@ -175,6 +225,11 @@ def new_announcement(request):
@ensure_group_membership(group_names=["newsletter_admin"])
def edit_announcement(request, pk):
event = get_object_or_404(Event, pk=pk)
previous_url = (
request.GET.get("next")
or request.META.get("HTTP_REFERER")
or reverse("newsletter_manage_announcements")
)

if request.GET.get("archive") == "true":
event.archive_event = True
Expand All @@ -190,17 +245,19 @@ def edit_announcement(request, pk):

if request.method == "POST":
form = EventForm(request.POST, request.FILES, instance=event)
previous_url = request.GET.get("next") or reverse("newsletter_manage_announcements")
if form.is_valid():
form.save()
messages.success(request, "Announcement updated successfully")
return redirect("newsletter_manage_announcements")
return redirect(request.POST.get("next") or previous_url)

else:
form = EventForm(instance=event)

return render(
request,
"newsletter/edit_announcement.html",
{"form": form, "announcement": event},
{"form": form, "announcement": event, "previous_url" : previous_url},
)


Expand All @@ -212,8 +269,11 @@ def toggle_announcement(request, pk):
event.save()
string = "archived" if event.archive_event else "unarchived"
messages.success(request, f"Announcement {string} successfully")
return redirect("newsletter_manage_announcements")

return redirect(
request.GET.get("next")
or request.POST.get("next")
or "newsletter_archived_events"
)

@module_enabled(module_name="newsletter")
@ensure_group_membership(group_names=["newsletter_admin"])
Expand Down
87 changes: 87 additions & 0 deletions corpus/templates/newsletter/archived_event_detail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{% extends "newsletter/base.html" %}
{% load static %}

{% block title %}
{{ event.name }} | Archive Detail
{% endblock %}

{% block content %}
<div class="px-4 sm:px-6 lg:px-8 py-8">

<a href="{% url 'newsletter_archived_events' %}"
class="inline-flex items-center text-blue-400 hover:text-blue-200 mb-8 transition-colors">
<svg class="w-5 h-5 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
Back to Archive
</a>
<article class="text-gray-900 dark:text-white">
<div class="p-8">
<h1 class="text-4xl font-bold break-words leading-tight text-gray-900 dark:text-white mb-6">{{ event.name }}</h1>
<div class="flex flex-wrap gap-4 items-center">
<span class="px-3 py-1 bg-purple-500 rounded-full text-sm font-medium flex items-center text-white">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
{{ event.start_date|date:"F j, Y" }}
</span>
{% for sig in event.sigs.all %}
<span class="px-3 py-1 rounded-full text-sm font-medium text-white"
style="background-color: {{ sig.color }}; border: none;">
{{ sig.name }}
</span>
{% empty %}
<span class="px-3 py-1 bg-gray-500 rounded-full text-sm font-medium text-white">
No SIGs listed
</span>
{% endfor %}
</div>
</div>

<div class="px-8 pb-8">
{% if event.description %}
<div class="mb-8 pt-4">
<h2 class="text-2xl font-semibold text-gray-900 dark:text-white mb-3 border-b pb-2 border-gray-700">Description</h2>
<div class="prose prose-purple max-w-none text-gray-700 dark:text-gray-300">
{{ event.description|safe }}
</div>
</div>
{% endif %}

<div class="mt-8 pt-4">
<h2 class="text-2xl font-semibold text-gray-900 dark:text-white mb-6 border-b pb-2 border-gray-700">Additional Information</h2>
<div class="p-0">
{% if event.details %}
<h3 class="text-xl font-medium text-gray-800 dark:text-white mb-4">Event Details</h3>
<div class="prose prose-lg max-w-none text-gray-700 dark:text-gray-300">
{{ event.details|safe }}
</div>
{% else %}
<p class="text-gray-400">No additional details provided.</p>
{% endif %}
</div>
</div>

{% if event.page_link %}
<div class="mt-8 pt-4 border-t border-gray-700 text-center">
<a href="{{ event.page_link }}" target="_blank"
class="inline-block bg-blue-600 text-white px-8 py-3 rounded-lg font-semibold text-lg hover:bg-blue-700 transition-colors shadow-lg">
Visit Event Page &rarr;
</a>
</div>
{% endif %}
</div>
</article>

<div class="mt-12">
<div class=text-center>
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">Explore More Archived Events</h2>
<a href="{% url 'newsletter_archived_events' %}"
class="inline-block bg-white text-teal-600 px-6 py-3 rounded-lg font-semibold hover:bg-blue-50 transition-colors">
View All Archived Events
</a>
</div>
</div>

</div>
{% endblock %}
113 changes: 113 additions & 0 deletions corpus/templates/newsletter/archived_events.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
{% extends 'newsletter/base.html' %}
{% load static %}

{% block title %}
Archived Events
{% endblock %}

{% block content %}
<div class="px-4 py-8 md:py-12">
<header class="text-center mb-12">
<h1 class="text-3xl md:text-4xl font-extrabold text-gray-800 dark:text-white mb-2">
Archived Events
</h1>
<p class="text-gray-500 dark:text-gray-400">A look back at past activities and events.</p>
</header>
<form method="get" class="mb-8 p-4 rounded-lg shadow-lg flex flex-wrap gap-4 items-center justify-center">
<div class="form-control">
<select name="year" id="year-select" class="select select-bordered w-full max-w-xs bg-gray-50 dark:bg-gray-700 dark:border-gray-600 dark:text-white font-bold text-base font-medium">
<option value="">All Years</option>
{% for year in available_years %}
<option value="{{ year }}" {% if selected_year|slugify == year|slugify %}selected{% endif %}>{{ year }}</option>
{% endfor %}
</select>
</div>
<div class="form-control">
<select name="sig" id="sig-select" class="select select-bordered w-full max-w-xs bg-gray-50 dark:bg-gray-700 dark:border-gray-600 dark:text-white font-bold text-base font-medium">
<option value="">All SIGs</option>
{% for sig in all_sigs %}
<option value="{{ sig.id }}" {% if selected_sig_id|slugify == sig.id|slugify %}selected{% endif %}>{{ sig.name }}</option>
{% endfor %}
</select>
</div>
<div class="mt-auto">
<button type="submit" class="btn btn-primary">Apply</button>
<a href="{% url 'newsletter_archived_events' %}" class="btn btn-ghost ml-2 dark:text-gray-300">Reset</a>
</div>
</form>
<div class="container mx-auto overflow-x-auto shadow-xl rounded-lg">
<table class="table w-full text-left bg-white dark:bg-gray-800 text-gray-900 dark:text-white">

<thead class="bg-gray-200 dark:bg-gray-700/70 border-b border-gray-300 dark:border-gray-700">
<tr>
<th class="px-6 py-3 text-xs font-semibold uppercase tracking-wider text-gray-700 dark:text-gray-300 w-1/3">
Event Name
</th>
<th class="px-6 py-3 text-xs font-semibold uppercase tracking-wider text-gray-700 dark:text-gray-300 w-1/4">
SIGs Involved
</th>
<th class="px-6 py-3 text-xs font-semibold uppercase tracking-wider text-gray-700 dark:text-gray-300 w-1/4">
Date
</th>
<th class="px-6 py-3 text-xs font-semibold uppercase tracking-wider text-gray-700 dark:text-gray-300 w-1/6">
Actions
</th>
</tr>
</thead>

<tbody class="text-lg font-medium">
{% for event in events %}
<tr>
<td class="px-6 py-4 whitespace-normal font-medium text-gray-900 dark:text-white">
{{ event.name }}
</td>
<td class="px-6 py-4">
<div class="flex flex-wrap gap-2">
{% for sig in event.sigs.all %}
<span class="badge text-white text-xs font-medium px-2 py-0.5 rounded"
style="background-color: {{ sig.color }}; border: none;">
{{ sig.name }}
</span>
{% empty %}
<span class="text-gray-500 dark:text-gray-400">—</span>
{% endfor %}
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-white-500 dark:text-white-400">
{{ event.start_date|date:"F j, Y" }}
</td>
<td class="px-6 py-4 whitespace-nowrap">
{% if is_admin %}
<a href="{% url 'newsletter_archived_event_detail' event.id %}" class="btn btn-primary btn-sm" role="button">
View Details
</a>
<form action="{% url 'newsletter_toggle_announcement' event.id %}" method="post" class="inline-block">
{% csrf_token %}
<button type="submit" class="btn btn-warning btn-sm">
Unarchive
</button>
</form>
<a href="{% url 'newsletter_edit_announcement' event.id %}"
class="btn btn-secondary btn-sm">
Edit
</a>

{% else %}
<a href="{% url 'newsletter_archived_event_detail' event.id %}" class="btn btn-primary btn-sm" role="button">
View Details
</a>
{% endif %}
</td>
</tr>
{% empty %}
<tr>
<td colspan="4" class="text-center py-10 bg-gray-100 dark:bg-gray-800 rounded-lg">
<p class="text-gray-500 dark:text-gray-400">No archived events match the current filter.</p>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
Loading