WIP: complete the public CFP form. More testing is needed
We will probabily recreate migrations of the cfp application from scratch before deploying in production
This commit is contained in:
parent
f5dcf1a2d6
commit
29ea8403e7
31
cfp/migrations/0002_auto_20170605_2023.py
Normal file
31
cfp/migrations/0002_auto_20170605_2023.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11 on 2017-06-05 20:23
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cfp', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='participant',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(blank=True, max_length=128),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='talk',
|
||||||
|
name='category',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='cfp.TalkCategory', verbose_name='Intervention kind'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='talk',
|
||||||
|
name='title',
|
||||||
|
field=models.CharField(max_length=128, verbose_name='Title'),
|
||||||
|
),
|
||||||
|
]
|
36
cfp/migrations/0003_auto_20170605_2035.py
Normal file
36
cfp/migrations/0003_auto_20170605_2035.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11 on 2017-06-05 20:35
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cfp', '0002_auto_20170605_2023'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='participant',
|
||||||
|
name='token',
|
||||||
|
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='talk',
|
||||||
|
name='description',
|
||||||
|
field=models.TextField(blank=True, verbose_name='Description of your talk'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='talk',
|
||||||
|
name='notes',
|
||||||
|
field=models.TextField(blank=True, help_text='If you have any constraint or if you have anything that may help you to select your talk, like a video or slides of your talk, please write it down here', verbose_name='Message to organizers'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='talk',
|
||||||
|
name='title',
|
||||||
|
field=models.CharField(max_length=128, verbose_name='Talk Title'),
|
||||||
|
),
|
||||||
|
]
|
21
cfp/migrations/0004_talk_token.py
Normal file
21
cfp/migrations/0004_talk_token.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11 on 2017-06-05 20:43
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cfp', '0003_auto_20170605_2035'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='talk',
|
||||||
|
name='token',
|
||||||
|
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||||
|
),
|
||||||
|
]
|
40
cfp/migrations/0005_auto_20170605_2243.py
Normal file
40
cfp/migrations/0005_auto_20170605_2243.py
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11 on 2017-06-05 22:43
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cfp', '0004_talk_token'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='talkcategory',
|
||||||
|
options={'ordering': ('pk',), 'verbose_name': 'category', 'verbose_name_plural': 'categories'},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='conference',
|
||||||
|
name='contact_email',
|
||||||
|
field=models.CharField(blank=True, max_length=100),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='conference',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(blank=True, max_length=100),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='talk',
|
||||||
|
name='category',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='cfp.TalkCategory', verbose_name='Talk Category'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='talk',
|
||||||
|
name='video_licence',
|
||||||
|
field=models.CharField(choices=[('CC-Zero CC-BY', 'CC-Zero CC-BY'), ('CC-BY-SA', 'CC-BY-SA'), ('CC-BY-ND', 'CC-BY-ND'), ('CC-BY-NC', 'CC-BY-NC'), ('CC-BY-NC-SA', 'CC-BY-NC-SA'), ('CC-BY-NC-ND', 'CC-BY-NC-ND')], default='CC-BY-SA', max_length=10, verbose_name='Video licence'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,6 +1,7 @@
|
||||||
from enum import IntEnum
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from os.path import join, basename
|
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
|
@ -12,29 +13,12 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from ponyconf.utils import PonyConfModel, enum_to_choices
|
from ponyconf.utils import PonyConfModel
|
||||||
|
|
||||||
from enum import IntEnum
|
|
||||||
from datetime import timedelta
|
|
||||||
from os.path import join, basename
|
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.contrib.sites.models import Site
|
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
|
||||||
from django.db import models
|
|
||||||
from django.db.models import Q
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
from django.utils.translation import ugettext
|
|
||||||
from django.utils import timezone
|
|
||||||
|
|
||||||
from autoslug import AutoSlugField
|
from autoslug import AutoSlugField
|
||||||
from colorful.fields import RGBColorField
|
from colorful.fields import RGBColorField
|
||||||
|
|
||||||
from .utils import query_sum
|
from .utils import query_sum
|
||||||
from .utils import generate_user_uid
|
|
||||||
|
|
||||||
from enum import IntEnum
|
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
|
@ -43,6 +27,7 @@ from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
|
|
||||||
|
|
||||||
#from ponyconf.utils import PonyConfModel, enum_to_choices
|
#from ponyconf.utils import PonyConfModel, enum_to_choices
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,9 +35,11 @@ from django.utils.translation import ugettext
|
||||||
class Conference(models.Model):
|
class Conference(models.Model):
|
||||||
|
|
||||||
site = models.OneToOneField(Site, on_delete=models.CASCADE)
|
site = models.OneToOneField(Site, on_delete=models.CASCADE)
|
||||||
|
name = models.CharField(blank=True, max_length=100)
|
||||||
home = models.TextField(blank=True, default="")
|
home = models.TextField(blank=True, default="")
|
||||||
venue = models.TextField(blank=True, default="")
|
venue = models.TextField(blank=True, default="")
|
||||||
city = models.CharField(max_length=64, blank=True, default="")
|
city = models.CharField(max_length=64, blank=True, default="")
|
||||||
|
contact_email = models.CharField(max_length=100, blank=True)
|
||||||
#subscriptions_open = models.BooleanField(default=False) # workshop subscription
|
#subscriptions_open = models.BooleanField(default=False) # workshop subscription
|
||||||
|
|
||||||
#def cfp_is_open(self):
|
#def cfp_is_open(self):
|
||||||
|
@ -66,6 +53,9 @@ class Conference(models.Model):
|
||||||
# .filter(Q(opening_date__isnull=True) | Q(opening_date__lte=now))\
|
# .filter(Q(opening_date__isnull=True) | Q(opening_date__lte=now))\
|
||||||
# .filter(Q(closing_date__isnull=True) | Q(closing_date__gte=now))
|
# .filter(Q(closing_date__isnull=True) | Q(closing_date__gte=now))
|
||||||
|
|
||||||
|
def from_email(self):
|
||||||
|
return self.name+' <'+self.contact_email+'>'
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.site)
|
return str(self.site)
|
||||||
|
|
||||||
|
@ -76,13 +66,12 @@ class Participant(PonyConfModel):
|
||||||
|
|
||||||
site = models.ForeignKey(Site, on_delete=models.CASCADE)
|
site = models.ForeignKey(Site, on_delete=models.CASCADE)
|
||||||
|
|
||||||
name = models.CharField(max_length=128)
|
name = models.CharField(max_length=128, blank=True)
|
||||||
email = models.EmailField()
|
email = models.EmailField()
|
||||||
|
|
||||||
phone_number = models.CharField(max_length=16, blank=True, default='', verbose_name=_('Phone number'))
|
phone_number = models.CharField(max_length=16, blank=True, default='', verbose_name=_('Phone number'))
|
||||||
biography = models.TextField(blank=True, verbose_name=_('Biography'))
|
biography = models.TextField(blank=True, verbose_name=_('Biography'))
|
||||||
#email_token = models.CharField(max_length=12, default=generate_user_uid, unique=True)
|
token = models.UUIDField(default=uuid.uuid4, editable=False)
|
||||||
|
|
||||||
|
|
||||||
# TALK
|
# TALK
|
||||||
#videotaped = models.BooleanField(_("I'm ok to be recorded on video"), default=True)
|
#videotaped = models.BooleanField(_("I'm ok to be recorded on video"), default=True)
|
||||||
|
@ -178,6 +167,8 @@ class TalkCategory(models.Model): # type of talk (conf 30min, 1h, stand, …)
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ('site', 'name')
|
unique_together = ('site', 'name')
|
||||||
ordering = ('pk',)
|
ordering = ('pk',)
|
||||||
|
verbose_name = "category"
|
||||||
|
verbose_name_plural = "categories"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return ugettext(self.name)
|
return ugettext(self.name)
|
||||||
|
@ -216,21 +207,28 @@ class TalkCategory(models.Model): # type of talk (conf 30min, 1h, stand, …)
|
||||||
|
|
||||||
class Talk(PonyConfModel):
|
class Talk(PonyConfModel):
|
||||||
|
|
||||||
LICENCES = IntEnum('Video licence', 'CC-Zero CC-BY CC-BY-SA CC-BY-ND CC-BY-NC CC-BY-NC-SA CC-BY-NC-ND')
|
LICENCES = (
|
||||||
|
('CC-Zero CC-BY', 'CC-Zero CC-BY'),
|
||||||
|
('CC-BY-SA', 'CC-BY-SA'),
|
||||||
|
('CC-BY-ND', 'CC-BY-ND'),
|
||||||
|
('CC-BY-NC', 'CC-BY-NC'),
|
||||||
|
('CC-BY-NC-SA','CC-BY-NC-SA'),
|
||||||
|
('CC-BY-NC-ND', 'CC-BY-NC-ND'),
|
||||||
|
)
|
||||||
|
|
||||||
site = models.ForeignKey(Site, on_delete=models.CASCADE)
|
site = models.ForeignKey(Site, on_delete=models.CASCADE)
|
||||||
|
|
||||||
#proposer = models.ForeignKey(User, related_name='+')
|
#proposer = models.ForeignKey(User, related_name='+')
|
||||||
speakers = models.ManyToManyField(Participant, verbose_name=_('Speakers'))
|
speakers = models.ManyToManyField(Participant, verbose_name=_('Speakers'))
|
||||||
title = models.CharField(max_length=128, verbose_name=_('Title'), help_text=_('After submission, title can only be changed by the staff.'))
|
title = models.CharField(max_length=128, verbose_name=_('Talk Title'))
|
||||||
slug = AutoSlugField(populate_from='title', unique=True)
|
slug = AutoSlugField(populate_from='title', unique=True)
|
||||||
#abstract = models.CharField(max_length=255, blank=True, verbose_name=_('Abstract'))
|
#abstract = models.CharField(max_length=255, blank=True, verbose_name=_('Abstract'))
|
||||||
description = models.TextField(blank=True, verbose_name=_('Description'))
|
description = models.TextField(blank=True, verbose_name=_('Description of your talk'))
|
||||||
track = models.ForeignKey(Track, blank=True, null=True, verbose_name=_('Track'))
|
track = models.ForeignKey(Track, blank=True, null=True, verbose_name=_('Track'))
|
||||||
notes = models.TextField(blank=True, verbose_name=_('Message to organizers'))
|
notes = models.TextField(blank=True, verbose_name=_('Message to organizers'), help_text=_('If you have any constraint or if you have anything that may help you to select your talk, like a video or slides of your talk, please write it down here'))
|
||||||
category = models.ForeignKey(TalkCategory, verbose_name=_('Intervention kind'))
|
category = models.ForeignKey(TalkCategory, blank=True, null=True, verbose_name=_('Talk Category'))
|
||||||
videotaped = models.BooleanField(_("I'm ok to be recorded on video"), default=True)
|
videotaped = models.BooleanField(_("I'm ok to be recorded on video"), default=True)
|
||||||
video_licence = models.IntegerField(choices=enum_to_choices(LICENCES), default=2, verbose_name=_("Video licence"))
|
video_licence = models.CharField(choices=LICENCES, default='CC-BY-SA', max_length=10, verbose_name=_("Video licence"))
|
||||||
sound = models.BooleanField(_("I need sound"), default=False)
|
sound = models.BooleanField(_("I need sound"), default=False)
|
||||||
accepted = models.NullBooleanField(default=None)
|
accepted = models.NullBooleanField(default=None)
|
||||||
#start_date = models.DateTimeField(null=True, blank=True, default=None)
|
#start_date = models.DateTimeField(null=True, blank=True, default=None)
|
||||||
|
@ -240,6 +238,8 @@ class Talk(PonyConfModel):
|
||||||
#materials = models.FileField(null=True, upload_to=talk_materials_destination, verbose_name=_('Materials'),
|
#materials = models.FileField(null=True, upload_to=talk_materials_destination, verbose_name=_('Materials'),
|
||||||
# help_text=_('You can use this field to share some materials related to your intervention.'))
|
# help_text=_('You can use this field to share some materials related to your intervention.'))
|
||||||
|
|
||||||
|
token = models.UUIDField(default=uuid.uuid4, editable=False)
|
||||||
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('title',)
|
ordering = ('title',)
|
||||||
|
|
|
@ -13,7 +13,11 @@
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<p>Merci pour votre participation !</p>
|
<p>{% trans "Thanks for your proposal" %}</p>
|
||||||
|
<p>{% trans "You can edit your talk at anytime:" %} <a href="{% url 'talk-proposal-edit' talk.token participant.token %}">{% if request.is_secure %}https{% else %}http{% endif %}://{{ site.domain }}{% url 'talk-proposal-edit' talk.token participant.token %}</a></p>
|
||||||
|
<p>{% trans "You can add an additionnal speaker:" %} <a href="{% url 'talk-proposal-speaker-add' talk.token %}">{% if request.is_secure %}https{% else %}http{% endif %}://{{ site.domain }}{% url 'talk-proposal-speaker-add' talk.token %}</a></p>
|
||||||
|
<p>{% trans "You can edit your profile:" %} <a href="{% url 'talk-proposal-speaker-edit' talk.token participant.token %}">{% if request.is_secure %}https{% else %}http{% endif %}://{{ site.domain }}{% url 'talk-proposal-speaker-edit' talk.token participant.token %}</a></p>
|
||||||
|
<p>{% trans "An email has been sent to you with those URLs" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
|
|
||||||
{% load ponyconf_tags i18n %}
|
{% load ponyconf_tags i18n %}
|
||||||
|
|
||||||
|
@ -13,7 +14,14 @@
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
{% include "_form.html" %}
|
<form method="POST" class="form-horizontal col-md-8 col-md-offset-2">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ participant_form|crispy }}
|
||||||
|
{{ talk_form|crispy }}
|
||||||
|
<div class="col-md-12 text-center">
|
||||||
|
<button type="submit" class="btn btn-primary text-center">{% trans "Save" %} <i class="fa fa-check"></i></button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
26
cfp/templates/cfp/speaker.html
Normal file
26
cfp/templates/cfp/speaker.html
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
|
|
||||||
|
{% load ponyconf_tags i18n %}
|
||||||
|
|
||||||
|
{% block proposetab %} class="active"{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="page-header">
|
||||||
|
<h1>
|
||||||
|
{% trans "Participate" %}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<form method="POST" class="form-horizontal col-md-8 col-md-offset-2">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ participant_form|crispy }}
|
||||||
|
<div class="col-md-12 text-center">
|
||||||
|
<button type="submit" class="btn btn-primary text-center">{% trans "Save" %} <i class="fa fa-check"></i></button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -3,8 +3,10 @@ from django.conf.urls import url
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^propose/$', views.ProposeView.as_view(), name='propose'),
|
url(r'^$', views.talk_proposal, name='talk-proposal'),
|
||||||
url(r'^thanks/$', views.CompleteView.as_view(), name='propose-complete'),
|
url(r'^(?P<talk_id>[\w\-]+)/speaker/add/$', views.talk_proposal_speaker_edit, name='talk-proposal-speaker-add'),
|
||||||
|
url(r'^(?P<talk_id>[\w\-]+)/speaker/(?P<speaker_id>[\w\-]+)/$', views.talk_proposal_speaker_edit, name='talk-proposal-speaker-edit'),
|
||||||
|
url(r'^(?P<talk_id>[\w\-]+)/(?P<participant_id>[\w\-]+)/$', views.talk_proposal, name='talk-proposal-edit'),
|
||||||
#url(r'^markdown/$', views.markdown_preview, name='markdown'),
|
#url(r'^markdown/$', views.markdown_preview, name='markdown'),
|
||||||
#url(r'^$', views.home, name='home'),
|
#url(r'^$', views.home, name='home'),
|
||||||
#url(r'^staff/$', views.staff, name='staff'),
|
#url(r'^staff/$', views.staff, name='staff'),
|
||||||
|
|
125
cfp/views.py
125
cfp/views.py
|
@ -1,36 +1,111 @@
|
||||||
from django.views.generic import FormView, TemplateView
|
|
||||||
|
from django.contrib.sites.shortcuts import get_current_site
|
||||||
|
from django.core.mail import send_mail
|
||||||
from django.core.urlresolvers import reverse_lazy
|
from django.core.urlresolvers import reverse_lazy
|
||||||
|
from django.forms.models import modelform_factory
|
||||||
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.views.generic import FormView, TemplateView
|
||||||
|
|
||||||
from .forms import ProposeForm
|
from .models import Participant, Talk
|
||||||
|
|
||||||
|
|
||||||
class ProposeView(FormView):
|
def talk_proposal(request, talk_id=None, participant_id=None):
|
||||||
form_class = ProposeForm
|
|
||||||
template_name = 'cfp/propose.html'
|
|
||||||
success_url = reverse_lazy('propose-complete')
|
|
||||||
|
|
||||||
def propose(request):
|
site = get_current_site(request)
|
||||||
TalkForm = modelform_factory(Talk)
|
talk = None
|
||||||
ParticipantForm = modelform_factory(Participant)
|
participant = None
|
||||||
talk_form = TalkForm(request.POST or None)
|
|
||||||
participant_form = ParticipantForm(request.POST or None)
|
if talk_id and participant_id:
|
||||||
forms = [talk_form, participant_form]
|
talk = get_object_or_404(Talk, token=talk_id, site=site)
|
||||||
if request.method == 'POST' and all([form.is_valid() for form in forms]):
|
participant = get_object_or_404(Participant, token=participant_id, site=site)
|
||||||
|
|
||||||
|
ParticipantForm = modelform_factory(Participant, fields=('name','email', 'biography'))
|
||||||
|
participant_form = ParticipantForm(request.POST or None, instance=participant)
|
||||||
|
TalkForm = modelform_factory(Talk, fields=('category', 'title', 'description','notes'))
|
||||||
|
talk_form = TalkForm(request.POST or None, instance=talk)
|
||||||
|
|
||||||
|
if request.method == 'POST' and talk_form.is_valid() and participant_form.is_valid():
|
||||||
talk = talk_form.save(commit=False)
|
talk = talk_form.save(commit=False)
|
||||||
talk.site = get_current_site(request)
|
talk.site = site
|
||||||
email = participant.cleaned_data['email']
|
|
||||||
try:
|
participant, created = Participant.objects.get_or_create(email=participant_form.cleaned_data['email'], site=site)
|
||||||
participant = Participant.objects.get(email=email)
|
participant_form = ParticipantForm(request.POST, instance=participant)
|
||||||
except Participant.DoesNoExist:
|
participant = participant_form.save()
|
||||||
participant = participant_form.save()
|
participant.save()
|
||||||
talk.participant = participant
|
|
||||||
talk.save()
|
talk.save()
|
||||||
return redirect(reverse('propose-complete'))
|
talk.speakers.add(participant)
|
||||||
return render('cfp/propose.html', {
|
|
||||||
'talk_form': talk_form,
|
protocol = 'http' if request.is_secure() else 'http'
|
||||||
|
base_url = protocol+'://'+site.domain
|
||||||
|
url_talk_proposal_edit = base_url + reverse('talk-proposal-edit', args=[talk.token, participant.token])
|
||||||
|
url_talk_proposal_speaker_add = base_url + reverse('talk-proposal-speaker-add', args=[talk.token])
|
||||||
|
url_talk_proposal_speaker_edit = base_url + reverse('talk-proposal-speaker-edit', args=[talk.token, participant.token])
|
||||||
|
msg_title = _('Your talk "{}" has been submitted for {}').format(talk.title, site.conference.name)
|
||||||
|
msg_body = _("""Hi {},
|
||||||
|
|
||||||
|
Your talk has been submitted for {}.
|
||||||
|
|
||||||
|
Here are the details of your talk:
|
||||||
|
Title: {}
|
||||||
|
Description {}
|
||||||
|
|
||||||
|
You can edit your talk at anytume: {}
|
||||||
|
You can add a new co-speaker here: {}
|
||||||
|
You can edit your profile here: {}
|
||||||
|
|
||||||
|
If you have any question, your can answer to this email.
|
||||||
|
|
||||||
|
Thanks!
|
||||||
|
|
||||||
|
{}
|
||||||
|
|
||||||
|
""").format(participant.name, site.conference.name, talk.title, talk.description, url_talk_proposal_edit, url_talk_proposal_speaker_add, url_talk_proposal_speaker_edit, site.conference.name)
|
||||||
|
|
||||||
|
send_mail(
|
||||||
|
msg_title,
|
||||||
|
msg_body,
|
||||||
|
site.conference.from_email(),
|
||||||
|
[participant.email],
|
||||||
|
fail_silently=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
return render(request, 'cfp/complete.html', {'talk': talk, 'participant': participant})
|
||||||
|
|
||||||
|
return render(request, 'cfp/propose.html', {
|
||||||
'participant_form': participant_form,
|
'participant_form': participant_form,
|
||||||
|
'site': site,
|
||||||
|
'talk_form': talk_form,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class CompleteView(TemplateView):
|
def talk_proposal_speaker_edit(request, talk_id, participant_id=None):
|
||||||
template_name = 'cfp/complete.html'
|
|
||||||
|
site = get_current_site(request)
|
||||||
|
talk = get_object_or_404(Talk, token=talk_id, site=site)
|
||||||
|
participant = None
|
||||||
|
|
||||||
|
if participant_id:
|
||||||
|
participant = get_object_or_404(Participant, token=participant_id, site=site)
|
||||||
|
|
||||||
|
ParticipantForm = modelform_factory(Participant, fields=('name','email', 'biography'))
|
||||||
|
participant_form = ParticipantForm(request.POST or None, instance=participant)
|
||||||
|
|
||||||
|
if request.method == 'POST' and participant_form.is_valid():
|
||||||
|
|
||||||
|
participant, created = Participant.objects.get_or_create(email=participant_form.cleaned_data['email'], site=site)
|
||||||
|
participant_form = ParticipantForm(request.POST, instance=participant)
|
||||||
|
participant = participant_form.save()
|
||||||
|
participant.save()
|
||||||
|
|
||||||
|
talk.speakers.add(participant)
|
||||||
|
|
||||||
|
return render(request,'cfp/complete.html', {'talk': talk, 'participant': participant})
|
||||||
|
|
||||||
|
return render(request, 'cfp/speaker.html', {
|
||||||
|
'participant_form': participant_form,
|
||||||
|
'site': site,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@ INSTALLED_APPS = [
|
||||||
#'registration',
|
#'registration',
|
||||||
#'django_select2',
|
#'django_select2',
|
||||||
#'avatar',
|
#'avatar',
|
||||||
|
'crispy_forms',
|
||||||
|
|
||||||
# build-in apps
|
# build-in apps
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
|
@ -209,6 +210,8 @@ SELECT2_CSS = 'select2/dist/css/select2.min.css'
|
||||||
#AUTHENTICATION_BACKENDS = ['yeouia.backends.YummyEmailOrUsernameInsensitiveAuth']
|
#AUTHENTICATION_BACKENDS = ['yeouia.backends.YummyEmailOrUsernameInsensitiveAuth']
|
||||||
LOGOUT_REDIRECT_URL = 'home'
|
LOGOUT_REDIRECT_URL = 'home'
|
||||||
|
|
||||||
|
CRISPY_TEMPLATE_PACK='bootstrap3'
|
||||||
|
|
||||||
# django-registration
|
# django-registration
|
||||||
ACCOUNT_ACTIVATION_DAYS = 7
|
ACCOUNT_ACTIVATION_DAYS = 7
|
||||||
INCLUDE_REGISTER_URL = True
|
INCLUDE_REGISTER_URL = True
|
||||||
|
@ -218,3 +221,9 @@ CACHES = {
|
||||||
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
|
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SERVER_EMAIL = 'ponyconf@example.com'
|
||||||
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||||
|
EMAIL_HOST = 'localhost'
|
||||||
|
EMAIL_PORT = 1025
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<div id="navbar" class="navbar-collapse collapse">
|
<div id="navbar" class="navbar-collapse collapse">
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li{% block hometab %}{% endblock %}><a href="{% url 'home' %}"><span class="glyphicon glyphicon-home"></span> {% trans "Home" %}</a></li>
|
<li{% block hometab %}{% endblock %}><a href="{% url 'home' %}"><span class="glyphicon glyphicon-home"></span> {% trans "Home" %}</a></li>
|
||||||
<li{% block proposetab %}{% endblock %}><a href="{% url 'propose' %}"><span class="glyphicon glyphicon-bullhorn"></span> {% trans "Call for participation" %}</a></li>
|
<li{% block proposetab %}{% endblock %}><a href="{% url 'talk-proposal' %}"><span class="glyphicon glyphicon-bullhorn"></span> {% trans "Call for participation" %}</a></li>
|
||||||
{% comment %}
|
{% comment %}
|
||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
<li{% block exhibitortab %}{% endblock %}><a href="{% url 'participate-as-speaker' %}"><span class="glyphicon glyphicon-bullhorn"></span> {% trans "Exhibitor" %}</a></li>
|
<li{% block exhibitortab %}{% endblock %}><a href="{% url 'participate-as-speaker' %}"><span class="glyphicon glyphicon-bullhorn"></span> {% trans "Exhibitor" %}</a></li>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user