Event resturcturing

- new short_description field instead of title
- autosave text

- autocompletion on login
This commit is contained in:
Martin Bauer
2013-09-28 18:57:19 +02:00
parent 6c3a7ca408
commit d71c35bcd7
32 changed files with 639 additions and 118 deletions

View File

@@ -10,7 +10,7 @@ class EventParticipationInline(admin.TabularInline):
has_add_permission = lambda self, req : False
has_delete_permission = lambda self, req, obj : False
template = "custom_tabular.html"
template = "eventplanner/admin_tabular.html"
class EventAdmin(admin.ModelAdmin):

Binary file not shown.

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-06-30 16:58+0200\n"
"POT-Creation-Date: 2013-09-28 16:56+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -18,95 +18,102 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: models.py:10
#: models.py:14
msgid "Rehearsal"
msgstr "Probe"
#: models.py:11
#: models.py:15
msgid "Concert"
msgstr "Konzert"
#: models.py:12
msgid "General Rehearsal"
msgstr "Generalprobe"
#: models.py:13
#: models.py:16
msgid "Party"
msgstr "Feier"
#: models.py:16
msgid "title"
msgstr "Titel"
#: models.py:17
msgid "Travel"
msgstr "Dienstreise"
#: models.py:20
msgid "type"
msgstr "Typ"
#: models.py:18
#: models.py:21
msgid "Short Description"
msgstr "Kurzbeschreibung"
#: models.py:22
msgid "location"
msgstr "Ort"
#: models.py:19
#: models.py:23
msgid "Location on map"
msgstr "Ort auf Karte"
#: models.py:24
msgid "description"
msgstr "Beschreibung"
#: models.py:21
#: models.py:26
msgid "date"
msgstr "Datum"
#: models.py:22
#: models.py:27
msgid "time"
msgstr "Uhrzeit"
#: models.py:23
#: models.py:28
msgid "meeting_time"
msgstr "Treffen um"
#: models.py:25
#: models.py:30
msgid "End Date"
msgstr "Bis:"
#: models.py:32
msgid "participants"
msgstr "Teilnehmer"
#: models.py:45
#: models.py:64
msgid "?"
msgstr ""
msgstr "?"
#: models.py:46
#: models.py:65
msgid "Yes"
msgstr "Ja"
#: models.py:47
#: models.py:66
msgid "No"
msgstr "Nein"
#: models.py:50
#: models.py:69
msgid "event"
msgstr "Termin"
#: models.py:51
msgid "musician"
msgstr "Musiker"
#: models.py:70
msgid "user"
msgstr "Benutzer"
#: models.py:52
#: models.py:71
msgid "status"
msgstr "Status"
#: models.py:53
#: models.py:72
msgid "comment"
msgstr "Kommentar"
#: models.py:72
#: models.py:100
msgid "Can modify participation status of other users"
msgstr ""
msgstr "Darf Teilnahmestatus von anderen ändern"
#: templates/custom_tabular.html:17
msgid "Delete?"
msgstr "Löschen"
#~ msgid "General Rehearsal"
#~ msgstr "Generalprobe"
#: templates/custom_tabular.html:74
#, python-format
msgid "Add another %(verbose_name)s"
msgstr ""
#~ msgid "title"
#~ msgstr "Titel"
#: templates/custom_tabular.html:75
msgid "Remove"
msgstr ""
#~ msgid "musician"
#~ msgstr "Musiker"
#~ msgid "Delete?"
#~ msgstr "Löschen"

View File

@@ -0,0 +1,112 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'Event'
db.create_table(u'eventplanner_event', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('type', self.gf('django.db.models.fields.CharField')(default='Reh', max_length=6)),
('short_desc', self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True)),
('location', self.gf('django.db.models.fields.TextField')()),
('map_location', self.gf('location_field.models.PlainLocationField')(max_length=63)),
('desc', self.gf('django.db.models.fields.TextField')(blank=True)),
('date', self.gf('django.db.models.fields.DateField')()),
('time', self.gf('django.db.models.fields.TimeField')(null=True, blank=True)),
('meeting_time', self.gf('django.db.models.fields.TimeField')(null=True, blank=True)),
('end_date', self.gf('django.db.models.fields.DateField')(null=True)),
))
db.send_create_signal(u'eventplanner', ['Event'])
# Adding model 'EventParticipation'
db.create_table(u'eventplanner_eventparticipation', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('event', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['eventplanner.Event'])),
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
('status', self.gf('django.db.models.fields.CharField')(default='?', max_length=3)),
('comment', self.gf('django.db.models.fields.CharField')(max_length=64, blank=True)),
))
db.send_create_signal(u'eventplanner', ['EventParticipation'])
# Adding unique constraint on 'EventParticipation', fields ['event', 'user']
db.create_unique(u'eventplanner_eventparticipation', ['event_id', 'user_id'])
def backwards(self, orm):
# Removing unique constraint on 'EventParticipation', fields ['event', 'user']
db.delete_unique(u'eventplanner_eventparticipation', ['event_id', 'user_id'])
# Deleting model 'Event'
db.delete_table(u'eventplanner_event')
# Deleting model 'EventParticipation'
db.delete_table(u'eventplanner_eventparticipation')
models = {
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'eventplanner.event': {
'Meta': {'object_name': 'Event'},
'date': ('django.db.models.fields.DateField', [], {}),
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'end_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'location': ('django.db.models.fields.TextField', [], {}),
'map_location': ('location_field.models.PlainLocationField', [], {'max_length': '63'}),
'meeting_time': ('django.db.models.fields.TimeField', [], {'null': 'True', 'blank': 'True'}),
'participants': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.User']", 'through': u"orm['eventplanner.EventParticipation']", 'symmetrical': 'False'}),
'short_desc': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'time': ('django.db.models.fields.TimeField', [], {'null': 'True', 'blank': 'True'}),
'type': ('django.db.models.fields.CharField', [], {'default': "'Reh'", 'max_length': '6'})
},
u'eventplanner.eventparticipation': {
'Meta': {'unique_together': "(('event', 'user'),)", 'object_name': 'EventParticipation'},
'comment': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['eventplanner.Event']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'status': ('django.db.models.fields.CharField', [], {'default': "'?'", 'max_length': '3'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
}
}
complete_apps = ['eventplanner']

View File

View File

@@ -13,24 +13,26 @@ class Event ( models.Model ):
EVENT_TYPES = (
( 'Reh', _('Rehearsal') ),
( 'Conc', _('Concert') ),
( 'GenReh', _('General Rehearsal') ),
( 'Party', _('Party') ),
( 'Travel', _('Travel') )
)
title = models.CharField( max_length=40, verbose_name = _("titel") )
type = models.CharField( max_length=6, choices=EVENT_TYPES, default='Reh', verbose_name= _("type") )
short_desc = models.CharField( null=True, max_length=100, blank = True, verbose_name= _("Short Description") )
location = models.TextField( blank=False, verbose_name=_("location") )
map_location = PlainLocationField( based_field = location, zoom=7 )
desc = models.TextField( blank=True, verbose_name=_("description"))
map_location = PlainLocationField(blank=True, based_field = location, zoom=7, verbose_name=_("Location on map") )
desc = models.TextField( blank=True, verbose_name=_("description") )
date = models.DateField( verbose_name= _("date") )
time = models.TimeField( null=True, blank=True, verbose_name = _("time") )
meeting_time = models.TimeField( null=True, blank=True, verbose_name = _("meeting_time") )
end_date = models.DateField( null=True, blank = True, verbose_name = _("End Date") )
participants = models.ManyToManyField( User, through='EventParticipation', verbose_name=_("participants") )
def __unicode__(self):
return self.title + " ( " + self.get_type_display() + " ) "
return self.title
def save(self, *args, **kwargs):
@@ -42,6 +44,14 @@ class Event ( models.Model ):
if not u in self.participants.all():
EventParticipation.objects.create( event=self, user = u, status='?', comment = '' )
@property
def title(self):
res = self.get_type_display()
if ( self.short_desc ):
res += " ( " + self.short_desc + " ) "
return res
@property
def displaytime(self):
if self.meeting_time is None or self.meeting_time == "":

View File

@@ -0,0 +1,78 @@
{% load i18n admin_static admin_modify %}
<div class="inline-group" id="{{ inline_admin_formset.formset.prefix }}-group">
<div class="tabular inline-related {% if forloop.last %}last-related{% endif %}">
{{ inline_admin_formset.formset.management_form }}
<fieldset class="module">
<h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h2>
{{ inline_admin_formset.formset.non_form_errors }}
<table>
<thead><tr>
{% for field in inline_admin_formset.fields %}
{% if not field.widget.is_hidden %}
<th{% if forloop.first %} colspan="2"{% endif %}{% if field.required %} class="required"{% endif %}>{{ field.label|capfirst }}
{% if field.help_text %}&nbsp;<img src="{% static "admin/img/icon-unknown.gif" %}" class="help help-tooltip" width="10" height="10" alt="({{ field.help_text|striptags }})" title="{{ field.help_text|striptags }}" />{% endif %}
</th>
{% endif %}
{% endfor %}
{% if inline_admin_formset.formset.can_delete %}<th>{% trans "Delete?" %}</th>{% endif %}
</tr></thead>
<tbody>
{% for inline_admin_form in inline_admin_formset %}
{% if inline_admin_form.form.non_field_errors %}
<tr><td colspan="{{ inline_admin_form|cell_count }}">{{ inline_admin_form.form.non_field_errors }}</td></tr>
{% endif %}
<tr class="form-row {% cycle "row1" "row2" %} {% if forloop.last %} empty-form{% endif %}"
id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
<td class="original">
{% if inline_admin_form.original or inline_admin_form.show_url %}<p>
</p>{% endif %}
{% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
{{ inline_admin_form.fk_field.field }}
{% spaceless %}
{% for fieldset in inline_admin_form %}
{% for line in fieldset %}
{% for field in line %}
{% if field.is_hidden %} {{ field.field }} {% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endspaceless %}
</td>
{% for fieldset in inline_admin_form %}
{% for line in fieldset %}
{% for field in line %}
<td{% if field.field.name %} class="field-{{ field.field.name }}"{% endif %}>
{% if field.is_readonly %}
<p>{{ field.contents|linebreaksbr }}</p>
{% else %}
{{ field.field.errors.as_ul }}
{{ field.field }}
{% endif %}
</td>
{% endfor %}
{% endfor %}
{% endfor %}
{% if inline_admin_formset.formset.can_delete %}
<td class="delete">{% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %}</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</fieldset>
</div>
</div>
<script type="text/javascript">
(function($) {
$("#{{ inline_admin_formset.formset.prefix }}-group .tabular.inline-related tbody tr").tabularFormset({
prefix: "{{ inline_admin_formset.formset.prefix }}",
adminStaticPrefix: '{% static "admin/" %}',
addText: "{% blocktrans with inline_admin_formset.opts.verbose_name|title as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}",
deleteText: "{% trans 'Remove' %}"
});
})(django.jQuery);
</script>

View File

@@ -22,11 +22,7 @@
<div class="row">
<div class="span12">
<h3>Termin bearbeiten</h3>
<!--
<form action="/contact/" method="post">
{% csrf_token %} {{ form.as_p }} <input type="submit" value="Submit" />
</form>
-->
{% crispy form %}
</div>
@@ -52,8 +48,8 @@
<script>
$(document).ready(function(){
$('.dateinput').datepicker({
format: "dd.mm.yyyy",
weekStart: 1,
@@ -62,17 +58,57 @@ $(document).ready(function(){
todayHighlight: true,
startDate: "{% now "SHORT_DATE_FORMAT" %}",
});
$('.timeinput').addClass('input-small').wrap('<div class="input-append bootstrap-timepicker">')
$(".input-append").append( '<span class="add-on"><i class="icon-time"></i></span>' )
$('.timeinput').addClass('input-small').wrap('<div class="input-append bootstrap-timepicker">')
$(".input-append").append( '<span class="add-on"><i class="icon-time"></i></span>' )
$('.timeinput').timepicker({
$('.timeinput').timepicker({
minuteStep: 15,
showMeridian: false,
defaultTime: false
});
function onTypeChange( val )
{
if ( val == "Reh") {
$("#div_id_time").show();
$("#div_id_meeting_time").hide();
$("#div_id_map_location").hide();
$("#div_id_end_date").hide();
if ( ! $("#id_time").val() ) {
$("#id_time").val("19:00");
}
if ( ! $("#id_location").val() ) {
$("#id_location").val("Rohr");
}
}
else if ( val == "Conc" ) {
$("#div_id_time").show();
$("#div_id_meeting_time").show();
$("#div_id_map_location").show();
$("#div_id_end_date").hide();
}
else if ( val == "Party") {
$("#div_id_time").show();
$("#div_id_meeting_time").hide();
$("#div_id_map_location").show();
$("#div_id_end_date").hide();
}
else if ( val == "Travel") {
$("#div_id_time").hide();
$("#div_id_meeting_time").hide();
$("#div_id_map_location").show();
$("#div_id_end_date").show();
}
}
$("#id_type").change( function() {
onTypeChange( $(this).val() );
} );
onTypeChange( $("#id_type").val() );
} );
</script>
{% endaddtoblock %}

View File

@@ -42,6 +42,8 @@
}
function putStatus( button, status ) {
$("#saving").html("Speichere..");
p = button.parent();
putObject = [ { "event": p.data("event-id"),
"user": p.data("username"),
@@ -51,7 +53,8 @@
type: "PUT",
url: "{% url 'event_api' %}",
contentType: "application/json",
data: JSON.stringify(putObject)
data: JSON.stringify(putObject),
success: function() { $("#saving").html("Ok"); }
});
setEventButtonStatus( button, status );
@@ -63,7 +66,8 @@
$(function(){
$(".event-comment").bindWithDelay("keypress", function() {
$("#saving").html("Speichere..");
putObject = [ { "event": $(this).data("event-id"),
"user": $(this).data("username"),
@@ -73,7 +77,8 @@
type: "PUT",
url: "{% url 'event_api' %}",
contentType: "application/json",
data: JSON.stringify(putObject)
data: JSON.stringify(putObject),
success: function() { $("#saving").html("Ok"); }
});
}, 800 );
@@ -98,6 +103,7 @@
<div class="container">
<form>
<div class="row">
<div class="row-fluid eventTable">
<div class="span12">
@@ -112,6 +118,7 @@
<th id='eventTitle'>Termin</th>
<th id='date' >Datum</th>
<th id='time' >Uhrzeit</th>
<th id='time' >Treffpunkt</th>
<th id='place' >Ort</th>
<th id='status' >Status ändern</th>
<th id='comment' >Kommentar</th>
@@ -121,11 +128,16 @@
{% for event in events %}
<tr>
<td class="center"> <a href="{{ event.pk }}"> {{ event.title }} </a> </td>
<td class="center"> {{ event.date }} </td>
<td class="center"> {% if event.time %} {{ event.time }} {% endif %} </td>
<!-- <td class="center"> {{ event.location }} </td> -->
<td class="center"> Ort </td>
{% if not perms.eventplanner.change_event %}
<td class="center"> {{ event.title }} </td>
{% else %}
<td class="center"> <a href="{{ event.pk }}"> {{ event.title }} </a> </td>
{% endif %}
<td class="center"> {{ event.date | date:"SHORT_DATE_FORMAT" }} </td>
<td class="center"> {% if event.time %} {{ event.time | time:"H:i" }} {% endif %} </td>
<td class="center"> {% if event.meeting_time %} {{ event.meeting_time | time:"H:i" }} {% endif %} </td>
<td class="center"> {{ event.location }} </td>
<td class="center">
<div class="btn-group event-status-select" data-event-id="{{event.pk}}" data-username="{{user.username}}" >
@@ -156,6 +168,13 @@
</div><!--/row-->
</div>
</div>
<div class="row">
<div class="span12">
<em>Änderungen werden automatisch gespeichert: </em> <em id="saving">Ok</em>
</div>
</div>
</form>
</div>
{% endblock %}

View File

@@ -129,7 +129,7 @@
{% for event in events %}
<tr class="eventRow">
<td class="center"> <a href="{{ event.pk }}"> {{ event.title }} </a> </td>
<td class="center"> {{ event.date }} </td>
<td class="center"> {{ event.date | date:"SHORT_DATE_FORMAT" }} </td>
{% for p in event.participation %}
@@ -176,7 +176,6 @@
<div class="span12">
<button id="saveButton" class="btn btn-primary" disabled="true">Speichern</button>
</div>
</div>
{% endif %}</form>

View File

@@ -119,7 +119,7 @@ class EventForm( ModelForm ):
class Meta:
model = Event
fields= [ 'type', 'title', 'date','time', 'meeting_time', 'location', 'map_location', 'desc', ]
fields= [ 'type', 'short_desc', 'date', 'end_date', 'time', 'meeting_time', 'location', 'map_location', 'desc', ]
widgets = {
'location' : TextInput(),
@@ -132,13 +132,24 @@ class EventUpdate( UpdateView ):
model = Event
template_name_suffix = "_update_form"
success_url = '.'
def get_context_data(self, **kwargs):
context = super(UpdateView, self).get_context_data(**kwargs)
context['viewtype'] = "update"
return context
class EventCreate( CreateView ):
form_class = EventForm
model = Event
template_name_suffix = "_update_form"
success_url = '.'
def get_context_data(self, **kwargs):
context = super(CreateView, self).get_context_data(**kwargs)
context['viewtype'] = "create"
return context