Skip to content

Commit

Permalink
Implemented initial badge nomination and approval; paths mapped named…
Browse files Browse the repository at this point in the history
… pages specified in feature background; section-constrained content search
  • Loading branch information
lmorchard committed Jul 17, 2010
1 parent 19fdc47 commit 8853d10
Show file tree
Hide file tree
Showing 19 changed files with 358 additions and 95 deletions.
27 changes: 27 additions & 0 deletions apps/badges/features/badge_award.feature
@@ -0,0 +1,27 @@
Feature: Awarding badges
As a nice person
I want to be able to award badges
In order to reward interesting behavior

Background:
Given a user named "user1"
And a user named "user2"
And a user named "user3"
And the "create badge" page is at "/badges/create"
And the "browse badges" page is at "/badges/"

Scenario: Badge creator approves a nomination to award a badge
Given "user1" creates a badge entitled "Nifty badge"
And "user2" nominates "user3" for a badge entitled "Nifty badge" because "user3 is Nifty"
And I am logged in as "user1"
And I go to the "badge detail" page for "Nifty badge"
When I click on "user3" in the "Nominations" section
Then I should see a page whose title contains "Badge nomination"
When I press "Approve"
Then I should see a page whose title contains "Badge detail"
And I should see "user3" somewhere in the "Awarded to" section
And I should not see "user3" anywhere in the "Nominations" section
And "user3" should be awarded the badge "Nifty badge"
And "user3" should receive a "Badge Awarded" notification


26 changes: 26 additions & 0 deletions apps/badges/features/badge_management.feature
@@ -0,0 +1,26 @@
Feature: Basic management of badges
As a nice person
I want to be able to create badges
In order to reward interesting behavior

Background:
Given a user named "user1"
And a user named "user2"
And a user named "user3"
And the "create badge" page is at "/badges/create"
And the "browse badges" page is at "/badges/"

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: Look for a badge on the browse badges page
Given "user1" creates a badge entitled "More awesome badge"
When I go to the "browse badges" page
Then I should see "More awesome badge" somewhere on the page
@@ -1,35 +1,26 @@
Feature: Basic creation and awarding of badges
Feature: Nominating users to be awarded badges
As a nice person
I want to be able to create and award badges
I want to be able to nominate people to be awarded badges
In order to reward interesting behavior

Background:
Given a user named "user1"
And a user named "user2"
And a user named "user3"
And the "create badge" page is at "/badges/create"
And the "browse badges" page is at "/badges/"

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
Scenario: A user nominates someone to be awarded 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"
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 I should see "user3" somewhere in the "Nominations" section
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


102 changes: 87 additions & 15 deletions apps/badges/features/steps.py
Expand Up @@ -21,6 +21,7 @@ def before_all(sc):
scc.current_path = None
scc.current_page = None
scc.current_form = None
scc.name_path_map = {}

@After
def after_all(sc):
Expand All @@ -30,6 +31,10 @@ def after_all(sc):
# Step definitions
###########################################################################

@Given(u'the "(.*)" page is at "(.*)"')
def establish_page_mapping(name, path):
scc.name_path_map[name] = path

@Given(u'a user named "(.*)"')
def establish_user(username):
user = get_user(username)
Expand All @@ -43,14 +48,10 @@ def given_i_am_logged_in_as(username):
)
ok_(succ, "login should succeed")

name_path_map = {
"create badge": "/badges/create"
}

@Given(u'I go to the "(.*)" page')
@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)
path = (page_name in scc.name_path_map and
scc.name_path_map[page_name] or page_name)
page = visit_page(path)

@Given(u'"(.*)" creates a badge entitled "(.*)"')
Expand All @@ -63,12 +64,32 @@ def user_creates_badge(username, title):
)
badge.save()

@Given(u'I go to the badge detail page for "(.*)"')
@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)

@Given(u'"(.*)" nominates "(.*)" for a badge entitled "(.*)" because "(.*)"')
def create_nomination(nominator_name, nominee_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(
nominee=nominee,
nominator=nominator,
badge=badge,
reason_why=badge_reason_why
)
nomination.save()

@When(u'I go to the "(.*)" page$')
def i_go_to_named_page(page_name):
path = (page_name in scc.name_path_map and
scc.name_path_map[page_name] or page_name)
page = 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"""
Expand All @@ -95,7 +116,6 @@ def fill_form_field(field_name, field_value):
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 "(.*)"')
Expand All @@ -104,7 +124,7 @@ def press_form_button(button_name):
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))
ok_(len(field) > 0, 'button "%s" should exist' % button_name)

form = field.parents('form:first')
form_action = form.attr('action')
Expand All @@ -125,6 +145,15 @@ def press_form_button(button_name):
eq_(200, resp.status_code)
set_current_page(form_action, resp)

@When(u'I click on "(.*)" in the "(.*)" section')
def click_link_in_section(link_content, section_title):
page = scc.current_page
section = find_section_in_page(section_title)
link = section.find('a:contains("%s")' % link_content)
ok_(len(link) > 0, 'link "%s" should be found in section "%s"' % (link_content, section_title))
path = link.attr('href')
page = visit_page(path)

@Then(u'I should see no form validation errors')
def should_see_no_form_validation_errors():
page = scc.current_page
Expand All @@ -140,26 +169,63 @@ def should_see_page_content(expected_content):
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 "(.*)" somewhere in the "(.*)" section')
def section_content_check(expected_content, section_title):
page = scc.current_page
section = find_section_in_page(section_title)
section_content = section.text()
try:
pos = section_content.index(expected_content)
except ValueError:
glc.log.debug("Section content: %s" % section_content)
ok_(False, '"%s" should be found in content for section "%s"' %
(expected_content, section_title))

@Then(u'I should not see "(.*)" anywhere in the "(.*)" section')
def section_no_content_check(expected_content, section_title):
page = scc.current_page
section = find_section_in_page(section_title)
section_content = section.text()
try:
pos = section_content.index(expected_content)
ok_(False, '"%s" should not be found in content for section "%s"' %
(expected_content, section_title))
except ValueError:
pass

@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'I should see a page whose title contains "(.*)"')
def page_title_should_contain(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,
nominee=nominee, nominator=nominator, badge=badge,
).get()

eq_(badge_reason_why, nomination.reason_why)

@Then(u'"(.*)" should be awarded the badge "(.*)"')
def check_badge_award(awardee_name, badge_title):
awardee = User.objects.get(username__exact=awardee_name)
badge = Badge.objects.get(title__exact=badge_title)

award = BadgeAward.objects.filter(
awardee=awardee, badge=badge
).get()

@Then(u'"(.*)" should receive a "(.*)" notification')
def check_notifications(username, notification_name):
try:
Expand All @@ -168,7 +234,7 @@ def check_notifications(username, notification_name):
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)
notices = Notice.objects.notices_for(user).filter(notice_type=notice_type).get()

###########################################################################
# Utility functions
Expand All @@ -194,6 +260,12 @@ def set_current_page(path, resp):

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)

def find_section_in_page(section_title):
page = scc.current_page
section = page(':header:contains("%s")' % section_title).parent()
ok_(len(section) > 0, "the section %s should be found" % section_title)
return section

8 changes: 7 additions & 1 deletion apps/badges/management.py
Expand Up @@ -21,7 +21,13 @@ def create_notice_types(app, created_models, verbosity, **kwargs):
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")
_("someone has been nominated to receive a badge for which you are a decision maker")
)

notification.create_notice_type(
"badge_awarded",
_("Badge Awarded"),
_("a badge has been awarded")
)

signals.post_syncdb.connect(create_notice_types, sender=notification)
16 changes: 12 additions & 4 deletions apps/badges/models.py
Expand Up @@ -40,26 +40,34 @@ def save(self, **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"))
nominee = models.ForeignKey(User, blank=False, related_name="nominee", verbose_name=_("nominee"))
nominator = models.ForeignKey(User, related_name="nominator", verbose_name=_("nominator"))
reason_why = models.TextField()
approved = models.BooleanField(default=False)
reason_why = models.TextField(blank=False)
created_at = models.DateTimeField(_("created at"), default=datetime.now)
updated_at = models.DateTimeField(_("updated at"))

def __unicode__(self):
return '%s nominated for %s' % (self.nominee.username, self.badge.title)

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"))
nomination = models.ForeignKey(BadgeNomination)
awardee = models.ForeignKey(User, verbose_name=_("awardee"))
created_at = models.DateTimeField(_("created at"), default=datetime.now)
updated_at = models.DateTimeField(_("updated at"))

def __unicode__(self):
return '%s awarded %s' % (self.awardee.username, self.badge.title)

def save(self, **kwargs):
self.updated_at = datetime.now()
super(Badge, self).save(**kwargs)
super(BadgeAward, self).save(**kwargs)

# handle notification of new comments
from threadedcomments.models import ThreadedComment
Expand Down
38 changes: 28 additions & 10 deletions apps/badges/templates/badges/detail.html
@@ -1,7 +1,6 @@
{% extends "site_base.html" %}

{% load i18n %}
{% load ifsetting_tag %}

{% block head_title %}{% trans "Badge details" %}{% endblock %}

Expand All @@ -11,17 +10,36 @@ <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>
<div>
<h3>Awarded to</h3>
<ul>
{% for award in awards %}
<li>{{ award.awardee }}</li>
{% endfor %}
</ul>
</div>

<div>
<h3>Nominations</h3>
<ul>
{% for nomination in nominations %}
<li><a href="{% url badge_nomination nomination.badge.slug nomination.nominee.username %}">{{ nomination.nominee }}</a></li>
{% endfor %}
</ul>
</form>
</div>

<div>
<h3>Nominate someone for this badge</h3>
<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>

</div>

{% endblock %}

0 comments on commit 8853d10

Please sign in to comment.