# pylint: disable=too-many-boolean-expressions
import logging
import pickle
from cacheops import invalidate_obj
from django import forms, http
from django.contrib import messages
from django.shortcuts import redirect, render
from django.urls import reverse
from ....auth.decorators import eighth_admin_required
from ....groups.models import Group
from ...forms.admin.activities import ActivityForm, QuickActivityForm
from ...models import EighthActivity, EighthRoom, EighthScheduledActivity, EighthSponsor, EighthWaitlist
from ...tasks import room_changed_activity_email
from ...utils import get_start_date
logger = logging.getLogger(__name__)
[docs]@eighth_admin_required
def add_activity_view(request):
if request.method == "POST":
form = QuickActivityForm(request.POST)
if form.is_valid():
new_id = request.POST.get("id", "default")
if new_id == "default":
activity = form.save()
else:
activity = EighthActivity.objects.create(name=form.cleaned_data["name"], id=int(new_id))
invalidate_obj(activity)
messages.success(request, "Successfully added activity.")
return redirect("eighth_admin_edit_activity", activity_id=activity.id)
else:
messages.error(request, "Error adding activity.")
request.session["add_activity_form"] = pickle.dumps(form)
return redirect("eighth_admin_dashboard")
else:
context = {"admin_page_title": "Add Activity", "form": QuickActivityForm(), "available_ids": EighthActivity.available_ids()}
return render(request, "eighth/admin/add_activity.html", context)
[docs]@eighth_admin_required
def edit_activity_view(request, activity_id):
try:
activity = EighthActivity.objects.get(id=activity_id) # include deleted
except EighthActivity.DoesNotExist as e:
raise http.Http404 from e
if request.method == "POST":
form = ActivityForm(request.POST, instance=activity, sponsors=activity.sponsors.all())
if form.is_valid():
try:
# Check if sponsor change
old_sponsors = activity.sponsors.all()
old_sponsor_ids = old_sponsors.values_list("id", flat=True)
new_sponsor_ids = [s.id for s in form.cleaned_data["sponsors"]]
if set(old_sponsor_ids) != set(new_sponsor_ids) and old_sponsor_ids:
start_date = get_start_date(request)
sched_acts_default = EighthScheduledActivity.objects.filter(activity=activity, sponsors=None, block__date__lt=start_date)
if sched_acts_default.count() > 0:
# This will change scheduled activities that used overrides in the past.
# Thus, by looping through the scheduled activities that didn't have any
# custom sponsors specified, we *could* prevent anything from visibly
# changing by making an override with the value of the previous default.
# Yes: Save History => Override old values
# No: Change Globally => Don't override old values, they will change to new default
if "change_sponsor_history" in request.POST:
change = request.POST.get("change_sponsor_history")
if change == "yes":
# Override old entries
for sa in sched_acts_default:
for sponsor in old_sponsors:
sa.sponsors.add(sponsor)
sa.save()
messages.success(request, f"Overrode {sched_acts_default.count()} scheduled activities to old sponsor default")
elif change == "no":
# Don't override
messages.success(request, "Changing default sponsors globally")
# Continues to form.save()
else:
# show message, asking whether to change history
context = {
"admin_page_title": "Keep Sponsor History?",
"activity": activity,
"sched_acts_count": sched_acts_default.count(),
"start_date": start_date,
"old_sponsors": EighthSponsor.objects.filter(id__in=old_sponsor_ids),
"new_sponsors": EighthSponsor.objects.filter(id__in=new_sponsor_ids),
"form": form,
}
return render(request, "eighth/admin/keep_sponsor_history.html", context)
else:
messages.success(request, "You modified the default sponsors, but those changes will not affect any scheduled activities.")
# Check if room change
old_rooms = activity.rooms.all()
old_room_ids = old_rooms.values_list("id", flat=True)
new_room_ids = [r.id for r in form.cleaned_data["rooms"]]
if set(old_room_ids) != set(new_room_ids) and old_room_ids:
start_date = get_start_date(request)
sched_acts_default = EighthScheduledActivity.objects.filter(activity=activity, rooms=None, block__date__lt=start_date)
if sched_acts_default.count() > 0:
# This will change scheduled activities that used overrides in the past.
# Thus, by looping through the scheduled activities that didn't have any
# custom rooms specified, we *could* prevent anything from visibly
# changing by making an override with the value of the previous default.
# Yes: Save History => Override old values
# No: Change Globally => Don't override old values, they will change to new default
if "change_room_history" in request.POST:
change = request.POST.get("change_room_history")
if change == "yes":
# Override old entries
for sa in sched_acts_default:
sa.rooms.set(old_rooms)
messages.success(request, f"Overrode {sched_acts_default.count()} scheduled activities to old room default")
elif change == "no":
# Don't override
messages.success(request, "Changing default rooms globally")
# Continues to form.save()
else:
# show message, asking whether to change history
context = {
"admin_page_title": "Keep Room History?",
"activity": activity,
"sched_acts_count": sched_acts_default.count(),
"start_date": start_date,
"old_rooms": EighthRoom.objects.filter(id__in=old_room_ids),
"new_rooms": EighthRoom.objects.filter(id__in=new_room_ids),
"form": form,
}
return render(request, "eighth/admin/keep_room_history.html", context)
else:
messages.success(request, "You modified the default rooms, but those changes will not affect any scheduled activities.")
if set(old_room_ids) != set(new_room_ids):
# Notify people that the activities they're signed up for have changed rooms
messages.success(request, "Notifying students of this room change.")
room_changed_activity_email.delay(activity, old_rooms, EighthRoom.objects.filter(id__in=new_room_ids))
activity = form.save()
activity.subscribers.add(*[sponsor.user for sponsor in form.cleaned_data["sponsors"]])
activity.subscribers.add(*form.cleaned_data["club_sponsors"], *form.cleaned_data["officers"])
activity.save()
except forms.ValidationError as error:
error = str(error)
messages.error(request, error)
else:
if (
activity.restricted
or activity.one_a_day
or activity.presign
or activity.both_blocks
or activity.sticky
or activity.administrative
):
all_sched_acts = EighthScheduledActivity.objects.filter(activity=activity)
for sa in all_sched_acts:
EighthWaitlist.objects.filter(scheduled_activity=sa).delete()
messages.success(request, "Successfully edited activity.")
if "add_group" in request.POST:
grp_name = f"Activity: {activity.name}"
grp, status = Group.objects.get_or_create(name=grp_name)
activity.restricted = True
activity.groups_allowed.add(grp)
activity.save()
invalidate_obj(activity)
messages.success(request, "{} to '{}' group".format("Created and added" if status else "Added", grp_name))
return redirect("eighth_admin_edit_group", grp.id)
return redirect("eighth_admin_edit_activity", activity_id)
else:
messages.error(request, "Error adding activity.")
else:
form = ActivityForm(instance=activity, sponsors=activity.sponsors.all())
activities = EighthActivity.undeleted_objects.order_by("name")
activity_groups = []
for g in activity.groups_allowed.all():
group = {}
group["id"] = g.id
group["name"] = str(g)
group["members_alpha"] = sorted(g.user_set.all(), key=lambda x: (x.last_name, x.first_name))
group["members_alpha_count"] = len(group["members_alpha"])
activity_groups.append(group)
activity_members = sorted(activity.users_allowed.all(), key=lambda x: (x.last_name, x.first_name))
context = {
"form": form,
"admin_page_title": "Edit Activity",
"delete_url": reverse("eighth_admin_delete_activity", args=[activity_id]),
"activity": activity,
"activity_groups": activity_groups,
"activities": activities,
"activity_members": activity_members,
}
return render(request, "eighth/admin/edit_activity.html", context)
[docs]@eighth_admin_required
def delete_activity_view(request, activity_id=None):
try:
activity = EighthActivity.objects.get(id=activity_id)
except EighthActivity.DoesNotExist as e:
raise http.Http404 from e
perm_delete = False
if activity.deleted and "perm" in request.GET:
perm_delete = True
if request.method == "POST":
if perm_delete:
activity.delete()
else:
activity.deleted = True
activity.save()
invalidate_obj(activity)
messages.success(request, "Successfully deleted activity.")
return redirect("eighth_admin_dashboard")
else:
context = {
"admin_page_title": "Delete Activity",
"item_name": activity.name,
"help_text": (
"Deleting will not destroy past attendance data for this "
"activity. The activity will just be marked as deleted "
"and hidden from non-attendance views."
if not perm_delete
else "This will destroy past attendance data."
),
}
return render(request, "eighth/admin/delete_form.html", context)