Add subject field to feedback model
New form to fill feedback mail via web. Fixes #1042 #1043 - Legacy-Id: 5748
This commit is contained in:
parent
f998e0d29f
commit
66c4a32c57
|
@ -20,7 +20,7 @@ from ietf.nomcom.models import NomCom, Nomination, Nominee, NomineePosition, \
|
|||
Position, Feedback, ReminderDates
|
||||
from ietf.nomcom.utils import (NOMINATION_RECEIPT_TEMPLATE, FEEDBACK_RECEIPT_TEMPLATE,
|
||||
get_user_email, validate_private_key, validate_public_key,
|
||||
get_or_create_nominee)
|
||||
get_or_create_nominee, create_feedback_email)
|
||||
from ietf.nomcom.decorators import nomcom_member_required
|
||||
|
||||
|
||||
|
@ -609,6 +609,24 @@ class FeedbackForm(BaseNomcomForm, forms.ModelForm):
|
|||
"/js/nomcom.js", )
|
||||
|
||||
|
||||
class FeedbackEmailForm(BaseNomcomForm, forms.Form):
|
||||
|
||||
email_text = forms.CharField(label='Email text', widget=forms.Textarea())
|
||||
|
||||
fieldsets = [('Feedback email', ('email_text',))]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.nomcom = kwargs.pop('nomcom', None)
|
||||
super(FeedbackEmailForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def save(self, commit=True):
|
||||
create_feedback_email(self.nomcom, self.cleaned_data['email_text'])
|
||||
|
||||
class Media:
|
||||
js = ("/js/jquery-1.5.1.min.js",
|
||||
"/js/nomcom.js", )
|
||||
|
||||
|
||||
class QuestionnaireForm(BaseNomcomForm, forms.ModelForm):
|
||||
|
||||
comments = forms.CharField(label='Questionnaire response from this candidate',
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
from optparse import make_option
|
||||
from email.utils import parseaddr
|
||||
import syslog
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
|
||||
from ietf.nomcom.utils import parse_email
|
||||
from ietf.nomcom.models import NomCom, Feedback
|
||||
from ietf.nomcom.models import NomCom
|
||||
from ietf.nomcom.utils import create_feedback_email
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = (u"Registry feedback from email. Usage: feeback_email --nomcom-year <nomcom-year> --email-file <email-file>")
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('--nomcom-year', dest='year', help='NomCom year'),
|
||||
make_option('--email-file', dest='email', help='Feedback email'),
|
||||
)
|
||||
make_option('--email-file', dest='email', help='Feedback email'),)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
email = options.get('email', None)
|
||||
|
@ -36,13 +34,5 @@ class Command(BaseCommand):
|
|||
except NomCom.DoesNotExist:
|
||||
raise CommandError("NomCom %s does not exist or it isn't active" % year)
|
||||
|
||||
by, subject, body = parse_email(msg)
|
||||
body = 'Subject: %s\n\n%s' % (subject, body)
|
||||
name, addr = parseaddr(by)
|
||||
|
||||
feedback = Feedback(nomcom=nomcom,
|
||||
author=addr,
|
||||
comments=body)
|
||||
feedback.save()
|
||||
|
||||
syslog.syslog(u"Read feedback email by %s" % by)
|
||||
feedback = create_feedback_email(nomcom, msg)
|
||||
syslog.syslog(u"Read feedback email by %s" % feedback.author)
|
||||
|
|
324
ietf/nomcom/migrations/0003_auto__add_field_feedback_subject.py
Normal file
324
ietf/nomcom/migrations/0003_auto__add_field_feedback_subject.py
Normal file
|
@ -0,0 +1,324 @@
|
|||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Adding field 'Feedback.subject'
|
||||
db.add_column('nomcom_feedback', 'subject', self.gf('django.db.models.fields.TextField')(default='', blank=True), keep_default=False)
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting field 'Feedback.subject'
|
||||
db.delete_column('nomcom_feedback', 'subject')
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'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': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
|
||||
},
|
||||
'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'}),
|
||||
'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'})
|
||||
},
|
||||
'dbtemplate.dbtemplate': {
|
||||
'Meta': {'object_name': 'DBTemplate'},
|
||||
'content': ('django.db.models.fields.TextField', [], {}),
|
||||
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DBTemplateTypeName']"}),
|
||||
'variables': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.docalias': {
|
||||
'Meta': {'object_name': 'DocAlias'},
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
|
||||
},
|
||||
'doc.document': {
|
||||
'Meta': {'object_name': 'Document'},
|
||||
'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocumentAuthor']", 'blank': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
|
||||
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'primary_key': 'True'}),
|
||||
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}),
|
||||
'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'reversely_related_document_set'", 'blank': 'True', 'through': "orm['doc.RelatedDocument']", 'to': "orm['doc.DocAlias']"}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
|
||||
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.documentauthor': {
|
||||
'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocumentAuthor'},
|
||||
'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}),
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1'})
|
||||
},
|
||||
'doc.relateddocument': {
|
||||
'Meta': {'object_name': 'RelatedDocument'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'relationship': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocRelationshipName']"}),
|
||||
'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocAlias']"})
|
||||
},
|
||||
'doc.state': {
|
||||
'Meta': {'ordering': "['type', 'order']", 'object_name': 'State'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'previous_states'", 'symmetrical': 'False', 'to': "orm['doc.State']"}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'doc.statetype': {
|
||||
'Meta': {'object_name': 'StateType'},
|
||||
'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'})
|
||||
},
|
||||
'group.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'acronym': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}),
|
||||
'charter': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'chartered_group'", 'unique': 'True', 'null': 'True', 'to': "orm['doc.Document']"}),
|
||||
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'list_archive': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'list_email': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
|
||||
'list_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']", 'null': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupTypeName']", 'null': 'True'}),
|
||||
'unused_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'name.dbtemplatetypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DBTemplateTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.docrelationshipname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocRelationshipName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.doctagname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocTagName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.doctypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.feedbacktype': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'FeedbackType'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.groupstatename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'GroupStateName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.grouptypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'GroupTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.intendedstdlevelname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'IntendedStdLevelName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.nomineepositionstate': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'NomineePositionState'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.stdlevelname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'StdLevelName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.streamname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'StreamName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'nomcom.feedback': {
|
||||
'Meta': {'ordering': "['time']", 'object_name': 'Feedback'},
|
||||
'author': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'comments': ('ietf.nomcom.fields.EncryptedTextField', [], {}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'nomcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.NomCom']"}),
|
||||
'nominees': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['nomcom.Nominee']", 'null': 'True', 'blank': 'True'}),
|
||||
'positions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['nomcom.Position']", 'null': 'True', 'blank': 'True'}),
|
||||
'subject': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.FeedbackType']", 'null': 'True', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'nomcom.nomcom': {
|
||||
'Meta': {'object_name': 'NomCom'},
|
||||
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'initial_text': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'public_key': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
|
||||
'reminder_interval': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'send_questionnaire': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
|
||||
},
|
||||
'nomcom.nomination': {
|
||||
'Meta': {'object_name': 'Nomination'},
|
||||
'candidate_email': ('django.db.models.fields.EmailField', [], {'max_length': '255'}),
|
||||
'candidate_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'candidate_phone': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'comments': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Feedback']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'nominator_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'nominee': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Nominee']"}),
|
||||
'position': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Position']"}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
|
||||
},
|
||||
'nomcom.nominee': {
|
||||
'Meta': {'unique_together': "(('email', 'nomcom'),)", 'object_name': 'Nominee'},
|
||||
'duplicated': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Nominee']", 'null': 'True', 'blank': 'True'}),
|
||||
'email': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'nomcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.NomCom']"}),
|
||||
'nominee_position': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['nomcom.Position']", 'through': "orm['nomcom.NomineePosition']", 'symmetrical': 'False'})
|
||||
},
|
||||
'nomcom.nomineeposition': {
|
||||
'Meta': {'ordering': "['nominee']", 'unique_together': "(('position', 'nominee'),)", 'object_name': 'NomineePosition'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'nominee': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Nominee']"}),
|
||||
'position': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Position']"}),
|
||||
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.NomineePositionState']"}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'nomcom.position': {
|
||||
'Meta': {'object_name': 'Position'},
|
||||
'description': ('django.db.models.fields.TextField', [], {}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'incumbent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}),
|
||||
'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'nomcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.NomCom']"}),
|
||||
'questionnaire': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questionnaire'", 'null': 'True', 'to': "orm['dbtemplate.DBTemplate']"}),
|
||||
'requirement': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'requirement'", 'null': 'True', 'to': "orm['dbtemplate.DBTemplate']"})
|
||||
},
|
||||
'nomcom.reminderdates': {
|
||||
'Meta': {'object_name': 'ReminderDates'},
|
||||
'date': ('django.db.models.fields.DateField', [], {}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'nomcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.NomCom']"})
|
||||
},
|
||||
'person.email': {
|
||||
'Meta': {'object_name': 'Email'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '64', 'primary_key': 'True'}),
|
||||
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'person.person': {
|
||||
'Meta': {'object_name': 'Person'},
|
||||
'address': ('django.db.models.fields.TextField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'ascii': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'ascii_short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['nomcom']
|
|
@ -185,6 +185,7 @@ class Feedback(models.Model):
|
|||
author = models.EmailField(verbose_name='Author', blank=True)
|
||||
positions = models.ManyToManyField('Position', blank=True, null=True)
|
||||
nominees = models.ManyToManyField('Nominee', blank=True, null=True)
|
||||
subject = models.TextField(verbose_name='Subject', blank=True)
|
||||
comments = EncryptedTextField(verbose_name='Comments')
|
||||
type = models.ForeignKey(FeedbackType, blank=True, null=True)
|
||||
user = models.ForeignKey(User, editable=False, blank=True, null=True)
|
||||
|
|
|
@ -8,6 +8,7 @@ urlpatterns = patterns('ietf.nomcom.views',
|
|||
url(r'^(?P<year>\d{4})/private/key/$', 'private_key', name='nomcom_private_key'),
|
||||
url(r'^(?P<year>\d{4})/private/nominate/$', 'private_nominate', name='nomcom_private_nominate'),
|
||||
url(r'^(?P<year>\d{4})/private/feedback/$', 'private_feedback', name='nomcom_private_feedback'),
|
||||
url(r'^(?P<year>\d{4})/private/feedback-email/$', 'private_feedback_email', name='nomcom_private_feedback_email'),
|
||||
url(r'^(?P<year>\d{4})/private/questionnaire-response/$', 'private_questionnaire', name='nomcom_private_questionnaire'),
|
||||
url(r'^(?P<year>\d{4})/private/view-feedback/$', 'view_feedback', name='nomcom_view_feedback'),
|
||||
url(r'^(?P<year>\d{4})/private/view-feedback/unrelated/$', 'view_feedback_unrelated', name='nomcom_view_feedback_unrelated'),
|
||||
|
|
|
@ -5,6 +5,8 @@ import os
|
|||
import re
|
||||
import tempfile
|
||||
|
||||
from email.utils import parseaddr
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.exceptions import PermissionDenied
|
||||
|
@ -155,7 +157,8 @@ def extract_body(payload):
|
|||
if isinstance(payload, str):
|
||||
return payload
|
||||
else:
|
||||
return '\n'.join([extract_body(part.get_payload()) for part in payload])
|
||||
if payload:
|
||||
return '\n'.join([extract_body(part.get_payload()) for part in payload])
|
||||
|
||||
|
||||
def parse_email(text):
|
||||
|
@ -164,7 +167,7 @@ def parse_email(text):
|
|||
# comment
|
||||
#body = quopri.decodestring(extract_body(msg.get_payload()))
|
||||
charset = msg.get_content_charset()
|
||||
body = extract_body(msg.get_payload(decode=True))
|
||||
body = extract_body(msg.get_payload())
|
||||
if charset:
|
||||
body = body.decode(charset)
|
||||
|
||||
|
@ -339,3 +342,16 @@ def get_or_create_nominee(nomcom, candidate_name, candidate_email, position, aut
|
|||
send_mail(None, to_email, from_email, subject, path, context)
|
||||
|
||||
return nominee
|
||||
|
||||
|
||||
def create_feedback_email(nomcom, msg):
|
||||
from ietf.nomcom.models import Feedback
|
||||
by, subject, body = parse_email(msg)
|
||||
name, addr = parseaddr(by)
|
||||
|
||||
feedback = Feedback(nomcom=nomcom,
|
||||
author=addr,
|
||||
subject=subject,
|
||||
comments=body)
|
||||
feedback.save()
|
||||
return feedback
|
||||
|
|
|
@ -24,7 +24,8 @@ from ietf.nomcom.decorators import nomcom_member_required, nomcom_private_key_re
|
|||
from ietf.nomcom.forms import (NominateForm, FeedbackForm, QuestionnaireForm,
|
||||
MergeForm, NomComTemplateForm, PositionForm,
|
||||
PrivateKeyForm, EditNomcomForm, EditNomineeForm,
|
||||
PendingFeedbackForm, ReminderDatesForm, FullFeedbackFormSet)
|
||||
PendingFeedbackForm, ReminderDatesForm, FullFeedbackFormSet,
|
||||
FeedbackEmailForm)
|
||||
from ietf.nomcom.models import Position, NomineePosition, Nominee, Feedback, NomCom, ReminderDates
|
||||
from ietf.nomcom.utils import (get_nomcom_by_year, store_nomcom_private_key,
|
||||
get_hash_nominee_position, send_reminder_to_nominees,
|
||||
|
@ -304,6 +305,38 @@ def feedback(request, year, public):
|
|||
'selected': 'feedback'}, RequestContext(request))
|
||||
|
||||
|
||||
@nomcom_member_required(role='chair')
|
||||
def private_feedback_email(request, year):
|
||||
nomcom = get_nomcom_by_year(year)
|
||||
has_publickey = nomcom.public_key and True or False
|
||||
message = None
|
||||
template = 'nomcom/private_feedback_email.html'
|
||||
|
||||
if not has_publickey:
|
||||
message = ('warning', "This Nomcom is not yet accepting feedback email")
|
||||
return render_to_response(template,
|
||||
{'message': message,
|
||||
'nomcom': nomcom,
|
||||
'year': year,
|
||||
'selected': 'feedback_email'}, RequestContext(request))
|
||||
|
||||
form = FeedbackEmailForm(nomcom=nomcom)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = FeedbackEmailForm(data=request.POST,
|
||||
nomcom=nomcom)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
message = ('success', 'The feedback email has been registered.')
|
||||
|
||||
return render_to_response(template,
|
||||
{'form': form,
|
||||
'message': message,
|
||||
'nomcom': nomcom,
|
||||
'year': year,
|
||||
'selected': 'feedback_email'}, RequestContext(request))
|
||||
|
||||
|
||||
@nomcom_member_required(role='chair')
|
||||
def private_questionnaire(request, year):
|
||||
nomcom = get_nomcom_by_year(year)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
{% if selected == "view_feedback" %}<span class="selected">View comments</span>{% else %}<a href="{% url nomcom_view_feedback year %}">View comments</a>{% endif %} |
|
||||
{% if selected == "private_key" %}<span class="selected">Private key</span>{% else %}<a href="{% url nomcom_private_key year %}">Private key</a>{% endif %}
|
||||
{% if user|is_chair:year %} |
|
||||
{% if selected == "feedback_email" %}<span class="selected">Provide Email Feedback</span>{% else %}<a href="{% url nomcom_private_feedback_email year %}">Provide Email Feedback</a>{% endif %} |
|
||||
{% if selected == "merge" %}<span class="selected">Merge nominee email addr</span>{% else %}<a href="{% url nomcom_private_merge year %}">Merge nominee email addr</a>{% endif %} |
|
||||
{% if selected == "send_reminder_mail" %}<span class="selected">Send Reminder Mail</span>{% else %}<a href="{% url nomcom_send_reminder_mail year %}">Send reminder mail</a>{% endif %} |
|
||||
{% if selected == "edit_members" %}<span class="selected">Nomcom members</span>{% else %}<a href="{% url nomcom_edit_members year %}">Nomcom members</a>{% endif %} |
|
||||
|
|
45
ietf/templates/nomcom/private_feedback_email.html
Normal file
45
ietf/templates/nomcom/private_feedback_email.html
Normal file
|
@ -0,0 +1,45 @@
|
|||
{% extends "nomcom/nomcom_private_base.html" %}
|
||||
|
||||
{% load nomcom_tags %}
|
||||
|
||||
{% block subtitle %} - Provide feeback email{% endblock %}
|
||||
|
||||
{% block pagehead %}
|
||||
{{ form.media }}
|
||||
{% endblock %}
|
||||
|
||||
{% block nomcom_content %}
|
||||
|
||||
|
||||
{% if message %}
|
||||
<div class="info-message-{{ message.0 }}">{{ message.1 }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if nomcom|has_publickey %}
|
||||
|
||||
<div class="js-info">
|
||||
Your browser has Javascript disabled. Please enable javascript and reload the page.
|
||||
<script type="text/javascript">
|
||||
(function ($) {
|
||||
$(".js-info").hide();
|
||||
})(jQuery);
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{% if form.errors %}<div class="info-message-error">Please correct the following errors</div>{% endif %}
|
||||
|
||||
<form id="questionnnaireform" action="" method="post">{% csrf_token %}
|
||||
{{ form }}
|
||||
|
||||
<div class="submitrow">
|
||||
<input type="submit" value="Save" name="save" {% if submit_disabled %}disabled="disabled"{% endif %}/>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% endblock %}
|
|
@ -34,17 +34,19 @@
|
|||
{% ifequal ft.slug "nomina" %}
|
||||
{% for fn in feedback.nomination_set.all %}
|
||||
{% if fn.candidate_name %}
|
||||
<p><b>Candidate name:</b> {{ fn.candidate_name }}</p>
|
||||
<h3>Candidate name:</h3> <pre>{{ fn.candidate_name }}</pre>
|
||||
{% endif %}
|
||||
{% if fn.candidate_phone %}
|
||||
<p><b>Candidate phone:</b> {{ fn.candidate_phone }}</p>
|
||||
<h3>Candidate phone:</h3> <pre>{{ fn.candidate_phone }}</pre>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endifequal %}
|
||||
<b>Positions:</b> {{ feedback.positions.all|join:"," }}
|
||||
<p>
|
||||
{% decrypt feedback.comments request year %}
|
||||
</p>
|
||||
<h3>Positions:</h3> <pre>{{ feedback.positions.all|join:"," }}</pre>
|
||||
{% if feedback.subject %}
|
||||
<h3>Subject:</h3> <pre>{{ feedback.subject }}</pre>
|
||||
{% endif %}
|
||||
<h3>Body</h3>
|
||||
<pre>{% decrypt feedback.comments request year %}</pre>
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% endfor %}
|
||||
|
|
|
@ -60,6 +60,8 @@
|
|||
<pre>{{ form.feedback_type }}</pre>
|
||||
<h3>Author</h3>
|
||||
<pre>{{ form.instance.author }}</pre>
|
||||
<h3>Subject</h3>
|
||||
<pre>{{ form.instance.subject }}</pre>
|
||||
<h3>Feedback body</h3>
|
||||
<pre>{% decrypt form.instance.comments request year 1 %}</pre>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue