Commits

Horst Gutmann committed 5311acf

Adds lastest_proposalversion to proposal metadata to facilitate the export

Comments (0)

Files changed (7)

pyconde/proposals/admin.py

 from . import models
 
 
-admin.site.register(models.Proposal,
-    list_display=("title", "kind", "conference", "duration", "speaker", "track"),
-    list_filter=("conference", "kind", "duration", "track"))
+class ProposalAdmin(admin.ModelAdmin):
+    list_display = ("title", "kind", "conference", "duration", "speaker", "track")
+    list_filter = ("conference", "kind", "duration", "track")
+
+
+admin.site.register(models.Proposal, ProposalAdmin)

pyconde/proposals/templates/admin/proposals/proposal/change_list.html

+{% extends "admin/change_list.html" %}
+{% load adminmedia admin_list i18n %}
+{% block content %}
+    <div id="info" style="float: left; padding: 10px; border: 1px dotted #417690; margin: 10px 250px 10px 0px; background: #DBF2FF">
+        <p>Diese Auflistung spiegelt Proposals wieder, wie sie ursprünglich durch den Benutzer
+            gemacht wurden. Sie sollten nur in Ausnahmefällen durch einen Admin modifiziert werden.
+        </p>
+        <p>Sowohl während der Proposal- als auch während der Review-Phase hat der Benutzer die Möglichkeit, das
+            Proposal selbst zu modifizieren. Da jedoch während der Review-Phase jede Änderung protokolliert werden
+            sollte, existiert hierfür in der Reviews-App eine eigene Datenstruktur.</p>
+    </div>
+    {{ block.super }}
+{% endblock %}

pyconde/reviews/management/commands/export_proposal_scores.py

+from django.core.management.base import BaseCommand
+
+from ... import models, utils
+
+
+class Command(BaseCommand):
+    help = """Exports proposals with their scores"""
+
+    def handle(self, *args, **kwargs):
+        print utils.create_proposal_score_export().csv

pyconde/reviews/migrations/0003_auto__add_field_proposalmetadata_latest_proposalversion.py

+# 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 'ProposalMetaData.latest_proposalversion'
+        db.add_column('reviews_proposalmetadata', 'latest_proposalversion', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['reviews.ProposalVersion'], null=True, blank=True), keep_default=False)
+
+
+    def backwards(self, orm):
+        
+        # Deleting field 'ProposalMetaData.latest_proposalversion'
+        db.delete_column('reviews_proposalmetadata', 'latest_proposalversion_id')
+
+
+    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': '30'})
+        },
+        'conference.audiencelevel': {
+            'Meta': {'object_name': 'AudienceLevel'},
+            'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'level': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'})
+        },
+        'conference.conference': {
+            'Meta': {'object_name': 'Conference'},
+            'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'reviews_active': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+            'reviews_end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'reviews_start_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+            'timezone': ('timezones.fields.TimeZoneField', [], {'blank': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'conference.sessionduration': {
+            'Meta': {'object_name': 'SessionDuration'},
+            'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'minutes': ('django.db.models.fields.IntegerField', [], {}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'})
+        },
+        'conference.sessionkind': {
+            'Meta': {'object_name': 'SessionKind'},
+            'closed': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+            'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}),
+            'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
+            'start_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+        },
+        'conference.track': {
+            'Meta': {'ordering': "['order']", 'object_name': 'Track'},
+            'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}),
+            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
+            'visible': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+        },
+        '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'})
+        },
+        'proposals.proposal': {
+            'Meta': {'object_name': 'Proposal'},
+            'abstract': ('django.db.models.fields.TextField', [], {}),
+            'additional_speakers': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'proposal_participations'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['speakers.Speaker']"}),
+            'audience_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.AudienceLevel']"}),
+            'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}),
+            'description': ('django.db.models.fields.TextField', [], {'max_length': '400'}),
+            'duration': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.SessionDuration']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'kind': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.SessionKind']"}),
+            'modified_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'speaker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'proposals'", 'to': "orm['speakers.Speaker']"}),
+            'submission_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.utcnow'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'track': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Track']", 'null': 'True', 'blank': 'True'})
+        },
+        'reviews.comment': {
+            'Meta': {'object_name': 'Comment'},
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+            'content': ('django.db.models.fields.TextField', [], {}),
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_comments'", 'null': 'True', 'to': "orm['auth.User']"}),
+            'deleted_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'deleted_reason': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'proposal': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['proposals.Proposal']"}),
+            'proposal_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['reviews.ProposalVersion']", 'null': 'True', 'blank': 'True'}),
+            'pub_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})
+        },
+        'reviews.proposal': {
+            'Meta': {'object_name': 'Proposal', 'db_table': "'proposals_proposal'", '_ormbases': ['proposals.Proposal'], 'proxy': 'True'}
+        },
+        'reviews.proposalmetadata': {
+            'Meta': {'object_name': 'ProposalMetaData'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'latest_activity_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'latest_comment_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'latest_proposalversion': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['reviews.ProposalVersion']", 'null': 'True', 'blank': 'True'}),
+            'latest_review_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'latest_version_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'num_comments': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+            'num_reviews': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+            'proposal': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'review_metadata'", 'unique': 'True', 'to': "orm['proposals.Proposal']"}),
+            'score': ('django.db.models.fields.FloatField', [], {'default': '0.0'})
+        },
+        'reviews.proposalversion': {
+            'Meta': {'object_name': 'ProposalVersion'},
+            'abstract': ('django.db.models.fields.TextField', [], {}),
+            'additional_speakers': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'proposalversion_participations'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['speakers.Speaker']"}),
+            'audience_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.AudienceLevel']"}),
+            'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}),
+            'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+            'description': ('django.db.models.fields.TextField', [], {'max_length': '400'}),
+            'duration': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.SessionDuration']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'kind': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.SessionKind']"}),
+            'modified_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'original': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'versions'", 'to': "orm['proposals.Proposal']"}),
+            'pub_date': ('django.db.models.fields.DateTimeField', [], {}),
+            'speaker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'proposalversions'", 'to': "orm['speakers.Speaker']"}),
+            'submission_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.utcnow'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'track': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Track']", 'null': 'True', 'blank': 'True'})
+        },
+        'reviews.review': {
+            'Meta': {'unique_together': "(('user', 'proposal'),)", 'object_name': 'Review'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'proposal': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reviews'", 'to': "orm['proposals.Proposal']"}),
+            'proposal_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['reviews.ProposalVersion']", 'null': 'True', 'blank': 'True'}),
+            'pub_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'rating': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
+            'summary': ('django.db.models.fields.TextField', [], {}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+        },
+        'speakers.speaker': {
+            'Meta': {'object_name': 'Speaker'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'speaker_profile'", 'unique': 'True', 'to': "orm['auth.User']"})
+        },
+        'taggit.tag': {
+            'Meta': {'object_name': 'Tag'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'})
+        },
+        'taggit.taggeditem': {
+            'Meta': {'object_name': 'TaggedItem'},
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"})
+        }
+    }
+
+    complete_apps = ['reviews']

pyconde/reviews/models.py

     """
     proposal = models.OneToOneField(Proposal, verbose_name=_("proposal"),
         related_name='review_metadata')
+    latest_proposalversion = models.ForeignKey("ProposalVersion",
+        verbose_name=_("latest proposal version"), null=True, blank=True)
     num_comments = models.PositiveIntegerField(
         verbose_name=_("number of comments"),
         default=0)
 
     try:
         latest_version = ProposalVersion.objects.get_latest_for(proposal)
+        md.latest_proposalversion = latest_version
         if latest_version:
             latest_version_date = latest_version.pub_date
     except Exception:
         logger.debug("Failed to fetch latest version of proposal", exc_info=True)
+        md.latest_proposalversion = None
 
     score = 0.0
     try:

pyconde/reviews/utils.py

     for review in queryset.select_related('user', 'proposal'):
         data.append((review.proposal.pk, review.proposal.title, review.pk, review.user.pk, review.user.username, review.rating))
     return data
+
+
+def create_proposal_score_export(queryset=None):
+    """
+    By default exports all proposals with their latest title (and original
+    title), final score etc. to a tablib dataset.
+    """
+    from . import models
+    if queryset is None:
+        queryset = models.ProposalMetaData.objects\
+            .select_related('proposal', 'proposal__speaker',
+                'latest_proposalversion')\
+            .order_by('-score')
+    data = tablib.Dataset(headers=['Title', 'OriginalTitle', 'SpeakerUsername', 'SpeakerName', 'Score', 'NumReviews'])
+    for md in queryset:
+        title = md.proposal.title
+        if md.latest_proposalversion:
+            title = md.latest_proposalversion.title
+        data.append((
+            title,
+            md.proposal.title,
+            md.proposal.speaker.user.username,
+            unicode(md.proposal.speaker),
+            md.score,
+            md.num_reviews
+            ))
+    return data

pyconde/speakers/models.py

     user = models.OneToOneField(User, related_name='speaker_profile')
 
     def __unicode__(self):
-        return u"{0} {1}".format(self.user.first_name, self.user.last_name)
+        if self.user.first_name and self.user.last_name:
+            return u"{0} {1}".format(self.user.first_name, self.user.last_name)
+        return self.user.username