implements forms and wizard replacement

This commit is contained in:
Benjamin Dauvergne 2012-11-06 15:40:17 +01:00
parent 24696da391
commit f1369f59ec
8 changed files with 496 additions and 0 deletions

102
polynum_blackboard/forms.py Normal file
View File

@ -0,0 +1,102 @@
# -*- coding: utf-8 -*-
from django import forms
from django.conf import settings
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Div, HTML, Field, Fieldset
from polynum.base.models import Entity
from polynum.request import widgets , forms as request_forms
import django_ws
YEAR = '2012'
DEFAULT_CATEGORY = ''
def categories():
yield ('', '---')
ok, response = django_ws.get_bb_conn().get_categories()
if ok:
for category in response.categories:
yield (category.id, category.name)
class func2iter(object):
def __init__(self, func):
self.func = func
def __iter__(self):
return self.func()
class CreateCourseForm(forms.Form):
helper = FormHelper()
helper.form_tag = False
helper.layout = Layout(
'description',
'entity',
'category',
'td_group',
'open_to_visitors',
'subscription_policy',
Div(Field('password'), css_class="hide"))
SUBSCRIPTION_POLICIES = (
('auto', u'oui'),
('password', u'avec mot de passe'),
('no', u'non'))
description = forms.CharField(max_length=32)
entity = forms.ModelChoiceField(Entity.objects.all(), label=u'Diplôme')
category = forms.ChoiceField(label=u'Catégorie',
choices=func2iter(categories))
td_group = forms.CharField(label=u'Groupe de TD', max_length=16,
required=False)
open_to_visitors = forms.BooleanField(label=u'Ouvert aux visiteurs',
required=False)
subscription_policy = forms.ChoiceField(label=u'Auto-inscription', choices=SUBSCRIPTION_POLICIES)
password = forms.CharField(max_length=32)
def __init__(self, request=None, *args, **kwargs):
self.request = request
super(CreateCourseForm, self).__init__(*args, **kwargs)
self.fields['entity'].widget = widgets.MillerColumns(attrs={'data-entity-type': 'etape'})
def clean(self):
cleaned_data = self.cleaned_data
if not cleaned_data['category']:
cleaned_data['category'] = DEFAULT_CATEGORY
if cleaned_data['subscription_policy'] == 'password' and not cleaned_data['password']:
raise forms.ValidationError(u'vous devez fournir un mot de passe')
if cleaned_data['entity'].entity_type.name != 'element pedagogique':
raise forms.ValidationError(u'vous devez sélectionner une UE')
diplome_entity = cleaned_data['entity'].parents().get(entity_type__name='etape')
cleaned_data['course_id'] = '{0}_{1}_{2}'.format(diplome_entity,
YEAR, self.request.user.username)
return cleaned_data
class MyCourseForm(request_forms.CopyrigtsForm):
send_to_mycourse = forms.BooleanField(
label=u'Envoyer le document à MyCourse')
visible_to_students = forms.BooleanField(
label=u'Visible aux étudiants',
initial=True)
course_name = forms.CharField(max_length=64)
class Meta(request_forms.CopyrigtsForm.Meta):
fields = ('copyright',)
required = ('copyright',)
def __init__(self, *args, **kwargs):
super(MyCourseForm, self).__init__(*args, **kwargs)
self.fields['course_name'].widget = forms.HiddenInput()
self.fields['send_to_mycourse'].initial = \
settings.POLYNUM_BB_SEND_TO_MYCOURSE_DEFAULT
self.helper.layout = Layout(
'copyright',
Fieldset(u'Diffusion sur la plateform d\'e-Learning',
'send_to_mycourse',
Div(
'visible_to_students',
HTML('{% include \'_select_course.html\' %}'),
id='mycourse-block', css_class='hide')))

View File

@ -0,0 +1,10 @@
from django.db import models
from polynum.base.models import Request
class BlackBoardPush(models.Model):
request = models.ForeignKey(Request)
course_name = models.TextField(max_length=64)
visible_to_students = models.BooleanField(blank=True)
sent = models.BooleanField(blank=True)

View File

@ -0,0 +1,54 @@
{% load sekizai_tags %}
{% load url from future %}
<div class="course-selector" data-refresh-url="{% url 'courses_list' pk=object.pk %}">
{% if courses.error %}
<div class="alert alert-error">Impossible de récupérer la liste des cours: {{ course.error }}</div>
{% else %}
<div class="control-group">
<label for="course-type-owner" class="control-label">Mes cours</label>
<div class="controls">
<select {% if not courses.user_courses.courses %}disabled{% endif %} class="courses-selector">
{% if not courses.user_courses.courses %}
<option>Aucun cours disponible</option>
{% else %}
<option value="">---</option>
{% for course in courses.user_courses.courses %}
<option {% if not course.avaiblable %}disabled{% endif %} value="{{ course.id }}">{{ course.name }}</option>
{% endfor %}
{% endif %}
</select>
<a href="#create-course" role="button" class="btn" data-toggle="modal">Créer un nouveau cours</a>
</div>
</div>
<div class="control-group">
<label for="course-type-ue" class="control-label">Cours proches du document</label>
<div class="controls">
<select {% if not courses.ue_courses.courses %}disabled{% endif %} class="courses-selector">
{% if not courses.ue_courses.courses %}
<option>Aucun cours disponible</option>
{% else %}
<option value="">---</option>
{% for course in courses.ue_courses.courses %}
<option {% if not course.avaiblable %}disabled{% endif %} value="{{ course.id }}">{{ course.name }}</option>
{% endfor %}
{% endif %}
</select>
</div>
</div>
{% endif %}
</div>
{% addtoblock "endscripts" %}
<script>
(function ($) {
$(function () {
$('body', 'change', '.courses-selector', function (){
$('.courses-selector').not(this).val('');
$('.courses-input').val($(this).val());
});
})
})(window.jQuery)
</script>
{% endaddtoblock %}

View File

@ -0,0 +1,73 @@
{% extends "new_request.html" %}
{% load url from future %}
{% load sekizai_tags %}
{% load crispy_forms_tags %}
{% load editor %}
{% block extra_scripts %}
{{ block.super }}
{{ create_course_form.media.css }}
<style>
#create-course .miller-columns {
height: 10em;
}
.modal.large {
margin: -250px 0px 0px -380px;
width: 760px;
}
.modal.large .modal-body {
max-height: 600px;
}
</style>
{% endblock %}
{% block form %}
{% editablecontent wizard.steps.current "form-header" %}
{% endeditablecontent %}
{{ wizard.management_form }}
{% crispy wizard.form %}
{% editablecontent wizard.steps.current "form-footer" %}
{% endeditablecontent %}
{% addtoblock "endscripts" %}
<div id="create-course" class="modal hide fade large">
<form action="{% url 'create_course' %}" method="POST">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3>Création d'un nouveau cours</h3>
</div>
<div class="modal-body">
{% crispy create_course_form %}
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn">Fermer</a>
<button class="btn btn-primary">Créer</a>
</div>
</form>
</div>
{{ create_course_form.media.js }}
<script>
(function ($) {
$(function () {
$('#id_subscription_policy').on('change', function() {
if ($(this).val() == 'password') {
$('#div_id_password').parent().show();
} else {
$('#div_id_password').parent().hide();
}
});
$('#create-course').on('shown', function () {
$('.miller-columns').millercolumns('refresh');
});
$('#id_document_copyrights-send_to_mycourse').on('change', function () {
$('#mycourse-block').toggle('slow');
});
$('#mycourse-block').toggle($('#id_document_copyrights-send_to_mycourse').is(':checked'));
})
})(window.jQuery)
</script>
{% endaddtoblock %}
{% endblock %}

View File

@ -0,0 +1,152 @@
<form class="form-horizontal">
<div class="control-group">
<label for="mycourse" class="control-label">Diffusion dans MyCourse</label>
<div class="controls">
{% with mycourse=1 %}
<input type="checkbox" id="mycourse" name="mycourse" {% if mycourse %}checked{% endif %}>
</div>
<style>
#diffusion { margin-left: 2em; border-left: 1px solid #DDD; padding: 1ex; }
.element-pedagogique { color: green; font-weight: bold; }
span.error { color: red }
#course-type-new-block { display: none; }
</style>
{% if not mycourse %}
<style>
#diffusion { display: none; }
</style>
{% endif %}
{% endwith %}
</div>
<div id="diffusion" class="control-group">
<div class="control-group">
<label for="visible" class="control-label">Fichier visible aux étudiants</label>
<div class="controls">
<input type="checkbox" id="visible" checked>
</div>
</div>
<div class="control-group">
<label for="control-type-owner" class="control-label">Dans un de mes cours</label>
<div class="controls">
<input type="radio" id="course-type-owner" name="course-type" {% if mycourse %}checked{% endif %}>
<select id="courses-owner" class="courses">
<option value="">---</option>
<option disabled>A</option>
<option disabled>B (indisponible)</option>
</select>
</div>
</div>
<div class="control-group">
<label for="control-type-sponsor" class="control-label">Dans un cours du commanditaire</label>
<div class="controls">
<input type="radio" id="course-type-sponsor" name="course-type">
<select id="courses-sponsor" class="courses">
<option value="">---</option>
<option>A</option>
<option>B</option>
</select>
</div>
</div>
<div class="control-group">
<label for="control-type-ue" class="control-label">Dans un cours de l'UE </label>
<div class="controls">
<input type="radio" id="course-type-ue" name="course-type">
<select id="courses-ue" class="courses">
<option value="">---</option>
</select>
</div>
</div>
<div class="control-group">
<label for="control-type-new" class="control-label">Créer un nouveau cours</label>
<div class="controls">
<input type="radio" id="course-type-new" name="course-type">
</div>
<div class="controls" id="course-type-new-block">
<div class="control-group">
<label for="control-type-ue">UE du nouveau cours (les UE sont affichées en vert)</label>
<input type="hidden" id="ue">
<div id="ue-selector">
</div>
<label for="control-type-ue">Groupe de TD (facultatif)</label>
<input type="text" id="td-group">
<div class="control-group">
<label for="control-type-new" class="control-label">Ouvert aux visiteurs</label>
<div class="controls">
<input type="checkbox" name="open-to-visitors">
</div>
</div>
<p>Nom du nouveau cours: <span id="course-name"></span>
</div>
</div>
</div>
</div>
</form>
{% addtoblock "css" %}
<link href="{{STATIC_URL}}eo/css/eo.millercolumns.css" rel="stylesheet">
{% endaddtoblock %}
{% addtoblock "endscripts" %}
<script src="{{STATIC_URL}}jquery/js/jquery-ui.js"></script>
<script src="{{STATIC_URL}}eo/js/eo.millercolumns.js"></script>
<script src="{{STATIC_URL}}eo/js/eo.django.millercolumns.widget.js"></script>
<script>
$(function () {
var MyCourseDelegate = PolynumDelegate('ue');
function UpdateCourseName() {
var item = $('#ue-selector').millercolumns('getSelection');
var parents = MyCourseDelegate.getParents(item);
var diplome;
var ue = MyCourseDelegate._getItem(item);
if (ue.type != 'element pedagogique') {
$('#course-name').html('<span class="error">L\'entité sélectionnée n\'est pas une UE</span>');
return;
}
for (i = parents.length - 1; i >= 0; i--) {
var data = MyCourseDelegate._getItem(parents[i]);
if (data.type == 'etape') {
diplome = data;
break;
}
}
var course_name = diplome.code+'_2012_'+ue.code+'_{{user.username}}';
var group = $('#td-group').val();
if (group) {
course_name += '_' + group;
}
$('#course-name').text(course_name);
}
MyCourseDelegate.old_selectItem = MyCourseDelegate.selectItem;
MyCourseDelegate.old_isLeaf = MyCourseDelegate.isLeaf;
MyCourseDelegate.is
MyCourseDelegate.selectItem = function (item) {
$('#course-type-new').attr('checked', 1);
this.old_selectItem(item);
UpdateCourseName();
}
$('#td-group').keyup(function () {
UpdateCourseName();
});
$('#ue-selector').millercolumns({delegate: MyCourseDelegate});
if ('{{object.entity.id}}') {
$('#ue-selector').millercolumns('setItem', '{{object.entity.id}}');
}
$('#mycourse').change(function () {
$('#diffusion').toggle();
return true;
});
$('.courses').each(function (i, v) {
if ($('option', v).not('[disabled]').length < 2) {
$('select, input', $(v).parent()).attr('disabled', 1);
$('<span>Aucun cours disponible</span>').appendTo($(v).parent());
}
});
$('#course-type-new').change(function (){
$('#course-type-new-block').toggle();
$('#ue-selector').millercolumns('refresh');
UpdateCourseName();
});
})
</script>
{% endaddtoblock %}

View File

@ -0,0 +1,12 @@
from django.conf.urls import patterns, include, url
import views
import wizard
urlpatterns = patterns('',
url(r'^request/(?P<pk>\d+)/edit/(?P<step>.+)/$', wizard.request_wizard_step, name='request_wizard_step'),
url(r'^request/(?P<pk>\d+)/edit/$', wizard.request_wizard_step, name='request_wizard'),
url(r'^request/(?P<pk>\d+)/course-list/$', views.courses_list, name='courses_list'),
url(r'bb/create_course/', views.create_course, name='create_course'),
(r'^', include('polynum.urls')))

View File

@ -0,0 +1,62 @@
import json
from django.http import HttpResponse
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_POST
from django.template import RequestContext
from django.template.loader import render_to_string
from django import shortcuts
from polynum.base.models import Request
import django_ws
from forms import CreateCourseForm
@require_POST
@login_required
def create_course(request):
form = CreateCourseForm(request.POST, request=request)
ctx = { 'form': form }
if form.is_valid():
conn = get_conn()
course_id = form.cleaned_data['course_id']
ok, result = conn.create_course(course_id,
form.cleaned_data['description'],
form.cleaned_data['category'],
form.cleaned_data['open_to_visitors'],
form.cleaned_data['subscription_policy'] != 'no',
form.cleaned_data['password'])
ctx['ok'], ctx['result'] = ok, result
form = CreateCourseForm(request=request)
data = {
"html": render_to_string("_create_course.html", ctx,
context_instance=RequestContext(request))
}
return HttpResponse(json.dumps(data), mimetype="application/json")
@login_required
def courses_list(request, pk):
polynum_request = shortcuts.get_object_or_404(Request, pk=pk)
data = { "html": render_to_string("_select_course.html", {
"courses": courses_ctx(request, polynum_request)},
context_instance=RequestContext(request)) }
return HttpResponse(json.dumps(data), mimetype="application/json")
def courses_ctx(request, polynum_request):
ctx = {}
conn = django_ws.get_bb_conn()
ok, result = conn.get_course_by_owner(request.user.username)
if not ok:
ctx['error'] = result
return ctx
user_courses = result
if polynum_request.entity:
ok, result = conn.get_course_by_ue(polynum_request.entity.code)
if not ok:
ctx['error'] = result
return ctx
ue_courses = result
return {
'ue_courses': ue_courses,
'user_courses': user_courses,
}

View File

@ -0,0 +1,31 @@
from django.contrib.auth.decorators import login_required
from polynum.request import views as request_views
import forms
import views
named_new_request_forms = []
for step, form_class in request_views.named_new_request_forms:
p = (step, form_class)
if step == 'document_copyrights':
p = (step, forms.MyCourseForm)
named_new_request_forms.append(p)
class RequestWizardView(request_views.RequestWizardView):
def get_context_data(self, form, **kwargs):
context = super(RequestWizardView, self).get_context_data(form=form, **kwargs)
polynum_request = self.get_object()
diplome_entity = polynum_request.entity
if diplome_entity:
possible_diplome_entity = diplome_entity.parents(True).filter(entity_type__name='etape')
if possible_diplome_entity:
diplome_entity = possible_diplome_entity[0]
context['create_course_form'] = forms.CreateCourseForm(request=self.request,
initial={'entity': diplome_entity})
context['courses'] = views.courses_ctx(self.request, polynum_request)
return context
request_wizard_step = login_required(RequestWizardView.as_view(named_new_request_forms,
done_step_name='finished', url_name='request_wizard_step'))