From 6b277c073ce9c545cd2d0bf49b4cecd269579a7a Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Sun, 8 Oct 2017 19:57:16 -0600 Subject: [PATCH 1/7] #18 starting survey results page --- acmwebsite/controllers/survey.py | 5 ++-- acmwebsite/templates/survey_results.xhtml | 34 +++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 acmwebsite/templates/survey_results.xhtml diff --git a/acmwebsite/controllers/survey.py b/acmwebsite/controllers/survey.py index 145f9ce..5b5eb02 100644 --- a/acmwebsite/controllers/survey.py +++ b/acmwebsite/controllers/survey.py @@ -18,14 +18,15 @@ class SurveyController(BaseController): def __init__(self, survey): self.survey = survey - @expose('json') + @expose('acmwebsite.templates.survey_results') @require(has_permission('admin')) def results(self, number=None): responses = self.survey.responses or [] responses = [response_to_dict(r) for r in responses] return { + 'survey': self.survey, 'count': len(responses), - 'responses': responses, + 'responses': responses, 'fields': survey_fields(self.survey), } diff --git a/acmwebsite/templates/survey_results.xhtml b/acmwebsite/templates/survey_results.xhtml new file mode 100644 index 0000000..904d723 --- /dev/null +++ b/acmwebsite/templates/survey_results.xhtml @@ -0,0 +1,34 @@ + + + + Mines ACM - Survey + + +
+ Unknown survey field! +
+ + + + +

${survey.title or (survey.meeting and survey.meeting.title) or 'Survey'}

+

Responses

+
+ + + + + + + + + +
+
+
+
+ + From f11f9dbe57fbbe8a7ce6159c2e16de57cbbf8c48 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Fri, 15 Dec 2017 12:22:01 -0700 Subject: [PATCH 2/7] #18 table with sorting to view survey responses --- acmwebsite/controllers/survey.py | 53 +++++++++++++++++------ acmwebsite/lib/helpers.py | 4 ++ acmwebsite/lib/surveytypes.py | 43 +++++++++++++++++- acmwebsite/model/survey.py | 6 ++- acmwebsite/templates/survey_results.xhtml | 41 ++++++++++++------ 5 files changed, 116 insertions(+), 31 deletions(-) diff --git a/acmwebsite/controllers/survey.py b/acmwebsite/controllers/survey.py index 5b5eb02..2a97dfa 100644 --- a/acmwebsite/controllers/survey.py +++ b/acmwebsite/controllers/survey.py @@ -1,33 +1,55 @@ -from tg import expose, redirect, validate, flash, url, lurl, abort, require, request -from tg.predicates import has_permission, not_anonymous +from tg import expose, redirect, flash, abort, require, request +from tg.predicates import has_permission from acmwebsite.lib.base import BaseController -from acmwebsite.lib.helpers import log -from acmwebsite.model import DBSession, Survey, SurveyResponse, SurveyData, User +from acmwebsite.model import DBSession, Survey, SurveyResponse, SurveyData -def survey_fields(survey): - return [{'name': f.name, 'type': f.type} for f in survey.fields] -def response_to_dict(response): - out = {'name': response.name, 'email': response.email} +def response_dict(response, fields): + out = { + 'name': response.name, + 'email': response.email, + } + + # Populate with the default value for the fields. This is necessary for + # sorting if some respondents didn't fill out an optional field. + for field in fields: + out[field.name] = field.type_object().default() + + # Override with the actual response data for the fields that exist. for item in response.data: out[item.field.name] = item.field.type_object().from_contents(item.contents) + return out + class SurveyController(BaseController): def __init__(self, survey): self.survey = survey @expose('acmwebsite.templates.survey_results') @require(has_permission('admin')) - def results(self, number=None): + def results(self, number=None, order_by=None, reverse=False): + if type(reverse) is str: + reverse = reverse == 'True' + responses = self.survey.responses or [] - responses = [response_to_dict(r) for r in responses] + responses = [response_dict(r, self.survey.fields) for r in responses] + if order_by: + responses = sorted(responses, + key=lambda x: x.get(order_by), + reverse=reverse) + return { 'survey': self.survey, + 'title': (self.survey.title or + (self.survey.meeting and self.survey.meeting.title) or + 'Survey'), 'count': len(responses), 'responses': responses, - 'fields': survey_fields(self.survey), + 'fields': self.survey.field_metadata(), + 'order_by': order_by, + 'reverse': reverse, } @expose('acmwebsite.templates.survey') @@ -44,7 +66,9 @@ def respond(self): form = request.POST if form: user = request.identity and request.identity.get('user') - response = SurveyResponse(user=user, provided_name=form.get('_provided_name'), survey=self.survey) + response = SurveyResponse(user=user, + provided_name=form.get('_provided_name'), + survey=self.survey) DBSession.add(response) requires_ft = bool(form.get('first_time')) @@ -59,12 +83,13 @@ def respond(self): flash('Response submitted successfully') redirect(base_url='/') else: - return {'survey': self.survey } + return {'survey': self.survey} + class SurveysController(BaseController): @expose() def _lookup(self, sid, *args): - survey = DBSession.query(Survey).filter(Survey.id==sid).first() + survey = DBSession.query(Survey).filter(Survey.id == sid).first() if not survey: abort(404, "No such survey") return SurveyController(survey), args diff --git a/acmwebsite/lib/helpers.py b/acmwebsite/lib/helpers.py index 9d5d457..a0be740 100644 --- a/acmwebsite/lib/helpers.py +++ b/acmwebsite/lib/helpers.py @@ -85,6 +85,10 @@ def field_cn(ty, *args): return ' '.join(args) +def order_by_link(column, current_order_by, reverse): + reverse = current_order_by == column and not reverse + return '?order_by={}&reverse={}'.format(column, reverse) + # Import commonly used helpers from WebHelpers2 and TG from tg.util.html import script_json_encode diff --git a/acmwebsite/lib/surveytypes.py b/acmwebsite/lib/surveytypes.py index 231adda..a036122 100644 --- a/acmwebsite/lib/surveytypes.py +++ b/acmwebsite/lib/surveytypes.py @@ -1,5 +1,6 @@ from ast import literal_eval + class SurveyType: def __init__(self, name, label=None, required=False, first_time=False, **kwargs): self.name = name @@ -14,6 +15,10 @@ def from_post(self, form): def from_contents(self, contents): return literal_eval(contents) + def default(self): + raise NotImplementedError('Descendants of SurveyType must implement default()') + + class Bool(SurveyType): template = 'checkbox' @@ -24,6 +29,10 @@ def __init__(self, value=None, **kwargs): def from_post(self, form): return str(bool(form.get(self.name))) + def default(self): + return False + + class Text(SurveyType): def __init__(self, value='', placeholder=None, **kwargs): super().__init__(**kwargs) @@ -37,12 +46,18 @@ def from_post(self, form): def from_contents(self, contents): return contents + def default(self): + return '' + + class ShortText(Text): template = 'text' + class LongText(Text): template = 'textarea' + class ManyOf(SurveyType): template = 'checkbox_group' @@ -54,6 +69,10 @@ def from_post(self, form): vals = [n for i, n in enumerate(self.options) if form.get('{}_{}'.format(self.name, i))] return str(vals) + def default(self): + return '' + + class OneOf(SurveyType): template = 'radio_group' @@ -68,6 +87,10 @@ def from_post(self, form): def from_contents(self, contents): return contents + def default(self): + return '' + + class Select(SurveyType): template = 'select' @@ -83,11 +106,19 @@ def from_post(self, form): def from_contents(self, contents): return contents + def default(self): + return self.value or '' + + class SelectMany(Select): def __init__(self, **kwargs): super().__init__(**kwargs) self.multiple = True - + + def default(self): + return '' + + class Number(SurveyType): template = 'number' @@ -104,4 +135,12 @@ def from_post(self, form): return None return repr(float(v)) -types = {k: v for k, v in globals().items() if isinstance(v, type) and issubclass(v, SurveyType)} + def default(self): + return self.value or 0 + + +types = { + k: v + for k, v in globals().items() + if isinstance(v, type) and issubclass(v, SurveyType) +} diff --git a/acmwebsite/model/survey.py b/acmwebsite/model/survey.py index 35d945e..3bd7623 100644 --- a/acmwebsite/model/survey.py +++ b/acmwebsite/model/survey.py @@ -13,7 +13,7 @@ survey_field_table = Table('survey_field', metadata, Column('survey_id', Integer, ForeignKey('survey.id'), primary_key=True), Column('field_id', Integer, ForeignKey('field.id'), primary_key=True) -) + ) class Survey(DeclarativeBase): __tablename__ = 'survey' @@ -30,6 +30,10 @@ def active(self): now = datetime.now() return self.opens and self.opens < now and (not self.closes or self.closes > now) + def field_metadata(self): + return [{'name': f.name, 'type': f.type} for f in self.fields] + + class SurveyField(DeclarativeBase): __tablename__ = 'field' diff --git a/acmwebsite/templates/survey_results.xhtml b/acmwebsite/templates/survey_results.xhtml index 904d723..bd9a957 100644 --- a/acmwebsite/templates/survey_results.xhtml +++ b/acmwebsite/templates/survey_results.xhtml @@ -8,27 +8,40 @@
- Unknown survey field! + Unknown survey field!
-

${survey.title or (survey.meeting and survey.meeting.title) or 'Survey'}

+

Responses

- - - - - - - - - -
-
-
+
+ + + + + + + + + + + +
+ Name + + + + +
+ +
+
From 5cac7eb2ea38dabffd0285e7ee121512ed437d88 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Fri, 15 Dec 2017 14:36:16 -0700 Subject: [PATCH 3/7] #18 Clean up, refactor --- acmwebsite/controllers/survey.py | 80 +++++++++++++---------- acmwebsite/lib/surveytypes.py | 4 +- acmwebsite/model/survey.py | 28 ++++---- acmwebsite/templates/survey_results.xhtml | 10 +-- 4 files changed, 69 insertions(+), 53 deletions(-) diff --git a/acmwebsite/controllers/survey.py b/acmwebsite/controllers/survey.py index 2a97dfa..3ea4151 100644 --- a/acmwebsite/controllers/survey.py +++ b/acmwebsite/controllers/survey.py @@ -1,26 +1,8 @@ -from tg import expose, redirect, flash, abort, require, request +from tg import abort, expose, flash, redirect, request, require from tg.predicates import has_permission from acmwebsite.lib.base import BaseController -from acmwebsite.model import DBSession, Survey, SurveyResponse, SurveyData - - -def response_dict(response, fields): - out = { - 'name': response.name, - 'email': response.email, - } - - # Populate with the default value for the fields. This is necessary for - # sorting if some respondents didn't fill out an optional field. - for field in fields: - out[field.name] = field.type_object().default() - - # Override with the actual response data for the fields that exist. - for item in response.data: - out[item.field.name] = item.field.type_object().from_contents(item.contents) - - return out +from acmwebsite.model import DBSession, Survey, SurveyData, SurveyResponse class SurveyController(BaseController): @@ -33,18 +15,16 @@ def results(self, number=None, order_by=None, reverse=False): if type(reverse) is str: reverse = reverse == 'True' - responses = self.survey.responses or [] - responses = [response_dict(r, self.survey.fields) for r in responses] + responses = self._survey_responses() if order_by: - responses = sorted(responses, - key=lambda x: x.get(order_by), - reverse=reverse) + responses.sort(key=lambda x: x.get(order_by), reverse=reverse) + survey_title = (self.survey.title or + (self.survey.meeting and self.survey.meeting.title) or + 'Survey') return { 'survey': self.survey, - 'title': (self.survey.title or - (self.survey.meeting and self.survey.meeting.title) or - 'Survey'), + 'title': survey_title, 'count': len(responses), 'responses': responses, 'fields': self.survey.field_metadata(), @@ -52,6 +32,37 @@ def results(self, number=None, order_by=None, reverse=False): 'reverse': reverse, } + @expose('json') + @require(has_permission('admin')) + def results_json(self, number=None): + responses = self._survey_responses() + return { + 'count': len(responses), + 'responses': responses, + 'fields': self.survey.field_metadata(), + } + + def _response_dict(self, response): + out = {'name': response.name, 'email': response.email} + + # Populate with the default value for the fields. This is necessary for + # sorting if some respondents didn't fill out an optional field. + for field in self.survey.fields: + out[field.name] = field.type_object().default() + + # Override with the actual response data for the fields that exist. + out.update({ + item.field.name: + item.field.type_object().from_contents(item.contents) + for item in response.data + }) + + return out + + def _survey_responses(self): + responses = self.survey.responses or [] + return [self._response_dict(r) for r in responses] + @expose('acmwebsite.templates.survey') def respond(self): if not self.survey: @@ -61,14 +72,16 @@ def respond(self): if not has_permission('admin'): abort(403, 'Survey not avalible') return - flash('This page is currently disabled. You can see it because you are an admin.', 'warn') + flash('This page is currently disabled. You can see it because you are an admin.', + 'warn') form = request.POST if form: user = request.identity and request.identity.get('user') - response = SurveyResponse(user=user, - provided_name=form.get('_provided_name'), - survey=self.survey) + response = SurveyResponse( + user=user, + provided_name=form.get('_provided_name'), + survey=self.survey) DBSession.add(response) requires_ft = bool(form.get('first_time')) @@ -79,7 +92,8 @@ def respond(self): fo = f.type_object() v = fo.from_post(form) if v: - DBSession.add(SurveyData(response=response, field=f, contents=v)) + DBSession.add( + SurveyData(response=response, field=f, contents=v)) flash('Response submitted successfully') redirect(base_url='/') else: diff --git a/acmwebsite/lib/surveytypes.py b/acmwebsite/lib/surveytypes.py index a036122..3d41f06 100644 --- a/acmwebsite/lib/surveytypes.py +++ b/acmwebsite/lib/surveytypes.py @@ -47,7 +47,7 @@ def from_contents(self, contents): return contents def default(self): - return '' + return self.value or '' class ShortText(Text): @@ -88,7 +88,7 @@ def from_contents(self, contents): return contents def default(self): - return '' + return self.value or '' class Select(SurveyType): diff --git a/acmwebsite/model/survey.py b/acmwebsite/model/survey.py index 3bd7623..3501fcd 100644 --- a/acmwebsite/model/survey.py +++ b/acmwebsite/model/survey.py @@ -1,26 +1,28 @@ -from sqlalchemy import * -from sqlalchemy.orm import mapper, relation, relationship, backref -from sqlalchemy import Table, ForeignKey, Column -from sqlalchemy.types import Integer, String, Unicode - from datetime import datetime -from acmwebsite.model import DeclarativeBase, metadata, DBSession +from sqlalchemy import Boolean, Column, DateTime, Float, ForeignKey, Table +from sqlalchemy.orm import relation +from sqlalchemy.types import Integer, String, Unicode + from acmwebsite.lib.surveytypes import types +from acmwebsite.model import DeclarativeBase, metadata -from ast import literal_eval +survey_field_table = Table( + 'survey_field', metadata, + Column('survey_id', Integer, ForeignKey('survey.id'), primary_key=True), + Column('field_id', Integer, ForeignKey('field.id'), primary_key=True)) -survey_field_table = Table('survey_field', metadata, - Column('survey_id', Integer, ForeignKey('survey.id'), primary_key=True), - Column('field_id', Integer, ForeignKey('field.id'), primary_key=True) - ) class Survey(DeclarativeBase): __tablename__ = 'survey' id = Column(Integer, autoincrement=True, primary_key=True) meeting = relation('Meeting', back_populates='survey', uselist=False) - fields = relation('SurveyField', secondary=survey_field_table, backref='surveys', order_by='SurveyField.priority') + fields = relation( + 'SurveyField', + secondary=survey_field_table, + backref='surveys', + order_by='SurveyField.priority') title = Column(Unicode) opens = Column(DateTime) closes = Column(DateTime) @@ -51,7 +53,6 @@ class SurveyField(DeclarativeBase): max = Column(Float) step = Column(Float) - def type_object(self): return types[self.type]( name=self.name, @@ -66,6 +67,7 @@ def type_object(self): step=self.step, ) + class SurveyResponse(DeclarativeBase): __tablename__ = 'response' diff --git a/acmwebsite/templates/survey_results.xhtml b/acmwebsite/templates/survey_results.xhtml index bd9a957..489d2b1 100644 --- a/acmwebsite/templates/survey_results.xhtml +++ b/acmwebsite/templates/survey_results.xhtml @@ -4,13 +4,9 @@ py:extends="master.xhtml"> - Mines ACM - Survey + Mines ACM - Survey ${survey.id} Responses -
- Unknown survey field! -
- @@ -19,6 +15,10 @@
+
From 4b0829f9ae2fdc8e6ede7c34e49111fc3b84e27b Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Mon, 18 Dec 2017 15:16:04 -0700 Subject: [PATCH 4/7] #18 combine survey template & json endpoints --- acmwebsite/controllers/survey.py | 20 ++++---------------- acmwebsite/templates/survey_results.xhtml | 4 +--- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/acmwebsite/controllers/survey.py b/acmwebsite/controllers/survey.py index 3ea4151..48317be 100644 --- a/acmwebsite/controllers/survey.py +++ b/acmwebsite/controllers/survey.py @@ -10,12 +10,14 @@ def __init__(self, survey): self.survey = survey @expose('acmwebsite.templates.survey_results') + @expose("json") @require(has_permission('admin')) def results(self, number=None, order_by=None, reverse=False): + responses = [self._response_dict(r) for r in self.survey.responses or []] + if type(reverse) is str: reverse = reverse == 'True' - responses = self._survey_responses() if order_by: responses.sort(key=lambda x: x.get(order_by), reverse=reverse) @@ -23,7 +25,7 @@ def results(self, number=None, order_by=None, reverse=False): (self.survey.meeting and self.survey.meeting.title) or 'Survey') return { - 'survey': self.survey, + 'survey_id': self.survey.id, 'title': survey_title, 'count': len(responses), 'responses': responses, @@ -32,16 +34,6 @@ def results(self, number=None, order_by=None, reverse=False): 'reverse': reverse, } - @expose('json') - @require(has_permission('admin')) - def results_json(self, number=None): - responses = self._survey_responses() - return { - 'count': len(responses), - 'responses': responses, - 'fields': self.survey.field_metadata(), - } - def _response_dict(self, response): out = {'name': response.name, 'email': response.email} @@ -59,10 +51,6 @@ def _response_dict(self, response): return out - def _survey_responses(self): - responses = self.survey.responses or [] - return [self._response_dict(r) for r in responses] - @expose('acmwebsite.templates.survey') def respond(self): if not self.survey: diff --git a/acmwebsite/templates/survey_results.xhtml b/acmwebsite/templates/survey_results.xhtml index 489d2b1..2dd98f0 100644 --- a/acmwebsite/templates/survey_results.xhtml +++ b/acmwebsite/templates/survey_results.xhtml @@ -4,12 +4,10 @@ py:extends="master.xhtml"> - Mines ACM - Survey ${survey.id} Responses + Mines ACM - Survey ${survey_id} Responses - -

Responses

From 1e70e1146f905ef056333de2d4947ecdb4e01152 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Mon, 18 Dec 2017 15:28:29 -0700 Subject: [PATCH 5/7] #18 updates from code review --- acmwebsite/lib/helpers.py | 4 ---- acmwebsite/templates/survey_results.xhtml | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/acmwebsite/lib/helpers.py b/acmwebsite/lib/helpers.py index a0be740..9d5d457 100644 --- a/acmwebsite/lib/helpers.py +++ b/acmwebsite/lib/helpers.py @@ -85,10 +85,6 @@ def field_cn(ty, *args): return ' '.join(args) -def order_by_link(column, current_order_by, reverse): - reverse = current_order_by == column and not reverse - return '?order_by={}&reverse={}'.format(column, reverse) - # Import commonly used helpers from WebHelpers2 and TG from tg.util.html import script_json_encode diff --git a/acmwebsite/templates/survey_results.xhtml b/acmwebsite/templates/survey_results.xhtml index 2dd98f0..91c85c5 100644 --- a/acmwebsite/templates/survey_results.xhtml +++ b/acmwebsite/templates/survey_results.xhtml @@ -13,19 +13,19 @@
- - - -
- Name + Name - From 3077d9783e17036ac1a7f557d51a6ee353bb6b89 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Mon, 18 Dec 2017 16:36:12 -0700 Subject: [PATCH 6/7] #18 a bit of cleaning up from code review --- acmwebsite/controllers/survey.py | 20 ++++++++++--------- acmwebsite/lib/surveytypes.py | 24 ----------------------- acmwebsite/templates/survey_results.xhtml | 17 ++++++---------- 3 files changed, 17 insertions(+), 44 deletions(-) diff --git a/acmwebsite/controllers/survey.py b/acmwebsite/controllers/survey.py index 48317be..05eadc6 100644 --- a/acmwebsite/controllers/survey.py +++ b/acmwebsite/controllers/survey.py @@ -13,13 +13,20 @@ def __init__(self, survey): @expose("json") @require(has_permission('admin')) def results(self, number=None, order_by=None, reverse=False): - responses = [self._response_dict(r) for r in self.survey.responses or []] - if type(reverse) is str: reverse = reverse == 'True' if order_by: - responses.sort(key=lambda x: x.get(order_by), reverse=reverse) + # TODO: this doesn't work... + # order = '{} {}'.format(order_by, 'asc' if reverse else 'desc') + # responses = self.survey.responses.order_by(order) + responses = self.survey.responses + else: + responses = self.survey.responses + + # TODO: This sucks. It would be good to have this done for us with + # SQLAlchemy magic + responses = [self._response_dict(r) for r in responses or []] survey_title = (self.survey.title or (self.survey.meeting and self.survey.meeting.title) or @@ -37,12 +44,7 @@ def results(self, number=None, order_by=None, reverse=False): def _response_dict(self, response): out = {'name': response.name, 'email': response.email} - # Populate with the default value for the fields. This is necessary for - # sorting if some respondents didn't fill out an optional field. - for field in self.survey.fields: - out[field.name] = field.type_object().default() - - # Override with the actual response data for the fields that exist. + # Add the actual response data for the fields that exist. out.update({ item.field.name: item.field.type_object().from_contents(item.contents) diff --git a/acmwebsite/lib/surveytypes.py b/acmwebsite/lib/surveytypes.py index 3d41f06..305e5f2 100644 --- a/acmwebsite/lib/surveytypes.py +++ b/acmwebsite/lib/surveytypes.py @@ -15,9 +15,6 @@ def from_post(self, form): def from_contents(self, contents): return literal_eval(contents) - def default(self): - raise NotImplementedError('Descendants of SurveyType must implement default()') - class Bool(SurveyType): template = 'checkbox' @@ -29,9 +26,6 @@ def __init__(self, value=None, **kwargs): def from_post(self, form): return str(bool(form.get(self.name))) - def default(self): - return False - class Text(SurveyType): def __init__(self, value='', placeholder=None, **kwargs): @@ -46,9 +40,6 @@ def from_post(self, form): def from_contents(self, contents): return contents - def default(self): - return self.value or '' - class ShortText(Text): template = 'text' @@ -69,9 +60,6 @@ def from_post(self, form): vals = [n for i, n in enumerate(self.options) if form.get('{}_{}'.format(self.name, i))] return str(vals) - def default(self): - return '' - class OneOf(SurveyType): template = 'radio_group' @@ -87,9 +75,6 @@ def from_post(self, form): def from_contents(self, contents): return contents - def default(self): - return self.value or '' - class Select(SurveyType): template = 'select' @@ -106,18 +91,12 @@ def from_post(self, form): def from_contents(self, contents): return contents - def default(self): - return self.value or '' - class SelectMany(Select): def __init__(self, **kwargs): super().__init__(**kwargs) self.multiple = True - def default(self): - return '' - class Number(SurveyType): template = 'number' @@ -135,9 +114,6 @@ def from_post(self, form): return None return repr(float(v)) - def default(self): - return self.value or 0 - types = { k: v diff --git a/acmwebsite/templates/survey_results.xhtml b/acmwebsite/templates/survey_results.xhtml index 91c85c5..3e67a6d 100644 --- a/acmwebsite/templates/survey_results.xhtml +++ b/acmwebsite/templates/survey_results.xhtml @@ -19,23 +19,18 @@ -->
- Name - - - - + +
- +
From e559ba58f831e44f85725a9b494e42b5bb029d09 Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Mon, 22 Jan 2018 10:45:43 -0700 Subject: [PATCH 7/7] #18 added todo annotations --- acmwebsite/controllers/survey.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/acmwebsite/controllers/survey.py b/acmwebsite/controllers/survey.py index 05eadc6..1ae058a 100644 --- a/acmwebsite/controllers/survey.py +++ b/acmwebsite/controllers/survey.py @@ -17,14 +17,15 @@ def results(self, number=None, order_by=None, reverse=False): reverse = reverse == 'True' if order_by: - # TODO: this doesn't work... + # TODO (#46): this doesn't work... If the column is nullable, then + # the sort can't deal with comparing None types # order = '{} {}'.format(order_by, 'asc' if reverse else 'desc') # responses = self.survey.responses.order_by(order) responses = self.survey.responses else: responses = self.survey.responses - # TODO: This sucks. It would be good to have this done for us with + # TODO (#46): This sucks. It would be good to have this done for us with # SQLAlchemy magic responses = [self._response_dict(r) for r in responses or []]