def test_award_detail(self):
        """Can view award detail"""
        user = self._get_user()
        user2 = self._get_user(username="******")

        b1, created = Badge.objects.get_or_create(creator=user, title="Code Badge #1", description="Some description")
        award = b1.award_to(user2)

        url = reverse("badger.views.award_detail", args=(b1.slug, award.pk))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        eq_("award_detail", doc.find("body").attr("id"))
        eq_(1, doc.find('.award .awarded_to .username:contains("%s")' % user2.username).length)
        eq_(1, doc.find('.badge-title:contains("%s")' % b1.title).length)

        # Now, take a look at the JSON format
        url = reverse("badger.award_detail_json", args=(b1.slug, award.pk))
        r = self.client.get(url, follow=True)

        data = json.loads(r.content)

        hash_salt = hashlib.md5("%s-%s" % (award.badge.pk, award.pk)).hexdigest()
        recipient_text = "%s%s" % (award.user.email, hash_salt)
        recipient_hash = "sha256$%s" % hashlib.sha256(recipient_text).hexdigest()

        eq_(recipient_hash, data["recipient"])
        eq_("http://testserver%s" % award.get_absolute_url(), data["evidence"])
        eq_(award.badge.title, data["badge"]["name"])
        eq_(award.badge.description, data["badge"]["description"])
        eq_("http://testserver%s" % award.badge.get_absolute_url(), data["badge"]["criteria"])
    def test_deferred_award_immediate_claim(self):
        """Ensure that a deferred award can be immediately claimed rather than
        viewing detail"""
        deferred_email = "*****@*****.**"
        user1 = self._get_user(username="******", email="*****@*****.**")
        b1 = Badge.objects.create(creator=user1, title="Badge to defer")

        da = DeferredAward(badge=b1, creator=user1)
        da.save()
        url = da.get_claim_url()

        # Just viewing the claim URL shouldn't require login.
        r = self.client.get(url, follow=False)
        eq_(200, r.status_code)

        # But, attempting to claim the award should require login
        r = self.client.post(reverse("badger.views.claim_deferred_award"), dict(code=da.claim_code), follow=False)
        eq_(302, r.status_code)
        ok_("login" in r["Location"])

        # So, try logging in and fetch the immediate-claim URL
        user2 = self._get_user(username="******", email=deferred_email)
        self.client.login(username="******", password="******")
        r = self.client.post(reverse("badger.views.claim_deferred_award"), dict(code=da.claim_code), follow=False)
        eq_(302, r.status_code)
        ok_("awards" in r["Location"])

        ok_(b1.is_awarded_to(user2))
Esempio n. 3
0
    def test_deferred_award_claim_on_login(self):
        """Ensure that a deferred award gets claimed on login."""
        deferred_email = "*****@*****.**"
        user1 = self._get_user(username="******", email="*****@*****.**")
        b1 = Badge.objects.create(creator=user1, title="Badge to defer")
        url = reverse('badger.views.award_badge', args=(b1.slug, ))

        self.client.login(username="******", password="******")
        r = self.client.get(url, follow=True)
        eq_(200, r.status_code)

        doc = pq(r.content)
        form = doc('form#award_badge')
        eq_(1, form.length)
        eq_(1, form.find('*[name=emails]').length)
        eq_(1, form.find('input.submit,button.submit').length)

        r = self.client.post(url, dict(emails=deferred_email, ), follow=False)

        ok_('award' not in r['Location'])

        user2 = self._get_user(username="******", email=deferred_email)
        self.client.login(username="******", password="******")
        r = self.client.get(reverse('badger.views.detail', args=(b1.slug, )),
                            follow=True)
        ok_(b1.is_awarded_to(user2))
Esempio n. 4
0
    def test_deferred_award_immediate_claim(self):
        """Ensure that a deferred award can be immediately claimed rather than
        viewing detail"""
        deferred_email = "*****@*****.**"
        user1 = self._get_user(username="******", email="*****@*****.**")
        b1 = Badge.objects.create(creator=user1, title="Badge to defer")

        da = DeferredAward(badge=b1, creator=user1)
        da.save()
        url = da.get_claim_url()

        # Just viewing the claim URL shouldn't require login.
        r = self.client.get(url, follow=False)
        eq_(200, r.status_code)

        # But, attempting to claim the award should require login
        r = self.client.post(reverse('badger.views.claim_deferred_award'),
                             dict(code=da.claim_code, ),
                             follow=False)
        eq_(302, r.status_code)
        ok_('login' in r['Location'])

        # So, try logging in and fetch the immediate-claim URL
        user2 = self._get_user(username="******", email=deferred_email)
        self.client.login(username="******", password="******")
        r = self.client.post(reverse('badger.views.claim_deferred_award'),
                             dict(code=da.claim_code, ),
                             follow=False)
        eq_(302, r.status_code)
        ok_('awards' in r['Location'])

        ok_(b1.is_awarded_to(user2))
Esempio n. 5
0
    def test_badge_detail(self):
        """Can view badge detail"""
        user = self._get_user()
        badge = Badge(creator=user,
                      title="Test II",
                      description="Another test")
        badge.save()

        r = self.client.get(reverse('badger.views.detail',
                                    args=(badge.slug, )),
                            follow=True)
        doc = pq(r.content)

        eq_('badge_detail', doc.find('body').attr('id'))
        eq_(1, doc.find('.badge-title:contains("%s")' % badge.title).length)
        eq_(badge.description, doc.find('.badge .description').text())

        # Now, take a look at the JSON format
        url = reverse('badger.detail_json', args=(badge.slug, ))
        r = self.client.get(url, follow=True)

        data = json.loads(r.content)
        eq_(badge.title, data['name'])
        eq_(badge.description, data['description'])
        eq_('http://testserver%s' % badge.get_absolute_url(), data['criteria'])
    def test_deferred_award_claim_on_login(self):
        """Ensure that a deferred award gets claimed on login."""
        deferred_email = "*****@*****.**"
        user1 = self._get_user(username="******", email="*****@*****.**")
        b1 = Badge.objects.create(creator=user1, title="Badge to defer")
        url = reverse("badger.views.award_badge", args=(b1.slug,))

        self.client.login(username="******", password="******")
        r = self.client.get(url, follow=True)
        eq_(200, r.status_code)

        doc = pq(r.content)
        form = doc("form#award_badge")
        eq_(1, form.length)
        eq_(1, form.find("*[name=emails]").length)
        eq_(1, form.find("input.submit,button.submit").length)

        r = self.client.post(url, dict(emails=deferred_email), follow=False)

        ok_("award" not in r["Location"])

        user2 = self._get_user(username="******", email=deferred_email)
        self.client.login(username="******", password="******")
        r = self.client.get(reverse("badger.views.detail", args=(b1.slug,)), follow=True)
        ok_(b1.is_awarded_to(user2))
Esempio n. 7
0
def build_related_link(self, model_name, name_single, name_plural, qs):
    link = '%s?%s' % (reverse('admin:badger_%s_changelist' % model_name,
                              args=[]), 'badge__exact=%s' % (self.id))
    new_link = '%s?%s' % (reverse('admin:badger_%s_add' % model_name,
                                  args=[]), 'badge=%s' % (self.id))
    count = qs.count()
    what = (count == 1) and name_single or name_plural
    return ('<a href="%s">%s %s</a> (<a href="%s">new</a>)' %
            (link, count, what, new_link))
Esempio n. 8
0
def _redirect_to_claimed_awards(awards, awards_ct):
    # Has this claim code already been used for awards?
    # If so, then a GET redirects to an award detail or list
    if awards_ct == 1:
        award = awards[0]
        url = reverse('badger.views.award_detail',
                      args=(award.badge.slug, award.id,))
        return HttpResponseRedirect(url)
    elif awards_ct > 1:
        award = awards[0]
        url = reverse('badger.views.awards_list',
                      args=(award.badge.slug,))
        return HttpResponseRedirect(url)
Esempio n. 9
0
def build_related_link(self, model_name, name_single, name_plural, qs):
    link = '%s?%s' % (
        reverse('admin:badger_%s_changelist' % model_name, args=[]),
        'badge__exact=%s' % (self.id)
    )
    new_link = '%s?%s' % (
        reverse('admin:badger_%s_add' % model_name, args=[]),
        'badge=%s' % (self.id)
    )
    count = qs.count()
    what = (count == 1) and name_single or name_plural
    return ('<a href="%s">%s %s</a> (<a href="%s">new</a>)' %
            (link, count, what, new_link))
Esempio n. 10
0
    def test_create(self):
        """Can create badge with form"""
        # Login should be required
        r = self.client.get(reverse('badger.views.create'))
        eq_(302, r.status_code)
        ok_('/accounts/login' in r['Location'])

        # Should be fine after login
        settings.BADGER_ALLOW_ADD_BY_ANYONE = True
        self.client.login(username="******", password="******")
        r = self.client.get(reverse('badger.views.create'))
        eq_(200, r.status_code)

        # Make a chick check for expected form elements
        doc = pq(r.content)

        form = doc('form#create_badge')
        eq_(1, form.length)

        eq_(1, form.find('input[name=title]').length)
        eq_(1, form.find('textarea[name=description]').length)
        # For styling purposes, we'll allow either an input or button element
        eq_(1, form.find('input.submit,button.submit').length)

        r = self.client.post(reverse('badger.views.create'),
                             dict(),
                             follow=True)
        doc = pq(r.content)
        eq_(1, doc.find('form .error > input[name=title]').length)

        badge_title = "Test badge #1"
        badge_desc = "This is a test badge"

        r = self.client.post(reverse('badger.views.create'),
                             dict(
                                 title=badge_title,
                                 description=badge_desc,
                             ),
                             follow=True)
        doc = pq(r.content)

        eq_('badge_detail', doc.find('body').attr('id'))
        ok_(badge_title in doc.find('.badge-title').text())
        eq_(badge_desc, doc.find('.badge .description').text())

        slug = doc.find('.badge').attr('data-slug')

        badge = Badge.objects.get(slug=slug)
        eq_(badge_title, badge.title)
        eq_(badge_desc, badge.description)
def _redirect_to_claimed_awards(awards, awards_ct):
    # Has this claim code already been used for awards?
    # If so, then a GET redirects to an award detail or list
    if awards_ct == 1:
        award = awards[0]
        url = reverse('badger.views.award_detail',
                      args=(
                          award.badge.slug,
                          award.id,
                      ))
        return HttpResponseRedirect(url)
    elif awards_ct > 1:
        award = awards[0]
        url = reverse('badger.views.awards_list', args=(award.badge.slug, ))
        return HttpResponseRedirect(url)
Esempio n. 12
0
    def test_delete(self):
        """Can delete badge"""
        user = self._get_user()
        badge = Badge(creator=user, title="Test III", description="Another test")
        badge.save()
        slug = badge.slug

        badge.award_to(user)

        self.client.login(username="******", password="******")

        r = self.client.get(reverse("badger.views.detail", args=(badge.slug,)), follow=True)
        doc = pq(r.content)

        eq_("badge_detail", doc.find("body").attr("id"))
        delete_url = doc.find("a.delete_badge").attr("href")
        ok_(delete_url is not None)

        r = self.client.get(delete_url)
        doc = pq(r.content)
        eq_("badge_delete", doc.find("body").attr("id"))
        eq_("1", doc.find(".awards_count").text())

        r = self.client.post(delete_url, {}, follow=True)
        doc = pq(r.content)

        try:
            badge = Badge.objects.get(slug=slug)
            ok_(False)
        except Badge.DoesNotExist:
            ok_(True)
Esempio n. 13
0
    def test_edit(self):
        """Can edit badge detail"""
        user = self._get_user()
        badge = Badge(creator=user, title="Test II", description="Another test")
        badge.save()

        self.client.login(username="******", password="******")

        r = self.client.get(reverse("badger.views.detail", args=(badge.slug,)), follow=True)
        doc = pq(r.content)

        eq_("badge_detail", doc.find("body").attr("id"))
        edit_url = doc.find("a.edit_badge").attr("href")
        ok_(edit_url is not None)

        r = self.client.get(edit_url)
        doc = pq(r.content)
        eq_("badge_edit", doc.find("body").attr("id"))

        badge_title = "Edited title"
        badge_desc = "Edited description"

        r = self.client.post(edit_url, dict(title=badge_title, description=badge_desc), follow=True)
        doc = pq(r.content)

        eq_("badge_detail", doc.find("body").attr("id"))
        ok_(badge_title in doc.find(".badge-title").text())
        eq_(badge_desc, doc.find(".badge .description").text())

        slug = doc.find(".badge").attr("data-slug")

        badge = Badge.objects.get(slug=slug)
        eq_(badge_title, badge.title)
        eq_(badge_desc, badge.description)
Esempio n. 14
0
    def test_grant_deferred_award(self):
        """Deferred award for a badge can be granted to an email address."""
        deferred_email = "*****@*****.**"
        user1 = self._get_user(username="******", email="*****@*****.**")
        b1 = Badge.objects.create(creator=user1, title="Badge to defer")

        da = DeferredAward(badge=b1, creator=user1, email="*****@*****.**")
        da.save()
        url = da.get_claim_url()

        self.client.login(username="******", password="******")
        r = self.client.get(url, follow=True)
        eq_(200, r.status_code)

        doc = pq(r.content)
        form = doc("form#grant_award")
        eq_(1, form.length)
        eq_(1, form.find("*[name=email]").length)
        eq_(1, form.find("input.submit,button.submit").length)

        r = self.client.post(url, dict(is_grant=1, email=deferred_email), follow=False)

        user2 = self._get_user(username="******", email=deferred_email)
        self.client.login(username="******", password="******")
        r = self.client.get(reverse("badger.views.detail", args=(b1.slug,)), follow=True)
        ok_(b1.is_awarded_to(user2))
    def test_baked_award_image(self):
        """Award gets image baked with OBI assertion"""
        # Get the source for a sample badge image
        img_data = open(BADGE_IMG_FN, 'r').read()

        # Make a badge with a creator
        user_creator = self._get_user(username="******")
        badge = self._get_badge(title="Badge with Creator",
                                creator=user_creator)
        badge.image.save('', ContentFile(img_data), True)

        # Get some users who can award any badge
        user_1 = self._get_user(username="******", is_superuser=True)
        user_2 = self._get_user(username="******", is_superuser=True)

        # Get some users who can receive badges
        user_awardee_1 = self._get_user(username="******")
        user_awardee_2 = self._get_user(username="******")

        # Try awarding the badge once with baking enabled and once without
        for enabled in (True, False):
            with patch_settings(BADGER_BAKE_AWARD_IMAGES=enabled):
                award_1 = badge.award_to(awardee=user_awardee_1)
                if not enabled:
                    ok_(not award_1.image)
                else:
                    ok_(award_1.image)
                    img = Image.open(award_1.image.file)
                    hosted_assertion_url = img.info['openbadges']
                    expected_url = '%s%s' % (
                        BASE_URL,
                        reverse('badger.award_detail_json',
                                args=(award_1.badge.slug, award_1.id)))
                    eq_(expected_url, hosted_assertion_url)
                award_1.delete()
Esempio n. 16
0
def staff_tools(request):
    """HACK: This page offers miscellaneous tools useful to event staff.
    Will go away in the future, addressed by:
    https://github.com/mozilla/django-badger/issues/35
    """
    if not (request.user.is_staff or request.user.is_superuser):
        return HttpResponseForbidden()

    if request.method != "POST":
        grant_form = DeferredAwardMultipleGrantForm()
    else:
        if request.REQUEST.get('is_grant', False) is not False:
            grant_form = DeferredAwardMultipleGrantForm(request.POST, request.FILES)
            if grant_form.is_valid():
                email = grant_form.cleaned_data['email']
                codes = grant_form.cleaned_data['claim_codes']
                for claim_code in codes:
                    da = DeferredAward.objects.get(claim_code=claim_code)
                    da.grant_to(email, request.user)
                    messages.info(request, _(u'Badge "{badgetitle}" granted to {email}').format(
                        badgetitle=da.badge, email=email))
                url = reverse('badger.views.staff_tools')
                return HttpResponseRedirect(url)

    return render_to_response('%s/staff_tools.html' % bsettings.TEMPLATE_BASE, dict(
        grant_form=grant_form
    ), context_instance=RequestContext(request))
Esempio n. 17
0
    def test_grant_deferred_award(self):
        """Deferred award for a badge can be granted to an email address."""
        deferred_email = "*****@*****.**"
        user1 = self._get_user(username="******", email="*****@*****.**")
        b1 = Badge.objects.create(creator=user1, title="Badge to defer")

        da = DeferredAward(badge=b1, creator=user1, email='*****@*****.**')
        da.save()
        url = da.get_claim_url()

        self.client.login(username="******", password="******")
        r = self.client.get(url, follow=True)
        eq_(200, r.status_code)

        doc = pq(r.content)
        form = doc('form#grant_award')
        eq_(1, form.length)
        eq_(1, form.find('*[name=email]').length)
        eq_(1, form.find('input.submit,button.submit').length)

        r = self.client.post(url,
                             dict(
                                 is_grant=1,
                                 email=deferred_email,
                             ),
                             follow=False)

        user2 = self._get_user(username="******", email=deferred_email)
        self.client.login(username="******", password="******")
        r = self.client.get(reverse('badger.views.detail', args=(b1.slug, )),
                            follow=True)
        ok_(b1.is_awarded_to(user2))
Esempio n. 18
0
    def test_delete(self):
        """Can delete badge"""
        user = self._get_user()
        badge = Badge(creator=user,
                      title="Test III",
                      description="Another test")
        badge.save()
        slug = badge.slug

        badge.award_to(user)

        self.client.login(username="******", password="******")

        r = self.client.get(reverse('badger.views.detail',
                                    args=(badge.slug, )),
                            follow=True)
        doc = pq(r.content)

        eq_('badge_detail', doc.find('body').attr('id'))
        delete_url = doc.find('a.delete_badge').attr('href')
        ok_(delete_url is not None)

        r = self.client.get(delete_url)
        doc = pq(r.content)
        eq_('badge_delete', doc.find('body').attr('id'))
        eq_("1", doc.find('.awards_count').text())

        r = self.client.post(delete_url, {}, follow=True)
        doc = pq(r.content)

        try:
            badge = Badge.objects.get(slug=slug)
            ok_(False)
        except Badge.DoesNotExist:
            ok_(True)
    def setUp(self):
        self.client = Client()

        self.testuser = self._get_user()

        self.badge = Badge(creator=self.testuser,
                           title="Test II",
                           description="Another test",
                           unique=True)
        self.badge.save()

        self.awards_url = reverse('badger.views.awards_list',
                                  args=(self.badge.slug, ))

        key = Key()
        key.user = self.testuser
        self.password = key.generate_secret()
        self.username = key.key
        key.save()
        self.key = key

        auth_ct = '%s:%s' % (self.username, self.password)
        self.basic_auth = 'Basic %s' % b64encode(auth_ct)
        self.headers = {'HTTP_AUTHORIZATION': self.basic_auth}

        Award.objects.all().delete()
Esempio n. 20
0
    def test_claim_code_shows_awards_after_claim(self):
        """Claim code URL should lead to award detail or list after claim"""
        user1 = self._get_user(username="******", email="*****@*****.**")
        user2 = self._get_user(username="******", email="*****@*****.**")
        b1 = Badge.objects.create(creator=user1,
                                  unique=False,
                                  title="Badge for claim viewing")
        da = DeferredAward(badge=b1, creator=user1)
        da.save()

        url = da.get_claim_url()

        # Before claim, code URL leads to claim page.
        r = self.client.get(url, follow=False)
        eq_(200, r.status_code)
        doc = pq(r.content)
        form = doc('form#claim_award')

        # After claim, code URL leads to a single award detail page.
        award = da.claim(user2)
        r = self.client.get(url, follow=False)
        eq_(302, r.status_code)
        award_url = reverse('badger.views.award_detail',
                            args=(award.badge.slug, award.pk))
        ok_(award_url in r['Location'])
def staff_tools(request):
    """HACK: This page offers miscellaneous tools useful to event staff.
    Will go away in the future, addressed by:
    https://github.com/mozilla/django-badger/issues/35
    """
    if not (request.user.is_staff or request.user.is_superuser):
        return HttpResponseForbidden()

    if request.method != "POST":
        grant_form = DeferredAwardMultipleGrantForm()
    else:
        if request.REQUEST.get('is_grant', False) is not False:
            grant_form = DeferredAwardMultipleGrantForm(
                request.POST, request.FILES)
            if grant_form.is_valid():
                email = grant_form.cleaned_data['email']
                codes = grant_form.cleaned_data['claim_codes']
                for claim_code in codes:
                    da = DeferredAward.objects.get(claim_code=claim_code)
                    da.grant_to(email, request.user)
                    messages.info(
                        request,
                        _(u'Badge "{badgetitle}" granted to {email}').format(
                            badgetitle=da.badge, email=email))
                url = reverse('badger.views.staff_tools')
                return HttpResponseRedirect(url)

    return render_to_response('%s/staff_tools.html' % bsettings.TEMPLATE_BASE,
                              dict(grant_form=grant_form),
                              context_instance=RequestContext(request))
def nomination_detail(request, slug, id, format="html"):
    """Show details on a nomination, provide for approval and acceptance"""
    badge = get_object_or_404(Badge, slug=slug)
    nomination = get_object_or_404(Nomination, badge=badge, pk=id)
    if not nomination.allows_detail_by(request.user):
        return HttpResponseForbidden()

    if request.method == "POST":
        action = request.POST.get('action', '')
        if action == 'approve_by':
            nomination.approve_by(request.user)
        elif action == 'accept':
            nomination.accept(request.user)
        elif action == 'reject_by':
            nomination.reject_by(request.user)
        return HttpResponseRedirect(
            reverse('badger.views.nomination_detail', args=(slug, id)))

    return render_to_response('%s/nomination_detail.html' %
                              bsettings.TEMPLATE_BASE,
                              dict(
                                  badge=badge,
                                  nomination=nomination,
                              ),
                              context_instance=RequestContext(request))
Esempio n. 23
0
    def test_delete_award(self):
        """Can delete award"""
        user = self._get_user()
        badge = Badge(creator=user,
                      title="Test III",
                      description="Another test")
        badge.save()

        award = badge.award_to(user)

        self.client.login(username="******", password="******")

        r = self.client.get(reverse('badger.views.award_detail',
                                    args=(badge.slug, award.id)),
                            follow=True)
        doc = pq(r.content)

        eq_('award_detail', doc.find('body').attr('id'))
        delete_url = doc.find('a.delete_award').attr('href')
        ok_(delete_url is not None)

        r = self.client.post(delete_url, {}, follow=True)

        try:
            award = Award.objects.get(pk=award.pk)
            ok_(False)
        except Award.DoesNotExist:
            ok_(True)
Esempio n. 24
0
def award_badge(request, slug):
    """Issue an award for a badge"""
    badge = get_object_or_404(Badge, slug=slug)
    if not badge.allows_award_to(request.user):
        return HttpResponseForbidden('Award forbidden')

    if request.method != "POST":
        form = BadgeAwardForm()
    else:
        form = BadgeAwardForm(request.POST, request.FILES)
        if form.is_valid():
            emails = form.cleaned_data['emails']
            description = form.cleaned_data['description']
            for email in emails:
                result = badge.award_to(email=email, awarder=request.user,
                                        description=description)
                if result:
                    if not hasattr(result, 'claim_code'):
                        messages.info(request, _(u'Award issued to {email}').format(
                            email=email))
                    else:
                        messages.info(request, _(
                            u'Invitation to claim award sent to {email}').format(email=email))
            return HttpResponseRedirect(reverse('badger.views.detail',
                                                args=(badge.slug,)))

    return render_to_response('%s/badge_award.html' % bsettings.TEMPLATE_BASE, dict(
        form=form, badge=badge,
    ), context_instance=RequestContext(request))
Esempio n. 25
0
    def test_award_detail(self):
        """Can view award detail"""
        user = self._get_user()
        user2 = self._get_user(username='******')

        b1, created = Badge.objects.get_or_create(
            creator=user,
            title="Code Badge #1",
            description="Some description")
        award = b1.award_to(user2)

        url = reverse('badger.views.award_detail', args=(
            b1.slug,
            award.pk,
        ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        eq_('award_detail', doc.find('body').attr('id'))
        eq_(
            1,
            doc.find('.award .awarded_to .username:contains("%s")' %
                     user2.username).length)
        eq_(1, doc.find('.badge-title:contains("%s")' % b1.title).length)

        # Now, take a look at the JSON format
        url = reverse('badger.award_detail_json', args=(
            b1.slug,
            award.pk,
        ))
        r = self.client.get(url, follow=True)

        data = json.loads(r.content)

        hash_salt = (hashlib.md5('%s-%s' %
                                 (award.badge.pk, award.pk)).hexdigest())
        recipient_text = '%s%s' % (award.user.email, hash_salt)
        recipient_hash = ('sha256$%s' %
                          hashlib.sha256(recipient_text).hexdigest())

        eq_(recipient_hash, data['recipient'])
        eq_('http://testserver%s' % award.get_absolute_url(), data['evidence'])
        eq_(award.badge.title, data['badge']['name'])
        eq_(award.badge.description, data['badge']['description'])
        eq_('http://testserver%s' % award.badge.get_absolute_url(),
            data['badge']['criteria'])
Esempio n. 26
0
    def test_create(self):
        """Can create badge with form"""
        # Login should be required
        r = self.client.get(reverse("badger.views.create"))
        eq_(302, r.status_code)
        ok_("/accounts/login" in r["Location"])

        # Should be fine after login
        settings.BADGER_ALLOW_ADD_BY_ANYONE = True
        self.client.login(username="******", password="******")
        r = self.client.get(reverse("badger.views.create"))
        eq_(200, r.status_code)

        # Make a chick check for expected form elements
        doc = pq(r.content)

        form = doc("form#create_badge")
        eq_(1, form.length)

        eq_(1, form.find("input[name=title]").length)
        eq_(1, form.find("textarea[name=description]").length)
        # For styling purposes, we'll allow either an input or button element
        eq_(1, form.find("input.submit,button.submit").length)

        r = self.client.post(reverse("badger.views.create"), dict(), follow=True)
        doc = pq(r.content)
        eq_(1, doc.find("form .error > input[name=title]").length)

        badge_title = "Test badge #1"
        badge_desc = "This is a test badge"

        r = self.client.post(
            reverse("badger.views.create"), dict(title=badge_title, description=badge_desc), follow=True
        )
        doc = pq(r.content)

        eq_("badge_detail", doc.find("body").attr("id"))
        ok_(badge_title in doc.find(".badge-title").text())
        eq_(badge_desc, doc.find(".badge .description").text())

        slug = doc.find(".badge").attr("data-slug")

        badge = Badge.objects.get(slug=slug)
        eq_(badge_title, badge.title)
        eq_(badge_desc, badge.description)
    def bake_obi_image(self, request=None):
        """Bake the OBI JSON badge award assertion into a copy of the original
        badge's image, if one exists."""

        if request:
            base_url = request.build_absolute_uri('/')
        else:
            base_url = 'http://%s' % (Site.objects.get_current().domain, )

        if self.badge.image:
            # Make a duplicate of the badge image
            self.badge.image.open()
            img_copy_fh = StringIO(self.badge.image.file.read())
        else:
            # Make a copy of the default badge image
            img_copy_fh = StringIO(open(DEFAULT_BADGE_IMAGE, 'rb').read())

        try:
            # Try processing the image copy, bail if the image is bad.
            img = Image.open(img_copy_fh)
        except IOError:
            return False

        # Here's where the baking gets done. JSON representation of the OBI
        # assertion gets written into the "openbadges" metadata field
        # see: http://blog.client9.com/2007/08/python-pil-and-png-metadata-take-2.html
        # see: https://github.com/mozilla/openbadges/blob/development/lib/baker.js
        # see: https://github.com/mozilla/openbadges/blob/development/controllers/baker.js
        try:
            from PIL import PngImagePlugin
        except ImportError:
            import PngImagePlugin
        meta = PngImagePlugin.PngInfo()

        # TODO: Will need this, if we stop doing hosted assertions
        # assertion = self.as_obi_assertion(request)
        # meta.add_text('openbadges', json.dumps(assertion))
        hosted_assertion_url = '%s%s' % (base_url,
                                         reverse(
                                             'badger.award_detail_json',
                                             args=(self.badge.slug, self.id)))
        meta.add_text('openbadges', hosted_assertion_url)

        # And, finally save out the baked image.
        new_img = StringIO()
        img.save(new_img, "PNG", pnginfo=meta)
        img_data = new_img.getvalue()
        name_before = self.image.name
        self.image.save('', ContentFile(img_data), False)
        if (self.image.storage.exists(name_before)):
            self.image.storage.delete(name_before)

        # Update the image field with the new image name
        # NOTE: Can't do a full save(), because this gets called in save()
        Award.objects.filter(pk=self.pk).update(image=self.image)

        return True
Esempio n. 28
0
def _do_claim(request, deferred_award):
    """Perform claim of a deferred award"""
    if not deferred_award.allows_claim_by(request.user):
        return HttpResponseForbidden('Claim denied')
    award = deferred_award.claim(request.user)
    if award:
        url = reverse('badger.views.award_detail',
                      args=(award.badge.slug, award.id,))
        return HttpResponseRedirect(url)
Esempio n. 29
0
    def bake_obi_image(self, request=None):
        """Bake the OBI JSON badge award assertion into a copy of the original
        badge's image, if one exists."""

        if request:
            base_url = request.build_absolute_uri('/')
        else:
            base_url = 'http://%s' % (Site.objects.get_current().domain,)

        if self.badge.image:
            # Make a duplicate of the badge image
            self.badge.image.open()
            img_copy_fh = StringIO(self.badge.image.file.read())
        else:
            # Make a copy of the default badge image
            img_copy_fh = StringIO(open(DEFAULT_BADGE_IMAGE, 'rb').read())

        try:
            # Try processing the image copy, bail if the image is bad.
            img = Image.open(img_copy_fh)
        except IOError:
            return False

        # Here's where the baking gets done. JSON representation of the OBI
        # assertion gets written into the "openbadges" metadata field
        # see: http://blog.client9.com/2007/08/python-pil-and-png-metadata-take-2.html
        # see: https://github.com/mozilla/openbadges/blob/development/lib/baker.js
        # see: https://github.com/mozilla/openbadges/blob/development/controllers/baker.js
        try:
            from PIL import PngImagePlugin
        except ImportError:
            import PngImagePlugin
        meta = PngImagePlugin.PngInfo()

        # TODO: Will need this, if we stop doing hosted assertions
        # assertion = self.as_obi_assertion(request)
        # meta.add_text('openbadges', json.dumps(assertion))
        hosted_assertion_url = '%s%s' % (
            base_url, reverse('badger.award_detail_json',
                              args=(self.badge.slug, self.id)))
        meta.add_text('openbadges', hosted_assertion_url)

        # And, finally save out the baked image.
        new_img = StringIO()
        img.save(new_img, "PNG", pnginfo=meta)
        img_data = new_img.getvalue()
        name_before = self.image.name
        self.image.save('', ContentFile(img_data), False)
        if (self.image.storage.exists(name_before)):
            self.image.storage.delete(name_before)

        # Update the image field with the new image name
        # NOTE: Can't do a full save(), because this gets called in save()
        Award.objects.filter(pk=self.pk).update(image=self.image)

        return True
def claim_deferred_award(request, claim_code=None):
    """Deferred award detail view"""
    if not claim_code:
        claim_code = request.REQUEST.get('code', '').strip()

    # Look for any awards that match this claim code.
    awards = Award.objects.filter(claim_code=claim_code)
    awards_ct = awards.count()

    # Try fetching a DeferredAward matching the claim code. If none found, then
    # make one last effort to redirect a POST to awards. Otherwise, 404
    try:
        deferred_award = DeferredAward.objects.get(claim_code=claim_code)

        # If this is a GET and there are awards matching the claim code,
        # redirect to the awards.
        if (request.method == "GET" and awards_ct > 0
                and not deferred_award.reusable):
            return _redirect_to_claimed_awards(awards, awards_ct)

    except DeferredAward.DoesNotExist:
        if awards_ct > 0:
            return _redirect_to_claimed_awards(awards, awards_ct)
        else:
            raise Http404('No such claim code, %s' % claim_code)

    if not deferred_award.allows_detail_by(request.user):
        return HttpResponseForbidden('Claim detail denied')

    if request.method != "POST":
        grant_form = DeferredAwardGrantForm()
    else:
        grant_form = DeferredAwardGrantForm(request.POST, request.FILES)
        if not request.POST.get('is_grant', False) is not False:
            return _do_claim(request, deferred_award)
        else:
            if not deferred_award.allows_grant_by(request.user):
                return HttpResponseForbidden('Grant denied')
            if grant_form.is_valid():
                email = request.POST.get('email', None)
                deferred_award.grant_to(email=email, granter=request.user)
                messages.info(
                    request,
                    _(u'Award claim granted to {email}').format(email=email))
                url = reverse('badger.views.detail',
                              args=(deferred_award.badge.slug, ))
                return HttpResponseRedirect(url)

    return render_to_response('%s/claim_deferred_award.html' %
                              bsettings.TEMPLATE_BASE,
                              dict(badge=deferred_award.badge,
                                   deferred_award=deferred_award,
                                   grant_form=grant_form),
                              context_instance=RequestContext(request))
def _do_claim(request, deferred_award):
    """Perform claim of a deferred award"""
    if not deferred_award.allows_claim_by(request.user):
        return HttpResponseForbidden('Claim denied')
    award = deferred_award.claim(request.user)
    if award:
        url = reverse('badger.views.award_detail',
                      args=(
                          award.badge.slug,
                          award.id,
                      ))
        return HttpResponseRedirect(url)
Esempio n. 32
0
    def test_badge_detail(self):
        """Can view badge detail"""
        user = self._get_user()
        badge = Badge(creator=user, title="Test II", description="Another test")
        badge.save()

        r = self.client.get(reverse("badger.views.detail", args=(badge.slug,)), follow=True)
        doc = pq(r.content)

        eq_("badge_detail", doc.find("body").attr("id"))
        eq_(1, doc.find('.badge-title:contains("%s")' % badge.title).length)
        eq_(badge.description, doc.find(".badge .description").text())

        # Now, take a look at the JSON format
        url = reverse("badger.detail_json", args=(badge.slug,))
        r = self.client.get(url, follow=True)

        data = json.loads(r.content)
        eq_(badge.title, data["name"])
        eq_(badge.description, data["description"])
        eq_("http://testserver%s" % badge.get_absolute_url(), data["criteria"])
def detail(request, slug, format="html"):
    """Badge detail view"""
    badge = get_object_or_404(Badge, slug=slug)
    if not badge.allows_detail_by(request.user):
        return HttpResponseForbidden('Detail forbidden')

    awards = (Award.objects.filter(
        badge=badge).order_by('-created'))[:bsettings.MAX_RECENT]

    # FIXME: This is awkward. It used to collect sections as responses to a
    # signal sent out to badger_multiplayer and hypothetical future expansions
    # to badger
    sections = dict()
    sections['award'] = dict(form=BadgeAwardForm())
    if badge.allows_nominate_for(request.user):
        sections['nominate'] = dict(form=BadgeSubmitNominationForm())

    if request.method == "POST":

        if request.POST.get('is_generate', None):
            if not badge.allows_manage_deferred_awards_by(request.user):
                return HttpResponseForbidden('Claim generate denied')
            amount = int(request.POST.get('amount', 10))
            reusable = (amount == 1)
            cg = badge.generate_deferred_awards(user=request.user,
                                                amount=amount,
                                                reusable=reusable)

        if request.POST.get('is_delete', None):
            if not badge.allows_manage_deferred_awards_by(request.user):
                return HttpResponseForbidden('Claim delete denied')
            group = request.POST.get('claim_group')
            badge.delete_claim_group(request.user, group)

        url = reverse('badger.views.detail', kwargs=dict(slug=slug))
        return HttpResponseRedirect(url)

    claim_groups = badge.claim_groups

    if format == 'json':
        data = badge.as_obi_serialization(request)
        resp = HttpResponse(json.dumps(data))
        resp['Content-Type'] = 'application/json'
        return resp
    else:
        return render_to_response('%s/badge_detail.html' %
                                  bsettings.TEMPLATE_BASE,
                                  dict(badge=badge,
                                       award_list=awards,
                                       sections=sections,
                                       claim_groups=claim_groups),
                                  context_instance=RequestContext(request))
Esempio n. 34
0
def claim_deferred_award(request, claim_code=None):
    """Deferred award detail view"""
    if not claim_code:
        claim_code = request.REQUEST.get('code', '').strip()

    # Look for any awards that match this claim code.
    awards = Award.objects.filter(claim_code=claim_code)
    awards_ct = awards.count()

    # Try fetching a DeferredAward matching the claim code. If none found, then
    # make one last effort to redirect a POST to awards. Otherwise, 404
    try:
        deferred_award = DeferredAward.objects.get(claim_code=claim_code)

        # If this is a GET and there are awards matching the claim code,
        # redirect to the awards.
        if (request.method == "GET" and awards_ct > 0 and
                not deferred_award.reusable):
            return _redirect_to_claimed_awards(awards, awards_ct)

    except DeferredAward.DoesNotExist:
        if awards_ct > 0:
            return _redirect_to_claimed_awards(awards, awards_ct)
        else:
            raise Http404('No such claim code, %s' % claim_code)

    if not deferred_award.allows_detail_by(request.user):
        return HttpResponseForbidden('Claim detail denied')

    if request.method != "POST":
        grant_form = DeferredAwardGrantForm()
    else:
        grant_form = DeferredAwardGrantForm(request.POST, request.FILES)
        if not request.POST.get('is_grant', False) is not False:
            return _do_claim(request, deferred_award)
        else:
            if not deferred_award.allows_grant_by(request.user):
                return HttpResponseForbidden('Grant denied')
            if grant_form.is_valid():
                email = request.POST.get('email', None)
                deferred_award.grant_to(email=email, granter=request.user)
                messages.info(request, _(u'Award claim granted to {email}').format(
                    email=email))
                url = reverse('badger.views.detail',
                              args=(deferred_award.badge.slug,))
                return HttpResponseRedirect(url)

    return render_to_response('%s/claim_deferred_award.html' % bsettings.TEMPLATE_BASE, dict(
        badge=deferred_award.badge, deferred_award=deferred_award,
        grant_form=grant_form
    ), context_instance=RequestContext(request))
Esempio n. 35
0
def detail(request, slug, format="html"):
    """Badge detail view"""
    badge = get_object_or_404(Badge, slug=slug)
    if not badge.allows_detail_by(request.user):
        return HttpResponseForbidden('Detail forbidden')

    awards = (Award.objects.filter(badge=badge)
                           .order_by('-created'))[:bsettings.MAX_RECENT]

    # FIXME: This is awkward. It used to collect sections as responses to a
    # signal sent out to badger_multiplayer and hypothetical future expansions
    # to badger
    sections = dict()
    sections['award'] = dict(form=BadgeAwardForm())
    if badge.allows_nominate_for(request.user):
        sections['nominate'] = dict(form=BadgeSubmitNominationForm())

    if request.method == "POST":

        if request.POST.get('is_generate', None):
            if not badge.allows_manage_deferred_awards_by(request.user):
                return HttpResponseForbidden('Claim generate denied')
            amount = int(request.POST.get('amount', 10))
            reusable = (amount == 1)
            cg = badge.generate_deferred_awards(user=request.user,
                                                amount=amount,
                                                reusable=reusable)

        if request.POST.get('is_delete', None):
            if not badge.allows_manage_deferred_awards_by(request.user):
                return HttpResponseForbidden('Claim delete denied')
            group = request.POST.get('claim_group')
            badge.delete_claim_group(request.user, group)

        url = reverse('badger.views.detail', kwargs=dict(slug=slug))
        return HttpResponseRedirect(url)

    claim_groups = badge.claim_groups

    if format == 'json':
        data = badge.as_obi_serialization(request)
        resp = HttpResponse(json.dumps(data))
        resp['Content-Type'] = 'application/json'
        return resp
    else:
        return render_to_response('%s/badge_detail.html' % bsettings.TEMPLATE_BASE, dict(
            badge=badge, award_list=awards, sections=sections,
            claim_groups=claim_groups
        ), context_instance=RequestContext(request))
def nominate_for(request, slug):
    """Submit nomination for a badge"""
    badge = get_object_or_404(Badge, slug=slug)
    if not badge.allows_nominate_for(request.user):
        return HttpResponseForbidden()

    if request.method != "POST":
        form = BadgeSubmitNominationForm()
    else:
        form = BadgeSubmitNominationForm(request.POST, request.FILES)
        if form.is_valid():
            emails = form.cleaned_data['emails']
            for email in emails:
                users = User.objects.filter(email=email)
                if not users:
                    # TODO: Need a deferred nomination mechanism for
                    # non-registered users.
                    pass
                else:
                    nominee = users[0]
                    try:
                        award = badge.nominate_for(nominee, request.user)
                        messages.info(
                            request,
                            _(u'Nomination submitted for {email}').format(
                                email=email))
                    except BadgeAlreadyAwardedException:
                        messages.info(
                            request,
                            _(u'Badge already awarded to {email}').format(
                                email=email))
                    except Exception:
                        messages.info(
                            request,
                            _(u'Nomination failed for {email}').format(
                                email=email))

            return HttpResponseRedirect(
                reverse('badger.views.detail', args=(badge.slug, )))

    return render_to_response('%s/badge_nominate_for.html' %
                              bsettings.TEMPLATE_BASE,
                              dict(
                                  form=form,
                                  badge=badge,
                              ),
                              context_instance=RequestContext(request))
Esempio n. 37
0
def award_delete(request, slug, id):
    """Delete an award"""
    badge = get_object_or_404(Badge, slug=slug)
    award = get_object_or_404(Award, badge=badge, pk=id)
    if not award.allows_delete_by(request.user):
        return HttpResponseForbidden('Award delete forbidden')

    if request.method == "POST":
        messages.info(request, _(u'Award for badge "{badgetitle}" deleted.').format(
            badgetitle=badge.title))
        award.delete()
        url = reverse('badger.views.detail', kwargs=dict(slug=slug))
        return HttpResponseRedirect(url)

    return render_to_response('%s/award_delete.html' % bsettings.TEMPLATE_BASE, dict(
        badge=badge, award=award
    ), context_instance=RequestContext(request))
Esempio n. 38
0
def delete(request, slug):
    """Delete a badge"""
    badge = get_object_or_404(Badge, slug=slug)
    if not badge.allows_delete_by(request.user):
        return HttpResponseForbidden()

    awards_count = badge.award_set.count()

    if request.method == "POST":
        messages.info(request, _(u'Badge "{badgetitle}" deleted.').format(
            badgetitle=badge.title))
        badge.delete()
        return HttpResponseRedirect(reverse('badger.views.badges_list'))

    return render_to_response('%s/badge_delete.html' % bsettings.TEMPLATE_BASE, dict(
        badge=badge, awards_count=awards_count,
    ), context_instance=RequestContext(request))
Esempio n. 39
0
    def test_issue_award(self):
        """Badge creator can issue award to another user"""
        SAMPLE_DESCRIPTION = u'This is a sample description'

        user1 = self._get_user(username="******", email="*****@*****.**")
        user2 = self._get_user(username="******", email="*****@*****.**")

        b1 = Badge.objects.create(creator=user1, title="Badge to awarded")

        url = reverse('badger.views.award_badge', args=(b1.slug, ))

        # Non-creator should be denied attempt to award badge
        self.client.login(username="******", password="******")
        r = self.client.get(url, follow=True)
        eq_(403, r.status_code)

        # But, the creator should be allowed
        self.client.login(username="******", password="******")
        r = self.client.get(url, follow=True)
        eq_(200, r.status_code)

        doc = pq(r.content)
        form = doc('form#award_badge')
        eq_(1, form.length)
        eq_(1, form.find('*[name=emails]').length)
        eq_(1, form.find('*[name=description]').length)
        eq_(1, form.find('input.submit,button.submit').length)

        r = self.client.post(url,
                             dict(emails=user2.email,
                                  description=SAMPLE_DESCRIPTION),
                             follow=False)

        ok_('award' in r['Location'])

        ok_(b1.is_awarded_to(user2))

        award = Award.objects.filter(user=user2, badge=b1)[0]
        eq_(SAMPLE_DESCRIPTION, award.description)

        r = self.client.get(award.get_absolute_url(), follow=True)
        eq_(200, r.status_code)

        doc = pq(r.content)
        eq_(SAMPLE_DESCRIPTION, doc.find('.award .description').text())
Esempio n. 40
0
    def test_edit_preserves_creator(self):
        """Edit preserves the original creator of the badge (bugfix)"""
        orig_user = self._get_user(username="******")
        badge = Badge(creator=orig_user, title="Test 3", description="Another test")
        badge.save()

        edit_user = self._get_user(username="******")
        edit_user.is_superuser = True
        edit_user.save()

        self.client.login(username="******", password="******")
        edit_url = reverse("badger.views.edit", args=(badge.slug,))
        r = self.client.post(edit_url, dict(title="New Title"), follow=True)
        doc = pq(r.content)

        # The badge's creator should not have changed to the editing user.
        badge_after = Badge.objects.get(pk=badge.pk)
        ok_(badge_after.creator.pk != edit_user.pk)
Esempio n. 41
0
    def test_disallowed_badge_award(self):
        """User should not be able to POST an award to a badge for which the
        user hasn't got permission to do so"""
        user = self._get_user(username="******",
                              email="*****@*****.**")
        badge = Badge(creator=user, title="Hey you badge",
                      description="Another test", unique=True)
        badge.save()

        awards_url = reverse('badger.views.awards_list',
                             args=(self.badge.slug,))

        data = dict(emails=['*****@*****.**',])

        resp = self.client.post(awards_url, json.dumps(data),
                                content_type='application/json',
                                HTTP_AUTHORIZATION=self.basic_auth)

        ok_(403, resp.status_code)
Esempio n. 42
0
    def test_awards_list(self):
        """Can view awards by badge"""
        user = self._get_user()
        b1 = Badge.objects.create(creator=user, title="Code Badge #1")

        u1 = self._get_user(username="******")
        u2 = self._get_user(username="******")
        u3 = self._get_user(username="******")

        for u in (u1, u2, u3):
            b1.award_to(u)

        url = reverse("badger.views.awards_list", args=(b1.slug,))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        eq_(3, doc.find(".award").length)
        for u in (u1, u2, u3):
            eq_(1, doc.find('.award .user:contains("%s")' % u.username).length)
Esempio n. 43
0
    def test_awards_by_badge(self):
        """Can view awards by badge"""
        user = self._get_user()
        b1 = Badge.objects.create(creator=user, title="Code Badge #1")

        u1 = self._get_user(username='******')
        u2 = self._get_user(username='******')
        u3 = self._get_user(username='******')

        for u in (u1, u2, u3):
            b1.award_to(u)

        url = reverse('badger.views.awards_by_badge', args=(b1.slug, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        eq_(3, doc.find('.award').length)
        for u in (u1, u2, u3):
            eq_(1, doc.find('.award .user:contains("%s")' % u.username).length)
Esempio n. 44
0
    def test_edit(self):
        """Can edit badge detail"""
        user = self._get_user()
        badge = Badge(creator=user,
                      title="Test II",
                      description="Another test")
        badge.save()

        self.client.login(username="******", password="******")

        r = self.client.get(reverse('badger.views.detail',
                                    args=(badge.slug, )),
                            follow=True)
        doc = pq(r.content)

        eq_('badge_detail', doc.find('body').attr('id'))
        edit_url = doc.find('a.edit_badge').attr('href')
        ok_(edit_url is not None)

        r = self.client.get(edit_url)
        doc = pq(r.content)
        eq_('badge_edit', doc.find('body').attr('id'))

        badge_title = "Edited title"
        badge_desc = "Edited description"

        r = self.client.post(edit_url,
                             dict(
                                 title=badge_title,
                                 description=badge_desc,
                             ),
                             follow=True)
        doc = pq(r.content)

        eq_('badge_detail', doc.find('body').attr('id'))
        ok_(badge_title in doc.find('.badge-title').text())
        eq_(badge_desc, doc.find('.badge .description').text())

        slug = doc.find('.badge').attr('data-slug')

        badge = Badge.objects.get(slug=slug)
        eq_(badge_title, badge.title)
        eq_(badge_desc, badge.description)
def award_delete(request, slug, id):
    """Delete an award"""
    badge = get_object_or_404(Badge, slug=slug)
    award = get_object_or_404(Award, badge=badge, pk=id)
    if not award.allows_delete_by(request.user):
        return HttpResponseForbidden('Award delete forbidden')

    if request.method == "POST":
        messages.info(
            request,
            _(u'Award for badge "{badgetitle}" deleted.').format(
                badgetitle=badge.title))
        award.delete()
        url = reverse('badger.views.detail', kwargs=dict(slug=slug))
        return HttpResponseRedirect(url)

    return render_to_response('%s/award_delete.html' % bsettings.TEMPLATE_BASE,
                              dict(badge=badge, award=award),
                              context_instance=RequestContext(request))
Esempio n. 46
0
    def test_issue_award(self):
        """Badge creator can issue award to another user"""
        SAMPLE_DESCRIPTION = u"This is a sample description"

        user1 = self._get_user(username="******", email="*****@*****.**")
        user2 = self._get_user(username="******", email="*****@*****.**")

        b1 = Badge.objects.create(creator=user1, title="Badge to awarded")

        url = reverse("badger.views.award_badge", args=(b1.slug,))

        # Non-creator should be denied attempt to award badge
        self.client.login(username="******", password="******")
        r = self.client.get(url, follow=True)
        eq_(403, r.status_code)

        # But, the creator should be allowed
        self.client.login(username="******", password="******")
        r = self.client.get(url, follow=True)
        eq_(200, r.status_code)

        doc = pq(r.content)
        form = doc("form#award_badge")
        eq_(1, form.length)
        eq_(1, form.find("*[name=emails]").length)
        eq_(1, form.find("*[name=description]").length)
        eq_(1, form.find("input.submit,button.submit").length)

        r = self.client.post(url, dict(emails=user2.email, description=SAMPLE_DESCRIPTION), follow=False)

        ok_("award" in r["Location"])

        ok_(b1.is_awarded_to(user2))

        award = Award.objects.filter(user=user2, badge=b1)[0]
        eq_(SAMPLE_DESCRIPTION, award.description)

        r = self.client.get(award.get_absolute_url(), follow=True)
        eq_(200, r.status_code)

        doc = pq(r.content)
        eq_(SAMPLE_DESCRIPTION, doc.find(".award .description").text())
Esempio n. 47
0
def edit(request, slug):
    """Edit an existing badge"""
    badge = get_object_or_404(Badge, slug=slug)
    if not badge.allows_edit_by(request.user):
        return HttpResponseForbidden()

    if request.method != "POST":
        form = BadgeEditForm(instance=badge)
    else:
        form = BadgeEditForm(request.POST, request.FILES, instance=badge)
        if form.is_valid():
            new_sub = form.save(commit=False)
            new_sub.save()
            form.save_m2m()
            return HttpResponseRedirect(reverse(
                    'badger.views.detail', args=(new_sub.slug,)))

    return render_to_response('%s/badge_edit.html' % bsettings.TEMPLATE_BASE, dict(
        badge=badge, form=form,
    ), context_instance=RequestContext(request))
Esempio n. 48
0
    def test_edit_preserves_creator(self):
        """Edit preserves the original creator of the badge (bugfix)"""
        orig_user = self._get_user(username='******')
        badge = Badge(creator=orig_user,
                      title="Test 3",
                      description="Another test")
        badge.save()

        edit_user = self._get_user(username='******')
        edit_user.is_superuser = True
        edit_user.save()

        self.client.login(username="******", password="******")
        edit_url = reverse('badger.views.edit', args=(badge.slug, ))
        r = self.client.post(edit_url, dict(title='New Title', ), follow=True)
        doc = pq(r.content)

        # The badge's creator should not have changed to the editing user.
        badge_after = Badge.objects.get(pk=badge.pk)
        ok_(badge_after.creator.pk != edit_user.pk)
def delete(request, slug):
    """Delete a badge"""
    badge = get_object_or_404(Badge, slug=slug)
    if not badge.allows_delete_by(request.user):
        return HttpResponseForbidden()

    awards_count = badge.award_set.count()

    if request.method == "POST":
        messages.info(
            request,
            _(u'Badge "{badgetitle}" deleted.').format(badgetitle=badge.title))
        badge.delete()
        return HttpResponseRedirect(reverse('badger.views.badges_list'))

    return render_to_response('%s/badge_delete.html' % bsettings.TEMPLATE_BASE,
                              dict(
                                  badge=badge,
                                  awards_count=awards_count,
                              ),
                              context_instance=RequestContext(request))
Esempio n. 50
0
def create(request):
    """Create a new badge"""
    if not Badge.objects.allows_add_by(request.user):
        return HttpResponseForbidden()

    if request.method != "POST":
        form = BadgeNewForm()
        form.initial['tags'] = request.GET.get('tags', '')
    else:
        form = BadgeNewForm(request.POST, request.FILES)
        if form.is_valid():
            new_sub = form.save(commit=False)
            new_sub.creator = request.user
            new_sub.save()
            form.save_m2m()
            return HttpResponseRedirect(reverse(
                    'badger.views.detail', args=(new_sub.slug,)))

    return render_to_response('%s/badge_create.html' % bsettings.TEMPLATE_BASE, dict(
        form=form,
    ), context_instance=RequestContext(request))
Esempio n. 51
0
    def test_awards_by_user(self):
        """Can view awards by user"""
        user = self._get_user()
        user2 = self._get_user(username="******")

        b1, created = Badge.objects.get_or_create(creator=user, title="Code Badge #1")
        b2, created = Badge.objects.get_or_create(creator=user, title="Code Badge #2")
        b3, created = Badge.objects.get_or_create(creator=user, title="Code Badge #3")

        b1.award_to(user2)
        award_badge(b2.slug, user2)
        Award.objects.create(badge=b3, user=user2)

        url = reverse("badger.views.awards_by_user", args=(user2.username,))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        eq_("badge_awards_by_user", doc.find("body").attr("id"))
        eq_(3, doc.find(".badge").length)
        for b in (b1, b2, b3):
            eq_(1, doc.find('.badge .title:contains("%s")' % b.title).length)
def create(request):
    """Create a new badge"""
    if not Badge.objects.allows_add_by(request.user):
        return HttpResponseForbidden()

    if request.method != "POST":
        form = BadgeNewForm()
        form.initial['tags'] = request.GET.get('tags', '')
    else:
        form = BadgeNewForm(request.POST, request.FILES)
        if form.is_valid():
            new_sub = form.save(commit=False)
            new_sub.creator = request.user
            new_sub.save()
            form.save_m2m()
            return HttpResponseRedirect(
                reverse('badger.views.detail', args=(new_sub.slug, )))

    return render_to_response('%s/badge_create.html' % bsettings.TEMPLATE_BASE,
                              dict(form=form, ),
                              context_instance=RequestContext(request))
Esempio n. 53
0
    def test_issue_multiple_awards(self):
        """Multiple emails can be submitted at once to issue awards"""
        # Build creator user and badge
        creator = self._get_user(username="******",
                                 email="*****@*****.**")
        b1 = Badge.objects.create(creator=creator, title="Badge to defer")

        # Build future awardees
        user1 = self._get_user(username="******", email="*****@*****.**")
        user2 = self._get_user(username="******", email="*****@*****.**")
        user3 = self._get_user(username="******", email="*****@*****.**")
        user4_email = '*****@*****.**'

        # Login as the badge creator, prepare to award...
        self.client.login(username="******", password="******")
        url = reverse('badger.views.award_badge', args=(b1.slug, ))
        r = self.client.get(url, follow=True)
        eq_(200, r.status_code)

        # Make sure the expected parts appear in the form.
        doc = pq(r.content)
        form = doc('form#award_badge')
        eq_(1, form.length)
        eq_(1, form.find('*[name=emails]').length)
        eq_(1, form.find('input.submit,button.submit').length)

        # Post a list of emails with a variety of separators.
        r = self.client.post(
            url,
            dict(emails=(
                "%s,%s\n%s %s" %
                (user1.email, user2.email, user3.email, user4_email)), ),
            follow=False)

        # Ensure that the known users received awards and the unknown user got
        # a deferred award.
        ok_(b1.is_awarded_to(user1))
        ok_(b1.is_awarded_to(user2))
        ok_(b1.is_awarded_to(user3))
        eq_(1, DeferredAward.objects.filter(email=user4_email).count())
Esempio n. 54
0
def nomination_detail(request, slug, id, format="html"):
    """Show details on a nomination, provide for approval and acceptance"""
    badge = get_object_or_404(Badge, slug=slug)
    nomination = get_object_or_404(Nomination, badge=badge, pk=id)
    if not nomination.allows_detail_by(request.user):
        return HttpResponseForbidden()

    if request.method == "POST":
        action = request.POST.get('action', '')
        if action == 'approve_by':
            nomination.approve_by(request.user)
        elif action == 'accept':
            nomination.accept(request.user)
        elif action == 'reject_by':
            nomination.reject_by(request.user)
        return HttpResponseRedirect(reverse(
                'badger.views.nomination_detail',
                args=(slug, id)))

    return render_to_response('%s/nomination_detail.html' % bsettings.TEMPLATE_BASE,
                              dict(badge=badge, nomination=nomination,),
                              context_instance=RequestContext(request))
Esempio n. 55
0
    def test_claim_code_shows_awards_after_claim(self):
        """Claim code URL should lead to award detail or list after claim"""
        user1 = self._get_user(username="******", email="*****@*****.**")
        user2 = self._get_user(username="******", email="*****@*****.**")
        b1 = Badge.objects.create(creator=user1, unique=False, title="Badge for claim viewing")
        da = DeferredAward(badge=b1, creator=user1)
        da.save()

        url = da.get_claim_url()

        # Before claim, code URL leads to claim page.
        r = self.client.get(url, follow=False)
        eq_(200, r.status_code)
        doc = pq(r.content)
        form = doc("form#claim_award")

        # After claim, code URL leads to a single award detail page.
        award = da.claim(user2)
        r = self.client.get(url, follow=False)
        eq_(302, r.status_code)
        award_url = reverse("badger.views.award_detail", args=(award.badge.slug, award.pk))
        ok_(award_url in r["Location"])
    def test_disallowed_badge_award(self):
        """User should not be able to POST an award to a badge for which the
        user hasn't got permission to do so"""
        user = self._get_user(username="******", email="*****@*****.**")
        badge = Badge(creator=user,
                      title="Hey you badge",
                      description="Another test",
                      unique=True)
        badge.save()

        awards_url = reverse('badger.views.awards_list',
                             args=(self.badge.slug, ))

        data = dict(emails=[
            '*****@*****.**',
        ])

        resp = self.client.post(awards_url,
                                json.dumps(data),
                                content_type='application/json',
                                HTTP_AUTHORIZATION=self.basic_auth)

        ok_(403, resp.status_code)
def edit(request, slug):
    """Edit an existing badge"""
    badge = get_object_or_404(Badge, slug=slug)
    if not badge.allows_edit_by(request.user):
        return HttpResponseForbidden()

    if request.method != "POST":
        form = BadgeEditForm(instance=badge)
    else:
        form = BadgeEditForm(request.POST, request.FILES, instance=badge)
        if form.is_valid():
            new_sub = form.save(commit=False)
            new_sub.save()
            form.save_m2m()
            return HttpResponseRedirect(
                reverse('badger.views.detail', args=(new_sub.slug, )))

    return render_to_response('%s/badge_edit.html' % bsettings.TEMPLATE_BASE,
                              dict(
                                  badge=badge,
                                  form=form,
                              ),
                              context_instance=RequestContext(request))
    def test_baked_award_image(self):
        """Award gets image baked with OBI assertion"""
        # Get the source for a sample badge image
        img_data = open(BADGE_IMG_FN, 'r').read()

        # Make a badge with a creator
        user_creator = self._get_user(username="******")
        badge = self._get_badge(title="Badge with Creator",
                                creator=user_creator)
        badge.image.save('', ContentFile(img_data), True)

        # Get some users who can award any badge
        user_1 = self._get_user(username="******",
                                is_superuser=True)
        user_2 = self._get_user(username="******",
                                is_superuser=True)

        # Get some users who can receive badges
        user_awardee_1 = self._get_user(username="******")
        user_awardee_2 = self._get_user(username="******")

        # Try awarding the badge once with baking enabled and once without
        for enabled in (True, False):
            with patch_settings(BADGER_BAKE_AWARD_IMAGES=enabled):
                award_1 = badge.award_to(awardee=user_awardee_1)
                if not enabled:
                    ok_(not award_1.image)
                else:
                    ok_(award_1.image)
                    img = Image.open(award_1.image.file)
                    hosted_assertion_url = img.info['openbadges']
                    expected_url = '%s%s' % (
                        BASE_URL, reverse('badger.award_detail_json',
                                          args=(award_1.badge.slug,
                                                award_1.id)))
                    eq_(expected_url, hosted_assertion_url)
                award_1.delete()
Esempio n. 59
0
def nominate_for(request, slug):
    """Submit nomination for a badge"""
    badge = get_object_or_404(Badge, slug=slug)
    if not badge.allows_nominate_for(request.user):
        return HttpResponseForbidden()

    if request.method != "POST":
        form = BadgeSubmitNominationForm()
    else:
        form = BadgeSubmitNominationForm(request.POST, request.FILES)
        if form.is_valid():
            emails = form.cleaned_data['emails']
            for email in emails:
                users = User.objects.filter(email=email)
                if not users:
                    # TODO: Need a deferred nomination mechanism for
                    # non-registered users.
                    pass
                else:
                    nominee = users[0]
                    try:
                        award = badge.nominate_for(nominee, request.user)
                        messages.info(request,
                            _(u'Nomination submitted for {email}').format(email=email))
                    except BadgeAlreadyAwardedException:
                        messages.info(request,
                            _(u'Badge already awarded to {email}').format(email=email))
                    except Exception:
                        messages.info(request,
                            _(u'Nomination failed for {email}').format(email=email))

            return HttpResponseRedirect(reverse('badger.views.detail',
                                                args=(badge.slug,)))

    return render_to_response('%s/badge_nominate_for.html' % bsettings.TEMPLATE_BASE,
                              dict(form=form, badge=badge,),
                              context_instance=RequestContext(request))
Esempio n. 60
0
    def setUp(self):
        self.client = Client()

        self.testuser = self._get_user()

        self.badge = Badge(creator=self.testuser, title="Test II",
                           description="Another test", unique=True)
        self.badge.save()

        self.awards_url = reverse('badger.views.awards_list',
                                  args=(self.badge.slug,))
        
        key = Key()
        key.user = self.testuser
        self.password = key.generate_secret()
        self.username = key.key
        key.save()
        self.key = key

        auth_ct = '%s:%s' % (self.username, self.password)
        self.basic_auth = 'Basic %s' % b64encode(auth_ct)
        self.headers = {'HTTP_AUTHORIZATION': self.basic_auth}

        Award.objects.all().delete()