Skip to content

Commit

Permalink
Merge pull request #1286 from BCStudentSoftwareDevTeam/undo-button
Browse files Browse the repository at this point in the history
Undo button for event deletion
  • Loading branch information
BrianRamsay committed Jul 31, 2024
2 parents 6bd7229 + 53ffbc4 commit 24df5c5
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 53 deletions.
27 changes: 25 additions & 2 deletions app/controllers/admin/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,10 +355,33 @@ def cancelRoute(eventId):
else:
abort(403)

@admin_bp.route('/event/undo', methods=['GET'])
def undoEvent():
try:
events = session['lastDeletedEvent']
for eventId in events:
Event.update({Event.deletionDate: None, Event.deletedBy: None}).where(Event.id == eventId).execute()
event = Event.get_or_none(Event.id == eventId)
recurringEvents = list(Event.select().where((Event.recurringId==event.recurringId) & (Event.deletionDate == None)).order_by(Event.id))
if event.recurringId is not None:
nameCounter = 1
for recurringEvent in recurringEvents:
newEventNameList = recurringEvent.name.split()
newEventNameList[-1] = f"{nameCounter}"
newEventNameList = " ".join(newEventNameList)
Event.update({Event.name: newEventNameList}).where(Event.id==recurringEvent.id).execute()
nameCounter += 1
flash("Deletion successfully undone.", "success")
return redirect('/eventsList/' + str(g.current_term))
except Exception as e:
print('Error while canceling event:', e)
return "", 500

@admin_bp.route('/event/<eventId>/delete', methods=['POST'])
def deleteRoute(eventId):
try:
deleteEvent(eventId)
session['lastDeletedEvent'] = [eventId]
flash("Event successfully deleted.", "success")
return redirect(url_for("main.events", selectedTerm=g.current_term))

Expand All @@ -369,7 +392,7 @@ def deleteRoute(eventId):
@admin_bp.route('/event/<eventId>/deleteEventAndAllFollowing', methods=['POST'])
def deleteEventAndAllFollowingRoute(eventId):
try:
deleteEventAndAllFollowing(eventId)
session["lastDeletedEvent"] = deleteEventAndAllFollowing(eventId)
flash("Events successfully deleted.", "success")
return redirect(url_for("main.events", selectedTerm=g.current_term))

Expand All @@ -380,7 +403,7 @@ def deleteEventAndAllFollowingRoute(eventId):
@admin_bp.route('/event/<eventId>/deleteAllRecurring', methods=['POST'])
def deleteAllRecurringEventsRoute(eventId):
try:
deleteAllRecurringEvents(eventId)
session["lastDeletedEvent"] = deleteAllRecurringEvents(eventId)
flash("Events successfully deleted.", "success")
return redirect(url_for("main.events", selectedTerm=g.current_term))

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/events/routes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from flask import Flask, redirect, flash, url_for, request, render_template, g, json, abort
from flask import Flask, redirect, flash, url_for, request, render_template, g, json, abort, session
from datetime import datetime
from peewee import DoesNotExist

Expand Down
35 changes: 19 additions & 16 deletions app/logic/events.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from flask import url_for
from flask import url_for, g, session
from peewee import DoesNotExist, fn, JOIN
from dateutil import parser
from datetime import timedelta, date, datetime
Expand Down Expand Up @@ -58,14 +58,14 @@ def deleteEvent(eventId):
newEventName = recurringEvent.name
eventDeleted = True

program = event.program
program = event.program

if program:
createActivityLog(f"Deleted \"{event.name}\" for {program.programName}, which had a start date of {datetime.strftime(event.startDate, '%m/%d/%Y')}.")
else:
createActivityLog(f"Deleted a non-program event, \"{event.name}\", which had a start date of {datetime.strftime(event.startDate, '%m/%d/%Y')}.")

event.delete_instance(recursive = True, delete_nullable = True)
Event.update({Event.deletionDate: datetime.now(), Event.deletedBy: g.current_user}).where(Event.id == event.id).execute()

def deleteEventAndAllFollowing(eventId):
"""
Expand All @@ -75,9 +75,10 @@ def deleteEventAndAllFollowing(eventId):
if event:
if event.recurringId:
recurringId = event.recurringId
recurringSeries = list(Event.select().where((Event.recurringId == recurringId) & (Event.startDate >= event.startDate)))
for seriesEvent in recurringSeries:
seriesEvent.delete_instance(recursive = True)
recurringSeries = list(Event.select(Event.id).where((Event.recurringId == recurringId) & (Event.startDate >= event.startDate)))
deletedEventList = [recurringEvent.id for recurringEvent in recurringSeries]
Event.update({Event.deletionDate: datetime.now(), Event.deletedBy: g.current_user}).where((Event.recurringId == recurringId) & (Event.startDate >= event.startDate)).execute()
return deletedEventList

def deleteAllRecurringEvents(eventId):
"""
Expand All @@ -87,9 +88,10 @@ def deleteAllRecurringEvents(eventId):
if event:
if event.recurringId:
recurringId = event.recurringId
allRecurringEvents = list(Event.select().where(Event.recurringId == recurringId))
for aRecurringEvent in allRecurringEvents:
aRecurringEvent.delete_instance(recursive = True)
allRecurringEvents = list(Event.select(Event.id).where(Event.recurringId == recurringId).order_by(Event.startDate))
eventId = allRecurringEvents[0].id
return deleteEventAndAllFollowing(eventId)



def attemptSaveEvent(eventData, attachmentFiles = None, renewedEvent = False):
Expand Down Expand Up @@ -188,7 +190,7 @@ def getStudentLedEvents(term):
studentLedEvents = list(Event.select(Event, Program)
.join(Program)
.where(Program.isStudentLed,
Event.term == term)
Event.term == term, Event.deletionDate == None)
.order_by(Event.startDate, Event.timeStart)
.execute())

Expand All @@ -207,7 +209,7 @@ def getUpcomingStudentLedCount(term, currentTime):
upcomingCount = (Program.select(Program.id, fn.COUNT(Event.id).alias("eventCount"))
.join(Event, on=(Program.id == Event.program_id))
.where(Program.isStudentLed,
Event.term == term,
Event.term == term, Event.deletionDate == None,
(Event.endDate > currentTime) | ((Event.endDate == currentTime) & (Event.timeEnd >= currentTime)),
Event.isCanceled == False)
.group_by(Program.id))
Expand All @@ -231,7 +233,7 @@ def getTrainingEvents(term, user):
trainingQuery = (Event.select(Event).distinct()
.join(Program, JOIN.LEFT_OUTER)
.where(Event.isTraining == True,
Event.term == term)
Event.term == term, Event.deletionDate == None)
.order_by(Event.isAllVolunteerTraining.desc(), Event.startDate, Event.timeStart))

hideBonner = (not user.isAdmin) and not (user.isStudent and user.isBonnerScholar)
Expand All @@ -244,13 +246,14 @@ def getBonnerEvents(term):
bonnerScholarsEvents = list(Event.select(Event, Program.id.alias("program_id"))
.join(Program)
.where(Program.isBonnerScholars,
Event.term == term)
Event.term == term, Event.deletionDate == None)
.order_by(Event.startDate, Event.timeStart)
.execute())
return bonnerScholarsEvents

def getOtherEvents(term):
"""
Get the list of the events not caught by other functions to be displayed in
the Other Events section of the Events List page.
:return: A list of Other Event objects
Expand All @@ -260,7 +263,7 @@ def getOtherEvents(term):

otherEvents = list(Event.select(Event, Program)
.join(Program, JOIN.LEFT_OUTER)
.where(Event.term == term,
.where(Event.term == term, Event.deletionDate == None,
Event.isTraining == False,
Event.isAllVolunteerTraining == False,
((Program.isOtherCeltsSponsored) |
Expand All @@ -285,7 +288,7 @@ def getUpcomingEventsForUser(user, asOf=datetime.now(), program=None):
.join(ProgramBan, JOIN.LEFT_OUTER, on=((ProgramBan.program == Event.program) & (ProgramBan.user == user)))
.join(Interest, JOIN.LEFT_OUTER, on=(Event.program == Interest.program))
.join(EventRsvp, JOIN.LEFT_OUTER, on=(Event.id == EventRsvp.event))
.where(Event.startDate >= asOf,
.where(Event.deletionDate == None, Event.startDate >= asOf,
(Interest.user == user) | (EventRsvp.user == user),
ProgramBan.user.is_null(True) | (ProgramBan.endDate < asOf)))

Expand Down Expand Up @@ -494,7 +497,7 @@ def getEventRsvpCountsForTerm(term):
"""
amount = (Event.select(Event, fn.COUNT(EventRsvp.event_id).alias('count'))
.join(EventRsvp, JOIN.LEFT_OUTER)
.where(Event.term == term)
.where(Event.term == term, Event.deletionDate == None)
.group_by(Event.id))

amountAsDict = {event.id: event.count for event in amount}
Expand Down
6 changes: 6 additions & 0 deletions app/models/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,18 @@ class Event(baseModel):
contactName = CharField(null=True)
program = ForeignKeyField(Program)
isCanceled = BooleanField(default=False)
deletionDate = DateTimeField(null=True)
deletedBy = TextField(null=True)

_spCache = "Empty"

def __str__(self):
return f"{self.id}: {self.description}"

@property
def isDeleted(self):
return self.deletionDate is not None

@property
def noProgram(self):
return not self.program_id
Expand Down
21 changes: 17 additions & 4 deletions app/static/js/base.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
const flashMessageResponse = function flashEventResponse(message){
if (message.slice(-8) == "deleted."){

return `<strong><a href="/event/undo" style="color: dark-green;">Undo</a></strong>`
}
return '';
}

function msgFlash(flash_message, status){
if (!["success", "warning", "info", "danger"].includes(status)) status = "danger";
$("#flash_container").prepend(`
<div class="alert alert-${status} alert-dismissible" role="alert">${flash_message}
<button type="button" class="btn-close kiosk-hide" data-bs-dismiss="alert" aria-label="Close"></button>
<div class="alert alert-${status} alert-dismissible alert-success" role="alert">${flash_message}
${flashMessageResponse(flash_message)}
<button type="button" class="btn-close kiosk-hide" id="flashResponded" aria-label="Close"></button>
</div>`);
$(".alert").delay(5000).fadeOut();
$("#flashResponded").click(function(){
$(".alert").delay(1000).fadeOut();
})
}



$(document).ready(function() {
$("select[name='newuser']").on('change', function(e) {
$(e.target).parent().submit();
});

$(flashMessages).each((i, messageData) => {msgFlash(messageData[1], messageData[0])})

toastElementList = [].slice.call(document.querySelectorAll('.toast'))
Expand Down
5 changes: 1 addition & 4 deletions app/static/js/event_list.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,4 @@ function removeRsvpForEvent(eventID){
console.log(error, status)
}
})
}



}
3 changes: 1 addition & 2 deletions app/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
<link rel="stylesheet" href="{{url_for('static', filename ='css/base.css') }}?u={{lastStaticUpdate}}">
<link rel="stylesheet" href="{{url_for('static', filename ='css/sidebar.css') }}?u={{lastStaticUpdate}}">
{% endblock %}

<title>
{% block title %}
{% if title %}CELTS Link - {{ title }}{% else %}Welcome to CELTS Link{% endif %}
Expand Down Expand Up @@ -47,7 +46,7 @@
<div id="maincontent" class="main-content container">
<div class="flash_container" id="flash_container">
{% with messages = get_flashed_messages(with_categories=true) %}
<script> var flashMessages = {{messages | tojson}} </script>
<script> var flashMessages = {{messages | tojson}} </script>
{% endwith %}
</div>
<div class="sidebar-icon d-lg-none position-fixed top-0 start-0 d-print-none">
Expand Down
16 changes: 9 additions & 7 deletions app/templates/events/event_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,12 @@ <h1 class="text-center">Events List for {{selectedTerm.description}}</h1>
<select class="form-select" name='eventTerm' id='inputTerm' onchange="location=this.value">
{% for term in listOfTerms %}
    <option value='/eventsList/{{term}}/{{activeTab}}/{{programID}}' {{ "selected" if selectedTerm.id == term.id }}>{{term.description}} </option>
    {% endfor %}
  {% endfor %}
    </select>
</div>
</div>
</div>
{% if user.isAdmin %}
<div class="row px-4">
{% if user.isAdmin %}
<div class="row col-md-4 px-4">
<div class = "d-none d-sm-block col "></div>
<div class="form-check form-switch mb-2 col-auto">
<label class="form-check-label" for="viewPastEventsToggle">View Past Events</label>
Expand All @@ -42,7 +41,8 @@ <h1 class="text-center">Events List for {{selectedTerm.description}}</h1>
{% endif %}
</div>
</div>
{% endif %}
{% endif %}
</div>
</div>
<div class="row">
<ul class="nav nav-tabs nav-fill mx-3 mb-3" id="pills-tab" role="tablist">
Expand All @@ -68,7 +68,7 @@ <h1 class="text-center">Events List for {{selectedTerm.description}}</h1>
</div>

{% macro createTable(events, type) %}
{% if events|count %}
{% if events|count%}
<div class="table-responsive">
<table class="table">
<thead>
Expand All @@ -84,7 +84,8 @@ <h1 class="text-center">Events List for {{selectedTerm.description}}</h1>
</tr>
</thead>
<tbody>
{% for event in events %}
{% for event in events%}

{% if event.isPastEnd %}
<tr height = '50' class="table-light showlist" style="display: none;">
{% else %}
Expand Down Expand Up @@ -135,6 +136,7 @@ <h1 class="text-center">Events List for {{selectedTerm.description}}</h1>
</td>
{% endif %}
</tr>

{% endfor %}
{% if selectedTerm == g.current_term and events[-1].isPastStart %}
<tr>
Expand Down
Loading

0 comments on commit 24df5c5

Please sign in to comment.