We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Signing in from RSR Up fails with error 'Unable to authorize:'
Login for a user who has `rsr.change_project` permissions for a lot of projects, but is not an `rsr_admin` can timeout. This piece of code seems like the [culprit code](https://github.com/akvo/akvo-rsr/blob/5a07b31d1c272f2014e5eb3209f23506aa6e91f1/akvo/rsr/views/account.py#L273). 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `akvo/rsr/views/account.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 """Akvo RSR is covered by the GNU Affero General Public License.
4 
5 See more details in the license.txt file located at the root folder of the
6 Akvo RSR module. For additional details on the GNU license please
7 see < http://www.gnu.org/licenses/agpl.html >.
8 """
9 
10 import re
11 import json
12 
13 from lxml import etree
14 from tastypie.models import ApiKey
15 
16 from akvo.rsr.forms import RegisterForm, InvitedUserForm
17 from akvo.rsr.models import Employment
18 from akvo.utils import rsr_send_mail
19 
20 from django.conf import settings
21 from django.contrib.auth import login, logout, authenticate, get_user_model
22 from django.contrib.auth.forms import AuthenticationForm, PasswordResetForm
23 from django.core.exceptions import ObjectDoesNotExist
24 from django.core.signing import TimestampSigner, BadSignature
25 from django.http import (HttpResponse, HttpResponseRedirect,
26                          HttpResponseForbidden)
27 from django.shortcuts import redirect, render, render_to_response
28 from django.template import RequestContext
29 
30 from registration.models import RegistrationProfile
31 
32 from django.views.decorators.csrf import csrf_exempt
33 from django.views.decorators.http import require_POST
34 
35 
36 def register(request):
37     """Register form."""
38     context = RequestContext(request)
39     if request.method == 'POST':
40         form = RegisterForm(data=request.POST, files=request.FILES)
41         if form.is_valid():
42             user = form.save(request)
43             return render_to_response('registration/register_complete.html',
44                                       {'new_user': user},
45                                       context_instance=context)
46     else:
47         form = RegisterForm()
48     return render_to_response('registration/register.html', {'form': form},
49                               context_instance=context)
50 
51 
52 def activate(request, activation_key, extra_context=None):
53     """Activate resouce.
54 
55     Activate a User's account, if their key is valid and hasn't expired.
56     Any values passed in the keyword argument "extra_context"
57     (which must be a dictionary) will be added to the context.
58     Any values in "extra_context" which are callable will be called prior to
59     being added to the context.
60     """
61     sha = re.compile('^[a-f0-9]{40}$')
62     activation_key = activation_key.lower()
63 
64     if sha.search(activation_key):
65         try:
66             registration_profile = RegistrationProfile.objects.get(
67                 activation_key=activation_key)
68         except RegistrationProfile.DoesNotExist:
69             user = False
70         else:
71             if not registration_profile.activation_key_expired():
72                 registration_profile.activation_key = RegistrationProfile.ACTIVATED
73                 registration_profile.save()
74                 user = registration_profile.user
75                 user.is_active = True
76                 user.save()
77 
78                 # Log in user without password, using custom backend
79                 user = authenticate(username=user.username, no_password=True)
80                 login(request, user)
81     if extra_context is None:
82         extra_context = {}
83     context = RequestContext(request)
84     for key, value in extra_context.items():
85         context[key] = callable(value) and value() or value
86     return render_to_response(
87         'registration/activate.html',
88         context_instance=context
89     )
90 
91 
92 def invite_activate(request, inviting_pk, user_pk, employment_pk, token_date, token):
93     """
94     Activate a user that has been invited to use RSR.
95 
96     :param request: the request
97     :param inviting_pk: the invitee user's primary key
98     :param user_pk: the invited user's primary key
99     :param employment_pk: the employment's primary key
100     :param token_date: the first part of the token
101     :param token: the second part of the token
102     """
103 
104     def approve_employment(invitee, invited, empl):
105         """
106         Approves the employment and sends a mail to the user that has invited the new user.
107 
108         :param invitee: the invitee user's instance
109         :param invited: the invited user's instance
110         :param empl: the employment's instance
111         """
112         empl.approve(invitee)
113 
114         if invitee:
115             # Send notification email to inviting user
116             rsr_send_mail(
117                 [invitee.email],
118                 subject='registration/inviting_user_notification_subject.txt',
119                 message='registration/inviting_user_notification_message.txt',
120                 html_message='registration/inviting_user_notification_message.html',
121                 subject_context={
122                     'user': invited,
123                 },
124                 msg_context={
125                     'invited_user': invited,
126                     'inviting_user': invitee,
127                     'organisation': empl.organisation,
128                 }
129             )
130 
131     def login_and_redirect(req, invited):
132         """
133         Log the invited user in and redirect to the My details page in MyRSR.
134 
135         :param req: the request
136         :param invited: the invited user's instance
137         """
138         invited = authenticate(username=invited.username, no_password=True)
139         login(request, invited)
140         return redirect('my_details')
141 
142     bad_link, user, inviting_user, employment = False, None, None, None
143 
144     try:
145         user = get_user_model().objects.get(pk=user_pk)
146         inviting_user = get_user_model().objects.get(pk=inviting_pk)
147         employment = Employment.objects.get(pk=employment_pk)
148     except ObjectDoesNotExist:
149         bad_link = True
150 
151     try:
152         TimestampSigner().unsign(':'.join([user.email, token_date, token]))
153     except BadSignature:
154         bad_link = True
155 
156     if user and user.is_active:
157         if employment and employment.is_approved:
158             # User is active and employment is approved, so nothing to do here
159             return login_and_redirect(request, user)
160         elif employment and not bad_link:
161             # Employment is not yet approved, and link is ok.
162             # Approve employment and log user in.
163             approve_employment(inviting_user, user, employment)
164             return login_and_redirect(request, user)
165 
166     if request.method == 'POST':
167         form = InvitedUserForm(user=user, data=request.POST)
168         if form.is_valid():
169             # Approve employment and save new user details
170             form.save(request)
171             approve_employment(inviting_user, user, employment)
172             return login_and_redirect(request, user)
173     else:
174         form = InvitedUserForm(user=user)
175 
176     context = {
177         'form': form,
178         'bad_link': bad_link,
179     }
180     return render(request, 'registration/invite_activate.html', context)
181 
182 
183 def sign_in(request):
184     """Sign in.
185 
186     POST have two variants with username & email:
187      - username > normal sign in
188      - email > password reset workflow
189     """
190     context = RequestContext(request)
191     form = AuthenticationForm()
192     reset_form = PasswordResetForm()
193     if request.method == "POST" and 'username' in request.POST:
194         form = AuthenticationForm(data=request.POST)
195         if form.is_valid():
196             login(request, form.get_user())
197             next_page = request.GET.get('next')
198             return HttpResponseRedirect(next_page) if next_page else redirect('my_details')
199     # Password reset on sign in page
200     elif request.method == "POST" and 'email' in request.POST:
201         reset_form = PasswordResetForm(data=request.POST)
202         if reset_form.is_valid():
203             reset_form.save(domain_override=settings.RSR_DOMAIN)
204         return HttpResponse()
205     return render_to_response('sign_in.html', {'form': form, 'reset_form': reset_form},
206                               context_instance=context)
207 
208 
209 def sign_out(request):
210     """Log out resouce."""
211     logout(request)
212     return redirect('index')
213 
214 
215 def api_key_xml_response(user, orgs):
216     """Build the XML response.
217 
218     This is used by the Up app - so make sure they match on change.
219     """
220     xml_root = etree.Element("credentials")
221 
222     # User
223     user_id_element = etree.SubElement(xml_root, "user_id")
224     user_id_element.text = str(user.id)
225     user_username_element = etree.SubElement(xml_root, "username")
226     user_username_element.text = user.username
227 
228     # Organisations
229     for org in orgs:
230         org_id_element = etree.SubElement(xml_root, "org_id")
231         org_id_element.text = str(org.id)
232 
233     # API key
234     api_key_element = etree.SubElement(xml_root, "api_key")
235     api_key_element.text = ApiKey.objects.get_or_create(user=user)[0].key
236 
237     # Published and editable projects
238     projects = user.organisations.all_projects().published()
239     pub_projs_element = etree.SubElement(xml_root, "published_projects")
240     edit_projs_element = etree.SubElement(xml_root, "allow_edit_projects")
241     for project in projects:
242         project_id_element = etree.SubElement(pub_projs_element, "id")
243         project_id_element.text = str(project.id)
244         if user.has_perm('rsr.change_project', project):
245             project_id_element = etree.SubElement(edit_projs_element, "id")
246             project_id_element.text = str(project.id)
247 
248     return etree.tostring(etree.ElementTree(xml_root))
249 
250 
251 def api_key_json_response(user, orgs):
252     """
253     Build the JSON response. This is used by the Up app - so make sure they match on change.
254     """
255     response_data = dict()
256 
257     # User
258     response_data["user_id"] = user.id
259     response_data["username"] = user.username
260 
261     # Organisations
262     response_data["organisations"] = [org.id for org in orgs]
263 
264     # API key
265     response_data["api_key"] = ApiKey.objects.get_or_create(user=user)[0].key
266 
267     # Published projects
268     projects = user.organisations.all_projects().published()
269     response_data["published_projects"] = [p.id for p in projects]
270 
271     # Editable projects
272     perm = 'rsr.change_project'
273     response_data["allow_edit_projects"] = [p.id for p in projects if user.has_perm(perm, p)]
274 
275     return json.dumps(response_data)
276 
277 
278 @require_POST
279 @csrf_exempt
280 def api_key(request):
281     """On successful user credentials returns an auth token for API usage.
282 
283     Since RSR changed in v3 to allow users without an organisation we need to
284     introduce a way to make old Up apps work as before but new ones support
285     users without any connected organisations.
286     """
287     request_format = request.GET.get('format', 'xml')
288     username = request.POST.get('username', False)
289     password = request.POST.get('password', False)
290     handles_unemployed = bool(request.POST.get("handles_unemployed", False))
291 
292     if username and password:
293         user = authenticate(username=username, password=password)
294         if user is not None and user.is_active:
295             orgs = user.approved_organisations()
296             if orgs or handles_unemployed:
297                 if request_format == 'xml':
298                     return HttpResponse(api_key_xml_response(user, orgs),
299                                         content_type="text/xml")
300                 elif request_format == 'json':
301                     return HttpResponse(api_key_json_response(user, orgs),
302                                         content_type="application/json")
303     return HttpResponseForbidden()
304
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/akvo/rsr/views/account.py b/akvo/rsr/views/account.py
--- a/akvo/rsr/views/account.py
+++ b/akvo/rsr/views/account.py
@@ -270,7 +270,8 @@
 
     # Editable projects
     perm = 'rsr.change_project'
-    response_data["allow_edit_projects"] = [p.id for p in projects if user.has_perm(perm, p)]
+    perm_filter = user.get_permission_filter(perm, '')
+    response_data["allow_edit_projects"] = list(projects.filter(perm_filter).values_list('id', flat=True))
 
     return json.dumps(response_data)

{"golden_diff": "diff --git a/akvo/rsr/views/account.py b/akvo/rsr/views/account.py\n--- a/akvo/rsr/views/account.py\n+++ b/akvo/rsr/views/account.py\n@@ -270,7 +270,8 @@\n \n     # Editable projects\n     perm = 'rsr.change_project'\n-    response_data[\"allow_edit_projects\"] = [p.id for p in projects if user.has_perm(perm, p)]\n+    perm_filter = user.get_permission_filter(perm, '')\n+    response_data[\"allow_edit_projects\"] = list(projects.filter(perm_filter).values_list('id', flat=True))\n \n     return json.dumps(response_data)\n", "issue": "Signing in from RSR Up fails with error 'Unable to authorize:'\nLogin for a user who has `rsr.change_project` permissions for a lot of projects, but is not an `rsr_admin` can timeout. This piece of code seems like the [culprit code](https://github.com/akvo/akvo-rsr/blob/5a07b31d1c272f2014e5eb3209f23506aa6e91f1/akvo/rsr/views/account.py#L273). \n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\n\"\"\"Akvo RSR is covered by the GNU Affero General Public License.\n\nSee more details in the license.txt file located at the root folder of the\nAkvo RSR module. For additional details on the GNU license please\nsee < http://www.gnu.org/licenses/agpl.html >.\n\"\"\"\n\nimport re\nimport json\n\nfrom lxml import etree\nfrom tastypie.models import ApiKey\n\nfrom akvo.rsr.forms import RegisterForm, InvitedUserForm\nfrom akvo.rsr.models import Employment\nfrom akvo.utils import rsr_send_mail\n\nfrom django.conf import settings\nfrom django.contrib.auth import login, logout, authenticate, get_user_model\nfrom django.contrib.auth.forms import AuthenticationForm, PasswordResetForm\nfrom django.core.exceptions import ObjectDoesNotExist\nfrom django.core.signing import TimestampSigner, BadSignature\nfrom django.http import (HttpResponse, HttpResponseRedirect,\n                         HttpResponseForbidden)\nfrom django.shortcuts import redirect, render, render_to_response\nfrom django.template import RequestContext\n\nfrom registration.models import RegistrationProfile\n\nfrom django.views.decorators.csrf import csrf_exempt\nfrom django.views.decorators.http import require_POST\n\n\ndef register(request):\n    \"\"\"Register form.\"\"\"\n    context = RequestContext(request)\n    if request.method == 'POST':\n        form = RegisterForm(data=request.POST, files=request.FILES)\n        if form.is_valid():\n            user = form.save(request)\n            return render_to_response('registration/register_complete.html',\n                                      {'new_user': user},\n                                      context_instance=context)\n    else:\n        form = RegisterForm()\n    return render_to_response('registration/register.html', {'form': form},\n                              context_instance=context)\n\n\ndef activate(request, activation_key, extra_context=None):\n    \"\"\"Activate resouce.\n\n    Activate a User's account, if their key is valid and hasn't expired.\n    Any values passed in the keyword argument \"extra_context\"\n    (which must be a dictionary) will be added to the context.\n    Any values in \"extra_context\" which are callable will be called prior to\n    being added to the context.\n    \"\"\"\n    sha = re.compile('^[a-f0-9]{40}$')\n    activation_key = activation_key.lower()\n\n    if sha.search(activation_key):\n        try:\n            registration_profile = RegistrationProfile.objects.get(\n                activation_key=activation_key)\n        except RegistrationProfile.DoesNotExist:\n            user = False\n        else:\n            if not registration_profile.activation_key_expired():\n                registration_profile.activation_key = RegistrationProfile.ACTIVATED\n                registration_profile.save()\n                user = registration_profile.user\n                user.is_active = True\n                user.save()\n\n                # Log in user without password, using custom backend\n                user = authenticate(username=user.username, no_password=True)\n                login(request, user)\n    if extra_context is None:\n        extra_context = {}\n    context = RequestContext(request)\n    for key, value in extra_context.items():\n        context[key] = callable(value) and value() or value\n    return render_to_response(\n        'registration/activate.html',\n        context_instance=context\n    )\n\n\ndef invite_activate(request, inviting_pk, user_pk, employment_pk, token_date, token):\n    \"\"\"\n    Activate a user that has been invited to use RSR.\n\n    :param request: the request\n    :param inviting_pk: the invitee user's primary key\n    :param user_pk: the invited user's primary key\n    :param employment_pk: the employment's primary key\n    :param token_date: the first part of the token\n    :param token: the second part of the token\n    \"\"\"\n\n    def approve_employment(invitee, invited, empl):\n        \"\"\"\n        Approves the employment and sends a mail to the user that has invited the new user.\n\n        :param invitee: the invitee user's instance\n        :param invited: the invited user's instance\n        :param empl: the employment's instance\n        \"\"\"\n        empl.approve(invitee)\n\n        if invitee:\n            # Send notification email to inviting user\n            rsr_send_mail(\n                [invitee.email],\n                subject='registration/inviting_user_notification_subject.txt',\n                message='registration/inviting_user_notification_message.txt',\n                html_message='registration/inviting_user_notification_message.html',\n                subject_context={\n                    'user': invited,\n                },\n                msg_context={\n                    'invited_user': invited,\n                    'inviting_user': invitee,\n                    'organisation': empl.organisation,\n                }\n            )\n\n    def login_and_redirect(req, invited):\n        \"\"\"\n        Log the invited user in and redirect to the My details page in MyRSR.\n\n        :param req: the request\n        :param invited: the invited user's instance\n        \"\"\"\n        invited = authenticate(username=invited.username, no_password=True)\n        login(request, invited)\n        return redirect('my_details')\n\n    bad_link, user, inviting_user, employment = False, None, None, None\n\n    try:\n        user = get_user_model().objects.get(pk=user_pk)\n        inviting_user = get_user_model().objects.get(pk=inviting_pk)\n        employment = Employment.objects.get(pk=employment_pk)\n    except ObjectDoesNotExist:\n        bad_link = True\n\n    try:\n        TimestampSigner().unsign(':'.join([user.email, token_date, token]))\n    except BadSignature:\n        bad_link = True\n\n    if user and user.is_active:\n        if employment and employment.is_approved:\n            # User is active and employment is approved, so nothing to do here\n            return login_and_redirect(request, user)\n        elif employment and not bad_link:\n            # Employment is not yet approved, and link is ok.\n            # Approve employment and log user in.\n            approve_employment(inviting_user, user, employment)\n            return login_and_redirect(request, user)\n\n    if request.method == 'POST':\n        form = InvitedUserForm(user=user, data=request.POST)\n        if form.is_valid():\n            # Approve employment and save new user details\n            form.save(request)\n            approve_employment(inviting_user, user, employment)\n            return login_and_redirect(request, user)\n    else:\n        form = InvitedUserForm(user=user)\n\n    context = {\n        'form': form,\n        'bad_link': bad_link,\n    }\n    return render(request, 'registration/invite_activate.html', context)\n\n\ndef sign_in(request):\n    \"\"\"Sign in.\n\n    POST have two variants with username & email:\n     - username > normal sign in\n     - email > password reset workflow\n    \"\"\"\n    context = RequestContext(request)\n    form = AuthenticationForm()\n    reset_form = PasswordResetForm()\n    if request.method == \"POST\" and 'username' in request.POST:\n        form = AuthenticationForm(data=request.POST)\n        if form.is_valid():\n            login(request, form.get_user())\n            next_page = request.GET.get('next')\n            return HttpResponseRedirect(next_page) if next_page else redirect('my_details')\n    # Password reset on sign in page\n    elif request.method == \"POST\" and 'email' in request.POST:\n        reset_form = PasswordResetForm(data=request.POST)\n        if reset_form.is_valid():\n            reset_form.save(domain_override=settings.RSR_DOMAIN)\n        return HttpResponse()\n    return render_to_response('sign_in.html', {'form': form, 'reset_form': reset_form},\n                              context_instance=context)\n\n\ndef sign_out(request):\n    \"\"\"Log out resouce.\"\"\"\n    logout(request)\n    return redirect('index')\n\n\ndef api_key_xml_response(user, orgs):\n    \"\"\"Build the XML response.\n\n    This is used by the Up app - so make sure they match on change.\n    \"\"\"\n    xml_root = etree.Element(\"credentials\")\n\n    # User\n    user_id_element = etree.SubElement(xml_root, \"user_id\")\n    user_id_element.text = str(user.id)\n    user_username_element = etree.SubElement(xml_root, \"username\")\n    user_username_element.text = user.username\n\n    # Organisations\n    for org in orgs:\n        org_id_element = etree.SubElement(xml_root, \"org_id\")\n        org_id_element.text = str(org.id)\n\n    # API key\n    api_key_element = etree.SubElement(xml_root, \"api_key\")\n    api_key_element.text = ApiKey.objects.get_or_create(user=user)[0].key\n\n    # Published and editable projects\n    projects = user.organisations.all_projects().published()\n    pub_projs_element = etree.SubElement(xml_root, \"published_projects\")\n    edit_projs_element = etree.SubElement(xml_root, \"allow_edit_projects\")\n    for project in projects:\n        project_id_element = etree.SubElement(pub_projs_element, \"id\")\n        project_id_element.text = str(project.id)\n        if user.has_perm('rsr.change_project', project):\n            project_id_element = etree.SubElement(edit_projs_element, \"id\")\n            project_id_element.text = str(project.id)\n\n    return etree.tostring(etree.ElementTree(xml_root))\n\n\ndef api_key_json_response(user, orgs):\n    \"\"\"\n    Build the JSON response. This is used by the Up app - so make sure they match on change.\n    \"\"\"\n    response_data = dict()\n\n    # User\n    response_data[\"user_id\"] = user.id\n    response_data[\"username\"] = user.username\n\n    # Organisations\n    response_data[\"organisations\"] = [org.id for org in orgs]\n\n    # API key\n    response_data[\"api_key\"] = ApiKey.objects.get_or_create(user=user)[0].key\n\n    # Published projects\n    projects = user.organisations.all_projects().published()\n    response_data[\"published_projects\"] = [p.id for p in projects]\n\n    # Editable projects\n    perm = 'rsr.change_project'\n    response_data[\"allow_edit_projects\"] = [p.id for p in projects if user.has_perm(perm, p)]\n\n    return json.dumps(response_data)\n\n\n@require_POST\n@csrf_exempt\ndef api_key(request):\n    \"\"\"On successful user credentials returns an auth token for API usage.\n\n    Since RSR changed in v3 to allow users without an organisation we need to\n    introduce a way to make old Up apps work as before but new ones support\n    users without any connected organisations.\n    \"\"\"\n    request_format = request.GET.get('format', 'xml')\n    username = request.POST.get('username', False)\n    password = request.POST.get('password', False)\n    handles_unemployed = bool(request.POST.get(\"handles_unemployed\", False))\n\n    if username and password:\n        user = authenticate(username=username, password=password)\n        if user is not None and user.is_active:\n            orgs = user.approved_organisations()\n            if orgs or handles_unemployed:\n                if request_format == 'xml':\n                    return HttpResponse(api_key_xml_response(user, orgs),\n                                        content_type=\"text/xml\")\n                elif request_format == 'json':\n                    return HttpResponse(api_key_json_response(user, orgs),\n                                        content_type=\"application/json\")\n    return HttpResponseForbidden()\n", "path": "akvo/rsr/views/account.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\n\"\"\"Akvo RSR is covered by the GNU Affero General Public License.\n\nSee more details in the license.txt file located at the root folder of the\nAkvo RSR module. For additional details on the GNU license please\nsee < http://www.gnu.org/licenses/agpl.html >.\n\"\"\"\n\nimport re\nimport json\n\nfrom lxml import etree\nfrom tastypie.models import ApiKey\n\nfrom akvo.rsr.forms import RegisterForm, InvitedUserForm\nfrom akvo.rsr.models import Employment\nfrom akvo.utils import rsr_send_mail\n\nfrom django.conf import settings\nfrom django.contrib.auth import login, logout, authenticate, get_user_model\nfrom django.contrib.auth.forms import AuthenticationForm, PasswordResetForm\nfrom django.core.exceptions import ObjectDoesNotExist\nfrom django.core.signing import TimestampSigner, BadSignature\nfrom django.http import (HttpResponse, HttpResponseRedirect,\n                         HttpResponseForbidden)\nfrom django.shortcuts import redirect, render, render_to_response\nfrom django.template import RequestContext\n\nfrom registration.models import RegistrationProfile\n\nfrom django.views.decorators.csrf import csrf_exempt\nfrom django.views.decorators.http import require_POST\n\n\ndef register(request):\n    \"\"\"Register form.\"\"\"\n    context = RequestContext(request)\n    if request.method == 'POST':\n        form = RegisterForm(data=request.POST, files=request.FILES)\n        if form.is_valid():\n            user = form.save(request)\n            return render_to_response('registration/register_complete.html',\n                                      {'new_user': user},\n                                      context_instance=context)\n    else:\n        form = RegisterForm()\n    return render_to_response('registration/register.html', {'form': form},\n                              context_instance=context)\n\n\ndef activate(request, activation_key, extra_context=None):\n    \"\"\"Activate resouce.\n\n    Activate a User's account, if their key is valid and hasn't expired.\n    Any values passed in the keyword argument \"extra_context\"\n    (which must be a dictionary) will be added to the context.\n    Any values in \"extra_context\" which are callable will be called prior to\n    being added to the context.\n    \"\"\"\n    sha = re.compile('^[a-f0-9]{40}$')\n    activation_key = activation_key.lower()\n\n    if sha.search(activation_key):\n        try:\n            registration_profile = RegistrationProfile.objects.get(\n                activation_key=activation_key)\n        except RegistrationProfile.DoesNotExist:\n            user = False\n        else:\n            if not registration_profile.activation_key_expired():\n                registration_profile.activation_key = RegistrationProfile.ACTIVATED\n                registration_profile.save()\n                user = registration_profile.user\n                user.is_active = True\n                user.save()\n\n                # Log in user without password, using custom backend\n                user = authenticate(username=user.username, no_password=True)\n                login(request, user)\n    if extra_context is None:\n        extra_context = {}\n    context = RequestContext(request)\n    for key, value in extra_context.items():\n        context[key] = callable(value) and value() or value\n    return render_to_response(\n        'registration/activate.html',\n        context_instance=context\n    )\n\n\ndef invite_activate(request, inviting_pk, user_pk, employment_pk, token_date, token):\n    \"\"\"\n    Activate a user that has been invited to use RSR.\n\n    :param request: the request\n    :param inviting_pk: the invitee user's primary key\n    :param user_pk: the invited user's primary key\n    :param employment_pk: the employment's primary key\n    :param token_date: the first part of the token\n    :param token: the second part of the token\n    \"\"\"\n\n    def approve_employment(invitee, invited, empl):\n        \"\"\"\n        Approves the employment and sends a mail to the user that has invited the new user.\n\n        :param invitee: the invitee user's instance\n        :param invited: the invited user's instance\n        :param empl: the employment's instance\n        \"\"\"\n        empl.approve(invitee)\n\n        if invitee:\n            # Send notification email to inviting user\n            rsr_send_mail(\n                [invitee.email],\n                subject='registration/inviting_user_notification_subject.txt',\n                message='registration/inviting_user_notification_message.txt',\n                html_message='registration/inviting_user_notification_message.html',\n                subject_context={\n                    'user': invited,\n                },\n                msg_context={\n                    'invited_user': invited,\n                    'inviting_user': invitee,\n                    'organisation': empl.organisation,\n                }\n            )\n\n    def login_and_redirect(req, invited):\n        \"\"\"\n        Log the invited user in and redirect to the My details page in MyRSR.\n\n        :param req: the request\n        :param invited: the invited user's instance\n        \"\"\"\n        invited = authenticate(username=invited.username, no_password=True)\n        login(request, invited)\n        return redirect('my_details')\n\n    bad_link, user, inviting_user, employment = False, None, None, None\n\n    try:\n        user = get_user_model().objects.get(pk=user_pk)\n        inviting_user = get_user_model().objects.get(pk=inviting_pk)\n        employment = Employment.objects.get(pk=employment_pk)\n    except ObjectDoesNotExist:\n        bad_link = True\n\n    try:\n        TimestampSigner().unsign(':'.join([user.email, token_date, token]))\n    except BadSignature:\n        bad_link = True\n\n    if user and user.is_active:\n        if employment and employment.is_approved:\n            # User is active and employment is approved, so nothing to do here\n            return login_and_redirect(request, user)\n        elif employment and not bad_link:\n            # Employment is not yet approved, and link is ok.\n            # Approve employment and log user in.\n            approve_employment(inviting_user, user, employment)\n            return login_and_redirect(request, user)\n\n    if request.method == 'POST':\n        form = InvitedUserForm(user=user, data=request.POST)\n        if form.is_valid():\n            # Approve employment and save new user details\n            form.save(request)\n            approve_employment(inviting_user, user, employment)\n            return login_and_redirect(request, user)\n    else:\n        form = InvitedUserForm(user=user)\n\n    context = {\n        'form': form,\n        'bad_link': bad_link,\n    }\n    return render(request, 'registration/invite_activate.html', context)\n\n\ndef sign_in(request):\n    \"\"\"Sign in.\n\n    POST have two variants with username & email:\n     - username > normal sign in\n     - email > password reset workflow\n    \"\"\"\n    context = RequestContext(request)\n    form = AuthenticationForm()\n    reset_form = PasswordResetForm()\n    if request.method == \"POST\" and 'username' in request.POST:\n        form = AuthenticationForm(data=request.POST)\n        if form.is_valid():\n            login(request, form.get_user())\n            next_page = request.GET.get('next')\n            return HttpResponseRedirect(next_page) if next_page else redirect('my_details')\n    # Password reset on sign in page\n    elif request.method == \"POST\" and 'email' in request.POST:\n        reset_form = PasswordResetForm(data=request.POST)\n        if reset_form.is_valid():\n            reset_form.save(domain_override=settings.RSR_DOMAIN)\n        return HttpResponse()\n    return render_to_response('sign_in.html', {'form': form, 'reset_form': reset_form},\n                              context_instance=context)\n\n\ndef sign_out(request):\n    \"\"\"Log out resouce.\"\"\"\n    logout(request)\n    return redirect('index')\n\n\ndef api_key_xml_response(user, orgs):\n    \"\"\"Build the XML response.\n\n    This is used by the Up app - so make sure they match on change.\n    \"\"\"\n    xml_root = etree.Element(\"credentials\")\n\n    # User\n    user_id_element = etree.SubElement(xml_root, \"user_id\")\n    user_id_element.text = str(user.id)\n    user_username_element = etree.SubElement(xml_root, \"username\")\n    user_username_element.text = user.username\n\n    # Organisations\n    for org in orgs:\n        org_id_element = etree.SubElement(xml_root, \"org_id\")\n        org_id_element.text = str(org.id)\n\n    # API key\n    api_key_element = etree.SubElement(xml_root, \"api_key\")\n    api_key_element.text = ApiKey.objects.get_or_create(user=user)[0].key\n\n    # Published and editable projects\n    projects = user.organisations.all_projects().published()\n    pub_projs_element = etree.SubElement(xml_root, \"published_projects\")\n    edit_projs_element = etree.SubElement(xml_root, \"allow_edit_projects\")\n    for project in projects:\n        project_id_element = etree.SubElement(pub_projs_element, \"id\")\n        project_id_element.text = str(project.id)\n        if user.has_perm('rsr.change_project', project):\n            project_id_element = etree.SubElement(edit_projs_element, \"id\")\n            project_id_element.text = str(project.id)\n\n    return etree.tostring(etree.ElementTree(xml_root))\n\n\ndef api_key_json_response(user, orgs):\n    \"\"\"\n    Build the JSON response. This is used by the Up app - so make sure they match on change.\n    \"\"\"\n    response_data = dict()\n\n    # User\n    response_data[\"user_id\"] = user.id\n    response_data[\"username\"] = user.username\n\n    # Organisations\n    response_data[\"organisations\"] = [org.id for org in orgs]\n\n    # API key\n    response_data[\"api_key\"] = ApiKey.objects.get_or_create(user=user)[0].key\n\n    # Published projects\n    projects = user.organisations.all_projects().published()\n    response_data[\"published_projects\"] = [p.id for p in projects]\n\n    # Editable projects\n    perm = 'rsr.change_project'\n    perm_filter = user.get_permission_filter(perm, '')\n    response_data[\"allow_edit_projects\"] = list(projects.filter(perm_filter).values_list('id', flat=True))\n\n    return json.dumps(response_data)\n\n\n@require_POST\n@csrf_exempt\ndef api_key(request):\n    \"\"\"On successful user credentials returns an auth token for API usage.\n\n    Since RSR changed in v3 to allow users without an organisation we need to\n    introduce a way to make old Up apps work as before but new ones support\n    users without any connected organisations.\n    \"\"\"\n    request_format = request.GET.get('format', 'xml')\n    username = request.POST.get('username', False)\n    password = request.POST.get('password', False)\n    handles_unemployed = bool(request.POST.get(\"handles_unemployed\", False))\n\n    if username and password:\n        user = authenticate(username=username, password=password)\n        if user is not None and user.is_active:\n            orgs = user.approved_organisations()\n            if orgs or handles_unemployed:\n                if request_format == 'xml':\n                    return HttpResponse(api_key_xml_response(user, orgs),\n                                        content_type=\"text/xml\")\n                elif request_format == 'json':\n                    return HttpResponse(api_key_json_response(user, orgs),\n                                        content_type=\"application/json\")\n    return HttpResponseForbidden()\n", "path": "akvo/rsr/views/account.py"}]}