Skip to content
Closed
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
14 changes: 7 additions & 7 deletions app/logic/events.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from flask import url_for, g, session
from peewee import DoesNotExist, fn, JOIN
from peewee import DoesNotExist, fn, JOIN, Case, Value
from dateutil import parser
from datetime import timedelta, date, datetime
from dateutil.relativedelta import relativedelta
Expand Down Expand Up @@ -398,21 +398,21 @@ def getParticipatedEventsForUser(user):
Used in testing, defaults to the current timestamp.
:return: A list of Event objects
"""

participatedEvents = (Event.select(Event, Program.programName)
participatedEvents = (Event.select(Event, Program.programName, Case(None, (
((Event.isLaborOnly | Event.name.contains("Labor")) & Event.isService, "Labor & Volunteer"),
((Event.isLaborOnly | Event.name.contains("Labor")), "Labor"),
(Event.isService, "Volunteer")), "Attendee").alias("participatedType"))
.join(Program, JOIN.LEFT_OUTER).switch()
.join(EventParticipant)
.where(EventParticipant.user == user,
Event.isAllVolunteerTraining == False, Event.deletionDate == None)
.order_by(Event.startDate, Event.name))

allVolunteer = (Event.select(Event, "")
allVolunteer = (Event.select(Event, "", Value("Volunteer").alias("participatedType"))
.join(EventParticipant)
.where(Event.isAllVolunteerTraining == True,
EventParticipant.user == user))
union = participatedEvents.union_all(allVolunteer)
unionParticipationWithVolunteer = list(union.select_from(union.c.id, union.c.programName, union.c.startDate, union.c.name).order_by(union.c.startDate, union.c.name).execute())

unionParticipationWithVolunteer = list(union.select_from(union.c.id, union.c.programName, union.c.startDate, union.c.name, union.c.participatedType).order_by(union.c.startDate, union.c.name).execute())
return unionParticipationWithVolunteer

def validateNewEventData(data):
Expand Down
27 changes: 27 additions & 0 deletions app/logic/volunteerSpreadsheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,32 @@ def termParticipation(term):

return dict(programParticipationDict)

def graduatingSeniorsVolunteerHours(academicYear):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm missing something but why do we need the function for graduating seniors hours? I thought we were looking at the event participation types for this PR

columns = ["Full Name", "Email", "B-Number", "Unique Volunteer Semesters", "Total Volunteer Hours"]

currentSeniors = (EventParticipant
.select(EventParticipant.user_id)
.join(User).switch(EventParticipant)
.join(Event)
.join(Term)
.where(Term.academicYear == academicYear, User.rawClassLevel.in_(["Senior", "Graduating"]), Event.isService == True,
Event.deletionDate == None, Event.isCanceled == False))

query = (EventParticipant
.select(fn.CONCAT(User.firstName, ' ', User.lastName),
fn.CONCAT(User.username, '@berea.edu'),
User.bnumber,
fn.COUNT(fn.DISTINCT(Event.term)).alias("semester_count"),
fn.SUM(EventParticipant.hoursEarned).alias("total_hours"))
.join(User).switch(EventParticipant)
.join(Event)
.where(Event.isService == True, Event.deletionDate == None, Event.isCanceled == False, EventParticipant.user_id.in_(currentSeniors))
.group_by(User.bnumber)
.having(fn.COUNT(fn.DISTINCT(Event.term)) >= 4)
.order_by(SQL("semester_count").desc()))

return (columns, query.tuples())


def removeNullParticipants(participantList):
return list(filter(lambda participant: participant, participantList))
Expand Down Expand Up @@ -270,6 +296,7 @@ def createSpreadsheet(academicYear):
makeDataXls("Unique Volunteers", getUniqueVolunteers(academicYear), workbook, sheetDesc=f"All students who participated in at least one service event during {academicYear}.")
makeDataXls("Only All Volunteer Training", onlyCompletedAllVolunteer(academicYear), workbook, sheetDesc="Students who participated in an All Volunteer Training, but did not participate in any service events.")
makeDataXls("Retention Rate By Semester", getRetentionRate(academicYear), workbook, sheetDesc="The percentage of students who participated in service events in the fall semester who also participated in a service event in the spring semester. Does not currently account for fall graduations.")
makeDataXls("Graduating Seniors", graduatingSeniorsVolunteerHours(academicYear), workbook, sheetDesc="Graduating seniors who have earned any number of service hours for at least 4 unique semesters.")

fallTerm = getFallTerm(academicYear)
springTerm = getSpringTerm(academicYear)
Expand Down
3 changes: 1 addition & 2 deletions app/static/js/volunteerDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ $(document).ready(function () {
}

function sortVolunteers() {
let sortedTable = $("#volunteerInformationTableToPrint_wrapper");
let entriesTable = sortedTable.find(".volunteerInfoEntries");


entriesTable.sort(function (a, b) {
let textA = a.getElementsByClassName('nameSelect')[0].innerText
Expand Down
2 changes: 2 additions & 0 deletions app/templates/main/userProfile.html
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,14 @@ <h3 class="accordion-header" id="headingTwo">
<thead>
<th scope="col">Program</th>
<th scope="col">Event Name</th>
<th scope="col">Participation Type</th>
<th scope="col">Event Date</th>
</thead>
{% for event in participatedEvents %}
<tr>
<td>{{event.programName}}</td>
<td><a href= '/event/{{event.id}}/view' class="link-primary">{{event.name}}</a></td>
<td>{{event.participatedType}}</td>
<td nowrap>{{event.startDate.strftime('%m/%d/%Y')}}</td>
</tr>
{% endfor %}
Expand Down
92 changes: 92 additions & 0 deletions tests/code/test_spreadsheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -684,4 +684,96 @@ def test_getUniqueVolunteers(fixture_info):
])


@pytest.mark.integration
def test_graduatingSeniorsVolunteerHours(fixture_info):
columns, rows = graduatingSeniorsVolunteerHours("2024-2025-test")
assert columns == ["Full Name", "Email", "B-Number", "Unique Volunteer Semesters", "Total Volunteer Hours"]

assert list(rows) == []

term5 = Term.create(description='Fall 2021', academicYear='2021-2022-test')
term6 = Term.create(description='Spring 2022', academicYear='2021-2022-test')
term7 = Term.create(description='Fall 2022', academicYear='2022-2023-test')

program5 = Program.create(programName='Program5')

event5 = Event.create(name='Event5', term=term5, program=program5, startDate=date(2021, 9, 1),
isCanceled=False, deletionDate=None, isService=True)
event6 = Event.create(name='Event6', term=term6, program=program5, startDate=date(2022, 2, 1),
isCanceled=False, deletionDate=None, isService=True)
event7 = Event.create(name='Event7', term=term7, program=program5, startDate=date(2022, 9, 1),
isCanceled=False, deletionDate=None, isService=True)

# Give Bob 3 more unique semesters of service (he already has 1 from before - term2/2024-2025)
EventParticipant.create(user=fixture_info['user3'], event=event5, hoursEarned=2)
EventParticipant.create(user=fixture_info['user3'], event=event6, hoursEarned=3)
EventParticipant.create(user=fixture_info['user3'], event=event7, hoursEarned=4)

# Bob now has 4 unique semesters total, and is a Senior in 2024-2025-test, so his info should appear
columns, rows = graduatingSeniorsVolunteerHours("2024-2025-test")
result = list(rows)
assert len(result) == 1
assert result[0] == ("Bob Builder", "builderb@berea.edu", "B00700932", 4, 9.0)

# Bob should NOT appear when querying a year where he is not a Senior (Bob is Senior only in 2024-2025)
columns, rows = graduatingSeniorsVolunteerHours("2023-2024-test")
assert list(rows) == []

# non-senior students should never appear even with enough semesters
extraTerm = Term.create(description='Spring 2021', academicYear='2020-2021-test')
extraTerm2 = Term.create(description='Fall 2020', academicYear='2020-2021-test')
extraTerm3 = Term.create(description='Spring 2020', academicYear='2019-2020-test')

event8 = Event.create(name='Event8', term=extraTerm, program=program5, startDate=date(2021, 2, 1),
isCanceled=False, deletionDate=None, isService=True)
event9 = Event.create(name='Event9', term=extraTerm2, program=program5, startDate=date(2020, 9, 1),
isCanceled=False, deletionDate=None, isService=True)
event10 = Event.create(name='Event10', term=extraTerm3, program=program5, startDate=date(2020, 2, 1),
isCanceled=False, deletionDate=None, isService=True)

# give John (Sophomore) 4 unique semesters, so it should never appear
EventParticipant.create(user=fixture_info['user1'], event=event8, hoursEarned=1)
EventParticipant.create(user=fixture_info['user1'], event=event9, hoursEarned=1)
EventParticipant.create(user=fixture_info['user1'], event=event10, hoursEarned=1)
# John already has term1 (2023-2024-test) from fixture, so now has 4 unique semesters
columns, rows = graduatingSeniorsVolunteerHours("2023-2024-test")
assert list(rows) == []

# Test "Graduating" class level works the same as "Senior"
graduatingUser = User.create(username="smithj", firstName="James", lastName="Smith",
bnumber="B999999", major="Math", rawClassLevel="Graduating")

gradTerm1 = Term.create(description='Fall 2023 Grad', academicYear='2023-2024-test')
gradTerm2 = Term.create(description='Spring 2023 Grad', academicYear='2022-2023-test')
gradTerm3 = Term.create(description='Fall 2022 Grad', academicYear='2022-2023-test')
gradTerm4 = Term.create(description='Spring 2022 Grad', academicYear='2021-2022-test')

gevent1 = Event.create(name='GEvent1', term=gradTerm1, program=program5, startDate=date(2023, 9, 5),
isCanceled=False, deletionDate=None, isService=True)
gevent2 = Event.create(name='GEvent2', term=gradTerm2, program=program5, startDate=date(2023, 2, 5),
isCanceled=False, deletionDate=None, isService=True)
gevent3 = Event.create(name='GEvent3', term=gradTerm3, program=program5, startDate=date(2022, 9, 5),
isCanceled=False, deletionDate=None, isService=True)
gevent4 = Event.create(name='GEvent4', term=gradTerm4, program=program5, startDate=date(2022, 2, 5),
isCanceled=False, deletionDate=None, isService=True)

EventParticipant.create(user=graduatingUser, event=gevent1, hoursEarned=5)
EventParticipant.create(user=graduatingUser, event=gevent2, hoursEarned=5)
EventParticipant.create(user=graduatingUser, event=gevent3, hoursEarned=5)
EventParticipant.create(user=graduatingUser, event=gevent4, hoursEarned=5)

columns, rows = graduatingSeniorsVolunteerHours("2023-2024-test")
result = list(rows)
assert len(result) == 1
assert result[0] == ("James Smith", "smithj@berea.edu", "B999999", 4, 20.0)

# non-service events should not be counted
nonServiceTerm = Term.create(description='Fall 2019', academicYear='2019-2020-test')
nonServiceEvent = Event.create(name='NonServiceEvent', term=nonServiceTerm, program=program5,
startDate=date(2019, 9, 1), isCanceled=False, deletionDate=None, isService=False)
EventParticipant.create(user=fixture_info['user3'], event=nonServiceEvent, hoursEarned=5)

# Bob still has exactly 4 semesters with volunteer hours, the non-service event participation should not push the count up
columns, rows = graduatingSeniorsVolunteerHours("2024-2025-test")
result = list(rows)
assert result[0][3] == 4
Loading