From b095bc191fbf6846de8e2b1a9352d22d0156936d Mon Sep 17 00:00:00 2001
From: Michael Zhang
Date: Fri, 26 Aug 2016 01:40:07 -0500
Subject: [PATCH 01/41] [WIP] Connect with OpenCTF
---
forms.py | 35 ++++++++++++++++++++++++++-------
models.py | 11 +++++++++--
requirements.txt | 1 +
templates/events/manage.html | 25 -----------------------
templates/users/oauthorize.html | 28 ++++++++++++++++++++++++++
views/events.py | 8 ++++----
views/oauth.py | 2 +-
7 files changed, 71 insertions(+), 39 deletions(-)
create mode 100644 templates/users/oauthorize.html
diff --git a/forms.py b/forms.py
index f919a44..a9fcebb 100644
--- a/forms.py
+++ b/forms.py
@@ -4,6 +4,7 @@
from wtforms.fields import *
from wtforms.validators import *
from wtforms.widgets import TextArea
+from wtforms_components import read_only
import util
from models import User
@@ -48,17 +49,37 @@ def validate_username(self, field):
raise ValidationError('Username taken!')
-class EventForm(Form):
+class EventCreateForm(Form):
title = StringField('Title', validators=[InputRequired(), Length(max=256)])
- start_time = IntegerField('Start Time',
- validators=[InputRequired(), NumberRange(min=0, max=2147483647,
- message='Start time must be between 0 and 2147483647!')])
- duration = FloatField('Duration (hours)',
- validators=[InputRequired(), NumberRange(min=0, max=2147483647,
- message='Duration must be between 0 and 2147483647!')])
+ start_time = IntegerField('Start Time', validators=[InputRequired(), NumberRange(min=0, max=2147483647,
+ message='Start time must be between 0 and 2147483647!')])
+ duration = FloatField('Duration (hours)', validators=[InputRequired(), NumberRange(min=0, max=2147483647,
+ message='Duration must be between 0 and 2147483647!')])
description = StringField('Description', widget=TextArea(), validators=[InputRequired(), Length(max=1024)])
link = StringField('Link', validators=[InputRequired(), Length(max=256)])
def validate_link(self, field):
if not any(field.data.startswith(prefix) for prefix in [u'http://', u'https://']):
raise ValidationError('Invalid link')
+
+
+class EventManageForm(Form):
+ title = StringField('Title', validators=[InputRequired(), Length(max=256)])
+ start_time = IntegerField('Start Time', validators=[InputRequired(), NumberRange(min=0, max=2147483647,
+ message='Start time must be between 0 and 2147483647!')])
+ duration = FloatField('Duration (hours)', validators=[InputRequired(), NumberRange(min=0, max=2147483647,
+ message='Duration must be between 0 and 2147483647!')])
+ description = StringField('Description', widget=TextArea(), validators=[InputRequired(), Length(max=1024)])
+ link = StringField('Link', validators=[InputRequired(), Length(max=256)])
+ client_id = StringField('Client ID')
+ client_secret = StringField('Client Secret')
+ redirect_uris = StringField('Redirect URIs', widget=TextArea(), validators=[])
+
+ def __init__(self, *args, **kwargs):
+ super(EventManageForm, self).__init__(*args, **kwargs)
+ read_only(self.client_id)
+ read_only(self.client_secret)
+
+ def validate_link(self, field):
+ if not any(field.data.startswith(prefix) for prefix in [u'http://', u'https://']):
+ raise ValidationError('Invalid link')
diff --git a/models.py b/models.py
index e34403a..ea94b83 100644
--- a/models.py
+++ b/models.py
@@ -101,7 +101,7 @@ class Event(db.Model):
client_secret = db.Column(db.String(55), unique=True, index=True, nullable=False, default=util.generate_string(32))
is_confidential = db.Column(db.Boolean, default=True)
_redirect_uris = db.Column(db.Text)
- _default_scopes = db.Column(db.Text)
+ _default_scopes = db.Column(db.Text, default='profile')
@property
def client_type(self):
@@ -111,10 +111,17 @@ def client_type(self):
@property
def redirect_uris(self):
+ 'getting'
if self._redirect_uris:
- return self._redirect_uris.split()
+ return self._redirect_uris#.split()
return []
+ @redirect_uris.setter
+ def redirect_uris(self, value):
+ 'setting'
+ self._redirect_uris = value
+ db.session.commit()
+
@property
def default_redirect_uri(self):
return self.redirect_uris[0]
diff --git a/requirements.txt b/requirements.txt
index 318c1a9..7a10840 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -16,3 +16,4 @@ pymysql
python-dotenv
sqlalchemy
wtforms
+wtforms_components
\ No newline at end of file
diff --git a/templates/events/manage.html b/templates/events/manage.html
index e318d68..947badf 100644
--- a/templates/events/manage.html
+++ b/templates/events/manage.html
@@ -56,31 +56,6 @@ Manage Event
-
-
-
OAuth Information
-
-
-
diff --git a/templates/users/oauthorize.html b/templates/users/oauthorize.html
new file mode 100644
index 0000000..d3505cd
--- /dev/null
+++ b/templates/users/oauthorize.html
@@ -0,0 +1,28 @@
+{% extends "layout.html" %}
+
+{% block title %}
+ Authorize {{ client.title }}?
+{% endblock %}
+
+{% block content %}
+
+
+
+
+
Authorize Application?
+
+
+
+
+
{{ client.title }}
+
+ to access your profile?
+
+
+
+
+
+
+{% endblock %}
diff --git a/views/events.py b/views/events.py
index ce5e26b..bc3c7d4 100644
--- a/views/events.py
+++ b/views/events.py
@@ -3,7 +3,7 @@
from flask import abort, Blueprint, redirect, render_template, url_for, flash
from flask_login import current_user, login_required
-from forms import EventForm
+from forms import EventCreateForm, EventManageForm
from models import db, Event
from util import admin_required, isoformat
@@ -13,7 +13,7 @@
@blueprint.route('/create', methods=['GET', 'POST'])
@login_required
def events_create():
- event_create_form = EventForm()
+ event_create_form = EventCreateForm()
if event_create_form.validate_on_submit():
new_event = Event(owner=current_user)
event_create_form.populate_obj(new_event)
@@ -112,10 +112,10 @@ def events_manage(event_id):
event = Event.query.get_or_404(event_id)
if current_user != event.owner:
abort(403)
- event_form = EventForm(obj=event)
+ event_form = EventManageForm(obj=event)
if event_form.validate_on_submit():
event_form.populate_obj(event)
- return redirect(url_for('.events_detail', event_id=event_id))
+ return redirect(url_for('.events_manage', event_id=event_id))
return render_template('events/manage.html', event=event, event_form=event_form)
diff --git a/views/oauth.py b/views/oauth.py
index 46ed448..3871414 100644
--- a/views/oauth.py
+++ b/views/oauth.py
@@ -14,7 +14,7 @@ def authorize(*args, **kwargs):
client_id = kwargs.get('client_id')
client = Event.query.filter_by(client_id=client_id).first()
kwargs['client'] = client
- return render_template('oauthorize.html', **kwargs)
+ return render_template('users/oauthorize.html', **kwargs)
confirm = request.form.get('confirm', 'no')
return confirm == 'yes'
From 0ad271bf589d5dee78e242473970c6704367931f Mon Sep 17 00:00:00 2001
From: David Hou
Date: Tue, 30 Aug 2016 15:56:20 -0700
Subject: [PATCH 02/41] Use functools.partial for functions as SQLAlchemy
Column defaults.
These are evaluated at interpret time so it would only be run once if you just put the plain value (function call) on.
---
models.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/models.py b/models.py
index ea94b83..4a912bb 100644
--- a/models.py
+++ b/models.py
@@ -1,4 +1,5 @@
from datetime import datetime, timedelta
+from functools import partial
from flask_login import current_user, LoginManager
from flask_oauthlib.provider import OAuth2Provider
@@ -97,8 +98,8 @@ class Event(db.Model):
removed = db.Column(db.Boolean, default=False)
# OAuth2 stuff
- client_id = db.Column(db.String(40), unique=True, default=util.generate_string(16))
- client_secret = db.Column(db.String(55), unique=True, index=True, nullable=False, default=util.generate_string(32))
+ client_id = db.Column(db.String(40), unique=True, default=partial(util.generate_string, 16))
+ client_secret = db.Column(db.String(55), unique=True, index=True, nullable=False, default=partial(util.generate_string, 32))
is_confidential = db.Column(db.Boolean, default=True)
_redirect_uris = db.Column(db.Text)
_default_scopes = db.Column(db.Text, default='profile')
From aba5bb8d30d6b953e7d5cc3a75288c57763396a5 Mon Sep 17 00:00:00 2001
From: David Hou
Date: Tue, 30 Aug 2016 14:58:11 -0700
Subject: [PATCH 03/41] Use url_for instead of hardcoding URLs in layout
template.
---
templates/layout.html | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/templates/layout.html b/templates/layout.html
index 3c7d222..a5e1b52 100644
--- a/templates/layout.html
+++ b/templates/layout.html
@@ -36,18 +36,18 @@
Community
From 855bee600cf71575d3c07a7b3b802795e8b64ba7 Mon Sep 17 00:00:00 2001
From: David Hou
Date: Tue, 30 Aug 2016 15:28:02 -0700
Subject: [PATCH 04/41] Paginate lists.
---
.cache/v/cache/lastfailed | 1 +
.coverage | 1 +
config.py | 3 +
views/events.py | 122 ++++++++++++++++++++++++++++----------
views/users.py | 18 ++++--
5 files changed, 109 insertions(+), 36 deletions(-)
create mode 100644 .cache/v/cache/lastfailed
create mode 100644 .coverage
diff --git a/.cache/v/cache/lastfailed b/.cache/v/cache/lastfailed
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/.cache/v/cache/lastfailed
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/.coverage b/.coverage
new file mode 100644
index 0000000..99a10b1
--- /dev/null
+++ b/.coverage
@@ -0,0 +1 @@
+!coverage.py: This is a private format, don't read it directly!{"lines": {"/vagrant/tests/__init__.py": [1], "/vagrant/filters.py": [], "/vagrant/views/events.py": [], "/vagrant/views/oauth.py": [], "/vagrant/forms.py": [], "/vagrant/manage.py": [], "/vagrant/models.py": [], "/vagrant/util.py": [], "/vagrant/views/users.py": [], "/vagrant/tests/test_general.py": [1, 2, 3], "/vagrant/config.py": [], "/vagrant/cal.py": [], "/vagrant/constants.py": [], "/vagrant/views/__init__.py": [], "/vagrant/views/base.py": [], "/vagrant/conftest.py": [1]}}
\ No newline at end of file
diff --git a/config.py b/config.py
index 0a309f6..e6590a5 100644
--- a/config.py
+++ b/config.py
@@ -5,6 +5,9 @@
load_dotenv(find_dotenv())
+EVENT_LIST_PAGE_SIZE = 25
+USER_LIST_PAGE_SIZE = 50
+
class CalendarConfig:
def __init__(self, app_root=None, testing=False):
diff --git a/views/events.py b/views/events.py
index ce5e26b..29a1e01 100644
--- a/views/events.py
+++ b/views/events.py
@@ -3,6 +3,7 @@
from flask import abort, Blueprint, redirect, render_template, url_for, flash
from flask_login import current_user, login_required
+import config
from forms import EventForm
from models import db, Event
from util import admin_required, isoformat
@@ -24,67 +25,124 @@ def events_create():
@blueprint.route('/list/json')
-def events_list_json():
- events = Event.query.filter_by().order_by(Event.start_time.desc()).all()
- event_list = []
- for event in events:
- start_time = event.start_time
- obj = {
- 'id': event.id,
- 'approved': event.approved,
- 'name': event.title,
- 'startTime': start_time * 1000,
- 'startTimeFormat': isoformat(start_time),
- 'endTime': (start_time + event.duration * 60 * 60) * 1000,
- 'duration': event.duration
- }
- event_list.append(obj)
+@blueprint.route('/list/json/')
+def events_list_json(page_number=1):
+ if page_number <= 0:
+ abort(404)
+
+ page_size = config.EVENT_LIST_PAGE_SIZE
+ page_offset = (page_number - 1) * page_size
+ events = Event.query.order_by(Event.start_time.desc()).offset(page_offset).limit(page_size)
+ if page_number != 1 and not events:
+ abort(404)
+
+ event_list = [{
+ 'id': event.id,
+ 'approved': event.approved,
+ 'name': event.title,
+ 'startTime': event.start_time * 1000,
+ 'startTimeFormat': isoformat(event.start_time),
+ 'endTime': (event.start_time + event.duration * 60 * 60) * 1000,
+ 'duration': event.duration
+ } for event in events]
return json.dumps(event_list)
@blueprint.route('/')
@blueprint.route('/all')
-def events_all():
- events = Event.query.filter_by(approved=True, removed=False).order_by(Event.start_time.desc()).all()
+@blueprint.route('/all/')
+def events_all(page_number=1):
+ if page_number <= 0:
+ abort(404)
+
+ page_size = config.EVENT_LIST_PAGE_SIZE
+ page_offset = (page_number - 1) * page_size
+ events = Event.query.filter_by(approved=True, removed=False).order_by(Event.start_time.desc()) \
+ .offset(page_offset).limit(page_size).all()
+ if page_number != 1 and not events:
+ abort(404)
+
for event in events:
event.start_time_format = isoformat(event.start_time)
- return render_template('events/list.html', tab='all', events=events)
+ return render_template('events/list.html', tab='all', page_number=page_number, events=events)
# todo
@blueprint.route('/upcoming')
-def events_upcoming():
- events = Event.query.filter_by(approved=True, removed=False).order_by(Event.start_time.desc()).all()
- for event in events:
+@blueprint.route('/upcoming/')
+def events_upcoming(page_number=1):
+ if page_number <= 0:
+ abort(404)
+
+ page_size = config.EVENT_LIST_PAGE_SIZE
+ page_offset = (page_number - 1) * page_size
+ upcoming_events = Event.query.filter_by(approved=True, removed=False).order_by(Event.start_time.desc()) \
+ .offset(page_offset).limit(page_size).all()
+ if page_number != 1 and not upcoming_events:
+ abort(404)
+
+ for event in upcoming_events:
event.start_time_format = isoformat(event.start_time)
- return render_template('events/list.html', tab='upcoming', events=events)
+ return render_template('events/list.html', tab='upcoming', page_number=page_number, events=upcoming_events)
# todo
@blueprint.route('/past')
-def events_past():
- events = Event.query.filter_by(approved=True, removed=False).order_by(Event.start_time.desc()).all()
- for event in events:
+@blueprint.route('/past/')
+def events_past(page_number=1):
+ if page_number <= 0:
+ abort(404)
+
+ page_size = config.EVENT_LIST_PAGE_SIZE
+ page_offset = (page_number - 1) * page_size
+ past_events = Event.query.filter_by(approved=True, removed=False).order_by(Event.start_time.desc()) \
+ .offset(page_offset).limit(page_size).all()
+ if page_number != 1 and not past_events:
+ abort(404)
+
+ for event in past_events:
event.start_time_format = isoformat(event.start_time)
- return render_template('events/list.html', tab='past', events=events)
+ return render_template('events/list.html', tab='past', page_number=page_number, events=past_events)
@blueprint.route('/unapproved')
+@blueprint.route('/unapproved/')
@admin_required
-def events_unapproved():
- unapproved_events = Event.query.filter_by(approved=False, removed=False).order_by(Event.start_time.desc()).all()
+def events_unapproved(page_number=1):
+ if page_number <= 0:
+ abort(404)
+
+ page_size = config.EVENT_LIST_PAGE_SIZE
+ page_offset = (page_number - 1) * page_size
+ unapproved_events = Event.query.filter_by(approved=False, removed=False).order_by(Event.start_time.desc()) \
+ .offset(page_offset).limit(page_size).all()
+ if page_number != 1 and not unapproved_events:
+ abort(404)
+
for event in unapproved_events:
event.start_time_format = isoformat(event.start_time)
- return render_template('events/list.html', tab='unapproved', events=unapproved_events, enabled_actions=['approve'])
+ return render_template('events/list.html', tab='unapproved', page_number=page_number, events=unapproved_events,
+ enabled_actions=['approve'])
@blueprint.route('/owned')
+@blueprint.route('/owned/')
@login_required
-def events_owned():
- owned_events = current_user.events.filter_by(removed=False)
+def events_owned(page_number=1):
+ if page_number <= 0:
+ abort(404)
+
+ page_size = config.EVENT_LIST_PAGE_SIZE
+ page_offset = (page_number - 1) * page_size
+ owned_events = current_user.events.filter_by(removed=False).order_by(Event.start_time.desc()) \
+ .offset(page_offset).limit(page_size).all()
+ if page_number != 1 and not owned_events:
+ abort(404)
+
for event in owned_events:
event.start_time_format = isoformat(event.start_time)
- return render_template('events/list.html', tab='owned', events=owned_events, enabled_actions=['manage', 'remove'])
+ return render_template('events/list.html', tab='owned', page_number=page_number, events=owned_events,
+ enabled_actions=['manage', 'remove'])
@blueprint.route('/')
diff --git a/views/users.py b/views/users.py
index ab39286..b2156b2 100644
--- a/views/users.py
+++ b/views/users.py
@@ -1,6 +1,7 @@
-from flask import Blueprint, render_template, redirect, url_for, send_file
+from flask import abort, Blueprint, render_template, redirect, url_for, send_file
from flask_login import current_user, login_required, login_user, logout_user
+import config
from forms import LoginForm, RegisterForm
from models import db
from models import login_manager, User
@@ -52,9 +53,18 @@ def profile():
@blueprint.route('/users')
-def users_list():
- users = User.query.order_by(User.id).all()
- return render_template('users/list.html', users=users)
+@blueprint.route('/users/')
+def users_list(page_number=1):
+ if page_number <= 0:
+ abort(404)
+
+ page_size = config.USER_LIST_PAGE_SIZE
+ page_offset = (page_number - 1) * page_size
+ users = User.query.order_by(User.id).order_by(User.id.desc()).offset(page_offset).limit(page_size)
+ if page_number != 1 and not users:
+ abort(404)
+
+ return render_template('users/list.html', page_number=page_number, users=users)
@blueprint.route('/users/')
From a32515a357a517049156c4d799f3a1170cc7a57b Mon Sep 17 00:00:00 2001
From: David Hou
Date: Tue, 30 Aug 2016 15:31:43 -0700
Subject: [PATCH 05/41] Move Event start time isoformatting to a @property
---
models.py | 4 ++++
templates/events/list.html | 2 +-
views/events.py | 23 ++++-------------------
3 files changed, 9 insertions(+), 20 deletions(-)
diff --git a/models.py b/models.py
index a9c2eb4..a0aada9 100644
--- a/models.py
+++ b/models.py
@@ -104,6 +104,10 @@ class Event(db.Model):
_redirect_uris = db.Column(db.Text)
_default_scopes = db.Column(db.Text)
+ @property
+ def formatted_start_time(self):
+ return util.isoformat(self.start_time)
+
@property
def client_type(self):
if self.is_confidential:
diff --git a/templates/events/list.html b/templates/events/list.html
index 84b2eaf..2c418cf 100644
--- a/templates/events/list.html
+++ b/templates/events/list.html
@@ -46,7 +46,7 @@
{{ event.description }} |
+ datetime="{{ event.formatted_start_time }}">{{ event.formatted_start_time }}
|
{{ event.duration|duration('hour') }} |
Website |
diff --git a/views/events.py b/views/events.py
index 29a1e01..f43842c 100644
--- a/views/events.py
+++ b/views/events.py
@@ -58,12 +58,9 @@ def events_all(page_number=1):
page_size = config.EVENT_LIST_PAGE_SIZE
page_offset = (page_number - 1) * page_size
events = Event.query.filter_by(approved=True, removed=False).order_by(Event.start_time.desc()) \
- .offset(page_offset).limit(page_size).all()
+ .offset(page_offset).limit(page_size)
if page_number != 1 and not events:
abort(404)
-
- for event in events:
- event.start_time_format = isoformat(event.start_time)
return render_template('events/list.html', tab='all', page_number=page_number, events=events)
@@ -77,12 +74,9 @@ def events_upcoming(page_number=1):
page_size = config.EVENT_LIST_PAGE_SIZE
page_offset = (page_number - 1) * page_size
upcoming_events = Event.query.filter_by(approved=True, removed=False).order_by(Event.start_time.desc()) \
- .offset(page_offset).limit(page_size).all()
+ .offset(page_offset).limit(page_size)
if page_number != 1 and not upcoming_events:
abort(404)
-
- for event in upcoming_events:
- event.start_time_format = isoformat(event.start_time)
return render_template('events/list.html', tab='upcoming', page_number=page_number, events=upcoming_events)
@@ -96,12 +90,9 @@ def events_past(page_number=1):
page_size = config.EVENT_LIST_PAGE_SIZE
page_offset = (page_number - 1) * page_size
past_events = Event.query.filter_by(approved=True, removed=False).order_by(Event.start_time.desc()) \
- .offset(page_offset).limit(page_size).all()
+ .offset(page_offset).limit(page_size)
if page_number != 1 and not past_events:
abort(404)
-
- for event in past_events:
- event.start_time_format = isoformat(event.start_time)
return render_template('events/list.html', tab='past', page_number=page_number, events=past_events)
@@ -115,12 +106,9 @@ def events_unapproved(page_number=1):
page_size = config.EVENT_LIST_PAGE_SIZE
page_offset = (page_number - 1) * page_size
unapproved_events = Event.query.filter_by(approved=False, removed=False).order_by(Event.start_time.desc()) \
- .offset(page_offset).limit(page_size).all()
+ .offset(page_offset).limit(page_size)
if page_number != 1 and not unapproved_events:
abort(404)
-
- for event in unapproved_events:
- event.start_time_format = isoformat(event.start_time)
return render_template('events/list.html', tab='unapproved', page_number=page_number, events=unapproved_events,
enabled_actions=['approve'])
@@ -138,9 +126,6 @@ def events_owned(page_number=1):
.offset(page_offset).limit(page_size).all()
if page_number != 1 and not owned_events:
abort(404)
-
- for event in owned_events:
- event.start_time_format = isoformat(event.start_time)
return render_template('events/list.html', tab='owned', page_number=page_number, events=owned_events,
enabled_actions=['manage', 'remove'])
From 7657e0531f07e180d95a909b578c41b2023db9ad Mon Sep 17 00:00:00 2001
From: David Hou
Date: Tue, 30 Aug 2016 15:45:42 -0700
Subject: [PATCH 06/41] Implement upcoming and past events
---
models.py | 10 +++++++++-
views/events.py | 9 +++++----
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/models.py b/models.py
index a0aada9..d59150a 100644
--- a/models.py
+++ b/models.py
@@ -92,7 +92,7 @@ class Event(db.Model):
approved = db.Column(db.Boolean, default=False)
title = db.Column(db.Unicode(length=256))
start_time = db.Column(db.Integer, index=True)
- duration = db.Column(db.Float)
+ duration = db.Column(db.Float) # in hours
description = db.Column(db.UnicodeText)
link = db.Column(db.Unicode(length=256))
removed = db.Column(db.Boolean, default=False)
@@ -108,6 +108,14 @@ class Event(db.Model):
def formatted_start_time(self):
return util.isoformat(self.start_time)
+ @hybrid_property
+ def end_time(self):
+ return self.start_time + self.duration * 60
+
+ @property
+ def formatted_end_time(self):
+ return util.isoformat(self.end_time)
+
@property
def client_type(self):
if self.is_confidential:
diff --git a/views/events.py b/views/events.py
index f43842c..c471ddc 100644
--- a/views/events.py
+++ b/views/events.py
@@ -1,4 +1,5 @@
import json
+import time
from flask import abort, Blueprint, redirect, render_template, url_for, flash
from flask_login import current_user, login_required
@@ -73,8 +74,8 @@ def events_upcoming(page_number=1):
page_size = config.EVENT_LIST_PAGE_SIZE
page_offset = (page_number - 1) * page_size
- upcoming_events = Event.query.filter_by(approved=True, removed=False).order_by(Event.start_time.desc()) \
- .offset(page_offset).limit(page_size)
+ upcoming_events = Event.query.filter_by(approved=True, removed=False).filter(Event.start_time > time.time()) \
+ .order_by(Event.start_time.desc()).offset(page_offset).limit(page_size)
if page_number != 1 and not upcoming_events:
abort(404)
return render_template('events/list.html', tab='upcoming', page_number=page_number, events=upcoming_events)
@@ -89,8 +90,8 @@ def events_past(page_number=1):
page_size = config.EVENT_LIST_PAGE_SIZE
page_offset = (page_number - 1) * page_size
- past_events = Event.query.filter_by(approved=True, removed=False).order_by(Event.start_time.desc()) \
- .offset(page_offset).limit(page_size)
+ past_events = Event.query.filter_by(approved=True, removed=False).filter(Event.end_time <= time.time()) \
+ .order_by(Event.start_time.desc()).offset(page_offset).limit(page_size)
if page_number != 1 and not past_events:
abort(404)
return render_template('events/list.html', tab='past', page_number=page_number, events=past_events)
From 6eadae3406b16b01e03a442d701fcb404e923065 Mon Sep 17 00:00:00 2001
From: Michael Zhang
Date: Tue, 30 Aug 2016 23:16:02 -0500
Subject: [PATCH 07/41] Add page numbers + use .all()
---
templates/events/list.html | 6 ++++++
templates/users/list.html | 8 +++++++-
views/events.py | 10 +++++-----
views/users.py | 4 ++--
4 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/templates/events/list.html b/templates/events/list.html
index 2c418cf..09e49f4 100644
--- a/templates/events/list.html
+++ b/templates/events/list.html
@@ -80,6 +80,12 @@
+
+ {% if page_number == 1 %}Prev{% else %}Prev{% endif %}
+ / Page {{ page_number }} /
+ Next
+
+
-
{% endblock %}
diff --git a/templates/events/list.html b/templates/events/list.html
index 7263ee0..9709a48 100644
--- a/templates/events/list.html
+++ b/templates/events/list.html
@@ -80,13 +80,13 @@
-
+
{% if page_number == 1 %}Prev{% else %}
Prev{% endif %}
/ Page {{ page_number }} /
{% if last_page %}Next{% else %}
Next{% endif %}
-
+
-
-
+
+
+
+
-