Permalink
Browse files

Merge branch 'ignite_templates' of github.com:rossbruniges/mozilla-ig…

…nite into ignite_templates
  • Loading branch information...
rossbruniges committed Nov 8, 2011
2 parents dcaf7e1 + 0545af2 commit e3c1efb0ab93539d4dcac8ec2b00d6499bf1d898
View
@@ -11,5 +11,4 @@ class Meta:
'title',
'brief_description',
'description',
- 'created_by'
)
@@ -0,0 +1,145 @@
+# 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):
+
+ # Changing field 'Submission.brief_description'
+ db.alter_column('challenges_submission', 'brief_description', self.gf('django.db.models.fields.CharField')(max_length=200))
+
+
+ def backwards(self, orm):
+
+ # Changing field 'Submission.brief_description'
+ db.alter_column('challenges_submission', 'brief_description', self.gf('django.db.models.fields.TextField')())
+
+
+ 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', [], {'unique': 'True', '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'})
+ },
+ 'challenges.challenge': {
+ 'Meta': {'object_name': 'Challenge'},
+ 'allow_voting': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'moderate': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']"}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '60', 'db_index': 'True'}),
+ 'start_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'summary': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '60'})
+ },
+ 'challenges.phase': {
+ 'Meta': {'ordering': "('order',)", 'unique_together': "(('challenge', 'name'),)", 'object_name': 'Phase'},
+ 'challenge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'phases'", 'to': "orm['challenges.Challenge']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'challenges.submission': {
+ 'Meta': {'ordering': "['-id']", 'object_name': 'Submission'},
+ 'brief_description': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'created_by': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['users.Profile']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'flagged_offensive': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'flagged_offensive_reason': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_live': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_winner': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'phase': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['challenges.Phase']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '60'})
+ },
+ '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'})
+ },
+ 'projects.project': {
+ 'Meta': {'object_name': 'Project'},
+ 'allow_participation': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'allow_sub_projects': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'featured': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'featured_image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'followers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'projects_following'", 'symmetrical': 'False', 'to': "orm['users.Profile']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'long_description': ('django.db.models.fields.TextField', [], {}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'parent_project_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}),
+ 'sub_project_label': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'team_members': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['users.Profile']", 'symmetrical': 'False'}),
+ 'topics': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['topics.Topic']", 'symmetrical': 'False'})
+ },
+ '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']"})
+ },
+ 'topics.topic': {
+ 'Meta': {'object_name': 'Topic'},
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'draft': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}),
+ 'long_description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'})
+ },
+ 'users.profile': {
+ 'Meta': {'object_name': 'Profile'},
+ 'avatar': ('django.db.models.fields.files.ImageField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}),
+ 'bio': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'featured': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'featured_image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '255', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['challenges']
View
@@ -1,27 +1,39 @@
from datetime import datetime
from django.conf import settings
+from django.core.urlresolvers import reverse, NoReverseMatch
from django.core.validators import MaxLengthValidator
from django.db import models
from django.db.models.signals import pre_save
from tower import ugettext_lazy as _
from challenges.lib import cached_bleach
-from innovate.models import BaseModel
+from innovate.models import BaseModel, BaseModelManager
from projects.models import Project
from users.models import Profile
+class ChallengeManager(BaseModelManager):
+
+ def get_by_natural_key(self, slug):
+ return self.get(slug=slug)
+
+
class Challenge(BaseModel):
"""A user participation challenge on a specific project."""
+ objects = ChallengeManager()
+
title = models.CharField(verbose_name=_(u'Title'), max_length=60, unique=True)
slug = models.SlugField(verbose_name=_(u'Slug'), max_length=60, unique=True)
summary = models.TextField(verbose_name=_(u'Summary'),
validators=[MaxLengthValidator(200)])
description = models.TextField(verbose_name=_(u'Description'))
+ def natural_key(self):
+ return (self.slug,)
+
@property
def description_html(self):
"""Challenge description with bleached HTML."""
@@ -47,15 +59,43 @@ def get_image_src(self):
def __unicode__(self):
return self.title
+
+ def get_absolute_url(self):
+ """Return this challenge's URL.
+
+ Note that this needs to account both for an Ignite-style URL structure,
+ where there is a single challenge for the entire site, and sites where
+ there are multiple challenges.
+
+ """
+ try:
+ # Match for a single-challenge site if we can
+ return reverse('challenge_show')
+ except NoReverseMatch:
+ kwargs = {'project': self.project.slug, 'slug': self.slug}
+ return reverse('challenge_show', kwargs=kwargs)
+
+
+class PhaseManager(BaseModelManager):
+
+ def get_from_natural_key(self, challenge_slug, phase_name):
+ return self.get(challenge__slug=challenge_slug, name=phase_name)
class Phase(BaseModel):
"""A phase of a challenge."""
- challenge = models.ForeignKey(Challenge)
+ objects = PhaseManager()
+
+ challenge = models.ForeignKey(Challenge, related_name='phases')
name = models.CharField(max_length=100)
- # TODO: auto-number phases on save
+ def natural_key(self):
+ return self.challenge.natural_key() + (self.name,)
+
+ natural_key.dependencies = ['challenges.challenge']
+
+ # TODO: replace explicit numbering with start and end dates
order = models.IntegerField()
def __unicode__(self):
@@ -70,8 +110,8 @@ class Submission(BaseModel):
"""A user's entry into a challenge."""
title = models.CharField(verbose_name=_(u'Title'), max_length=60, unique=True)
- brief_description = models.TextField(verbose_name=_(u'Brief Description'),
- validators=[MaxLengthValidator(200)],
+ brief_description = models.CharField(max_length=200,
+ verbose_name=_(u'Brief Description'),
help_text = _(u'Think of this as an elevator pitch - keep it short and sweet'))
description = models.TextField(verbose_name=_(u'Description'))
@@ -3,7 +3,7 @@
{% from 'layout/helpers.html' import sectiontitle, challenge_nav with context %}
{% block page_title %}
- {{ _('Entries | {part} | Mozilla Labs')|f(part=p11n.title) }}
+ {{ _('Entries | {part} | Mozilla Labs')|f(part=challenge.title) }}
{% endblock %}
{% block page_id %}all_entries{% endblock %}
@@ -14,13 +14,13 @@
(url('innovate_splash'), _('Mozilla Labs Home')),
(url('projects_programs'), _('Programs')),
(url('projects_show', slug=project.slug), project.name),
- (url('challenge_show', project=project.slug, slug=p11n.slug), p11n.title),
+ (challenge.get_absolute_url(), challenge.title),
last=_('Entries')) }}
{% endblock %}
{% block content %}
-{{ sectiontitle(_('All Entries to {part}')|f(part=p11n.title)) }}
-{{ challenge_nav(p11n.get_image_src(), p11n.summary, p11n.start_date, p11n.end_date) }}
+{{ sectiontitle(_('All Entries to {part}')|f(part=challenge.title)) }}
+{{ challenge_nav(challenge.get_image_src(), challenge.summary, challenge.start_date, challenge.end_date) }}
<section class="c4 clearfix">
<div class="row clearfix">
{% if entries %}
@@ -30,7 +30,7 @@
<article>
<h2 class="light sans">{{ e.title }}</h2>
<p>{{ e.brief_description }}</p>
- <p><a href="{{ url('entry_show', project=project.slug, slug=p11n.slug, entry_id=e.id) }}">Read the full entry</a></p>
+ <p><a href="{{ url('entry_show', project=project.slug, slug=challenge.slug, entry_id=e.id) }}">Read the full entry</a></p>
<footer>
<p>Entry from:</p>
<ul class="db_related clearfix">
@@ -4,26 +4,26 @@
{% block page_title %}
{% if not errors %}
- {{ _('Create entry on {part} : Participation : Mozilla Labs')|f(part=p11n.title) }}
+ {{ _('Create entry on {part} : Participation : Mozilla Labs')|f(part=challenge.title) }}
{% else %}
- {{ _('Entry failed: Create entry on {part} : Participation : Mozilla Labs')|f(part=p11n.title) }}
+ {{ _('Entry failed: Create entry on {part} : Participation : Mozilla Labs')|f(part=challenge.title) }}
{% endif %}
{% endblock %}
-{% block page_id %}p11n_create{% endblock %}
+{% block page_id %}challenge_create{% endblock %}
{% block section_class %}projects{% endblock %}
{% block breadcrumbs %}
{{ breadcrumbs(
(url('innovate_splash'), _('Mozilla Labs Home')),
(url('projects_programs'), _('Programs')),
(url('projects_show', slug=project.slug), project.name),
- (url('challenge_show', project=project.slug, slug=p11n.slug), p11n.title),
+ (challenge.get_absolute_url(), challenge.title),
last=_('Create entry')) }}
{% endblock %}
{% block content %}
-{{ sectiontitle(_('Create entry on {part}')|f(part=p11n.title)) }}
+{{ sectiontitle(_('Create entry on {part}')|f(part=challenge.title)) }}
<section id="profile_edit" class="w6 clearfix">
<div class="paper c3">
{% if errors %}
@@ -36,7 +36,7 @@
{% endfor %}
</ul>
{% endif %}
- <form action="{{ url('entry_create', project=project.slug, slug=p11n.slug) }}" method="post">
+ <form action="{{ url('entry_create', project=project.slug, slug=challenge.slug) }}" method="post">
{{ csrf()|safe }}
<ul class="db_objects">
<li>
@@ -3,7 +3,7 @@
{% from "layout/helpers.html" import sectiontitle, challenge_nav with context %}
{% block page_title %}
- {{ _('{part} : Participation : Mozilla Labs')|f(part=p11n.title) }}
+ {{ _('{part} : Participation : Mozilla Labs')|f(part=challenge.title) }}
{% endblock %}
{% block page_id %}participation_detail{% endblock %}
@@ -14,16 +14,16 @@
(url('innovate_splash'), _('Mozilla Labs Home')),
(url('projects_programs'), _('Programs')),
(url('projects_show', slug=project.slug), project.name),
- last=p11n.title) }}
+ last=challenge.title) }}
{% endblock %}
{% block content %}
-{{ sectiontitle(p11n.title) }}
-{{ challenge_nav(p11n.get_image_src(), p11n.summary, p11n.start_date, p11n.end_date) }}
+{{ sectiontitle(challenge.title) }}
+{{ challenge_nav(challenge.get_image_src(), challenge.summary, challenge.start_date, challenge.end_date) }}
<section class="c4 clearfix">
<div class="row clearfix">
<h2 class="light sans">The brief</h2>
- {{ p11n.description }}
+ {{ challenge.description }}
{% if entries %}
<div class="entries">
<h3>Entries</h3>
@@ -33,7 +33,7 @@ <h3>Entries</h3>
<article>
<h4>{{ e.title }}</h4>
<p>{{ e.brief_description }}</p>
- <p><a href="{{ url('entry_show', project=project.slug, slug=p11n.slug, entry_id=e.id) }}">Read the full entry</a></p>
+ <p><a href="{{ url('entry_show', project=project.slug, slug=challenge.slug, entry_id=e.id) }}">Read the full entry</a></p>
<footer>
<p>Entry from:</p>
<ul class="db_related clearfix">
@@ -52,7 +52,7 @@ <h4>{{ e.title }}</h4>
</ul>
</div>
{% endif %}
- <a href="{{ url('entry_create', project=project.slug, slug=p11n.slug) }}" class="button submit">Participate now</a>
+ <a href="{{ url('entry_create', project=project.slug, slug=challenge.slug) }}" class="button submit">Participate now</a>
</div>
</section>
{% endblock %}
Oops, something went wrong.

0 comments on commit e3c1efb

Please sign in to comment.