Repository: liberapay/liberapay.com

Issue:
Goal page is not accessible once connected
"405 Method Not Allowed"
on this page 
https://liberapay.com/unisson/goal.html when i want to change my goal
I'm connected on my account.

Goal page is not accessible once connected
"405 Method Not Allowed"
on this page 
https://liberapay.com/unisson/goal.html when i want to change my goal
I'm connected on my account.



Discussion:
I'm confused as to how you ended up in this situation @SimonSarazin, changing a team's goal works fine.

I've made a change that may prevent this, reopen if it ever happens again.

Looks like I misunderstood the problem, @Zatalyz is reporting the same issue.

The same, but with 403 error. I can't modify goal.

Okay, I've found the problem, and why I wasn't able to see it, so now I can really fix it.

I'm confused as to how you ended up in this situation @SimonSarazin, changing a team's goal works fine.

I've made a change that may prevent this, reopen if it ever happens again.

Looks like I misunderstood the problem, @Zatalyz is reporting the same issue.

The same, but with 403 error. I can't modify goal.

Okay, I've found the problem, and why I wasn't able to see it, so now I can really fix it.


Resolving patch:
diff --git a/liberapay/utils/__init__.py b/liberapay/utils/__init__.py
--- a/liberapay/utils/__init__.py
+++ b/liberapay/utils/__init__.py
@@ -6,6 +6,8 @@
 from datetime import date, datetime, timedelta
 import re
 
+from six.moves.urllib.parse import quote as urlquote
+
 from aspen import Response, json
 from aspen.utils import to_rfc822, utcnow
 from markupsafe import Markup
@@ -13,6 +15,7 @@
 
 import liberapay
 from liberapay.exceptions import AuthRequired
+from liberapay.models.community import Community
 from liberapay.utils.i18n import Money
 
 
@@ -74,6 +77,30 @@ def get_participant(state, restrict=True, redirect_stub=True, allow_member=False
     return participant
 
 
+def get_community(state, restrict=False):
+    request, response = state['request'], state['response']
+    user = state['user']
+    name = request.path['name']
+
+    c = Community.from_name(name)
+    if request.method in ('GET', 'HEAD'):
+        if not c:
+            response.redirect('/for/new?name=' + urlquote(name))
+        if c.name != name:
+            response.redirect('/for/' + c.name + request.line.uri[5+len(name):])
+    elif not c:
+        raise Response(404)
+
+    if restrict:
+        if user.ANON:
+            raise AuthRequired
+        if user.id != c.creator and not user.is_admin:
+            _ = state['_']
+            raise Response(403, _("You are not authorized to access this page."))
+
+    return c
+
+
 def b64decode_s(s, **kw):
     udecode = lambda a: a.decode('utf8')
     if s[:1] == b'.':


Test patch:
diff --git a/tests/py/test_communities.py b/tests/py/test_communities.py
--- a/tests/py/test_communities.py
+++ b/tests/py/test_communities.py
@@ -86,6 +86,26 @@ def test_subscribe_and_unsubscribe(self):
         assert len(json.loads(response.body)) == 0
 
 
+class TestCommunityEdit(Harness):
+
+    def setUp(self):
+        Harness.setUp(self)
+        self.alice = self.make_participant("alice")
+        self.community = Community.create('test', self.alice.id)
+
+    def test_creator_can_edit_community(self):
+        data = {'lang': 'en', 'subtitle': '', 'sidebar': ''}
+        response = self.client.POST('/for/test/edit', data, auth_as=self.alice)
+        assert response.code == 200
+
+    def test_others_cant_edit_community(self):
+        response = self.client.PxST('/for/test/edit')
+        assert response.code == 403
+        bob = self.make_participant('bob')
+        response = self.client.PxST('/for/test/edit', auth_as=bob)
+        assert response.code == 403
+
+
 class TestForCommunityJson(Harness):
 
     def setUp(self):
diff --git a/tests/py/test_goal.py b/tests/py/test_goal.py
--- a/tests/py/test_goal.py
+++ b/tests/py/test_goal.py
@@ -55,3 +55,14 @@ def test_change_goal(self):
           ORDER BY ts DESC
         """)
         assert actual == ['400', None, '1100.00', '0', '100']
+
+    def test_team_member_can_change_team_goal(self):
+        team = self.make_participant('team', kind='group')
+        team.add_member(self.alice)
+        r = self.client.PxST(
+            '/team/goal',
+            {'goal': 'custom', 'goal_custom': '99.99'},
+            auth_as=self.alice
+        )
+        assert r.code == 302
+        assert team.refetch().goal == Decimal('99.99')