We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Enable users to delete their own account
Currently, people are posting issues if they need their account deleted. This leads to extra noise in the issues, and to some privacy concerns. 

I propose we add an email account and notice to the README, letting users know where they can email to request account deletion. This will allow better triaging and chunking of deletions. 

@ericholscher What do you think? 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `readthedocs/core/forms.py`
Content:
```
1 """Forms for core app."""
2 
3 from __future__ import absolute_import
4 from builtins import object
5 import logging
6 
7 from haystack.forms import SearchForm
8 from haystack.query import SearchQuerySet
9 from django import forms
10 from django.forms.fields import CharField
11 from django.utils.translation import ugettext_lazy as _
12 
13 from .models import UserProfile
14 
15 log = logging.getLogger(__name__)
16 
17 
18 class UserProfileForm(forms.ModelForm):
19     first_name = CharField(label=_('First name'), required=False)
20     last_name = CharField(label=_('Last name'), required=False)
21 
22     class Meta(object):
23         model = UserProfile
24         # Don't allow users edit someone else's user page,
25         fields = ['first_name', 'last_name', 'homepage', 'allow_ads']
26 
27     def __init__(self, *args, **kwargs):
28         super(UserProfileForm, self).__init__(*args, **kwargs)
29         try:
30             self.fields['first_name'].initial = self.instance.user.first_name
31             self.fields['last_name'].initial = self.instance.user.last_name
32         except AttributeError:
33             pass
34 
35     def save(self, commit=True):
36         first_name = self.cleaned_data.pop('first_name', None)
37         last_name = self.cleaned_data.pop('last_name', None)
38         profile = super(UserProfileForm, self).save(commit=commit)
39         if commit:
40             user = profile.user
41             user.first_name = first_name
42             user.last_name = last_name
43             user.save()
44         return profile
45 
46 
47 class FacetField(forms.MultipleChoiceField):
48 
49     """
50     For filtering searches on a facet.
51 
52     Has validation for the format of facet values.
53     """
54 
55     def valid_value(self, value):
56         """
57         Although this is a choice field, no choices need to be supplied.
58 
59         Instead, we just validate that the value is in the correct format
60         for facet filtering (facet_name:value)
61         """
62         if ":" not in value:
63             return False
64         return True
65 
66 
67 class FacetedSearchForm(SearchForm):
68 
69     """
70     Supports fetching faceted results with a corresponding query.
71 
72     `facets`
73         A list of facet names for which to get facet counts
74     `models`
75         Limit the search to one or more models
76     """
77 
78     selected_facets = FacetField(required=False)
79 
80     def __init__(self, *args, **kwargs):
81         facets = kwargs.pop('facets', [])
82         models = kwargs.pop('models', [])
83         super(FacetedSearchForm, self).__init__(*args, **kwargs)
84 
85         for facet in facets:
86             self.searchqueryset = self.searchqueryset.facet(facet)
87         if models:
88             self.searchqueryset = self.searchqueryset.models(*models)
89 
90     def clean_selected_facets(self):
91         facets = self.cleaned_data['selected_facets']
92         cleaned_facets = []
93         clean = SearchQuerySet().query.clean
94         for facet in facets:
95             field, value = facet.split(":", 1)
96             if not value:  # Ignore empty values
97                 continue
98             value = clean(value)
99             cleaned_facets.append(u'%s:"%s"' % (field, value))
100         return cleaned_facets
101 
102     def search(self):
103         sqs = super(FacetedSearchForm, self).search()
104         for facet in self.cleaned_data['selected_facets']:
105             sqs = sqs.narrow(facet)
106         self.searchqueryset = sqs
107         return sqs
108
```

Path: `readthedocs/profiles/views.py`
Content:
```
1 """Views for creating, editing and viewing site-specific user profiles."""
2 
3 from __future__ import absolute_import
4 from django.contrib.auth.decorators import login_required
5 from django.contrib.auth.models import User
6 from django.core.exceptions import ObjectDoesNotExist
7 from django.core.urlresolvers import reverse
8 from django.http import Http404
9 from django.http import HttpResponseRedirect
10 from django.shortcuts import get_object_or_404
11 from django.shortcuts import render_to_response
12 from django.template import RequestContext
13 
14 
15 def create_profile(request, form_class, success_url=None,
16                    template_name='profiles/private/create_profile.html',
17                    extra_context=None):
18     """
19     Create a profile for the current user, if one doesn't already exist.
20 
21     If the user already has a profile, a redirect will be issued to the
22     :view:`profiles.views.edit_profile` view.
23 
24     **Optional arguments:**
25 
26     ``extra_context``
27         A dictionary of variables to add to the template context. Any
28         callable object in this dictionary will be called to produce
29         the end result which appears in the context.
30 
31     ``form_class``
32         The form class to use for validating and creating the user
33         profile. This form class must define a method named
34         ``save()``, implementing the same argument signature as the
35         ``save()`` method of a standard Django ``ModelForm`` (this
36         view will call ``save(commit=False)`` to obtain the profile
37         object, and fill in the user before the final save). If the
38         profile object includes many-to-many relations, the convention
39         established by ``ModelForm`` of using a method named
40         ``save_m2m()`` will be used, and so your form class should
41         also define this method.
42 
43     ``success_url``
44         The URL to redirect to after successful profile creation. If
45         this argument is not supplied, this will default to the URL of
46         :view:`profiles.views.profile_detail` for the newly-created
47         profile object.
48 
49     ``template_name``
50         The template to use when displaying the profile-creation
51         form. If not supplied, this will default to
52         :template:`profiles/create_profile.html`.
53 
54     **Context:**
55 
56     ``form``
57         The profile-creation form.
58 
59     **Template:**
60 
61     ``template_name`` keyword argument, or
62     :template:`profiles/create_profile.html`.
63 
64     """
65     try:
66         profile_obj = request.user.profile
67         return HttpResponseRedirect(reverse('profiles_edit_profile'))
68     except ObjectDoesNotExist:
69         pass
70 
71     #
72     # We set up success_url here, rather than as the default value for
73     # the argument. Trying to do it as the argument's default would
74     # mean evaluating the call to reverse() at the time this module is
75     # first imported, which introduces a circular dependency: to
76     # perform the reverse lookup we need access to profiles/urls.py,
77     # but profiles/urls.py in turn imports this module.
78     #
79 
80     if success_url is None:
81         success_url = reverse('profiles_profile_detail',
82                               kwargs={'username': request.user.username})
83     if request.method == 'POST':
84         form = form_class(data=request.POST, files=request.FILES)
85         if form.is_valid():
86             profile_obj = form.save(commit=False)
87             profile_obj.user = request.user
88             profile_obj.save()
89             if hasattr(form, 'save_m2m'):
90                 form.save_m2m()
91             return HttpResponseRedirect(success_url)
92     else:
93         form = form_class()
94 
95     if extra_context is None:
96         extra_context = {}
97     context = RequestContext(request)
98     for key, value in list(extra_context.items()):
99         context[key] = (value() if callable(value) else value)
100 
101     return render_to_response(template_name,
102                               {'form': form},
103                               context_instance=context)
104 create_profile = login_required(create_profile)
105 
106 
107 def edit_profile(request, form_class, success_url=None,
108                  template_name='profiles/private/edit_profile.html',
109                  extra_context=None):
110     """
111     Edit the current user's profile.
112 
113     If the user does not already have a profile, a redirect will be issued to
114     the :view:`profiles.views.create_profile` view.
115 
116     **Optional arguments:**
117 
118     ``extra_context``
119         A dictionary of variables to add to the template context. Any
120         callable object in this dictionary will be called to produce
121         the end result which appears in the context.
122 
123     ``form_class``
124         The form class to use for validating and editing the user
125         profile. This form class must operate similarly to a standard
126         Django ``ModelForm`` in that it must accept an instance of the
127         object to be edited as the keyword argument ``instance`` to
128         its constructor, and it must implement a method named
129         ``save()`` which will save the updates to the object.
130 
131     ``success_url``
132         The URL to redirect to following a successful edit. If not
133         specified, this will default to the URL of
134         :view:`profiles.views.profile_detail` for the profile object
135         being edited.
136 
137     ``template_name``
138         The template to use when displaying the profile-editing
139         form. If not specified, this will default to
140         :template:`profiles/edit_profile.html`.
141 
142     **Context:**
143 
144     ``form``
145         The form for editing the profile.
146 
147     ``profile``
148          The user's current profile.
149 
150     **Template:**
151 
152     ``template_name`` keyword argument or
153     :template:`profiles/edit_profile.html`.
154 
155     """
156     try:
157         profile_obj = request.user.profile
158     except ObjectDoesNotExist:
159         return HttpResponseRedirect(reverse('profiles_profile_create'))
160 
161     if success_url is None:
162         success_url = reverse('profiles_profile_detail',
163                               kwargs={'username': request.user.username})
164     if request.method == 'POST':
165         form = form_class(data=request.POST, files=request.FILES, instance=profile_obj)
166         if form.is_valid():
167             form.save()
168             return HttpResponseRedirect(success_url)
169     else:
170         form = form_class(instance=profile_obj)
171 
172     if extra_context is None:
173         extra_context = {}
174     context = RequestContext(request)
175     for key, value in list(extra_context.items()):
176         context[key] = (value() if callable(value) else value)
177 
178     return render_to_response(template_name, {
179         'form': form,
180         'profile': profile_obj,
181         'user': profile_obj.user,
182     }, context_instance=context)
183 edit_profile = login_required(edit_profile)
184 
185 
186 def profile_detail(request, username, public_profile_field=None,
187                    template_name='profiles/public/profile_detail.html',
188                    extra_context=None):
189     """
190     Detail view of a user's profile.
191 
192     If the user has not yet created a profile, ``Http404`` will be
193     raised.
194 
195     **Required arguments:**
196 
197     ``username``
198         The username of the user whose profile is being displayed.
199 
200     **Optional arguments:**
201 
202     ``extra_context``
203         A dictionary of variables to add to the template context. Any
204         callable object in this dictionary will be called to produce
205         the end result which appears in the context.
206 
207     ``public_profile_field``
208         The name of a ``BooleanField`` on the profile model; if the
209         value of that field on the user's profile is ``False``, the
210         ``profile`` variable in the template will be ``None``. Use
211         this feature to allow users to mark their profiles as not
212         being publicly viewable.
213 
214         If this argument is not specified, it will be assumed that all
215         users' profiles are publicly viewable.
216 
217     ``template_name``
218         The name of the template to use for displaying the profile. If
219         not specified, this will default to
220         :template:`profiles/profile_detail.html`.
221 
222     **Context:**
223 
224     ``profile``
225         The user's profile, or ``None`` if the user's profile is not
226         publicly viewable (see the description of
227         ``public_profile_field`` above).
228 
229     **Template:**
230 
231     ``template_name`` keyword argument or
232     :template:`profiles/profile_detail.html`.
233 
234     """
235     user = get_object_or_404(User, username=username)
236     try:
237         profile_obj = user.profile
238     except ObjectDoesNotExist:
239         raise Http404
240     if public_profile_field is not None and \
241        not getattr(profile_obj, public_profile_field):
242         profile_obj = None
243 
244     if extra_context is None:
245         extra_context = {}
246     context = RequestContext(request)
247     for key, value in list(extra_context.items()):
248         context[key] = (value() if callable(value) else value)
249 
250     return render_to_response(template_name,
251                               {'profile': profile_obj},
252                               context_instance=context)
253
```

Path: `readthedocs/profiles/urls/private.py`
Content:
```
1 """URL patterns for views to modify user profiles."""
2 
3 from __future__ import absolute_import
4 from django.conf.urls import url
5 
6 from readthedocs.core.forms import UserProfileForm
7 from readthedocs.profiles import views
8 
9 urlpatterns = [
10     url(r'^create/', views.create_profile,
11         {
12             'form_class': UserProfileForm,
13         },
14         name='profiles_profile_create'),
15     url(r'^edit/', views.edit_profile,
16         {
17             'form_class': UserProfileForm,
18             'template_name': 'profiles/private/edit_profile.html',
19         },
20         name='profiles_profile_edit'),
21 ]
22
```
--- 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/readthedocs/core/forms.py b/readthedocs/core/forms.py
--- a/readthedocs/core/forms.py
+++ b/readthedocs/core/forms.py
@@ -4,6 +4,7 @@
 from builtins import object
 import logging
 
+from django.contrib.auth.models import User
 from haystack.forms import SearchForm
 from haystack.query import SearchQuerySet
 from django import forms
@@ -44,6 +45,22 @@
         return profile
 
 
+class UserDeleteForm(forms.ModelForm):
+    username = CharField(label=_('Username'), help_text=_('Please type your username to confirm.'))
+
+    class Meta(object):
+        model = User
+        fields = ['username']
+
+    def clean_username(self):
+        data = self.cleaned_data['username']
+
+        if self.instance.username != data:
+            raise forms.ValidationError(_("Username does not match!"))
+
+        return data
+
+
 class FacetField(forms.MultipleChoiceField):
 
     """
diff --git a/readthedocs/profiles/urls/private.py b/readthedocs/profiles/urls/private.py
--- a/readthedocs/profiles/urls/private.py
+++ b/readthedocs/profiles/urls/private.py
@@ -18,4 +18,5 @@
             'template_name': 'profiles/private/edit_profile.html',
         },
         name='profiles_profile_edit'),
+    url(r'^delete/', views.delete_account, name='delete_account')
 ]
diff --git a/readthedocs/profiles/views.py b/readthedocs/profiles/views.py
--- a/readthedocs/profiles/views.py
+++ b/readthedocs/profiles/views.py
@@ -1,16 +1,21 @@
 """Views for creating, editing and viewing site-specific user profiles."""
 
 from __future__ import absolute_import
+
+from django.contrib import messages
+from django.contrib.auth import logout
 from django.contrib.auth.decorators import login_required
 from django.contrib.auth.models import User
 from django.core.exceptions import ObjectDoesNotExist
 from django.core.urlresolvers import reverse
 from django.http import Http404
 from django.http import HttpResponseRedirect
-from django.shortcuts import get_object_or_404
+from django.shortcuts import get_object_or_404, render, redirect
 from django.shortcuts import render_to_response
 from django.template import RequestContext
 
+from readthedocs.core.forms import UserDeleteForm
+
 
 def create_profile(request, form_class, success_url=None,
                    template_name='profiles/private/create_profile.html',
@@ -183,6 +188,27 @@
 edit_profile = login_required(edit_profile)
 
 
+@login_required()
+def delete_account(request):
+    form = UserDeleteForm()
+    template_name = 'profiles/private/delete_account.html'
+
+    if request.method == 'POST':
+        form = UserDeleteForm(instance=request.user, data=request.POST)
+        if form.is_valid():
+
+            # Do not delete the account permanently because it may create disaster
+            # Inactive the user instead.
+            request.user.is_active = False
+            request.user.save()
+            logout(request)
+            messages.info(request, 'You have successfully deleted your account')
+
+            return redirect('homepage')
+
+    return render(request, template_name, {'form': form})
+
+
 def profile_detail(request, username, public_profile_field=None,
                    template_name='profiles/public/profile_detail.html',
                    extra_context=None):

{"golden_diff": "diff --git a/readthedocs/core/forms.py b/readthedocs/core/forms.py\n--- a/readthedocs/core/forms.py\n+++ b/readthedocs/core/forms.py\n@@ -4,6 +4,7 @@\n from builtins import object\n import logging\n \n+from django.contrib.auth.models import User\n from haystack.forms import SearchForm\n from haystack.query import SearchQuerySet\n from django import forms\n@@ -44,6 +45,22 @@\n         return profile\n \n \n+class UserDeleteForm(forms.ModelForm):\n+    username = CharField(label=_('Username'), help_text=_('Please type your username to confirm.'))\n+\n+    class Meta(object):\n+        model = User\n+        fields = ['username']\n+\n+    def clean_username(self):\n+        data = self.cleaned_data['username']\n+\n+        if self.instance.username != data:\n+            raise forms.ValidationError(_(\"Username does not match!\"))\n+\n+        return data\n+\n+\n class FacetField(forms.MultipleChoiceField):\n \n     \"\"\"\ndiff --git a/readthedocs/profiles/urls/private.py b/readthedocs/profiles/urls/private.py\n--- a/readthedocs/profiles/urls/private.py\n+++ b/readthedocs/profiles/urls/private.py\n@@ -18,4 +18,5 @@\n             'template_name': 'profiles/private/edit_profile.html',\n         },\n         name='profiles_profile_edit'),\n+    url(r'^delete/', views.delete_account, name='delete_account')\n ]\ndiff --git a/readthedocs/profiles/views.py b/readthedocs/profiles/views.py\n--- a/readthedocs/profiles/views.py\n+++ b/readthedocs/profiles/views.py\n@@ -1,16 +1,21 @@\n \"\"\"Views for creating, editing and viewing site-specific user profiles.\"\"\"\n \n from __future__ import absolute_import\n+\n+from django.contrib import messages\n+from django.contrib.auth import logout\n from django.contrib.auth.decorators import login_required\n from django.contrib.auth.models import User\n from django.core.exceptions import ObjectDoesNotExist\n from django.core.urlresolvers import reverse\n from django.http import Http404\n from django.http import HttpResponseRedirect\n-from django.shortcuts import get_object_or_404\n+from django.shortcuts import get_object_or_404, render, redirect\n from django.shortcuts import render_to_response\n from django.template import RequestContext\n \n+from readthedocs.core.forms import UserDeleteForm\n+\n \n def create_profile(request, form_class, success_url=None,\n                    template_name='profiles/private/create_profile.html',\n@@ -183,6 +188,27 @@\n edit_profile = login_required(edit_profile)\n \n \n+@login_required()\n+def delete_account(request):\n+    form = UserDeleteForm()\n+    template_name = 'profiles/private/delete_account.html'\n+\n+    if request.method == 'POST':\n+        form = UserDeleteForm(instance=request.user, data=request.POST)\n+        if form.is_valid():\n+\n+            # Do not delete the account permanently because it may create disaster\n+            # Inactive the user instead.\n+            request.user.is_active = False\n+            request.user.save()\n+            logout(request)\n+            messages.info(request, 'You have successfully deleted your account')\n+\n+            return redirect('homepage')\n+\n+    return render(request, template_name, {'form': form})\n+\n+\n def profile_detail(request, username, public_profile_field=None,\n                    template_name='profiles/public/profile_detail.html',\n                    extra_context=None):\n", "issue": "Enable users to delete their own account\nCurrently, people are posting issues if they need their account deleted. This leads to extra noise in the issues, and to some privacy concerns. \r\n\r\nI propose we add an email account and notice to the README, letting users know where they can email to request account deletion. This will allow better triaging and chunking of deletions. \r\n\r\n@ericholscher What do you think? \n", "before_files": [{"content": "\"\"\"Forms for core app.\"\"\"\n\nfrom __future__ import absolute_import\nfrom builtins import object\nimport logging\n\nfrom haystack.forms import SearchForm\nfrom haystack.query import SearchQuerySet\nfrom django import forms\nfrom django.forms.fields import CharField\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom .models import UserProfile\n\nlog = logging.getLogger(__name__)\n\n\nclass UserProfileForm(forms.ModelForm):\n    first_name = CharField(label=_('First name'), required=False)\n    last_name = CharField(label=_('Last name'), required=False)\n\n    class Meta(object):\n        model = UserProfile\n        # Don't allow users edit someone else's user page,\n        fields = ['first_name', 'last_name', 'homepage', 'allow_ads']\n\n    def __init__(self, *args, **kwargs):\n        super(UserProfileForm, self).__init__(*args, **kwargs)\n        try:\n            self.fields['first_name'].initial = self.instance.user.first_name\n            self.fields['last_name'].initial = self.instance.user.last_name\n        except AttributeError:\n            pass\n\n    def save(self, commit=True):\n        first_name = self.cleaned_data.pop('first_name', None)\n        last_name = self.cleaned_data.pop('last_name', None)\n        profile = super(UserProfileForm, self).save(commit=commit)\n        if commit:\n            user = profile.user\n            user.first_name = first_name\n            user.last_name = last_name\n            user.save()\n        return profile\n\n\nclass FacetField(forms.MultipleChoiceField):\n\n    \"\"\"\n    For filtering searches on a facet.\n\n    Has validation for the format of facet values.\n    \"\"\"\n\n    def valid_value(self, value):\n        \"\"\"\n        Although this is a choice field, no choices need to be supplied.\n\n        Instead, we just validate that the value is in the correct format\n        for facet filtering (facet_name:value)\n        \"\"\"\n        if \":\" not in value:\n            return False\n        return True\n\n\nclass FacetedSearchForm(SearchForm):\n\n    \"\"\"\n    Supports fetching faceted results with a corresponding query.\n\n    `facets`\n        A list of facet names for which to get facet counts\n    `models`\n        Limit the search to one or more models\n    \"\"\"\n\n    selected_facets = FacetField(required=False)\n\n    def __init__(self, *args, **kwargs):\n        facets = kwargs.pop('facets', [])\n        models = kwargs.pop('models', [])\n        super(FacetedSearchForm, self).__init__(*args, **kwargs)\n\n        for facet in facets:\n            self.searchqueryset = self.searchqueryset.facet(facet)\n        if models:\n            self.searchqueryset = self.searchqueryset.models(*models)\n\n    def clean_selected_facets(self):\n        facets = self.cleaned_data['selected_facets']\n        cleaned_facets = []\n        clean = SearchQuerySet().query.clean\n        for facet in facets:\n            field, value = facet.split(\":\", 1)\n            if not value:  # Ignore empty values\n                continue\n            value = clean(value)\n            cleaned_facets.append(u'%s:\"%s\"' % (field, value))\n        return cleaned_facets\n\n    def search(self):\n        sqs = super(FacetedSearchForm, self).search()\n        for facet in self.cleaned_data['selected_facets']:\n            sqs = sqs.narrow(facet)\n        self.searchqueryset = sqs\n        return sqs\n", "path": "readthedocs/core/forms.py"}, {"content": "\"\"\"Views for creating, editing and viewing site-specific user profiles.\"\"\"\n\nfrom __future__ import absolute_import\nfrom django.contrib.auth.decorators import login_required\nfrom django.contrib.auth.models import User\nfrom django.core.exceptions import ObjectDoesNotExist\nfrom django.core.urlresolvers import reverse\nfrom django.http import Http404\nfrom django.http import HttpResponseRedirect\nfrom django.shortcuts import get_object_or_404\nfrom django.shortcuts import render_to_response\nfrom django.template import RequestContext\n\n\ndef create_profile(request, form_class, success_url=None,\n                   template_name='profiles/private/create_profile.html',\n                   extra_context=None):\n    \"\"\"\n    Create a profile for the current user, if one doesn't already exist.\n\n    If the user already has a profile, a redirect will be issued to the\n    :view:`profiles.views.edit_profile` view.\n\n    **Optional arguments:**\n\n    ``extra_context``\n        A dictionary of variables to add to the template context. Any\n        callable object in this dictionary will be called to produce\n        the end result which appears in the context.\n\n    ``form_class``\n        The form class to use for validating and creating the user\n        profile. This form class must define a method named\n        ``save()``, implementing the same argument signature as the\n        ``save()`` method of a standard Django ``ModelForm`` (this\n        view will call ``save(commit=False)`` to obtain the profile\n        object, and fill in the user before the final save). If the\n        profile object includes many-to-many relations, the convention\n        established by ``ModelForm`` of using a method named\n        ``save_m2m()`` will be used, and so your form class should\n        also define this method.\n\n    ``success_url``\n        The URL to redirect to after successful profile creation. If\n        this argument is not supplied, this will default to the URL of\n        :view:`profiles.views.profile_detail` for the newly-created\n        profile object.\n\n    ``template_name``\n        The template to use when displaying the profile-creation\n        form. If not supplied, this will default to\n        :template:`profiles/create_profile.html`.\n\n    **Context:**\n\n    ``form``\n        The profile-creation form.\n\n    **Template:**\n\n    ``template_name`` keyword argument, or\n    :template:`profiles/create_profile.html`.\n\n    \"\"\"\n    try:\n        profile_obj = request.user.profile\n        return HttpResponseRedirect(reverse('profiles_edit_profile'))\n    except ObjectDoesNotExist:\n        pass\n\n    #\n    # We set up success_url here, rather than as the default value for\n    # the argument. Trying to do it as the argument's default would\n    # mean evaluating the call to reverse() at the time this module is\n    # first imported, which introduces a circular dependency: to\n    # perform the reverse lookup we need access to profiles/urls.py,\n    # but profiles/urls.py in turn imports this module.\n    #\n\n    if success_url is None:\n        success_url = reverse('profiles_profile_detail',\n                              kwargs={'username': request.user.username})\n    if request.method == 'POST':\n        form = form_class(data=request.POST, files=request.FILES)\n        if form.is_valid():\n            profile_obj = form.save(commit=False)\n            profile_obj.user = request.user\n            profile_obj.save()\n            if hasattr(form, 'save_m2m'):\n                form.save_m2m()\n            return HttpResponseRedirect(success_url)\n    else:\n        form = form_class()\n\n    if extra_context is None:\n        extra_context = {}\n    context = RequestContext(request)\n    for key, value in list(extra_context.items()):\n        context[key] = (value() if callable(value) else value)\n\n    return render_to_response(template_name,\n                              {'form': form},\n                              context_instance=context)\ncreate_profile = login_required(create_profile)\n\n\ndef edit_profile(request, form_class, success_url=None,\n                 template_name='profiles/private/edit_profile.html',\n                 extra_context=None):\n    \"\"\"\n    Edit the current user's profile.\n\n    If the user does not already have a profile, a redirect will be issued to\n    the :view:`profiles.views.create_profile` view.\n\n    **Optional arguments:**\n\n    ``extra_context``\n        A dictionary of variables to add to the template context. Any\n        callable object in this dictionary will be called to produce\n        the end result which appears in the context.\n\n    ``form_class``\n        The form class to use for validating and editing the user\n        profile. This form class must operate similarly to a standard\n        Django ``ModelForm`` in that it must accept an instance of the\n        object to be edited as the keyword argument ``instance`` to\n        its constructor, and it must implement a method named\n        ``save()`` which will save the updates to the object.\n\n    ``success_url``\n        The URL to redirect to following a successful edit. If not\n        specified, this will default to the URL of\n        :view:`profiles.views.profile_detail` for the profile object\n        being edited.\n\n    ``template_name``\n        The template to use when displaying the profile-editing\n        form. If not specified, this will default to\n        :template:`profiles/edit_profile.html`.\n\n    **Context:**\n\n    ``form``\n        The form for editing the profile.\n\n    ``profile``\n         The user's current profile.\n\n    **Template:**\n\n    ``template_name`` keyword argument or\n    :template:`profiles/edit_profile.html`.\n\n    \"\"\"\n    try:\n        profile_obj = request.user.profile\n    except ObjectDoesNotExist:\n        return HttpResponseRedirect(reverse('profiles_profile_create'))\n\n    if success_url is None:\n        success_url = reverse('profiles_profile_detail',\n                              kwargs={'username': request.user.username})\n    if request.method == 'POST':\n        form = form_class(data=request.POST, files=request.FILES, instance=profile_obj)\n        if form.is_valid():\n            form.save()\n            return HttpResponseRedirect(success_url)\n    else:\n        form = form_class(instance=profile_obj)\n\n    if extra_context is None:\n        extra_context = {}\n    context = RequestContext(request)\n    for key, value in list(extra_context.items()):\n        context[key] = (value() if callable(value) else value)\n\n    return render_to_response(template_name, {\n        'form': form,\n        'profile': profile_obj,\n        'user': profile_obj.user,\n    }, context_instance=context)\nedit_profile = login_required(edit_profile)\n\n\ndef profile_detail(request, username, public_profile_field=None,\n                   template_name='profiles/public/profile_detail.html',\n                   extra_context=None):\n    \"\"\"\n    Detail view of a user's profile.\n\n    If the user has not yet created a profile, ``Http404`` will be\n    raised.\n\n    **Required arguments:**\n\n    ``username``\n        The username of the user whose profile is being displayed.\n\n    **Optional arguments:**\n\n    ``extra_context``\n        A dictionary of variables to add to the template context. Any\n        callable object in this dictionary will be called to produce\n        the end result which appears in the context.\n\n    ``public_profile_field``\n        The name of a ``BooleanField`` on the profile model; if the\n        value of that field on the user's profile is ``False``, the\n        ``profile`` variable in the template will be ``None``. Use\n        this feature to allow users to mark their profiles as not\n        being publicly viewable.\n\n        If this argument is not specified, it will be assumed that all\n        users' profiles are publicly viewable.\n\n    ``template_name``\n        The name of the template to use for displaying the profile. If\n        not specified, this will default to\n        :template:`profiles/profile_detail.html`.\n\n    **Context:**\n\n    ``profile``\n        The user's profile, or ``None`` if the user's profile is not\n        publicly viewable (see the description of\n        ``public_profile_field`` above).\n\n    **Template:**\n\n    ``template_name`` keyword argument or\n    :template:`profiles/profile_detail.html`.\n\n    \"\"\"\n    user = get_object_or_404(User, username=username)\n    try:\n        profile_obj = user.profile\n    except ObjectDoesNotExist:\n        raise Http404\n    if public_profile_field is not None and \\\n       not getattr(profile_obj, public_profile_field):\n        profile_obj = None\n\n    if extra_context is None:\n        extra_context = {}\n    context = RequestContext(request)\n    for key, value in list(extra_context.items()):\n        context[key] = (value() if callable(value) else value)\n\n    return render_to_response(template_name,\n                              {'profile': profile_obj},\n                              context_instance=context)\n", "path": "readthedocs/profiles/views.py"}, {"content": "\"\"\"URL patterns for views to modify user profiles.\"\"\"\n\nfrom __future__ import absolute_import\nfrom django.conf.urls import url\n\nfrom readthedocs.core.forms import UserProfileForm\nfrom readthedocs.profiles import views\n\nurlpatterns = [\n    url(r'^create/', views.create_profile,\n        {\n            'form_class': UserProfileForm,\n        },\n        name='profiles_profile_create'),\n    url(r'^edit/', views.edit_profile,\n        {\n            'form_class': UserProfileForm,\n            'template_name': 'profiles/private/edit_profile.html',\n        },\n        name='profiles_profile_edit'),\n]\n", "path": "readthedocs/profiles/urls/private.py"}], "after_files": [{"content": "\"\"\"Forms for core app.\"\"\"\n\nfrom __future__ import absolute_import\nfrom builtins import object\nimport logging\n\nfrom django.contrib.auth.models import User\nfrom haystack.forms import SearchForm\nfrom haystack.query import SearchQuerySet\nfrom django import forms\nfrom django.forms.fields import CharField\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom .models import UserProfile\n\nlog = logging.getLogger(__name__)\n\n\nclass UserProfileForm(forms.ModelForm):\n    first_name = CharField(label=_('First name'), required=False)\n    last_name = CharField(label=_('Last name'), required=False)\n\n    class Meta(object):\n        model = UserProfile\n        # Don't allow users edit someone else's user page,\n        fields = ['first_name', 'last_name', 'homepage', 'allow_ads']\n\n    def __init__(self, *args, **kwargs):\n        super(UserProfileForm, self).__init__(*args, **kwargs)\n        try:\n            self.fields['first_name'].initial = self.instance.user.first_name\n            self.fields['last_name'].initial = self.instance.user.last_name\n        except AttributeError:\n            pass\n\n    def save(self, commit=True):\n        first_name = self.cleaned_data.pop('first_name', None)\n        last_name = self.cleaned_data.pop('last_name', None)\n        profile = super(UserProfileForm, self).save(commit=commit)\n        if commit:\n            user = profile.user\n            user.first_name = first_name\n            user.last_name = last_name\n            user.save()\n        return profile\n\n\nclass UserDeleteForm(forms.ModelForm):\n    username = CharField(label=_('Username'), help_text=_('Please type your username to confirm.'))\n\n    class Meta(object):\n        model = User\n        fields = ['username']\n\n    def clean_username(self):\n        data = self.cleaned_data['username']\n\n        if self.instance.username != data:\n            raise forms.ValidationError(_(\"Username does not match!\"))\n\n        return data\n\n\nclass FacetField(forms.MultipleChoiceField):\n\n    \"\"\"\n    For filtering searches on a facet.\n\n    Has validation for the format of facet values.\n    \"\"\"\n\n    def valid_value(self, value):\n        \"\"\"\n        Although this is a choice field, no choices need to be supplied.\n\n        Instead, we just validate that the value is in the correct format\n        for facet filtering (facet_name:value)\n        \"\"\"\n        if \":\" not in value:\n            return False\n        return True\n\n\nclass FacetedSearchForm(SearchForm):\n\n    \"\"\"\n    Supports fetching faceted results with a corresponding query.\n\n    `facets`\n        A list of facet names for which to get facet counts\n    `models`\n        Limit the search to one or more models\n    \"\"\"\n\n    selected_facets = FacetField(required=False)\n\n    def __init__(self, *args, **kwargs):\n        facets = kwargs.pop('facets', [])\n        models = kwargs.pop('models', [])\n        super(FacetedSearchForm, self).__init__(*args, **kwargs)\n\n        for facet in facets:\n            self.searchqueryset = self.searchqueryset.facet(facet)\n        if models:\n            self.searchqueryset = self.searchqueryset.models(*models)\n\n    def clean_selected_facets(self):\n        facets = self.cleaned_data['selected_facets']\n        cleaned_facets = []\n        clean = SearchQuerySet().query.clean\n        for facet in facets:\n            field, value = facet.split(\":\", 1)\n            if not value:  # Ignore empty values\n                continue\n            value = clean(value)\n            cleaned_facets.append(u'%s:\"%s\"' % (field, value))\n        return cleaned_facets\n\n    def search(self):\n        sqs = super(FacetedSearchForm, self).search()\n        for facet in self.cleaned_data['selected_facets']:\n            sqs = sqs.narrow(facet)\n        self.searchqueryset = sqs\n        return sqs\n", "path": "readthedocs/core/forms.py"}, {"content": "\"\"\"Views for creating, editing and viewing site-specific user profiles.\"\"\"\n\nfrom __future__ import absolute_import\n\nfrom django.contrib import messages\nfrom django.contrib.auth import logout\nfrom django.contrib.auth.decorators import login_required\nfrom django.contrib.auth.models import User\nfrom django.core.exceptions import ObjectDoesNotExist\nfrom django.core.urlresolvers import reverse\nfrom django.http import Http404\nfrom django.http import HttpResponseRedirect\nfrom django.shortcuts import get_object_or_404, render, redirect\nfrom django.shortcuts import render_to_response\nfrom django.template import RequestContext\n\nfrom readthedocs.core.forms import UserDeleteForm\n\n\ndef create_profile(request, form_class, success_url=None,\n                   template_name='profiles/private/create_profile.html',\n                   extra_context=None):\n    \"\"\"\n    Create a profile for the current user, if one doesn't already exist.\n\n    If the user already has a profile, a redirect will be issued to the\n    :view:`profiles.views.edit_profile` view.\n\n    **Optional arguments:**\n\n    ``extra_context``\n        A dictionary of variables to add to the template context. Any\n        callable object in this dictionary will be called to produce\n        the end result which appears in the context.\n\n    ``form_class``\n        The form class to use for validating and creating the user\n        profile. This form class must define a method named\n        ``save()``, implementing the same argument signature as the\n        ``save()`` method of a standard Django ``ModelForm`` (this\n        view will call ``save(commit=False)`` to obtain the profile\n        object, and fill in the user before the final save). If the\n        profile object includes many-to-many relations, the convention\n        established by ``ModelForm`` of using a method named\n        ``save_m2m()`` will be used, and so your form class should\n        also define this method.\n\n    ``success_url``\n        The URL to redirect to after successful profile creation. If\n        this argument is not supplied, this will default to the URL of\n        :view:`profiles.views.profile_detail` for the newly-created\n        profile object.\n\n    ``template_name``\n        The template to use when displaying the profile-creation\n        form. If not supplied, this will default to\n        :template:`profiles/create_profile.html`.\n\n    **Context:**\n\n    ``form``\n        The profile-creation form.\n\n    **Template:**\n\n    ``template_name`` keyword argument, or\n    :template:`profiles/create_profile.html`.\n\n    \"\"\"\n    try:\n        profile_obj = request.user.profile\n        return HttpResponseRedirect(reverse('profiles_edit_profile'))\n    except ObjectDoesNotExist:\n        pass\n\n    #\n    # We set up success_url here, rather than as the default value for\n    # the argument. Trying to do it as the argument's default would\n    # mean evaluating the call to reverse() at the time this module is\n    # first imported, which introduces a circular dependency: to\n    # perform the reverse lookup we need access to profiles/urls.py,\n    # but profiles/urls.py in turn imports this module.\n    #\n\n    if success_url is None:\n        success_url = reverse('profiles_profile_detail',\n                              kwargs={'username': request.user.username})\n    if request.method == 'POST':\n        form = form_class(data=request.POST, files=request.FILES)\n        if form.is_valid():\n            profile_obj = form.save(commit=False)\n            profile_obj.user = request.user\n            profile_obj.save()\n            if hasattr(form, 'save_m2m'):\n                form.save_m2m()\n            return HttpResponseRedirect(success_url)\n    else:\n        form = form_class()\n\n    if extra_context is None:\n        extra_context = {}\n    context = RequestContext(request)\n    for key, value in list(extra_context.items()):\n        context[key] = (value() if callable(value) else value)\n\n    return render_to_response(template_name,\n                              {'form': form},\n                              context_instance=context)\ncreate_profile = login_required(create_profile)\n\n\ndef edit_profile(request, form_class, success_url=None,\n                 template_name='profiles/private/edit_profile.html',\n                 extra_context=None):\n    \"\"\"\n    Edit the current user's profile.\n\n    If the user does not already have a profile, a redirect will be issued to\n    the :view:`profiles.views.create_profile` view.\n\n    **Optional arguments:**\n\n    ``extra_context``\n        A dictionary of variables to add to the template context. Any\n        callable object in this dictionary will be called to produce\n        the end result which appears in the context.\n\n    ``form_class``\n        The form class to use for validating and editing the user\n        profile. This form class must operate similarly to a standard\n        Django ``ModelForm`` in that it must accept an instance of the\n        object to be edited as the keyword argument ``instance`` to\n        its constructor, and it must implement a method named\n        ``save()`` which will save the updates to the object.\n\n    ``success_url``\n        The URL to redirect to following a successful edit. If not\n        specified, this will default to the URL of\n        :view:`profiles.views.profile_detail` for the profile object\n        being edited.\n\n    ``template_name``\n        The template to use when displaying the profile-editing\n        form. If not specified, this will default to\n        :template:`profiles/edit_profile.html`.\n\n    **Context:**\n\n    ``form``\n        The form for editing the profile.\n\n    ``profile``\n         The user's current profile.\n\n    **Template:**\n\n    ``template_name`` keyword argument or\n    :template:`profiles/edit_profile.html`.\n\n    \"\"\"\n    try:\n        profile_obj = request.user.profile\n    except ObjectDoesNotExist:\n        return HttpResponseRedirect(reverse('profiles_profile_create'))\n\n    if success_url is None:\n        success_url = reverse('profiles_profile_detail',\n                              kwargs={'username': request.user.username})\n    if request.method == 'POST':\n        form = form_class(data=request.POST, files=request.FILES, instance=profile_obj)\n        if form.is_valid():\n            form.save()\n            return HttpResponseRedirect(success_url)\n    else:\n        form = form_class(instance=profile_obj)\n\n    if extra_context is None:\n        extra_context = {}\n    context = RequestContext(request)\n    for key, value in list(extra_context.items()):\n        context[key] = (value() if callable(value) else value)\n\n    return render_to_response(template_name, {\n        'form': form,\n        'profile': profile_obj,\n        'user': profile_obj.user,\n    }, context_instance=context)\nedit_profile = login_required(edit_profile)\n\n\n@login_required()\ndef delete_account(request):\n    form = UserDeleteForm()\n    template_name = 'profiles/private/delete_account.html'\n\n    if request.method == 'POST':\n        form = UserDeleteForm(instance=request.user, data=request.POST)\n        if form.is_valid():\n\n            # Do not delete the account permanently because it may create disaster\n            # Inactive the user instead.\n            request.user.is_active = False\n            request.user.save()\n            logout(request)\n            messages.info(request, 'You have successfully deleted your account')\n\n            return redirect('homepage')\n\n    return render(request, template_name, {'form': form})\n\n\ndef profile_detail(request, username, public_profile_field=None,\n                   template_name='profiles/public/profile_detail.html',\n                   extra_context=None):\n    \"\"\"\n    Detail view of a user's profile.\n\n    If the user has not yet created a profile, ``Http404`` will be\n    raised.\n\n    **Required arguments:**\n\n    ``username``\n        The username of the user whose profile is being displayed.\n\n    **Optional arguments:**\n\n    ``extra_context``\n        A dictionary of variables to add to the template context. Any\n        callable object in this dictionary will be called to produce\n        the end result which appears in the context.\n\n    ``public_profile_field``\n        The name of a ``BooleanField`` on the profile model; if the\n        value of that field on the user's profile is ``False``, the\n        ``profile`` variable in the template will be ``None``. Use\n        this feature to allow users to mark their profiles as not\n        being publicly viewable.\n\n        If this argument is not specified, it will be assumed that all\n        users' profiles are publicly viewable.\n\n    ``template_name``\n        The name of the template to use for displaying the profile. If\n        not specified, this will default to\n        :template:`profiles/profile_detail.html`.\n\n    **Context:**\n\n    ``profile``\n        The user's profile, or ``None`` if the user's profile is not\n        publicly viewable (see the description of\n        ``public_profile_field`` above).\n\n    **Template:**\n\n    ``template_name`` keyword argument or\n    :template:`profiles/profile_detail.html`.\n\n    \"\"\"\n    user = get_object_or_404(User, username=username)\n    try:\n        profile_obj = user.profile\n    except ObjectDoesNotExist:\n        raise Http404\n    if public_profile_field is not None and \\\n       not getattr(profile_obj, public_profile_field):\n        profile_obj = None\n\n    if extra_context is None:\n        extra_context = {}\n    context = RequestContext(request)\n    for key, value in list(extra_context.items()):\n        context[key] = (value() if callable(value) else value)\n\n    return render_to_response(template_name,\n                              {'profile': profile_obj},\n                              context_instance=context)\n", "path": "readthedocs/profiles/views.py"}, {"content": "\"\"\"URL patterns for views to modify user profiles.\"\"\"\n\nfrom __future__ import absolute_import\nfrom django.conf.urls import url\n\nfrom readthedocs.core.forms import UserProfileForm\nfrom readthedocs.profiles import views\n\nurlpatterns = [\n    url(r'^create/', views.create_profile,\n        {\n            'form_class': UserProfileForm,\n        },\n        name='profiles_profile_create'),\n    url(r'^edit/', views.edit_profile,\n        {\n            'form_class': UserProfileForm,\n            'template_name': 'profiles/private/edit_profile.html',\n        },\n        name='profiles_profile_edit'),\n    url(r'^delete/', views.delete_account, name='delete_account')\n]\n", "path": "readthedocs/profiles/urls/private.py"}]}