Merge conflict from master

This commit is contained in:
Tom Price
2015-04-21 19:57:45 +01:00
15 changed files with 12358 additions and 77 deletions

View File

@@ -33,6 +33,8 @@ class RigboardIndex(generic.TemplateView):
context['events'] = models.Event.objects.current_events() context['events'] = models.Event.objects.current_events()
return context return context
class WebCalendar(generic.TemplateView):
template_name = 'RIGS/calendar.html'
class EventDetail(generic.DetailView): class EventDetail(generic.DetailView):
model = models.Event model = models.Event

1061
RIGS/static/css/fullcalendar.css Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,202 @@
/*!
* FullCalendar v2.3.1 Print Stylesheet
* Docs & License: http://fullcalendar.io/
* (c) 2015 Adam Shaw
*/
/*
* Include this stylesheet on your page to get a more printer-friendly calendar.
* When including this stylesheet, use the media='print' attribute of the <link> tag.
* Make sure to include this stylesheet IN ADDITION to the regular fullcalendar.css.
*/
.fc {
max-width: 100% !important;
}
/* Global Event Restyling
--------------------------------------------------------------------------------------------------*/
.fc-event {
background: #fff !important;
color: #000 !important;
page-break-inside: avoid;
}
.fc-event .fc-resizer {
display: none;
}
/* Table & Day-Row Restyling
--------------------------------------------------------------------------------------------------*/
th,
td,
hr,
thead,
tbody,
.fc-row {
border-color: #ccc !important;
background: #fff !important;
}
/* kill the overlaid, absolutely-positioned common components */
.fc-bg,
.fc-bgevent-skeleton,
.fc-highlight-skeleton,
.fc-helper-skeleton {
display: none;
}
/* don't force a min-height on rows (for DayGrid) */
.fc tbody .fc-row {
height: auto !important; /* undo height that JS set in distributeHeight */
min-height: 0 !important; /* undo the min-height from each view's specific stylesheet */
}
.fc tbody .fc-row .fc-content-skeleton {
position: static; /* undo .fc-rigid */
padding-bottom: 0 !important; /* use a more border-friendly method for this... */
}
.fc tbody .fc-row .fc-content-skeleton tbody tr:last-child td { /* only works in newer browsers */
padding-bottom: 1em; /* ...gives space within the skeleton. also ensures min height in a way */
}
.fc tbody .fc-row .fc-content-skeleton table {
/* provides a min-height for the row, but only effective for IE, which exaggerates this value,
making it look more like 3em. for other browers, it will already be this tall */
height: 1em;
}
/* Undo month-view event limiting. Display all events and hide the "more" links
--------------------------------------------------------------------------------------------------*/
.fc-more-cell,
.fc-more {
display: none !important;
}
.fc tr.fc-limited {
display: table-row !important;
}
.fc td.fc-limited {
display: table-cell !important;
}
.fc-popover {
display: none; /* never display the "more.." popover in print mode */
}
/* TimeGrid Restyling
--------------------------------------------------------------------------------------------------*/
/* undo the min-height 100% trick used to fill the container's height */
.fc-time-grid {
min-height: 0 !important;
}
/* don't display the side axis at all ("all-day" and time cells) */
.fc-agenda-view .fc-axis {
display: none;
}
/* don't display the horizontal lines */
.fc-slats,
.fc-time-grid hr { /* this hr is used when height is underused and needs to be filled */
display: none !important; /* important overrides inline declaration */
}
/* let the container that holds the events be naturally positioned and create real height */
.fc-time-grid .fc-content-skeleton {
position: static;
}
/* in case there are no events, we still want some height */
.fc-time-grid .fc-content-skeleton table {
height: 4em;
}
/* kill the horizontal spacing made by the event container. event margins will be done below */
.fc-time-grid .fc-event-container {
margin: 0 !important;
}
/* TimeGrid *Event* Restyling
--------------------------------------------------------------------------------------------------*/
/* naturally position events, vertically stacking them */
.fc-time-grid .fc-event {
position: static !important;
margin: 3px 2px !important;
}
/* for events that continue to a future day, give the bottom border back */
.fc-time-grid .fc-event.fc-not-end {
border-bottom-width: 1px !important;
}
/* indicate the event continues via "..." text */
.fc-time-grid .fc-event.fc-not-end:after {
content: "...";
}
/* for events that are continuations from previous days, give the top border back */
.fc-time-grid .fc-event.fc-not-start {
border-top-width: 1px !important;
}
/* indicate the event is a continuation via "..." text */
.fc-time-grid .fc-event.fc-not-start:before {
content: "...";
}
/* time */
/* undo a previous declaration and let the time text span to a second line */
.fc-time-grid .fc-event .fc-time {
white-space: normal !important;
}
/* hide the the time that is normally displayed... */
.fc-time-grid .fc-event .fc-time span {
display: none;
}
/* ...replace it with a more verbose version (includes AM/PM) stored in an html attribute */
.fc-time-grid .fc-event .fc-time:after {
content: attr(data-full);
}
/* Vertical Scroller & Containers
--------------------------------------------------------------------------------------------------*/
/* kill the scrollbars and allow natural height */
.fc-scroller,
.fc-day-grid-container, /* these divs might be assigned height, which we need to cleared */
.fc-time-grid-container { /* */
overflow: visible !important;
height: auto !important;
}
/* kill the horizontal border/padding used to compensate for scrollbars */
.fc-row {
border: 0 !important;
margin: 0 !important;
}
/* Button Controls
--------------------------------------------------------------------------------------------------*/
.fc-button-group,
.fc button {
display: none; /* don't display any button-related controls */
}

10789
RIGS/static/js/fullcalendar.js Executable file

File diff suppressed because it is too large Load Diff

7
RIGS/static/js/moment.min.js vendored Executable file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,111 @@
{% extends 'base.html' %}
{% load static %}
{% block title %}Calendar{% endblock %}
{% block css %}
<link href="{% static "css/fullcalendar.css" %}" rel='stylesheet' />
<link href="{% static "css/fullcalendar.print.css" %}" rel='stylesheet' media='print' />
{% endblock %}
{% block js %}
{# <script src="//code.jquery.com/jquery-latest.min.js"></script> #}
<script src="{% static "js/moment.min.js" %}"></script>
<script src="{% static "js/fullcalendar.js" %}"></script>
<script>
$(document).ready(function() {
$('#calendar').fullCalendar({
//defaultDate: '2015-02-12',
editable: false,
eventLimit: true, // allow "more" link when too many events
firstDay: 1,
aspectRatio: 1.5,
timeFormat: 'HH:mm',
views: {
basic: {
// options apply to basicWeek and basicDay views
},
agenda: {
// options apply to agendaWeek and agendaDay views
},
week: {
columnFormat:'ddd D/M'
},
day: {
// options apply to basicDay and agendaDay views
}
},
buttonText:{
today: 'Today',
month: 'Month',
week: 'Week',
day: 'Day'
},
header:{
left: 'title',
center: '',
right: 'today prev,next month,agendaWeek,agendaDay'
},
events: function(start_moment, end_moment, timezone, callback) {
$.ajax({
url: '/api/event',
dataType: 'json',
data: {
start: moment(start_moment).format("YYYY-MM-DD[T]HH:mm:ss[Z]"),
end: moment(end_moment).format("YYYY-MM-DD[T]HH:mm:ss[Z]")
},
success: function(doc) {
var events = [];
var colours =
$(doc).each(function() {
thisEvent = [];
colours = {'Provisional': 'orange',
'Confirmed': 'green' ,
'Booked': 'green' ,
'Cancelled': 'grey'
};
thisEvent['start'] = $(this).attr('start_date');
if ($(this).attr('start_time')) {
thisEvent['start'] += 'T' + $(this).attr('start_time');
}
if ($(this).attr('end_date')) {
thisEvent['end'] = $(this).attr('end_date');
if ($(this).attr('end_time')) {
thisEvent['end'] += 'T' + $(this).attr('end_time');
}
}
thisEvent['className'] = 'modal-href';
thisEvent['title'] = $(this).attr('title');
thisEvent['color'] = colours[$(this).attr('status')];
thisEvent['url'] = $(this).attr('url');
events.push(thisEvent);
});
callback(events);
}
});
}
});
});
</script>
{% endblock %}
{% block content %}
<div class="row">
<div style="col-sm-12">
<div id='calendar'>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1,18 +1,27 @@
{% extends 'base.html' %} {% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
{% block title %}Event {% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }} {% block title %}Event {% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}
{% endif %}{% endblock %} {% endif %}{% endblock %}
{% block buttons %}
{% if not request.is_ajax %}
{% endif %}
{% endblock %}
{% block content %} {% block content %}
<div class="row">
{% if not request.is_ajax %}
<div class="col-sm-12"> <div class="col-sm-12">
<div class="col-sm-8"> <div class="col-sm-8">
<h1>Event {% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}{% endif %}</h1> <h1>Event {% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}{% endif %}</h1>
</div> </div>
<div class="col-sm-4 text-right"> <div class="col-sm-12 text-right">
<div class="btn-group btn-page"> <div class="btn-group btn-page">
<a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span <a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-edit"></span></a> class="glyphicon glyphicon-edit"></span></a>
{% if event.is_rig %} {% if event.is_rig %}
<a href="{% url 'event_print' event.pk %}" class="btn btn-default"><span <a href="{% url 'event_print' event.pk %}" target="_blank" class="btn btn-default"><span
class="glyphicon glyphicon-print"></span></a> class="glyphicon glyphicon-print"></span></a>
{% endif %} {% endif %}
<a href="{% url 'event_duplicate' event.pk %}" class="btn btn-default" title="Duplicate Rig"><span <a href="{% url 'event_duplicate' event.pk %}" class="btn btn-default" title="Duplicate Rig"><span
@@ -26,7 +35,7 @@
</div> </div>
</div> </div>
</div> </div>
{% endif %}
{% if object.is_rig %} {% if object.is_rig %}
{# only need contact details for a rig #} {# only need contact details for a rig #}
<div class="col-sm-12 col-md-6 col-lg-5"> <div class="col-sm-12 col-md-6 col-lg-5">
@@ -154,12 +163,13 @@
</div> </div>
</div> </div>
</div> </div>
{% if not request.is_ajax %}
<div class="col-sm-12 text-right"> <div class="col-sm-12 text-right">
<div class="btn-group btn-page"> <div class="btn-group btn-page">
<a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span <a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-edit"></span></a> class="glyphicon glyphicon-edit"></span></a>
{% if event.is_rig %} {% if event.is_rig %}
<a href="{% url 'event_print' event.pk %}" class="btn btn-default"><span <a href="{% url 'event_print' event.pk %}" target="_blank" class="btn btn-default"><span
class="glyphicon glyphicon-print"></span></a> class="glyphicon glyphicon-print"></span></a>
{% endif %} {% endif %}
<a href="{% url 'event_duplicate' event.pk %}" class="btn btn-default" title="Duplicate Rig"><span <a href="{% url 'event_duplicate' event.pk %}" class="btn btn-default" title="Duplicate Rig"><span
@@ -172,6 +182,7 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
{% endif %}
{% if event.is_rig %} {% if event.is_rig %}
<div class="col-sm-12"> <div class="col-sm-12">
<div class="panel panel-default"> <div class="panel panel-default">
@@ -185,22 +196,50 @@
</div> </div>
</div> </div>
</div> </div>
{% if not request.is_ajax %}
<div class="col-sm-12 text-right"> <div class="col-sm-12 text-right">
<div class="btn-group btn-page"> <div class="btn-group btn-page">
<a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span <a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-edit"></span></a> class="glyphicon glyphicon-edit"></span></a>
<a href="{% url 'event_print' event.pk %}" class="btn btn-default"><span <<<<<<< HEAD
{% if event.is_rig %}
<a href="{% url 'event_print' event.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-print"></span></a>
{% endif %}
=======
<a href="{% url 'event_print' event.pk %}" target="_blank" class="btn btn-default"><span
class="glyphicon glyphicon-print"></span></a> class="glyphicon glyphicon-print"></span></a>
>>>>>>> master
<a href="{% url 'event_duplicate' event.pk %}" class="btn btn-default" title="Duplicate Rig"><span <a href="{% url 'event_duplicate' event.pk %}" class="btn btn-default" title="Duplicate Rig"><span
class="glyphicon glyphicon-duplicate"></span></a> class="glyphicon glyphicon-duplicate"></span></a>
{% if perms.RIGS.add_invoice %} {% if event.is_rig %}
<a href="{% url 'invoice_event' event.pk %}" class="btn btn-default" title="Invoice Rig"><span {% if perms.RIGS.add_invoice %}
class="glyphicon glyphicon-gbp"></span></a> <a href="{% url 'invoice_event' event.pk %}" class="btn btn-default" title="Invoice Rig"><span
class="glyphicon glyphicon-gbp"></span></a>
{% endif %}
{% endif %} {% endif %}
</div> </div>
<div>Last edited at {{ object.last_edited_at|date:"SHORT_DATETIME_FORMAT" }} <div>Last edited at {{ object.last_edited_at|date:"SHORT_DATETIME_FORMAT" }}
by {{ object.last_edited_by.name }}. by {{ object.last_edited_by.name }}.
</div> </div>
</div> </div>
{% endif %}
{% endif %} {% endif %}
</div>
{% endblock %} {% endblock %}
{% if request.is_ajax %}
{% block footer %}
<div class="row">
<div class="col-sm-10 align-left">
Lasted edited at {{ object.last_edited_at|date:"SHORT_DATE_FORMAT" }} by {{ object.last_edited_by.name }}
</div>
<div class="col-sm-2">
<div class="pull-right">
<a href="{% url 'event_detail' object.pk %}" class="btn btn-primary">Open Event Page <span
class="glyphicon glyphicon-eye"></span></a>
</div>
</div>
</div>
{% endblock %}
{% endif %}

View File

@@ -53,8 +53,8 @@
<img src="{{ object.mic.profile_picture }}" class="event-mic-photo"/> <img src="{{ object.mic.profile_picture }}" class="event-mic-photo"/>
</td> </td>
<td class="text-right"> <td class="text-right">
<a href="{% url 'invoice_event' object.pk %}" class="btn btn-default"> <a href="{% url 'invoice_event' object.pk %}" target="_blank" class="btn btn-default">
<span class="glyphicon glyphicon-pencil"></span> <span class="glyphicon glyphicon-gbp"></span>
</a> </a>
</td> </td>
</tr> </tr>

View File

@@ -25,7 +25,7 @@
<tfoot> <tfoot>
<tr> <tr>
<td rowspan="3" colspan="2"></td> <td rowspan="3" colspan="2"></td>
<td>Sum Total</td> <td>Total (ex. VAT)</td>
<td colspan="2">£ <span id="sumtotal">{{object.sum_total|default:0|floatformat:2}}</span></td> <td colspan="2">£ <span id="sumtotal">{{object.sum_total|default:0|floatformat:2}}</span></td>
</tr> </tr>
<tr> <tr>

View File

@@ -3,17 +3,23 @@
{% block title %}RIGS Profile {{object.pk}}{% endblock %} {% block title %}RIGS Profile {{object.pk}}{% endblock %}
{% block content %} {% block content %}
<div class="col-sm-10 col-sm-offset-1"> <div class="col-md-10 col-md-offset-1">
<div class="col-sm-10">
<div class="col-sm-12">
<div class="col-sm-6">
<h3>{{object.name}}</h3> <h3>{{object.name}}</h3>
</div> </div>
{% if object.pk == user.pk %} {% if object.pk == user.pk %}
<div class="col-sm-2"> <div class="col-sm-6 text-right">
<div class="pull-right"> <div class="btn-group btn-page">
<a href="{% url 'profile_update_self' %}" class="btn btn-primary"> <a href="{% url 'profile_update_self' %}" class="btn btn-default">
Edit <span class="glyphicon glyphicon-pencil"></span> Edit Profile <span class="glyphicon glyphicon-pencil"></span>
</a> </a>
</div> <a href="{% url 'password_change' %}" class="btn btn-default">
Change Password <span class="glyphicon glyphicon-lock"></span>
</a>
</div>
</div> </div>
{% endif %} {% endif %}
<div class="col-sm-8 "> <div class="col-sm-8 ">

View File

@@ -58,6 +58,7 @@ urlpatterns = patterns('',
# Rigboard # Rigboard
url(r'^rigboard/$', rigboard.RigboardIndex.as_view(), name='rigboard'), url(r'^rigboard/$', rigboard.RigboardIndex.as_view(), name='rigboard'),
url(r'^rigboard/calendar/$', login_required()(rigboard.WebCalendar.as_view()), name='web_calendar'),
url(r'^rigboard/archive/$', RedirectView.as_view(pattern_name='event_archive')), url(r'^rigboard/archive/$', RedirectView.as_view(pattern_name='event_archive')),
url(r'^event/(?P<pk>\d+)/$', url(r'^event/(?P<pk>\d+)/$',
@@ -127,8 +128,5 @@ urlpatterns = patterns('',
url(r'^rig/show/(?P<pk>\d+)/$', RedirectView.as_view(pattern_name='event_detail')), url(r'^rig/show/(?P<pk>\d+)/$', RedirectView.as_view(pattern_name='event_detail')),
url(r'^bookings/$', RedirectView.as_view(pattern_name='rigboard')), url(r'^bookings/$', RedirectView.as_view(pattern_name='rigboard')),
url(r'^bookings/past/$', RedirectView.as_view(pattern_name='event_archive')), url(r'^bookings/past/$', RedirectView.as_view(pattern_name='event_archive')),
# Calendar may have gone away, redirect to the archive for now
url(r'^rigboard/calendar/$',
RedirectView.as_view(pattern_name='event_archive', permanent=False)),
) )

View File

@@ -8,6 +8,7 @@ from django.shortcuts import get_object_or_404
from django.core import serializers from django.core import serializers
import simplejson import simplejson
from django.contrib import messages from django.contrib import messages
import datetime
from RIGS import models, forms from RIGS import models, forms
@@ -194,6 +195,7 @@ class SecureAPIRequest(generic.View):
'person': models.Person, 'person': models.Person,
'organisation': models.Organisation, 'organisation': models.Organisation,
'profile': models.Profile, 'profile': models.Profile,
'event': models.Event,
} }
perms = { perms = {
@@ -201,6 +203,7 @@ class SecureAPIRequest(generic.View):
'person': 'RIGS.view_person', 'person': 'RIGS.view_person',
'organisation': 'RIGS.view_organisation', 'organisation': 'RIGS.view_organisation',
'profile': None, 'profile': None,
'event': 'RIGS.view_event',
} }
''' '''
@@ -261,6 +264,71 @@ class SecureAPIRequest(generic.View):
json = simplejson.dumps(results[:20]) json = simplejson.dumps(results[:20])
return HttpResponse(json, content_type="application/json") # Always json return HttpResponse(json, content_type="application/json") # Always json
start = request.GET.get('start', None)
end = request.GET.get('end', None)
if model == "event" and start and end:
# Probably a calendar request
start_datetime = datetime.datetime.strptime( start, "%Y-%m-%dT%H:%M:%SZ" )
end_datetime = datetime.datetime.strptime( end, "%Y-%m-%dT%H:%M:%SZ" )
all_objects = self.models[model].objects
results = []
filter = Q(start_date__lte=end_datetime) & Q(start_date__gte=start_datetime)
objects = all_objects.filter(filter).select_related('person', 'organisation', 'venue', 'mic').order_by('-start_date')
for item in objects:
data = {
'pk': item.pk,
'title': item.name
}
data['is_rig'] = item.is_rig
data['status'] = str(item.get_status_display())
if item.start_date:
data['start_date'] = item.start_date.strftime('%Y-%m-%d')
if item.start_time:
data['start_time'] = item.start_time.strftime('%H:%M:%SZ')
if item.end_date:
data['end_date'] = item.end_date.strftime('%Y-%m-%d')
if item.end_time:
data['end_time'] = item.end_time.strftime('%H:%M:%SZ')
if item.meet_at:
data['meet_at'] = item.meet_at.strftime('%Y-%m-%dT%H:%M:%SZ')
if item.access_at:
data['access_at'] = item.access_at.strftime('%Y-%m-%dT%H:%M:%SZ')
if item.venue:
data['venue'] = item.venue.name
if item.person:
data['person'] = item.person.name
if item.organisation:
data['organisation'] = item.organisation.name
if item.mic:
data['mic'] = {
'name':item.mic.get_full_name(),
'initials':item.mic.initials
}
if item.description:
data['description'] = item.description
if item.notes:
data['notes'] = item.notes
data['url'] = str(reverse_lazy('event_detail',kwargs={'pk':item.pk}))
results.append(data)
json = simplejson.dumps(results)
return HttpResponse(json, content_type="application/json") # Always json
return HttpResponse(model) return HttpResponse(model)
class ProfileDetail(generic.DetailView): class ProfileDetail(generic.DetailView):
@@ -295,4 +363,4 @@ class ResetApiKey(generic.RedirectView):
self.request.user.save() self.request.user.save()
return reverse_lazy('profile_detail') return reverse_lazy('profile_detail')

View File

@@ -42,6 +42,7 @@
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="{% url 'rigboard' %}">Rigboard</a></li> <li><a href="{% url 'rigboard' %}">Rigboard</a></li>
<li><a href="{% url 'event_archive' %}">Archive</a></li> <li><a href="{% url 'event_archive' %}">Archive</a></li>
<li><a href="{% url 'web_calendar' %}">Calendar</a></li>
</ul> </ul>
</li> </li>
{% if perms.RIGS.view_invoice %} {% if perms.RIGS.view_invoice %}

View File

@@ -0,0 +1,20 @@
{% extends "base.html" %}
{% load i18n %}
{% load url from future %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; {% trans 'Password reset' %}
</div>
{% endblock %}
{% block title %}{% trans 'Password change successful' %}{% endblock %}
{% block content %}
<div class="col-sm-12">
<h1>{% trans 'Password change successful' %}</h1>
<p>{% trans "Your password has been changed" %}</p>
</div>
{% endblock %}

View File

@@ -1,56 +1,33 @@
{% extends "admin/base_site.html" %} {% extends "base.html" %}
{% load i18n static %} {% load widget_tweaks %}
{% load url from future %} {% load url from future %}
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />{% endblock %}
{% block userlinks %}{% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %} {% trans 'Change password' %} / <a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>{% endblock %} {% block title %}Change Password{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumbs"> {% block content %}
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; {% trans 'Password change' %} <div class="col-sm-10 col-sm-offset-1">
</div> <h3>Change Password</h3>
{% endblock %} {% if form.errors or supplement_form.errors %}
<div class="alert alert-danger">
{% block title %}{% trans 'Password change' %}{% endblock %} Please correct the error(s) below.
{{form.errors}}
{% block content %}<div id="content-main"> {{supplement_form.errors}}
</div>
<form action="" method="post">{% csrf_token %} {% endif %}
<div> <p>Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly.</p>
{% if form.errors %}
<p class="errornote"> <div class="col-sm-8 col-sm-offset-2">
{% blocktrans count counter=form.errors.items|length %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %} <form action="" method="post" class="form-horizontal" role="form">{% csrf_token %}
</p> {% for field in form %}
{% endif %} <div class="form-group">
<label for="{{ field.id_for_label }}" class="control-label col-sm-4">{{ field.label }}</label>
<h1>{% trans 'Password change' %}</h1> <div class="controls col-sm-8">
{% render_field field class+="form-control" placeholder=field.label %}
<p>{% trans "Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly." %}</p> </div>
</div>
<fieldset class="module aligned wide"> {% endfor %}
<p><input type="submit" value="Change Password" class="btn btn-primary pull-right"></p>
<div class="form-row"> </form>
{{ form.old_password.errors }} </div>
<label for="id_old_password" class="required">{% trans 'Old password' %}:</label>{{ form.old_password }}
</div>
<div class="form-row">
{{ form.new_password1.errors }}
<label for="id_new_password1" class="required">{% trans 'New password' %}:</label>{{ form.new_password1 }}
</div>
<div class="form-row">
{{ form.new_password2.errors }}
<label for="id_new_password2" class="required">{% trans 'Password (again)' %}:</label>{{ form.new_password2 }}
</div>
</fieldset>
<div class="submit-row">
<input type="submit" value="{% trans 'Change my password' %}" class="default" />
</div>
<script type="text/javascript">document.getElementById("id_old_password").focus();</script>
</div>
</form></div>
{% endblock %} {% endblock %}