internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: liberapay/liberapay.com

Issue:
Timeouts
We've received two emails from people saying that they're unable to donate because they get a Cloudflare 504 error page. The new implementation of the email domain check could be the cause.


Discussion:

Resolving patch:
diff --git a/liberapay/exceptions.py b/liberapay/exceptions.py
--- a/liberapay/exceptions.py
+++ b/liberapay/exceptions.py
@@ -181,7 +181,7 @@ def __init__(self, address, exception_or_message=None):
         self.exception_or_message = exception_or_message
 
     def __str__(self):
-        return self.email_address
+        return "%s (%r)" % (self.email_address, self.exception_or_message)
 
 
 class EmailAlreadyTaken(EmailAddressError):
diff --git a/liberapay/utils/emails.py b/liberapay/utils/emails.py
--- a/liberapay/utils/emails.py
+++ b/liberapay/utils/emails.py
@@ -5,7 +5,7 @@
 import logging
 from random import random
 from smtplib import SMTP, SMTPException, SMTPResponseException
-from time import sleep
+import time
 
 from aspen.simplates.pagination import parse_specline, split_and_escape
 from aspen_jinja2_renderer import SimplateLoader
@@ -174,10 +174,14 @@ def check_email_address(email: NormalizedEmailAddress, state: dict) -> None:
         )
         if not is_known_good_domain:
             # Try to resolve the domain and connect to its SMTP server(s).
-            bypass_error = state['request'].body.get('email.bypass_error') == 'yes'
             try:
                 test_email_domain(email.domain)
             except EmailAddressError as e:
+                request = state.get('request')
+                if request:
+                    bypass_error = request.body.get('email.bypass_error') == 'yes'
+                else:
+                    bypass_error = False
                 if not (bypass_error and e.bypass_allowed):
                     raise
             except Exception as e:
@@ -192,6 +196,7 @@ def test_email_domain(domain: str):
         NonEmailDomain: if the domain doesn't accept email (RFC 7505)
 
     """
+    start_time = time.monotonic()
     try:
         ip_addresses = get_email_server_addresses(domain)
         exceptions = []
@@ -212,6 +217,9 @@ def test_email_domain(domain: str):
             n_attempts += 1
             if n_attempts >= 3:
                 break
+            time_elapsed = time.monotonic() - start_time
+            if time_elapsed >= website.app_conf.socket_timeout:
+                break
         if not success:
             if n_ip_addresses == 0:
                 raise BrokenEmailDomain(domain, (
@@ -308,7 +316,7 @@ def test_email_server(ip_address: str) -> None:
                                 both correctly and quickly enough
 
     """
-    smtp = SMTP(timeout=website.app_conf.socket_timeout)
+    smtp = SMTP(timeout=5.0)
     if website.env.logging_level == 'debug':
         smtp.set_debuglevel(2)
     try:
@@ -395,7 +403,7 @@ def handle_email_bounces():
                 _handle_ses_notification(msg)
             except Exception as e:
                 website.tell_sentry(e, {})
-        sleep(1)
+        time.sleep(1)
 
 
 def _handle_ses_notification(msg):


Test patch:
Repository: liberapay/liberapay.com

Issue:
Unlabeled avatar header and menu.
When logged in, there is an unlabeled button and an unlabeled graphic. The button opens up a menu, it looks like.

avatar-default etag=.HVo94CoZc…

Right after that is the unlabeled button.
  


Discussion:

Resolving patch:
diff --git a/liberapay/i18n/base.py b/liberapay/i18n/base.py
--- a/liberapay/i18n/base.py
+++ b/liberapay/i18n/base.py
@@ -342,6 +342,12 @@ def make_sorted_dict(keys, d):
     sr ss st sv sw ta te tg th ti tn to tr ts uk ur uz ve vi vo xh yo zh zu
 """.split()
 
+Locale.LANGUAGE_NAMES = {
+    code: babel.localedata.load(code)['languages'][code]
+    for code in LANGUAGE_CODES_2
+    if babel.localedata.exists(code)
+}
+
 LANGUAGES_2 = make_sorted_dict(LANGUAGE_CODES_2, Locale('en').languages)
 
 LOCALES = {}
diff --git a/liberapay/wireup.py b/liberapay/wireup.py
--- a/liberapay/wireup.py
+++ b/liberapay/wireup.py
@@ -10,6 +10,7 @@
 from time import time
 import traceback
 
+import babel.localedata
 from babel.messages.pofile import read_po
 from babel.numbers import parse_pattern
 import boto3
@@ -699,6 +700,14 @@ def load_i18n(canonical_host, canonical_scheme, project_root, tell_sentry):
             tell_sentry(e, {})
     del source_strings
 
+    # Unload the Babel data that we no longer need
+    # We load a lot of data to populate the LANGUAGE_NAMES dict, we don't want
+    # to keep it all in RAM.
+    used_data_dict_addresses = set(id(l._data._data) for l in locales.values())
+    for key, data_dict in list(babel.localedata._cache.items()):
+        if id(data_dict) not in used_data_dict_addresses:
+            del babel.localedata._cache[key]
+
     # Prepare a unique and sorted list for use in the language switcher
     percent = lambda l, total: sum((percent(s, len(s)) if isinstance(s, tuple) else 1) for s in l if s) / total
     for l in list(locales.values()):


Test patch:
Repository: liberapay/liberapay.com

Issue:
The username change warning isn't clear enough
<https://mastodonten.de/@scroom/100724362756380264>:

> [@Liberapay](https://mastodon.xyz/@Liberapay) I have a question about existing links to donation accounts: I changed my name and then I got a hint that I had to change the donation links. So far the old link still works. Will it be turned off at some point?
>
> https://liberapay.com/~32819/donate


Discussion:

Resolving patch:
diff --git a/liberapay/constants.py b/liberapay/constants.py
--- a/liberapay/constants.py
+++ b/liberapay/constants.py
@@ -330,6 +330,10 @@ def __missing__(self, currency):
     },
 }
 
+PAYIN_SETTLEMENT_DELAYS = {
+    'stripe-sdd': timedelta(days=6),
+}
+
 PAYMENT_METHODS = {
     'mango-ba': _("Direct Debit"),
     'mango-bw': _("Bank Wire"),


Test patch:
diff --git a/tests/py/test_settings.py b/tests/py/test_settings.py
--- a/tests/py/test_settings.py
+++ b/tests/py/test_settings.py
@@ -52,12 +52,26 @@ def test_team_participant_doesnt_show_up_on_explore_teams(self):
 
 class TestUsername(Harness):
 
+    def test_participant_can_set_username(self):
+        alice = self.make_participant(None)
+        r = self.client.POST(
+            f'/~{alice.id}/edit/username', {'username': 'alice'},
+            auth_as=alice, raise_immediately=False
+        )
+        assert r.code == 302
+        assert r.headers[b'Location'].startswith(b'/alice/edit/username')
+        alice = alice.refetch()
+        assert alice.username == 'alice'
+
     def change_username(self, new_username, auth_as='alice'):
         if auth_as:
             auth_as = self.make_participant(auth_as)
 
-        r = self.client.POST('/alice/edit/username', {'username': new_username},
-                             auth_as=auth_as, raise_immediately=False)
+        r = self.client.POST(
+            '/alice/edit/username',
+            {'username': new_username, 'confirmed': 'true'},
+            auth_as=auth_as, raise_immediately=False,
+        )
         return r
 
     def test_participant_can_change_their_username(self):
@@ -111,6 +125,10 @@ def test_change_team_name(self):
         team.add_member(bob)
         r = self.client.POST('/team/edit/username', {'username': 'Team'},
                              auth_as=alice, raise_immediately=False)
+        assert r.code == 200
+        assert ">Confirm</button>" in r.text
+        r = self.client.POST('/team/edit/username', {'username': 'Team', 'confirmed': 'true'},
+                             auth_as=alice, raise_immediately=False)
         assert r.code == 302
         assert r.headers[b'Location'].startswith(b'/Team/edit/username')
         team = team.refetch()
Repository: liberapay/liberapay.com

Issue:
Allow custom amount from GET parameter in donation form
Bonjour, j'avais envie de proposer aux utilisateurs de Meta-Press.es de faire un don d'un centime par résultat trouvé lors d'une recherche (enfin, de résultats effectivement rappatriés).

Du coup, je regardais la page : https://liberapay.com/Meta-Press.es/donate et je rêvais qu'il soit possible d'ajouter un paramètre à l'URL pour pré-remplir le champs Custom amount…

J'aurais alors fait un lien du genre : 
- https://liberapay.com/Meta-Press.es/donate?amount=3.14

Pour proposer un don personnalisé de 3,14€ 

C'est amusant comme idée non ?



Discussion:
For the non-French readers:

----

Hello, I wanted to propose to Meta-Press.es users to donate one cent per result found during a search (well, results actually returned).

So, I was looking at the page: https://liberapay.com/Meta-Press.es/donate and I dreamed that it would be possible to add a parameter to the URL to pre-fill the Custom amount field...

Then I would have made a connection like this:

- https://liberapay.com/Meta-Press.es/donate?amount=3.14

To propose a personalized donation of 3,14€.

It's a fun idea, isn't it?

Resolving patch:
diff --git a/liberapay/main.py b/liberapay/main.py
--- a/liberapay/main.py
+++ b/liberapay/main.py
@@ -255,6 +255,10 @@ def check_payin_allowed(website, request, user, method=None):
     raise Warning('aspen.http.mapping.Mapping.get_int() already exists')
 aspen.http.mapping.Mapping.get_int = utils.get_int
 
+if hasattr(aspen.http.mapping.Mapping, 'get_money_amount'):
+    raise Warning('aspen.http.mapping.Mapping.get_money_amount() already exists')
+aspen.http.mapping.Mapping.get_money_amount = utils.get_money_amount
+
 if hasattr(aspen.http.mapping.Mapping, 'get_choice'):
     raise Warning('aspen.http.mapping.Mapping.get_choice() already exists')
 aspen.http.mapping.Mapping.get_choice = utils.get_choice
diff --git a/liberapay/utils/__init__.py b/liberapay/utils/__init__.py
--- a/liberapay/utils/__init__.py
+++ b/liberapay/utils/__init__.py
@@ -475,6 +475,16 @@ def get_int(d, k, default=NO_DEFAULT, minimum=None, maximum=None):
     return r
 
 
+def get_money_amount(d, k, currency, default=NO_DEFAULT):
+    try:
+        r = d[k]
+    except (KeyError, Response):
+        if default is NO_DEFAULT:
+            raise
+        return default
+    return LOCALE_EN.parse_money_amount(r, currency)
+
+
 def get_choice(d, k, choices, default=NO_DEFAULT):
     try:
         r = d[k]


Test patch:
Repository: liberapay/liberapay.com

Issue:
Inconsistent language for receipts
I had them in a language that was not the one I need to show them to the tax administration (if I need to someday) so I changed my Liberapay and browser requested language to french but part of receipts are still in english.

examples:
https://fr.liberapay.com/tuxayo/receipts/direct/2260 => english
https://fr.liberapay.com/tuxayo/receipts/direct/2259 => french
Inconsistent language for receipts
I had them in a language that was not the one I need to show them to the tax administration (if I need to someday) so I changed my Liberapay and browser requested language to french but part of receipts are still in english.

examples:
https://fr.liberapay.com/tuxayo/receipts/direct/2260 => english
https://fr.liberapay.com/tuxayo/receipts/direct/2259 => french


Discussion:

Resolving patch:
diff --git a/liberapay/main.py b/liberapay/main.py
--- a/liberapay/main.py
+++ b/liberapay/main.py
@@ -273,7 +273,7 @@ def _Querystring_derive(self, **kw):
     new_qs = aspen.http.mapping.Mapping(self)
     for k, v in kw.items():
         if v is None:
-            new_qs.pop(k, None)
+            new_qs.popall(k, None)
         else:
             new_qs[k] = v
     return '?' + urlencode(new_qs, doseq=True)
diff --git a/liberapay/wireup.py b/liberapay/wireup.py
--- a/liberapay/wireup.py
+++ b/liberapay/wireup.py
@@ -751,6 +751,12 @@ def load_i18n(canonical_host, canonical_scheme, project_root, tell_sentry):
     for k, v in list(locales.items()):
         locales.setdefault(k.split('_', 1)[0], v)
 
+    # Add universal strings
+    # These strings don't need to be translated, but they have to be in the catalogs
+    # so that they're counted as translated.
+    for l in locales.values():
+        l.catalog.add("PayPal", "PayPal")
+
     # Patch the locales to look less formal
     locales['fr'].currency_formats['standard'] = parse_pattern('#,##0.00\u202f\xa4')
     locales['fr'].currencies['USD'] = 'dollar états-unien'


Test patch:
Repository: liberapay/liberapay.com

Issue:
Obsolete browser warning
We don't support obsolete browsers like IE ≤ 8, but we don't say it anywhere. It would be good if we displayed a warning to visitors that appear to be using obsolete software.
Obsolete browser warning
We don't support obsolete browsers like IE ≤ 8, but we don't say it anywhere. It would be good if we displayed a warning to visitors that appear to be using obsolete software.


Discussion:

Resolving patch:
diff --git a/liberapay/main.py b/liberapay/main.py
--- a/liberapay/main.py
+++ b/liberapay/main.py
@@ -47,8 +47,8 @@
 from liberapay.utils.emails import clean_up_emails, handle_email_bounces
 from liberapay.utils.state_chain import (
     attach_environ_to_request, create_response_object, reject_requests_bypassing_proxy,
-    canonize, insert_constants, enforce_rate_limits, set_output_to_None,
-    add_content_disposition_header, merge_responses,
+    canonize, detect_obsolete_browsers, insert_constants, enforce_rate_limits,
+    set_output_to_None, add_content_disposition_header, merge_responses,
     bypass_csp_for_form_redirects, delegate_error_to_simplate, return_500_for_exception,
     turn_socket_error_into_50X, overwrite_status_code_of_gateway_errors,
 )
@@ -188,6 +188,8 @@ def _assert(x):
     authentication.authenticate_user_if_possible,
     add_currency_to_state,
 
+    detect_obsolete_browsers,
+
     algorithm['dispatch_path_to_filesystem'],
     algorithm['raise_404_if_missing'],
 
diff --git a/liberapay/utils/state_chain.py b/liberapay/utils/state_chain.py
--- a/liberapay/utils/state_chain.py
+++ b/liberapay/utils/state_chain.py
@@ -84,6 +84,25 @@ def canonize(request, website):
         response.redirect(url)
 
 
+def detect_obsolete_browsers(request, response, state):
+    """Respond with a warning message if the user agent seems to be obsolete.
+    """
+    if b'MSIE' in request.headers.get(b'User-Agent', b''):
+        cookie = request.headers.cookie.get('obsolete_browser_warning')
+        if cookie and cookie.value == 'ignore':
+            return
+        if request.method == 'POST':
+            try:
+                action = request.body.get('obsolete-browser-warning')
+            except Exception:
+                pass
+            else:
+                if action == 'ignore':
+                    response.headers.cookie['obsolete_browser_warning'] = 'ignore'
+                    return
+        raise response.render('simplates/obsolete-browser-warning.spt', state)
+
+
 def insert_constants():
     return {'constants': constants}
 


Test patch:
Repository: liberapay/liberapay.com

Issue:
Limit the input field for team names
The first step when creating a team at https://liberapay.com/about/teams is selecting a name. I tried to enter a name and it was rejected because it was too long. The input field name currently accepts 30 characters. I suggest to reduce it to the maximum allowed characters for team names.



Discussion:
I guess line 95 in https://github.com/liberapay/liberapay.com/blob/ca814ed2478108b119fef4498a8ee521a5553914/www/about/teams.spt#L95

should be changed to something like

`    <input class="form-control" name="name" size=30 maxlength=USERNAME_MAX_SIZE`

Resolving patch:
diff --git a/liberapay/wireup.py b/liberapay/wireup.py
--- a/liberapay/wireup.py
+++ b/liberapay/wireup.py
@@ -265,6 +265,7 @@ class AppConf:
         smtp_password=str,
         smtp_use_tls=bool,
         stripe_callback_secret=str,
+        stripe_connect_callback_secret=str,
         stripe_connect_id=str,
         stripe_publishable_key=str,
         stripe_secret_key=str,


Test patch:
Repository: liberapay/liberapay.com

Issue:
Cloudflare reports that the server is down
Since today's morning (for me), Cloudflare has been reporting that the server is down, and I cannot access the website or anything related to Liberapay. Some hours ago, I saw the website was working, but I just tried again, and it's not working.

![image](https://user-images.githubusercontent.com/51391473/121968737-7afa0380-cd38-11eb-9061-5c28c47524a9.png)

Have there been any server-related issues recently?
Thanks for reading, folks. 😄



Discussion:

Resolving patch:
diff --git a/liberapay/main.py b/liberapay/main.py
--- a/liberapay/main.py
+++ b/liberapay/main.py
@@ -59,6 +59,7 @@
     enforce_rate_limits,
     insert_constants,
     merge_responses,
+    no_response_body_for_HEAD_requests,
     overwrite_status_code_of_gateway_errors,
     raise_response_to_OPTIONS_request,
     return_500_for_exception,
@@ -236,6 +237,7 @@ def default_body_parser(body_bytes, headers):
     csrf.add_token_to_response,
     http_caching.add_caching_to_response,
     overwrite_status_code_of_gateway_errors,
+    no_response_body_for_HEAD_requests,
 
     tell_sentry,
     return_500_for_exception,
diff --git a/liberapay/utils/state_chain.py b/liberapay/utils/state_chain.py
--- a/liberapay/utils/state_chain.py
+++ b/liberapay/utils/state_chain.py
@@ -277,3 +277,15 @@ def overwrite_status_code_of_gateway_errors(response):
     """
     if response.code in (502, 504):
         response.code = 500
+
+
+def no_response_body_for_HEAD_requests(response, request=None, exception=None):
+    """This function ensures that we only return headers in response to a HEAD request.
+
+    Gunicorn, Pando and Aspen currently all fail to prevent a body from being sent
+    in a response to a HEAD request, even though the HTTP spec clearly states that
+    a “server MUST NOT send a message body in the response [to a HEAD request]”:
+    https://datatracker.ietf.org/doc/html/rfc7231#section-4.3.2
+    """
+    if request and request.method == 'HEAD' and response.body:
+        response.body = b''


Test patch:
Repository: liberapay/liberapay.com

Issue:
Commas with Conditional Sentences
I've seen a bunch of sentences that don't have a comma after the dependent clause (`if`); they should. See:

- https://www.ego4u.com/en/cram-up/writing/comma?10
- https://www.grammarly.com/blog/conditional-sentences/
- https://english.stackexchange.com/questions/6786/comma-in-conditional-sentence-and-in-antithesis

You can use `sed -n '/\<if\>/Ip' i18n/core/es.po` to get a list of all sentences that use the word 'if' or 'If'.


Discussion:

Resolving patch:
diff --git a/liberapay/exceptions.py b/liberapay/exceptions.py
--- a/liberapay/exceptions.py
+++ b/liberapay/exceptions.py
@@ -592,7 +592,7 @@ class UnableToSendEmail(LazyResponseXXX):
     def msg(self, _):
         return _(
             "The attempt to send an email to {email_address} failed. Please "
-            "check that the address is valid and retry. If the problem persists "
+            "check that the address is valid and retry. If the problem persists, "
             "please contact support@liberapay.com.", email_address=self.args[0]
         )
 


Test patch:
Repository: liberapay/liberapay.com

Issue:
Can't see the patrons from a team I'm belong to
Now that #2100 is fixed, I can see this when enabling the new functionality:

![liberapay-patrons-display-bug](https://user-images.githubusercontent.com/8705846/145708100-cb26faa6-303c-498a-9f4d-bf6e28be6b13.png)

That said, if I'm clicking on the "View the patrons of LibraZiK" button, I'm getting this error:

![liberapay-patrons-display-bug-2](https://user-images.githubusercontent.com/8705846/145708116-6574382d-99a6-46bd-8e6c-979fce4f2a79.png)

Am I missing any step?


Discussion:

Resolving patch:
diff --git a/liberapay/models/participant.py b/liberapay/models/participant.py
--- a/liberapay/models/participant.py
+++ b/liberapay/models/participant.py
@@ -2639,7 +2639,7 @@ def set_tip_to(self, tippee, periodic_amount, period='weekly', renewal_mode=None
                           )
                         , coalesce(
                               %(visibility)s,
-                              (SELECT visibility FROM current_tip),
+                              (SELECT abs(visibility) FROM current_tip),
                               1
                           ) )
               RETURNING tips
@@ -3299,9 +3299,6 @@ def get_giving_details(self):
                      , t.renewal_mode
                      , t.visibility
                      , p.payment_providers
-                     , ( t.paid_in_advance IS NULL OR
-                         t.paid_in_advance < (t.amount * 3)
-                       ) AS awaits_payment
                   FROM current_tips t
                   JOIN participants p ON p.id = t.tippee
                  WHERE t.tipper = %s
@@ -3334,7 +3331,7 @@ def get_giving_details(self):
 
         return tips, pledges
 
-    def get_tips_awaiting_payment(self):
+    def get_tips_awaiting_payment(self, weeks_early=3):
         """Fetch a list of the user's donations that need to be renewed, and
         determine if some of them can be grouped into a single charge.
 
@@ -3357,7 +3354,7 @@ def get_tips_awaiting_payment(self):
              WHERE t.tipper = %s
                AND t.renewal_mode > 0
                AND ( t.paid_in_advance IS NULL OR
-                     t.paid_in_advance < (t.amount * 3)
+                     t.paid_in_advance < (t.amount * %s)
                    )
                AND p.status = 'active'
                AND ( p.goal IS NULL OR p.goal >= 0 )
@@ -3378,7 +3375,7 @@ def get_tips_awaiting_payment(self):
                    ) NULLS FIRST
                  , (t.paid_in_advance).amount / (t.amount).amount NULLS FIRST
                  , t.ctime
-        """, (self.id,))
+        """, (self.id, weeks_early))
         return self.group_tips_into_payments(tips)
 
     def group_tips_into_payments(self, tips):


Test patch: