Skip to content
This repository has been archived by the owner on Feb 8, 2018. It is now read-only.

UI to send confirmation email for unclaimed packages #4309

Merged
merged 7 commits into from
Feb 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions gratipay/models/package/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,10 @@ def from_names(cls, package_manager, name):
"""
return cls.db.one("SELECT packages.*::packages FROM packages "
"WHERE package_manager=%s and name=%s", (package_manager, name))


# Emails
# ======

def send_confirmation_email(self, address):
pass
1 change: 0 additions & 1 deletion js/gratipay/emails.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ Gratipay.emails.post = function(e) {
var $this = $(this);
var action = this.className;
var $inputs = $('.emails button, .emails input');
console.log($this);
var address = $this.parent().data('email') || $('input.add-email').val();

$inputs.prop('disabled', true);
Expand Down
29 changes: 29 additions & 0 deletions js/gratipay/packages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
Gratipay.packages = {};

Gratipay.packages.post = function(e) {
e.preventDefault();
var $this = $(this);
var action = 'add-email-and-claim-package';
var package_id = $('input[name=package_id]').val();
var email = $('input[name=email]:checked').val();

var $inputs = $('input, button');
$inputs.prop('disabled', true);

$.ajax({
url: '/~' + Gratipay.username + '/emails/modify.json',
type: 'POST',
data: {action: action, address: email, package_id: package_id},
dataType: 'json',
success: function (msg) {
if (msg) {
Gratipay.notification(msg, 'success');
}
$inputs.prop('disabled', false);
},
error: [
function () { $inputs.prop('disabled', false); },
Gratipay.error
],
});
};
6 changes: 6 additions & 0 deletions scss/components/listing.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
.sorry {
text-align: center;
font: normal 12px/15px $Ideal;
color: $medium-gray;
}

table.listing {
width: 100%;

Expand Down
8 changes: 8 additions & 0 deletions scss/pages/package.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#package {
.emails {
margin: 1em 0;
li {
list-style: none;
}
}
}
6 changes: 0 additions & 6 deletions scss/pages/search.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@
}
}

.sorry {
text-align: center;
font: normal 12px/15px $Ideal;
color: $medium-gray;
}

h2 {
margin-top: 4em;
&:first-of-type {
Expand Down
30 changes: 27 additions & 3 deletions tests/py/test_www_npm_package.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,37 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals

from gratipay.models.package import NPM
from gratipay.testing import Harness


class TestAnon(Harness):
class TestClaimingWorkflow(Harness):

def setUp(self):
self.make_package()

def test_gets_signin_page(self):
assert 'npm/foo</a> has not been claimed' in self.client.GET('/on/npm/foo/').body
def test_anon_gets_signin_page_from_unclaimed(self):
body = self.client.GET('/on/npm/foo/').body
assert 'npm/foo</a> has not been claimed' in body
assert 'with a couple clicks' in body

def test_auth_gets_send_confirmation_page_from_unclaimed(self):
self.make_participant('bob', claimed_time='now')
body = self.client.GET('/on/npm/foo/', auth_as='bob').body
assert 'npm/foo</a> has not been claimed' in body
assert 'using any email address' in body
assert '[email protected]' in body

def test_auth_gets_multiple_options_if_present(self):
self.make_package(NPM, 'bar', 'Bar', ['[email protected]', '[email protected]'])
self.make_participant('bob', claimed_time='now')
body = self.client.GET('/on/npm/bar/', auth_as='bob').body
assert 'using any email address' in body
assert '[email protected]' in body
assert '[email protected]' in body

def test_auth_gets_something_if_no_emails(self):
self.make_package(NPM, 'bar', 'Bar', [])
self.make_participant('bob', claimed_time='now')
body = self.client.GET('/on/npm/bar/', auth_as='bob').body
assert "didn&#39;t find any email addresses" in body
28 changes: 28 additions & 0 deletions tests/ttw/test_package_claiming.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals

from gratipay.testing import BrowserHarness


class TestSendConfirmationLink(BrowserHarness):

def check(self, choice=0):
self.make_participant('bob', claimed_time='now')
self.sign_in('bob')
self.visit('/on/npm/foo/')
self.css('input[type=radio]')[choice].click()
self.css('button')[0].click()
assert self.has_element('.notification.notification-success', 1)
assert self.has_text('Check [email protected] for a confirmation link.')

def test_appears_to_work(self):
self.make_package()
self.check()

def test_works_when_there_are_multiple_addresses(self):
self.make_package(emails=['[email protected]', '[email protected]'])
self.check()

def test_can_send_to_second_email(self):
self.make_package(emails=['[email protected]', '[email protected]'])
self.check(choice=1)
1 change: 1 addition & 0 deletions www/assets/gratipay.css.spt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
@import "scss/pages/history";
@import "scss/pages/identities";
@import "scss/pages/team";
@import "scss/pages/package";
@import "scss/pages/profile-edit";
@import "scss/pages/giving";
@import "scss/pages/settings";
Expand Down
41 changes: 34 additions & 7 deletions www/on/npm/%package/index.html.spt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ package = Package.from_names('npm', package_name)
if package is None:
raise Response(404)
banner = package_name
page_id = "on-npm-foo"
page_id = "package"
suppress_sidebar = True
url = 'https://npmjs.com/package/' + package.name
[---]
Expand All @@ -26,16 +26,43 @@ url = 'https://npmjs.com/package/' + package.name
</a>
{% endblock %}

{% block scripts %}
<script>
$(document).ready(function() {
$('button.send').on('click', Gratipay.packages.post);
});
</script>
{{ super() }}
{% endblock %}

{% block content %}
{% if user.ANON %}
<h2>{{ _( '{npm_package} has not been claimed on Gratipay.'
, npm_package=('<a href="' + url + '">' + 'npm/' + package_name + '</a>')|safe
) }}</h2>
<p>{{ _('Is this yours? You can claim it on Gratipay with a couple clicks:') }}</p>
{% include "templates/sign-in-using.html" %}
{% if user.ANON %}
<p>{{ _('Is this yours? You can claim it on Gratipay with a couple clicks:') }}</p>
{% include "templates/sign-in-using.html" %}

<h2>{{ _("What is Gratipay?") }}</h2>
<p>{{ _("Gratipay helps companies and others pay for open source.") }}
<a href="/about/">{{ _("Learn more") }}</a></p>
<h2>{{ _('What is Gratipay?') }}</h2>
<p>{{ _('Gratipay helps companies and others pay for open source.') }}
<a href="/about/">{{ _("Learn more") }}</a></p>
{% else %}
<p>{{ _( 'Is this yours? You can claim it on Gratipay using any email address {a}on file{_a} in the maintainers field in the npm registry.'
, a=('<a href="https://registry.npmjs.com/' + package.name + '">')|safe
, _a='</a>'|safe
) }}
{% if len(package.emails) == 0 %}
<p class="sorry">{{ _("Sorry, we didn't find any email addresses on file.") }}</p>
{% else %}
<input type="hidden" name="package_id" value="{{ package.id }}">
<ul class="emails">
{% for i, email in enumerate(package.emails) %}
<li><input type="radio" name="email" value="{{ email }}" id="email-{{i}}"
{% if i == 0 %}checked{% endif %}>
<label for="email-{{ i }}">{{ email }}</a></li>
{% endfor %}
</ul>
<button type="submit" class="send selected">{{ _('Send confirmation link') }}</button>
{% endif %}
{% endif %}
{% endblock %}
6 changes: 6 additions & 0 deletions www/~/%username/emails/modify.json.spt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import re
from aspen import Response
from gratipay.exceptions import ProblemChangingEmail
from gratipay.utils import get_participant
from gratipay.models.package import Package

email_re = re.compile(r'^[^@]+@[^@]+\.[^@]+$')

Expand Down Expand Up @@ -36,6 +37,11 @@ elif action == 'set-primary':
participant.update_email(address)
elif action == 'remove':
participant.remove_email(address)
elif action == 'add-email-and-claim-package':
package_id = request.body['package_id']
package = Package.from_id(package_id)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if it's None?

package.send_confirmation_email(address)
msg = _("Check {email} for a confirmation link.", email=address)
else:
raise Response(400, 'unknown action "%s"' % action)

Expand Down