Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Student Onsite Webapp #2507

Merged
merged 65 commits into from
Mar 24, 2020
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
74fde17
Webapp handler and dummy templates
willgearty Jan 22, 2018
86c30fc
Migration for new module.
willgearty Jan 26, 2018
164d75c
css file, prep for dynamic schedule
willgearty Jan 29, 2018
70e33a5
Dynamic schedule.
willgearty Jan 30, 2018
761494b
Catalog and survey templates. Fixed aux_calls
willgearty Feb 1, 2018
ad7e76f
Catalog updates
willgearty Feb 3, 2018
0ad108e
Catalog shows class info. Can be filtered by timeslot.
willgearty Feb 3, 2018
91280f4
Merge branch 'main' of https://github.com/learning-unlimited/ESP-Webs…
willgearty Feb 5, 2018
749a694
Checks for attendance status. Adds buttons to enroll in classes.
willgearty Feb 7, 2018
4a456d2
Button almost works
willgearty Feb 8, 2018
c95f1cb
Catalog is now cached. Enrollment buttons now work.
willgearty Feb 8, 2018
a4ae174
Ability to remove classes from schedule.
willgearty Feb 9, 2018
ee7699b
Filters classes by student grade when looking at specific timeslot.
willgearty Feb 10, 2018
45f46fc
Style changes
willgearty Feb 14, 2018
e41b40b
Style changes, add buttons now disabled if there are class conflicts
willgearty Feb 15, 2018
534c42e
More style changes
willgearty Feb 17, 2018
dcb33ce
Maps update.
willgearty Feb 17, 2018
b430d28
Style changes
willgearty Feb 21, 2018
35fef9d
prepare fix
willgearty Feb 21, 2018
b5e353d
lint fix
willgearty Feb 21, 2018
3f039d2
isStep and map fixes
willgearty Feb 27, 2018
fcb6956
Not checked in note on schedule
willgearty Mar 21, 2018
5d98643
Added popup when buttons are clicked when not checked in
willgearty Mar 21, 2018
1e75cab
Pulls classroom lat/long data from an associated resource (if one exi…
willgearty Apr 7, 2018
b09bda9
Switch to /default_styles
willgearty Apr 24, 2018
aad11e5
Fixes directions origin precision, map overlap with navbar
willgearty Apr 28, 2018
d1c45ac
Add backup directions map if user does not give tracking permission
willgearty Apr 30, 2018
1c18cf0
Merge branch 'main' into webapp
willgearty Aug 21, 2018
ed38fe0
migrations are bad...mmkay
willgearty Aug 21, 2018
3598346
meh, they aren't that bad
willgearty Aug 26, 2018
f392f1a
fixes for travis
willgearty Aug 26, 2018
989ef8e
fixes for travis 2
willgearty Aug 26, 2018
24f3465
Pulled out shared code, added scroll button on catalog
willgearty Nov 24, 2018
d5cbf45
Handle invalid classroom ids
willgearty Nov 24, 2018
f8060b9
Switch to Javascript API for directions, refresh directions every 30 …
willgearty Nov 25, 2018
c48827d
Fix caching and check for cancelled sections
willgearty Nov 28, 2018
7a061cc
Webapp catalog bug fixes
willgearty Jan 4, 2019
c8949a7
Map fixes
willgearty Jan 4, 2019
840b2d5
Include fixes from #2597
willgearty Jan 4, 2019
8291145
Prettier category buttons
willgearty Jan 4, 2019
7888bc8
Prettier classroom links
willgearty Jan 4, 2019
295038e
Let students enroll in classes based on checked in numbers
willgearty Jan 6, 2019
8419527
Include new tags in tag lists
willgearty Jan 6, 2019
0d594ed
test fix
willgearty Jan 6, 2019
f467e06
Sort fillslot like catalog
willgearty Jan 6, 2019
68b9a3b
factor out code
willgearty Jan 7, 2019
bcd8413
use factored out category sorting code
willgearty Jan 7, 2019
02ee145
fix implementation
willgearty Jan 7, 2019
cba1283
Fix logic for reg based on checked-in records
willgearty Feb 13, 2019
09d24e7
Remove walk-in buttons, fix category buttons, fix gap
willgearty Apr 30, 2019
b91610a
Change seq
willgearty Jan 23, 2020
193d13e
Merge branch 'main' into webapp
willgearty Mar 10, 2020
e1a86d0
Fix migration
willgearty Mar 10, 2020
2e084f3
Remove unnecessary imports
willgearty Mar 10, 2020
1e1a6f3
Make directions button more obvious
willgearty Mar 10, 2020
c1652c9
Fix map height
willgearty Mar 10, 2020
6deb1b7
Raise error if problem encountered while clearing timeslot
willgearty Mar 10, 2020
3efd68b
Mark webapp enrollments with webapp student registration
willgearty Mar 10, 2020
c6db989
Update tagdict
willgearty Mar 10, 2020
2668bec
Add built-in survey, fix styling
willgearty Mar 10, 2020
4bb4af8
Lint fix
willgearty Mar 10, 2020
980f52e
Expand category buttons for longer categories
willgearty Mar 24, 2020
784ef77
Fix #2937
willgearty Mar 24, 2020
1724bdc
Fix textareas to 100% width
willgearty Mar 24, 2020
abae9e8
Prevent horizontal resizing
willgearty Mar 24, 2020
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
36 changes: 22 additions & 14 deletions esp/esp/program/modules/handlers/studentclassregmodule.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,18 +199,24 @@ def deadline_met_or_lottery_open(self, extension=None):
super(StudentClassRegModule, self).deadline_met('/Classes/Lottery')

def prepare(self, context={}):
user = get_current_request().user
program = self.program
scrmi = self.program.studentclassregmoduleinfo
return self.prepare_static(user, program, context=context, scrm = self)

@staticmethod
def prepare_static(user, program, context={}, scrm = ""):
from esp.program.controllers.studentclassregmodule import RegistrationTypeController as RTC
verbs = RTC.getVisibleRegistrationTypeNames(prog=self.program)
regProf = RegistrationProfile.getLastForProgram(get_current_request().user, self.program)
timeslots = self.program.getTimeSlots(types=['Class Time Block', 'Compulsory'])
verbs = RTC.getVisibleRegistrationTypeNames(prog=program)
regProf = RegistrationProfile.getLastForProgram(user, program)
timeslots = program.getTimeSlots(types=['Class Time Block', 'Compulsory'])
classList = ClassSection.prefetch_catalog_data(regProf.preregistered_classes(verbs=verbs))

prevTimeSlot = None
blockCount = 0

user = get_current_request().user
is_onsite = user.isOnsite(self.program)
scrmi = self.program.studentclassregmoduleinfo
is_onsite = user.isOnsite(program)
scrmi = program.studentclassregmoduleinfo

# Filter out volunteer timeslots
timeslots = [x for x in timeslots if x.event_type.description != 'Volunteer']
Expand Down Expand Up @@ -267,7 +273,8 @@ def prepare(self, context={}):
context['num_classes'] = len(classList)
context['timeslots'] = schedule
context['use_priority'] = scrmi.use_priority
context['allow_removal'] = self.deadline_met('/Removal')
if scrm:
context['allow_removal'] = scrm.deadline_met('/Removal')

return context

Expand Down Expand Up @@ -326,11 +333,12 @@ def ajax_schedule(self, request, tl, one, two, module, extra, prog):

return HttpResponse(json.dumps(json_data))

def addclass_logic(self, request, tl, one, two, module, extra, prog):
@staticmethod
def addclass_logic(request, tl, one, two, module, extra, prog):
""" Pre-register the student for the class section in POST['section_id'].
Return True if there are no errors.
"""
scrmi = self.program.studentclassregmoduleinfo
scrmi = prog.studentclassregmoduleinfo

# Explicitly set the user's onsiteness, since we refer to it soon.
if not hasattr(request.user, "onsite_local"):
Expand All @@ -344,10 +352,10 @@ def addclass_logic(self, request, tl, one, two, module, extra, prog):

section = ClassSection.objects.get(id=sectionid)
if not scrmi.use_priority:
error = section.cannotAdd(request.user,self.scrmi.enforce_max)
error = section.cannotAdd(request.user,scrmi.enforce_max)
if scrmi.use_priority or not error:
cobj = ClassSubject.objects.get(id=classid)
error = cobj.cannotAdd(request.user,self.scrmi.enforce_max) or section.cannotAdd(request.user, self.scrmi.enforce_max)
error = cobj.cannotAdd(request.user,scrmi.enforce_max) or section.cannotAdd(request.user, scrmi.enforce_max)

if scrmi.use_priority:
priority = request.user.getRegistrationPriority(prog, section.meeting_times.all())
Expand All @@ -367,7 +375,7 @@ def addclass_logic(self, request, tl, one, two, module, extra, prog):
@needs_student
@meets_deadline('/Classes')
@meets_cap
def addclass(self,request, tl, one, two, module, extra, prog):
def addclass(self, request, tl, one, two, module, extra, prog):
""" Preregister a student for the specified class, then return to the studentreg page """
if self.addclass_logic(request, tl, one, two, module, extra, prog):
return self.goToCore(tl)
Expand Down Expand Up @@ -594,8 +602,8 @@ def class_docs(self, request, tl, one, two, module, extra, prog):

return render_to_response(self.baseDir()+'class_docs.html', request, context)


def clearslot_logic(self, request, tl, one, two, module, extra, prog):
@staticmethod
def clearslot_logic(request, tl, one, two, module, extra, prog):
""" Clear the specified timeslot from a student registration and return True if there are no errors """

# Get the sections that the student is registered for in the specified timeslot.
Expand Down
169 changes: 169 additions & 0 deletions esp/esp/program/modules/handlers/studentonsite.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
__author__ = "Individual contributors (see AUTHORS file)"
__date__ = "$DATE$"
__rev__ = "$REV$"
__license__ = "AGPL v.3"
__copyright__ = """
This file is part of the ESP Web Site
Copyright (c) 2007 by the individual contributors
(see AUTHORS file)

The ESP Web Site is free software; you can redistribute it and/or
modify it under the terms of the GNU Affero General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

Contact information:
MIT Educational Studies Program
84 Massachusetts Ave W20-467, Cambridge, MA 02139
Phone: 617-253-4882
Email: [email protected]
Learning Unlimited, Inc.
527 Franklin St, Cambridge, MA 02139
Phone: 617-379-0178
Email: [email protected]
"""
from esp.program.modules.base import ProgramModuleObj, needs_student, meets_deadline, meets_grade, CoreModule, main_call, aux_call, _checkDeadline_helper, meets_cap
from esp.program.models import Program, ClassSubject
from esp.utils.web import render_to_response
from esp.users.models import ESPUser, Permission, Record
from esp.cal.models import Event
from esp.middleware import ESPError
from esp.tagdict.models import Tag
from datetime import datetime
from django.db import models
from django.contrib import admin
from django.http import HttpResponseRedirect
from django.template import Template
from django.template.loader import render_to_string, get_template, select_template

from esp.program.modules.handlers.studentclassregmodule import StudentClassRegModule

class StudentOnsite(ProgramModuleObj, CoreModule):
@classmethod
def module_properties(cls):
return {
"link_title": "Student Onsite",
"admin_title": "Student Onsite Webapp",
"module_type": "learn",
"seq": -9999
}

@main_call
@needs_student
@meets_grade
@meets_deadline('/Webapp')
@meets_cap
def studentonsite(self, request, tl, one, two, module, extra, prog):
""" Display the landing page for the student onsite webapp """
user = request.user

context = StudentClassRegModule.prepare_static(user, prog)

context['user'] = user
context['program'] = prog
context['one'] = one
context['two'] = two
context['scrmi'] = prog.studentclassregmoduleinfo
context['checked_in'] = Record.objects.filter(program=prog, event='attended', user=user).exists()

return render_to_response(self.baseDir()+'schedule.html', request, context)

@aux_call
@needs_student
@meets_grade
@meets_deadline('/Webapp')
@meets_cap
def onsitemap(self, request, tl, one, two, module, extra, prog):
context = {}
context['user'] = request.user
context['program'] = prog
context['one'] = one
context['two'] = two
context['center'] = Tag.getTag('program_center', default='{lat: 37.427490, lng: -122.170267}')
#extra should be a classroom id
if extra:
#gets lat/long of classroom and adds it to context
context['classroom'] = "37.427490, -122.170267"
return render_to_response(self.baseDir()+'map.html', request, context)

@aux_call
@needs_student
@meets_grade
@meets_deadline('/Webapp')
@meets_cap
def onsitecatalog(self, request, tl, one, two, module, extra, prog):
user = request.user
context = {}
context['user'] = user
context['program'] = prog
context['one'] = one
context['two'] = two
user_grade = user.getGrade(self.program)
if extra:
try:
ts = Event.objects.get(id=int(extra), program=prog)
except:
raise ESPError('Please use the links on the schedule page.', log=False)
context['timeslot'] = ts
classes = list(ClassSubject.objects.catalog(prog, ts))
classes = filter(lambda c: c.grade_min <=user_grade and c.grade_max >= user_grade, classes)
context['checked_in'] = Record.objects.filter(program=prog, event='attended', user=user).exists()

else:
classes = list(ClassSubject.objects.catalog(prog))

categories = {}

for cls in classes:
categories[cls.category_id] = {'id':cls.category_id, 'category':cls.category_txt if hasattr(cls, 'category_txt') else cls.category.category}

context['classes'] = classes
context['categories'] = categories.values()
context['prereg_url'] = prog.get_learn_url() + 'onsiteaddclass'

return render_to_response(self.baseDir()+'catalog.html', request, context)

@aux_call
@needs_student
@meets_grade
@meets_deadline('/Webapp')
@meets_cap
def onsitesurvey(self, request, tl, one, two, module, extra, prog):
context = {}
context['user'] = request.user
context['program'] = prog
context['one'] = one
context['two'] = two
return render_to_response(self.baseDir()+'survey.html', request, context)

@aux_call
@needs_student
@meets_grade
@meets_deadline('/Webapp')
def onsiteaddclass(self, request, tl, one, two, module, extra, prog):
if StudentClassRegModule.addclass_logic(request, tl, one, two, module, extra, prog):
return HttpResponseRedirect(prog.get_learn_url() + 'studentonsite')

@aux_call
@needs_student
@meets_grade
@meets_deadline('/Webapp')
def onsiteclearslot(self, request, tl, one, two, module, extra, prog):
result = StudentClassRegModule.clearslot_logic(request, tl, one, two, module, extra, prog)
return HttpResponseRedirect(prog.get_learn_url() + 'studentonsite')

def isStep(self):
return Tag.getBooleanTag('webapp_isstep', default=False)

class Meta:
proxy = True
app_label = 'modules'
24 changes: 24 additions & 0 deletions esp/esp/program/modules/migrations/0016_studentonsite.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models
import esp.program.modules.base


class Migration(migrations.Migration):

dependencies = [
('modules', '0015_merge'),
]

operations = [
migrations.CreateModel(
name='StudentOnsite',
fields=[
],
options={
'proxy': True,
},
bases=('modules.programmoduleobj', esp.program.modules.base.CoreModule),
),
]
19 changes: 19 additions & 0 deletions esp/esp/program/templatetags/class_render.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,25 @@ def render_class(cls, user=None, filter=False, timeslot=None):
render_class.cached_function.depend_on_row('program.StudentRegistration', lambda reg: {'user': reg.user})
render_class.cached_function.get_or_create_token(('user',))

@cache_inclusion_tag(register, 'inclusion/program/class_catalog_webapp.html')
def render_class_webapp(cls, user=None, filter=False, timeslot=None, checked_in=False):
"""Render the entire class for the webapp, including user-specific parts.

Calls render_class_core for non-user-specific parts.
"""
context = _render_class_helper(cls, user, filter, timeslot)
context['checked_in'] = checked_in
context['prereg_url'] = cls.parent_program.get_learn_url() + 'onsiteaddclass'
return context
render_class.cached_function.depend_on_cache(render_class_core.cached_function, lambda cls=wildcard, **kwargs: {'cls': cls})
render_class.cached_function.get_or_create_token(('cls',))
# We need to depend on not only the user's StudentRegistrations for this
# section, but in fact on their StudentRegistrations for all sections, because
# of things like lunch constraints -- a change made in another block could
# affect whether you can add a class in this one. So we depend on all SRs for
# this user. This only applies to tags that can depend on a user.
render_class.cached_function.depend_on_row('program.StudentRegistration', lambda reg: {'user': reg.user})
render_class.cached_function.get_or_create_token(('user',))

@cache_function
def render_class_direct(cls):
Expand Down
3 changes: 2 additions & 1 deletion esp/esp/users/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2243,7 +2243,7 @@ class Permission(ExpirableModel):
("Administer", "Full administrative permissions"),
("View", "Able to view a program"),
("Onsite", "Access to onsite interfaces"),
# The following two are outside of "Student/" so that they aren't
# The following are outside of "Student/" so that they aren't
# implied by "Student/All".
("GradeOverride", "Ignore grade ranges for studentreg"),
("OverrideFull", "Register for a full program"),
Expand All @@ -2267,6 +2267,7 @@ class Permission(ExpirableModel):
("Student/Survey", "Access to survey"),
("Student/FormstackMedliab", "Access to Formstack medical and liability form"),
("Student/Finaid", "Access to financial aid application"),
("Student/Webapp", "Access to student onsite webapp"),
)),
("Teacher Deadlines", (
("Teacher", "Basic teacher access"),
Expand Down
Loading