Project for the UPV to develop an app like BlaBlaCar but only for UPV people.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

ui changes

+512 -87
+1
.gitignore
··· 60 60 upvcarshare/static/dist/css 61 61 upvcarshare/static/dist/js 62 62 upvcarshare/static/dist/img 63 + upvcarshare/media
+2
package.json
··· 7 7 "dependencies": {}, 8 8 "devDependencies": { 9 9 "angular": "^1.5.5", 10 + "angular-cookies": "^1.5.7", 11 + "angularjs-scroll-glue": "^2.0.7", 10 12 "babel-polyfill": "^6.9.1", 11 13 "babel-preset-es2015": "^6.6.0", 12 14 "babel-preset-react": "^6.5.0",
+3 -1
upvcarshare/config/urls.py
··· 1 1 # -*- coding: utf-8 -*- 2 2 from django.conf import settings 3 3 from django.conf.urls import url, include 4 + from django.conf.urls.static import static 4 5 from django.contrib import admin 5 6 from django.utils.translation import ugettext_lazy as _ 6 7 from django.views import defaults as default_views 7 8 8 9 from config.router import urlpatterns as api_urlpatterns 9 - # App URLs 10 10 from core.views import PartialsTemplateView 11 11 from pages.views import HomeView 12 12 ··· 44 44 url(r'^404/$', default_views.page_not_found, kwargs={'exception': Exception('Page not Found')}), 45 45 url(r'^500/$', default_views.server_error), 46 46 ] 47 + # Media URLs on debug 48 + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
+1 -1
upvcarshare/journeys/api/v1/serializers.py
··· 71 71 72 72 class Meta: 73 73 model = Message 74 - fields = ["user", "journey", "content", "created"] 74 + fields = ["id", "user", "journey", "content", "created"] 75 75 76 76 @dispatch(MESSAGE) 77 77 def save(self, **kwargs):
+39 -3
upvcarshare/journeys/forms.py
··· 9 9 from core.widgets import GMapsPointWidget 10 10 from journeys import JOURNEY_KINDS, GOING, RETURN 11 11 from journeys.helpers import make_point_projected 12 - from journeys.models import Residence, Journey, Campus 12 + from journeys.models import Residence, Journey, Campus, Transport 13 13 from users.models import User 14 14 15 15 ··· 59 59 60 60 class Meta: 61 61 model = Journey 62 - fields = ["residence", "campus", "kind", "i_am_driver", "free_places", "departure", "time_window"] 62 + fields = ["residence", "campus", "kind", "i_am_driver", "transport", "free_places", "departure", "time_window"] 63 63 widgets = { 64 + "transport": forms.Select(attrs={"class": "form-control"}), 64 65 "residence": forms.Select(attrs={"class": "form-control"}), 65 66 "campus": forms.Select(attrs={"class": "form-control"}), 66 67 "kind": forms.Select(attrs={"class": "form-control"}), ··· 74 75 super(JourneyForm, self).__init__(*args, **kwargs) 75 76 if self.user: 76 77 self.fields['residence'].queryset = Residence.objects.filter(user=self.user) 78 + self.fields['transport'].queryset = Transport.objects.filter(user=self.user) 77 79 78 80 def save(self, commit=True, **kwargs): 79 81 """When save a journey form, you have to provide an user.""" ··· 105 107 106 108 class Meta: 107 109 model = Journey 108 - fields = ["origin", "destiny", "i_am_driver", "free_places", "departure", "time_window"] 110 + fields = ["origin", "destiny", "i_am_driver", "transport", "free_places", "departure", "time_window"] 109 111 widgets = { 112 + "transport": forms.Select(attrs={"class": "form-control"}), 110 113 "kind": forms.Select(attrs={"class": "form-control"}), 111 114 "free_places": forms.NumberInput(attrs={"class": "form-control"}), 112 115 "departure": floppyforms.DateTimeInput(attrs={"class": "form-control"}), ··· 116 119 def __init__(self, *args, **kwargs): 117 120 self.user = kwargs.pop("user") 118 121 super(SmartJourneyForm, self).__init__(*args, **kwargs) 122 + if self.user: 123 + self.fields['transport'].queryset = Transport.objects.filter(user=self.user) 119 124 120 125 def clean_origin(self): 121 126 origin = self.cleaned_data["origin"] ··· 200 205 except User.DoesNotExist: 201 206 raise forms.ValidationError(_("El usuario no existe")) 202 207 return user 208 + 209 + 210 + class TransportForm(forms.ModelForm): 211 + """Form to create transport data.""" 212 + 213 + class Meta: 214 + model = Transport 215 + fields = ["name", "default_places", "brand", "model", "color"] 216 + widgets = { 217 + "name": forms.TextInput(attrs={"class": "form-control"}), 218 + "default_places": forms.NumberInput(attrs={"class": "form-control"}), 219 + "brand": floppyforms.TextInput(attrs={"class": "form-control"}), 220 + "model": forms.TextInput(attrs={"class": "form-control"}), 221 + "color": forms.TextInput(attrs={"class": "form-control"}), 222 + } 223 + 224 + def __init__(self, *args, **kwargs): 225 + self.user = kwargs.pop("user") 226 + super(TransportForm, self).__init__(*args, **kwargs) 227 + 228 + def save(self, commit=True, **kwargs): 229 + """When save a transport form, you have to provide an user.""" 230 + user = self.user 231 + if "user" in kwargs: 232 + assert isinstance(kwargs["user"], User) 233 + user = kwargs.get("user") 234 + transport = super(TransportForm, self).save(commit=False) 235 + transport.user = user 236 + if commit: 237 + transport.save() 238 + return transport
+41
upvcarshare/journeys/migrations/0007_auto_20160620_1001.py
··· 1 + # -*- coding: utf-8 -*- 2 + # Generated by Django 1.9.7 on 2016-06-20 10:01 3 + from __future__ import unicode_literals 4 + 5 + from django.db import migrations, models 6 + import django.db.models.deletion 7 + 8 + 9 + class Migration(migrations.Migration): 10 + 11 + dependencies = [ 12 + ('journeys', '0006_passenger_status'), 13 + ] 14 + 15 + operations = [ 16 + migrations.AddField( 17 + model_name='journey', 18 + name='transport', 19 + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='journeys.Transport', verbose_name='Medio de transporte utilizado'), 20 + ), 21 + migrations.AddField( 22 + model_name='transport', 23 + name='brand', 24 + field=models.TextField(blank=True, default='', max_length=250, verbose_name='Marca'), 25 + ), 26 + migrations.AddField( 27 + model_name='transport', 28 + name='color', 29 + field=models.TextField(blank=True, default='', max_length=250, verbose_name='Color'), 30 + ), 31 + migrations.AddField( 32 + model_name='transport', 33 + name='model', 34 + field=models.TextField(blank=True, default='', max_length=250, verbose_name='Modelo'), 35 + ), 36 + migrations.AlterField( 37 + model_name='transport', 38 + name='default_places', 39 + field=models.PositiveIntegerField(default=4, verbose_name='Plazas libres'), 40 + ), 41 + ]
+21
upvcarshare/journeys/migrations/0008_auto_20160620_1013.py
··· 1 + # -*- coding: utf-8 -*- 2 + # Generated by Django 1.9.7 on 2016-06-20 10:13 3 + from __future__ import unicode_literals 4 + 5 + from django.db import migrations, models 6 + import django.db.models.deletion 7 + 8 + 9 + class Migration(migrations.Migration): 10 + 11 + dependencies = [ 12 + ('journeys', '0007_auto_20160620_1001'), 13 + ] 14 + 15 + operations = [ 16 + migrations.AlterField( 17 + model_name='journey', 18 + name='transport', 19 + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='journeys', to='journeys.Transport', verbose_name='Medio de transporte utilizado'), 20 + ), 21 + ]
+22 -1
upvcarshare/journeys/models.py
··· 132 132 default=DEFAULT_TIME_WINDOW, 133 133 blank=True 134 134 ) 135 + transport = models.ForeignKey( 136 + "journeys.Transport", 137 + related_name="journeys", 138 + verbose_name=_("Medio de transporte utilizado"), 139 + null=True, 140 + blank=True 141 + ) 135 142 disabled = models.BooleanField(default=False, verbose_name=_("marcar como deshabilitado")) 136 143 137 144 objects = JourneyManager() ··· 271 278 return self.passengers.filter(status=CONFIRMED) 272 279 return Passenger.objects.none() 273 280 281 + 274 282 class Passenger(TimeStampedModel): 275 283 """A user who has joined a journey.""" 276 284 user = models.ForeignKey(settings.AUTH_USER_MODEL) ··· 281 289 unique_together = ["user", "journey"] 282 290 283 291 292 + @python_2_unicode_compatible 284 293 class Transport(TimeStampedModel): 285 294 """Saves the transport data for a user.""" 286 295 name = models.CharField(max_length=64, blank=True, null=True) 287 296 user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="transports") 288 - default_places = models.PositiveIntegerField(default=4) 297 + default_places = models.PositiveIntegerField(verbose_name=_("Plazas libres"), default=4) 298 + brand = models.TextField(verbose_name=_("Marca"), max_length=250, blank=True, default="") 299 + model = models.TextField(verbose_name=_("Modelo"), max_length=250, blank=True, default="") 300 + color = models.TextField(verbose_name=_("Color"), max_length=250, blank=True, default="") 301 + 302 + def __str__(self): 303 + return self.name 304 + 305 + def description(self): 306 + return ", ".join([self.brand, self.model, self.color]) 307 + 308 + def count_used_journeys(self): 309 + return self.journeys.count() 289 310 290 311 291 312 class Message(TimeStampedModel):
+7 -1
upvcarshare/journeys/urls.py
··· 6 6 from journeys.views import CreateJourneyView, CreateResidenceView, EditResidenceView, EditJourneyView, \ 7 7 RecommendedJourneyView, CurrentUserJourneyView, CurrentUserResidencesView, JoinJourneyView, LeaveJourneyView, \ 8 8 JourneyView, PassengerJourneyView, ThrowOutPassengerView, DeleteResidence, CancelJourneyView, ConfirmJourneyView, \ 9 - RejectJourneyView 9 + RejectJourneyView, CreateTransportView, EditTransportView, DeleteTransportView, TransportListView 10 10 11 11 urlpatterns = [ 12 12 # Residences ··· 14 14 url(r"residences/(?P<pk>\d+)/edit/$", EditResidenceView.as_view(), name="edit-residence"), 15 15 url(r"residences/(?P<pk>\d+)/delete/$", DeleteResidence.as_view(), name="delete-residence"), 16 16 url(r"residences/$", CurrentUserResidencesView.as_view(), name="residences"), 17 + 18 + # Transports 19 + url(r"transports/create/$", CreateTransportView.as_view(), name="create-transport"), 20 + url(r"transports/(?P<pk>\d+)/edit/$", EditTransportView.as_view(), name="edit-transport"), 21 + url(r"transports/(?P<pk>\d+)/delete/$", DeleteTransportView.as_view(), name="delete-transport"), 22 + url(r"transports/$", TransportListView.as_view(), name="transports"), 17 23 18 24 # Journeys 19 25 url(r"recommended/$", RecommendedJourneyView.as_view(), name="recommended"),
+65 -3
upvcarshare/journeys/views.py
··· 12 12 from journeys import GOING 13 13 from journeys.exceptions import AlreadyAPassenger, NoFreePlaces, NotAPassenger 14 14 from journeys.forms import JourneyForm, ResidenceForm, FilterForm, CancelJourneyForm, SmartJourneyForm, \ 15 - ConfirmRejectJourneyForm 16 - from journeys.models import Journey, Residence, Campus, Passenger 15 + ConfirmRejectJourneyForm, TransportForm 16 + from journeys.models import Journey, Residence, Campus, Passenger, Transport 17 17 18 18 19 19 class CreateResidenceView(LoginRequiredMixin, View): ··· 146 146 147 147 @staticmethod 148 148 def show_messenger(request, journey): 149 - if journey.user == request.user: 149 + if journey.user == request.user and not journey.needs_driver(): 150 150 return True 151 151 return journey.is_passenger(request.user) 152 152 ··· 355 355 journey = get_object_or_404(Journey, pk=pk, user=request.user) 356 356 journey.cancel() 357 357 return redirect("journeys:details", pk=journey.pk) 358 + 359 + 360 + class TransportListView(LoginRequiredMixin, View): 361 + """Shows the list of users' transports.""" 362 + template_name = "transports/list.html" 363 + 364 + def get(self, request): 365 + data = { 366 + "transports": Transport.objects.filter(user=request.user) 367 + } 368 + return render(request, self.template_name, data) 369 + 370 + 371 + class CreateTransportView(LoginRequiredMixin, View): 372 + """Handles the creation of a new transport.""" 373 + template_name = "transports/create.html" 374 + form = TransportForm 375 + 376 + def get(self, request): 377 + data = { 378 + "form": self.form(user=request.user) 379 + } 380 + return render(request, self.template_name, data) 381 + 382 + def post(self, request): 383 + form = self.form(request.POST, user=request.user) 384 + if form.is_valid(): 385 + form.save(user=request.user) 386 + messages.success(request, _('Has creado el transporte correctamente')) 387 + return redirect("journeys:transports") 388 + data = {"form": form} 389 + return render(request, self.template_name, data) 390 + 391 + 392 + class EditTransportView(LoginRequiredMixin, View): 393 + """Handles the edition of a new transport.""" 394 + template_name = "transports/edit.html" 395 + form = TransportForm 396 + 397 + def get(self, request, pk): 398 + transport = get_object_or_404(Transport, pk=pk, user=request.user) 399 + data = { 400 + "form": self.form(instance=transport, user=request.user), 401 + "transport": transport 402 + } 403 + return render(request, self.template_name, data) 404 + 405 + def post(self, request, pk): 406 + transport = get_object_or_404(Transport, pk=pk, user=request.user) 407 + form = self.form(request.POST, user=request.user, instance=transport) 408 + if form.is_valid(): 409 + messages.success(request, _('Has editado el transporte correctamente')) 410 + return redirect("journeys:transports") 411 + data = { 412 + "form": form, 413 + "transport": transport 414 + } 415 + return render(request, self.template_name, data) 416 + 417 + 418 + class DeleteTransportView(LoginRequiredMixin, View): 419 + pass
upvcarshare/static/src/img/avatar.png

This is a binary file and will not be displayed.

+1 -1
upvcarshare/static/src/js/app.js
··· 23 23 .config(['$httpProvider', '$interpolateProvider', ($httpProvider, $interpolateProvider) => { 24 24 $interpolateProvider.startSymbol('[[').endSymbol(']]'); 25 25 $httpProvider.defaults.xsrfCookieName = 'csrftoken'; 26 - $httpProvider.defaults.srfHeaderName = 'X-CSRFToken'; 26 + $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken'; 27 27 }]);
+9 -1
upvcarshare/static/src/js/messenger/index.js
··· 1 1 import angular from 'angular'; 2 + import 'angularjs-scroll-glue'; 3 + import 'angular-cookies'; 4 + 2 5 import MessengerService from './messenger.service' 6 + import MessageUserColor from './messenger.directive' 3 7 import {MessengerComponent, MessageListComponent, MessageFormComponent} from './messenger.component'; 4 8 5 9 6 10 // Messenger module 7 11 const messenger = angular 8 - .module('messenger', []) 12 + .module('messenger', [ 13 + 'ngCookies', 14 + 'luegg.directives' 15 + ]) 9 16 .service('MessengerService', MessengerService) 17 + .directive('userColor', MessageUserColor) 10 18 .component('messenger', MessengerComponent) 11 19 .component('messageList', MessageListComponent) 12 20 .component('messageForm', MessageFormComponent);
+4 -3
upvcarshare/static/src/js/messenger/messenger.controller.js
··· 1 1 import moment from 'moment'; 2 - moment.locale('es'); 2 + import jQuery from 'jquery'; 3 3 4 4 5 5 class MessengerController { 6 6 7 - constructor($scope, MessengerService) { 7 + constructor($scope,$element, MessengerService) { 8 8 this.messengerService = MessengerService; 9 9 this.$scope = $scope; 10 + this.$element = $element; 10 11 } 11 12 12 13 $onInit() { ··· 70 71 } 71 72 72 73 } 73 - MessengerController.$inject = ['$scope', 'MessengerService']; 74 + MessengerController.$inject = ['$scope', '$element', 'MessengerService']; 74 75 75 76 76 77 class MessageListController {
+63
upvcarshare/static/src/js/messenger/messenger.directive.js
··· 1 + // Directive to change the color of the user 2 + const MessageUserColor = ($cookies) => ({ 3 + restrict: 'A', 4 + 5 + link($scope, $element, $attrs) { 6 + var userId = $attrs.userColor; 7 + var journeyId = $attrs.journey; 8 + var colors = [ 9 + "#e74c3c", 10 + "#e67e22", 11 + "#f1c615", 12 + "#3498db", 13 + "#2ecc71", 14 + "#1abc9c", 15 + "#9b59b6", 16 + "#34495e" 17 + ]; 18 + var usedColorsCookieKey = `used-colors-${journeyId}`; 19 + var userColorCookieKey = `user-color-${journeyId}-${userId}`; 20 + 21 + // Get used colors 22 + var usedColors = $cookies.get(usedColorsCookieKey); 23 + if (usedColors !== undefined) { 24 + var usedColorsList = []; 25 + usedColors.split(',').forEach( value => { 26 + "use strict"; 27 + usedColorsList.push(value); 28 + }); 29 + usedColors = usedColorsList; 30 + } 31 + else { 32 + usedColors = []; 33 + } 34 + 35 + // Get available colors 36 + var availableColors = []; 37 + colors.forEach( value => { 38 + "use strict"; 39 + if (usedColors.indexOf(value) == -1) { 40 + availableColors.push(value); 41 + } 42 + }); 43 + 44 + // Assign color 45 + var selectColor = $cookies.get(userColorCookieKey); 46 + if (!selectColor) { 47 + var randomIndex = Math.floor(Math.random() * (availableColors.length - 1)); 48 + selectColor = availableColors[randomIndex]; 49 + $cookies.put(userColorCookieKey, selectColor); 50 + usedColors.push(selectColor); 51 + } 52 + 53 + // Save used colors 54 + $cookies.put(usedColorsCookieKey, usedColors.join()); 55 + 56 + // Change color 57 + $element.css("color", selectColor); 58 + } 59 + 60 + }); 61 + MessageUserColor.$inject = ['$cookies']; 62 + 63 + export default MessageUserColor;
+2
upvcarshare/static/src/js/messenger/messenger.service.js
··· 32 32 33 33 } 34 34 35 + MessengerService.$inject = ['$http']; 36 + 35 37 export default MessengerService;
+17
upvcarshare/static/src/sass/journeys.scss
··· 23 23 } 24 24 } 25 25 26 + .journey-actions { 27 + padding-bottom: 15px; 28 + margin-bottom: 10px; 29 + border-bottom: $table-border-width dotted $table-border-color; 30 + } 31 + 32 + .avatar { 33 + width: 32px; 34 + height: 32px; 35 + } 36 + 37 + .passenger-actions { 38 + td { 39 + border-top: none; 40 + } 41 + } 42 + 26 43 #id_i_am_driver { 27 44 @extend .list-unstyled; 28 45 }
+5
upvcarshare/static/src/sass/messenger.scss
··· 3 3 4 4 5 5 .messenger { 6 + .messages-list { 7 + height: 500px; 8 + overflow-y: scroll; 9 + } 6 10 .message { 7 11 padding: 5px; 8 12 background-color: #eee; ··· 10 14 margin-bottom: 10px; 11 15 } 12 16 } 17 +
+1
upvcarshare/templates/header.html
··· 55 55 <a class="dropdown-item" href="{% url "journeys:passenger" %}">{% trans "Trayectos en los que viajo" %}</a> 56 56 <div class="dropdown-divider"></div> 57 57 <a class="dropdown-item" href="{% url "journeys:residences" %}">{% trans "Mis lugares" %}</a> 58 + <a class="dropdown-item" href="{% url "journeys:transports" %}">{% trans "Mis medios de transporte" %}</a> 58 59 </div> 59 60 </li> 60 61 <li class="nav-item {% add_active_class "users:edit" %} dropdown">
+15
upvcarshare/templates/journeys/blocks/details.actions.html
··· 1 + {% load i18n %} 2 + {% load journeys_tags %} 3 + <div class="journey-actions"> 4 + <h3>{% trans "Acciones" %}</h3> 5 + 6 + {% if request.user == journey.user %} 7 + <a href="{% url "journeys:edit" journey.pk %}" class="btn btn-success">{% trans "Editar" %}</a> 8 + {% if not journey.needs_driver and not journey.disabled %} 9 + <a href="{% url "journeys:cancel" journey.pk %}" class="btn btn-danger">{% trans "Cancelar trayecto" %}</a> 10 + {% endif %} 11 + {% else %} 12 + {% journey_join_leave_button journey %} 13 + {% endif %} 14 + 15 + </div>
+6
upvcarshare/templates/journeys/blocks/details.description.html
··· 13 13 <th scope="row">{% trans "Plazas libres" %}</th> 14 14 <td>{{ journey.current_free_places }}/{{ journey.free_places }}</td> 15 15 </tr> 16 + {% if journey.transport %} 17 + <tr> 18 + <th scope="row">{% trans "Datos del transporte" %}</th> 19 + <td>{{ journey.transport.description }}</td> 20 + </tr> 21 + {% endif %} 16 22 </tbody> 17 23 </table> 18 24 {% elif is_fulfilled %}
+41 -32
upvcarshare/templates/journeys/blocks/details.passengers.html
··· 1 1 {% load i18n %} 2 2 3 - <h3>{% trans "Pasajeros" %}</h3> 3 + <h3>{% trans "Lista de pasajeros" %}</h3> 4 4 <table class="table"> 5 5 <tbody> 6 6 {% for passenger in passengers %} 7 - <td> 8 - {{ passenger.user.get_full_name }} <br /> 9 - <small>{% trans "Unido el" %} {{ passenger.created }}</small> 10 - </td> 11 - {% if request.user == journey.driver and request.user == journey.user %} 12 - {% if passenger.status == CONFIRMED %} 13 - <td> 14 - <form method="post" action="{% url "journeys:throw-out" passenger.pk %}"> 15 - {% csrf_token %} 16 - <input type="hidden" name="return_to" value="{{ request.path }}"> 17 - <button type="submit" class="btn btn-danger">{% trans "Expulsar" %}</button> 18 - </form> 19 - </td> 20 - {% else %} 21 - <td> 22 - <form method="post" action="{% url "journeys:confirm" passenger.pk %}"> 23 - {% csrf_token %} 24 - <input type="hidden" name="return_to" value="{{ request.path }}"> 25 - <input type="hidden" name="user" value="{{ passenger.user.pk }}"> 26 - <button type="submit" class="btn btn-success">{% trans "Confirmar" %}</button> 27 - </form> 28 - </td> 29 - <td> 30 - <form method="post" action="{% url "journeys:reject" passenger.pk %}"> 31 - {% csrf_token %} 32 - <input type="hidden" name="return_to" value="{{ request.path }}"> 33 - <input type="hidden" name="user" value="{{ passenger.user.pk }}"> 34 - <button type="submit" class="btn btn-danger">{% trans "Rechazar" %}</button> 35 - </form> 36 - </td> 7 + <tr> 8 + <td> 9 + <img src="{{ passenger.user.get_avatar_url }}" class="img-circle avatar"> 10 + </td> 11 + <td> 12 + {{ passenger.user.get_full_name }} <br /> 13 + <small>{% trans "Unido el" %} {{ passenger.created }}</small> 14 + </td> 15 + </tr> 16 + <tr class="passenger-actions"> 17 + {% if request.user == journey.driver and request.user == journey.user %} 18 + {% if passenger.status == CONFIRMED %} 19 + <td colspan="2"> 20 + <form method="post" action="{% url "journeys:throw-out" passenger.pk %}"> 21 + {% csrf_token %} 22 + <input type="hidden" name="return_to" value="{{ request.path }}"> 23 + <button type="submit" class="btn btn-danger">{% trans "Expulsar" %}</button> 24 + </form> 25 + </td> 26 + {% else %} 27 + <td> 28 + <form method="post" action="{% url "journeys:confirm" passenger.pk %}"> 29 + {% csrf_token %} 30 + <input type="hidden" name="return_to" value="{{ request.path }}"> 31 + <input type="hidden" name="user" value="{{ passenger.user.pk }}"> 32 + <button type="submit" class="btn btn-success">{% trans "Confirmar" %}</button> 33 + </form> 34 + </td> 35 + <td> 36 + <form method="post" action="{% url "journeys:reject" passenger.pk %}"> 37 + {% csrf_token %} 38 + <input type="hidden" name="return_to" value="{{ request.path }}"> 39 + <input type="hidden" name="user" value="{{ passenger.user.pk }}"> 40 + <button type="submit" class="btn btn-danger">{% trans "Rechazar" %}</button> 41 + </form> 42 + </td> 43 + {% endif %} 37 44 {% endif %} 38 - {% endif %} 45 + </tr> 46 + {% empty %} 47 + <p class="text-muted">{% trans "No hay pasajeros ahora mismo." %}</p> 39 48 {% endfor %} 40 49 </tbody> 41 50 </table>
+10 -18
upvcarshare/templates/journeys/details.html
··· 14 14 </div> 15 15 {% endblock section_title %} 16 16 17 - {% block sidebar %} 18 - {% if request.user == journey.user %} 19 - <a href="{% url "journeys:edit" journey.pk %}" class="btn btn-success" style="margin-bottom: 5px">{% trans "Editar" %}</a> 20 - {% if not journey.needs_driver and not journey.disabled %} 21 - <a href="{% url "journeys:cancel" journey.pk %}" class="btn btn-danger">{% trans "Cancelar trayecto" %}</a> 22 - {% endif %} 23 - {% else %} 24 - {% journey_join_leave_button journey %} 25 - {% endif %} 26 - {% endblock sidebar %} 27 - 28 17 {% block content %} 29 18 <div class="row"> 30 - <div class="col-sm-8"> 19 + <div class="col-sm-3"> 20 + {% include "journeys/blocks/details.actions.html" %} 21 + {% if show_passengers %} 22 + {% include "journeys/blocks/details.passengers.html" %} 23 + {% endif %} 24 + {% include "journeys/blocks/details.location.html" %} 25 + </div> 26 + <div class="col-sm-9"> 31 27 {% include "journeys/blocks/details.description.html" %} 32 28 {% if show_messenger %} 33 29 <h3>{% trans "Tablón de mensajes" %}</h3> 30 + <p class="text-muted">{% trans "Habla con los otros pasajeros del viaje para concretar los detalles del viaje. La lista de mensajes <strong>no se actualiza automáticamente</strong>." %}</p> 34 31 <messenger journey="{{ journey.pk }}" first-name="{{ request.user.first_name }}" last-name="{{ request.user.last_name }}"></messenger> 35 32 {% endif %} 36 33 </div> 37 - <div class="col-sm-4"> 38 - {% if show_passengers %} 39 - {% include "journeys/blocks/details.passengers.html" %} 40 - {% endif %} 41 - {% include "journeys/blocks/details.location.html" %} 42 - </div> 34 + 43 35 </div> 44 36 {% endblock content %}
+14 -10
upvcarshare/templates/partials/messenger/message.form.html
··· 1 1 {% load i18n %} 2 - <form name="messageForm" ng-submit="$ctrl.onSubmit();"> 3 - {% csrf_token %} 4 - <div class="row"> 5 - <div class="col-xs-10"> 6 - <textarea class="form-control" ng-model="$ctrl.message.content"></textarea> 7 - </div> 8 - <div class="col-xs-2"> 9 - <button type="submit" class="btn btn-primary">{% trans "Enviar" %}</button> 10 - </div> 2 + <div class="row"> 3 + <div class="col-sm-12"> 4 + <form name="messageForm" ng-submit="$ctrl.onSubmit();"> 5 + {% csrf_token %} 6 + <div class="form-group row"> 7 + <div class="col-xs-10"> 8 + <input type="text" placeholder="{% trans "Escribe tu mensaje" %}" class="form-control form-control-lg" ng-model="$ctrl.message.content"> 9 + </div> 10 + <div class="col-xs-2"> 11 + <button type="submit" class="btn btn-lg btn-info pull-xs-right">{% trans "Enviar" %}</button> 12 + </div> 13 + </div> 14 + </form> 11 15 </div> 12 - </form> 16 + </div> 13 17 14 18
+12 -10
upvcarshare/templates/partials/messenger/message.list.html
··· 1 - <div class="message" ng-repeat="message in $ctrl.messages"> 2 - <div class="row"> 3 - <div class="col-xs-12"> 4 - <div class="row"> 5 - <div class="col-sm-10"> 6 - <h5 class="text-danger">[[message.user.first_name]] [[message.user.last_name]]</h5> 7 - </div> 8 - <div class="col-sm-2"> 9 - <small>[[$ctrl.showTimestamp(message.created)]]</small> 1 + <div class="messages-list js-messages-list" scroll-glue> 2 + <div class="message" ng-repeat="message in $ctrl.messages"> 3 + <div class="row"> 4 + <div class="col-xs-12"> 5 + <div class="row"> 6 + <div class="col-sm-10"> 7 + <h5 user-color="[[message.user.id]]" data-journey="[[message.journey]]">[[message.user.first_name]] [[message.user.last_name]]</h5> 8 + </div> 9 + <div class="col-sm-2"> 10 + <small>[[$ctrl.showTimestamp(message.created)]]</small> 11 + </div> 10 12 </div> 13 + <p class="content">[[ message.content ]]</p> 11 14 </div> 12 - <p class="content">[[ message.content ]]</p> 13 15 </div> 14 16 </div> 15 17 </div>
+39
upvcarshare/templates/transports/create.html
··· 1 + {% extends "header.html" %} 2 + {% load i18n %} 3 + 4 + {% block extra_head %} 5 + {{ form.media }} 6 + {% endblock %} 7 + 8 + {% block section_title %} 9 + <div class="row"> 10 + <div class="col-xs-12"> 11 + <h2>{% trans "Crear medio de transporte" %}</h2> 12 + </div> 13 + </div> 14 + {% endblock section_title %} 15 + 16 + {% block content %} 17 + <div class="row"> 18 + <div class="col-xs-12"> 19 + <form method="post" action=""> 20 + {% csrf_token %} 21 + {% for field in form %} 22 + <div class="form-group row{% if field.errors %} has-danger{% endif %}"> 23 + <label for="{{ field.auto_id }}" class="col-sm-3 form-control-label">{{ field.label }}</label> 24 + <div class="col-sm-9"> 25 + {{ field }} 26 + <span class="text-muted">{{ field.help_text }}</span> 27 + <span class="text-muted">{{ field.errors }}</span> 28 + </div> 29 + </div> 30 + {% endfor %} 31 + <div class="form-group row"> 32 + <div class="col-sm-offset-3 col-sm-9"> 33 + <button type="submit" class="btn btn-success">{% trans "Guardar" %}</button> 34 + </div> 35 + </div> 36 + </form> 37 + </div> 38 + </div> 39 + {% endblock content %}
+10
upvcarshare/templates/transports/edit.html
··· 1 + {% extends "residences/create.html" %} 2 + {% load i18n %} 3 + 4 + {% block section_title %} 5 + <div class="row"> 6 + <div class="col-xs-12"> 7 + <h2>{% trans "Editar medio de transporte" %}</h2> 8 + </div> 9 + </div> 10 + {% endblock section_title %}
+52
upvcarshare/templates/transports/list.html
··· 1 + {% extends "sidebar.html" %} 2 + {% load i18n %} 3 + {% load core_tags %} 4 + 5 + {% block section_title %} 6 + <div class="row"> 7 + <div class="col-sm-12"> 8 + <h2>{% trans "Mis medios de transporte" %}</h2> 9 + <p>{% trans "Medios de transporte que puedes utilizar en tus trayectos." %}</p> 10 + </div> 11 + </div> 12 + {% endblock section_title %} 13 + 14 + {% block sidebar %} 15 + <a href="{% url "journeys:create-transport" %}" class="btn btn-primary">{% trans "Nuevo transporte" %}</a> 16 + {% endblock sidebar %} 17 + 18 + {% block content %} 19 + {% for transport in transports %} 20 + <div class="residence-entry"> 21 + <div class="row"> 22 + <div class="col-sm-10"> 23 + <h4>{{ transport.name }}</h4> 24 + <table class="table table-sm"> 25 + <tbody> 26 + <tr> 27 + <th scope="row">{% trans "Marca" %}</th> 28 + <td>{{ transport.brand }}</td> 29 + </tr> 30 + <tr> 31 + <th scope="row">{% trans "Model"%}</th> 32 + <td>{{ transport.model }}</td> 33 + </tr> 34 + <tr> 35 + <th scope="row">{% trans "Color" %}</th> 36 + <td>{{ transport.color }}</td> 37 + </tr> 38 + </tbody> 39 + </table> 40 + </div> 41 + <div class="col-sm-2"> 42 + <p class="text-xs-center"><a href="{% url "journeys:edit-transport" transport.pk %}" class="btn btn-success">{% trans "Editar" %}</a></p> 43 + {% if transport.count_used_journeys == 0 %} 44 + <p class="text-xs-center"><a href="{% url "journeys:delete-transport" transport.pk %}" class="btn btn-danger">{% trans "Borrar" %}</a></p> 45 + {% endif %} 46 + </div> 47 + </div> 48 + </div> 49 + {% empty %} 50 + <h3 class="text-muted">{% trans "No tienes medios de transporte creados" %}</h3> 51 + {% endfor %} 52 + {% endblock content %}
+9 -2
upvcarshare/users/models.py
··· 5 5 from django.contrib.auth.models import PermissionsMixin, AbstractUser, UserManager 6 6 from django.contrib.gis.db import models 7 7 from django.contrib.gis.gdal import SpatialReference, CoordTransform 8 + from django.templatetags.static import static 8 9 from django.utils.six import python_2_unicode_compatible 9 10 from django.utils.translation import ugettext_lazy as _ 10 11 from rest_framework.authtoken.models import Token ··· 17 18 class User(AbstractUser): 18 19 """Custom user model.""" 19 20 avatar = models.ImageField( 20 - upload_to=UploadToDir('avatars/', random_name=True), default="avatars/default.png", 21 - null=True, blank=True, 21 + upload_to=UploadToDir('avatars/', random_name=True), 22 + null=True, 23 + blank=True, 22 24 max_length=255 23 25 ) 24 26 ··· 59 61 full_name = '%s %s' % (self.first_name, self.last_name) 60 62 return full_name.strip() 61 63 return self.username 64 + 65 + def get_avatar_url(self): 66 + if self.avatar: 67 + return self.avatar.url 68 + return static("img/avatar.png") 62 69 63 70 def get_default_position_wgs84(self): 64 71 """Transforms position to WGS-84 system."""