Skip to content

Commit

Permalink
Blow-up prevention. Error displaying. Conflicting courses display. St…
Browse files Browse the repository at this point in the history
…ylistic Changes
  • Loading branch information
turtlesoupy committed Jan 10, 2011
1 parent 1903c16 commit f3d4520
Show file tree
Hide file tree
Showing 11 changed files with 184 additions and 152 deletions.
8 changes: 0 additions & 8 deletions .htaccess

This file was deleted.

1 change: 1 addition & 0 deletions coursequalifier/config/deployment.ini_tmpl
Expand Up @@ -25,6 +25,7 @@ beaker.session.secret = ${app_instance_secret}
app_instance_uuid = ${app_instance_uuid}
uwdata.address = uwdata.ca
uwdata.key = GET_YOUR_OWN
maxSearchSpace = 10000

# If you'd like to fine-tune the individual locations of the cache data dirs
# for the Cache data, or the Session saves, un-comment the desired settings
Expand Down
65 changes: 50 additions & 15 deletions coursequalifier/controllers/schedule.py
Expand Up @@ -4,9 +4,10 @@
import logging
from itertools import chain

from pylons import request, response, session, tmpl_context as c
from pylons import request, response, session, tmpl_context as c, config
from pylons.controllers.util import abort, redirect_to

from coursequalifier.lib.uwdata import CourseMissingException, UWDataError
from coursequalifier.lib.base import BaseController, render
from coursequalifier.lib.pdf_schedule import PDFSchedule
from coursequalifier.lib.filters import NotFullFilter, \
Expand All @@ -31,38 +32,66 @@ def compute_all(self):
directCourses = []
for course in r['courses']:
query = course["course_query"].strip()
if query == "":
continue
if query == "": continue

courseFilters = self._course_filters(course["options"])
m = self.directRE.match(query)
if m:
courses = Course.coursesFromCode(m.group(1), m.group(2), term,\
sectionFilters=requestSectionFilters)
try:
courses = Course.coursesFromCode(m.group(1), m.group(2), term,\
sectionFilters=requestSectionFilters)
except CourseMissingException, e:
return json.dumps({"error": {
"type": "no_query_results",
"query": query
}})
except UWDataError, e:
return json.dumps({"error": {
"type": "uwdata",
"query": query
}})

catalogFilters.extend(self._course_catalog_filters(courses, course["options"]))
directCourses.extend([e for e in courses\
if all(courseFilter.passes(e) for courseFilter in courseFilters)])
else:
courseGroups = []
for courseGroup in Course.courseGroupsFromSearch(query, term, sectionFilters=requestSectionFilters):
filteredGroup = [e for e in courseGroup if all(courseFilter.passes(e) for courseFilter in courseFilters)]
if len(filteredGroup) > 0:
courseGroups.append(filteredGroup)
try:
for courseGroup in Course.courseGroupsFromSearch(query, term, sectionFilters=requestSectionFilters):
filteredGroup = [e for e in courseGroup if all(courseFilter.passes(e) for courseFilter in courseFilters)]
if len(filteredGroup) > 0:
courseGroups.append(filteredGroup)
except CourseMissingException, e:
return json.dumps({"error": {
"type": "no_query_results",
"query": query
}})
except UWDataError, e:
return json.dumps({"error": {
"type": "uwdata",
"query": query
}})

catalogFilters.extend(self._course_catalog_filters(chain(*courseGroups), course["options"]))
searchGroups.append(courseGroups)

allCourses = directCourses + list(chain(*([chain(*e) for e in searchGroups])))
allCourses = directCourses + list(chain(*([chain(*e) for e in searchGroups])))
searchSpaceCount = Catalog.searchSpaceCount(directCourses, searchGroups)
if searchSpaceCount > int(config['maxSearchSpace']):
return json.dumps({"error": {
"type": "large_search_space",
"size": searchSpaceCount
}})

catalogs = [c for c in Catalog.computeAll(directCourses, searchGroups)\
if all(catalogFilter.passes(c) for catalogFilter in catalogFilters)]
catalogs, conflicts = Catalog.computeAll(directCourses, searchGroups)

filteredCatalogs= [c for c in catalogs \
if all(catalogFilter.passes(c) for catalogFilter in catalogFilters)]

return json.dumps({"result": {
"courses": dict((e.uniqueName, self._course_dict(e)) for e in allCourses),
"conflicts": {"courses": [], "messages": []},
"catalogs": [self._catalog_dict(c) for c in catalogs]
"courses": dict((e.uniqueName, self._course_dict(e)) for e in allCourses),
"conflicts": [self._conflict_dict(c) for c in conflicts],
"catalogs": [self._catalog_dict(c) for c in filteredCatalogs]
}})

def pdf(self):
Expand Down Expand Up @@ -125,6 +154,12 @@ def _request_section_filters(self, req):

return ret

def _conflict_dict(self, conflict):
s1,s2 = conflict
return [{ "courseName": s.courseName,
"sectionNum": s.sectionNum
} for s in (s1,s2)]


def _course_dict(self, course):
return {
Expand Down
2 changes: 0 additions & 2 deletions coursequalifier/lib/filters.py
Expand Up @@ -59,7 +59,5 @@ def __init__(self, courseGroup, requiredSectionNumbers=set()):

def passes(self, catalog):
scopedNums = set(e.sectionNum for e in catalog.sections if e.courseName in self.courseNames)
print scopedNums
print self.requiredSectionNumbers
return len(self.requiredSectionNumbers - scopedNums) == 0

3 changes: 2 additions & 1 deletion coursequalifier/lib/uwdata.py
Expand Up @@ -24,7 +24,6 @@ def pullSearchCourses(query):
)

def getJSONFromPath(basePath, query=[]):
print config['uwdata.address']
connection = HTTPConnection(config['uwdata.address'])

path = "%s?key=%s%s" % \
Expand All @@ -43,6 +42,8 @@ def getJSONFromPath(basePath, query=[]):
text = data['error']['text']
if text == "Unknown course":
raise CourseMissingException()
elif text == "No courses found":
raise CourseMissingException()
else:
raise UWDataError(data['error']['text'])
else:
Expand Down
31 changes: 24 additions & 7 deletions coursequalifier/model/catalog.py
Expand Up @@ -13,9 +13,10 @@ def cartesian(*args):
class CatalogCombinatorics(object):
"""Algorithm-object for doing actual 'course qualifying'."""
def __init__(self, direct, searchGroups):
self.direct = direct
self.searchGroups = searchGroups
self.output = []
self.direct = direct
self.searchGroups = searchGroups
self.output = []
self.conflictingSections = []

def computeSections(self):
self.computeInternal(self.direct)
Expand All @@ -42,24 +43,40 @@ def computeSearchCourses(self):

def computeInternal(self, remainingCourses, sectionAcc=[]):
if len(remainingCourses) == 0:
if len(sectionAcc) > 0: #and self.checkCatalog(sectionAcc):
self.output.append(sectionAcc)
if len(sectionAcc) > 0:
self.output.append(sectionAcc) #Side effect!
else:
currentCourse = remainingCourses.pop()
for currSection in currentCourse.sections:
for otherSection in sectionAcc:
if currSection.conflictsWith(otherSection):
#self.conflictingSections.add((currSection, otherSection))
self.conflictingSections.append((currSection, otherSection))
break
else:
self.computeInternal(remainingCourses[:], sectionAcc[:] + [currSection])

class Catalog(object):
@classmethod
def searchSpaceCount(cls, directCourses, searchGroups):
if len(directCourses) == 0 and len(searchGroups) == 0:
return 0

if len(directCourses) > 0:
numCatalogs = reduce(lambda x,y: x * y, (len(e.sections) \
for e in directCourses if len(e.sections) > 0))
else:
numCatalogs = 1

for courseOption in searchGroups:
numClasses *= sum(sum(len(c.sections) for c in courseGroup) for courseGroup in searchGroups)

return numCatalogs

@classmethod
def computeAll(cls, directCourses, searchGroups):
c = CatalogCombinatorics(directCourses, searchGroups)
c.computeSections()
return [cls(e) for e in c.output]
return ([cls(e) for e in c.output], c.conflictingSections)

def __init__(self, sections):
self.sections = sections
Expand Down
26 changes: 23 additions & 3 deletions coursequalifier/public/css/qualifier.css
@@ -1,7 +1,7 @@
body {
text-align:center;
font-family:Arial, Helvetica, sans-serif;
font-size:0.9em;
font-family: Verdana, Arial, sans-serif;
font-size:75%;
margin:0;
padding:0;
background-color:#646890;
Expand Down Expand Up @@ -69,6 +69,22 @@ html .fb_share_button:hover { color:#a0a0a0; margin-left: 10px; border-color:#29
margin-top: 1em;
}

#error_area {
border: 1px solid black;
padding: 10px 12px;
background: #800000;
width: 80%;
color: white;
display: none;
}

#error_area h3 {
font-size: 18pt;
font-weight: bold;
margin-top: 0;
margin-bottom: 10px;
}

#too_many_explanation {
border: 1px solid #c93;
padding: 10px 12px;
Expand All @@ -91,6 +107,10 @@ html .fb_share_button:hover { color:#a0a0a0; margin-left: 10px; border-color:#29
#too_many_number {
}

#result_area {
display: none;
}

h2 {
color: #0080c3;
font-size: 1.5em;
Expand Down Expand Up @@ -207,7 +227,7 @@ a, a:visited, a:active {
}

span.noemphasis {
font-size: 0.7em;
font-size: 0.8em;
}


Expand Down
Binary file removed coursequalifier/public/favicon.ico
Binary file not shown.

0 comments on commit f3d4520

Please sign in to comment.