Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100755 585 lines (533 sloc) 26.959 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 f…
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
841fefb added meaningful descriptions to ical events.
Stig Hackvan authored
8 from icalendar import Calendar, Event as CalendarEvent
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
2ad290e @billsaysthis add logging model and obscure list view
billsaysthis authored
13 from models import Event, Feedback, HDLog, ROOM_OPTIONS, PENDING_LIFETIME
c97598b @dustball Room Conflict Detection
dustball authored
14 from utils import username, human_username, set_cookie, local_today, is_phone_valid, UserRights, dojo
81a81e1 @progrium adding errors for form validation, full notifications, and minor edit…
progrium authored
15 from notices import *
7742592 @progrium start of maintaining form state on errors
progrium authored
16
9f06c39 @casey Added RSS for upcoming events.
casey authored
17 import PyRSS2Gen
841fefb added meaningful descriptions to ical events.
Stig Hackvan authored
18 import re
7787223 restored an inscrutible but necessary pytz tzinfo quirk to the start/…
Stig Hackvan authored
19 import pytz
9f06c39 @casey Added RSS for upcoming events.
casey authored
20
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
21 webapp.template.register_template_library('templatefilters')
22
9f06c39 @casey Added RSS for upcoming events.
casey authored
23 def event_path(event):
24 return '/event/%s-%s' % (event.key().id(), slugify(event.name))
25
219203b @dustball Cache better
dustball authored
26 class DomainCacheCron(webapp.RequestHandler):
27 def post(self):
28 noop = dojo('/groups/events',force=True)
29
30
f49797a @dustball Reminders 2.0
dustball authored
31 class ReminderCron(webapp.RequestHandler):
32 def post(self):
33 self.response.out.write("REMINDERS")
34 today = local_today()
35 # remind everyone 3 days in advance they need to show up
36 events = Event.all() \
37 .filter('status IN', ['approved']) \
38 .filter('reminded =', False) \
39 .filter('start_time <', today + timedelta(days=3))
40 for event in events:
41 self.response.out.write(event.name)
42 # only mail them if they created the event 2+ days ago
43 if event.created < today - timedelta(days=2):
44 schedule_reminder_email(event)
45 event.reminded = True
46 event.put()
47
48
e2b9558 @btubbs Fixes issue 4. Changed to jqueryUI datepicker. Replaced jquery
btubbs authored
49 class ExpireCron(webapp.RequestHandler):
47a7f7a @progrium basic form validation, added end time, start of notifications, some f…
progrium authored
50 def post(self):
51 # Expire events marked to expire today
b879063 @mdhancher Respect the local timezone (Pacific), and tidy up related imports.
mdhancher authored
52 today = local_today()
47a7f7a @progrium basic form validation, added end time, start of notifications, some f…
progrium authored
53 events = Event.all() \
54 .filter('status IN', ['pending', 'understaffed']) \
55 .filter('expired >=', today) \
56 .filter('expired <', today + timedelta(days=1))
57 for event in events:
58 event.expire()
59 notify_owner_expired(event)
f49797a @dustball Reminders 2.0
dustball authored
60
f1997e4 @christopherb Made misc style fixes
christopherb authored
61
47a7f7a @progrium basic form validation, added end time, start of notifications, some f…
progrium authored
62 class ExpireReminderCron(webapp.RequestHandler):
63 def post(self):
64 # Find events expiring in 10 days to warn owner
b879063 @mdhancher Respect the local timezone (Pacific), and tidy up related imports.
mdhancher authored
65 ten_days = local_today() + timedelta(days=10)
47a7f7a @progrium basic form validation, added end time, start of notifications, some f…
progrium authored
66 events = Event.all() \
67 .filter('status IN', ['pending', 'understaffed']) \
68 .filter('expired >=', ten_days) \
69 .filter('expired <', ten_days + timedelta(days=1))
70 for event in events:
71 notify_owner_expiring(event)
72
841fefb added meaningful descriptions to ical events.
Stig Hackvan authored
73 class ExportHandler(webapp.RequestHandler):
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
74 def get(self, format):
9c331d0 @progrium refactoring the export handler a bit
progrium authored
75 content_type, body = getattr(self, 'export_%s' % format)()
76 self.response.headers['content-type'] = content_type
77 self.response.out.write(body)
78
79 def export_json(self):
20a578c @dustball Reasonable limits
dustball authored
80 events = Event.get_recent_past_and_future()
9c331d0 @progrium refactoring the export handler a bit
progrium authored
81 for k in self.request.GET:
82 if self.request.GET[k] and k in ['member']:
83 value = users.User(urllib.unquote(self.request.GET[k]))
84 else:
85 value = urllib.unquote(self.request.GET[k])
86 events = events.filter('%s =' % k, value)
87 events = map(lambda x: x.to_dict(summarize=True), events)
88 return 'application/json', simplejson.dumps(events)
89
90 def export_ics(self):
20a578c @dustball Reasonable limits
dustball authored
91 events = Event.get_recent_past_and_future()
841fefb added meaningful descriptions to ical events.
Stig Hackvan authored
92 url_base = 'http://' + self.request.headers.get('host', 'events.hackerdojo.com')
9c331d0 @progrium refactoring the export handler a bit
progrium authored
93 cal = Calendar()
94 for event in events:
95 iev = CalendarEvent()
96 iev.add('summary', event.name if event.status == 'approved' else event.name + ' (%s)' % event.status.upper())
97 # make verbose description with empty fields where information is missing
98 ev_desc = '__Status: %s\n__Member: %s\n__Type: %s\n__Estimated size: %s\n__Info URL: %s\n__Fee: %s\n__Contact: %s, %s\n__Rooms: %s\n\n__Details: %s\n\n__Notes: %s' % (
99 event.status,
100 event.owner(),
101 event.type,
102 event.estimated_size,
103 event.url,
104 event.fee,
105 event.contact_name,
106 event.contact_phone,
107 event.roomlist(),
108 event.details,
109 event.notes)
110 # then delete the empty fields with a regex
111 ev_desc = re.sub(re.compile(r'^__.*?:[ ,]*$\n*',re.M),'',ev_desc)
112 ev_desc = re.sub(re.compile(r'^__',re.M),'',ev_desc)
113 ev_url = url_base + event_path(event)
114 iev.add('description', ev_desc + '\n--\n' + ev_url)
115 iev.add('url', ev_url)
116 if event.start_time:
117 iev.add('dtstart', event.start_time.replace(tzinfo=pytz.timezone('US/Pacific')))
118 if event.end_time:
119 iev.add('dtend', event.end_time.replace(tzinfo=pytz.timezone('US/Pacific')))
120 cal.add_component(iev)
121 return 'text/calendar', cal.as_string()
85d17af @dustball "Large Events" page and iCal feed
dustball authored
122
123 def export_large_ics(self):
20a578c @dustball Reasonable limits
dustball authored
124 events = Event.get_recent_past_and_future()
85d17af @dustball "Large Events" page and iCal feed
dustball authored
125 url_base = 'http://' + self.request.headers.get('host', 'events.hackerdojo.com')
126 cal = Calendar()
127 for event in events:
128 iev = CalendarEvent()
129 iev.add('summary', event.name + ' (%s)' % event.estimated_size)
130 # make verbose description with empty fields where information is missing
131 ev_desc = '__Status: %s\n__Member: %s\n__Type: %s\n__Estimated size: %s\n__Info URL: %s\n__Fee: %s\n__Contact: %s, %s\n__Rooms: %s\n\n__Details: %s\n\n__Notes: %s' % (
132 event.status,
133 event.owner(),
134 event.type,
135 event.estimated_size,
136 event.url,
137 event.fee,
138 event.contact_name,
139 event.contact_phone,
140 event.roomlist(),
141 event.details,
142 event.notes)
143 # then delete the empty fields with a regex
144 ev_desc = re.sub(re.compile(r'^__.*?:[ ,]*$\n*',re.M),'',ev_desc)
145 ev_desc = re.sub(re.compile(r'^__',re.M),'',ev_desc)
146 ev_url = url_base + event_path(event)
147 iev.add('description', ev_desc + '\n--\n' + ev_url)
148 iev.add('url', ev_url)
149 if event.start_time:
150 iev.add('dtstart', event.start_time.replace(tzinfo=pytz.timezone('US/Pacific')))
151 if event.end_time:
152 iev.add('dtend', event.end_time.replace(tzinfo=pytz.timezone('US/Pacific')))
153 cal.add_component(iev)
154 return 'text/calendar', cal.as_string()
9c331d0 @progrium refactoring the export handler a bit
progrium authored
155
156 def export_rss(self):
157 url_base = 'http://' + self.request.headers.get('host', 'events.hackerdojo.com')
20a578c @dustball Reasonable limits
dustball authored
158 events = Event.get_recent_past_and_future()
9c331d0 @progrium refactoring the export handler a bit
progrium authored
159 rss = PyRSS2Gen.RSS2(
160 title = "Hacker Dojo Events Feed",
161 link = url_base,
162 description = "Upcoming events at the Hacker Dojo in Mountain View, CA",
163 lastBuildDate = datetime.now(),
164 items = [PyRSS2Gen.RSSItem(
165 title = event.name,
166 link = url_base + event_path(event),
167 description = event.details,
168 guid = url_base + event_path(event),
169 pubDate = event.updated,
170 ) for event in events]
171 )
172 return 'application/xml', rss.to_xml()
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
173
f1997e4 @christopherb Made misc style fixes
christopherb authored
174
ca8c7f2 @dustball Let edit events and refactor error handling
dustball authored
175 class EditHandler(webapp.RequestHandler):
176 def get(self, id):
177 event = Event.get_by_id(int(id))
178 user = users.get_current_user()
736390e @dustball Bug fixes & UI
dustball authored
179 show_all_nav = user
ca8c7f2 @dustball Let edit events and refactor error handling
dustball authored
180 access_rights = UserRights(user, event)
181 if access_rights.can_edit:
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
182 logout_url = users.create_logout_url('/')
183 rooms = ROOM_OPTIONS
184 hours = [1,2,3,4,5,6,7,8,9,10,11,12]
185 self.response.out.write(template.render('templates/edit.html', locals()))
ca8c7f2 @dustball Let edit events and refactor error handling
dustball authored
186 else:
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
187 self.response.out.write("Access denied")
ca8c7f2 @dustball Let edit events and refactor error handling
dustball authored
188
189 def post(self, id):
190 event = Event.get_by_id(int(id))
191 user = users.get_current_user()
192 access_rights = UserRights(user, event)
193 if access_rights.can_edit:
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
194 try:
8aa7c21 patch edit screen.. changed datepicker formatting to be cohesive.. fi…
jonathan authored
195 start_time = datetime.strptime('%s %s:%s %s' % (
196 self.request.get('date'),
197 self.request.get('start_time_hour'),
198 self.request.get('start_time_minute'),
199 self.request.get('start_time_ampm')), '%m/%d/%Y %I:%M %p')
200 end_time = datetime.strptime('%s %s:%s %s' % (
201 self.request.get('date'),
202 self.request.get('end_time_hour'),
203 self.request.get('end_time_minute'),
204 self.request.get('end_time_ampm')), '%m/%d/%Y %I:%M %p')
20c252d @dustball Fix key/index bug
dustball authored
205 conflicts = Event.check_conflict(start_time,end_time,self.request.get_all('rooms'), int(id))
c97598b @dustball Room Conflict Detection
dustball authored
206 if conflicts:
81f76e6 @dustball Better error message for deck/savannah conflicts
dustball authored
207 if "Deck" in self.request.get_all('rooms') or "Savanna" in self.request.get_all('rooms'):
208 raise ValueError('Room conflict detected <small>(Note: Deck &amp; Savanna share the same area, two events cannot take place at the same time in these rooms.)</small>')
209 else:
210 raise ValueError('Room conflict detected')
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
211 if not self.request.get('estimated_size').isdigit():
212 raise ValueError('Estimated number of people must be a number')
213 if not int(self.request.get('estimated_size')) > 0:
214 raise ValueError('Estimated number of people must be greater then zero')
215 if ( self.request.get( 'contact_phone' ) and not is_phone_valid( self.request.get( 'contact_phone' ) ) ):
216 raise ValueError( 'Phone number does not appear to be valid' )
217 else:
b193624 much nicer event edit logs
jonathan authored
218 log_desc = "Event edited<br />"
8aa7c21 patch edit screen.. changed datepicker formatting to be cohesive.. fi…
jonathan authored
219 previous_object = Event.get_by_id(int(id))
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
220 event.name = self.request.get('name')
8aa7c21 patch edit screen.. changed datepicker formatting to be cohesive.. fi…
jonathan authored
221 if (previous_object.name != event.name):
a4f9ae7 changed my mind about the italics
jonathan authored
222 log_desc = log_desc + "<strong>Title:</strong> " + previous_object.name + " to " + event.name + "<br />"
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
223 event.start_time = start_time
8aa7c21 patch edit screen.. changed datepicker formatting to be cohesive.. fi…
jonathan authored
224 if (previous_object.start_time != event.start_time):
a4f9ae7 changed my mind about the italics
jonathan authored
225 log_desc = log_desc + "<strong>Start time:</strong> " + str(previous_object.start_time) + " to " + str(event.start_time) + "<br />"
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
226 event.end_time = end_time
8aa7c21 patch edit screen.. changed datepicker formatting to be cohesive.. fi…
jonathan authored
227 if (previous_object.end_time != event.end_time):
a4f9ae7 changed my mind about the italics
jonathan authored
228 log_desc = log_desc + "<strong>End time:</strong> " + str(previous_object.end_time) + " to " + str(event.end_time) + "<br />"
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
229 event.estimated_size = cgi.escape(self.request.get('estimated_size'))
8aa7c21 patch edit screen.. changed datepicker formatting to be cohesive.. fi…
jonathan authored
230 if (previous_object.estimated_size != event.estimated_size):
a4f9ae7 changed my mind about the italics
jonathan authored
231 log_desc = log_desc + "<strong>Est. size:</strong> " + previous_object.estimated_size + " to " + event.estimated_size + "<br />"
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
232 event.contact_name = cgi.escape(self.request.get('contact_name'))
8aa7c21 patch edit screen.. changed datepicker formatting to be cohesive.. fi…
jonathan authored
233 if (previous_object.contact_name != event.contact_name):
a4f9ae7 changed my mind about the italics
jonathan authored
234 log_desc = log_desc + "<strong>Contact:</strong> " + previous_object.contact_name + " to " + event.contact_name + "<br />"
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
235 event.contact_phone = cgi.escape(self.request.get('contact_phone'))
8aa7c21 patch edit screen.. changed datepicker formatting to be cohesive.. fi…
jonathan authored
236 if (previous_object.contact_phone != event.contact_phone):
a4f9ae7 changed my mind about the italics
jonathan authored
237 log_desc = log_desc + "<strong>Contact phone:</strong> " + previous_object.contact_phone + " to " + event.contact_phone + "<br />"
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
238 event.details = cgi.escape(self.request.get('details'))
8aa7c21 patch edit screen.. changed datepicker formatting to be cohesive.. fi…
jonathan authored
239 if (previous_object.details != event.details):
a4f9ae7 changed my mind about the italics
jonathan authored
240 log_desc = log_desc + "<strong>Details:</strong> " + previous_object.details + " to " + event.details + "<br />"
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
241 event.url = cgi.escape(self.request.get('url'))
8aa7c21 patch edit screen.. changed datepicker formatting to be cohesive.. fi…
jonathan authored
242 if (previous_object.url != event.url):
a4f9ae7 changed my mind about the italics
jonathan authored
243 log_desc = log_desc + "<strong>Url:</strong> " + previous_object.url + " to " + event.url + "<br />"
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
244 event.fee = cgi.escape(self.request.get('fee'))
8aa7c21 patch edit screen.. changed datepicker formatting to be cohesive.. fi…
jonathan authored
245 if (previous_object.fee != event.fee):
a4f9ae7 changed my mind about the italics
jonathan authored
246 log_desc = log_desc + "<strong>Fee:</strong> " + previous_object.fee + " to " + event.fee + "<br />"
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
247 event.notes = cgi.escape(self.request.get('notes'))
8aa7c21 patch edit screen.. changed datepicker formatting to be cohesive.. fi…
jonathan authored
248 if (previous_object.notes != event.notes):
a4f9ae7 changed my mind about the italics
jonathan authored
249 log_desc = log_desc + "<strong>Notes:</strong> " + previous_object.notes + " to " + event.notes + "<br />"
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
250 event.rooms = self.request.get_all('rooms')
8aa7c21 patch edit screen.. changed datepicker formatting to be cohesive.. fi…
jonathan authored
251 if (previous_object.rooms != event.rooms):
6199d1a issue 11 print this page for your record
jonathan authored
252 log_desc = log_desc + "<strong>Rooms changed</strong><br />"
f35ea58 patches requested to log
jonathan authored
253 log_desc = log_desc + "<strong>Old room:</strong> " + previous_object.roomlist() + "<br />"
254 log_desc = log_desc + "<strong>New room:</strong> " + event.roomlist() + "<br />"
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
255 event.put()
8aa7c21 patch edit screen.. changed datepicker formatting to be cohesive.. fi…
jonathan authored
256 log = HDLog(event=event,description=log_desc)
2ad290e @billsaysthis add logging model and obscure list view
billsaysthis authored
257 log.put()
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
258 self.redirect(event_path(event))
2ad290e @billsaysthis add logging model and obscure list view
billsaysthis authored
259 except ValueError, e:
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
260 error = str(e)
261 self.response.out.write(template.render('templates/error.html', locals()))
ca8c7f2 @dustball Let edit events and refactor error handling
dustball authored
262 else:
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
263 self.response.out.write("Access denied")
ca8c7f2 @dustball Let edit events and refactor error handling
dustball authored
264
265
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
266 class EventHandler(webapp.RequestHandler):
267 def get(self, id):
5ef05d9 @dustball RSVP system
dustball authored
268
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
269 event = Event.get_by_id(int(id))
2e08a66 @progrium cleaning things up and adding json representations for jon
progrium authored
270 if self.request.path.endswith('json'):
271 self.response.headers['content-type'] = 'application/json'
272 self.response.out.write(simplejson.dumps(event.to_dict()))
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
273 else:
2e08a66 @progrium cleaning things up and adding json representations for jon
progrium authored
274 user = users.get_current_user()
275 if user:
766e87c @christopherb Added UserRights class.
christopherb authored
276 access_rights = UserRights(user, event)
2e08a66 @progrium cleaning things up and adding json representations for jon
progrium authored
277 logout_url = users.create_logout_url('/')
766e87c @christopherb Added UserRights class.
christopherb authored
278
2e08a66 @progrium cleaning things up and adding json representations for jon
progrium authored
279 else:
280 login_url = users.create_login_url('/')
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
281 event.details = db.Text(event.details.replace('\n','<br/>'))
736390e @dustball Bug fixes & UI
dustball authored
282 show_all_nav = user
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
283 event.notes = db.Text(event.notes.replace('\n','<br/>'))
2e08a66 @progrium cleaning things up and adding json representations for jon
progrium authored
284 self.response.out.write(template.render('templates/event.html', locals()))
e2b9558 @btubbs Fixes issue 4. Changed to jqueryUI datepicker. Replaced jquery
btubbs authored
285
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
286 def post(self, id):
287 event = Event.get_by_id(int(id))
288 user = users.get_current_user()
766e87c @christopherb Added UserRights class.
christopherb authored
289 access_rights = UserRights(user, event)
290
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
291 state = self.request.get('state')
292 if state:
0eb5a92 @billsaysthis basic logging for all user-initiated post methods in place
billsaysthis authored
293 desc = ''
766e87c @christopherb Added UserRights class.
christopherb authored
294 if state.lower() == 'approve' and access_rights.can_approve:
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
295 event.approve()
0eb5a92 @billsaysthis basic logging for all user-initiated post methods in place
billsaysthis authored
296 desc = 'Approved event'
5ef05d9 @dustball RSVP system
dustball authored
297 if state.lower() == 'rsvp' and user:
298 event.rsvp()
b84b533 @dustball Fix one more staff logic bomb
dustball authored
299 if state.lower() == 'staff' and access_rights.can_staff:
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
300 event.add_staff(user)
0eb5a92 @billsaysthis basic logging for all user-initiated post methods in place
billsaysthis authored
301 desc = 'Added self as staff'
766e87c @christopherb Added UserRights class.
christopherb authored
302 if state.lower() == 'unstaff' and access_rights.can_unstaff:
72849c2 @billsaysthis added unstaff event, including email notification if event becomes un…
billsaysthis authored
303 event.remove_staff(user)
0eb5a92 @billsaysthis basic logging for all user-initiated post methods in place
billsaysthis authored
304 desc = 'Removed self as staff'
f8ffd89 @billsaysthis refactor lists to use singe event partial, adds contact email link in…
billsaysthis authored
305 if state.lower() == 'onhold' and access_rights.can_cancel:
306 event.on_hold()
307 desc = 'Put event on hold'
766e87c @christopherb Added UserRights class.
christopherb authored
308 if state.lower() == 'cancel' and access_rights.can_cancel:
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
309 event.cancel()
0eb5a92 @billsaysthis basic logging for all user-initiated post methods in place
billsaysthis authored
310 desc = 'Cancelled event'
766e87c @christopherb Added UserRights class.
christopherb authored
311 if state.lower() == 'delete' and access_rights.is_admin:
a67ac50 @mdhancher Add a simple admin-only event delete and undelete.
mdhancher authored
312 event.delete()
0eb5a92 @billsaysthis basic logging for all user-initiated post methods in place
billsaysthis authored
313 desc = 'Deleted event'
766e87c @christopherb Added UserRights class.
christopherb authored
314 if state.lower() == 'undelete' and access_rights.is_admin:
a67ac50 @mdhancher Add a simple admin-only event delete and undelete.
mdhancher authored
315 event.undelete()
0eb5a92 @billsaysthis basic logging for all user-initiated post methods in place
billsaysthis authored
316 desc = 'Undeleted event'
766e87c @christopherb Added UserRights class.
christopherb authored
317 if state.lower() == 'expire' and access_rights.is_admin:
47a7f7a @progrium basic form validation, added end time, start of notifications, some f…
progrium authored
318 event.expire()
0eb5a92 @billsaysthis basic logging for all user-initiated post methods in place
billsaysthis authored
319 desc = 'Expired event'
47a7f7a @progrium basic form validation, added end time, start of notifications, some f…
progrium authored
320 if event.status == 'approved':
321 notify_owner_approved(event)
0eb5a92 @billsaysthis basic logging for all user-initiated post methods in place
billsaysthis authored
322 if desc != '':
323 log = HDLog(event=event,description=desc)
324 log.put()
9f06c39 @casey Added RSS for upcoming events.
casey authored
325 self.redirect(event_path(event))
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
326
f1997e4 @christopherb Made misc style fixes
christopherb authored
327
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
328 class ApprovedHandler(webapp.RequestHandler):
329 def get(self):
330 user = users.get_current_user()
331 if user:
332 logout_url = users.create_logout_url('/')
333 else:
334 login_url = users.create_login_url('/')
b879063 @mdhancher Respect the local timezone (Pacific), and tidy up related imports.
mdhancher authored
335 today = local_today()
736390e @dustball Bug fixes & UI
dustball authored
336 show_all_nav = user
47a7f7a @progrium basic form validation, added end time, start of notifications, some f…
progrium authored
337 events = Event.get_approved_list()
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
338 tomorrow = today + timedelta(days=1)
d63161a Add widget mode
Brian Klug authored
339 whichbase = 'base.html'
340 if self.request.get('base'):
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
341 whichbase = self.request.get('base') + '.html'
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
342 self.response.out.write(template.render('templates/approved.html', locals()))
343
f1997e4 @christopherb Made misc style fixes
christopherb authored
344
a82b43e @billsaysthis add myevents, pastevents code, refined list display on event page
billsaysthis authored
345 class MyEventsHandler(webapp.RequestHandler):
346 @util.login_required
347 def get(self):
348 user = users.get_current_user()
349 if user:
350 logout_url = users.create_logout_url('/')
351 else:
352 login_url = users.create_login_url('/')
353 events = Event.all().filter('member = ', user).order('start_time')
736390e @dustball Bug fixes & UI
dustball authored
354 show_all_nav = user
b879063 @mdhancher Respect the local timezone (Pacific), and tidy up related imports.
mdhancher authored
355 today = local_today()
a82b43e @billsaysthis add myevents, pastevents code, refined list display on event page
billsaysthis authored
356 tomorrow = today + timedelta(days=1)
357 self.response.out.write(template.render('templates/myevents.html', locals()))
358
f1997e4 @christopherb Made misc style fixes
christopherb authored
359
a82b43e @billsaysthis add myevents, pastevents code, refined list display on event page
billsaysthis authored
360 class PastHandler(webapp.RequestHandler):
361 def get(self):
362 user = users.get_current_user()
363 if user:
364 logout_url = users.create_logout_url('/')
365 else:
366 login_url = users.create_login_url('/')
b879063 @mdhancher Respect the local timezone (Pacific), and tidy up related imports.
mdhancher authored
367 today = local_today()
736390e @dustball Bug fixes & UI
dustball authored
368 show_all_nav = user
d75579f @progrium minor updates here and there to bills contributions.
progrium authored
369 events = Event.all().filter('start_time < ', today).order('-start_time')
a82b43e @billsaysthis add myevents, pastevents code, refined list display on event page
billsaysthis authored
370 self.response.out.write(template.render('templates/past.html', locals()))
371
f1997e4 @christopherb Made misc style fixes
christopherb authored
372
b4ea292 Handler to bug pending events
Brian Klug authored
373 class CronBugOwnersHandler(webapp.RequestHandler):
374 def get(self):
375 events = Event.get_pending_list()
376 for e in events:
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
377 bug_owner_pending(e)
378
379
380 class AllFutureHandler(webapp.RequestHandler):
381 def get(self):
382 user = users.get_current_user()
383 if user:
384 logout_url = users.create_logout_url('/')
385 else:
386 login_url = users.create_login_url('/')
736390e @dustball Bug fixes & UI
dustball authored
387 show_all_nav = user
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
388 events = Event.get_all_future_list()
389 today = local_today()
390 tomorrow = today + timedelta(days=1)
391 self.response.out.write(template.render('templates/all_future.html', locals()))
b4ea292 Handler to bug pending events
Brian Klug authored
392
85d17af @dustball "Large Events" page and iCal feed
dustball authored
393 class LargeHandler(webapp.RequestHandler):
394 def get(self):
395 user = users.get_current_user()
396 if user:
397 logout_url = users.create_logout_url('/')
398 else:
399 login_url = users.create_login_url('/')
400 show_all_nav = user
401 events = Event.get_large_list()
402 today = local_today()
403 tomorrow = today + timedelta(days=1)
404 self.response.out.write(template.render('templates/large.html', locals()))
405
f1997e4 @christopherb Made misc style fixes
christopherb authored
406
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
407 class PendingHandler(webapp.RequestHandler):
408 def get(self):
409 user = users.get_current_user()
410 if user:
411 logout_url = users.create_logout_url('/')
412 else:
413 login_url = users.create_login_url('/')
47a7f7a @progrium basic form validation, added end time, start of notifications, some f…
progrium authored
414 events = Event.get_pending_list()
736390e @dustball Bug fixes & UI
dustball authored
415 show_all_nav = user
b879063 @mdhancher Respect the local timezone (Pacific), and tidy up related imports.
mdhancher authored
416 today = local_today()
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
417 tomorrow = today + timedelta(days=1)
418 self.response.out.write(template.render('templates/pending.html', locals()))
419
f1997e4 @christopherb Made misc style fixes
christopherb authored
420
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
421 class NewHandler(webapp.RequestHandler):
fcf7602 @progrium working approval process and ical view of approved events
progrium authored
422 @util.login_required
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
423 def get(self):
424 user = users.get_current_user()
4d85afa @dustball Remove staffing requirement and make members more responsible
dustball authored
425 human = human_username(user)
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
426 if user:
427 logout_url = users.create_logout_url('/')
428 else:
429 login_url = users.create_login_url('/')
430 rooms = ROOM_OPTIONS
cb7a9d1 pull in the rules live and memcache them for 1 day on new and confirm…
jonathan authored
431 rules = memcache.get("rules")
432 if(rules is None):
f35065d @dustball New wiki page
dustball authored
433 rules = urlfetch.fetch("http://wiki.hackerdojo.com/api_v2/op/GetPage/page/Event+Policies/_type/html", "GET").content
cb7a9d1 pull in the rules live and memcache them for 1 day on new and confirm…
jonathan authored
434 memcache.add("rules", rules, 86400)
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
435 self.response.out.write(template.render('templates/new.html', locals()))
e2b9558 @btubbs Fixes issue 4. Changed to jqueryUI datepicker. Replaced jquery
btubbs authored
436
f1997e4 @christopherb Made misc style fixes
christopherb authored
437
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
438 def post(self):
439 user = users.get_current_user()
7742592 @progrium start of maintaining form state on errors
progrium authored
440 try:
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
441 start_time = datetime.strptime('%s %s:%s %s' % (
7742592 @progrium start of maintaining form state on errors
progrium authored
442 self.request.get('date'),
443 self.request.get('start_time_hour'),
444 self.request.get('start_time_minute'),
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
445 self.request.get('start_time_ampm')), '%m/%d/%Y %I:%M %p')
446 end_time = datetime.strptime('%s %s:%s %s' % (
7742592 @progrium start of maintaining form state on errors
progrium authored
447 self.request.get('date'),
448 self.request.get('end_time_hour'),
449 self.request.get('end_time_minute'),
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
450 self.request.get('end_time_ampm')), '%m/%d/%Y %I:%M %p')
c97598b @dustball Room Conflict Detection
dustball authored
451 conflicts = Event.check_conflict(start_time,end_time,self.request.get_all('rooms'))
452 if conflicts:
81f76e6 @dustball Better error message for deck/savannah conflicts
dustball authored
453 if "Deck" in self.request.get_all('rooms') or "Savanna" in self.request.get_all('rooms'):
454 raise ValueError('Room conflict detected <small>(Note: Deck &amp; Savanna share the same area, two events cannot take place at the same time in these rooms.)</small>')
455 else:
456 raise ValueError('Room conflict detected')
8615877 Fix validation for event size
Brian Klug authored
457 if not self.request.get('estimated_size').isdigit():
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
458 raise ValueError('Estimated number of people must be a number')
8615877 Fix validation for event size
Brian Klug authored
459 if not int(self.request.get('estimated_size')) > 0:
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
460 raise ValueError('Estimated number of people must be greater then zero')
7742592 @progrium start of maintaining form state on errors
progrium authored
461 if (end_time-start_time).days < 0:
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
462 raise ValueError('End time must be after start time')
a244c65 @dustball Bug fixes
dustball authored
463 if ( self.request.get( 'contact_phone' ) and not is_phone_valid( self.request.get( 'contact_phone' ) ) ):
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
464 raise ValueError( 'Phone number does not appear to be valid' )
7742592 @progrium start of maintaining form state on errors
progrium authored
465 else:
466 event = Event(
ca3c6dd Escaped additional fields that could be used for XSS
Christopher Biettchert authored
467 name = cgi.escape(self.request.get('name')),
7742592 @progrium start of maintaining form state on errors
progrium authored
468 start_time = start_time,
469 end_time = end_time,
ca3c6dd Escaped additional fields that could be used for XSS
Christopher Biettchert authored
470 type = cgi.escape(self.request.get('type')),
471 estimated_size = cgi.escape(self.request.get('estimated_size')),
472 contact_name = cgi.escape(self.request.get('contact_name')),
473 contact_phone = cgi.escape(self.request.get('contact_phone')),
8414350 @billsaysthis multiline for details and notes fields
billsaysthis authored
474 details = cgi.escape(self.request.get('details')),
ca3c6dd Escaped additional fields that could be used for XSS
Christopher Biettchert authored
475 url = cgi.escape(self.request.get('url')),
476 fee = cgi.escape(self.request.get('fee')),
8414350 @billsaysthis multiline for details and notes fields
billsaysthis authored
477 notes = cgi.escape(self.request.get('notes')),
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
478 rooms = self.request.get_all('rooms'),
b879063 @mdhancher Respect the local timezone (Pacific), and tidy up related imports.
mdhancher authored
479 expired = local_today() + timedelta(days=PENDING_LIFETIME), # Set expected expiration date
7742592 @progrium start of maintaining form state on errors
progrium authored
480 )
481 event.put()
0eb5a92 @billsaysthis basic logging for all user-initiated post methods in place
billsaysthis authored
482 log = HDLog(event=event,description="Created new event")
483 log.put()
7742592 @progrium start of maintaining form state on errors
progrium authored
484 notify_owner_confirmation(event)
485 notify_new_event(event)
81a81e1 @progrium adding errors for form validation, full notifications, and minor edit…
progrium authored
486 set_cookie(self.response.headers, 'formvalues', None)
87868cf issue 11 add a confirmation page
jonathan authored
487 #self.redirect('/event/%s-%s' % (event.key().id(), slugify(event.name)))
488 self.redirect('/confirm/%s-%s' % (event.key().id(), slugify(event.name)))
489
81a81e1 @progrium adding errors for form validation, full notifications, and minor edit…
progrium authored
490 except Exception, e:
491 message = str(e)
492 if 'match format' in message:
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
493 message = 'Date is required.'
81a81e1 @progrium adding errors for form validation, full notifications, and minor edit…
progrium authored
494 if message.startswith('Property'):
495 message = message[9:].replace('_', ' ').capitalize()
ca8c7f2 @dustball Let edit events and refactor error handling
dustball authored
496 # This is NOT a reliable way to handle erorrs
497 #set_cookie(self.response.headers, 'formerror', message)
498 #set_cookie(self.response.headers, 'formvalues', dict(self.request.POST))
499 #self.redirect('/new')
500 error = message
501 self.response.out.write(template.render('templates/error.html', locals()))
87868cf issue 11 add a confirmation page
jonathan authored
502
503 class ConfirmationHandler(webapp.RequestHandler):
504 def get(self, id):
505 event = Event.get_by_id(int(id))
cb7a9d1 pull in the rules live and memcache them for 1 day on new and confirm…
jonathan authored
506 rules = memcache.get("rules")
507 if(rules is None):
f35065d @dustball New wiki page
dustball authored
508 rules = urlfetch.fetch("http://wiki.hackerdojo.com/api_v2/op/GetPage/page/Event+Policies/_type/html", "GET").content
cb7a9d1 pull in the rules live and memcache them for 1 day on new and confirm…
jonathan authored
509 memcache.add("rules", rules, 86400)
87868cf issue 11 add a confirmation page
jonathan authored
510 self.response.out.write(template.render('templates/confirmation.html', locals()))
511
2ad290e @billsaysthis add logging model and obscure list view
billsaysthis authored
512 class LogsHandler(webapp.RequestHandler):
513 @util.login_required
514 def get(self):
515 user = users.get_current_user()
516 logs = HDLog.get_logs_list()
517 if user:
518 logout_url = users.create_logout_url('/')
519 else:
520 login_url = users.create_login_url('/')
736390e @dustball Bug fixes & UI
dustball authored
521 show_all_nav = user
2ad290e @billsaysthis add logging model and obscure list view
billsaysthis authored
522 self.response.out.write(template.render('templates/logs.html', locals()))
523
d2c3dc7 @billsaysthis moved app-specific js to separate file
billsaysthis authored
524 class FeedbackHandler(webapp.RequestHandler):
525 @util.login_required
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
526 def get(self, id):
d2c3dc7 @billsaysthis moved app-specific js to separate file
billsaysthis authored
527 user = users.get_current_user()
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
528 event = Event.get_by_id(int(id))
d2c3dc7 @billsaysthis moved app-specific js to separate file
billsaysthis authored
529 if user:
530 logout_url = users.create_logout_url('/')
531 else:
532 login_url = users.create_login_url('/')
533 self.response.out.write(template.render('templates/feedback.html', locals()))
534
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
535 def post(self, id):
d2c3dc7 @billsaysthis moved app-specific js to separate file
billsaysthis authored
536 user = users.get_current_user()
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
537 event = Event.get_by_id(int(id))
8c52522 @billsaysthis small tweak to how feedbacks displayed in event page
billsaysthis authored
538 try:
539 if self.request.get('rating'):
540 feedback = Feedback(
541 event = event,
542 rating = int(self.request.get('rating')),
ca3c6dd Escaped additional fields that could be used for XSS
Christopher Biettchert authored
543 comment = cgi.escape(self.request.get('comment')))
8c52522 @billsaysthis small tweak to how feedbacks displayed in event page
billsaysthis authored
544 feedback.put()
0eb5a92 @billsaysthis basic logging for all user-initiated post methods in place
billsaysthis authored
545 log = HDLog(event=event,description="Posted feedback")
546 log.put()
8c52522 @billsaysthis small tweak to how feedbacks displayed in event page
billsaysthis authored
547 self.redirect('/event/%s-%s' % (event.key().id(), slugify(event.name)))
548 else:
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
549 raise ValueError('Please select a rating')
8c52522 @billsaysthis small tweak to how feedbacks displayed in event page
billsaysthis authored
550 except Exception:
551 set_cookie(self.response.headers, 'formvalues', dict(self.request.POST))
7ebb2cd @christopherb Cleaned up the style of the files some. Mostly standardizing on singl…
christopherb authored
552 self.redirect('/feedback/new/' + id)
d2c3dc7 @billsaysthis moved app-specific js to separate file
billsaysthis authored
553
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
554 def main():
555 application = webapp.WSGIApplication([
556 ('/', ApprovedHandler),
4c7da5d @billsaysthis added func to ensure word 'in' only shown when rooms are assigned
billsaysthis authored
557 ('/all_future', AllFutureHandler),
85d17af @dustball "Large Events" page and iCal feed
dustball authored
558 ('/large', LargeHandler),
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
559 ('/pending', PendingHandler),
841fefb added meaningful descriptions to ical events.
Stig Hackvan authored
560 ('/past', PastHandler),
b4ea292 Handler to bug pending events
Brian Klug authored
561 ('/cronbugowners', CronBugOwnersHandler),
a82b43e @billsaysthis add myevents, pastevents code, refined list display on event page
billsaysthis authored
562 ('/myevents', MyEventsHandler),
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
563 ('/new', NewHandler),
87868cf issue 11 add a confirmation page
jonathan authored
564 ('/confirm/(\d+).*', ConfirmationHandler),
ca8c7f2 @dustball Let edit events and refactor error handling
dustball authored
565 ('/edit/(\d+).*', EditHandler),
841fefb added meaningful descriptions to ical events.
Stig Hackvan authored
566 # single event views
47a7f7a @progrium basic form validation, added end time, start of notifications, some f…
progrium authored
567 ('/event/(\d+).*', EventHandler),
2e08a66 @progrium cleaning things up and adding json representations for jon
progrium authored
568 ('/event/(\d+)\.json', EventHandler),
841fefb added meaningful descriptions to ical events.
Stig Hackvan authored
569 # various export methods -- events.{json,rss,ics}
570 ('/events\.(.+)', ExportHandler),
571 #
572 # CRON tasks
47a7f7a @progrium basic form validation, added end time, start of notifications, some f…
progrium authored
573 ('/expire', ExpireCron),
34d98f0 @billsaysthis moved feedback stuff to separate py file, small tweak to email notifi…
billsaysthis authored
574 ('/expiring', ExpireReminderCron),
219203b @dustball Cache better
dustball authored
575 ('/domaincache', DomainCacheCron),
f49797a @dustball Reminders 2.0
dustball authored
576 ('/reminder', ReminderCron),
841fefb added meaningful descriptions to ical events.
Stig Hackvan authored
577 #
2ad290e @billsaysthis add logging model and obscure list view
billsaysthis authored
578 ('/logs', LogsHandler),
d2c3dc7 @billsaysthis moved app-specific js to separate file
billsaysthis authored
579 ('/feedback/new/(\d+).*', FeedbackHandler) ],debug=True)
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
580 util.run_wsgi_app(application)
581
f1997e4 @christopherb Made misc style fixes
christopherb authored
582
9b632dd @progrium initial commit -- basic form, rough listing
progrium authored
583 if __name__ == '__main__':
584 main()
Something went wrong with that request. Please try again.