diff --git a/src/bornhack/urls.py b/src/bornhack/urls.py index 733849ed..71bea179 100644 --- a/src/bornhack/urls.py +++ b/src/bornhack/urls.py @@ -134,33 +134,33 @@ urlpatterns = [ name='schedule_index' ), url( - r'^submissions/', include([ + r'^proposals/', include([ url( r'^$', - SubmissionListView.as_view(), - name='submission_list', + ProposalListView.as_view(), + name='proposal_list', ), url( r'^speakers/', include([ url( r'^create/$', - SpeakerSubmissionCreateView.as_view(), - name='speakersubmission_create' + SpeakerProposalCreateView.as_view(), + name='speakerproposal_create' ), url( r'^(?P[a-f0-9-]+)/$', - SpeakerSubmissionDetailView.as_view(), - name='speakersubmission_detail' + SpeakerProposalDetailView.as_view(), + name='speakerproposal_detail' ), url( r'^(?P[a-f0-9-]+)/edit/$', - SpeakerSubmissionUpdateView.as_view(), - name='speakersubmission_update' + SpeakerProposalUpdateView.as_view(), + name='speakerproposal_update' ), url( r'^(?P[a-f0-9-]+)/pictures/(?P[-_\w+]+)/$', - SpeakerSubmissionPictureView.as_view(), - name='speakersubmission_picture', + SpeakerProposalPictureView.as_view(), + name='speakerproposal_picture', ), ]) ), @@ -168,18 +168,18 @@ urlpatterns = [ r'^events/', include([ url( r'^create/$', - EventSubmissionCreateView.as_view(), - name='eventsubmission_create' + EventProposalCreateView.as_view(), + name='eventproposal_create' ), url( r'^(?P[a-f0-9-]+)/$', - EventSubmissionDetailView.as_view(), - name='eventsubmission_detail' + EventProposalDetailView.as_view(), + name='eventproposal_detail' ), url( r'^(?P[a-f0-9-]+)/edit/$', - EventSubmissionUpdateView.as_view(), - name='eventsubmission_update' + EventProposalUpdateView.as_view(), + name='eventproposal_update' ), ]) ), diff --git a/src/profiles/templates/profiles/profile_base.html b/src/profiles/templates/profiles/profile_base.html index eefeafef..afceddc0 100644 --- a/src/profiles/templates/profiles/profile_base.html +++ b/src/profiles/templates/profiles/profile_base.html @@ -33,6 +33,7 @@ Credit Notes {% endif %} + {% endif %}


diff --git a/src/program/admin.py b/src/program/admin.py index e25a5158..37f7fe51 100644 --- a/src/program/admin.py +++ b/src/program/admin.py @@ -1,15 +1,15 @@ from django.contrib import admin -from .models import Event, Speaker, EventType, EventInstance, EventLocation, SpeakerSubmission, EventSubmission +from .models import Event, Speaker, EventType, EventInstance, EventLocation, SpeakerProposal, EventProposal -@admin.register(SpeakerSubmission) -class SpeakerSubmissionAdmin(admin.ModelAdmin): +@admin.register(SpeakerProposal) +class SpeakerProposalAdmin(admin.ModelAdmin): pass -@admin.register(EventSubmission) -class EventSubmissionAdmin(admin.ModelAdmin): +@admin.register(EventProposal) +class EventProposalAdmin(admin.ModelAdmin): pass diff --git a/src/program/migrations/0033_auto_20170312_1857.py b/src/program/migrations/0033_auto_20170312_1857.py new file mode 100644 index 00000000..5f6391be --- /dev/null +++ b/src/program/migrations/0033_auto_20170312_1857.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-03-12 17:57 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import program.models +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('camps', '0020_camp_read_only'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('program', '0032_auto_20170312_1556'), + ] + + operations = [ + migrations.CreateModel( + name='EventProposal', + fields=[ + ('created', models.DateTimeField(auto_now_add=True)), + ('updated', models.DateTimeField(auto_now=True)), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('proposal_status', models.CharField(choices=[('draft', 'Draft'), ('pending', 'Pending approval'), ('approved', 'Approved'), ('rejected', 'Rejected')], default='draft', max_length=50)), + ('title', models.CharField(help_text='The title of this event', max_length=255)), + ('abstract', models.TextField(help_text='The abstract for this event')), + ('camp', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='eventproposals', to='camps.Camp')), + ('event_type', models.ForeignKey(help_text='The type of event', on_delete=django.db.models.deletion.CASCADE, to='program.EventType')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='SpeakerProposal', + fields=[ + ('created', models.DateTimeField(auto_now_add=True)), + ('updated', models.DateTimeField(auto_now=True)), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('proposal_status', models.CharField(choices=[('draft', 'Draft'), ('pending', 'Pending approval'), ('approved', 'Approved'), ('rejected', 'Rejected')], default='draft', max_length=50)), + ('name', models.CharField(help_text='Name or alias of the speaker', max_length=150)), + ('biography', models.TextField(help_text='Markdown is supported.')), + ('picture_large', models.ImageField(blank=True, help_text='A picture of the speaker', null=True, upload_to=program.models.get_speakerproposal_picture_upload_path)), + ('picture_small', models.ImageField(blank=True, help_text='A thumbnail of the speaker picture', null=True, upload_to=program.models.get_speakerproposal_picture_upload_path)), + ('camp', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='speakerproposals', to='camps.Camp')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'abstract': False, + }, + ), + migrations.RemoveField( + model_name='eventsubmission', + name='camp', + ), + migrations.RemoveField( + model_name='eventsubmission', + name='event_type', + ), + migrations.RemoveField( + model_name='eventsubmission', + name='speakers', + ), + migrations.RemoveField( + model_name='eventsubmission', + name='user', + ), + migrations.RemoveField( + model_name='speakersubmission', + name='camp', + ), + migrations.RemoveField( + model_name='speakersubmission', + name='user', + ), + migrations.RemoveField( + model_name='speaker', + name='submission', + ), + migrations.DeleteModel( + name='EventSubmission', + ), + migrations.DeleteModel( + name='SpeakerSubmission', + ), + migrations.AddField( + model_name='eventproposal', + name='speakers', + field=models.ManyToManyField(blank=True, help_text='Pick the speaker(s) for this event', to='program.SpeakerProposal'), + ), + migrations.AddField( + model_name='eventproposal', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='speaker', + name='proposal', + field=models.OneToOneField(blank=True, help_text='The speaker proposal object this speaker was created from', null=True, on_delete=django.db.models.deletion.CASCADE, to='program.SpeakerProposal'), + ), + ] diff --git a/src/program/mixins.py b/src/program/mixins.py index 92c4b357..87fb9cda 100644 --- a/src/program/mixins.py +++ b/src/program/mixins.py @@ -2,34 +2,46 @@ from django.views.generic.detail import SingleObjectMixin from django.shortcuts import redirect from django.urls import reverse from . import models +from django.contrib import messages -class CreateUserSubmissionMixin(SingleObjectMixin): +class CreateUserProposalMixin(SingleObjectMixin): def form_valid(self, form): # set camp and user before saving form.instance.camp = self.camp form.instance.user = self.request.user speaker = form.save() - return redirect(reverse('submission_list', kwargs={'camp_slug': self.camp.slug})) + return redirect(reverse('proposal_list', kwargs={'camp_slug': self.camp.slug})) -class EnsureUnpprovedSubmissionMixin(SingleObjectMixin): +class EnsureUnpprovedProposalMixin(SingleObjectMixin): def dispatch(self, request, *args, **kwargs): - # do not permit editing if the submission is already approved - if self.get_object().submission_status == models.UserSubmittedModel.SUBMISSION_APPROVED: - messages.error(request, "This submission has already been approved. Please contact the organisers if you need to modify something." % self.camp.title) - return redirect(reverse('submissions_list', kwargs={'camp_slug': self.camp.slug})) + # do not permit editing if the proposal is already approved + if self.get_object().proposal_status == models.UserSubmittedModel.PROPOSAL_APPROVED: + messages.error(request, "This proposal has already been approved. Please contact the organisers if you need to modify something." % self.camp.title) + return redirect(reverse('proposal_list', kwargs={'camp_slug': self.camp.slug})) # alright, continue with the request return super().dispatch(request, *args, **kwargs) -class EnsureUserOwnsSubmissionMixin(SingleObjectMixin): +class EnsureWritableCampMixin(SingleObjectMixin): def dispatch(self, request, *args, **kwargs): - # make sure that this submission belongs to the logged in user + # do not permit view if camp is in readonly mode + if self.camp.read_only: + messages.error(request, "No thanks") + return redirect(reverse('proposal_list', kwargs={'camp_slug': self.camp.slug})) + + # alright, continue with the request + return super().dispatch(request, *args, **kwargs) + + +class EnsureUserOwnsProposalMixin(SingleObjectMixin): + def dispatch(self, request, *args, **kwargs): + # make sure that this proposal belongs to the logged in user if self.get_object().user.username != request.user.username: messages.error(request, "No thanks") - return redirect(reverse('submissions_list', kwargs={'camp_slug': self.camp.slug})) + return redirect(reverse('proposal_list', kwargs={'camp_slug': self.camp.slug})) # alright, continue with the request return super().dispatch(request, *args, **kwargs) diff --git a/src/program/models.py b/src/program/models.py index 289abfef..0ebe49e0 100644 --- a/src/program/models.py +++ b/src/program/models.py @@ -13,7 +13,7 @@ import uuid class UserSubmittedModel(CampRelatedModel): """ An abstract model containing the stuff that is shared - between the SpeakerSubmission and EventSubmission models. + between the SpeakerProposal and EventProposal models. """ class Meta: @@ -29,50 +29,59 @@ class UserSubmittedModel(CampRelatedModel): 'auth.User', ) - SUBMISSION_DRAFT = 'draft' - SUBMISSION_PENDING = 'pending' - SUBMISSION_APPROVED = 'approved' - SUBMISSION_REJECTED = 'rejected' + PROPOSAL_DRAFT = 'draft' + PROPOSAL_PENDING = 'pending' + PROPOSAL_APPROVED = 'approved' + PROPOSAL_REJECTED = 'rejected' - SUBMISSION_STATUSES = [ - SUBMISSION_DRAFT, - SUBMISSION_PENDING, - SUBMISSION_APPROVED, - SUBMISSION_REJECTED + PROPOSAL_STATUSES = [ + PROPOSAL_DRAFT, + PROPOSAL_PENDING, + PROPOSAL_APPROVED, + PROPOSAL_REJECTED ] - SUBMISSION_STATUS_CHOICES = [ - (SUBMISSION_DRAFT, 'Draft'), - (SUBMISSION_PENDING, 'Pending approval'), - (SUBMISSION_APPROVED, 'Approved'), - (SUBMISSION_REJECTED, 'Rejected'), + PROPOSAL_STATUS_CHOICES = [ + (PROPOSAL_DRAFT, 'Draft'), + (PROPOSAL_PENDING, 'Pending approval'), + (PROPOSAL_APPROVED, 'Approved'), + (PROPOSAL_REJECTED, 'Rejected'), ] - submission_status = models.CharField( + proposal_status = models.CharField( max_length=50, - choices=SUBMISSION_STATUS_CHOICES, - default=SUBMISSION_DRAFT, + choices=PROPOSAL_STATUS_CHOICES, + default=PROPOSAL_DRAFT, ) def __str__(self): - return '%s (submitted by: %s, status: %s)' % (self.headline, self.user, self.submission_status) + return '%s (submitted by: %s, status: %s)' % (self.headline, self.user, self.proposal_status) +def get_speakerproposal_picture_upload_path(instance, filename): + """ We want speakerproposal pictures saved as MEDIA_ROOT/public/speakerproposals/camp-slug/proposal-uuid/filename """ + return 'public/speakerproposals/%(campslug)s/%(proposaluuid)s/%(filename)s' % { + 'campslug': instance.camp.slug, + 'proposaluuidd': instance.uuid, + 'filename': filename + } + def get_speakersubmission_picture_upload_path(instance, filename): - """ We want speakersubmission pictures saved as MEDIA_ROOT/public/speakersubmissions/camp-slug/submission-uuid/filename """ - return 'public/speakersubmissions/%(campslug)s/%(submissionuuid)s/%(filename)s' % { + """ We want speakerproposal pictures saved as MEDIA_ROOT/public/speakerproposals/camp-slug/proposal-uuid/filename """ + return 'public/speakerproposals/%(campslug)s/%(proposaluuid)s/%(filename)s' % { 'campslug': instance.camp.slug, - 'submissionuuidd': instance.uuid, + 'proposaluuidd': instance.uuid, 'filename': filename } -class SpeakerSubmission(UserSubmittedModel): - """ A speaker submission """ + +class SpeakerProposal(UserSubmittedModel): + """ A speaker proposal """ camp = models.ForeignKey( 'camps.Camp', - related_name='speakersubmissions' + related_name='speakerproposals' ) name = models.CharField( @@ -87,14 +96,14 @@ class SpeakerSubmission(UserSubmittedModel): picture_large = models.ImageField( null=True, blank=True, - upload_to=get_speakersubmission_picture_upload_path, + upload_to=get_speakerproposal_picture_upload_path, help_text='A picture of the speaker' ) picture_small = models.ImageField( null=True, blank=True, - upload_to=get_speakersubmission_picture_upload_path, + upload_to=get_speakerproposal_picture_upload_path, help_text='A thumbnail of the speaker picture' ) @@ -103,15 +112,15 @@ class SpeakerSubmission(UserSubmittedModel): return self.name def get_absolute_url(self): - return reverse_lazy('speakersubmission_detail', kwargs={'camp_slug': self.camp.slug, 'pk': self.uuid}) + return reverse_lazy('speakerproposal_detail', kwargs={'camp_slug': self.camp.slug, 'pk': self.uuid}) -class EventSubmission(UserSubmittedModel): - """ An event submission """ +class EventProposal(UserSubmittedModel): + """ An event proposal """ camp = models.ForeignKey( 'camps.Camp', - related_name='eventsubmissions' + related_name='eventproposals' ) title = models.CharField( @@ -129,7 +138,7 @@ class EventSubmission(UserSubmittedModel): ) speakers = models.ManyToManyField( - 'program.SpeakerSubmission', + 'program.SpeakerProposal', blank=True, help_text='Pick the speaker(s) for this event', ) @@ -139,7 +148,7 @@ class EventSubmission(UserSubmittedModel): return self.title def get_absolute_url(self): - return reverse_lazy('eventsubmission_detail', kwargs={'camp_slug': self.camp.slug, 'pk': self.uuid}) + return reverse_lazy('eventproposal_detail', kwargs={'camp_slug': self.camp.slug, 'pk': self.uuid}) ############################################################################################# @@ -379,11 +388,11 @@ class Speaker(CampRelatedModel): help_text='The event(s) this speaker is anchoring', ) - submission = models.OneToOneField( - 'program.SpeakerSubmission', + proposal = models.OneToOneField( + 'program.SpeakerProposal', null=True, blank=True, - help_text='The speaker submission object this speaker was created from', + help_text='The speaker proposal object this speaker was created from', ) class Meta: diff --git a/src/program/templates/eventproposal_detail.html b/src/program/templates/eventproposal_detail.html new file mode 100644 index 00000000..d1988d18 --- /dev/null +++ b/src/program/templates/eventproposal_detail.html @@ -0,0 +1,24 @@ +{% extends 'program_base.html' %} +{% load commonmark %} + +{% block program_content %} + +

{{ camp.title }} Event Proposal Details

+ +
    +
  • Status: {{ eventproposal.proposal_status }}
  • +
  • ID: {{ eventproposal.uuid }}
  • +
+ +
+
{{ eventproposal.title }}
+
+ {{ eventproposal.abstract|commonmark }} +
+
+ +

+ Back to List +

+ +{% endblock program_content %} diff --git a/src/program/templates/eventsubmission_form.html b/src/program/templates/eventproposal_form.html similarity index 59% rename from src/program/templates/eventsubmission_form.html rename to src/program/templates/eventproposal_form.html index 7f1a8483..26a36643 100644 --- a/src/program/templates/eventsubmission_form.html +++ b/src/program/templates/eventproposal_form.html @@ -6,8 +6,7 @@
{% csrf_token %} {% bootstrap_form form %} - {% bootstrap_button "Save as draft" button_type="submit" button_class="btn-primary" %} - {% bootstrap_button "Save and submit for approval" button_type="submit" button_class="btn-primary" %} + {% bootstrap_button "Save draft" button_type="submit" button_class="btn-primary" %}
{% endblock program_content %} diff --git a/src/program/templates/eventsubmission_detail.html b/src/program/templates/eventsubmission_detail.html deleted file mode 100644 index 8dd52c5d..00000000 --- a/src/program/templates/eventsubmission_detail.html +++ /dev/null @@ -1,24 +0,0 @@ -{% extends 'program_base.html' %} -{% load commonmark %} - -{% block program_content %} - -

{{ camp.title }} Event Proposal Details

- -
    -
  • Status: {{ eventsubmission.submission_status }}
  • -
  • ID: {{ eventsubmission.uuid }}
  • -
- -
-
{{ eventsubmission.title }}
-
- {{ eventsubmission.abstract|commonmark }} -
-
- -

- Back to List -

- -{% endblock program_content %} diff --git a/src/program/templates/proposal_list.html b/src/program/templates/proposal_list.html new file mode 100644 index 00000000..947fe6fd --- /dev/null +++ b/src/program/templates/proposal_list.html @@ -0,0 +1,83 @@ +{% extends 'program_base.html' %} + +{% block title %} +Proposals | {{ block.super }} +{% endblock %} + +{% block program_content %} + +

Your {{ camp.title }} Speaker Proposals

+{% if speakerproposal_list %} + + + + + + + + + + {% for speakerproposal in speakerproposal_list %} + + + + + + {% endfor %} + +
NameStatusActions
{{ speakerproposal.name }}{{ speakerproposal.proposal_status }} + Details + {% if not camp.read_only %} + Modify + Delete + {% endif %} +
+{% else %} +

No speaker proposals found

+{% endif %} + +{% if not camp.read_only %} +Propose New Speaker +{% endif %} + +

+
+

+ +

Your {{ camp.title }} Event Proposals

+{% if eventproposal_list %} + + + + + + + + + + + {% for eventproposal in eventproposal_list %} + + + + + + + {% endfor %} + +
TitleTypeStatusActions
{{ eventproposal.title }}{{ eventproposal.event_type }}{{ eventproposal.proposal_status }} + Details + {% if not camp.read_only %} + Modify + Delete + {% endif %} +
+{% else %} +

No event proposals found

+{% endif %} + +{% if not camp.read_only %} + Propose New Event +{% endif %} + +{% endblock %} diff --git a/src/program/templates/schedule_base.html b/src/program/templates/schedule_base.html index 6b54301b..18bba6d0 100644 --- a/src/program/templates/schedule_base.html +++ b/src/program/templates/schedule_base.html @@ -38,7 +38,7 @@ {% if request.user.is_authenticated %} - Manage My Proposals + Manage My Proposals {% endif %} diff --git a/src/program/templates/speaker_list.html b/src/program/templates/speaker_list.html index 6c69c0b1..80855446 100644 --- a/src/program/templates/speaker_list.html +++ b/src/program/templates/speaker_list.html @@ -11,7 +11,6 @@ {% for speaker in speaker_list %} {{ speaker.name }} ({{ speaker.events.all.count }} event{{ speaker.events.all.count|pluralize }}) - {% if not speaker.is_public %}(unpublished, {{ speaker.submission_status }}){% endif %} {% endfor %} diff --git a/src/program/templates/speakerproposal_detail.html b/src/program/templates/speakerproposal_detail.html new file mode 100644 index 00000000..cf1ed7fb --- /dev/null +++ b/src/program/templates/speakerproposal_detail.html @@ -0,0 +1,37 @@ +{% extends 'program_base.html' %} +{% load commonmark %} + +{% block program_content %} + +

{{ camp.title }} Speaker Proposal Details

+ +
    +
  • Status: {{ speakerproposal.proposal_status }}
  • +
  • ID: {{ speakerproposal.uuid }}
  • +
+ +
+
{{ speakerproposal.name }}
+
+ {% if speakerproposal.picture_large and speakerproposal.picture_small %} +
+
+ {{ speakerproposal.biography|commonmark }} +
+
+ + {{ camp.title }} speaker picture of {{ speakerproposal.name }} + +
+
+ {% else %} + {{ speakerproposal.biography|commonmark }} + {% endif %} +
+
+ +

+ Back to List +

+ +{% endblock program_content %} diff --git a/src/program/templates/speakersubmission_form.html b/src/program/templates/speakerproposal_form.html similarity index 59% rename from src/program/templates/speakersubmission_form.html rename to src/program/templates/speakerproposal_form.html index 2b8f12ae..cfe7d6cc 100644 --- a/src/program/templates/speakersubmission_form.html +++ b/src/program/templates/speakerproposal_form.html @@ -6,8 +6,7 @@
{% csrf_token %} {% bootstrap_form form %} - {% bootstrap_button "Save as draft" button_type="submit" button_class="btn-primary" %} - {% bootstrap_button "Save and submit for approval" button_type="submit" button_class="btn-primary" %} + {% bootstrap_button "Save draft" button_type="submit" button_class="btn-primary" %}
{% endblock program_content %} diff --git a/src/program/templates/speakersubmission_detail.html b/src/program/templates/speakersubmission_detail.html deleted file mode 100644 index 52e982f4..00000000 --- a/src/program/templates/speakersubmission_detail.html +++ /dev/null @@ -1,37 +0,0 @@ -{% extends 'program_base.html' %} -{% load commonmark %} - -{% block program_content %} - -

{{ camp.title }} Speaker Proposal Details

- -
    -
  • Status: {{ speakersubmission.submission_status }}
  • -
  • ID: {{ speakersubmission.uuid }}
  • -
- -
-
{{ speakersubmission.name }}
-
- {% if speakersubmission.picture_large and speakersubmission.picture_small %} -
-
- {{ speakersubmission.biography|commonmark }} -
-
- - {{ camp.title }} speaker picture of {{ speakersubmission.name }} - -
-
- {% else %} - {{ speakersubmission.biography|commonmark }} - {% endif %} -
-
- -

- Back to List -

- -{% endblock program_content %} diff --git a/src/program/templates/submission_list.html b/src/program/templates/submission_list.html deleted file mode 100644 index d1821b22..00000000 --- a/src/program/templates/submission_list.html +++ /dev/null @@ -1,71 +0,0 @@ -{% extends 'program_base.html' %} - -{% block title %} -Proposals | {{ block.super }} -{% endblock %} - -{% block program_content %} - -

Your {{ camp.title }} Speaker Proposals

-{% if speakersubmission_list %} - - - - - - - - - - {% for speakersubmission in speakersubmission_list %} - - - - - - {% endfor %} - -
NameStatusActions
{{ speakersubmission.name }}{{ speakersubmission.submission_status }} - Details - Modify - Delete -
-{% else %} -

No speaker proposals found

-{% endif %} - -Propose New Speaker - -

- -

Your {{ camp.title }} Event Proposals

-{% if eventsubmission_list %} - - - - - - - - - - {% for eventsubmission in eventsubmission_list %} - - - - - - {% endfor %} - -
TitleStatusActions
{{ eventsubmission.title }}{{ eventsubmission.submission_status }} - Details - Modify - Delete -
-{% else %} -

No event proposals found

-{% endif %} - -Propose New Event - -{% endblock %} diff --git a/src/program/views.py b/src/program/views.py index 0ae4b352..cd63aad7 100644 --- a/src/program/views.py +++ b/src/program/views.py @@ -9,50 +9,53 @@ from django.contrib import messages from django.shortcuts import redirect from django.urls import reverse from camps.mixins import CampViewMixin -from .mixins import CreateUserSubmissionMixin, EnsureUnpprovedSubmissionMixin, EnsureUserOwnsSubmissionMixin +from .mixins import CreateUserProposalMixin, EnsureUnpprovedProposalMixin, EnsureUserOwnsProposalMixin, EnsureWritableCampMixin from . import models import datetime, os -############## submissions ######################################################## +############## proposals ######################################################## -class SubmissionListView(LoginRequiredMixin, CampViewMixin, ListView): - model = models.SpeakerSubmission - template_name = 'submission_list.html' - context_object_name = 'speakersubmission_list' +class ProposalListView(LoginRequiredMixin, CampViewMixin, ListView): + model = models.SpeakerProposal + template_name = 'proposal_list.html' + context_object_name = 'speakerproposal_list' def get_queryset(self, **kwargs): - # only show speaker submissions for the current user + # only show speaker proposals for the current user return super().get_queryset().filter(user=self.request.user) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - # add eventsubmissions to the context - context['eventsubmission_list'] = models.EventSubmission.objects.filter(camp=self.camp, user=self.request.user) + # add eventproposals to the context + context['eventproposal_list'] = models.EventProposal.objects.filter(camp=self.camp, user=self.request.user) return context -class SpeakerSubmissionCreateView(LoginRequiredMixin, CampViewMixin, CreateUserSubmissionMixin, CreateView): - model = models.SpeakerSubmission +class SpeakerProposalCreateView(LoginRequiredMixin, CampViewMixin, CreateUserProposalMixin, EnsureWritableCampMixin, CreateView): + model = models.SpeakerProposal fields = ['name', 'biography', 'picture_small', 'picture_large'] - template_name = 'speakersubmission_form.html' + template_name = 'speakerproposal_form.html' -class SpeakerSubmissionUpdateView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsSubmissionMixin, EnsureUnpprovedSubmissionMixin, UpdateView): - model = models.SpeakerSubmission +class SpeakerProposalUpdateView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, EnsureUnpprovedProposalMixin, EnsureWritableCampMixin, UpdateView): + model = models.SpeakerProposal fields = ['name', 'biography', 'picture_small', 'picture_large'] - template_name = 'speakersubmission_form.html' + template_name = 'speakerproposal_form.html' + + def get_success_url(self): + return reverse('proposal_list', kwargs={'camp_slug': self.camp.slug}) -class SpeakerSubmissionDetailView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsSubmissionMixin, DetailView): - model = models.SpeakerSubmission - template_name = 'speakersubmission_detail.html' +class SpeakerProposalDetailView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, DetailView): + model = models.SpeakerProposal + template_name = 'speakerproposal_detail.html' @method_decorator(require_safe, name='dispatch') -class SpeakerSubmissionPictureView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsSubmissionMixin, DetailView): - model = models.SpeakerSubmission +class SpeakerProposalPictureView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, DetailView): + model = models.SpeakerProposal def get(self, request, *args, **kwargs): # is the speaker public, or owned by current user? @@ -77,42 +80,39 @@ class SpeakerSubmissionPictureView(LoginRequiredMixin, CampViewMixin, EnsureUser # (this works for nginx only, other webservers use x-sendfile), # TODO: what about runserver mode here? response = HttpResponse() - response['X-Accel-Redirect'] = '/public/speakersubmissions/%(campslug)s/%(submissionuuid)s/%(filename)s' % { + response['X-Accel-Redirect'] = '/public/speakerproposals/%(campslug)s/%(proposaluuid)s/%(filename)s' % { 'campslug': self.camp.slug, - 'submissionuuid': self.get_object().uuid, + 'proposaluuid': self.get_object().uuid, 'filename': os.path.basename(picture.name), } response['Content-Type'] = '' return response -class EventSubmissionCreateView(LoginRequiredMixin, CampViewMixin, CreateUserSubmissionMixin, CreateView): - model = models.EventSubmission +class EventProposalCreateView(LoginRequiredMixin, CampViewMixin, CreateUserProposalMixin, EnsureWritableCampMixin, CreateView): + model = models.EventProposal fields = ['title', 'abstract', 'event_type', 'speakers'] - template_name = 'eventsubmission_form.html' + template_name = 'eventproposal_form.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['form'].fields['speakers'].queryset = models.SpeakerSubmission.objects.filter(camp=self.camp, user=self.request.user) + context['form'].fields['speakers'].queryset = models.SpeakerProposal.objects.filter(camp=self.camp, user=self.request.user) context['form'].fields['event_type'].queryset = models.EventType.objects.filter(public=True) return context -class EventSubmissionUpdateView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsSubmissionMixin, EnsureUnpprovedSubmissionMixin, UpdateView): - model = models.EventSubmission +class EventProposalUpdateView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, EnsureUnpprovedProposalMixin, EnsureWritableCampMixin, UpdateView): + model = models.EventProposal fields = ['title', 'abstract', 'event_type', 'speakers'] - template_name = 'eventsubmission_form.html' + template_name = 'eventproposal_form.html' - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context['form'].fields['speakers'].queryset = models.SpeakerSubmission.objects.filter(camp=self.camp, user=self.request.user) - context['form'].fields['event_type'].queryset = models.EventType.objects.filter(public=True) - return context + def get_success_url(self): + return reverse('proposal_list', kwargs={'camp_slug': self.camp.slug}) -class EventSubmissionDetailView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsSubmissionMixin, DetailView): - model = models.EventSubmission - template_name = 'eventsubmission_detail.html' +class EventProposalDetailView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsProposalMixin, DetailView): + model = models.EventProposal + template_name = 'eventproposal_detail.html' ################## speakers ###############################################