program: as_xml
This commit is contained in:
parent
d988a11a71
commit
afedd6635b
|
@ -7,6 +7,8 @@ from django.dispatch import receiver
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.translation import ugettext_noop
|
from django.utils.translation import ugettext_noop
|
||||||
|
|
||||||
|
from ponyconf.decorators import disable_for_loaddata
|
||||||
|
|
||||||
from .models import Connector, Participation, Profile, Transport
|
from .models import Connector, Participation, Profile, Transport
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,8 +38,8 @@ def on_user_logged_out(sender, request, **kwargs):
|
||||||
messages.success(request, _('Goodbye!'), fail_silently=True) # FIXME
|
messages.success(request, _('Goodbye!'), fail_silently=True) # FIXME
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=User, weak=False, dispatch_uid='create_profile')
|
||||||
|
@disable_for_loaddata
|
||||||
def create_profile(sender, instance, created, **kwargs):
|
def create_profile(sender, instance, created, **kwargs):
|
||||||
if created:
|
if created:
|
||||||
Profile.objects.create(user=instance)
|
Profile.objects.create(user=instance)
|
||||||
|
|
||||||
post_save.connect(create_profile, sender=User, weak=False, dispatch_uid='create_profile')
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ from django.db.models import Q
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
from ponyconf.decorators import disable_for_loaddata
|
||||||
from accounts.models import Participation
|
from accounts.models import Participation
|
||||||
from proposals.models import Talk
|
from proposals.models import Talk
|
||||||
from proposals.signals import talk_added, talk_edited
|
from proposals.signals import talk_added, talk_edited
|
||||||
|
@ -11,6 +12,7 @@ from .models import ConversationAboutTalk, ConversationWithParticipant, Message
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Participation, dispatch_uid="Create ConversationWithParticipant")
|
@receiver(post_save, sender=Participation, dispatch_uid="Create ConversationWithParticipant")
|
||||||
|
@disable_for_loaddata
|
||||||
def create_conversation_with_participant(sender, instance, created, **kwargs):
|
def create_conversation_with_participant(sender, instance, created, **kwargs):
|
||||||
if not created:
|
if not created:
|
||||||
return
|
return
|
||||||
|
@ -19,6 +21,7 @@ def create_conversation_with_participant(sender, instance, created, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Talk, dispatch_uid="Create ConversationAboutTalk")
|
@receiver(post_save, sender=Talk, dispatch_uid="Create ConversationAboutTalk")
|
||||||
|
@disable_for_loaddata
|
||||||
def create_conversation_about_talk(sender, instance, created, **kwargs):
|
def create_conversation_about_talk(sender, instance, created, **kwargs):
|
||||||
if not created:
|
if not created:
|
||||||
return
|
return
|
||||||
|
@ -53,6 +56,7 @@ def notify_talk_edited(sender, instance, author, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Message, dispatch_uid="Notify new message")
|
@receiver(post_save, sender=Message, dispatch_uid="Notify new message")
|
||||||
|
@disable_for_loaddata
|
||||||
def notify_new_message(sender, instance, created, **kwargs):
|
def notify_new_message(sender, instance, created, **kwargs):
|
||||||
if not created:
|
if not created:
|
||||||
# Possibly send a modification notification?
|
# Possibly send a modification notification?
|
||||||
|
|
|
@ -10,7 +10,7 @@ from itertools import islice
|
||||||
|
|
||||||
from .models import Room
|
from .models import Room
|
||||||
|
|
||||||
from proposals.models import Talk
|
from proposals.models import Conference, Talk
|
||||||
|
|
||||||
|
|
||||||
Event = namedtuple('Event', ['talk', 'row', 'rowcount'])
|
Event = namedtuple('Event', ['talk', 'row', 'rowcount'])
|
||||||
|
@ -18,6 +18,7 @@ Event = namedtuple('Event', ['talk', 'row', 'rowcount'])
|
||||||
|
|
||||||
class Program:
|
class Program:
|
||||||
def __init__(self, site, empty_rooms=False, talk_filter=None):
|
def __init__(self, site, empty_rooms=False, talk_filter=None):
|
||||||
|
self.site = site
|
||||||
self.talks = Talk.objects.\
|
self.talks = Talk.objects.\
|
||||||
filter(site=site, room__isnull=False, start_date__isnull=False).\
|
filter(site=site, room__isnull=False, start_date__isnull=False).\
|
||||||
filter(Q(duration__gt=0) | Q(event__duration__gt=0)).\
|
filter(Q(duration__gt=0) | Q(event__duration__gt=0)).\
|
||||||
|
@ -49,17 +50,6 @@ class Program:
|
||||||
if dt2 not in self.days[d2]['timeslots']:
|
if dt2 not in self.days[d2]['timeslots']:
|
||||||
self.days[d2]['timeslots'].append(dt2)
|
self.days[d2]['timeslots'].append(dt2)
|
||||||
|
|
||||||
self.cols = OrderedDict([(room, 1) for room in self.rooms])
|
|
||||||
for day in self.days.keys():
|
|
||||||
self.days[day]['timeslots'] = sorted(self.days[day]['timeslots'])
|
|
||||||
self.days[day]['rows'] = OrderedDict([(timeslot, OrderedDict([(room, []) for room in self.rooms])) for timeslot in self.days[day]['timeslots'][:-1]])
|
|
||||||
|
|
||||||
for talk in self.talks.exclude(plenary=True).all():
|
|
||||||
self._add_talk(talk)
|
|
||||||
|
|
||||||
for talk in self.talks.filter(plenary=True).all():
|
|
||||||
self._add_talk(talk)
|
|
||||||
|
|
||||||
def _add_talk(self, talk):
|
def _add_talk(self, talk):
|
||||||
room = talk.room
|
room = talk.room
|
||||||
dt1 = talk.start_date
|
dt1 = talk.start_date
|
||||||
|
@ -150,9 +140,111 @@ class Program:
|
||||||
timeslot = '<td>%s – %s</td>' % tuple(map(date_to_string, [start, end]))
|
timeslot = '<td>%s – %s</td>' % tuple(map(date_to_string, [start, end]))
|
||||||
return style, timeslot
|
return style, timeslot
|
||||||
|
|
||||||
def __str__(self):
|
def as_html(self):
|
||||||
template = """<table class="table table-bordered text-center">\n%(header)s\n%(body)s\n</table>"""
|
template = """<table class="table table-bordered text-center">\n%(header)s\n%(body)s\n</table>"""
|
||||||
|
|
||||||
|
self.cols = OrderedDict([(room, 1) for room in self.rooms])
|
||||||
|
for day in self.days.keys():
|
||||||
|
self.days[day]['timeslots'] = sorted(self.days[day]['timeslots'])
|
||||||
|
self.days[day]['rows'] = OrderedDict([(timeslot, OrderedDict([(room, []) for room in self.rooms])) for timeslot in self.days[day]['timeslots'][:-1]])
|
||||||
|
|
||||||
|
for talk in self.talks.exclude(plenary=True).all():
|
||||||
|
self._add_talk(talk)
|
||||||
|
|
||||||
|
for talk in self.talks.filter(plenary=True).all():
|
||||||
|
self._add_talk(talk)
|
||||||
|
|
||||||
return mark_safe(template % {
|
return mark_safe(template % {
|
||||||
'header': self._header(),
|
'header': self._header(),
|
||||||
'body': self._body(),
|
'body': self._body(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def as_xml(self):
|
||||||
|
result = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<schedule>
|
||||||
|
%(conference)s
|
||||||
|
%(days)s
|
||||||
|
</schedule>
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not len(self.days):
|
||||||
|
return result % {'conference': '', 'days': ''}
|
||||||
|
|
||||||
|
conference = Conference.objects.get(site=self.site)
|
||||||
|
conference_xml = """<conference>
|
||||||
|
<title>%(title)s</title>
|
||||||
|
<subtitle></subtitle>
|
||||||
|
<venue>%(venue)s</venue>
|
||||||
|
<city>%(city)s</city>
|
||||||
|
<start>%(start_date)s</start>
|
||||||
|
<end>%(end_date)s</end>
|
||||||
|
<days>%(days_count)s</days>
|
||||||
|
<day_change>09:00:00</day_change>
|
||||||
|
<timeslot_duration>00:05:00</timeslot_duration>
|
||||||
|
</conference>
|
||||||
|
""" % {
|
||||||
|
'title': self.site.name,
|
||||||
|
'venue': ', '.join(conference.venue.split('\n')),
|
||||||
|
'city': conference.city,
|
||||||
|
'start_date': sorted(self.days.keys())[0].strftime('%Y-%m-%d'),
|
||||||
|
'end_date': sorted(self.days.keys(), reverse=True)[0].strftime('%Y-%m-%d'),
|
||||||
|
'days_count': len(self.days),
|
||||||
|
}
|
||||||
|
|
||||||
|
days_xml = ''
|
||||||
|
for index, day in enumerate(sorted(self.days.keys())):
|
||||||
|
days_xml += '<day index="%(index)s" date="%(date)s">\n' % {
|
||||||
|
'index': index + 1,
|
||||||
|
'date': day.strftime('%Y-%m-%d'),
|
||||||
|
}
|
||||||
|
for room in self.rooms.all():
|
||||||
|
days_xml += ' <room name="%s">\n' % room.name
|
||||||
|
for talk in self.talks.filter(room=room).order_by('start_date'):
|
||||||
|
if localtime(talk.start_date).date() != day:
|
||||||
|
continue
|
||||||
|
duration = talk.estimated_duration
|
||||||
|
persons = ''
|
||||||
|
for speaker in talk.speakers.all():
|
||||||
|
persons += ' <person id="%(person_id)s">%(person)s</person>\n' % {
|
||||||
|
'person_id': speaker.id,
|
||||||
|
'person': str(speaker),
|
||||||
|
}
|
||||||
|
days_xml += """ <event id="%(id)s">
|
||||||
|
<start>%(start)s</start>
|
||||||
|
<duration>%(duration)s</duration>
|
||||||
|
<room>%(room)s</room>
|
||||||
|
<slug>%(slug)s</slug>
|
||||||
|
<title>%(title)s</title>
|
||||||
|
<subtitle/>
|
||||||
|
<track>%(track)s</track>
|
||||||
|
<type>%(type)s</type>
|
||||||
|
<language/>
|
||||||
|
<abstract>%(abstract)s</abstract>
|
||||||
|
<description>%(description)s</description>
|
||||||
|
<persons>
|
||||||
|
%(persons)s </persons>
|
||||||
|
<links>
|
||||||
|
</links>
|
||||||
|
</event>\n""" % {
|
||||||
|
'id': talk.id,
|
||||||
|
'start': localtime(talk.start_date).strftime('%H:%M'),
|
||||||
|
'duration': '%02d:%02d' % (talk.estimated_duration / 60, talk.estimated_duration % 60),
|
||||||
|
'room': escape(room.name),
|
||||||
|
'slug': escape(talk.slug),
|
||||||
|
'title': escape(talk.title),
|
||||||
|
'track': escape(talk.track),
|
||||||
|
'type': escape(talk.event.name),
|
||||||
|
'abstract': escape(talk.abstract),
|
||||||
|
'description': escape(talk.description),
|
||||||
|
'persons': persons,
|
||||||
|
}
|
||||||
|
days_xml += ' </room>\n'
|
||||||
|
days_xml += '</day>\n'
|
||||||
|
|
||||||
|
return result % {
|
||||||
|
'conference': '\n'.join(map(lambda x: ' ' + x, conference_xml.split('\n'))),
|
||||||
|
'days': '\n'.join(map(lambda x: ' ' + x, days_xml.split('\n'))),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.as_html()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.contrib.sites.shortcuts import get_current_site
|
from django.contrib.sites.shortcuts import get_current_site
|
||||||
from django.views.generic import CreateView, DetailView, ListView, UpdateView
|
from django.views.generic import CreateView, DetailView, ListView, UpdateView
|
||||||
|
from django.http import HttpResponse
|
||||||
|
|
||||||
from ponyconf.mixins import OnSiteFormMixin
|
from ponyconf.mixins import OnSiteFormMixin
|
||||||
|
|
||||||
|
@ -40,6 +41,10 @@ class RoomDetail(StaffRequiredMixin, RoomMixin, DetailView):
|
||||||
@staff_required
|
@staff_required
|
||||||
def program(request):
|
def program(request):
|
||||||
program = Program(site=get_current_site(request))
|
program = Program(site=get_current_site(request))
|
||||||
return render(request, 'planning/program.html', {
|
f = request.GET.get('format')
|
||||||
'program': program,
|
if f == 'xml':
|
||||||
})
|
return HttpResponse(program.as_xml(), content_type="application/xml")
|
||||||
|
else:
|
||||||
|
return render(request, 'planning/program.html', {
|
||||||
|
'program': program,
|
||||||
|
})
|
||||||
|
|
10
ponyconf/decorators.py
Normal file
10
ponyconf/decorators.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
|
||||||
|
def disable_for_loaddata(signal_handler):
|
||||||
|
@wraps(signal_handler)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
if kwargs.get('raw'):
|
||||||
|
return
|
||||||
|
signal_handler(*args, **kwargs)
|
||||||
|
return wrapper
|
|
@ -179,4 +179,10 @@ class TrackForm(forms.ModelForm):
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
|
||||||
ConferenceForm = modelform_factory(Conference, fields=['cfp_opening_date', 'cfp_closing_date', 'home'])
|
ConferenceForm = modelform_factory(Conference,
|
||||||
|
fields=['cfp_opening_date', 'cfp_closing_date', 'venue', 'city', 'home'],
|
||||||
|
widgets={
|
||||||
|
'cfp_opening_date': forms.TextInput(),
|
||||||
|
'cfp_closing_date': forms.TextInput(),
|
||||||
|
'venue': forms.Textarea(attrs={'rows': 4}),
|
||||||
|
})
|
||||||
|
|
25
proposals/migrations/0024_auto_20161024_1313.py
Normal file
25
proposals/migrations/0024_auto_20161024_1313.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.1 on 2016-10-24 13:13
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('proposals', '0023_merge_20161019_2040'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='conference',
|
||||||
|
name='city',
|
||||||
|
field=models.CharField(blank=True, default='', max_length=64),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='conference',
|
||||||
|
name='venue',
|
||||||
|
field=models.TextField(blank=True, default=''),
|
||||||
|
),
|
||||||
|
]
|
|
@ -24,6 +24,8 @@ class Conference(models.Model):
|
||||||
|
|
||||||
site = models.OneToOneField(Site, on_delete=models.CASCADE)
|
site = models.OneToOneField(Site, on_delete=models.CASCADE)
|
||||||
home = models.TextField(blank=True, default="")
|
home = models.TextField(blank=True, default="")
|
||||||
|
venue = models.TextField(blank=True, default="")
|
||||||
|
city = models.CharField(max_length=64, blank=True, default="")
|
||||||
cfp_opening_date = models.DateTimeField(null=True, blank=True, default=None)
|
cfp_opening_date = models.DateTimeField(null=True, blank=True, default=None)
|
||||||
cfp_closing_date = models.DateTimeField(null=True, blank=True, default=None)
|
cfp_closing_date = models.DateTimeField(null=True, blank=True, default=None)
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ from django.contrib.sites.models import Site
|
||||||
from django.utils.translation import ugettext_noop
|
from django.utils.translation import ugettext_noop
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
|
from ponyconf.decorators import disable_for_loaddata
|
||||||
from accounts.models import Participation
|
from accounts.models import Participation
|
||||||
|
|
||||||
from .models import Conference, Talk, Topic, Event
|
from .models import Conference, Talk, Topic, Event
|
||||||
|
@ -14,11 +15,13 @@ talk_edited = Signal(providing_args=["sender", "instance", "author"])
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Site, dispatch_uid="Create Conference for Site")
|
@receiver(post_save, sender=Site, dispatch_uid="Create Conference for Site")
|
||||||
|
@disable_for_loaddata
|
||||||
def create_conference(sender, instance, **kwargs):
|
def create_conference(sender, instance, **kwargs):
|
||||||
Conference.objects.get_or_create(site=instance)
|
Conference.objects.get_or_create(site=instance)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Site, dispatch_uid="Create default events type for Site")
|
@receiver(post_save, sender=Site, dispatch_uid="Create default events type for Site")
|
||||||
|
@disable_for_loaddata
|
||||||
def create_events(sender, instance, **kwargs):
|
def create_events(sender, instance, **kwargs):
|
||||||
if not Event.objects.filter(site=instance).exists():
|
if not Event.objects.filter(site=instance).exists():
|
||||||
Event.objects.bulk_create([
|
Event.objects.bulk_create([
|
||||||
|
@ -36,7 +39,7 @@ def call_first_site_post_save(apps, **kwargs):
|
||||||
site.first().save()
|
site.first().save()
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=Talk.speakers.through, dispatch_uid="Create Participation for speakers")
|
#@receiver(m2m_changed, sender=Talk.speakers.through, dispatch_uid="Create Participation for speakers")
|
||||||
def create_participation_for_speakers(sender, instance, action, reverse, model, pk_set, using, **kwargs):
|
def create_participation_for_speakers(sender, instance, action, reverse, model, pk_set, using, **kwargs):
|
||||||
if action != "pre_add":
|
if action != "pre_add":
|
||||||
pass
|
pass
|
||||||
|
@ -44,7 +47,7 @@ def create_participation_for_speakers(sender, instance, action, reverse, model,
|
||||||
Participation.objects.get_or_create(user=speaker, site=instance.site)
|
Participation.objects.get_or_create(user=speaker, site=instance.site)
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=Topic.reviewers.through, dispatch_uid="Create Participation for reviewers")
|
#@receiver(m2m_changed, sender=Topic.reviewers.through, dispatch_uid="Create Participation for reviewers")
|
||||||
def create_participation_for_reviewers(sender, instance, action, reverse, model, pk_set, using, **kwargs):
|
def create_participation_for_reviewers(sender, instance, action, reverse, model, pk_set, using, **kwargs):
|
||||||
if action != "pre_add":
|
if action != "pre_add":
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% bootstrap_field form.cfp_opening_date addon_after='<span class="glyphicon glyphicon-calendar"></span>' %}
|
{% bootstrap_field form.cfp_opening_date addon_after='<span class="glyphicon glyphicon-calendar"></span>' %}
|
||||||
{% bootstrap_field form.cfp_closing_date addon_after='<span class="glyphicon glyphicon-calendar"></span>' %}
|
{% bootstrap_field form.cfp_closing_date addon_after='<span class="glyphicon glyphicon-calendar"></span>' %}
|
||||||
|
{% bootstrap_form form exclude='cfp_opening_date,cfp_closing_date,home' %}
|
||||||
<ul class="nav nav-tabs" role="tablist">
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
<li class="active"><a href="#editor" role="tab" data-toggle="tab">Editor</a></li>
|
<li class="active"><a href="#editor" role="tab" data-toggle="tab">Editor</a></li>
|
||||||
<li><a href="#preview" role="tab" data-toggle="tab">Preview</a></li>
|
<li><a href="#preview" role="tab" data-toggle="tab">Preview</a></li>
|
||||||
|
|
21
volunteers/migrations/0003_auto_20161024_1313.py
Normal file
21
volunteers/migrations/0003_auto_20161024_1313.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.1 on 2016-10-24 13:13
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('volunteers', '0002_activity_slug'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='activity',
|
||||||
|
name='participants',
|
||||||
|
field=models.ManyToManyField(blank=True, related_name='activities', to=settings.AUTH_USER_MODEL, verbose_name='Participants'),
|
||||||
|
),
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user