2024-01-22 12:33:34 -05:00
from datetime import datetime , timedelta
2023-12-22 01:08:20 -05:00
from django . conf import settings
from django . contrib import messages
2024-01-17 11:16:43 -05:00
from django . contrib . auth . decorators import permission_required
2024-01-15 21:31:06 -05:00
from django . contrib . auth . mixins import PermissionRequiredMixin
2024-01-19 15:33:54 -05:00
from django . db . models . functions import TruncMonth , TruncYear
2023-12-22 01:08:20 -05:00
from django . shortcuts import render
2024-01-22 12:33:34 -05:00
from django . template . defaultfilters import floatformat
2024-01-19 15:33:54 -05:00
from django . views . generic . dates import (
ArchiveIndexView ,
MonthArchiveView ,
YearArchiveView ,
)
2023-12-22 01:08:20 -05:00
2024-01-22 12:33:34 -05:00
import django_tables2 as tables
2022-05-05 17:21:48 -04:00
from dal import autocomplete
2024-01-22 12:33:34 -05:00
from django_tables2 import A , SingleTableMixin
2024-01-22 13:17:02 -05:00
from django_tables2 . export . views import ExportMixin
2022-02-03 13:45:58 -05:00
2024-01-17 21:17:24 -05:00
from membershipworks . membershipworks_api import MembershipWorks
from . models import EventExt , Member
2022-05-05 17:21:48 -04:00
class MemberAutocomplete ( autocomplete . Select2QuerySetView ) :
model = Member
search_fields = [ " account_name " ]
def get_queryset ( self ) :
if not self . request . user . has_perm ( " membershipworks.view_member " ) :
return Member . objects . none ( )
else :
return super ( ) . get_queryset ( )
2023-12-22 01:08:20 -05:00
2024-01-17 11:16:43 -05:00
@permission_required ( " membershipworks.view_eventext " )
2023-12-22 01:08:20 -05:00
def upcoming_events ( request ) :
now = datetime . now ( )
membershipworks = MembershipWorks ( )
membershipworks . login (
settings . MEMBERSHIPWORKS_USERNAME , settings . MEMBERSHIPWORKS_PASSWORD
)
events = membershipworks . get_events_list ( now )
if " error " in events :
messages . add_message (
request ,
messages . ERROR ,
f " MembershipWorks Error: { events [ ' error ' ] } " ,
)
# TODO: this should probably be an HTTP 500 response
return render ( request , " base.dj.html " )
ongoing_events = [ ]
full_events = [ ]
upcoming_events = [ ]
for event in events [ " evt " ] :
try :
# ignore hidden events
if event [ " cal " ] == 0 :
continue
event_details = membershipworks . get_event_by_eid ( event [ " eid " ] )
# Convert timestamps to datetime objects
event_details [ " sdp_dt " ] = datetime . fromtimestamp ( event_details [ " sdp " ] )
event_details [ " edp_dt " ] = datetime . fromtimestamp ( event_details [ " edp " ] )
# registration has already ended
if (
" erd " in event_details
and datetime . fromtimestamp ( event_details [ " erd " ] ) < now
) :
ongoing_events . append ( event_details )
# class is full
elif event_details [ " cnt " ] > = event_details [ " cap " ] :
full_events . append ( event_details )
else :
upcoming_events . append ( event_details )
except KeyError as e :
messages . add_message (
request ,
messages . ERROR ,
f " Event ' { event . get ( ' ttl ' ) } ' missing required property: ' { e . args [ 0 ] } ' " ,
)
# TODO: this should probably be an HTTP 500 response
return render ( request , " base.dj.html " )
context = {
" event_sections " : [
{
" title " : " Upcoming Events " ,
" blurb " : " Events that are currently open for registration. " ,
" events " : upcoming_events ,
" truncate " : False ,
} ,
{
" title " : " Just Missed " ,
" blurb " : " These classes are currently full at time of writing. If you are interested, please check the event ' s page; spots occasionally open up. Keep an eye on this newsletter to see when these classes are offered again. " ,
" events " : full_events ,
" truncate " : True ,
} ,
{
" title " : " Ongoing Events " ,
" blurb " : " These events are ongoing. Registration is currently closed, but these events may be offered again in the future. " ,
" events " : ongoing_events ,
" truncate " : True ,
} ,
]
}
return render ( request , " membershipworks/upcoming_events.dj.html " , context )
2024-01-15 21:31:06 -05:00
2024-01-22 12:33:34 -05:00
class DurationColumn ( tables . Column ) :
def render ( self , value : timedelta ) :
if value is None :
return None
return floatformat ( value . total_seconds ( ) / 60 / 60 , - 2 )
2024-01-22 13:17:02 -05:00
def value ( self , value : timedelta ) :
if value is None :
return None
return value . total_seconds ( ) / 60 / 60
2024-01-22 12:33:34 -05:00
class EventTable ( tables . Table ) :
title = tables . Column (
linkify = lambda record : f " https://membershipworks.com/admin/#!event/admin/ { record . url } "
)
2024-01-22 13:17:02 -05:00
occurred = tables . BooleanColumn ( visible = False )
2024-01-22 12:33:34 -05:00
start = tables . DateColumn ( " N d, Y " )
duration = DurationColumn ( )
person_hours = DurationColumn ( )
2024-01-29 14:04:35 -05:00
meetings = tables . Column ( )
2024-01-22 12:33:34 -05:00
class Meta :
model = EventExt
fields = (
" title " ,
2024-01-22 13:17:02 -05:00
" occurred " ,
2024-01-22 12:33:34 -05:00
" start " ,
" instructor " ,
" category " ,
" count " ,
" cap " ,
2024-01-29 14:04:35 -05:00
" meetings " ,
2024-01-22 12:33:34 -05:00
" duration " ,
" person_hours " ,
)
row_attrs = {
" class " : lambda record : (
" " if record . occurred else " text-decoration-line-through table-danger "
)
}
class EventSummaryTable ( tables . Table ) :
event_count = tables . Column ( " Events " )
canceled_event_count = tables . Column ( " Canceled Events " )
count__sum = tables . Column ( " Tickets " )
instructor__count = tables . Column ( " Unique Instructors " )
2024-01-29 14:04:35 -05:00
meetings__sum = tables . Column ( " Meetings " )
2024-01-22 12:33:34 -05:00
duration__sum = DurationColumn ( " Class Hours " )
person_hours__sum = DurationColumn ( " Person Hours " )
2024-01-22 13:17:02 -05:00
class EventIndexReport (
ExportMixin , SingleTableMixin , PermissionRequiredMixin , ArchiveIndexView
) :
2024-01-19 15:33:54 -05:00
permission_required = " membershipworks.view_eventext "
queryset = EventExt . objects . all ( )
date_field = " start "
template_name = " membershipworks/event_index_report.dj.html "
make_object_list = True
2024-01-22 12:33:34 -05:00
table_class = EventSummaryTable
2024-01-22 13:17:02 -05:00
export_formats = ( " csv " , " xlsx " , " ods " )
export_name = " mw_events_index "
2024-01-22 12:33:34 -05:00
2024-01-29 14:13:00 -05:00
def get_table_data ( self ) :
return (
super ( )
. get_table_data ( )
. values ( year = TruncYear ( " start " ) )
. summarize ( )
. order_by ( " year " )
)
2024-01-22 12:33:34 -05:00
def get_table_kwargs ( self ) :
year_column = tables . DateColumn (
" Y " ,
linkify = (
" membershipworks:event-year-report " ,
[ A ( " year__year " ) ] ,
) ,
)
return {
" sequence " : ( " year " , " ... " ) ,
" extra_columns " : ( ( " year " , year_column ) , ) ,
}
2024-01-19 15:33:54 -05:00
2024-01-22 13:17:02 -05:00
class EventYearReport (
ExportMixin , SingleTableMixin , PermissionRequiredMixin , YearArchiveView
) :
2024-01-19 15:33:54 -05:00
permission_required = " membershipworks.view_eventext "
queryset = EventExt . objects . all ( )
date_field = " start "
template_name = " membershipworks/event_year_report.dj.html "
make_object_list = True
2024-01-22 12:33:34 -05:00
table_class = EventSummaryTable
2024-01-22 13:17:02 -05:00
export_formats = ( " csv " , " xlsx " , " ods " )
2024-01-29 14:13:00 -05:00
def get_table_data ( self ) :
return (
super ( )
. get_table_data ( )
. values ( month = TruncMonth ( " start " ) )
. summarize ( )
. order_by ( " month " )
)
2024-01-22 13:17:02 -05:00
def get_export_filename ( self , export_format ) :
return f " mw_events_ { self . get_year ( ) } . { export_format } "
2024-01-22 12:33:34 -05:00
def get_table_kwargs ( self ) :
month_column = tables . DateColumn (
" F Y " ,
linkify = (
" membershipworks:event-month-report " ,
[ A ( " month__year " ) , A ( " month__month " ) ] ,
) ,
)
return {
" sequence " : ( " month " , " ... " ) ,
" extra_columns " : ( ( " month " , month_column ) , ) ,
}
2024-01-19 15:33:54 -05:00
2024-01-22 13:17:02 -05:00
class EventMonthReport (
ExportMixin , SingleTableMixin , PermissionRequiredMixin , MonthArchiveView
) :
2024-01-15 21:31:06 -05:00
permission_required = " membershipworks.view_eventext "
2024-01-29 14:13:00 -05:00
queryset = EventExt . objects . all ( )
2024-01-15 21:31:06 -05:00
date_field = " start "
2024-01-17 11:15:57 -05:00
template_name = " membershipworks/event_month_report.dj.html "
2024-01-22 12:33:34 -05:00
table_class = EventTable
2024-01-22 13:17:02 -05:00
export_formats = ( " csv " , " xlsx " , " ods " )
2024-01-29 14:13:00 -05:00
def get_table_data ( self ) :
return super ( ) . get_table_data ( ) . select_related ( " category " , " instructor " )
2024-01-22 13:17:02 -05:00
def get_export_filename ( self , export_format ) :
return f " mw_events_ { self . get_year ( ) } - { self . get_month ( ) : 02 } . { export_format } "