Adding Not Approved status for events #42

Merged
merged 1 commit into from Nov 26, 2011
View
85 main.py
@@ -24,20 +24,20 @@ def event_path(event):
return '/event/%s-%s' % (event.key().id(), slugify(event.name))
class DomainCacheCron(webapp.RequestHandler):
- def post(self):
+ def post(self):
noop = dojo('/groups/events',force=True)
class ReminderCron(webapp.RequestHandler):
- def post(self):
+ def post(self):
self.response.out.write("REMINDERS")
today = local_today()
# remind everyone 3 days in advance they need to show up
events = Event.all() \
.filter('status IN', ['approved']) \
.filter('reminded =', False) \
.filter('start_time <', today + timedelta(days=3))
- for event in events:
+ for event in events:
self.response.out.write(event.name)
# only mail them if they created the event 2+ days ago
if event.created < today - timedelta(days=2):
@@ -57,7 +57,7 @@ def post(self):
for event in events:
event.expire()
notify_owner_expired(event)
-
+
class ExpireReminderCron(webapp.RequestHandler):
def post(self):
@@ -75,7 +75,7 @@ def get(self, format):
content_type, body = getattr(self, 'export_%s' % format)()
self.response.headers['content-type'] = content_type
self.response.out.write(body)
-
+
def export_json(self):
events = Event.get_recent_past_and_future()
for k in self.request.GET:
@@ -86,7 +86,7 @@ def export_json(self):
events = events.filter('%s =' % k, value)
events = map(lambda x: x.to_dict(summarize=True), events)
return 'application/json', simplejson.dumps(events)
-
+
def export_ics(self):
events = Event.get_recent_past_and_future()
url_base = 'http://' + self.request.headers.get('host', 'events.hackerdojo.com')
@@ -96,16 +96,16 @@ def export_ics(self):
iev.add('summary', event.name if event.status == 'approved' else event.name + ' (%s)' % event.status.upper())
# make verbose description with empty fields where information is missing
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' % (
- event.status,
- event.owner(),
- event.type,
- event.estimated_size,
- event.url,
- event.fee,
- event.contact_name,
- event.contact_phone,
- event.roomlist(),
- event.details,
+ event.status,
+ event.owner(),
+ event.type,
+ event.estimated_size,
+ event.url,
+ event.fee,
+ event.contact_name,
+ event.contact_phone,
+ event.roomlist(),
+ event.details,
event.notes)
# then delete the empty fields with a regex
ev_desc = re.sub(re.compile(r'^__.*?:[ ,]*$\n*',re.M),'',ev_desc)
@@ -129,16 +129,16 @@ def export_large_ics(self):
iev.add('summary', event.name + ' (%s)' % event.estimated_size)
# make verbose description with empty fields where information is missing
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' % (
- event.status,
- event.owner(),
- event.type,
- event.estimated_size,
- event.url,
- event.fee,
- event.contact_name,
- event.contact_phone,
- event.roomlist(),
- event.details,
+ event.status,
+ event.owner(),
+ event.type,
+ event.estimated_size,
+ event.url,
+ event.fee,
+ event.contact_name,
+ event.contact_phone,
+ event.roomlist(),
+ event.details,
event.notes)
# then delete the empty fields with a regex
ev_desc = re.sub(re.compile(r'^__.*?:[ ,]*$\n*',re.M),'',ev_desc)
@@ -152,7 +152,7 @@ def export_large_ics(self):
iev.add('dtend', event.end_time.replace(tzinfo=pytz.timezone('US/Pacific')))
cal.add_component(iev)
return 'text/calendar', cal.as_string()
-
+
def export_rss(self):
url_base = 'http://' + self.request.headers.get('host', 'events.hackerdojo.com')
events = Event.get_recent_past_and_future()
@@ -179,7 +179,7 @@ def get(self, id):
show_all_nav = user
access_rights = UserRights(user, event)
if access_rights.can_edit:
- logout_url = users.create_logout_url('/')
+ logout_url = users.create_logout_url('/')
rooms = ROOM_OPTIONS
hours = [1,2,3,4,5,6,7,8,9,10,11,12]
self.response.out.write(template.render('templates/edit.html', locals()))
@@ -265,7 +265,7 @@ def post(self, id):
class EventHandler(webapp.RequestHandler):
def get(self, id):
-
+
event = Event.get_by_id(int(id))
if self.request.path.endswith('json'):
self.response.headers['content-type'] = 'application/json'
@@ -275,7 +275,7 @@ def get(self, id):
if user:
access_rights = UserRights(user, event)
logout_url = users.create_logout_url('/')
-
+
else:
login_url = users.create_login_url('/')
event.details = db.Text(event.details.replace('\n','<br/>'))
@@ -294,6 +294,9 @@ def post(self, id):
if state.lower() == 'approve' and access_rights.can_approve:
event.approve()
desc = 'Approved event'
+ if state.lower() == 'notapproved' and access_rights.can_not_approve:
+ event.not_approved()
+ desc = 'Event marked not approved'
if state.lower() == 'rsvp' and user:
event.rsvp()
notify_owner_rsvp(event,user)
@@ -371,6 +374,19 @@ def get(self):
self.response.out.write(template.render('templates/past.html', locals()))
+class NotApprovedHandler(webapp.RequestHandler):
+ def get(self):
+ user = users.get_current_user()
+ if user:
+ logout_url = users.create_logout_url('/')
+ else:
+ login_url = users.create_login_url('/')
+ today = local_today()
+ show_all_nav = user
+ events = Event.get_recent_not_approved_list()
+ self.response.out.write(template.render('templates/not_approved.html', locals()))
+
+
class CronBugOwnersHandler(webapp.RequestHandler):
def get(self):
events = Event.get_pending_list()
@@ -431,7 +447,7 @@ def get(self):
rooms = ROOM_OPTIONS
rules = memcache.get("rules")
if(rules is None):
- rules = urlfetch.fetch("http://wiki.hackerdojo.com/api_v2/op/GetPage/page/Event+Policies/_type/html", "GET").content
+ rules = urlfetch.fetch("http://wiki.hackerdojo.com/api_v2/op/GetPage/page/Event+Policies/_type/html", "GET").content
memcache.add("rules", rules, 86400)
self.response.out.write(template.render('templates/new.html', locals()))
@@ -487,7 +503,7 @@ def post(self):
set_cookie(self.response.headers, 'formvalues', None)
#self.redirect('/event/%s-%s' % (event.key().id(), slugify(event.name)))
self.redirect('/confirm/%s-%s' % (event.key().id(), slugify(event.name)))
-
+
except Exception, e:
message = str(e)
if 'match format' in message:
@@ -506,7 +522,7 @@ def get(self, id):
event = Event.get_by_id(int(id))
rules = memcache.get("rules")
if(rules is None):
- rules = urlfetch.fetch("http://wiki.hackerdojo.com/api_v2/op/GetPage/page/Event+Policies/_type/html", "GET").content
+ rules = urlfetch.fetch("http://wiki.hackerdojo.com/api_v2/op/GetPage/page/Event+Policies/_type/html", "GET").content
memcache.add("rules", rules, 86400)
self.response.out.write(template.render('templates/confirmation.html', locals()))
@@ -561,6 +577,7 @@ def main():
('/past', PastHandler),
('/cronbugowners', CronBugOwnersHandler),
('/myevents', MyEventsHandler),
+ ('/not_approved', NotApprovedHandler),
('/new', NewHandler),
('/confirm/(\d+).*', ConfirmationHandler),
('/edit/(\d+).*', EditHandler),
@@ -573,7 +590,7 @@ def main():
# CRON tasks
('/expire', ExpireCron),
('/expiring', ExpireReminderCron),
- ('/domaincache', DomainCacheCron),
+ ('/domaincache', DomainCacheCron),
('/reminder', ReminderCron),
#
('/logs', LogsHandler),
View
@@ -19,7 +19,7 @@
class Event(db.Model):
status = db.StringProperty(required=True, default='pending', choices=set(
- ['pending', 'understaffed', 'approved', 'canceled', 'onhold', 'expired', 'deleted']))
+ ['pending', 'understaffed', 'approved', 'not_approved', 'canceled', 'onhold', 'expired', 'deleted']))
member = db.UserProperty(auto_current_user_add=True)
name = db.StringProperty(required=True)
start_time = db.DateTimeProperty(required=True)
@@ -66,7 +66,7 @@ def check_conflict(cls,proposed_start_time,proposed_end_time,proposed_rooms,opti
def get_all_future_list(cls):
return cls.all() \
.filter('start_time >', local_today()) \
- .filter('status IN', ['approved', 'canceled', 'pending', 'onhold']) \
+ .filter('status IN', ['approved', 'not_approved', 'canceled', 'pending', 'onhold']) \
.order('start_time')
@classmethod
@@ -77,7 +77,7 @@ def get_large_list(cls):
if int(e.estimated_size) >= 50:
large_list.append(e)
return large_list
-
+
@classmethod
def get_approved_list(cls):
return cls.all() \
@@ -99,9 +99,17 @@ def get_pending_list(cls):
.filter('status IN', ['pending', 'understaffed', 'onhold', 'expired']) \
.order('start_time')
+ @classmethod
+ # show last 60 days and all future not approved events
+ def get_recent_not_approved_list(cls):
+ return cls.all() \
+ .filter('start_time >', local_today() - timedelta(days=60)) \
+ .filter('status IN', ['not_approved']) \
+ .order('start_time')
+
def owner(self):
return human_username(self.member)
-
+
def stafflist(self):
return to_sentence_list(map(human_username, self.staff))
@@ -113,7 +121,7 @@ def roomlist_as_phrase(self):
return "in " + self.roomlist()
else:
return ""
-
+
def is_staffed(self):
return len(self.staff) >= self.staff_needed()
@@ -142,6 +150,9 @@ def is_deleted(self):
def is_past(self):
return self.end_time < local_today()
+ def is_not_approved(self):
+ return self.status == 'not_approved'
+
def start_date(self):
return self.start_time.date()
@@ -175,10 +186,10 @@ def has_rsvped(self):
def can_rsvp(self):
if self.has_rsvped():
return False
- time_till_event = self.start_time.replace(tzinfo=pytz.timezone('US/Pacific')) - datetime.now(pytz.timezone('US/Pacific'))
+ time_till_event = self.start_time.replace(tzinfo=pytz.timezone('US/Pacific')) - datetime.now(pytz.timezone('US/Pacific'))
hours = time_till_event.seconds/3600+time_till_event.days*24
return (hours > 48)
-
+
def cancel(self):
user = users.get_current_user()
self.status = 'canceled'
@@ -191,6 +202,12 @@ def on_hold(self):
self.put()
logging.info('%s put %s on hold' % (user.nickname, self.name))
+ def not_approved(self):
+ user = users.get_current_user()
+ self.status = 'not_approved'
+ self.put()
+ logging.info('%s not_approved %s' % (user.nickname, self.name))
+
def delete(self):
user = users.get_current_user()
self.status = 'deleted'
View
@@ -9,10 +9,11 @@
{% if event.is_deleted %}
{% if access_rights.is_admin %}<input type="submit" name="state" value="Undelete" />{% endif %}
(This will return the event to the &ldquo;pending&rdquo; status.)
- {% else %}
+ {% else %}
<div id="edit-approve-btns">
{% if access_rights.can_cancel and not event.is_onhold %}<input type="submit" name="state" value="OnHold" />{% endif %}
{% if access_rights.can_approve %}<input type="submit" name="state" value="Approve" />{% endif %}
+ {% if access_rights.can_not_approve %}<input type="submit" name="state" value="NotApproved" />{% endif %}
{% if access_rights.can_edit %}<input type="button" value="Edit" onclick="document.location.href='/edit/{{event.key.id}}';" />{% endif %}
</div>
<div id="cancel-delete-btns">
@@ -32,7 +33,7 @@
<span style="color: red; font-weight: bold">This event is not yet visible.</span><br/>
This event will not appear on the public calendar until it has been approved. If this does not happen soon, contact <a href="email:events@hackerdojo.com">events@hackerdojo.com</a> for assistance.
</p>{% endif %}{% endif %}
-
+
<div class='b-block'><div class='b-label'>Status:</div><div class='b-data'>{{event.status|title}}</div></div>
<div class='b-block'><div class='b-label'>Date:</div><div class='b-data'>{{event.start_time|date:"l, F j Y"}}</div></div>
<div class='b-block'><div class='b-label'>Time:</div><div class='b-data'>{{event.start_time|date:"g:iA"|lower}} to {{event.end_time|date:"g:iA"|lower}}</div></div>
@@ -41,7 +42,7 @@
<div class='b-block'><div class='b-label'>Estimated size:</div><div class='b-data'>{{event.estimated_size}}</div></div>
{% if event.contact_name %}
<div class='b-block'><div class='b-label'>Contact:</div><div class='b-data'>{{event.contact_name}}{% if user %}, {{event.contact_phone}}{% endif %}</div></div>
- {% endif %}
+ {% endif %}
<div class='b-block'><div class='b-label'>URL:</div><div class='b-data'><a href='{{event.url}}'>{{event.url}}</a></div></div>
<div class='b-block'><div class='b-label'>Fee:</div><div class='b-data'>{{event.fee}}</div></div>
<div class='b-block'><div class='b-label'>Rooms:</div><div class='b-data'>{{event.roomlist}}</div></div>
@@ -64,28 +65,28 @@
{% endif %}
{% ifequal event.status 'approved' %}
<br/>
- <div class='thin-border'></div>
+ <div class='thin-border'></div>
<form method="post" style="display: inline;">
<h4 style="margin-top:0; margin-bottom:1em">Member RSVP</h4>
{% if user and event.can_rsvp %}
<input type="submit" name="state" value="RSVP" />
{% endif %}
-
+
</form>
-
+
<p>Hacker Dojo members may {% if not user %} <a href="{{login_url}}">login</a> to {% endif %} reserve space in the event room up to 48 hours before the event.</p>
<p>Member RSVP does not imply event registration if applicable.</p>
-
+
{% if user and event.rsvps.count %}
<hr size=1>
<p>The following members have RSVPed:</p>
<ol>
{% for rsvp in event.rsvps %}
<li>{{ rsvp.user }}</li>
- {% endfor %}
+ {% endfor %}
</ol>
- {% endif %}
-
+ {% endif %}
+
{% endifequal %}
</div>
@@ -0,0 +1,20 @@
+{% extends 'base.html' %}
+{% block content %}
+
+<div id="primary">
+ <h3>Not Approved Events</h3>
+ <a href="/" style="font-size: smaller; margin-top: -20px; display: block;">&larr; Upcoming Events</a>
+
+ {% regroup events by start_date as grouped_events %}
+ {% for events in grouped_events %}
+ <h4>{% ifequal events.grouper today.date %}<span style="text-decoration:underline;">Today</span> - {% endifequal %}{{events.grouper|date:"l, F j"}}</h4>
+ <table>
+ {% for event in events.list %}
+ {% include 'list_event.html' %}
+ {% endfor %}
+ </table>
+ {% endfor %}
+</div>
+
+
+{% endblock %}
Oops, something went wrong.