Repository: liberapay/liberapay.com

Issue:
Internal Server Error when create community
I have more "Internal Server Error" about community. 

first, when I create a community (here "Jeux_vidéos", with "french" language), i'm redirected on https://liberapay.com/for/new but this page is only with "Internal Server Error".

But, community is created ; I can see it when I search. 

I join it, and again : "Internal Server Error" when I join. Again, despite error, I have join this community.

So : it's work, but it display a terrifying error :-D

Internal Server Error when create community
I have more "Internal Server Error" about community. 

first, when I create a community (here "Jeux_vidéos", with "french" language), i'm redirected on https://liberapay.com/for/new but this page is only with "Internal Server Error".

But, community is created ; I can see it when I search. 

I join it, and again : "Internal Server Error" when I join. Again, despite error, I have join this community.

So : it's work, but it display a terrifying error :-D



Discussion:

Resolving patch:
diff --git a/liberapay/billing/exchanges.py b/liberapay/billing/exchanges.py
--- a/liberapay/billing/exchanges.py
+++ b/liberapay/billing/exchanges.py
@@ -220,7 +220,7 @@ def charge(db, participant, amount, return_url):
         return record_exchange_result(db, e_id, 'failed', error, participant)
 
     if payin.ExecutionDetails.SecureModeRedirectURL:
-        raise Response(302, headers={'Location': payin.ExecutionDetails.SecureModeRedirectURL})
+        raise Response().redirect(payin.ExecutionDetails.SecureModeRedirectURL)
 
     return record_exchange_result(db, e_id, payin.Status.lower(), repr_error(payin), participant)
 
diff --git a/liberapay/main.py b/liberapay/main.py
--- a/liberapay/main.py
+++ b/liberapay/main.py
@@ -1,5 +1,7 @@
 from __future__ import division
 
+import string
+
 from six.moves import builtins
 from six.moves.urllib.parse import quote as urlquote
 
@@ -7,6 +9,7 @@
 import aspen.http.mapping
 import pando
 from pando.algorithms.website import fill_response_with_output
+from pando.utils import maybe_encode
 
 from liberapay import canonize, insert_constants, utils, wireup
 from liberapay.cron import Cron
@@ -136,19 +139,17 @@ def return_500_for_exception(website, exception):
 # Monkey patch aspen and pando
 # ============================
 
-pop = aspen.http.mapping.Mapping.pop
-def _pop(self, name, default=aspen.http.mapping.NO_DEFAULT):
-    try:
-        return pop(self, name, default)
-    except KeyError:
-        raise aspen.Response(400, "Missing key: %s" % repr(name))
-aspen.http.mapping.Mapping.pop = _pop
+if hasattr(pando.Response, 'encode_url'):
+    raise Warning('pando.Response.encode_url() already exists')
+def _encode_url(url):
+    return maybe_encode(urlquote(maybe_encode(url, 'utf8'), string.punctuation))
+pando.Response.encode_url = staticmethod(_encode_url)
 
 if hasattr(pando.Response, 'redirect'):
     raise Warning('pando.Response.redirect() already exists')
 def _redirect(response, url, code=302):
     response.code = code
-    response.headers['Location'] = url
+    response.headers['Location'] = response.encode_url(url)
     raise response
 pando.Response.redirect = _redirect
 
diff --git a/liberapay/utils/__init__.py b/liberapay/utils/__init__.py
--- a/liberapay/utils/__init__.py
+++ b/liberapay/utils/__init__.py
@@ -35,6 +35,7 @@ def get_participant(state, restrict=True, redirect_stub=True, allow_member=False
 
     """
     request = state['request']
+    response = state['response']
     user = state['user']
     slug = request.line.uri.path['username']
     _ = state['_']
@@ -60,7 +61,7 @@ def get_participant(state, restrict=True, redirect_stub=True, allow_member=False
     if request.method in ('GET', 'HEAD'):
         if slug != participant.username:
             canon = '/' + participant.username + request.line.uri[len(slug)+1:]
-            raise Response(302, headers={'Location': canon})
+            raise response.redirect(canon)
 
     status = participant.status
     if status == 'closed':
@@ -71,7 +72,7 @@ def get_participant(state, restrict=True, redirect_stub=True, allow_member=False
         if redirect_stub:
             to = participant.resolve_stub()
             assert to
-            raise Response(302, headers={'Location': to})
+            raise response.redirect(to)
 
     if restrict:
         if participant != user:


Test patch: