Permalink
Browse files

Ask for help implemented

  • Loading branch information...
alfredo committed Mar 20, 2012
1 parent 240e2c0 commit fae84a5d3197731894371cd7488a97e3ff4472e5
View
@@ -8,7 +8,7 @@
Category, ExclusionFlag, JudgingCriterion,
JudgingAnswer, Judgement, JudgeAssignment,
PhaseCriterion, PhaseRound, SubmissionParent,
- SubmissionVersion)
+ SubmissionVersion, SubmissionHelp)
from badges.models import SubmissionBadge
@@ -168,3 +168,4 @@ class SubmissionParentAdmin(admin.ModelAdmin):
admin.site.register(Judgement, JudgementAdmin)
admin.site.register(JudgeAssignment)
admin.site.register(SubmissionParent, SubmissionParentAdmin)
+admin.site.register(SubmissionHelp)
@@ -1,5 +1,6 @@
import functools
+from challenges.models import Challenge
from django.conf import settings
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.models import User, Permission
@@ -47,3 +48,25 @@ def phase_open_required(func=None, methods_allowed=None):
def phase_closed_required(func=None, methods_allowed=None):
return phase_required(func=func, methods_allowed=methods_allowed,
is_open=False)
+
+
+def project_challenge_required(func):
+ """Makes sure a valid project and a challenge are passed to a view"""
+ @functools.wraps(func)
+ def wrapper(request, *args, **kwargs):
+ if not all(['project' in kwargs, 'slug' in kwargs]):
+ raise ValueError('``project_challenge_required`` decorator '
+ 'requires ``slug`` and ``project`` arguments'
+ ' as part of the view')
+ project_slug = kwargs.pop('project')
+ challenge_slug = kwargs.pop('slug')
+ # Make sure we have a challenge and a project by those slugs
+ try:
+ challenge = (Challenge.objects.select_related('project')
+ .get(project__slug=project_slug,
+ slug=challenge_slug))
+ except Challenge.DoesNotExist:
+ raise Http404
+ # pass the challenge and project instances to the view
+ return func(request, challenge.project, challenge, *args, **kwargs)
+ return wrapper
View
@@ -6,7 +6,7 @@
from challenges.models import (Submission, ExternalLink, Category,
Judgement, JudgingCriterion, JudgingAnswer,
- PhaseRound)
+ PhaseRound, SubmissionHelp)
from challenges.widgets import CustomRadioSelect
@@ -249,3 +249,9 @@ def clean(self):
raise forms.ValidationError('This round dates overlap with other '
'rounds')
return self.cleaned_data
+
+
+class SubmissionHelpForm(forms.ModelForm):
+ class Meta:
+ model = SubmissionHelp
+ fields = ('notes', 'status',)
@@ -0,0 +1,6 @@
+from django.db import models
+
+class SubmissionHelpManager(models.Manager):
+
+ def get_active(self):
+ return self.filter(status=self.model.PUBLISHED)

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -15,6 +15,7 @@
from django.dispatch import receiver
from challenges.lib import cached_bleach, cached_property
+from challenges.managers import SubmissionHelpManager
from django_extensions.db.fields import (AutoSlugField,
CreationDateTimeField,
ModificationDateTimeField)
@@ -405,6 +406,10 @@ def get_delete_url(self):
def get_judging_url(self):
"""Return the URL to judge this submission."""
return self._lookup_url('entry_judge', {'pk': self.id})
+
+ def get_help_url(self):
+ """Return the URL to judge this submission."""
+ return self._lookup_url('entry_help', {'pk': self.id})
# Permission shortcuts, for use in templates
@@ -697,3 +702,26 @@ class Meta:
def __unicode__(self):
return u'Version for %s on %s' % (self.submission, self.created)
+
+
+class SubmissionHelp(models.Model):
+ """Users can ask for help with a given submission"""
+ PUBLISHED = 1
+ DRAFT = 2
+ STATUS_CHOICES = (
+ (PUBLISHED, 'Published'),
+ (DRAFT, 'Draft'),
+ )
+ parent = models.OneToOneField('challenges.SubmissionParent')
+ created = CreationDateTimeField()
+ notes = models.TextField()
+ status = models.IntegerField(choices=STATUS_CHOICES, default=DRAFT)
+
+ # managers
+ objects = SubmissionHelpManager()
+
+ class Meta:
+ verbose_name_plural = 'Submission Help'
+
+ def __unicode__(self):
+ return u'Help needed for %s' % self.parent
View
@@ -23,9 +23,11 @@
from voting.models import Vote
from badges.models import SubmissionBadge
from commons.helpers import get_page
-from challenges.decorators import phase_open_required, phase_closed_required
+from challenges.decorators import (phase_open_required, phase_closed_required,
+ project_challenge_required)
from challenges.forms import (EntryForm, EntryLinkForm, InlineLinkFormSet,
- JudgingForm, NewEntryForm)
+ JudgingForm, NewEntryForm, SubmissionHelpForm,
+ SubmissionHelp)
from challenges.models import (Challenge, Phase, Submission, Category,
ExternalLink, Judgement, SubmissionParent,
JudgeAssignment, SubmissionVersion)
@@ -232,20 +234,15 @@ def extract_form_errors(form, link_form):
@phase_open_required(methods_allowed=['GET'])
@login_required
-def create_entry(request, project, slug):
+@project_challenge_required
+def create_entry(request, project, challenge):
"""Creates a ``Submission`` from the user details"""
- try:
- challenge = (Challenge.objects.select_related('project')
- .get(project__slug=project, slug=slug))
- except Challenge.DoesNotExist:
- raise Http404
- project = challenge.project
profile = request.user.get_profile()
LinkFormSet = formset_factory(EntryLinkForm, extra=2)
form_errors = False
if request.method == 'POST':
# If there is not an active phase it shouldn't be able to get here
- phase = Phase.objects.get_current_phase(slug)
+ phase = Phase.objects.get_current_phase(challenge.slug)
if not phase:
raise Http404
form = NewEntryForm(data=request.POST,
@@ -289,15 +286,9 @@ def create_entry(request, project, slug):
'errors': form_errors
})
-
-def entry_version(request, project, slug, entry_id):
+@project_challenge_required
+def entry_version(request, project, challenge, entry_id):
"""Redirects an ``Submission`` version to the ``SubmissionParent``"""
- try:
- challenge = (Challenge.objects.select_related('project')
- .get(project__slug=project, slug=slug))
- except Challenge.DoesNotExist:
- raise Http404
- # Submisison is on the Parent
try:
parent = (SubmissionParent.objects
.get(submission__id=entry_id,
@@ -315,14 +306,9 @@ def entry_version(request, project, slug, entry_id):
return HttpResponseRedirect(version.parent.get_absolute_url())
-def entry_show(request, project, slug, entry_id, judging_form=None):
+@project_challenge_required
+def entry_show(request, project, challenge, entry_id, judging_form=None):
"""Detail of an idea, show any related information to it"""
- try:
- challenge = (Challenge.objects.select_related('project')
- .get(project__slug=project, slug=slug))
- except Challenge.DoesNotExist:
- raise Http404
- project = challenge.project
# SubmissionParent acts as an proxy for any of the revisions.
# and it only shows the current revision
try:
@@ -544,7 +530,7 @@ def get_forms(self):
def get(self, request, *args, **kwargs):
"""Respond to a GET request by displaying the edit form."""
self.object = self.get_object()
-
+ self.parent = self.object.parent
context = self.get_context_data(**self.get_forms())
"""
We now access errrors direct in the template - so with no errors
@@ -574,6 +560,7 @@ def form_valid(self, form, link_form):
messages.success(self.request, 'Your entry has been updated.')
phase = Phase.objects.get_current_phase(settings.IGNITE_CHALLENGE_SLUG)
object_phase = self.object.phase_round if self.object.phase_round else None
+ self.parent = self.object.parent
if self.object.phase == phase and object_phase == phase.current_round:
# No changes during a different Round and Phase update the
# current entry
@@ -584,7 +571,6 @@ def form_valid(self, form, link_form):
# Phase / Round with the new details
previous_submission = self.object
profile = self.request.user.get_profile()
- parent = previous_submission.parent
submission = Submission(created_by=profile,
category=previous_submission.category,
phase=phase)
@@ -599,7 +585,7 @@ def form_valid(self, form, link_form):
if not kwargs['files']:
new_submission.sketh_note = previous_submission.sketh_note
new_submission.save()
- parent.update_version(new_submission)
+ self.parent.update_version(new_submission)
# Duplicate links
for link in link_form.cleaned_data:
if not link:
@@ -671,3 +657,37 @@ def dispatch(self, *args, **kwargs):
return super(DeleteEntryView, self).dispatch(*args, **kwargs)
entry_delete = DeleteEntryView.as_view()
+
+
+@login_required
+@project_challenge_required
+def submission_help(request, project, challenge, entry_id):
+ """``Submissions`` that need help"""
+ # SubmissionParent acts as an proxy for any of the revisions.
+ # and it only shows the current revision
+ try:
+ parent = (SubmissionParent.objects.select_related('submission')
+ .get(slug=entry_id, submission__phase__challenge=challenge))
+ except SubmissionParent.DoesNotExist:
+ raise Http404
+ # Make sure the user can edit the submission
+ if not parent.submission.editable_by(request.user):
+ raise Http404
+ try:
+ help_instance = parent.submissionhelp
+ except SubmissionHelp.DoesNotExist:
+ help_instance = None
+ if request.method == 'POST':
+ form = SubmissionHelpForm(request.POST, instance=help_instance)
+ instance = form.save(commit=False)
+ instance.parent = parent
+ instance.save()
+ if instance.status == SubmissionHelp.PUBLISHED:
+ msg = _('Your message has been posted successfully and is now '
+ 'available on your Idea page')
+ messages.success(request, msg)
+ return HttpResponseRedirect(parent.submission.get_absolute_url())
+ else:
+ form = SubmissionHelpForm(instance=help_instance)
+ context = {'form': form}
+ return jingo.render(request, 'challenges/submission_help.html', context)
View
@@ -75,7 +75,7 @@ def test(*args):
# TODO: add the rest of the apps and make sure the tests pass!
apps = 'challenges timeslot webcast awards activity badges events users'
print yellow('Testing: %s' % apps)
- local('python manage.py test %s --settings=settings_test' % apps)
+ local('python manage_test.py test %s --settings=settings_test' % apps)
def deploy(branch):
View
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+import os
+import site
+import sys
+
+ROOT = os.path.dirname(os.path.abspath(__file__))
+path = lambda *a: os.path.join(ROOT,*a)
+
+
+# Adjust the python path and put local packages in front.
+prev_sys_path = list(sys.path)
+
+site.addsitedir(path('apps'))
+site.addsitedir(path('lib'))
+
+# Local (project) vendor library
+site.addsitedir(path('vendor-local'))
+site.addsitedir(path('vendor-local/lib/python'))
+
+# Global (upstream) vendor library
+site.addsitedir(path('vendor'))
+site.addsitedir(path('vendor/lib/python'))
+
+
+# Move the new items to the front of sys.path. (via virtualenv)
+new_sys_path = []
+for item in list(sys.path):
+ if item not in prev_sys_path:
+ new_sys_path.append(item)
+ sys.path.remove(item)
+sys.path[:0] = new_sys_path
+
+from django.core.management import execute_manager
+import imp
+
+try:
+ imp.find_module('settings_local')
+ import settings_local as settings
+except ImportError:
+ try:
+ imp.find_module('settings')
+ import settings
+ except ImportError:
+ sys.stderr.write(
+ "Error: Tried importing 'settings_local.py' and 'settings.py' "
+ "but neither could be found (or they're throwing an ImportError)."
+ " Please come back and try again later.")
+ raise
+
+# Configure Celery
+import djcelery
+djcelery.setup_loader()
+
+# Monkey-patch django forms to avoid having to use Jinja2's |safe everywhere.
+import safe_django_forms
+safe_django_forms.monkeypatch()
+
+if __name__ == "__main__":
+ execute_manager(settings)
View
@@ -20,5 +20,6 @@ nose_progressive==1.3
# Dev tools
-e git://github.com/robhudson/django-debug-toolbar.git#egg=django-debug-toolbar
+-e git://github.com/playfire/django-debug-toolbar-user-panel.git#egg=django-debug-toolbar-user-panel
fabric
ipdb
@@ -30,6 +30,7 @@ <h1 class="shout">{{ entry.title }}</h1>
{% if entry.editable_by(user) %}
<ul class="user_tools">
{% if entry.owned_by(user) %}
+ <li><a href="{{ url('entry_help', entry_id=entry.parent.slug) }}" class="cta do">Ask for help</a></li>
<li><a href="{{ entry.get_edit_url() }}" class="cta do">Edit your submission</a></li>
<li><a href="{{ entry.get_delete_url() }}" class="cta do">Delete your submission</a></li>
{% if entry.needs_booking %}
@@ -0,0 +1,17 @@
+{% extends "base.html" %}
+{% block content %}
+<h1>Help wanted</h1>
+<form method="post" id="form-submissionhelp-id" action="">
+ <div class="highlight {% if form.errors %}fail{% endif %}">
+ <label for="wmd-input" class="announce">{{ _('Describe what do you need help with') }}</label>
+ <p class="hint" id="info_description">{{ _('Describe who would be a good fit for helping you with your Idea') }}</p>
+ <div class="ed">
+ {% for error in form.notes.errors %}<strong>*{{ error }}</strong>{% endfor%}
+ {{ form.notes }}
+ {{ form.status }}
+ </div>
+ </div>
+ {{ csrf()|safe }}
+ <input type="submit" value="Update" class="cta">
+</form>
+{% endblock content %}
Oops, something went wrong.

0 comments on commit fae84a5

Please sign in to comment.