Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100755 287 lines (256 sloc) 12.105 kb
8414350 @billsaysthis multiline for details and notes fields
billsaysthis authored
1 import cgi
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
2 from google.appengine.ext import webapp, db
3 from google.appengine.ext.webapp import util, template
47a7f7a @progrium basic form validation, added end time, start of notifications, some fixe...
progrium authored
4 from google.appengine.api import urlfetch, memcache, users, mail
5
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
6 from django.utils import simplejson
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
7 from django.template.defaultfilters import slugify
5cd04ac Fixed iCalendar-related imports, and added the end date to the
Matt Hancher authored
8 from icalendar import Calendar
b4ea292 Handler to bug pending events
Brian Klug authored
9 import logging, urllib, os
7bdb866 Let all members staff events.
Brian Klug authored
10 from pprint import pprint
b879063 @mdhancher Respect the local timezone (Pacific), and tidy up related imports.
mdhancher authored
11 from datetime import datetime, timedelta
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
12
81a81e1 @progrium adding errors for form validation, full notifications, and minor edits t...
progrium authored
13 from models import Event, Feedback, ROOM_OPTIONS, GUESTS_PER_STAFF, PENDING_LIFETIME
d8e72b5 @chrismeyer Added checking for phone numbers as well as a unit testing framework.
chrismeyer authored
14 from utils import dojo, username, human_username, set_cookie, local_today, is_phone_valid
81a81e1 @progrium adding errors for form validation, full notifications, and minor edits t...
progrium authored
15 from notices import *
7742592 @progrium start of maintaining form state on errors
progrium authored
16
e2b9558 @btubbs Fixes issue 4. Changed to jqueryUI datepicker. Replaced jquery
btubbs authored
17 class ExpireCron(webapp.RequestHandler):
47a7f7a @progrium basic form validation, added end time, start of notifications, some fixe...
progrium authored
18 def post(self):
19 # Expire events marked to expire today
b879063 @mdhancher Respect the local timezone (Pacific), and tidy up related imports.
mdhancher authored
20 today = local_today()
47a7f7a @progrium basic form validation, added end time, start of notifications, some fixe...
progrium authored
21 events = Event.all() \
22 .filter('status IN', ['pending', 'understaffed']) \
23 .filter('expired >=', today) \
24 .filter('expired <', today + timedelta(days=1))
25 for event in events:
26 event.expire()
27 notify_owner_expired(event)
28
f1997e4 @christopherb Made misc style fixes
christopherb authored
29
47a7f7a @progrium basic form validation, added end time, start of notifications, some fixe...
progrium authored
30 class ExpireReminderCron(webapp.RequestHandler):
31 def post(self):
32 # Find events expiring in 10 days to warn owner
b879063 @mdhancher Respect the local timezone (Pacific), and tidy up related imports.
mdhancher authored
33 ten_days = local_today() + timedelta(days=10)
47a7f7a @progrium basic form validation, added end time, start of notifications, some fixe...
progrium authored
34 events = Event.all() \
35 .filter('status IN', ['pending', 'understaffed']) \
36 .filter('expired >=', ten_days) \
37 .filter('expired <', ten_days + timedelta(days=1))
38 for event in events:
39 notify_owner_expiring(event)
40
f1997e4 @christopherb Made misc style fixes
christopherb authored
41
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
42 class EventsHandler(webapp.RequestHandler):
43 def get(self, format):
44 if format == 'ics':
a493a39 @progrium changing the json events list to the approved list
progrium authored
45 events = Event.all().filter('status IN', ['approved', 'canceled']).order('start_time')
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
46 cal = Calendar()
47 for event in events:
48 cal.add_component(event.to_ical())
49 self.response.headers['content-type'] = 'text/calendar'
50 self.response.out.write(cal.as_string())
2e08a66 @progrium cleaning things up and adding json representations for jon
progrium authored
51 elif format == 'json':
52 self.response.headers['content-type'] = 'application/json'
a493a39 @progrium changing the json events list to the approved list
progrium authored
53 events = map(lambda x: x.to_dict(summarize=True), Event.get_approved_list())
2e08a66 @progrium cleaning things up and adding json representations for jon
progrium authored
54 self.response.out.write(simplejson.dumps(events))
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
55
f1997e4 @christopherb Made misc style fixes
christopherb authored
56
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
57 class EventHandler(webapp.RequestHandler):
58 def get(self, id):
59 event = Event.get_by_id(int(id))
2e08a66 @progrium cleaning things up and adding json representations for jon
progrium authored
60 if self.request.path.endswith('json'):
61 self.response.headers['content-type'] = 'application/json'
62 self.response.out.write(simplejson.dumps(event.to_dict()))
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
63 else:
2e08a66 @progrium cleaning things up and adding json representations for jon
progrium authored
64 user = users.get_current_user()
65 if user:
66 is_admin = username(user) in dojo('/groups/events')
67 is_staff = username(user) in dojo('/groups/staff')
68 can_approve = (event.status in ['pending'] and is_admin and not user == event.member)
69 can_staff = (event.status in ['pending', 'understaffed', 'approved'] and is_staff and not user in event.staff)
70 can_unstaff = (not event.status in ['canceled', 'deleted'] and is_staff and user in event.staff)
71 logout_url = users.create_logout_url('/')
ad675ec @progrium brian's code didn't work when not logged in, and it should be more consi...
progrium authored
72 can_cancel = is_admin or user == event.member
2e08a66 @progrium cleaning things up and adding json representations for jon
progrium authored
73 else:
74 login_url = users.create_login_url('/')
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
75 event.details = db.Text(event.details.replace('\n','<br/>'))
76 event.notes = db.Text(event.notes.replace('\n','<br/>'))
2e08a66 @progrium cleaning things up and adding json representations for jon
progrium authored
77 self.response.out.write(template.render('templates/event.html', locals()))
e2b9558 @btubbs Fixes issue 4. Changed to jqueryUI datepicker. Replaced jquery
btubbs authored
78
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
79 def post(self, id):
80 event = Event.get_by_id(int(id))
81 user = users.get_current_user()
82 is_admin = username(user) in dojo('/groups/events')
7bdb866 Let all members staff events.
Brian Klug authored
83 is_staff = True
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
84 state = self.request.get('state')
85 if state:
86 if state.lower() == 'approve' and is_admin:
87 event.approve()
88 if state.lower() == 'staff' and is_staff:
89 event.add_staff(user)
72849c2 @billsaysthis added unstaff event, including email notification if event becomes under...
billsaysthis authored
90 if state.lower() == 'unstaff' and is_staff:
91 event.remove_staff(user)
92 # send notification is state changed to understaffed
93 if event.status == 'understaffed':
94 notify_unapproved_unstaff_event(event)
dde285e Let owners delete events
Brian Klug authored
95 if state.lower() == 'cancel' and is_admin or event.member == user:
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
96 event.cancel()
a67ac50 @mdhancher Add a simple admin-only event delete and undelete.
mdhancher authored
97 if state.lower() == 'delete' and is_admin:
98 event.delete()
99 if state.lower() == 'undelete' and is_admin:
100 event.undelete()
47a7f7a @progrium basic form validation, added end time, start of notifications, some fixe...
progrium authored
101 if state.lower() == 'expire' and is_admin:
102 event.expire()
103 if event.status == 'approved':
104 notify_owner_approved(event)
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
105 self.redirect('/event/%s-%s' % (event.key().id(), slugify(event.name)))
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
106
f1997e4 @christopherb Made misc style fixes
christopherb authored
107
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
108 class ApprovedHandler(webapp.RequestHandler):
109 def get(self):
110 user = users.get_current_user()
111 if user:
112 logout_url = users.create_logout_url('/')
113 else:
114 login_url = users.create_login_url('/')
b879063 @mdhancher Respect the local timezone (Pacific), and tidy up related imports.
mdhancher authored
115 today = local_today()
47a7f7a @progrium basic form validation, added end time, start of notifications, some fixe...
progrium authored
116 events = Event.get_approved_list()
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
117 tomorrow = today + timedelta(days=1)
d63161a Add widget mode
Brian Klug authored
118 whichbase = 'base.html'
119 if self.request.get('base'):
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
120 whichbase = self.request.get('base') + '.html'
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
121 self.response.out.write(template.render('templates/approved.html', locals()))
122
f1997e4 @christopherb Made misc style fixes
christopherb authored
123
a82b43e @billsaysthis add myevents, pastevents code, refined list display on event page
billsaysthis authored
124 class MyEventsHandler(webapp.RequestHandler):
125 @util.login_required
126 def get(self):
127 user = users.get_current_user()
128 if user:
129 logout_url = users.create_logout_url('/')
130 else:
131 login_url = users.create_login_url('/')
132 events = Event.all().filter('member = ', user).order('start_time')
b879063 @mdhancher Respect the local timezone (Pacific), and tidy up related imports.
mdhancher authored
133 today = local_today()
a82b43e @billsaysthis add myevents, pastevents code, refined list display on event page
billsaysthis authored
134 tomorrow = today + timedelta(days=1)
135 is_admin = username(user) in dojo('/groups/events')
136 self.response.out.write(template.render('templates/myevents.html', locals()))
137
f1997e4 @christopherb Made misc style fixes
christopherb authored
138
a82b43e @billsaysthis add myevents, pastevents code, refined list display on event page
billsaysthis authored
139 class PastHandler(webapp.RequestHandler):
140 def get(self):
141 user = users.get_current_user()
142 if user:
143 logout_url = users.create_logout_url('/')
144 else:
145 login_url = users.create_login_url('/')
b879063 @mdhancher Respect the local timezone (Pacific), and tidy up related imports.
mdhancher authored
146 today = local_today()
d75579f @progrium minor updates here and there to bills contributions.
progrium authored
147 events = Event.all().filter('start_time < ', today).order('-start_time')
a82b43e @billsaysthis add myevents, pastevents code, refined list display on event page
billsaysthis authored
148 is_admin = username(user) in dojo('/groups/events')
149 self.response.out.write(template.render('templates/past.html', locals()))
150
f1997e4 @christopherb Made misc style fixes
christopherb authored
151
b4ea292 Handler to bug pending events
Brian Klug authored
152 class CronBugOwnersHandler(webapp.RequestHandler):
153 def get(self):
154 events = Event.get_pending_list()
155 for e in events:
156 bug_owner_pending(e)
157
f1997e4 @christopherb Made misc style fixes
christopherb authored
158
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
159 class PendingHandler(webapp.RequestHandler):
160 def get(self):
161 user = users.get_current_user()
162 if user:
163 logout_url = users.create_logout_url('/')
164 else:
165 login_url = users.create_login_url('/')
47a7f7a @progrium basic form validation, added end time, start of notifications, some fixe...
progrium authored
166 events = Event.get_pending_list()
b879063 @mdhancher Respect the local timezone (Pacific), and tidy up related imports.
mdhancher authored
167 today = local_today()
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
168 tomorrow = today + timedelta(days=1)
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
169 is_admin = username(user) in dojo('/groups/events')
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
170 self.response.out.write(template.render('templates/pending.html', locals()))
171
f1997e4 @christopherb Made misc style fixes
christopherb authored
172
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
173 class NewHandler(webapp.RequestHandler):
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
174 @util.login_required
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
175 def get(self):
176 user = users.get_current_user()
177 if user:
178 logout_url = users.create_logout_url('/')
179 else:
180 login_url = users.create_login_url('/')
181 rooms = ROOM_OPTIONS
182 self.response.out.write(template.render('templates/new.html', locals()))
e2b9558 @btubbs Fixes issue 4. Changed to jqueryUI datepicker. Replaced jquery
btubbs authored
183
f1997e4 @christopherb Made misc style fixes
christopherb authored
184
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
185 def post(self):
186 user = users.get_current_user()
7742592 @progrium start of maintaining form state on errors
progrium authored
187 try:
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
188 start_time = datetime.strptime('%s %s:%s %s' % (
7742592 @progrium start of maintaining form state on errors
progrium authored
189 self.request.get('date'),
190 self.request.get('start_time_hour'),
191 self.request.get('start_time_minute'),
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
192 self.request.get('start_time_ampm')), '%m/%d/%Y %I:%M %p')
193 end_time = datetime.strptime('%s %s:%s %s' % (
7742592 @progrium start of maintaining form state on errors
progrium authored
194 self.request.get('date'),
195 self.request.get('end_time_hour'),
196 self.request.get('end_time_minute'),
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
197 self.request.get('end_time_ampm')), '%m/%d/%Y %I:%M %p')
8615877 Fix validation for event size
Brian Klug authored
198 if not self.request.get('estimated_size').isdigit():
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
199 raise ValueError('Estimated number of people must be a number')
8615877 Fix validation for event size
Brian Klug authored
200 if not int(self.request.get('estimated_size')) > 0:
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
201 raise ValueError('Estimated number of people must be greater then zero')
7742592 @progrium start of maintaining form state on errors
progrium authored
202 if (end_time-start_time).days < 0:
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
203 raise ValueError('End time must be after start time')
d8e72b5 @chrismeyer Added checking for phone numbers as well as a unit testing framework.
chrismeyer authored
204 if ( not is_phone_valid( self.request.get( 'contact_phone' ) ) ):
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
205 raise ValueError( 'Phone number does not appear to be valid' )
7742592 @progrium start of maintaining form state on errors
progrium authored
206 else:
207 event = Event(
ca3c6dd Escaped additional fields that could be used for XSS
Christopher Biettchert authored
208 name = cgi.escape(self.request.get('name')),
7742592 @progrium start of maintaining form state on errors
progrium authored
209 start_time = start_time,
210 end_time = end_time,
ca3c6dd Escaped additional fields that could be used for XSS
Christopher Biettchert authored
211 type = cgi.escape(self.request.get('type')),
212 estimated_size = cgi.escape(self.request.get('estimated_size')),
213 contact_name = cgi.escape(self.request.get('contact_name')),
214 contact_phone = cgi.escape(self.request.get('contact_phone')),
8414350 @billsaysthis multiline for details and notes fields
billsaysthis authored
215 details = cgi.escape(self.request.get('details')),
ca3c6dd Escaped additional fields that could be used for XSS
Christopher Biettchert authored
216 url = cgi.escape(self.request.get('url')),
217 fee = cgi.escape(self.request.get('fee')),
8414350 @billsaysthis multiline for details and notes fields
billsaysthis authored
218 notes = cgi.escape(self.request.get('notes')),
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
219 rooms = self.request.get_all('rooms'),
b879063 @mdhancher Respect the local timezone (Pacific), and tidy up related imports.
mdhancher authored
220 expired = local_today() + timedelta(days=PENDING_LIFETIME), # Set expected expiration date
7742592 @progrium start of maintaining form state on errors
progrium authored
221 )
222 event.put()
223 notify_owner_confirmation(event)
224 if not event.is_staffed():
225 notify_staff_needed(event)
226 notify_new_event(event)
81a81e1 @progrium adding errors for form validation, full notifications, and minor edits t...
progrium authored
227 set_cookie(self.response.headers, 'formvalues', None)
7742592 @progrium start of maintaining form state on errors
progrium authored
228 self.redirect('/event/%s-%s' % (event.key().id(), slugify(event.name)))
81a81e1 @progrium adding errors for form validation, full notifications, and minor edits t...
progrium authored
229 except Exception, e:
230 message = str(e)
231 if 'match format' in message:
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
232 message = 'Date is required.'
81a81e1 @progrium adding errors for form validation, full notifications, and minor edits t...
progrium authored
233 if message.startswith('Property'):
234 message = message[9:].replace('_', ' ').capitalize()
235 set_cookie(self.response.headers, 'formerror', message)
7742592 @progrium start of maintaining form state on errors
progrium authored
236 set_cookie(self.response.headers, 'formvalues', dict(self.request.POST))
237 self.redirect('/new')
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
238
d2c3dc7 @billsaysthis moved app-specific js to separate file
billsaysthis authored
239
240 class FeedbackHandler(webapp.RequestHandler):
241 @util.login_required
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
242 def get(self, id):
d2c3dc7 @billsaysthis moved app-specific js to separate file
billsaysthis authored
243 user = users.get_current_user()
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
244 event = Event.get_by_id(int(id))
d2c3dc7 @billsaysthis moved app-specific js to separate file
billsaysthis authored
245 if user:
246 logout_url = users.create_logout_url('/')
247 else:
248 login_url = users.create_login_url('/')
249 self.response.out.write(template.render('templates/feedback.html', locals()))
250
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
251 def post(self, id):
d2c3dc7 @billsaysthis moved app-specific js to separate file
billsaysthis authored
252 user = users.get_current_user()
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
253 event = Event.get_by_id(int(id))
8c52522 @billsaysthis small tweak to how feedbacks displayed in event page
billsaysthis authored
254 try:
255 if self.request.get('rating'):
256 feedback = Feedback(
257 event = event,
258 rating = int(self.request.get('rating')),
ca3c6dd Escaped additional fields that could be used for XSS
Christopher Biettchert authored
259 comment = cgi.escape(self.request.get('comment')))
8c52522 @billsaysthis small tweak to how feedbacks displayed in event page
billsaysthis authored
260 feedback.put()
261 self.redirect('/event/%s-%s' % (event.key().id(), slugify(event.name)))
262 else:
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
263 raise ValueError('Please select a rating')
8c52522 @billsaysthis small tweak to how feedbacks displayed in event page
billsaysthis authored
264 except Exception:
265 set_cookie(self.response.headers, 'formvalues', dict(self.request.POST))
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on single q...
christopherb authored
266 self.redirect('/feedback/new/' + id)
d2c3dc7 @billsaysthis moved app-specific js to separate file
billsaysthis authored
267
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
268 def main():
269 application = webapp.WSGIApplication([
270 ('/', ApprovedHandler),
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
271 ('/events\.(.+)', EventsHandler),
d75579f @progrium minor updates here and there to bills contributions.
progrium authored
272 ('/past', PastHandler),
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
273 ('/pending', PendingHandler),
b4ea292 Handler to bug pending events
Brian Klug authored
274 ('/cronbugowners', CronBugOwnersHandler),
a82b43e @billsaysthis add myevents, pastevents code, refined list display on event page
billsaysthis authored
275 ('/myevents', MyEventsHandler),
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
276 ('/new', NewHandler),
47a7f7a @progrium basic form validation, added end time, start of notifications, some fixe...
progrium authored
277 ('/event/(\d+).*', EventHandler),
2e08a66 @progrium cleaning things up and adding json representations for jon
progrium authored
278 ('/event/(\d+)\.json', EventHandler),
47a7f7a @progrium basic form validation, added end time, start of notifications, some fixe...
progrium authored
279 ('/expire', ExpireCron),
34d98f0 @billsaysthis moved feedback stuff to separate py file, small tweak to email notificat...
billsaysthis authored
280 ('/expiring', ExpireReminderCron),
d2c3dc7 @billsaysthis moved app-specific js to separate file
billsaysthis authored
281 ('/feedback/new/(\d+).*', FeedbackHandler) ],debug=True)
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
282 util.run_wsgi_app(application)
283
f1997e4 @christopherb Made misc style fixes
christopherb authored
284
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
285 if __name__ == '__main__':
286 main()
Something went wrong with that request. Please try again.