Skip to content
Browse files

rideshare backend functional mostly

  • Loading branch information...
1 parent 86d14aa commit ce8cbd69d0d6707659a78e818b0494008a59bf10 @thirtyseven thirtyseven committed Oct 3, 2011
View
23 occupywallst/api.py
@@ -33,7 +33,7 @@
"""
import re
-from datetime import datetime
+from datetime import datetime, date
from django.conf import settings
from django.contrib import auth
@@ -86,14 +86,31 @@ def rides(bounds=None, **kwargs):
bbox = _str_to_bbox(bounds)
qset = (db.Ride.objects
.filter(route__isnull=False,
- route__bboverlaps=bbox))
+ route__bboverlaps=bbox,
+ depart_time__gte=date.today()))
else:
qset = (db.Ride.objects
.filter(route__isnull=False))
for ride in qset:
- yield {'id': ride.user.id,
+ yield {'id': ride.id,
'route': ride.route}
+def ride_request_update(request_id, status, user=None, **kwargs):
+ ride_request = (db.RideRequest.objects.filter(id=request_id)
+ .select_related("ride","ride__user"))
+ try:
+ req = ride_request[0]
+ except IndexError:
+ raise APIException("Request not found.")
+ if req.ride.user == user:
+ req.status=status
+ req.save()
+ return [{"id": req.id, "status": req.status }]
+ else:
+ raise APIException("You do not have permission to update this request.")
+
+
+
def attendee_info(username, **kwargs):
"""Get information for displaying attendee bubble
View
14 occupywallst/forms.py
@@ -8,6 +8,7 @@
"""
from django import forms
+from django.forms.models import modelformset_factory
from occupywallst import models as db
@@ -141,5 +142,14 @@ def save(self):
class RideForm(forms.ModelForm):
class Meta:
model = db.Ride
- exclude = ['seats_used', 'route', 'route_data',]
-
+ exclude = ['seats_used', 'route', 'route_data', 'forum_post']
+
+class RideRequestForm(forms.Form):
+ info = forms.CharField(help_text="Want a seat? Tell us about yourself.",
+ widget=forms.widgets.Textarea)
+ def save(self, user, ride):
+ ride_request = db.RideRequest(user=user,ride=ride)
+ ride_request.status = "pending"
+ ride_request.info = self.cleaned_data['info']
+ ride_request.save()
+ return ride_request
View
1 occupywallst/media/css/occupywallst.css
@@ -250,3 +250,4 @@ a.button:active {
#sql-info .item:first-child { border-top: none; }
#sql-info .item p { margin: 0; padding: 0; text-indent: -3em; margin-left: 3em;
font: 8pt "DeJavu Sans Mono", monospace; }
+#mapright { width: 600px; font-size: 0.9em; vertical-align: top; }
View
64 occupywallst/media/js/occupywallst/rides.js
@@ -7,11 +7,40 @@ var rides_init;
var map;
var dserv;
var markers = [];
+ var lines = {}
+ var current_line = null;
var philadelphia;
- $("#add_link").click(function() {
- $("#add_ride").toggle(100);
- return false;
+ function clear_map() {
+ $.each(lines, function(i, e) {
+ console.log(e);
+ e.setMap(null);
+ });
+ $.each(markers, function(i, e) {
+ e.setMap(null);
+ });
+ if (current_line) {
+ current_line.setMap(null);
+ }
+ markers = [];
+ lines = {}
+
+ }
+
+ $("form select[name='status']").change(function() {
+ var option = $(this).val();
+ var form = $(this).parent();
+ $.post(form.attr('action'), form.serialize(), function() {
+ var status = form.parent().parent().find(".req-status");
+ });
+ });
+
+ $("#id_waypoints").change(function() {
+ clear_map();
+ var waypoints = $(this).val().split("\n");
+ if (waypoints.length > 1) {
+ show_route(waypoints);
+ }
});
function init(args) {
@@ -25,7 +54,20 @@ var rides_init;
zoomControl: true,
scaleControl: true
});
- google.maps.event.addListener(map, "idle", update_rides);
+ if (args.update_rides) {
+ google.maps.event.addListener(map, "idle", update_rides);
+ }
+ if (args.initial_polyline) {
+ var bounds = new google.maps.LatLngBounds();
+ var polyline_arr = args.initial_polyline.map(function(e) {
+ var latlng = new google.maps.LatLng(e[0],e[1]);
+ bounds.extend(latlng);
+ return latlng;
+ })
+ var polyline = happy_line(polyline_arr);
+ map.fitBounds(bounds);
+
+ }
// $("#addroute").click(function() {
// ev.preventDefault();
// show_route($("textarea").val().split('\n'));
@@ -37,12 +79,17 @@ var rides_init;
var bounds = { bounds: map.getBounds().toUrlValue() };
$.getJSON("/api/safe/rides/", bounds, function(rides) {
+ clear_map();
rides.results.forEach(function(ride, i) {
- console.log(ride) ;
- happy_line(ride.route.map(function(p) {
+ var line = happy_line(ride.route.map(function(p) {
var point = new google.maps.LatLng(p[1],p[0]);
return point;
}));
+ google.maps.event.addListener(line, 'click', function(e) {
+ window.location = "/rides/"+ride.id+"/";
+ });
+ lines[ride.id]=line;
+ console.log(line);
});
});
}
@@ -75,7 +122,7 @@ var rides_init;
return line;
}
- function show_route(waypoints) {
+ function show_route(waypoints, info) {
var i;
var from = waypoints[0];
var to = waypoints[waypoints.length - 1];
@@ -99,8 +146,9 @@ var rides_init;
return;
}
var line = happy_line(result.routes[0].overview_path);
+ current_line = line;
google.maps.event.addListener(line, 'click', function(e) {
- var balloon = new google.maps.InfoWindow({content: 'we\'re driving from ' + from + '<br /> so you should carpool with us :3'});
+ var balloon = new google.maps.InfoWindow({content: info});
balloon.open(map, new google.maps.Marker({position: e.latLng}));
});
// if (glob.bounds) {
View
53 occupywallst/models.py
@@ -22,8 +22,9 @@
from django.contrib.gis.geos import Point, LineString
from django.contrib.auth.models import User, Group
from django.core.exceptions import ValidationError
-from django.db.models import F
-from django.db import transaction
+from django.db.models.signals import post_save
+from django.dispatch import receiver
+from django.template.defaultfilters import slugify
from occupywallst.utils import jsonify
from occupywallst import geo
@@ -572,6 +573,7 @@ class Ride(models.Model):
Google's goofy compressed version of route coords.""")
info = models.TextField(blank=True, help_text="""
A long description written by user in markup.""")
+ forum_post = models.ForeignKey(ForumPost, null=True, blank=True)
is_deleted = models.BooleanField(default=False, editable=False,
help_text="""
Flag to indicate should no longer be listed on site.""")
@@ -595,12 +597,25 @@ def clean(self):
if len(self.waypoint_list) < 2:
raise ValidationError('Must have at least two waypoints')
- def update_from_maps(self):
+ @property
+ def pending_requests(self):
+ return self.requests.filter(status="pending")
+
+ @property
+ def accepted_requests(self):
+ return self.requests.filter(status="accepted")
+
+ def forum_title(self):
+ waypoints = self.waypoint_list
+ return "%s to %s on %s" % (
+ waypoints[0], waypoints[-1], self.depart_time.date())
+
+ def retrieve_route_from_google(self):
route = geo.directions(self.waypoint_list)
points = []
for waypoint in route:
points += \
- [ p[::-1] for p in waypoint['overview_polyline']['points']]
+ [ (x,y) for y,x in waypoint['overview_polyline']['points']]
self.route = LineString(points)
@property
@@ -609,7 +624,22 @@ def waypoint_list(self):
@property
def seats_avail(self):
- return self.seats_total - self.seats_used
+ return self.seats_total - self.accepted_requests.count()
+
+ @models.permalink
+ def get_absolute_url(self):
+ return ('occupywallst.views.ride_info', [self.id])
+
+
+@receiver(post_save, sender=Ride)
+def ride_save_callback(sender, instance, created, *args, **kwargs):
+ if created:
+ post = ForumPost(title=instance.forum_title(), author=instance.user)
+ post.slug = ("ride-%s-%s"
+ % (instance.user.username, slugify(instance.title)))
+ post.save()
+ instance.forum_post = post
+ instance.save()
class RideRequest(models.Model):
@@ -623,13 +653,13 @@ class RideRequest(models.Model):
('rejected', 'Rejected'),
)
- ride = models.ForeignKey(Ride, editable=False, unique=True,
+ ride = models.ForeignKey(Ride, editable=False,
related_name="requests", help_text="""
The ride the user wants to get in on.""")
- user = models.ForeignKey(User, editable=False, unique=True, help_text="""
+ user = models.ForeignKey(User, help_text="""
The user who needs a ride to the event.""")
status = models.CharField(max_length=32, choices=STATUS_CHOICES,
- help_text="""
+ default="pending", help_text="""
Current acceptance status of request.""")
info = models.TextField(blank=True, help_text="""
User explains why they think they deserve a ride.""")
@@ -639,6 +669,13 @@ class RideRequest(models.Model):
objects = models.GeoManager()
+ @property
+ def accepted(self):
+ return self.status=="accepted"
+ @property
+ def declined(self):
+ return self.status=="declined"
+
class Meta:
unique_together = ("ride", "user")
View
118 occupywallst/templates/occupywallst/ride_info.html
@@ -0,0 +1,118 @@
+{% extends base %}
+{% load ows %}
+
+{% block title %}Free Bus/Carpool Route Map | OccupyWallSt.org{% endblock title %}
+
+{% block stylesheets %}
+ <style type="text/css">
+ #navbar .nav-rides { background: #900; }
+ </style>
+{% endblock stylesheets %}
+
+{% block scripts %}
+ <script src="//maps.google.com/maps/api/js?sensor=false&region=us" type="text/javascript"></script>
+ <script src="//maps.google.com/maps/api/js?libraries=places&sensor=false&region=us" type="text/javascript"></script>
+{% endblock scripts %}
+
+{% block js_init %}
+ {{ block.super }}
+ rides_init({
+ "map": document.getElementById("map"),
+ "center": new google.maps.LatLng(40.717712644386026, -74.00913921356198),
+ "zoom": 8,
+ "initial_polyline": [{% for point in ride.route %}[{{point.1}},{{point.0}}],{%endfor%}]
+ });
+ article_init();
+
+{% endblock js_init %}
+
+{% block content %}
+<table><tbody><tr><td id="left">
+ <h1>Info for {{ ride.title }}</h1>
+ {% if user == ride.user %}
+ <a href="{% url ride_edit ride.id %}">edit</a>
+ {% endif %}
+ <h2>{{ ride.get_ridetype_display }} leaving {{ ride.depart_time }}</h2>
+ {{ ride.info|markup }}
+ <h3>Destinations</h3>
+ <ol>
+ {% for waypoint in ride.waypoint_list %}
+ <li>{{waypoint}}</li>
+ {% endfor %}
+ </ol>
+ <p>{{ ride.seats_avail }} seats available</p>
+ {% if ride.user == request.user %}
+ <p>Ride requests</p>
+ <table><tbody>
+ {% for req in requests %}
+ <tr>
+ <td><a href="{{req.user.get_absolute_url}}">{{req.user.username}}:</a></td>
+ <td>{{req.info}}</td>
+ <td>
+ <form class="request_accept_form" method="POST" action="{% url ride_request_update %}">
+ {% csrf_token %}
+ <input type="hidden" name="request_id" value="{{req.id}}"/>
+ <select name="status">
+ <option value="pending" {% if req.status = "pending" %}selected{% endif %}>Pending</option>
+ <option value="accepted"{% if req.status = "accepted" %}selected{% endif %}>Accept</option>
+ <option value="declined"{% if req.status = "declined" %}selected{% endif %}>Decline</option>
+ </select>
+ </form>
+ </td>
+ <td><div class="req-status">{% if req.accepted %}☺{%else%}{%if req.declined %}☹{%endif%}{%endif%}</div></td>
+ </tr>
+ {% empty %}
+ No pending requests
+
+ {% endfor %}
+</tbody></table>
+ {% else %}
+ {% if ride_request %}
+ <div id="requeststatus">
+ {% if ride_request.status = "pending" %}
+ You have requested a seat.
+ {% else %}
+ {% if ride_request.status == "accepted" %}
+ You have a seat on this ride.
+ {% else %}
+ {% if ride_request.status == "reject" %}
+ Your ride request has been rejected.
+ {% endif %}
+ {% endif %}
+ {% endif %}
+ </div>
+ {% else %}
+ <div id="request">
+ <form method="POST" action="request/">{%csrf_token%}
+ <p>{{ form.info.help_text }}</p>
+ <p>{{ form.info }}</p>
+ <input type="submit" value="Request a seat"/>
+ </form>
+ </div>
+ {% endif %}
+ {% endif %}
+ <article id="{{ride.forum_post.slug}}"/>
+ <h2>Comments</h2>
+ <div id="postform">
+ <textarea rows="5" cols="70"></textarea><br />
+ <button class="save">post comment</button>
+ <img class="loader" src="/media/img/ajax-loader.gif"
+ width="16" height="16" />
+ <span class="error"></span>
+ {% if not user.is_authenticated %}
+ <p class="warning"><strong>Warning:</strong> When posting anonymously
+ you will not be able to edit/delete your post. Please consider
+ <a href="{% url signup %}">signing up for account</a>.</p>
+ {% endif %}
+ </div>
+ <section id="comment-list">
+ {% show_comments user comments %}
+ </section>
+ </td><td id="mapright">
+ <div style="width: 100%; height: 500px" id="map">
+
+ </div>
+</td></tr>
+</tbody></table>
+
+{% endblock content %}
View
49 occupywallst/templates/occupywallst/ride_update.html
@@ -0,0 +1,49 @@
+{% extends base %}
+
+{% block title %}Free Bus/Carpool Route Map | OccupyWallSt.org{% endblock title %}
+
+{% block stylesheets %}
+ <style type="text/css">
+ #navbar .nav-rides { background: #900; }
+ </style>
+{% endblock stylesheets %}
+
+{% block scripts %}
+ <script src="//maps.google.com/maps/api/js?sensor=false&region=us" type="text/javascript"></script>
+ <script src="//maps.google.com/maps/api/js?libraries=places&sensor=false&region=us" type="text/javascript"></script>
+{% endblock scripts %}
+
+{% block js_init %}
+ {{ block.super }}
+ rides_init({
+ "map": document.getElementById("map"),
+ "center": new google.maps.LatLng(40.717712644386026, -74.00913921356198),
+ "zoom": 8
+ });
+
+{% endblock js_init %}
+
+{% block content %}
+{% if ride %}
+<h1>Update {{ride.title}}</h1>
+{% else %}
+<h1>Add a ride</h1>
+{% endif %}
+<table style="width:100%"><tbody><tr><td id="left">
+ <form method="POST" action=".">{% csrf_token %}
+ <table class="formtable">
+ <tbody>
+ {{ form.as_table }}
+ <tr><th></th><td><input type="submit" value="{% if ride %}Update{% else %}Add{%endif%} ride"/></td></tr>
+ </tbody>
+ </table>
+ </form>
+ </td><td id="mapright">
+ <div style="height: 500px" id="map">
+
+ </div>
+</td></tr>
+</tbody>
+</table>
+
+{% endblock content %}
View
4 occupywallst/templates/occupywallst/rides.html
@@ -18,7 +18,8 @@
rides_init({
"map": document.getElementById("map"),
"center": new google.maps.LatLng(40.717712644386026, -74.00913921356198),
- "zoom": 8
+ "zoom": 8,
+ "update_rides" : true,
});
{% endblock js_init %}
@@ -29,7 +30,6 @@ <h1 style="margin-bottom: 0.5em; ">
Bus/Carpool
<img id="loader" style="display:none" src="/media/img/ajax-loader.gif" width="16" height="16" />
</h1>
- <p><strong>This feature is still in progress!</strong></p>
<div style="width: 100%; height: 500px; " id="map"></div>
<div id="add_ride" style="display:none">
<form method="POST" action=".">{% csrf_token %}
View
6 occupywallst/urls.py
@@ -27,6 +27,11 @@
url(r'^attendees/$', 'occupywallst.views.attendees', name='attendees'),
url(r'^notification/(?P<id>\d+)/$', 'occupywallst.views.notification', name='notification'),
url(r'^rides/$', 'occupywallst.views.rides', name='rides'),
+ url(r'^rides/(?P<ride_id>\d+)/$', 'occupywallst.views.ride_info', name='ride_info'),
+ url(r'^rides/create/$', 'occupywallst.views.ride_create', name='ride_create'),
+ url(r'^rides/(?P<ride_id>\d+)/edit/$', 'occupywallst.views.ride_edit', name='ride_edit'),
+ url(r'^rides/(?P<ride_id>\d+)/request/$', 'occupywallst.views.ride_request_add', name='ride_request'),
+ url(r'^rides/(?P<ride_id>\d+)/request/delete/$', 'occupywallst.views.ride_request_delete', name='ride_request_delete'),
url(r'^calendar/$', 'occupywallst.views.calendar', name='calendar'),
url(r'^chat/$', 'occupywallst.views.chat', name='chat'),
url(r'^chat/(?P<room>[a-zA-Z0-9]+)/$', 'occupywallst.views.chat', name='chat-private'),
@@ -42,6 +47,7 @@
url(r'^api/safe/attendees/$', require_GET(utils.api_view(api.attendees))),
url(r'^api/safe/attendee_info/$', require_GET(utils.api_view(api.attendee_info))),
url(r'^api/safe/rides/$', require_GET(utils.api_view(api.rides))),
+ url(r'^api/ride_request_update/$', require_POST(utils.api_view(api.ride_request_update)), name="ride_request_update"),
url(r'^api/safe/article_get/$', require_GET(utils.api_view(api.article_get))),
url(r'^api/article_new/$', require_POST(utils.api_view(api.article_new))),
url(r'^api/article_edit/$', require_POST(utils.api_view(api.article_edit))),
View
99 occupywallst/views.py
@@ -11,13 +11,14 @@
from datetime import datetime, timedelta
from django.db.models import Q
+from django.forms import ValidationError
from django.contrib.auth import views as authviews
from django.template import RequestContext
-from django.shortcuts import render_to_response
+from django.shortcuts import render_to_response, get_object_or_404
from django.http import Http404, HttpResponseRedirect
from django.contrib.auth.decorators import login_required
-from occupywallst.forms import ProfileForm, SignupForm, RideForm
+from occupywallst.forms import ProfileForm, SignupForm, RideForm, RideRequestForm
from occupywallst import api
from occupywallst import models as db
@@ -127,26 +128,96 @@ def attendees(request):
def rides(request):
+ rides = db.Ride.objects.all()
+ return render_to_response(
+ 'occupywallst/rides.html', {
+ "rides" : rides,
+ },
+ context_instance=RequestContext(request))
+
+@login_required
+def ride_create(request):
+ return ride_create_or_update(request)
+
+@login_required
+def ride_edit(request, ride_id):
+ ride = get_object_or_404(db.Ride, pk=int(ride_id))
+ return ride_create_or_update(request, ride)
+
+@login_required
+def ride_create_or_update(request, instance=None):
if request.method == "POST":
- if request.user.is_authenticated():
- form = RideForm(request.POST)
- if form.is_valid():
- ride = form.save(commit=False)
- ride.user = request.user
- ride.update_from_maps()
+ form = RideForm(request.POST, instance=instance)
+ if form.is_valid():
+ ride = form.save(commit=False)
+ ride.user = request.user
+ try:
+# this should maybe go into some work queue instead of being run sync
+ ride.retrieve_route_from_google()
+ ride.full_clean()
ride.save()
- else:
- return HttpResponseRedirect("/signup")
+ return HttpResponseRedirect(ride.get_absolute_url())
+ except ValidationError as v:
+ # stupid hack
+ from django.forms.util import ErrorList
+ form._errors["title"] = ErrorList(
+ [u"""You have already created a ride with
+ that title."""])
+
else:
- form = RideForm()
- rides = db.Ride.objects.all()
+ form = RideForm(instance=instance)
return render_to_response(
- 'occupywallst/rides.html', {
+ 'occupywallst/ride_update.html', {
"form" : form,
- "rides" : rides,
+ "ride" : instance,},
+ context_instance=RequestContext(request))
+
+
+def ride_info(request, ride_id):
+ ride = get_object_or_404(db.Ride, pk=int(ride_id))
+ ride_request = None
+ requests = None
+ comments = ride.forum_post.comments_as_user(request.user)
+ comments = _instate_hierarchy(comments)
+ if request.user.is_authenticated():
+ if request.user == ride.user:
+ requests = ride.requests.order_by('status').select_related("user")
+ else:
+ requests = None
+ try:
+ ride_request = ride.requests.get(
+ user=request.user,is_deleted=False)
+ except db.RideRequest.DoesNotExist:
+ ride_request = None
+ form = RideRequestForm()
+ return render_to_response(
+ 'occupywallst/ride_info.html', {
+ "ride" : ride,
+ "form" : form,
+ "requests" : requests,
+ "ride_request" : ride_request,
+ "comments" : comments,
},
context_instance=RequestContext(request))
+@login_required
+def ride_request_add(request, ride_id):
+ ride = get_object_or_404(db.Ride, pk=int(ride_id))
+ request_form = RideRequestForm(request.POST)
+ request_exists = db.RideRequest.objects.filter(
+ user=request.user, ride=ride)
+ if request_form.is_valid() and not request_exists:
+ request_form.save(request.user, ride)
+ return HttpResponseRedirect(ride.get_absolute_url())
+
+@login_required
+def ride_request_delete(request, ride_id):
+ if request.method == "POST":
+ ride = get_object_or_404(db.Ride, pk=int(ride_id))
+ db.RideRequest.objects.filter(ride=ride, user=request.user).update(
+ is_deleted=True)
+ return HttpResponseRedirect(ride.get_absolute_url())
+
def housing(request):
return render_to_response(

0 comments on commit ce8cbd6

Please sign in to comment.
Something went wrong with that request. Please try again.