More cleanup

moved login, logout and password change from website app to musicians
This commit is contained in:
Martin Bauer 2014-01-11 15:01:40 +01:00
parent 1aa97e53d3
commit 010efe137e
13 changed files with 202 additions and 163 deletions

View File

@ -78,8 +78,8 @@ STATIC_ROOT = PROJECT_PATH + '/static_collection'
# Example: "http://example.com/static/", "http://static.example.com/"
STATIC_URL = '/static/'
LOGIN_URL="/login"
PUBLIC_URLS=( "^login/?$", "^login/usernames/?$")
LOGIN_URL="/musicians/login"
PUBLIC_URLS=( "^musicians/login/?$", "^musicians/login/usernames/?$")
# Additional locations of static files
STATICFILES_DIRS = (

View File

@ -9,6 +9,11 @@ from datetime import datetime
from location_field.models import PlainLocationField
class NoNextEventException( Exception ):
def __str__(self):
return ("No event scheduled for the future")
class Event ( models.Model ):
EVENT_TYPES = (
@ -64,11 +69,50 @@ class Event ( models.Model ):
@property
def displaydatetime(self):
if not self.displaytime == None:
return datetime.combine( self.date, self.displaytime() )
return datetime.combine( self.date, self.displaytime )
else:
return datetime.combine( self.date, datetime.min.time())
return datetime.combine( self.date, datetime.min.time() )
@staticmethod
def getNextEvent( eventType = "", includePreviousFromToday = True ):
"""Return the next event, of the given type. If type is the empty string the next event is returned
regardless of its type.
if includePreviousFromToday the nextEvent returned could also have been today with a startime < now """
if includePreviousFromToday:
if eventType == "":
nextEvents = Event.objects.filter( date__gte = datetime.now() ).order_by('date')[:1]
else:
nextEvents = Event.objects.filter( date__gte = datetime.now(), type = eventType ).order_by('date')[:1]
if len( nextEvents ) == 0:
raise NoNextEventException()
return nextEvents[0]
else:
maximalNumberOfEventsOnSameDay = 4
nextEvents = []
if eventType =="":
nextEvents = Event.objects.filter( date__gte = datetime.now() ).order_by('date')[:maximalNumberOfEventsOnSameDay]
else:
nextEvents = Event.objects.filter( date__gte = datetime.now(), type = eventType ).order_by('date')[:maximalNumberOfEventsOnSameDay]
if len(nextEvents) == 0:
raise NoNextEventException()
i = 0
nextEvent = nextEvents[0]
# nextEvent is not necessarily events[0] since events[0] may have been previously today
while nextEvent.displaydatetime < datetime.now():
if len(nextEvents ) <= i:
raise NoNextEventException()
else:
i += 1
nextEvent = nextEvents[i]
return nextEvent
class EventParticipation( models.Model ):
OPTIONS = ( ('?' , _('?' )),

55
eventplanner/snippets.py Normal file
View File

@ -0,0 +1,55 @@
from datetime import datetime
from models import Event, EventParticipation, NoNextEventException
from musicians.models import Musician
def addEventCountdownForNextEventToContext( context, username, eventType = "" ):
"""Returns an object that has to be added to the render context on the page where the countdown
should be displayed . The username is required to also supply participation information."""
try:
nextEvent = Event.getNextEvent( eventType, False )
except NoNextEventException:
return
countdown = dict()
if EventParticipation.isMember( username ):
part = EventParticipation.objects.filter( user = username ).filter( event = nextEvent )
countdown['participation'] = part[0].status
eventTime = nextEvent.displaydatetime
countdown['event'] = nextEvent
countdown['epoch'] = int( (eventTime - datetime.now() ).total_seconds() * 1000 )
context["countdown"] = countdown
def addEventRouteForNextEventToContext( context, username, eventType = ""):
"""Returns an object that has to be added to the render context on the page where the route
should be displayed . The starting address of the route will be the home of the specified user"""
try:
nextEvent = Event.getNextEvent( eventType, True )
except NoNextEventException:
return
routeInfo = dict()
routeInfo['event'] = nextEvent
musician = Musician.objects.get( user = username );
routeInfo['origin'] = musician.street + ", " + str( musician.zip_code ) + " " + musician.city
if nextEvent.map_location:
# map_location has format "lat,longitute,zoomlevel"
routeInfo['destination'] = ",".join( nextEvent.map_location.split(",")[:2] )
else:
routeInfo['destination'] = nextEvent.location
context["route"] = routeInfo

View File

@ -3,12 +3,10 @@
Context:
Coordinates or textual adresses:
{{routeInfo.origin}}
{{routeInfo.destination}}
{{route.origin}}
{{route.destination}}
Event object:
{{nextConcert}}
{{route.event}}
{% endcomment %}
@ -16,9 +14,8 @@
{% load sekizai_tags staticfiles %}
{% if hasNextConcertInfo %}
{% if route %}
{% addtoblock "css" strip %}<link rel="stylesheet" href="{{STATIC_URL}}/css/concert_route.css" type="text/css" media="screen" />{% endaddtoblock %}
{% addtoblock "js" strip %}<script type="text/javascript" src="//maps.google.com/maps/api/js?sensor=false&amp;language=de"></script>{% endaddtoblock %}
@ -86,10 +83,10 @@
google.maps.event.addDomListener(controlUI, 'click', function()
{
{% if not nextConcert.map_location %}
{% if not route.event.map_location %}
geocoder = new google.maps.Geocoder();
geocoder.region = "de";
geocoder.geocode( {"address": "{{ nextConcert.location }}" }, function(results, status) {
geocoder.geocode( {"address": "{{ route.event.location }}" }, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setMapTypeId( google.maps.MapTypeId.HYBRID );
map.setZoom( 15 );
@ -98,7 +95,7 @@
}
});
{% else %}
var loc = new google.maps.LatLng( {{ nextConcert.map_location }} );
var loc = new google.maps.LatLng( {{ route.event.map_location }} );
map.setMapTypeId( google.maps.MapTypeId.HYBRID );
map.setZoom( 20 );
@ -127,8 +124,8 @@
directionsDisplay.setMap( map );
var request = {
origin: "{{routeInfo.origin}}",
destination: "{{routeInfo.destination}}",
origin: "{{route.origin}}",
destination: "{{route.destination}}",
travelMode: google.maps.DirectionsTravelMode.DRIVING
}
@ -180,8 +177,8 @@
<!--
</div>
Nächstes Konzert ist in <br> <em>{{nextConcert.location}}</em> <br> am {{nextConcert.date | date:"SHORT_DATE_FORMAT" }} um {{nextConcert.time | time:"H:i" }} Uhr <br/>
{% if nextConcert.meeting_time %} Treffpunkt ist um {{ nextConcert.meeting_time | time:"H:i" }} Uhr <br/> {% endif %}
Nächstes Konzert ist in <br> <em>{{route.event.location}}</em> <br> am {{route.event.date | date:"SHORT_DATE_FORMAT" }} um {{route.event.time | time:"H:i" }} Uhr <br/>
{% if route.event.meeting_time %} Treffpunkt ist um {{ route.event.meeting_time | time:"H:i" }} Uhr <br/> {% endif %}
<table>
<tr> <td> Fahrzeit:</td> <td> <span id="route_duration"></span> </td> </tr>
@ -189,10 +186,10 @@
</table>
-->
<table class="table table-striped table-condensed">
<tr><td>Ort: </td> <td> {{nextConcert.location}} </td> </tr>
<tr><td>Datum: </td> <td> {{nextConcert.date | date:"D, d.m.y" }} </td> </tr>
<tr><td>Uhrzeit: </td> <td> {{nextConcert.time | time:"H:i" }} Uhr </td> </tr>
{% if nextConcert.meeting_time %} <tr><td>Treffen um: </td> <td> {{ nextConcert.meeting_time | time:"H:i" }} Uhr </td> </tr> {% endif %}
<tr><td>Ort: </td> <td> {{route.event.location}} </td> </tr>
<tr><td>Datum: </td> <td> {{route.event.date | date:"D, d.m.y" }} </td> </tr>
<tr><td>Uhrzeit: </td> <td> {{route.event.time | time:"H:i" }} Uhr </td> </tr>
{% if route.event.meeting_time %} <tr><td>Treffen um: </td> <td> {{route.event.meeting_time | time:"H:i" }} Uhr </td> </tr> {% endif %}
<tr> <td> Fahrzeit:</td> <td> <span id="route_duration"></span> </td> </tr>
<tr> <td> Strecke: </td> <td> <span id="route_distance"></span> </td> </tr>
</table>

View File

@ -60,7 +60,7 @@
});
$.get( "/login/usernames", function( data ) {
$.get( "/musicians/login/usernames", function( data ) {
$("#username").autocomplete( { source: data } );
});
});

View File

@ -6,6 +6,9 @@ import musicians.views
urlpatterns = patterns('',
url(r'^$', musicians.views.addressbook ),
url(r'^profile$', musicians.views.own_profile ),
#url(r'^(?P<username>[\w]+)$$', musicians.views.user_edit ),
url(r'^changePassword/$', musicians.views.change_password ),
url(r'^login/$', musicians.views.login_view),
url(r'^login/usernames$', musicians.views.userlistForAutocompletion),
url(r'^logout/$', musicians.views.logout_view),
)

View File

@ -79,9 +79,76 @@ def addressbook( request ):
return render( request, 'musicians/addressbook.html', context )
############################################################################################################
######################### User Management Views ############################################################
############################################################################################################
from django.contrib.auth.views import password_change
from django.contrib.auth import authenticate, login, logout
from django.shortcuts import redirect
from django.http import HttpResponse
from django.utils import simplejson
from django.contrib.auth.models import User
from datetime import timedelta
def change_password( request ):
return password_change(request, "musicians/change_password.html", post_change_redirect= "/" )
def logout_view(request):
logout( request )
return redirect( login_view )
def userlistForAutocompletion(request):
result = [ u.username for u in User.objects.all() ]
return HttpResponse( simplejson.dumps(result), mimetype='application/json' )
def login_view( request ):
if request.method == 'POST': # If the form has been submitted...
raiseFirstLetter = lambda s: s[:1].upper() + s[1:] if s else ''
username = raiseFirstLetter( request.POST['username'] )
password = request.POST['password']
user = authenticate( username=username, password=password )
result = dict()
result['err'] = ""
if user is not None:
if user.is_active:
if not request.POST.get('remember', None):
# Expire in one year
request.session.set_expiry( timedelta( weeks=52 ) )
else:
# Expire on browser close
request.session.set_expiry( 0 )
login(request, user)
result['redirect'] = "/"
print ( "Setting Redirect" )
if 'next' in request.POST :
result['redirect'] = request.POST["next"]
print ( "Using " + request.POST["next"] )
else:
result['err'] = "Dein Account wurde deaktiviert."
# Return a 'disabled account' error message
else:
result['err'] = "Falscher Benutzername oder falsches Kennwort."
return HttpResponse( simplejson.dumps(result), mimetype='application/json' )
else:
# Check if user already logged in
if request.user.is_authenticated():
return redirect( "/")
if 'next' in request.GET:
nextPage = request.GET['next']
else:
nextPage = "/"
return render( request, 'musicians/login.html', { 'next' : nextPage } )

View File

@ -48,8 +48,8 @@
</a>
<ul class="dropdown-menu">
<li><a href="/musicians/profile">Eigenes Profil</a></li>
<li><a href="/changePassword">Passwort ändern</a> </li>
<li><a href="/logout"> Logout</a></li>
<li><a href="/musicians/changePassword">Passwort ändern</a> </li>
<li><a href="/musicians/logout"> Logout</a></li>
</ul>
</li>
{% endif %}

View File

@ -1,14 +1,12 @@
{% extends "website/base.html" %}
{% load sekizai_tags staticfiles %}
{% block content %}
{% include "website/event_countdown.html" %}
{% include "website/concert_route.html" %}
{% include "eventplanner/countdown.inc.html" %}
{% include "eventplanner/routeToEventMap.inc.html" %}
{% endblock %}

View File

@ -1,13 +1,9 @@
from django.conf.urls import patterns, url
from website.views import home_view, login_view, userlistForAutocompletion,logout_view, change_password
from website.views import home_view
urlpatterns = patterns('',
url(r'$^', home_view ),
url(r'^login/$', login_view),
url(r'^login/usernames$', userlistForAutocompletion),
url(r'^logout/$', logout_view),
url(r'^changePassword/$', change_password),
url(r'$^', home_view ),
)

View File

@ -1,20 +1,8 @@
# Create your views here.
from django.shortcuts import render
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponse
from django.utils import simplejson
from django.contrib.auth.decorators import login_required
from eventplanner.models import Event, EventParticipation
from musicians.models import Musician
from datetime import datetime
from datetime import timedelta
from django.contrib.auth.models import User
from eventplanner.snippets import addEventCountdownForNextEventToContext, addEventRouteForNextEventToContext
from eventplanner.models import EventParticipation
@login_required
@ -25,117 +13,8 @@ def home_view(request):
if EventParticipation.isMember( request.user ):
context['hasParticipationSetForAllEvents'] = EventParticipation.hasUserSetParticipationForAllEvents( request.user)
# Countdown
countdown = dict()
events = Event.objects.filter( date__gte = datetime.now() ).order_by('date')[:3]
if ( len(events) > 0 ):
i = 0
nextEvent = events[0]
while nextEvent.displaydatetime < datetime.now():
if len(events ) <= i:
return
else:
i += 1
nextEvent = events[i]
if EventParticipation.isMember( request.user ):
part = EventParticipation.objects.filter( user = request.user ).filter( event = nextEvent )
countdown['participation'] = part[0].status
eventTime = nextEvent.displaydatetime
countdown['event'] = nextEvent
countdown['epoch'] = int( (eventTime - datetime.now() ).total_seconds() * 1000 )
context['countdown'] = countdown
# Route to concert
nextConcerts = Event.objects.filter( date__gte = datetime.now(), type = 'Conc' ).order_by('date')[:1]
if len( nextConcerts) > 0 :
nextConcert = nextConcerts[0]
routeInfo = dict()
musician = Musician.objects.get( user = request.user );
routeInfo['origin'] = musician.street + ", " + str( musician.zip_code ) + " " + musician.city
if nextConcert.map_location:
# map_location has format "lat,longitute,zoomlevel"
routeInfo['destination'] = ",".join( nextConcert.map_location.split(",")[:2] )
else:
routeInfo['destination'] = nextConcert.location
context['routeInfo'] = routeInfo
context['nextConcert'] = nextConcert
context['hasNextConcertInfo'] = True
else:
context['hasNextConcertInfo'] = False
addEventCountdownForNextEventToContext( context, request.user );
addEventRouteForNextEventToContext(context, request.user, 'Conc' )
return render( request, 'website/mainpage.html', context )
def logout_view(request):
logout( request )
return redirect( login_view )
def userlistForAutocompletion(request):
result = [ u.username for u in User.objects.all() ]
return HttpResponse( simplejson.dumps(result), mimetype='application/json' )
def login_view( request ):
if request.method == 'POST': # If the form has been submitted...
raiseFirstLetter = lambda s: s[:1].upper() + s[1:] if s else ''
username = raiseFirstLetter( request.POST['username'] )
password = request.POST['password']
user = authenticate( username=username, password=password )
result = dict()
result['err'] = ""
if user is not None:
if user.is_active:
if not request.POST.get('remember', None):
# Expire in one year
request.session.set_expiry( timedelta( weeks=52 ) )
else:
# Expire on browser close
request.session.set_expiry( 0 )
login(request, user)
result['redirect'] = "/"
print ( "Setting Redirect" )
if 'next' in request.POST :
result['redirect'] = request.POST["next"]
print ( "Using " + request.POST["next"] )
else:
result['err'] = "Dein Account wurde deaktiviert."
# Return a 'disabled account' error message
else:
result['err'] = "Falscher Benutzername oder falsches Kennwort."
return HttpResponse( simplejson.dumps(result), mimetype='application/json' )
else:
# Check if user already logged in
if request.user.is_authenticated():
return redirect( "/")
if 'next' in request.GET:
nextPage = request.GET['next']
else:
nextPage = "/"
return render( request, 'website/login.html', { 'next' : nextPage } )
import django.contrib.auth.views
from django.core.urlresolvers import reverse
def change_password( request ):
template_name = "website/change_password.html"
return django.contrib.auth.views.password_change(request, template_name, post_change_redirect= "/" )