Repository: liberapay/liberapay.com

Issue:
TooMany exception when logging in with email as id
https://sentry.changaco.oy.lc/share/issue/322e3530/

Basically the SQL query in `participant.py` is wrong, we need a failing test and a fix.



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
@@ -158,6 +158,8 @@ def _from_thing(cls, thing, value):
                   JOIN participants p ON p.id = e.participant
                  WHERE e.address = %s
                    AND (p.email IS NULL OR p.email = e.address)
+              ORDER BY p.email NULLS LAST, p.id ASC
+                 LIMIT 1
             """, (value,))
         return cls.db.one("""
             SELECT participants.*::participants


Test patch:
diff --git a/liberapay/testing/__init__.py b/liberapay/testing/__init__.py
--- a/liberapay/testing/__init__.py
+++ b/liberapay/testing/__init__.py
@@ -198,6 +198,12 @@ def make_participant(self, username, **kw):
                  VALUES (%s,%s,%s,%s)
         """, (platform, participant.id, username, participant.id))
 
+        if 'email' in kw:
+            self.db.run("""
+                INSERT INTO emails
+                            (participant, address, verified, verified_time)
+                     VALUES (%s, %s, true, now())
+            """, (participant.id, kw['email']))
         if 'last_bill_result' in kw2:
             ExchangeRoute.insert(participant, 'mango-cc', '-1', kw2['last_bill_result'])
         if 'balance' in kw2 and kw2['balance'] != 0:
diff --git a/tests/py/test_close.py b/tests/py/test_close.py
--- a/tests/py/test_close.py
+++ b/tests/py/test_close.py
@@ -278,7 +278,10 @@ def test_cpi_clears_personal_information(self):
         assert alice.npatrons == new_alice.npatrons == 0
         assert alice.session_token == new_alice.session_token == None
         assert alice.session_expires.year == new_alice.session_expires.year == date.today().year
-        assert not alice.get_emails()
+        emails = alice.get_emails()
+        assert len(emails) == 1
+        assert emails[0].address == 'alice@example.com'
+        assert emails[0].verified
 
     def test_cpi_clears_communities(self):
         alice = self.make_participant('alice')
diff --git a/tests/py/test_sign_in.py b/tests/py/test_sign_in.py
--- a/tests/py/test_sign_in.py
+++ b/tests/py/test_sign_in.py
@@ -32,6 +32,9 @@ def log_in(self, username, password, **kw):
 
     def log_in_and_check(self, p, password, **kw):
         r = self.log_in(p.username, password, **kw)
+        return self.check_login(r, p)
+
+    def check_login(self, r, p):
         p = p.refetch()
         # Basic checks
         assert r.code == 302
@@ -56,6 +59,16 @@ def test_log_in(self):
         alice.update_password(password)
         self.log_in_and_check(alice, password)
 
+    def test_log_in_with_email_as_id(self):
+        email = 'alice@example.net'
+        password = 'password'
+        alice = self.make_participant('alice')
+        alice.add_email(email)
+        bob = self.make_participant('bob', email=email)
+        bob.update_password(password)
+        r = self.log_in(email, password)
+        self.check_login(r, bob)
+
     def test_log_in_with_old_session(self):
         alice = self.make_participant('alice')
         alice.update_session('x', utcnow() - timedelta(days=1))