Skip to content
Browse files

Progress checkpoint; using freshen for BDD and scenarios; can create …

…a new badge and nominate someone to receive a badge.
  • Loading branch information...
1 parent 17769d7 commit 19fdc4714e297f12e5972712bfa700b3c2a977e2 @lmorchard committed
Showing with 628 additions and 40 deletions.
  1. +26 −3 README.md
  2. +7 −0 apps/badges/admin.py
  3. +35 −0 apps/badges/features/basics.feature
  4. +199 −0 apps/badges/features/steps.py
  5. +29 −1 apps/badges/forms.py
  6. +27 −0 apps/badges/management.py
  7. +74 −1 apps/badges/models.py
  8. +19 −0 apps/badges/templates/badges/create.html
  9. +27 −0 apps/badges/templates/badges/detail.html
  10. 0 apps/badges/templates/notification/badge_nomination_proposed/full.html
  11. 0 apps/badges/templates/notification/badge_nomination_proposed/full.txt
  12. +1 −0 apps/badges/templates/notification/badge_nomination_proposed/notice.html
  13. +1 −0 apps/badges/templates/notification/badge_nomination_proposed/short.txt
  14. 0 apps/badges/templates/notification/badge_nomination_received/full.html
  15. 0 apps/badges/templates/notification/badge_nomination_received/full.txt
  16. +1 −0 apps/badges/templates/notification/badge_nomination_received/notice.html
  17. +1 −0 apps/badges/templates/notification/badge_nomination_received/short.txt
  18. 0 apps/badges/templates/notification/badge_nomination_sent/full.html
  19. 0 apps/badges/templates/notification/badge_nomination_sent/full.txt
  20. +1 −0 apps/badges/templates/notification/badge_nomination_sent/notice.html
  21. +1 −0 apps/badges/templates/notification/badge_nomination_sent/short.txt
  22. +0 −24 apps/badges/tests.py
  23. +59 −0 apps/badges/tests/test_models.py
  24. +8 −1 apps/badges/urls.py
  25. +75 −1 apps/badges/views.py
  26. +0 −3 context_processors.py
  27. +5 −0 requirements/dev.txt
  28. +4 −3 settings.py
  29. +2 −1 templates/homepage.html
  30. +5 −1 templates/site_base.html
  31. +18 −0 terrain.py
  32. +3 −1 urls.py
View
29 README.md
@@ -1,10 +1,15 @@
-# Badger
+# Badger v0.0
It might be nice to gift badges and track achievements for deserving people.
+## Installation / Deployment
+
+* Never been done, yet.
+
## FAQ
+
* Hasn't this been done before?
- * Yes, [at least once][bravonation].
+ * Yes, [at least once][bravonation] on the net.
* Why are you doing it, then?
* Because I'd like to:
1. Revive the idea;
@@ -12,7 +17,25 @@ It might be nice to gift badges and track achievements for deserving people.
3. Introduce automated web-wide scanning for achievement conditions.
* Why's it all Comic Sans?
* Because I want to annoy you into fixing it for me.
- * Also, because it's all still a prototype.
+ * Also, because it's all still a prototype, and you shouldn't take it seriously yet.
+
+## Hacking
+
+I'll assume you're a bit of a Django hacker here, but this might help kick things off:
+
+* Get the source from [github](http://github.com/lmorchard/badger).
+ * (You're probably there now.)
+* Make sure you have Python 2.4+, [pip][], and [virtualenv][].
+ * I'm using Python 2.6.5 from MacPorts, for what it's worth.
+* Follow the [Getting started guide for Pinax](http://pinaxproject.com/docs/dev/gettingstarted.html), mainly:
+ * Use [virtualenv][] to create and use a new environment.
+ * `pip install -r requirements/dev.txt`
+ * `python manage.py syncdb`
+ * `python manage.py runserver`
+* If anything goes wrong, you're probably better informed than I am to fix it.
+
+[virtualenv]: http://pypi.python.org/pypi/virtualenv
+[pip]: http://pip.openplans.org/
## Credits & Influences
View
7 apps/badges/admin.py
@@ -0,0 +1,7 @@
+from django.contrib import admin
+
+from badger.apps.badges.models import Badge, BadgeNomination, BadgeAward
+
+admin.site.register(Badge)
+admin.site.register(BadgeNomination)
+admin.site.register(BadgeAward)
View
35 apps/badges/features/basics.feature
@@ -0,0 +1,35 @@
+Feature: Basic creation and awarding of badges
+ As a nice person
+ I want to be able to create and award badges
+ In order to reward interesting behavior
+
+ Background:
+ Given a user named "user1"
+ And a user named "user2"
+ And a user named "user3"
+
+ Scenario: Create a new badge
+ Given I am logged in as "user1"
+ And I go to the "create badge" page
+ When I fill in "Title" with "Awesome Tester"
+ And I fill in "Description" with "This is an awesome badge for awesome testers"
+ And I press "Create"
+ Then I should see no form validation errors
+ And I should see a page entitled "Badge details"
+ And I should see "Awesome Tester" somewhere on the page
+
+ Scenario: Nominate someone to receive a badge
+ Given "user1" creates a badge entitled "Awesome badge"
+ And I am logged in as "user2"
+ And I go to the badge detail page for "Awesome badge"
+ When I fill in "Nominee" with "user3"
+ And I fill in "Reason why" with "user3 is awesome"
+ And I press "Nominate for badge"
+ Then I should see no form validation errors
+ And I should see "user3 nominated" somewhere on the page
+ And "user3" should be nominated by "user2" for badge "Awesome badge" because "user3 is awesome"
+ And "user1" should receive a "Badge Nomination Proposed" notification
+ And "user2" should receive a "Badge Nomination Sent" notification
+ And "user3" should receive a "Badge Nomination Received" notification
+
+
View
199 apps/badges/features/steps.py
@@ -0,0 +1,199 @@
+""" """
+# -*- coding: utf-8 -*-
+from freshen import *
+
+import logging
+from lxml import etree
+from pyquery import PyQuery
+from django.test.client import Client
+from nose.tools import assert_equal, with_setup, assert_false, eq_, ok_
+from django.contrib.auth.models import User
+from pinax.apps.profiles.models import Profile
+from pinax.apps.account.models import Account
+from badger.apps.badges.models import Badge, BadgeNomination, BadgeAward
+from notification.models import NoticeType, Notice
+
+@Before
+def before_all(sc):
+ glc.log = logging.getLogger('nose.badger')
+ scc.browser = Client()
+ scc.last_response = None
+ scc.current_path = None
+ scc.current_page = None
+ scc.current_form = None
+
+@After
+def after_all(sc):
+ pass
+
+###########################################################################
+# Step definitions
+###########################################################################
+
+@Given(u'a user named "(.*)"')
+def establish_user(username):
+ user = get_user(username)
+
+@Given(u'I am logged in as "(.*)"')
+def given_i_am_logged_in_as(username):
+ user = get_user(username)
+ succ = scc.browser.login(
+ username=username,
+ password='%s_password' % username
+ )
+ ok_(succ, "login should succeed")
+
+name_path_map = {
+ "create badge": "/badges/create"
+}
+
+@Given(u'I go to the "(.*)" page')
+def i_am_on_named_page(page_name):
+ path = (page_name in name_path_map and
+ name_path_map[page_name] or page_name)
+ page = visit_page(path)
+
+@Given(u'"(.*)" creates a badge entitled "(.*)"')
+def user_creates_badge(username, title):
+ user = get_user(username)
+ badge = Badge(
+ title = title,
+ description = "Example description",
+ creator = user
+ )
+ badge.save()
+
+@Given(u'I go to the badge detail page for "(.*)"')
+def go_to_badge_detail_page(title):
+ badge = Badge.objects.get(title__exact=title)
+ path = '/badges/details/%s' % badge.slug
+ visit_page(path)
+
+@When(u'I fill in "(.*)" with "(.*)"')
+def fill_form_field(field_name, field_value):
+ """Look for the named field and fill it"""
+ page = scc.current_page
+ ok_(scc.current_page is not None, "there should be a current page")
+
+ # Try by direct name first.
+ field = page('*[name="%s"]' % field_name)
+
+ # Then, try by ID.
+ if (len(field) == 0):
+ field = page('#%s' % field_name)
+
+ # Next, try by association with a label.
+ if (len(field) == 0):
+ label = page('label:contains("%s")' % field_name)
+ if (len(label) == 1):
+ field_name = label.attr('for')
+ # Try the label's for attribute as either name or ID.
+ field = page('*[name="%s"]' % field_name)
+ if (len(field)==0):
+ field = page('#%s' % field_name)
+
+ ok_(len(field) == 1, 'the form field named/labelled "%s" should exist on %s' % (
+ field_name, scc.current_path
+ ))
+ glc.log.debug("Found field %s - %s" % (field.attr('name'), field))
+ scc.current_form[field.attr('name')] = field_value
+
+@When(u'I press "(.*)"')
+def press_form_button(button_name):
+ page = scc.current_page
+ ok_(scc.current_page is not None, "there should be a current page")
+
+ field = page('input[value="%s"]' % button_name)
+ glc.log.debug("Found button by value %s - %s" % (button_name, field))
+
+ form = field.parents('form:first')
+ form_action = form.attr('action')
+ if not form_action:
+ form_action = scc.current_path
+ form_method = form.attr('method')
+ if not form_method:
+ form_method = 'post'
+
+ scc.current_form['csrfmiddlewaretoken'] = \
+ page('input[name=csrfmiddlewaretoken]').val()
+
+ if form_method == 'post':
+ resp = scc.browser.post(form_action, scc.current_form, follow=True)
+ else:
+ resp = scc.browser.get(form_action, scc.current_form, follow=True)
+
+ eq_(200, resp.status_code)
+ set_current_page(form_action, resp)
+
+@Then(u'I should see no form validation errors')
+def should_see_no_form_validation_errors():
+ page = scc.current_page
+ error_lists = page('ul.errorlist')
+ eq_(0, len(error_lists), 'there should be no error lists')
+
+@Then(u'I should see "(.*)" somewhere on the page')
+def should_see_page_content(expected_content):
+ page_content = scc.last_response.content
+ try:
+ pos = page_content.index(expected_content)
+ except ValueError:
+ glc.log.debug("Page content: %s" % scc.last_response.content)
+ ok_(False, '"%s" should be found in page content' % expected_content)
+
+@Then(u'I should see a page entitled "(.*)"')
+def should_see_page_title(expected_title):
+ page = scc.current_page
+ hit = page('title:contains("%s")' % expected_title)
+ ok_(len(hit) > 0, '"%s" should be found in page title' % expected_title)
+
+@Then(u'"(.*)" should be nominated by "(.*)" for badge "(.*)" because "(.*)"')
+def check_nomination(nominee_name, nominator_name, badge_title, badge_reason_why):
+ nominee = User.objects.get(username__exact=nominee_name)
+ nominator = User.objects.get(username__exact=nominator_name)
+ badge = Badge.objects.get(title__exact=badge_title)
+
+ nomination = BadgeNomination.objects.filter(
+ nominee__exact=nominee,
+ nominator__exact=nominator,
+ badge__exact=badge,
+ ).get()
+
+ eq_(badge_reason_why, nomination.reason_why)
+
+@Then(u'"(.*)" should receive a "(.*)" notification')
+def check_notifications(username, notification_name):
+ try:
+ notice_type = NoticeType.objects.filter(label__exact=notification_name).get()
+ except NoticeType.DoesNotExist:
+ notice_type = NoticeType.objects.filter(display__exact=notification_name).get()
+
+ user = User.objects.filter(username__exact=username).get()
+ notices = Notice.objects.notices_for(user).filter(notice_type__exact=notice_type)
+
+###########################################################################
+# Utility functions
+###########################################################################
+
+def get_user(username, password=None, email=None):
+ """Get a user for the given username, creating it if necessary."""
+ if password is None: password = '%s_password' % username
+ if email is None: email = '%s@example.com' % username
+ try:
+ user = User.objects.get(username__exact=username)
+ except User.DoesNotExist:
+ user = User.objects.create_user(username, email, password)
+ ok_(user is not None, "user should exist")
+ return user
+
+def set_current_page(path, resp):
+ scc.last_response = resp
+ scc.current_path = path
+ scc.current_page = PyQuery(resp.content)
+ scc.current_form = {}
+ return scc.current_page
+
+def visit_page(path, data={}, follow=True, status_code=200, **extra):
+ resp = scc.browser.get(path)
+ glc.log.debug("Visiting path %s with status %s" % (path, resp.status_code))
+ eq_(status_code, resp.status_code)
+ return set_current_page(path, resp)
View
30 apps/badges/forms.py
@@ -1,3 +1,31 @@
from django import forms
-# place form definition here
+from django.contrib.auth.models import User
+from badger.apps.badges.models import Badge, BadgeNomination
+
+class BadgeForm(forms.ModelForm):
+ class Meta:
+ model = Badge
+ fields = ( 'title', 'description', 'tags' )
+
+class UserField(forms.CharField):
+
+ def clean(self, value):
+
+ if not value:
+ return None
+ if isinstance(value, (User)):
+ return value
+ try:
+ return User.objects.get(username__exact=value)
+ except User.DoesNotExist:
+ return None
+
+class BadgeNominationForm(forms.ModelForm):
+ nominee = UserField()
+
+ class Meta:
+ model = BadgeNomination
+ fields = ('nominee', 'reason_why')
+
+
View
27 apps/badges/management.py
@@ -0,0 +1,27 @@
+from django.db.models import signals, get_app
+from django.core.exceptions import ImproperlyConfigured
+from django.utils.translation import ugettext_noop as _
+
+notification = get_app('notification')
+
+def create_notice_types(app, created_models, verbosity, **kwargs):
+
+ notification.create_notice_type(
+ "badge_nomination_sent",
+ _("Badge Nomination Sent"),
+ _("you have sent a nomination for a badge")
+ )
+
+ notification.create_notice_type(
+ "badge_nomination_received",
+ _("Badge Nomination Received"),
+ _("you have been nominated for a badge")
+ )
+
+ notification.create_notice_type(
+ "badge_nomination_proposed",
+ _("Badge Nomination Proposed"),
+ _("someone has nominated someone else to receive a badge for which you are a decision maker")
+ )
+
+signals.post_syncdb.connect(create_notice_types, sender=notification)
View
75 apps/badges/models.py
@@ -1,3 +1,76 @@
+"""Models for the badge application"""
+from datetime import datetime
+
+from django.conf import settings
+from django.core.urlresolvers import reverse
from django.db import models
+from django.utils.translation import ugettext_lazy as _
+from django.template.defaultfilters import slugify
+
+from django.contrib.auth.models import User
+
+from tagging.fields import TagField
+from tagging.models import Tag
+
+from notification import models as notification
+
+class Badge(models.Model):
+ """Badge model"""
+ title = models.CharField(_("title"), max_length=255, blank=False, unique=True)
+ slug = models.SlugField(_("slug"), blank=False, unique=True)
+ description = models.TextField(_("description"), blank=False)
+ tags = TagField()
+ creator = models.ForeignKey(User)
+ creator_ip = models.IPAddressField(
+ _("IP Address of the Creator"),
+ blank = True, null = True
+ )
+ created_at = models.DateTimeField(_("created at"), default=datetime.now)
+ updated_at = models.DateTimeField(_("updated at"))
+
+ def __unicode__(self):
+ return self.title
+
+ def save(self, **kwargs):
+ if not self.slug:
+ self.slug = slugify(self.title)
+ self.updated_at = datetime.now()
+ super(Badge, self).save(**kwargs)
+
+class BadgeNomination(models.Model):
+ """Representation of a user nominated to receive a badge"""
+ badge = models.ForeignKey(Badge)
+ nominee = models.ForeignKey(User, related_name="nominee", verbose_name=_("nominee"))
+ nominator = models.ForeignKey(User, related_name="nominator", verbose_name=_("nominator"))
+ reason_why = models.TextField()
+ created_at = models.DateTimeField(_("created at"), default=datetime.now)
+ updated_at = models.DateTimeField(_("updated at"))
+
+ def save(self, **kwargs):
+ self.updated_at = datetime.now()
+ super(BadgeNomination, self).save(**kwargs)
+
+class BadgeAward(models.Model):
+ """Representation of a badge awarded to a user"""
+ badge = models.ForeignKey(Badge)
+ awardee = models.ForeignKey(User, verbose_name=_("user"))
+ created_at = models.DateTimeField(_("created at"), default=datetime.now)
+ updated_at = models.DateTimeField(_("updated at"))
+
+ def save(self, **kwargs):
+ self.updated_at = datetime.now()
+ super(Badge, self).save(**kwargs)
+
+# handle notification of new comments
+from threadedcomments.models import ThreadedComment
+def new_comment(sender, instance, **kwargs):
+ post = instance.content_object
+ if isinstance(post, Badge):
+ if notification:
+ notification.send([post.author], "badge_comment", {
+ "user": instance.user,
+ "post": post,
+ "comment": instance
+ })
-# Create your models here.
+models.signals.post_save.connect(new_comment, sender=ThreadedComment)
View
19 apps/badges/templates/badges/create.html
@@ -0,0 +1,19 @@
+{% extends "site_base.html" %}
+
+{% load i18n %}
+{% load ifsetting_tag %}
+
+{% block head_title %}{% trans "Create a badge" %}{% endblock %}
+
+{% block body %}
+ <h1>{% trans "Create a badge" %}</h1>
+
+ <form action="" method="post">
+ {% csrf_token %}
+ <ul class="fields">
+ {{form.as_ul}}
+ <li><input type="submit" value="Create" /></li>
+ </ul>
+ </form>
+
+{% endblock %}
View
27 apps/badges/templates/badges/detail.html
@@ -0,0 +1,27 @@
+{% extends "site_base.html" %}
+
+{% load i18n %}
+{% load ifsetting_tag %}
+
+{% block head_title %}{% trans "Badge details" %}{% endblock %}
+
+{% block body %}
+ <h1>{% trans "Badge details" %}</h1>
+
+ <div>
+ <h2>{{ badge.title }}</h2>
+ <p>{{ badge.description }}</p>
+ </div>
+
+ <div>
+ <h2>Nominate someone for this badge</h2>
+ <form action="" method="post">
+ {% csrf_token %}
+ <ul class="fields">
+ {{nomination_form.as_ul}}
+ <li><input type="submit" value="Nominate for badge" /></li>
+ </ul>
+ </form>
+ </div>
+
+{% endblock %}
View
0 apps/badges/templates/notification/badge_nomination_proposed/full.html
No changes.
View
0 apps/badges/templates/notification/badge_nomination_proposed/full.txt
No changes.
View
1 apps/badges/templates/notification/badge_nomination_proposed/notice.html
@@ -0,0 +1 @@
+{{nomination.nominator.username}} has proposed that {{nomination.nominee.username}} should be awarded the badge "{{nomination.badge.title}}" because "{{nomination.reason_why}}"
View
1 apps/badges/templates/notification/badge_nomination_proposed/short.txt
@@ -0,0 +1 @@
+{{nomination.nominator.username}} has proposed that {{nomination.nominee.username}} should be awarded the badge "{{nomination.badge.title}}" because "{{nomination.reason_why}}"
View
0 apps/badges/templates/notification/badge_nomination_received/full.html
No changes.
View
0 apps/badges/templates/notification/badge_nomination_received/full.txt
No changes.
View
1 apps/badges/templates/notification/badge_nomination_received/notice.html
@@ -0,0 +1 @@
+{{nomination.nominator.username}} has proposed that <strong>you</strong> should be awarded the badge "{{nomination.badge.title}}" because "{{nomination.reason_why}}"
View
1 apps/badges/templates/notification/badge_nomination_received/short.txt
@@ -0,0 +1 @@
+{{nomination.nominator.username}} has proposed that you should be awarded the badge "{{nomination.badge.title}}" because "{{nomination.reason_why}}"
View
0 apps/badges/templates/notification/badge_nomination_sent/full.html
No changes.
View
0 apps/badges/templates/notification/badge_nomination_sent/full.txt
No changes.
View
1 apps/badges/templates/notification/badge_nomination_sent/notice.html
@@ -0,0 +1 @@
+you have proposed that {{nomination.nominee.username}} should be awarded the badge "{{nomination.badge.title}}" because "{{nomination.reason_why}}"
View
1 apps/badges/templates/notification/badge_nomination_sent/short.txt
@@ -0,0 +1 @@
+you have proposed that {{nomination.nominee.username}} should be awarded the badge "{{nomination.badge.title}}" because "{{nomination.reason_why}}"
View
24 apps/badges/tests.py
@@ -1,24 +0,0 @@
-""" """
-from django.http import HttpRequest
-from django.test import TestCase
-
-#import mock
-#from nose.tools import assert_false, eq_
-#from test_utils import TestCase
-#from .acl import match_rules, action_allowed, check_ownership
-
-def test_thing():
- assert False
-
-class TestBadges(TestCase):
-
- def setUp(self):
- pass
-
- def tearDown(self):
- pass
-
- def test_again(self):
- assert False
-
-
View
59 apps/badges/tests/test_models.py
@@ -0,0 +1,59 @@
+""" """
+from django.http import HttpRequest
+from django.test import TestCase
+
+from django.contrib.auth.models import User
+
+from pinax.apps.profiles.models import Profile
+from pinax.apps.account.models import Account
+
+from badger.apps.badges.models import Badge, BadgeNomination, BadgeAward
+
+from nose.tools import assert_equal, with_setup, assert_false, eq_, ok_
+
+class TestBadges(TestCase):
+
+ def setUp(self):
+ self.users = {}
+ for user_name in ( 'user1', 'user2', 'user3' ):
+ self.users[user_name] = User.objects.create(username=user_name)
+
+ def tearDown(self):
+ for name, user in self.users.items():
+ user.delete()
+
+ def test_create_badge(self):
+ """Exercise simple creation of badges"""
+ p1 = Profile.objects.get(user=self.users['user1'])
+ a1 = Account.objects.get(user=self.users['user1'])
+
+ b1 = Badge.objects.create(
+ creator = self.users['user1'],
+ title = "First test passed!",
+ description = "Congratulations, the first test passed"
+ )
+
+ b2 = Badge.objects.create(
+ creator = self.users['user2'],
+ title = "Second test passed!",
+ description = "Congratulations, the second test passed"
+ )
+
+ b3 = Badge.objects.create(
+ creator = self.users['user3'],
+ title = "Third test passed!",
+ description = "Congratulations, the third test passed"
+ )
+
+ def test_badge_nomination(self):
+ ok_(False, "TODO")
+
+ def test_badge_award(self):
+ ok_(False, "TODO")
+
+ def test_tags_on_badges(self):
+ ok_(False, "TODO")
+
+ def test_comments_on_badges(self):
+ ok_(False, "TODO")
+
View
9 apps/badges/urls.py
@@ -1,3 +1,10 @@
from django.conf.urls.defaults import *
-# place app url patterns here
+urlpatterns = patterns("badger.apps.badges.views",
+ #url(r"^$", "friends_app.views.friends", name="invitations"),
+ #url(r"^contacts/$", "friends_app.views.contacts", name="invitations_contacts"),
+ #url(r"^accept/(\w+)/$", "friends_app.views.accept_join", name="friends_accept_join"),
+ url(r"^create$", "create", name="create_badge"),
+ url(r"^details/(.*)$", "details", name="badge_details"),
+)
+
View
76 apps/badges/views.py
@@ -1 +1,75 @@
-# Create your views here.
+from django.conf import settings
+from django.core.urlresolvers import reverse
+from django.http import HttpResponseRedirect, HttpResponse
+from django.shortcuts import get_object_or_404, render_to_response
+from django.template import RequestContext
+from django.contrib import messages
+from django.contrib.auth.decorators import login_required
+from django.utils.translation import ugettext, ugettext_lazy as _
+
+from badger.apps.badges.models import Badge, BadgeNomination
+from badger.apps.badges.forms import BadgeForm, BadgeNominationForm
+
+from notification import models as notification
+
+def details(request, badge_slug):
+
+ badge = get_object_or_404(Badge, slug__exact=badge_slug)
+
+ if request.method == "POST":
+ nomination_form = BadgeNominationForm(request.POST)
+ if nomination_form.is_valid():
+
+ new_nomination = nomination_form.save(commit=False)
+ new_nomination.badge = badge
+ new_nomination.nominator = request.user
+ new_nomination.save()
+
+ messages.add_message(
+ request, messages.SUCCESS,
+ ugettext("%s nominated for %s" %
+ (new_nomination.nominee, badge))
+ )
+
+ notes_to_send = (
+ ( request.user, 'badge_nomination_sent'),
+ ( badge.creator, 'badge_nomination_proposed'),
+ ( new_nomination.nominee, 'badge_nomination_received')
+ )
+
+ for note_to_send in notes_to_send:
+ notification.send( [ note_to_send[0] ], note_to_send[1], {
+ "nomination": new_nomination
+ })
+
+ return HttpResponseRedirect(reverse(
+ 'badger.apps.badges.views.details', args=(badge.slug,)
+ ))
+ else:
+ nomination_form = BadgeNominationForm()
+
+ return render_to_response('badges/detail.html', {
+ 'badge': badge,
+ 'nomination_form': nomination_form
+ }, context_instance=RequestContext(request))
+
+
+@login_required
+def create(request):
+
+ if request.method == "POST":
+ form = BadgeForm(request.POST)
+ if form.is_valid():
+ new_badge = form.save(commit=False)
+ new_badge.creator = request.user
+ new_badge.save()
+ return HttpResponseRedirect(reverse(
+ 'badger.apps.badges.views.details', args=(new_badge.slug,)
+ ))
+ else:
+ form = BadgeForm()
+
+ return render_to_response('badges/create.html', {
+ 'form': form
+ }, context_instance=RequestContext(request))
+
View
3 context_processors.py
@@ -2,10 +2,7 @@
from django.core.exceptions import ImproperlyConfigured
from django.contrib.auth.models import User
-from microblogging.models import Tweet
from pinax.apps.tribes.models import Tribe
-from bookmarks.models import Bookmark
-from pinax.apps.blog.models import Post
_inbox_count_sources = None
View
5 requirements/dev.txt
@@ -6,3 +6,8 @@
-e git+http://github.com/jbalogh/django-nose.git#egg=django-nose
-e git+http://github.com/jbalogh/check.git#egg=check
# -e git+http://github.com/jbalogh/test-utils.git#egg=test-utils
+
+lxml
+pyquery
+freshen
+mock
View
7 settings.py
@@ -113,6 +113,7 @@
ROOT_URLCONF = "badger.urls"
TEMPLATE_DIRS = [
+ os.path.join(PROJECT_ROOT, "apps", "badges", "templates"),
os.path.join(PROJECT_ROOT, "templates"),
os.path.join(PINAX_ROOT, "templates", PINAX_THEME),
]
@@ -169,12 +170,10 @@
"groups",
"gravatar",
"threadedcomments",
- "wiki",
"timezones",
"voting",
"tagging",
"ajax_validation",
- "photologue",
"avatar",
"flag",
"uni_form",
@@ -195,11 +194,13 @@
"pinax.apps.voting_extras",
# project
- "badges",
+ "badger.apps.about",
+ "badger.apps.badges",
]
if DEBUG:
INSTALLED_APPS += [
+ "lettuce.django",
"django_nose",
]
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
View
3 templates/homepage.html
@@ -16,9 +16,10 @@
Badger thinks it might be nice to gift badges and track achievements for people
on the web.
-We'll see how well he manages to do it, hopefully with your help!
+We'll see how well it manages to do this, hopefully with your help!
{% endblocktrans %}{% endfilter %}
+<a href="#">Create badge</a>
<hr />
{% if user.is_authenticated %}
{% url what_next as what_next_url %}
View
6 templates/site_base.html
@@ -23,7 +23,11 @@
{% block login %}
{% if user.is_authenticated %}
- Welcome, <a href="{% url profile_detail user %}">{% ifopenid %}<img src="{{ STATIC_URL }}images/openid-icon.png" alt="Logged in with OpenID" />{% endifopenid %}<b>{% user_display user %}</b></a> | <a href="{% url acct_email %}">{% trans "Settings" %}</a> | <a href="{% url messages_inbox %}">{% trans "Inbox" %} ({{ combined_inbox_count }})</a> | {% if user.is_staff %}<a href="/admin/">{% trans "Admin" %}</a> | {% endif %}<a href="/openid/logout/?next={% url acct_logout %}">{% trans "Log out" %}</a>
+ Welcome, <a href="{% url profile_detail user %}" title="Profile details">{% ifopenid %}<img src="{{ STATIC_URL }}images/openid-icon.png" alt="Logged in with OpenID" />{% endifopenid %}<b>{% user_display user %}</b></a> |
+ <a href="{% url messages_inbox %}">{% trans "Inbox" %} ({{ combined_inbox_count }})</a> |
+ {% if user.is_staff %}<a href="/admin/">{% trans "Admin panel" %}</a> | {% endif %}
+ <a href="{% url acct_email %}">{% trans "Account settings" %}</a> |
+ <a href="/openid/logout/?next={% url acct_logout %}">{% trans "Log out" %}</a>
{% else %}
<a href="{% url acct_login %}">{% trans "Log in" %}</a> {% ifsetting ACCOUNT_OPEN_SIGNUP %}{% trans "or" %} <a href="{% url acct_signup %}"><b>{% trans "Sign up" %}</b></a>{% endifsetting %}
{% endif %}
View
18 terrain.py
@@ -0,0 +1,18 @@
+"""Global terrain for all Lettuce features"""
+# see also: http://lettuce.it/reference/terrain.html#terrain-py
+
+from lettuce import *
+
+@before.all
+def before_all():
+ print "Hello there!"
+ print "Lettuce will start to run tests right now..."
+
+@after.all
+def after_all(total):
+ print "Congratulations, %d of %d scenarios passed!" % (
+ total.scenarios_ran,
+ total.scenarios_passed
+ )
+ print "Goodbye!"
+
View
4 urls.py
@@ -6,7 +6,7 @@
admin.autodiscover()
from tagging.models import TaggedItem
-from wiki.models import Article as WikiArticle
+#from wiki.models import Article as WikiArticle
from pinax.apps.account.openid_consumer import PinaxConsumer
from pinax.apps.topics.models import Topic
@@ -26,6 +26,8 @@
url(r"^$", direct_to_template, {
"template": "homepage.html",
}, name="home"),
+
+ (r"^badges/", include("badger.apps.badges.urls")),
url(r"^admin/invite_user/$", "pinax.apps.signup_codes.views.admin_invite_user", name="admin_invite_user"),
url(r"^account/signup/$", signup_view, name="acct_signup"),

0 comments on commit 19fdc47

Please sign in to comment.
Something went wrong with that request. Please try again.