diff --git a/gratipay/homepage.py b/gratipay/homepage.py index deab32e05d..8ea27a3aa6 100644 --- a/gratipay/homepage.py +++ b/gratipay/homepage.py @@ -45,10 +45,10 @@ def _parse(raw): email_address = email_address[:255] errors.append('email_address') - follow_up = x('follow_up') - if follow_up not in ('quarterly', 'yearly', 'never'): - follow_up = 'quarterly' - errors.append('follow_up') + on_mailing_list = x('on_mailing_list') + if on_mailing_list not in ('yes', 'no'): + on_mailing_list = 'yes' + errors.append('on_mailing_list') # promo fields promotion_name = x('promotion_name') @@ -78,7 +78,7 @@ def _parse(raw): , 'grateful_for': grateful_for , 'name': name , 'email_address': email_address - , 'follow_up': follow_up + , 'on_mailing_list': on_mailing_list , 'promotion_name': promotion_name , 'promotion_url': promotion_url , 'promotion_twitter': promotion_twitter diff --git a/gratipay/models/participant/email.py b/gratipay/models/participant/email.py index 029fe337ee..7f6da22007 100644 --- a/gratipay/models/participant/email.py +++ b/gratipay/models/participant/email.py @@ -159,7 +159,7 @@ def get_email_verification_link(self, c, email, *packages): nonce = self.get_email_verification_nonce(c, email) if packages: self.start_package_claims(c, nonce, *packages) - link = "{base_url}/~{username}/emails/verify.html?email2={encoded_email}&nonce={nonce}" + link = "{base_url}/~{username}/emails/verify.html?email={encoded_email}&nonce={nonce}" return link.format( base_url=gratipay.base_url , username=self.username_lower , encoded_email=encode_for_querystring(email) diff --git a/gratipay/models/payment_for_open_source.py b/gratipay/models/payment_for_open_source.py index f6ecc4caa0..0dd1ce41a3 100644 --- a/gratipay/models/payment_for_open_source.py +++ b/gratipay/models/payment_for_open_source.py @@ -38,20 +38,21 @@ def from_uuid(cls, uuid, cursor=None): @classmethod - def insert(cls, amount, grateful_for, name, follow_up, email_address, + def insert(cls, amount, grateful_for, name, on_mailing_list, email_address, promotion_name, promotion_url, promotion_twitter, promotion_message, cursor=None): """Take baseline info and insert into the database. """ uuid = uuid4().hex + on_mailing_list = on_mailing_list == 'yes' return (cursor or cls.db).one(""" INSERT INTO payments_for_open_source - (uuid, amount, grateful_for, name, follow_up, email_address, + (uuid, amount, grateful_for, name, on_mailing_list, email_address, promotion_name, promotion_url, promotion_twitter, promotion_message) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s) RETURNING payments_for_open_source.*::payments_for_open_source - """, (uuid, amount, grateful_for, name, follow_up, email_address, + """, (uuid, amount, grateful_for, name, on_mailing_list, email_address, promotion_name, promotion_url, promotion_twitter, promotion_message)) diff --git a/gratipay/project_review_process.py b/gratipay/project_review_process.py index 756d7d2688..dd0de5c835 100644 --- a/gratipay/project_review_process.py +++ b/gratipay/project_review_process.py @@ -12,6 +12,9 @@ from gratipay.models.participant import Participant +SHIELD = "[![Gratipay](https://img.shields.io/gratipay/project/{}.svg)](https://gratipay.com{})" + + class ProjectReviewProcess(object): def __init__(self, env, db, email_queue): @@ -43,7 +46,11 @@ def start(self, *teams): else: title = "{} and {} other projects".format(teams[0].name, nteams-1) - body = [] + body = [ '*This application will remain open for at least a week.*' + , '' + , '## Project' + ('s' if nteams > 1 else '') + , '' + ] team_ids = [] owner_usernames = set() for team in teams: @@ -51,7 +58,21 @@ def start(self, *teams): owner_usernames.add(team.owner) body.append('https://gratipay.com{}'.format(team.url_path)) assert len(owner_usernames) == 1, owner_usernames - body.extend(['', '(This application will remain open for at least a week.)']) + + shield = SHIELD.format(teams[0].slug, teams[0].url_path) + # let them discover how to adapt for additional projects + body += [ '' + , '## Badge' + , '' + , 'Add a [badge](http://shields.io/) to your README?' + , '' + , shield + , '' + , '```markdown' + , shield + , '```' + ] + data = json.dumps({'title': title, 'body': '\n'.join(body)}) review_url = self._poster.post(data) diff --git a/gratipay/security/__init__.py b/gratipay/security/__init__.py index 304579c0ab..82bf0960eb 100644 --- a/gratipay/security/__init__.py +++ b/gratipay/security/__init__.py @@ -43,6 +43,10 @@ def add_headers_to_response(website, response): if 'X-Content-Type-Options' not in response.headers: response.headers['X-Content-Type-Options'] = 'nosniff' + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security + if 'strict-transport-security' not in response.headers: + response.headers['strict-transport-security'] = 'max-age=31536000' + # https://www.owasp.org/index.php/List_of_useful_HTTP_headers if 'X-XSS-Protection' not in response.headers: response.headers['X-XSS-Protection'] = '1; mode=block' diff --git a/gratipay/testing/harness.py b/gratipay/testing/harness.py index ecd670d61c..99254dd8e5 100644 --- a/gratipay/testing/harness.py +++ b/gratipay/testing/harness.py @@ -148,7 +148,7 @@ def make_payment_for_open_source(self, **info): , grateful_for='open source!' , name='Alice Liddell' , email_address='alice@example.com' - , follow_up='quarterly' + , on_mailing_list=True , promotion_name='Wonderland' , promotion_url='http://www.example.com/' , promotion_twitter='thebestbutter' diff --git a/i18n/core/de.po b/i18n/core/de.po index bb525b6d69..9a0dd9cb8e 100644 --- a/i18n/core/de.po +++ b/i18n/core/de.po @@ -727,8 +727,8 @@ msgstr "" msgid "Eep! Mind looking over your info for us?" msgstr "" -msgid "Pay for open source." -msgstr "Für Open Source bezahlen." +msgid "Invest in open source." +msgstr "" msgid "Payment complete!" msgstr "" @@ -750,7 +750,7 @@ msgstr "" msgid "We weren't able to process your card." msgstr "" -msgid "Thank you for paying for open source!" +msgid "Thank you for investing in open source!" msgstr "" msgid "Email {support}{br}with questions or feedback." @@ -773,20 +773,26 @@ msgstr[0] "" msgstr[1] "" msgid "" -"Open source boosts the productivity of your developers {a}by 20%{_a}. " -"Companies fund half of open source through developer time." +"From {varnish} to {vuejs}, {drf} to {django} itself, {ruby} to {webpack}, " +"there are more and more examples of community-led open source projects " +"funded by enlightened companies." msgstr "" msgid "" -"Gratipay is the easiest way to pay for {a}the other half{_a}. Pay for open " -"source, and {b}strengthen the foundation{_b} that your developers build on. " -"Increase innovation and {b}reduce risk{_b} for your company." +"Inspired by this trend, #BackTheStack is a {b} funding campaign for the " +"whole open source community{_b}. If we all band together, can we encourage " +"even more of the industry to participate? Can we sustain even more of the " +"ecosystem, including parts that are less flashy?" msgstr "" msgid "" -"Gratipay can {b}report back{_b} to you on the progress your payment enables," -" and we can {b}promote{_b} your contribution, increasing your visibility " -"within the open source community." +"Your company's ROI on #BackTheStack will be {b}at least 10x{_b}. Pay $10,000" +" for $100,000 in maintenance and new development. We'll report back on the " +"impact of this shared investment, and we'd be thrilled to promote your " +"company's contribution to it." +msgstr "" + +msgid "Join #BackTheStack and invest in open source today!" msgstr "" msgid "Optional" @@ -822,22 +828,19 @@ msgstr "" msgid "You will get a link to an invoice for your payment." msgstr "" -msgid "Follow-up" -msgstr "" - -msgid "Quarterly" +msgid "Join Mailing List" msgstr "" -msgid "Yearly" -msgstr "" +msgid "Yes" +msgstr "Ja" -msgid "Never" -msgstr "" +msgid "No" +msgstr "Nein" msgid "I am surprised that you are seeing this message." msgstr "" -msgid "You will get a progress report, with a reminder to pay again." +msgid "We send updates related to #BackTheStack." msgstr "" msgid "Promotion" @@ -873,7 +876,7 @@ msgstr "" msgid "Submit Form" msgstr "" -msgid "Pay for Open Source" +msgid "Invest in Open Source" msgstr "" msgid "Processing ..." @@ -1007,12 +1010,6 @@ msgstr "Hinzufügen" msgid "Are you sure?" msgstr "Sind Sie sicher?" -msgid "Yes" -msgstr "Ja" - -msgid "No" -msgstr "Nein" - msgid "Already closed." msgstr "Bereits geschlossen." @@ -1270,21 +1267,30 @@ msgstr "" msgid "Linked to a different account" msgstr "" -msgid "Ready to use" -msgstr "" - msgid "Your primary email address" msgstr "" msgid "Linked to your account" msgstr "" -msgid "Half-linked to your account" +msgid "Verification pending" msgstr "" +msgid "Unverified" +msgstr "Unverifiziert" + msgid "Apply to accept payments" msgstr "" +msgid "Resend verification" +msgstr "" + +msgid "Verify email address" +msgstr "" + +msgid "Dead-end, sorry" +msgstr "" + msgid "Addresses are from {a}{code}maintainers{_code}{_a}." msgstr "" @@ -1615,9 +1621,6 @@ msgstr "Identitäten" msgid "Verified" msgstr "Verifiziert" -msgid "Unverified" -msgstr "Unverifiziert" - msgid "Add Identity" msgstr "Identität Hinzufügen" diff --git a/i18n/core/es.po b/i18n/core/es.po index 3c01985219..7dcacf51aa 100644 --- a/i18n/core/es.po +++ b/i18n/core/es.po @@ -723,8 +723,8 @@ msgstr "" msgid "Eep! Mind looking over your info for us?" msgstr "" -msgid "Pay for open source." -msgstr "Pagar por código abierto." +msgid "Invest in open source." +msgstr "" msgid "Payment complete!" msgstr "" @@ -746,7 +746,7 @@ msgstr "" msgid "We weren't able to process your card." msgstr "" -msgid "Thank you for paying for open source!" +msgid "Thank you for investing in open source!" msgstr "" msgid "Email {support}{br}with questions or feedback." @@ -769,20 +769,26 @@ msgstr[0] "" msgstr[1] "" msgid "" -"Open source boosts the productivity of your developers {a}by 20%{_a}. " -"Companies fund half of open source through developer time." +"From {varnish} to {vuejs}, {drf} to {django} itself, {ruby} to {webpack}, " +"there are more and more examples of community-led open source projects " +"funded by enlightened companies." msgstr "" msgid "" -"Gratipay is the easiest way to pay for {a}the other half{_a}. Pay for open " -"source, and {b}strengthen the foundation{_b} that your developers build on. " -"Increase innovation and {b}reduce risk{_b} for your company." +"Inspired by this trend, #BackTheStack is a {b} funding campaign for the " +"whole open source community{_b}. If we all band together, can we encourage " +"even more of the industry to participate? Can we sustain even more of the " +"ecosystem, including parts that are less flashy?" msgstr "" msgid "" -"Gratipay can {b}report back{_b} to you on the progress your payment enables," -" and we can {b}promote{_b} your contribution, increasing your visibility " -"within the open source community." +"Your company's ROI on #BackTheStack will be {b}at least 10x{_b}. Pay $10,000" +" for $100,000 in maintenance and new development. We'll report back on the " +"impact of this shared investment, and we'd be thrilled to promote your " +"company's contribution to it." +msgstr "" + +msgid "Join #BackTheStack and invest in open source today!" msgstr "" msgid "Optional" @@ -818,22 +824,19 @@ msgstr "" msgid "You will get a link to an invoice for your payment." msgstr "" -msgid "Follow-up" -msgstr "" - -msgid "Quarterly" +msgid "Join Mailing List" msgstr "" -msgid "Yearly" -msgstr "" +msgid "Yes" +msgstr "Sí" -msgid "Never" -msgstr "" +msgid "No" +msgstr "No" msgid "I am surprised that you are seeing this message." msgstr "" -msgid "You will get a progress report, with a reminder to pay again." +msgid "We send updates related to #BackTheStack." msgstr "" msgid "Promotion" @@ -869,7 +872,7 @@ msgstr "" msgid "Submit Form" msgstr "" -msgid "Pay for Open Source" +msgid "Invest in Open Source" msgstr "" msgid "Processing ..." @@ -1003,12 +1006,6 @@ msgstr "Añadir" msgid "Are you sure?" msgstr "¿Estás seguro?" -msgid "Yes" -msgstr "Sí" - -msgid "No" -msgstr "No" - msgid "Already closed." msgstr "Ya está cerrado." @@ -1266,21 +1263,30 @@ msgstr "" msgid "Linked to a different account" msgstr "" -msgid "Ready to use" -msgstr "" - msgid "Your primary email address" msgstr "" msgid "Linked to your account" msgstr "" -msgid "Half-linked to your account" +msgid "Verification pending" msgstr "" +msgid "Unverified" +msgstr "No verificado" + msgid "Apply to accept payments" msgstr "" +msgid "Resend verification" +msgstr "" + +msgid "Verify email address" +msgstr "" + +msgid "Dead-end, sorry" +msgstr "" + msgid "Addresses are from {a}{code}maintainers{_code}{_a}." msgstr "" @@ -1611,9 +1617,6 @@ msgstr "Identidades" msgid "Verified" msgstr "Verificado" -msgid "Unverified" -msgstr "No verificado" - msgid "Add Identity" msgstr "Añadir Identidad" diff --git a/i18n/core/fr.po b/i18n/core/fr.po index c991ff1fbb..6b1829a5a3 100644 --- a/i18n/core/fr.po +++ b/i18n/core/fr.po @@ -723,8 +723,8 @@ msgstr "" msgid "Eep! Mind looking over your info for us?" msgstr "" -msgid "Pay for open source." -msgstr "Payer pour open source." +msgid "Invest in open source." +msgstr "" msgid "Payment complete!" msgstr "" @@ -746,7 +746,7 @@ msgstr "" msgid "We weren't able to process your card." msgstr "" -msgid "Thank you for paying for open source!" +msgid "Thank you for investing in open source!" msgstr "" msgid "Email {support}{br}with questions or feedback." @@ -769,20 +769,26 @@ msgstr[0] "" msgstr[1] "" msgid "" -"Open source boosts the productivity of your developers {a}by 20%{_a}. " -"Companies fund half of open source through developer time." +"From {varnish} to {vuejs}, {drf} to {django} itself, {ruby} to {webpack}, " +"there are more and more examples of community-led open source projects " +"funded by enlightened companies." msgstr "" msgid "" -"Gratipay is the easiest way to pay for {a}the other half{_a}. Pay for open " -"source, and {b}strengthen the foundation{_b} that your developers build on. " -"Increase innovation and {b}reduce risk{_b} for your company." +"Inspired by this trend, #BackTheStack is a {b} funding campaign for the " +"whole open source community{_b}. If we all band together, can we encourage " +"even more of the industry to participate? Can we sustain even more of the " +"ecosystem, including parts that are less flashy?" msgstr "" msgid "" -"Gratipay can {b}report back{_b} to you on the progress your payment enables," -" and we can {b}promote{_b} your contribution, increasing your visibility " -"within the open source community." +"Your company's ROI on #BackTheStack will be {b}at least 10x{_b}. Pay $10,000" +" for $100,000 in maintenance and new development. We'll report back on the " +"impact of this shared investment, and we'd be thrilled to promote your " +"company's contribution to it." +msgstr "" + +msgid "Join #BackTheStack and invest in open source today!" msgstr "" msgid "Optional" @@ -818,22 +824,19 @@ msgstr "" msgid "You will get a link to an invoice for your payment." msgstr "" -msgid "Follow-up" -msgstr "" - -msgid "Quarterly" +msgid "Join Mailing List" msgstr "" -msgid "Yearly" -msgstr "" +msgid "Yes" +msgstr "Oui" -msgid "Never" -msgstr "" +msgid "No" +msgstr "Non" msgid "I am surprised that you are seeing this message." msgstr "" -msgid "You will get a progress report, with a reminder to pay again." +msgid "We send updates related to #BackTheStack." msgstr "" msgid "Promotion" @@ -869,7 +872,7 @@ msgstr "" msgid "Submit Form" msgstr "" -msgid "Pay for Open Source" +msgid "Invest in Open Source" msgstr "" msgid "Processing ..." @@ -1003,12 +1006,6 @@ msgstr "Ajouter" msgid "Are you sure?" msgstr "Êtes-vous sûr ?" -msgid "Yes" -msgstr "Oui" - -msgid "No" -msgstr "Non" - msgid "Already closed." msgstr "Déjà fermé." @@ -1266,21 +1263,30 @@ msgstr "" msgid "Linked to a different account" msgstr "" -msgid "Ready to use" -msgstr "" - msgid "Your primary email address" msgstr "" msgid "Linked to your account" msgstr "" -msgid "Half-linked to your account" +msgid "Verification pending" msgstr "" +msgid "Unverified" +msgstr "Non vérifiée" + msgid "Apply to accept payments" msgstr "" +msgid "Resend verification" +msgstr "" + +msgid "Verify email address" +msgstr "" + +msgid "Dead-end, sorry" +msgstr "" + msgid "Addresses are from {a}{code}maintainers{_code}{_a}." msgstr "" @@ -1611,9 +1617,6 @@ msgstr "Identités" msgid "Verified" msgstr "Vérifiée" -msgid "Unverified" -msgstr "Non vérifiée" - msgid "Add Identity" msgstr "Ajouter une identité" diff --git a/i18n/core/it.po b/i18n/core/it.po index 3e133258c5..c5b2ad586b 100644 --- a/i18n/core/it.po +++ b/i18n/core/it.po @@ -716,8 +716,8 @@ msgstr "Acconsento anche agli altri {0}termini di servizio{1}." msgid "Eep! Mind looking over your info for us?" msgstr "Aah! Ti dispiacerebbe controllare le tue informazioni per noi?" -msgid "Pay for open source." -msgstr "Paga per open source." +msgid "Invest in open source." +msgstr "" msgid "Payment complete!" msgstr "Pagamento completato!" @@ -734,49 +734,55 @@ msgid "" msgstr "{a}Raccomandiamo{_a} $2000 all'anno{br}per ciascun impiegato tecnico{br}nella tua azienda." msgid "Loading credit card form ..." -msgstr "" +msgstr "Modulo per carta di credito in caricamento ..." msgid "We weren't able to process your card." msgstr "Non siamo stati in grado di elaborare la tua carta." -msgid "Thank you for paying for open source!" -msgstr "Grazie per pagare per l'open source!" +msgid "Thank you for investing in open source!" +msgstr "" msgid "Email {support}{br}with questions or feedback." msgstr "Invia un'email a {support} con{br}domande o suggerimenti." msgid "Campaign" -msgstr "" +msgstr "Campagna" msgid "payment" msgid_plural "payments" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Pagamento" +msgstr[1] "Pagamenti" msgid "out of {goal} = {percent}" -msgstr "" +msgstr "raggiunto il {percent} di {goal}" msgid "day left" msgid_plural "days left" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "giorno mancante" +msgstr[1] "giorni mancanti" msgid "" -"Open source boosts the productivity of your developers {a}by 20%{_a}. " -"Companies fund half of open source through developer time." -msgstr "L'open source incrementa la produttività dei tuoi sviluppatori {a}del 20%{_a}. Le aziende finanziano metà dell'open source attraverso il lavoro degli sviluppatori." +"From {varnish} to {vuejs}, {drf} to {django} itself, {ruby} to {webpack}, " +"there are more and more examples of community-led open source projects " +"funded by enlightened companies." +msgstr "" msgid "" -"Gratipay is the easiest way to pay for {a}the other half{_a}. Pay for open " -"source, and {b}strengthen the foundation{_b} that your developers build on. " -"Increase innovation and {b}reduce risk{_b} for your company." +"Inspired by this trend, #BackTheStack is a {b} funding campaign for the " +"whole open source community{_b}. If we all band together, can we encourage " +"even more of the industry to participate? Can we sustain even more of the " +"ecosystem, including parts that are less flashy?" msgstr "" msgid "" -"Gratipay can {b}report back{_b} to you on the progress your payment enables," -" and we can {b}promote{_b} your contribution, increasing your visibility " -"within the open source community." -msgstr "Gratipay può {b}informarti{_b} dei progressi messi in grado dal tuo finanziamento, e possiamo {b}promuovere{_b} il tuo contributo, aumentando la tua visibilità nella comunità dell'open source." +"Your company's ROI on #BackTheStack will be {b}at least 10x{_b}. Pay $10,000" +" for $100,000 in maintenance and new development. We'll report back on the " +"impact of this shared investment, and we'd be thrilled to promote your " +"company's contribution to it." +msgstr "" + +msgid "Join #BackTheStack and invest in open source today!" +msgstr "" msgid "Optional" msgstr "Opzionale" @@ -811,23 +817,20 @@ msgstr "Per favore inserisci un indirizzo email valido con meno di 255 caratteri msgid "You will get a link to an invoice for your payment." msgstr "Riceverai un link alla fattura del tuo pagamento." -msgid "Follow-up" -msgstr "Seguito" - -msgid "Quarterly" -msgstr "Trimestrale" +msgid "Join Mailing List" +msgstr "Iscrizione Mailing List" -msgid "Yearly" -msgstr "Annuale" +msgid "Yes" +msgstr "Sì" -msgid "Never" -msgstr "Mai" +msgid "No" +msgstr "No" msgid "I am surprised that you are seeing this message." msgstr "Sono sorpreso che tu stia vedendo questo messaggio." -msgid "You will get a progress report, with a reminder to pay again." -msgstr "Riceverai un aggiornamento sul progresso, con un promemoria di pagare nuovamente." +msgid "We send updates related to #BackTheStack." +msgstr "Inviamo aggiornamenti relativi a #BackTheStack." msgid "Promotion" msgstr "Promozione" @@ -862,8 +865,8 @@ msgstr "Per favore limita il tuo messaggio a 128 caratteri." msgid "Submit Form" msgstr "Invia Il Modulo" -msgid "Pay for Open Source" -msgstr "Paga per l'Open Source" +msgid "Invest in Open Source" +msgstr "" msgid "Processing ..." msgstr "In elaborazione ..." @@ -996,12 +999,6 @@ msgstr "Aggiungi" msgid "Are you sure?" msgstr "Sei sicuro?" -msgid "Yes" -msgstr "Sì" - -msgid "No" -msgstr "No" - msgid "Already closed." msgstr "Già chiuso." @@ -1259,21 +1256,30 @@ msgstr "Nessun indirizzo email registrato." msgid "Linked to a different account" msgstr "Collegato con un account differente" -msgid "Ready to use" -msgstr "Pronto all'uso" - msgid "Your primary email address" msgstr "Il tuo indirizzo email primario" msgid "Linked to your account" msgstr "Collegato col tuo account" -msgid "Half-linked to your account" -msgstr "Semi-collegato col tuo account" +msgid "Verification pending" +msgstr "In attesa di verifica" + +msgid "Unverified" +msgstr "Non verificato" msgid "Apply to accept payments" msgstr "Richiedi di poter accettare pagamenti" +msgid "Resend verification" +msgstr "Invia nuovamente la verifica" + +msgid "Verify email address" +msgstr "Verifica indirizzo email" + +msgid "Dead-end, sorry" +msgstr "Vicolo cieco, scusa" + msgid "Addresses are from {a}{code}maintainers{_code}{_a}." msgstr "Gli indirizzi sono da {a}{code}maintainers{_code}{_a}." @@ -1604,9 +1610,6 @@ msgstr "Identità" msgid "Verified" msgstr "Verificato" -msgid "Unverified" -msgstr "Non verificato" - msgid "Add Identity" msgstr "Aggiungi Identità" diff --git a/i18n/core/ja.po b/i18n/core/ja.po index 98f9393daf..dee6aff89f 100644 --- a/i18n/core/ja.po +++ b/i18n/core/ja.po @@ -710,8 +710,8 @@ msgstr "他の {0}利用規約{1} にも同意します。" msgid "Eep! Mind looking over your info for us?" msgstr "" -msgid "Pay for open source." -msgstr "オープンソースに支払います。" +msgid "Invest in open source." +msgstr "" msgid "Payment complete!" msgstr "" @@ -733,7 +733,7 @@ msgstr "" msgid "We weren't able to process your card." msgstr "" -msgid "Thank you for paying for open source!" +msgid "Thank you for investing in open source!" msgstr "" msgid "Email {support}{br}with questions or feedback." @@ -754,20 +754,26 @@ msgid_plural "days left" msgstr[0] "" msgid "" -"Open source boosts the productivity of your developers {a}by 20%{_a}. " -"Companies fund half of open source through developer time." +"From {varnish} to {vuejs}, {drf} to {django} itself, {ruby} to {webpack}, " +"there are more and more examples of community-led open source projects " +"funded by enlightened companies." msgstr "" msgid "" -"Gratipay is the easiest way to pay for {a}the other half{_a}. Pay for open " -"source, and {b}strengthen the foundation{_b} that your developers build on. " -"Increase innovation and {b}reduce risk{_b} for your company." +"Inspired by this trend, #BackTheStack is a {b} funding campaign for the " +"whole open source community{_b}. If we all band together, can we encourage " +"even more of the industry to participate? Can we sustain even more of the " +"ecosystem, including parts that are less flashy?" msgstr "" msgid "" -"Gratipay can {b}report back{_b} to you on the progress your payment enables," -" and we can {b}promote{_b} your contribution, increasing your visibility " -"within the open source community." +"Your company's ROI on #BackTheStack will be {b}at least 10x{_b}. Pay $10,000" +" for $100,000 in maintenance and new development. We'll report back on the " +"impact of this shared investment, and we'd be thrilled to promote your " +"company's contribution to it." +msgstr "" + +msgid "Join #BackTheStack and invest in open source today!" msgstr "" msgid "Optional" @@ -803,22 +809,19 @@ msgstr "" msgid "You will get a link to an invoice for your payment." msgstr "" -msgid "Follow-up" -msgstr "" - -msgid "Quarterly" +msgid "Join Mailing List" msgstr "" -msgid "Yearly" -msgstr "" +msgid "Yes" +msgstr "はい" -msgid "Never" -msgstr "" +msgid "No" +msgstr "いいえ" msgid "I am surprised that you are seeing this message." msgstr "" -msgid "You will get a progress report, with a reminder to pay again." +msgid "We send updates related to #BackTheStack." msgstr "" msgid "Promotion" @@ -854,7 +857,7 @@ msgstr "" msgid "Submit Form" msgstr "" -msgid "Pay for Open Source" +msgid "Invest in Open Source" msgstr "" msgid "Processing ..." @@ -984,12 +987,6 @@ msgstr "追加" msgid "Are you sure?" msgstr "よろしいですか?" -msgid "Yes" -msgstr "はい" - -msgid "No" -msgstr "いいえ" - msgid "Already closed." msgstr "すでに閉じています。" @@ -1244,21 +1241,30 @@ msgstr "" msgid "Linked to a different account" msgstr "" -msgid "Ready to use" -msgstr "" - msgid "Your primary email address" msgstr "" msgid "Linked to your account" msgstr "" -msgid "Half-linked to your account" +msgid "Verification pending" msgstr "" +msgid "Unverified" +msgstr "未確認" + msgid "Apply to accept payments" msgstr "" +msgid "Resend verification" +msgstr "" + +msgid "Verify email address" +msgstr "" + +msgid "Dead-end, sorry" +msgstr "" + msgid "Addresses are from {a}{code}maintainers{_code}{_a}." msgstr "" @@ -1588,9 +1594,6 @@ msgstr "ID" msgid "Verified" msgstr "確認済" -msgid "Unverified" -msgstr "未確認" - msgid "Add Identity" msgstr "ID を追加" diff --git a/i18n/core/nl.po b/i18n/core/nl.po index 1e80e09725..57bda7aa1e 100644 --- a/i18n/core/nl.po +++ b/i18n/core/nl.po @@ -718,7 +718,7 @@ msgstr "" msgid "Eep! Mind looking over your info for us?" msgstr "" -msgid "Pay for open source." +msgid "Invest in open source." msgstr "" msgid "Payment complete!" @@ -741,7 +741,7 @@ msgstr "" msgid "We weren't able to process your card." msgstr "" -msgid "Thank you for paying for open source!" +msgid "Thank you for investing in open source!" msgstr "" msgid "Email {support}{br}with questions or feedback." @@ -764,20 +764,26 @@ msgstr[0] "" msgstr[1] "" msgid "" -"Open source boosts the productivity of your developers {a}by 20%{_a}. " -"Companies fund half of open source through developer time." +"From {varnish} to {vuejs}, {drf} to {django} itself, {ruby} to {webpack}, " +"there are more and more examples of community-led open source projects " +"funded by enlightened companies." msgstr "" msgid "" -"Gratipay is the easiest way to pay for {a}the other half{_a}. Pay for open " -"source, and {b}strengthen the foundation{_b} that your developers build on. " -"Increase innovation and {b}reduce risk{_b} for your company." +"Inspired by this trend, #BackTheStack is a {b} funding campaign for the " +"whole open source community{_b}. If we all band together, can we encourage " +"even more of the industry to participate? Can we sustain even more of the " +"ecosystem, including parts that are less flashy?" msgstr "" msgid "" -"Gratipay can {b}report back{_b} to you on the progress your payment enables," -" and we can {b}promote{_b} your contribution, increasing your visibility " -"within the open source community." +"Your company's ROI on #BackTheStack will be {b}at least 10x{_b}. Pay $10,000" +" for $100,000 in maintenance and new development. We'll report back on the " +"impact of this shared investment, and we'd be thrilled to promote your " +"company's contribution to it." +msgstr "" + +msgid "Join #BackTheStack and invest in open source today!" msgstr "" msgid "Optional" @@ -813,22 +819,19 @@ msgstr "" msgid "You will get a link to an invoice for your payment." msgstr "" -msgid "Follow-up" -msgstr "" - -msgid "Quarterly" +msgid "Join Mailing List" msgstr "" -msgid "Yearly" -msgstr "" +msgid "Yes" +msgstr "Ja" -msgid "Never" -msgstr "" +msgid "No" +msgstr "Nee" msgid "I am surprised that you are seeing this message." msgstr "" -msgid "You will get a progress report, with a reminder to pay again." +msgid "We send updates related to #BackTheStack." msgstr "" msgid "Promotion" @@ -864,7 +867,7 @@ msgstr "" msgid "Submit Form" msgstr "" -msgid "Pay for Open Source" +msgid "Invest in Open Source" msgstr "" msgid "Processing ..." @@ -998,12 +1001,6 @@ msgstr "Toevoegen" msgid "Are you sure?" msgstr "" -msgid "Yes" -msgstr "Ja" - -msgid "No" -msgstr "Nee" - msgid "Already closed." msgstr "" @@ -1261,21 +1258,30 @@ msgstr "" msgid "Linked to a different account" msgstr "" -msgid "Ready to use" -msgstr "" - msgid "Your primary email address" msgstr "" msgid "Linked to your account" msgstr "" -msgid "Half-linked to your account" +msgid "Verification pending" msgstr "" +msgid "Unverified" +msgstr "Niet geverifieerd" + msgid "Apply to accept payments" msgstr "" +msgid "Resend verification" +msgstr "" + +msgid "Verify email address" +msgstr "" + +msgid "Dead-end, sorry" +msgstr "" + msgid "Addresses are from {a}{code}maintainers{_code}{_a}." msgstr "" @@ -1606,9 +1612,6 @@ msgstr "" msgid "Verified" msgstr "" -msgid "Unverified" -msgstr "Niet geverifieerd" - msgid "Add Identity" msgstr "" diff --git a/js/gratipay/packages.js b/js/gratipay/packages.js index cb47b88453..55c59b5873 100644 --- a/js/gratipay/packages.js +++ b/js/gratipay/packages.js @@ -1,14 +1,20 @@ Gratipay.packages = {}; Gratipay.packages.initBulk = function() { - $('button.apply').on('click', Gratipay.packages.postBulk); + $('.important-button button.apply').on('click', Gratipay.packages.postBulk); }; Gratipay.packages.initSingle = function() { - Gratipay.Select('.gratipay-select'); - $('button.apply').on('click', Gratipay.packages.postOne); + Gratipay.Select('.gratipay-select', Gratipay.packages.selectOne); + $('.important-button button').on('click', Gratipay.packages.postOne); + Gratipay.packages.selectOne($('.gratipay-select li.selected')); }; +Gratipay.packages.selectOne = function($li) { + var action = $li.data('action'); + $('.important-button span').hide(); + $('.important-button span.' + action).show(); +}; Gratipay.packages.postBulk = function(e) { e.preventDefault(); @@ -20,20 +26,25 @@ Gratipay.packages.postBulk = function(e) { package_ids_by_email[pkg.email].push(pkg.packageId); }); for (email in package_ids_by_email) - Gratipay.packages.post(email, package_ids_by_email[email], true); + Gratipay.packages.post(email, package_ids_by_email[email], 'yes'); }; Gratipay.packages.postOne = function(e) { e.preventDefault(); - var email = $('input[name=email]:checked').val(); - var package_id = $('input[name=package_id]').val(); - Gratipay.packages.post(email, [package_id]); + var $input = $('input[name=email]:checked'); + var email = $input.val(); + var package_ids; + var show_address_in_message = 'no'; + if ($input.closest('li').data('action') === 'apply') { + package_ids = [$('input[name=package_id]').val()]; + show_address_in_message = 'yes'; + } + Gratipay.packages.post(email, package_ids, show_address_in_message); } - -Gratipay.packages.post = function(email, package_ids, show_email) { +Gratipay.packages.post = function(email, package_ids, show_address_in_message) { var action = 'start-verification'; - var $button = $('button.apply') + var $button = $('.important-button button') $button.prop('disabled', true); function reenable() { $button.prop('disabled', false); } @@ -43,7 +54,7 @@ Gratipay.packages.post = function(email, package_ids, show_email) { data: { action: action , address: email , package_id: package_ids - , show_address_in_message: true + , show_address_in_message: show_address_in_message }, traditional: true, dataType: 'json', diff --git a/js/gratipay/select.js b/js/gratipay/select.js index 25691a5c09..4a82daf1f7 100644 --- a/js/gratipay/select.js +++ b/js/gratipay/select.js @@ -1,6 +1,7 @@ -Gratipay.Select = function(selector) { +Gratipay.Select = function(selector, onselect) { var $ul = $('ul', selector); var $labels = $('label', $ul); + var onselect = onselect || function() {}; // state for vertical position var topFactor = 0; // float between 0 and $labels.length-1 @@ -51,9 +52,11 @@ Gratipay.Select = function(selector) { function close($label) { if ($label) { - if ($label.closest('li').hasClass('disabled')) return; + var $li = $label.closest('li'); + if ($li.hasClass('disabled')) return; $('.selected', $ul).removeClass('selected') - $label.closest('li').addClass('selected').removeClass('hover'); + $li.addClass('selected').removeClass('hover'); + onselect($li); } $ul.css({'top': 0}).removeClass('open'); $ul.unbind('mousewheel'); diff --git a/scss/pages/homepage.scss b/scss/pages/homepage.scss index ccc3e2e85f..f7a034a780 100644 --- a/scss/pages/homepage.scss +++ b/scss/pages/homepage.scss @@ -238,12 +238,12 @@ text-align: center; } } - &.email_address, &.follow_up { + &.email_address, &.on_mailing_list { .fine-print { text-align: left; } } - &.follow_up { + &.on_mailing_list { text-align: left; .fancy-radio { position: relative; diff --git a/scss/pages/package.scss b/scss/pages/package.scss index a9f1ccdfbe..bfa49920b3 100644 --- a/scss/pages/package.scss +++ b/scss/pages/package.scss @@ -14,6 +14,12 @@ color: $medium-gray; } + .important-button { + span { + display: none; + } + } + .status-icon { font-size: 12px; line-height: 12px; diff --git a/scss/pages/widgets.scss b/scss/pages/widgets.scss new file mode 100644 index 0000000000..87bef3c08b --- /dev/null +++ b/scss/pages/widgets.scss @@ -0,0 +1,8 @@ +#widgets { + textarea { + font: normal 10px/12px $Mono; + width: 100%; + padding: 10px; + height: 60px; + } +} diff --git a/sql/schema.sql b/sql/schema.sql index 9aef2c2b48..8fdf303907 100644 --- a/sql/schema.sql +++ b/sql/schema.sql @@ -1301,13 +1301,13 @@ CREATE TABLE payments_for_open_source ( braintree_transaction_id text, braintree_result_message text, name text NOT NULL, - follow_up follow_up NOT NULL, email_address text NOT NULL, promotion_name text DEFAULT ''::text NOT NULL, promotion_url text DEFAULT ''::text NOT NULL, promotion_twitter text DEFAULT ''::text NOT NULL, promotion_message text DEFAULT ''::text NOT NULL, - grateful_for text DEFAULT ''::text NOT NULL + grateful_for text DEFAULT ''::text NOT NULL, + on_mailing_list boolean DEFAULT true NOT NULL ); diff --git a/templates/team-base.html b/templates/team-base.html index d27fbd0d38..f467797da1 100644 --- a/templates/team-base.html +++ b/templates/team-base.html @@ -62,6 +62,7 @@ {% set pages = [ ('/', _('Profile')) , ('/history/', _('History')) , ('/receiving/', _('Receiving')) + , ('/widgets/', _('Widgets')) ] + ([('/distributing/', _('Distributing'))] if team.available else [])%} {% if pages %} {% include "templates/nav.html" %} diff --git a/tests/py/test_participant_emails.py b/tests/py/test_participant_emails.py index 2f7abba0a6..db12325578 100644 --- a/tests/py/test_participant_emails.py +++ b/tests/py/test_participant_emails.py @@ -63,7 +63,7 @@ def hit_email_spt(self, action, address, user='alice', package_ids=[], should_fa def hit_verify_spt(self, email, nonce, username='alice', should_fail=False): # Email address is encoded in url. - url = '/~%s/emails/verify.html?email2=%s&nonce=%s' + url = '/~%s/emails/verify.html?email=%s&nonce=%s' url %= (username, encode_for_querystring(email), nonce) f = self.client.GxT if should_fail else self.client.GET return f(url, auth_as=username) @@ -93,7 +93,7 @@ def test_email_address_is_encoded_in_sent_verification_link(self): encoded = encode_for_querystring(address) self.hit_email_spt('add-email', address) last_email = self.get_last_email() - assert "~alice/emails/verify.html?email2="+encoded in last_email['body_text'] + assert "~alice/emails/verify.html?email="+encoded in last_email['body_text'] def test_verification_email_doesnt_contain_unsubscribe(self): self.hit_email_spt('add-email', 'alice@gratipay.com') @@ -190,14 +190,17 @@ def test_empty_nonce_fails(self): assert result == (_email.VERIFICATION_FAILED, None, None) def test_email_verification_is_backwards_compatible(self): - """Test email verification still works with unencoded email in verification link. + """Test email verification still works with 'email2' field in verification link. """ - self.hit_email_spt('add-email', 'alice@example.com') - nonce = self.alice.get_email('alice@example.com').nonce - url = '/~alice/emails/verify.html?email=alice@example.com&nonce='+nonce - self.client.GET(url, auth_as='alice') - expected = 'alice@example.com' - actual = P('alice').email_address + username = 'alice' + email = 'alice@example.com' + self.hit_email_spt('add-email', email) + nonce = self.alice.get_email(email).nonce + url = '/~%s/emails/verify.html?email2=%s&nonce=%s' + url %= (username, encode_for_querystring(email), nonce) + self.client.GET(url, auth_as=username) + expected = email + actual = P(username).email_address assert expected == actual def test_verified_email_is_not_changed_after_update(self): @@ -573,7 +576,7 @@ def test_returns_a_link(self): with self.db.get_cursor() as c: alice = self.make_participant('alice') link = alice.get_email_verification_link(c, 'alice@example.com') - assert link.startswith('/~alice/emails/verify.html?email2=YWxpY2VAZXhhbXBsZS5jb20~&nonce=') + assert link.startswith('/~alice/emails/verify.html?email=YWxpY2VAZXhhbXBsZS5jb20~&nonce=') def test_makes_no_claims_by_default(self): with self.db.get_cursor() as c: diff --git a/tests/py/test_project_review_process.py b/tests/py/test_project_review_process.py index ddbd70a219..257ff85b88 100644 --- a/tests/py/test_project_review_process.py +++ b/tests/py/test_project_review_process.py @@ -57,9 +57,15 @@ def test_github_poster_attempts_to_post_to_github(self, post): args, kwargs = post.mock_calls[0][1:] assert args[0] == 'https://api.github.com/repos/some/repo/issues' assert kwargs['data'] == ( - '{"body": "https://gratipay.com/foo/\\nhttps://gratipay.com/bar/\\n' - 'https://gratipay.com/baz/\\n\\n(This application will remain open ' - 'for at least a week.)", "title": "foo and 2 other projects"}') + '{"body": "*This application will remain open for at least a week.*\\n\\n' + '## Projects\\n\\nhttps://gratipay.com/foo/\\nhttps://gratipay.com/bar/\\n' + 'https://gratipay.com/baz/\\n\\n' + '## Badge\\n\\n' + 'Add a [badge](http://shields.io/) to your README?\\n\\n' + '[![Gratipay](https://img.shields.io/gratipay/project/foo.svg)](https://gratipay.com/foo/)\\n\\n' + '```markdown\\n' + '[![Gratipay](https://img.shields.io/gratipay/project/foo.svg)](https://gratipay.com/foo/)\\n' + '```", "title": "foo and 2 other projects"}') assert kwargs['auth'] == ('cheeseburger', 'di3tc0ke') diff --git a/tests/py/test_security.py b/tests/py/test_security.py index 72b97f8674..fa0b2d7b5a 100644 --- a/tests/py/test_security.py +++ b/tests/py/test_security.py @@ -71,6 +71,10 @@ def test_sets_referrer_policy(self): assert headers['Referrer-Policy'] == \ 'no-referrer-when-downgrade, strict-origin-when-cross-origin' + def test_sets_strict_transport_security(self): + headers = self.client.GET('/about/').headers + assert headers['strict-transport-security'] == 'max-age=31536000' + def test_doesnt_set_content_security_policy_by_default(self): assert 'content-security-policy-report-only' not in self.client.GET('/about/').headers diff --git a/tests/py/test_www_homepage.py b/tests/py/test_www_homepage.py index 271b87bfb6..aeaa98ac10 100644 --- a/tests/py/test_www_homepage.py +++ b/tests/py/test_www_homepage.py @@ -19,7 +19,7 @@ , 'grateful_for': 'python, javascript' , 'name': 'Alice Liddell' , 'email_address': 'alice@example.com' - , 'follow_up': 'yearly' + , 'on_mailing_list': 'yes' , 'promotion_name': 'Wonderland' , 'promotion_url': 'http://www.example.com/' , 'promotion_twitter': 'thebestbutter' @@ -30,7 +30,7 @@ , 'grateful_for': 'x' * (16 * 2**10) + 'x' , 'name': 'Alice Liddell' * 20 , 'email_address': 'alice' * 100 + '@example.com' - , 'follow_up': 'cheese' + , 'on_mailing_list': 'cheese' , 'promotion_name': 'Wonderland' * 100 , 'promotion_url': 'http://www.example.com/' + 'cheese' * 100 , 'promotion_twitter': 'thebestbutter' * 10 @@ -41,7 +41,7 @@ , 'grateful_for': '' , 'name': '' , 'email_address': '' - , 'follow_up': 'quarterly' + , 'on_mailing_list': 'no' , 'promotion_name': '' , 'promotion_url': '' , 'promotion_twitter': '' @@ -52,13 +52,14 @@ , 'grateful_for': 'x' * (16 * 2**10) , 'name': 'Alice Liddell' * 19 + 'Alice Li' , 'email_address': 'alice' * 51 - , 'follow_up': 'quarterly' + , 'on_mailing_list': 'yes' , 'promotion_name': 'WonderlandWonderlandWonderlandWo' , 'promotion_url': 'http://www.example.com/' + 'cheese' * 38 + 'chee' , 'promotion_twitter': 'thebestbutterthebestbutterthebes' , 'promotion_message': 'Love me!' * 16 } -ALL = ['amount', 'payment_method_nonce', 'grateful_for', 'name', 'email_address', 'follow_up', +ALL = ['amount', 'payment_method_nonce', + 'grateful_for', 'name', 'email_address', 'on_mailing_list', 'promotion_name', 'promotion_url', 'promotion_twitter', 'promotion_message'] @@ -125,7 +126,7 @@ def test_stores_info(self): parsed.pop('payment_method_nonce') assert self.fetch() is None _store(parsed) - assert self.fetch().follow_up == 'yearly' + assert self.fetch().on_mailing_list class Send(QueuedEmailHarness): diff --git a/tests/ttw/test_homepage.py b/tests/ttw/test_homepage.py index ee875cd884..d6ce7da0ee 100644 --- a/tests/ttw/test_homepage.py +++ b/tests/ttw/test_homepage.py @@ -39,7 +39,7 @@ def fill_form(self, amount, credit_card_number, expiration, cvv, def test_loads_for_anon(self): - assert self.css('#banner h1').text == 'Pay for open source.' + assert self.css('#banner h1').text == 'Invest in open source.' assert self.css('#header .sign-in button').html.strip()[:17] == 'Sign in / Sign up' def test_redirects_for_authed_exclamation_point(self): diff --git a/tests/ttw/test_package_claiming.py b/tests/ttw/test_package_claiming.py index 472005955b..5d1b32f1ed 100644 --- a/tests/ttw/test_package_claiming.py +++ b/tests/ttw/test_package_claiming.py @@ -9,13 +9,25 @@ class Test(BrowserHarness): - def check(self, choice=0): - self.make_participant('alice', claimed_time='now') + def setUp(self): + BrowserHarness.setUp(self) + self.alice = self.make_participant( 'alice' + , claimed_time='now' + , email_address='alice@example.com' + ) + self.add_and_verify_email(self.alice, 'bob@example.com') self.sign_in('alice') + + def choose(self, choice=0): + self.css('#content li.selected label').click() # activate select + want = self.css('#content label')[choice] + want.click() + return want.text + + def check(self, choice=0): self.visit('/on/npm/foo') - self.css('#content label')[0].click() # activate select - self.css('#content label')[choice].click() - self.css('#content button')[0].click() + self.choose(choice) + self.css('#content .important-button button').click() address = ('alice' if choice == 0 else 'bob') + '@example.com' assert self.wait_for_success() == 'Check {} for a verification link.'.format(address) return self.db.one('select address from claims c ' @@ -39,18 +51,42 @@ def test_can_send_to_second_email(self): self.make_package(emails=['alice@example.com', 'bob@example.com']) assert self.check(choice=1) == 'bob@example.com' - def test_disabled_items_are_disabled(self): - self.make_package(emails=['alice@example.com', 'bob@example.com']) - alice = self.make_participant('alice', claimed_time='now') - self.add_and_verify_email(alice, 'alice@example.com', 'bob@example.com') - self.sign_in('alice') + def test_button_varies_with_email_state(self): + self.make_package(emails=['alice@example.com', 'bob@example.com', 'cat@example.com', + 'doug@example.com', 'edna@example.com']) + self.make_participant('doug', claimed_time='now', email_address='doug@example.com') + self.alice.start_email_verification('cat@example.com') + self.visit('/on/npm/foo') + + self.choose(0) == 'alice@example.com' + self.css('li.selected').text.endswith('Your primary email address') + self.css('button').text == 'Apply to accept payments' + + self.choose(1) == 'bob@example.com' + self.css('li.selected').text.endswith('Linked to your account') + self.css('button').text == 'Apply to accept payments' + + self.choose(2) == 'cat@example.com' + self.css('li.selected').text.endswith('Verification pending') + self.css('button').text == 'Resend verification' + + self.choose(3) == 'edna@example.com' + self.css('li.selected').text.endswith('Unverified') + self.css('button').text == 'Verify email address' + + # doug is last, can't even be selected + self.choose(4) == 'doug@example.com' + self.css('li.selected label') == 'edna@example.com' + self.css('#content li')[4].text.endswith('Linked to a different account') + + def test_sending_to_unverified_doesnt_start_a_claim(self): + self.make_package(emails=['alice@example.com', 'cat@example.com']) self.visit('/on/npm/foo') - self.css('#content label')[0].click() # activate select - self.css('#content label')[1].click() # click second item - self.css('#content li')[0].has_class('selected') # first item is still selected - self.css('#content ul')[0].has_class('open') # still open - self.css('#content button').has_class('disabled') - assert self.db.all('select * from claims') == [] + self.choose(1) + self.css('#content .important-button button').click() + assert self.wait_for_success() == 'Check your inbox for a verification link.' + assert self.db.one('select address from claims c ' + 'join email_addresses e on c.nonce = e.nonce') is None def test_claimed_packages_can_be_given_to(self): @@ -79,7 +115,7 @@ def test_visiting_verify_link_shows_helpful_information(self): self.make_package() self.check() - link = pickle.loads(self.db.one('select context from email_messages'))['link'] + link = pickle.loads(self.db.all('select context from email_messages')[-1])['link'] link = link[len(self.base_url):] # strip because visit will add it back self.visit(link) diff --git a/www/%team/widgets/index.html.spt b/www/%team/widgets/index.html.spt new file mode 100644 index 0000000000..4c34514589 --- /dev/null +++ b/www/%team/widgets/index.html.spt @@ -0,0 +1,44 @@ +from aspen import Response + +[-----------------------------------------------------------------------------] + +team = request.path['team'] +if team.is_approved in (None, False): + raise website.redirect('..') +elif user.ANON: + raise Response(401) +elif not (user.ADMIN or user.participant.username == team.owner): + raise Response(403) + +banner = team.name +page_id = 'widgets' +title = _("Widgets") + +[-----------------------------------------------------------------------------] +{% extends "templates/team-base.html" %} +{% block content %} + +

Shields.io provides quality metadata badges +for open source projects. This badge shows how much your project receives +weekly:

+ +

+ + + +

+ +

Copy the code below to use on your repository README or website.

+ + +

Markdown

+ + + + +

HTML

+ + + +{% endblock %} + diff --git a/www/assets/gratipay.css.spt b/www/assets/gratipay.css.spt index 90209eb93b..b011bac6bc 100644 --- a/www/assets/gratipay.css.spt +++ b/www/assets/gratipay.css.spt @@ -78,3 +78,4 @@ @import "scss/pages/on-confirm"; @import "scss/pages/search"; @import "scss/pages/hall-of-fame"; +@import "scss/pages/widgets"; diff --git a/www/index.spt b/www/index.spt index d7ee6377e9..b6769b7472 100644 --- a/www/index.spt +++ b/www/index.spt @@ -13,7 +13,7 @@ if not user.ANON: suppress_banner = True suppress_sidebar = True page_id = "homepage" -banner = "Pay for Open Source" # goofy w/ suppress_banner, it's for +banner = "Invest in Open Source" # goofy w/ suppress_banner, it's for <title> npayments = website.campaign_npayments raised = website.campaign_raised @@ -35,7 +35,7 @@ result {% block head %} <link rel="publisher" href="https://plus.google.com/104524895706770139568"> <link type="application/opensearchdescription+xml" rel="search" href="/opensearch.osdd" /> - <meta name="description" content="Pay for open source on Gratipay." /> + <meta name="description" content="Invest in open source on Gratipay." /> <meta name="fb:app_id" content="229465400522758" /> <meta name="og:type" content="website" /> <meta name="og:url" content="https://gratipay.com/" /> @@ -63,7 +63,7 @@ $(document).ready(function() { <fieldset id="banner"> <h1> - <span class="pending">{{ _("Pay for open source.") }}</span> + <span class="pending">{{ _("Invest in open source.") }}</span> <span class="complete">{{ _("Payment complete!") }}</span> </h1> @@ -100,7 +100,7 @@ $(document).ready(function() { <div class="payment-complete" style="display: none;"> <p class="instructions"> - {{ _("Thank you for paying for open source!") }} 💃 + {{ _("Thank you for investing in open source!") }} 💃 </p> <div class="important-button" class="important-button"> <a class="button large selected invoice" href="">{{ _("View Invoice") }}</a> @@ -164,28 +164,36 @@ $(document).ready(function() { </section> <section class="materials"> + <p class="prose"> - {{ _( 'Open source boosts the productivity of your developers {a}by 20%{_a}. Companies fund half of open source through developer time.' - , a='<a href="https://medium.com/@nayafia/open-source-was-worth-at-least-143m-of-instagram-s-1b-acquisition-808bb85e4681">'|safe - , _a='</a>'|safe + {{ _( "From {varnish} to {vuejs}, {drf} to {django} itself, {ruby} to {webpack}, there are more and more examples of community-led open source projects funded by enlightened companies." + , varnish='<a href="http://phk.freebsd.dk/VML/">Varnish</a>'|safe + , vuejs='<a href="https://www.patreon.com/evanyou">Vue.js</a>'|safe + , drf='<a href="https://fund.django-rest-framework.org/topics/funding/">DRF</a>'|safe + , django='<a href="https://www.djangoproject.com/fundraising/">Django</a>'|safe + , ruby='<a href="https://rubytogether.org/">Ruby</a>'|safe + , webpack='<a href="https://opencollective.com/webpack">WebPack</a>'|safe ) }} </p> <p class="prose"> - {{ _( 'Gratipay is the easiest way to pay for {a}the other half{_a}. Pay for open source, and {b}strengthen the foundation{_b} that your developers build on. Increase innovation and {b}reduce risk{_b} for your company.' - , a='<a href="https://gratipay.news/open-source-captures-almost-none-of-the-value-it-creates-9015eb7e293e">'|safe - , _a='</a>'|safe - , b='<b>'|safe - , _b='</b>'|safe - ) }} + {{ _( "Inspired by this trend, #BackTheStack is a {b} funding campaign for the whole open source community{_b}. If we all band together, can we encourage even more of the industry to participate? Can we sustain even more of the ecosystem, including parts that are less flashy?" + , b='<b>'|safe + , _b='</b>'|safe + ) }} </p> <p class="prose"> - {{ _( 'Gratipay can {b}report back{_b} to you on the progress your payment enables, and we can {b}promote{_b} your contribution, increasing your visibility within the open source community.' + {{ _( "Your company's ROI on #BackTheStack will be {b}at least 10x{_b}. Pay $10,000 for $100,000 in maintenance and new development. We'll report back on the impact of this shared investment, and we'd be thrilled to promote your company's contribution to it." , b='<b>'|safe , _b='</b>'|safe ) }} </p> + + <p class="prose"> + {{ _("Join #BackTheStack and invest in open source today!") }} + </p> + </section> <section class="partners"> @@ -238,24 +246,20 @@ $(document).ready(function() { </p> </div> - <div class="field follow_up"> + <div class="field on_mailing_list"> <fieldset> - <legend>{{ _('Follow-up') }}</legend> - - <div class="fancy-radio"> - <input type="radio" name="follow_up" id="follow-up-quarterly" - value="quarterly" checked> - <label for="follow-up-quarterly">{{ _('Quarterly') }}</label> - </div> + <legend>{{ _('Join Mailing List') }}</legend> <div class="fancy-radio"> - <input type="radio" name="follow_up" id="follow-up-yearly" value="yearly"> - <label for="follow-up-yearly">{{ _('Yearly') }}</label> + <input type="radio" name="on_mailing_list" id="mailing-list-yes" + value="yes" checked> + <label for="mailing-list-yes">{{ _('Yes') }}</label> </div> <div class="fancy-radio"> - <input type="radio" name="follow_up" id="follow-up-never" value="never"> - <label for="follow-up-never">{{ _('Never') }}</label> + <input type="radio" name="on_mailing_list" id="mailing-list-no" + value="no"> + <label for="mailing-list-no">{{ _('No') }}</label> </div> <p class="fine-print help"> @@ -263,7 +267,7 @@ $(document).ready(function() { </p> <p class="fine-print"> - {{ _('You will get a progress report, with a reminder to pay again.') }} + {{ _('We send updates related to #BackTheStack.') }} </p> </fieldset> </div> @@ -315,7 +319,7 @@ $(document).ready(function() { <div class="important-button"> <button type="submit" class="selected large"> - <span class="active">{{ _("Pay for Open Source") }}</span> + <span class="active">{{ _("Invest in Open Source") }}</span> <span class="processing">{{ _("Processing ...") }}</span> </button> </div> diff --git a/www/on/npm/%package.spt b/www/on/npm/%package.spt index 9756f27809..808077bd1c 100644 --- a/www/on/npm/%package.spt +++ b/www/on/npm/%package.spt @@ -22,7 +22,6 @@ banner = package.name if user.participant: emails = package.classify_emails_for_participant(user.participant) - has_email_options = bool([x for x in emails if x[1] != OTHER]) [---] text/html {% extends "templates/base.html" %} @@ -77,7 +76,11 @@ if user.participant: <ul> {% for i, (email, group) in enumerate(emails, start=1) %} <li class="{% if group == OTHER %}disabled{% endif %} - {% if i == 1 %}selected{% endif %}"> + {% if i == 1 %}selected{% endif %}" + data-action="{{ 'apply' if group in (PRIMARY, VERIFIED) else + 'resend' if group == UNVERIFIED else + 'verify' if group == UNLINKED else + 'none' }}"> <input type="radio" name="email" value="{{ email }}" id="email-{{i}}" {% if i == 1 %}checked{% endif %}> <span class="icon"></span> @@ -91,19 +94,22 @@ if user.participant: {{ icons.STATUS_ICONS['failure']|safe }}</span> {{ _('Linked to a different account') }} {% else %} - {{ _('Ready to use') }} {% if group == PRIMARY %} - · <span class="status-icon feature"> + <span class="status-icon feature"> {{ icons.STATUS_ICONS['feature']|safe }}</span> {{ _('Your primary email address') }} {% elif group == VERIFIED %} - · <span class="status-icon success"> + <span class="status-icon success"> {{ icons.STATUS_ICONS['success']|safe }}</span> {{ _('Linked to your account') }} {% elif group == UNVERIFIED %} - · <span class="status-icon warning"> + <span class="status-icon warning"> {{ icons.STATUS_ICONS['warning']|safe }}</span> - {{ _('Half-linked to your account') }} + {{ _('Verification pending') }} + {% elif group == UNLINKED %} + <span class="status-icon warning"> + {{ icons.STATUS_ICONS['warning']|safe }}</span> + {{ _('Unverified') }} {% endif %} {% endif %} </div> @@ -116,15 +122,17 @@ if user.participant: </div> <div class="important-button"> - <button type="submit" class="apply selected large" - {% if not has_email_options %} disabled{% endif %}> - {{ _('Apply to accept payments') }} + <button type="submit" class="selected large disabled"> + <span class="apply">{{ _('Apply to accept payments') }}</span> + <span class="resend">{{ _('Resend verification') }}</span> + <span class="verify">{{ _('Verify email address') }}</span> + <span class="dead-end">{{ _('Dead-end, sorry') }}</span> </button> </div> {% endif %} <p class="fine-print"> {{ _( 'Addresses are from {a}{code}maintainers{_code}{_a}.' - , a=('<a href="' + package.remote_api_url + '">')|safe + , a='<a href="%s">'|safe % package.remote_api_url , _a='</a>'|safe , code='<code>'|safe , _code='</code>'|safe @@ -132,7 +140,7 @@ if user.participant: </p> <p class="fine-print"> {{ _( 'Out of date? Update {a}at npm{_a} and refresh.' - , a=('<a href="' + package.remote_human_url + '">')|safe + , a='<a href="%s">'|safe % package.remote_human_url , _a='</a>'|safe ) }} </p> diff --git a/www/version.txt b/www/version.txt index 631455b4bd..ea2d7fdefc 100644 --- a/www/version.txt +++ b/www/version.txt @@ -1 +1 @@ -2118 +2122 diff --git a/www/~/%username/emails/modify.json.spt b/www/~/%username/emails/modify.json.spt index 77e904d609..735c312daa 100644 --- a/www/~/%username/emails/modify.json.spt +++ b/www/~/%username/emails/modify.json.spt @@ -12,7 +12,7 @@ participant = get_participant(state, restrict=True) action = request.body['action'] address = request.body['address'] -show_address_in_message = bool(request.body.get('show_address_in_message', '')) +show_address_in_message = request.body.get('show_address_in_message', '') == 'yes' # Basic checks. The real validation will happen when we send the email. if not is_valid_email_address(address): diff --git a/www/~/%username/emails/verify.html.spt b/www/~/%username/emails/verify.html.spt index 555eed1b8a..67c2fdb025 100644 --- a/www/~/%username/emails/verify.html.spt +++ b/www/~/%username/emails/verify.html.spt @@ -12,15 +12,17 @@ from gratipay.models.participant import email participant = get_participant(state, restrict=False) banner = '~' + participant.username if participant == user.participant: - if 'email' in request.qs: + if 'email2' in request.qs: - # Deprecated in GH-3965. We shouldn't be generating any more of these, - # and this can be removed when we're confident that there are no more - # old-style verification links hanging out there. + # As of GH-4662, we've renamed the temporary 'email2' field, introduced + # in GH-3965, with 'email' and this can be removed when we're confident + # that there are no verification links live with field 'email2' in + # their query string. - email_address = request.qs['email'] + email_field = 'email2' else: - email_address = decode_from_querystring(request.qs.get('email2', ''), default='') + email_field = 'email' + email_address = decode_from_querystring(request.qs.get(email_field, ''), default='') nonce = request.qs.get('nonce', '') result, packages, paypal_updated = participant.finish_email_verification(email_address, nonce) project_list = None if packages is None else [p.team for p in packages]