Skip to content

Commit

Permalink
SIO-1421 Teachers: separate link for adding a teacher
Browse files Browse the repository at this point in the history
Change-Id: Ifc00ab7e1410f302bff6096a5970b57f1a5f8ba2
  • Loading branch information
wosiu committed Jun 16, 2014
1 parent 6fe8f7b commit df281ce
Show file tree
Hide file tree
Showing 10 changed files with 389 additions and 174 deletions.
4 changes: 2 additions & 2 deletions oioioi/teachers/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ def response_add(self, request, obj, post_url_continue='../%s/'):
return super(ContestAdminMixin, self).response_add(request, obj,
post_url_continue)
self.message_user(request, _("Contest added successfully."))
return redirect('oioioi.teachers.views.pupils_view',
contest_id=obj.id)
return redirect('oioioi.teachers.views.members_view',
contest_id=obj.id, member_type='pupil')

def __init__(self, *args, **kwargs):
super(ContestAdminMixin, self).__init__(*args, **kwargs)
Expand Down
112 changes: 112 additions & 0 deletions oioioi/teachers/migrations/0005_separate_key_for_joining_teachers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
from oioioi.teachers.models import RegistrationConfig

class Migration(SchemaMigration):

def forwards(self, orm):
db.rename_column(u'teachers_registrationconfig', 'key', 'pupil_key')
db.rename_column(u'teachers_registrationconfig', 'is_active', 'is_active_pupil')

# Adding field 'RegistrationConfig.teacher_key', temporary allows setting as null
db.add_column(u'teachers_registrationconfig', 'teacher_key',
self.gf('django.db.models.fields.CharField')(max_length=40, null=True))

# Adding field 'RegistrationConfig.is_active_teacher'
db.add_column(u'teachers_registrationconfig', 'is_active_teacher',
self.gf('django.db.models.fields.BooleanField')(default=True),
keep_default=False)

if not db.dry_run:
for p in orm.RegistrationConfig.objects.all():
p.teacher_key = p.generate_key()
p.save()

db.alter_column(u'teachers_registrationconfig', 'teacher_key',
self.gf('django.db.models.fields.CharField')(max_length=40))

def backwards(self, orm):
db.rename_column(u'teachers_registrationconfig', 'pupil_key', 'key')
db.rename_column(u'teachers_registrationconfig', 'is_active_pupil', 'is_active')


# Deleting field 'RegistrationConfig.teacher_key'
db.delete_column(u'teachers_registrationconfig', 'teacher_key')

# Deleting field 'RegistrationConfig.is_active_teacher'
db.delete_column(u'teachers_registrationconfig', 'is_active_teacher')




models = {
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'contests.contest': {
'Meta': {'object_name': 'Contest'},
'controller_name': ('oioioi.base.fields.DottedNameField', [], {'max_length': '255', 'superclass': "'oioioi.contests.controllers.ContestController'"}),
'creation_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
'default_submissions_limit': ('django.db.models.fields.IntegerField', [], {'default': '10', 'blank': 'True'}),
'id': ('django.db.models.fields.CharField', [], {'max_length': '32', 'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
},
u'teachers.contestteacher': {
'Meta': {'unique_together': "(('contest', 'teacher'),)", 'object_name': 'ContestTeacher'},
'contest': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contests.Contest']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'teacher': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['teachers.Teacher']"})
},
u'teachers.registrationconfig': {
'Meta': {'object_name': 'RegistrationConfig'},
'contest': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['contests.Contest']", 'unique': 'True', 'primary_key': 'True'}),
'is_active_teacher': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_active_pupil': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'pupil_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
'teacher_key': ('django.db.models.fields.CharField', [], {'max_length': '40'})
},
u'teachers.teacher': {
'Meta': {'object_name': 'Teacher'},
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'school': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True', 'primary_key': 'True'})
}
}

complete_apps = ['teachers']
21 changes: 13 additions & 8 deletions oioioi/teachers/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,19 @@ def __unicode__(self):

class RegistrationConfig(models.Model):
contest = models.OneToOneField(Contest, primary_key=True)
is_active = models.BooleanField(default=True)
key = models.CharField(max_length=40)

def save(self, *args, **kwargs):
if not self.key:
self.generate_key()
super(RegistrationConfig, self).save(*args, **kwargs)
is_active_pupil = models.BooleanField(default=True)
is_active_teacher = models.BooleanField(default=True)
pupil_key = models.CharField(max_length=40)
teacher_key = models.CharField(max_length=40)

def __init__(self, *args, **kwargs):
super(RegistrationConfig, self).__init__(*args, **kwargs)
if self.contest:
if not self.teacher_key:
self.teacher_key = self.generate_key()
if not self.pupil_key:
self.pupil_key = self.generate_key()

def generate_key(self):
data = str(random.random()) + str(self.contest_id)
self.key = hashlib.sha1(data).hexdigest()
return hashlib.sha1(data).hexdigest()
7 changes: 7 additions & 0 deletions oioioi/teachers/static/teachers/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,10 @@ form.teachers-delete-pupils .info {
font-size: inherit;
}

.copy_link_container {
position: relative;
}

h3.members {
margin-top: 1em;
}
8 changes: 5 additions & 3 deletions oioioi/teachers/templates/teachers/activation_error.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@

{% block content %}
<div class="empty-space-filler">
{% if not registration_active %}
<p>{% trans "Registration has been disabled by the teacher." %}</p>
{% elif not key_ok %}
{% if teacher_key_ok and not teacher_registration_active %}
<p>{% trans "Registration for teachers has been disabled." %}</p>
{% elif pupil_key_ok and not pupil_regitration_active %}
<p>{% trans "Registration for pupils has been disabled." %}</p>
{% elif not teacher_key_ok and not pupil_key_ok %}
<p>{% trans "Invalid activation link." %}</p>
{% endif %}
</div>
Expand Down
10 changes: 7 additions & 3 deletions oioioi/teachers/templates/teachers/confirm_join.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@
{% block title %}{% if is_teacher %}{% trans "Choose registration type" %}{% else %}{% trans "Confirm registration" %}{% endif %}{% endblock %}

{% block help_text %}
{% if is_teacher %}
{% if is_teacher_registration %}
<p>{% blocktrans %}Your account is a teacher account. Please choose, if you wish to
register to the {{ contest }} contest as a teacher or as a pupil.{% endblocktrans %}
{% else %}
<p>{% blocktrans %}You are going to register to the {{ contest }} contest. Please, confirm your registration.{% endblocktrans %}
{% if has_teacher_perm %}
<p>{% blocktrans %}Your account is a teacher account. If you wish to register to the {{ contest }} contest as a teacher, <strong>ask contest admin for link intended for teachers</strong>. Otherwise confirm below your registration as a pupil.{% endblocktrans %}
{% else %}
<p>{% blocktrans %}You are going to register to the {{ contest }} contest. Please, confirm your registration.{% endblocktrans %}
{% endif %}
{% endif %}
{% endblock %}

{% block buttons %}
{% if is_teacher %}
{% if is_teacher_registration %}
<button type="submit" class="btn btn-primary" name="register_as" value="teacher">{% trans "Register as a teacher" %}</button>
<button type="submit" class="btn" name="register_as" value="pupil">{% trans "Register as a pupil" %}</button>
{% else %}
Expand Down
111 changes: 111 additions & 0 deletions oioioi/teachers/templates/teachers/members.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
{% extends "base-with-menu.html" %}
{% load i18n listutil %}

{% block styles %}
{{ block.super }}
<link charset="utf-8" rel="stylesheet" type="text/css" href="{{ STATIC_URL }}teachers/style.css">
{% endblock %}

{% block scripts %}
{{ block.super }}
<script type="text/javascript" src="{{ STATIC_URL }}teachers/ZeroClipboard.min.js"></script>
{% endblock %}

{% block title %}
{% if member_type == 'teacher' %}
{% trans "Contest teachers" %}
{% else %}
{% trans "Contest pupils" %}
{% endif %}
{% endblock %}

{% block content %}
<h2>{% trans "Contest "|add:member_type|add:"s" %}</h2>

{% if is_registration_active %}
{% if member_type == 'teacher' %}
<p>{% trans "To allow a teacher to access this contest, ask him/her to visit the following link:" %}</p>
{% else %}
<p>{% trans "To allow a pupil to access this contest, ask him/her to visit the following link:" %}</p>
{% endif %}
<pre>{{ registration_link }}</pre>
<div class="pull-right" id="copy_link_container">
<button class="btn btn-mini" id="copy_link">
{% trans "Copy to clipboard" %}
</button>
</div>
<div class="pull-right" id="copy_link_ok" style="display: none">
<i class="icon-ok"></i><small> copied!</small>
</div>
<script type="text/javascript">
ZeroClipboard.setMoviePath('{{ STATIC_URL }}teachers/ZeroClipboard.swf');
var clip = new ZeroClipboard.Client();
clip.setText('{{ registration_link|escapejs }}');
clip.glue('copy_link', 'copy_link_container');
clip.addEventListener('onComplete', function() {
$('#copy_link_container').hide();
$('#copy_link_ok').show();
});
</script>
<p>
<a class="btn btn-info btn-mini" data-post-url="{% url 'teachers_disable_registration' contest_id=contest.id member_type=member_type %}">{% trans "Disable link" %}</a>
<a class="btn btn-mini" data-post-url="{% url 'teachers_regenerate_key' contest_id=contest.id member_type=member_type %}">{% trans "Re-generate key" %}</a>
</p>
{% else %}
{% if member_type == 'teacher' %}
<p>{% trans "Registration of teachers is disabled." %}</p>
{% else %}
<p>{% trans "Registration of pupils is disabled." %}</p>
{% endif %}
<p>
<a class="btn btn-info" data-post-url="{% url 'teachers_enable_registration' contest_id=contest.id member_type=member_type %}">{% trans "Re-enable registration" %}</a>
</p>
{% endif %}

<form action="{% url 'teachers_delete_members' contest_id=contest.id member_type=member_type %}" class="teachers-delete-pupils" method="post">
{% csrf_token %}

<h3 class="members">{% trans "Members" %}</h3>

{% if members %}
<div class="row-fluid">
{% for sublist in members|partition:"3" %}
<div class="span4">
{% for member in sublist %}
<label class="checkbox"><input type="checkbox" name="member" value="{{ member.id }}" {% if member_type == 'teacher' and member == user %}disabled{% endif %}>
{{ member.get_full_name }}
</label>
{% endfor %}
</div>
{% endfor %}

<div class="btn-toolbar">
<button type="button" class="btn btn-small"
onclick="$('.teachers-delete-pupils input[type=\'checkbox\']').not('[disabled]').attr('checked', 'checked')">{% trans "Select all" %}</button>
<button type="button" class="btn btn-small"
onclick="$('.teachers-delete-pupils input[type=\'checkbox\']').not('[disabled]').removeAttr('checked')">{% trans "Select none" %}</button>
<button type="submit" class="btn btn-danger btn-small">{% trans "Delete selected" %}</button>
{% if other_contests %}
<div class="btn-group">
<button type="button" class="btn dropdown-toggle" data-toggle="dropdown" href="#">{% trans "Add from other contest" %} <span class="caret"></span></button>
<ul class="dropdown-menu">
{% for c in other_contests %}
<li><a data-post-url="{% url 'teachers_bulk_add_pupils' contest_id=contest.id other_contest_id=c.id %}">{{ c }}</a></li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
</div>
{% else %}
<p class="info">
{% if member_type == 'teacher' %}
{% trans "No teachers." %}
{% else %}
{% trans "No pupils." %}
{% endif %}
</p>
{% endif %}

</form>
{% endblock %}
Loading

0 comments on commit df281ce

Please sign in to comment.