We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Change profile edit form success page
Currently, when a user saves the profile edit form, the success page is not the profile form page, the user gets redirected to the profile public view page. This is quite confusing UX but might be baked into Allauth. I would expect this end up on the profile edit form page instead.

--- 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/profiles/views.py`
Content:
```
1 """Views for creating, editing and viewing site-specific user profiles."""
2 
3 from allauth.account.views import LoginView as AllAuthLoginView
4 from allauth.account.views import LogoutView as AllAuthLogoutView
5 from django.conf import settings
6 from django.contrib import messages
7 from django.contrib.auth import logout
8 from django.contrib.auth.models import User
9 from django.contrib.messages.views import SuccessMessageMixin
10 from django.http import Http404, HttpResponseRedirect
11 from django.urls import reverse
12 from django.utils import timezone
13 from django.utils.translation import gettext_lazy as _
14 from rest_framework.authtoken.models import Token
15 from vanilla import CreateView, DeleteView, DetailView, FormView, ListView, UpdateView
16 
17 from readthedocs.audit.filters import UserSecurityLogFilter
18 from readthedocs.audit.models import AuditLog
19 from readthedocs.core.forms import UserAdvertisingForm, UserDeleteForm, UserProfileForm
20 from readthedocs.core.history import set_change_reason
21 from readthedocs.core.mixins import PrivateViewMixin
22 from readthedocs.core.models import UserProfile
23 from readthedocs.core.permissions import AdminPermission
24 from readthedocs.core.utils.extend import SettingsOverrideObject
25 from readthedocs.organizations.models import Organization
26 from readthedocs.projects.models import Project
27 from readthedocs.projects.utils import get_csv_file
28 
29 
30 class LoginViewBase(AllAuthLoginView):
31 
32     pass
33 
34 
35 class LoginView(SettingsOverrideObject):
36 
37     _default_class = LoginViewBase
38 
39 
40 class LogoutViewBase(AllAuthLogoutView):
41 
42     pass
43 
44 
45 class LogoutView(SettingsOverrideObject):
46 
47     _default_class = LogoutViewBase
48 
49 
50 class ProfileEdit(PrivateViewMixin, UpdateView):
51 
52     """Edit the current user's profile."""
53 
54     model = UserProfile
55     form_class = UserProfileForm
56     template_name = 'profiles/private/edit_profile.html'
57     context_object_name = 'profile'
58 
59     def get_object(self):
60         return self.request.user.profile
61 
62     def get_success_url(self):
63         return reverse(
64             'profiles_profile_detail',
65             kwargs={'username': self.request.user.username},
66         )
67 
68 
69 class AccountDelete(PrivateViewMixin, SuccessMessageMixin, FormView):
70 
71     form_class = UserDeleteForm
72     template_name = 'profiles/private/delete_account.html'
73     success_message = _('You have successfully deleted your account')
74 
75     def get_object(self):
76         return User.objects.get(pk=self.request.user.pk)
77 
78     def form_valid(self, form):
79         user = self.get_object()
80         logout(self.request)
81         set_change_reason(user, self.get_change_reason())
82         user.delete()
83         return super().form_valid(form)
84 
85     def get_form(self, data=None, files=None, **kwargs):
86         kwargs['instance'] = self.get_object()
87         kwargs['initial'] = {'username': ''}
88         return super().get_form(data, files, **kwargs)
89 
90     def get_context_data(self, **kwargs):
91         context = super().get_context_data(**kwargs)
92         user = self.request.user
93         context["projects_to_be_deleted"] = Project.objects.single_owner(user)
94         context["organizations_to_be_deleted"] = Organization.objects.single_owner(user)
95         return context
96 
97     def get_success_url(self):
98         return reverse('homepage')
99 
100     def get_change_reason(self):
101         klass = self.__class__.__name__
102         return f'origin=form class={klass}'
103 
104 
105 class ProfileDetail(DetailView):
106 
107     model = User
108     template_name = 'profiles/public/profile_detail.html'
109     lookup_field = 'username'
110 
111     def get_object(self):
112         """
113         Get the user object.
114 
115         If organizations are enabled, show the profile to users in the same organization only.
116         Otherwise, all users can see the profile of others.
117         """
118         user = super().get_object()
119         if not settings.RTD_ALLOW_ORGANIZATIONS:
120             return user
121 
122         request_user = self.request.user
123         if not request_user.is_authenticated:
124             raise Http404()
125 
126         # Always allow users to see their own profile.
127         if request_user == user:
128             return user
129 
130         for org in Organization.objects.for_user(request_user):
131             if AdminPermission.is_member(user=user, obj=org):
132                 return user
133         raise Http404()
134 
135     def get_context_data(self, **kwargs):
136         context = super().get_context_data(**kwargs)
137         context['profile'] = self.get_object().profile
138         return context
139 
140 
141 class AccountAdvertisingEdit(PrivateViewMixin, SuccessMessageMixin, UpdateView):
142 
143     model = UserProfile
144     form_class = UserAdvertisingForm
145     context_object_name = 'profile'
146     template_name = 'profiles/private/advertising_profile.html'
147     success_message = _('Updated your advertising preferences')
148 
149     def get_object(self):
150         return self.request.user.profile
151 
152     def get_success_url(self):
153         return reverse('account_advertising')
154 
155 
156 class TokenMixin(PrivateViewMixin):
157 
158     """User token to access APIv3."""
159 
160     model = Token
161     lookup_url_kwarg = 'token_pk'
162     template_name = 'profiles/private/token_list.html'
163 
164     def get_queryset(self):
165         # NOTE: we are currently showing just one token since the DRF model has
166         # a OneToOneField relation with User. Although, we plan to have multiple
167         # scope-based tokens.
168         return Token.objects.filter(user__in=[self.request.user])
169 
170     def get_success_url(self):
171         return reverse('profiles_tokens')
172 
173 
174 class TokenListView(TokenMixin, ListView):
175     pass
176 
177 
178 class TokenCreateView(TokenMixin, CreateView):
179 
180     """Simple view to generate a Token object for the logged in User."""
181 
182     http_method_names = ['post']
183 
184     def post(self, request, *args, **kwargs):
185         _, created = Token.objects.get_or_create(user=self.request.user)
186         if created:
187             messages.info(request, 'API Token created successfully')
188         return HttpResponseRedirect(self.get_success_url())
189 
190 
191 class TokenDeleteView(TokenMixin, DeleteView):
192 
193     """View to delete/revoke the current Token of the logged in User."""
194 
195     http_method_names = ['post']
196 
197     def get_object(self, queryset=None):  # noqa
198         return self.request.user.auth_token
199 
200 
201 class UserSecurityLogView(PrivateViewMixin, ListView):
202     model = AuditLog
203     template_name = 'profiles/private/security_log.html'
204     days_limit = settings.RTD_AUDITLOGS_DEFAULT_RETENTION_DAYS
205 
206     def get(self, request, *args, **kwargs):
207         download_data = request.GET.get('download', False)
208         if download_data:
209             return self._get_csv_data()
210         return super().get(request, *args, **kwargs)
211 
212     def _get_start_date(self):
213         """Get the date to show logs from."""
214         creation_date = self.request.user.date_joined.date()
215         start_date = timezone.now().date() - timezone.timedelta(days=self.days_limit)
216         # The max we can go back is to the creation of the user.
217         return max(start_date, creation_date)
218 
219     def _get_csv_data(self):
220         current_timezone = settings.TIME_ZONE
221         values = [
222             (f"Date ({current_timezone})", "created"),
223             ("User", "log_user_username"),
224             ("Project", "log_project_slug"),
225             ("Organization", "log_organization_slug"),
226             ("Action", "action"),
227             ("IP", "ip"),
228             ("Browser", "browser"),
229             ("Extra data", "data"),
230         ]
231         data = self.get_queryset().values_list(*[value for _, value in values])
232 
233         start_date = self._get_start_date()
234         end_date = timezone.now().date()
235         date_filter = self.filter.form.cleaned_data.get('date')
236         if date_filter:
237             start_date = date_filter.start or start_date
238             end_date = date_filter.stop or end_date
239 
240         filename = 'readthedocs_user_security_logs_{username}_{start}_{end}.csv'.format(
241             username=self.request.user.username,
242             start=timezone.datetime.strftime(start_date, '%Y-%m-%d'),
243             end=timezone.datetime.strftime(end_date, '%Y-%m-%d'),
244         )
245         csv_data = [
246             [timezone.datetime.strftime(date, '%Y-%m-%d %H:%M:%S'), *rest]
247             for date, *rest in data
248         ]
249         csv_data.insert(0, [header for header, _ in values])
250         return get_csv_file(filename=filename, csv_data=csv_data)
251 
252     def get_context_data(self, **kwargs):
253         context = super().get_context_data(**kwargs)
254         context['days_limit'] = self.days_limit
255         context['filter'] = self.filter
256         context['AuditLog'] = AuditLog
257         return context
258 
259     def _get_queryset(self):
260         """Return the queryset without filters."""
261         user = self.request.user
262         start_date = self._get_start_date()
263         queryset = AuditLog.objects.filter(
264             user=user,
265             action__in=[action for action, _ in UserSecurityLogFilter.allowed_actions],
266             created__gte=start_date,
267         )
268         return queryset
269 
270     def get_queryset(self):
271         """
272         Return the queryset with filters.
273 
274         If you want the original queryset without filters,
275         use `_get_queryset`.
276         """
277         queryset = self._get_queryset()
278         # Set filter on self, so we can use it in the context.
279         # Without executing it twice.
280         self.filter = UserSecurityLogFilter(
281             self.request.GET,
282             queryset=queryset,
283         )
284         return self.filter.qs
285
```
--- 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/profiles/views.py b/readthedocs/profiles/views.py
--- a/readthedocs/profiles/views.py
+++ b/readthedocs/profiles/views.py
@@ -61,8 +61,7 @@
 
     def get_success_url(self):
         return reverse(
-            'profiles_profile_detail',
-            kwargs={'username': self.request.user.username},
+            "profiles_profile_edit",
         )

{"golden_diff": "diff --git a/readthedocs/profiles/views.py b/readthedocs/profiles/views.py\n--- a/readthedocs/profiles/views.py\n+++ b/readthedocs/profiles/views.py\n@@ -61,8 +61,7 @@\n \n     def get_success_url(self):\n         return reverse(\n-            'profiles_profile_detail',\n-            kwargs={'username': self.request.user.username},\n+            \"profiles_profile_edit\",\n         )\n", "issue": "Change profile edit form success page\nCurrently, when a user saves the profile edit form, the success page is not the profile form page, the user gets redirected to the profile public view page. This is quite confusing UX but might be baked into Allauth. I would expect this end up on the profile edit form page instead.\n", "before_files": [{"content": "\"\"\"Views for creating, editing and viewing site-specific user profiles.\"\"\"\n\nfrom allauth.account.views import LoginView as AllAuthLoginView\nfrom allauth.account.views import LogoutView as AllAuthLogoutView\nfrom django.conf import settings\nfrom django.contrib import messages\nfrom django.contrib.auth import logout\nfrom django.contrib.auth.models import User\nfrom django.contrib.messages.views import SuccessMessageMixin\nfrom django.http import Http404, HttpResponseRedirect\nfrom django.urls import reverse\nfrom django.utils import timezone\nfrom django.utils.translation import gettext_lazy as _\nfrom rest_framework.authtoken.models import Token\nfrom vanilla import CreateView, DeleteView, DetailView, FormView, ListView, UpdateView\n\nfrom readthedocs.audit.filters import UserSecurityLogFilter\nfrom readthedocs.audit.models import AuditLog\nfrom readthedocs.core.forms import UserAdvertisingForm, UserDeleteForm, UserProfileForm\nfrom readthedocs.core.history import set_change_reason\nfrom readthedocs.core.mixins import PrivateViewMixin\nfrom readthedocs.core.models import UserProfile\nfrom readthedocs.core.permissions import AdminPermission\nfrom readthedocs.core.utils.extend import SettingsOverrideObject\nfrom readthedocs.organizations.models import Organization\nfrom readthedocs.projects.models import Project\nfrom readthedocs.projects.utils import get_csv_file\n\n\nclass LoginViewBase(AllAuthLoginView):\n\n    pass\n\n\nclass LoginView(SettingsOverrideObject):\n\n    _default_class = LoginViewBase\n\n\nclass LogoutViewBase(AllAuthLogoutView):\n\n    pass\n\n\nclass LogoutView(SettingsOverrideObject):\n\n    _default_class = LogoutViewBase\n\n\nclass ProfileEdit(PrivateViewMixin, UpdateView):\n\n    \"\"\"Edit the current user's profile.\"\"\"\n\n    model = UserProfile\n    form_class = UserProfileForm\n    template_name = 'profiles/private/edit_profile.html'\n    context_object_name = 'profile'\n\n    def get_object(self):\n        return self.request.user.profile\n\n    def get_success_url(self):\n        return reverse(\n            'profiles_profile_detail',\n            kwargs={'username': self.request.user.username},\n        )\n\n\nclass AccountDelete(PrivateViewMixin, SuccessMessageMixin, FormView):\n\n    form_class = UserDeleteForm\n    template_name = 'profiles/private/delete_account.html'\n    success_message = _('You have successfully deleted your account')\n\n    def get_object(self):\n        return User.objects.get(pk=self.request.user.pk)\n\n    def form_valid(self, form):\n        user = self.get_object()\n        logout(self.request)\n        set_change_reason(user, self.get_change_reason())\n        user.delete()\n        return super().form_valid(form)\n\n    def get_form(self, data=None, files=None, **kwargs):\n        kwargs['instance'] = self.get_object()\n        kwargs['initial'] = {'username': ''}\n        return super().get_form(data, files, **kwargs)\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        user = self.request.user\n        context[\"projects_to_be_deleted\"] = Project.objects.single_owner(user)\n        context[\"organizations_to_be_deleted\"] = Organization.objects.single_owner(user)\n        return context\n\n    def get_success_url(self):\n        return reverse('homepage')\n\n    def get_change_reason(self):\n        klass = self.__class__.__name__\n        return f'origin=form class={klass}'\n\n\nclass ProfileDetail(DetailView):\n\n    model = User\n    template_name = 'profiles/public/profile_detail.html'\n    lookup_field = 'username'\n\n    def get_object(self):\n        \"\"\"\n        Get the user object.\n\n        If organizations are enabled, show the profile to users in the same organization only.\n        Otherwise, all users can see the profile of others.\n        \"\"\"\n        user = super().get_object()\n        if not settings.RTD_ALLOW_ORGANIZATIONS:\n            return user\n\n        request_user = self.request.user\n        if not request_user.is_authenticated:\n            raise Http404()\n\n        # Always allow users to see their own profile.\n        if request_user == user:\n            return user\n\n        for org in Organization.objects.for_user(request_user):\n            if AdminPermission.is_member(user=user, obj=org):\n                return user\n        raise Http404()\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['profile'] = self.get_object().profile\n        return context\n\n\nclass AccountAdvertisingEdit(PrivateViewMixin, SuccessMessageMixin, UpdateView):\n\n    model = UserProfile\n    form_class = UserAdvertisingForm\n    context_object_name = 'profile'\n    template_name = 'profiles/private/advertising_profile.html'\n    success_message = _('Updated your advertising preferences')\n\n    def get_object(self):\n        return self.request.user.profile\n\n    def get_success_url(self):\n        return reverse('account_advertising')\n\n\nclass TokenMixin(PrivateViewMixin):\n\n    \"\"\"User token to access APIv3.\"\"\"\n\n    model = Token\n    lookup_url_kwarg = 'token_pk'\n    template_name = 'profiles/private/token_list.html'\n\n    def get_queryset(self):\n        # NOTE: we are currently showing just one token since the DRF model has\n        # a OneToOneField relation with User. Although, we plan to have multiple\n        # scope-based tokens.\n        return Token.objects.filter(user__in=[self.request.user])\n\n    def get_success_url(self):\n        return reverse('profiles_tokens')\n\n\nclass TokenListView(TokenMixin, ListView):\n    pass\n\n\nclass TokenCreateView(TokenMixin, CreateView):\n\n    \"\"\"Simple view to generate a Token object for the logged in User.\"\"\"\n\n    http_method_names = ['post']\n\n    def post(self, request, *args, **kwargs):\n        _, created = Token.objects.get_or_create(user=self.request.user)\n        if created:\n            messages.info(request, 'API Token created successfully')\n        return HttpResponseRedirect(self.get_success_url())\n\n\nclass TokenDeleteView(TokenMixin, DeleteView):\n\n    \"\"\"View to delete/revoke the current Token of the logged in User.\"\"\"\n\n    http_method_names = ['post']\n\n    def get_object(self, queryset=None):  # noqa\n        return self.request.user.auth_token\n\n\nclass UserSecurityLogView(PrivateViewMixin, ListView):\n    model = AuditLog\n    template_name = 'profiles/private/security_log.html'\n    days_limit = settings.RTD_AUDITLOGS_DEFAULT_RETENTION_DAYS\n\n    def get(self, request, *args, **kwargs):\n        download_data = request.GET.get('download', False)\n        if download_data:\n            return self._get_csv_data()\n        return super().get(request, *args, **kwargs)\n\n    def _get_start_date(self):\n        \"\"\"Get the date to show logs from.\"\"\"\n        creation_date = self.request.user.date_joined.date()\n        start_date = timezone.now().date() - timezone.timedelta(days=self.days_limit)\n        # The max we can go back is to the creation of the user.\n        return max(start_date, creation_date)\n\n    def _get_csv_data(self):\n        current_timezone = settings.TIME_ZONE\n        values = [\n            (f\"Date ({current_timezone})\", \"created\"),\n            (\"User\", \"log_user_username\"),\n            (\"Project\", \"log_project_slug\"),\n            (\"Organization\", \"log_organization_slug\"),\n            (\"Action\", \"action\"),\n            (\"IP\", \"ip\"),\n            (\"Browser\", \"browser\"),\n            (\"Extra data\", \"data\"),\n        ]\n        data = self.get_queryset().values_list(*[value for _, value in values])\n\n        start_date = self._get_start_date()\n        end_date = timezone.now().date()\n        date_filter = self.filter.form.cleaned_data.get('date')\n        if date_filter:\n            start_date = date_filter.start or start_date\n            end_date = date_filter.stop or end_date\n\n        filename = 'readthedocs_user_security_logs_{username}_{start}_{end}.csv'.format(\n            username=self.request.user.username,\n            start=timezone.datetime.strftime(start_date, '%Y-%m-%d'),\n            end=timezone.datetime.strftime(end_date, '%Y-%m-%d'),\n        )\n        csv_data = [\n            [timezone.datetime.strftime(date, '%Y-%m-%d %H:%M:%S'), *rest]\n            for date, *rest in data\n        ]\n        csv_data.insert(0, [header for header, _ in values])\n        return get_csv_file(filename=filename, csv_data=csv_data)\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['days_limit'] = self.days_limit\n        context['filter'] = self.filter\n        context['AuditLog'] = AuditLog\n        return context\n\n    def _get_queryset(self):\n        \"\"\"Return the queryset without filters.\"\"\"\n        user = self.request.user\n        start_date = self._get_start_date()\n        queryset = AuditLog.objects.filter(\n            user=user,\n            action__in=[action for action, _ in UserSecurityLogFilter.allowed_actions],\n            created__gte=start_date,\n        )\n        return queryset\n\n    def get_queryset(self):\n        \"\"\"\n        Return the queryset with filters.\n\n        If you want the original queryset without filters,\n        use `_get_queryset`.\n        \"\"\"\n        queryset = self._get_queryset()\n        # Set filter on self, so we can use it in the context.\n        # Without executing it twice.\n        self.filter = UserSecurityLogFilter(\n            self.request.GET,\n            queryset=queryset,\n        )\n        return self.filter.qs\n", "path": "readthedocs/profiles/views.py"}], "after_files": [{"content": "\"\"\"Views for creating, editing and viewing site-specific user profiles.\"\"\"\n\nfrom allauth.account.views import LoginView as AllAuthLoginView\nfrom allauth.account.views import LogoutView as AllAuthLogoutView\nfrom django.conf import settings\nfrom django.contrib import messages\nfrom django.contrib.auth import logout\nfrom django.contrib.auth.models import User\nfrom django.contrib.messages.views import SuccessMessageMixin\nfrom django.http import Http404, HttpResponseRedirect\nfrom django.urls import reverse\nfrom django.utils import timezone\nfrom django.utils.translation import gettext_lazy as _\nfrom rest_framework.authtoken.models import Token\nfrom vanilla import CreateView, DeleteView, DetailView, FormView, ListView, UpdateView\n\nfrom readthedocs.audit.filters import UserSecurityLogFilter\nfrom readthedocs.audit.models import AuditLog\nfrom readthedocs.core.forms import UserAdvertisingForm, UserDeleteForm, UserProfileForm\nfrom readthedocs.core.history import set_change_reason\nfrom readthedocs.core.mixins import PrivateViewMixin\nfrom readthedocs.core.models import UserProfile\nfrom readthedocs.core.permissions import AdminPermission\nfrom readthedocs.core.utils.extend import SettingsOverrideObject\nfrom readthedocs.organizations.models import Organization\nfrom readthedocs.projects.models import Project\nfrom readthedocs.projects.utils import get_csv_file\n\n\nclass LoginViewBase(AllAuthLoginView):\n\n    pass\n\n\nclass LoginView(SettingsOverrideObject):\n\n    _default_class = LoginViewBase\n\n\nclass LogoutViewBase(AllAuthLogoutView):\n\n    pass\n\n\nclass LogoutView(SettingsOverrideObject):\n\n    _default_class = LogoutViewBase\n\n\nclass ProfileEdit(PrivateViewMixin, UpdateView):\n\n    \"\"\"Edit the current user's profile.\"\"\"\n\n    model = UserProfile\n    form_class = UserProfileForm\n    template_name = 'profiles/private/edit_profile.html'\n    context_object_name = 'profile'\n\n    def get_object(self):\n        return self.request.user.profile\n\n    def get_success_url(self):\n        return reverse(\n            \"profiles_profile_edit\",\n        )\n\n\nclass AccountDelete(PrivateViewMixin, SuccessMessageMixin, FormView):\n\n    form_class = UserDeleteForm\n    template_name = 'profiles/private/delete_account.html'\n    success_message = _('You have successfully deleted your account')\n\n    def get_object(self):\n        return User.objects.get(pk=self.request.user.pk)\n\n    def form_valid(self, form):\n        user = self.get_object()\n        logout(self.request)\n        set_change_reason(user, self.get_change_reason())\n        user.delete()\n        return super().form_valid(form)\n\n    def get_form(self, data=None, files=None, **kwargs):\n        kwargs['instance'] = self.get_object()\n        kwargs['initial'] = {'username': ''}\n        return super().get_form(data, files, **kwargs)\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        user = self.request.user\n        context[\"projects_to_be_deleted\"] = Project.objects.single_owner(user)\n        context[\"organizations_to_be_deleted\"] = Organization.objects.single_owner(user)\n        return context\n\n    def get_success_url(self):\n        return reverse('homepage')\n\n    def get_change_reason(self):\n        klass = self.__class__.__name__\n        return f'origin=form class={klass}'\n\n\nclass ProfileDetail(DetailView):\n\n    model = User\n    template_name = 'profiles/public/profile_detail.html'\n    lookup_field = 'username'\n\n    def get_object(self):\n        \"\"\"\n        Get the user object.\n\n        If organizations are enabled, show the profile to users in the same organization only.\n        Otherwise, all users can see the profile of others.\n        \"\"\"\n        user = super().get_object()\n        if not settings.RTD_ALLOW_ORGANIZATIONS:\n            return user\n\n        request_user = self.request.user\n        if not request_user.is_authenticated:\n            raise Http404()\n\n        # Always allow users to see their own profile.\n        if request_user == user:\n            return user\n\n        for org in Organization.objects.for_user(request_user):\n            if AdminPermission.is_member(user=user, obj=org):\n                return user\n        raise Http404()\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['profile'] = self.get_object().profile\n        return context\n\n\nclass AccountAdvertisingEdit(PrivateViewMixin, SuccessMessageMixin, UpdateView):\n\n    model = UserProfile\n    form_class = UserAdvertisingForm\n    context_object_name = 'profile'\n    template_name = 'profiles/private/advertising_profile.html'\n    success_message = _('Updated your advertising preferences')\n\n    def get_object(self):\n        return self.request.user.profile\n\n    def get_success_url(self):\n        return reverse('account_advertising')\n\n\nclass TokenMixin(PrivateViewMixin):\n\n    \"\"\"User token to access APIv3.\"\"\"\n\n    model = Token\n    lookup_url_kwarg = 'token_pk'\n    template_name = 'profiles/private/token_list.html'\n\n    def get_queryset(self):\n        # NOTE: we are currently showing just one token since the DRF model has\n        # a OneToOneField relation with User. Although, we plan to have multiple\n        # scope-based tokens.\n        return Token.objects.filter(user__in=[self.request.user])\n\n    def get_success_url(self):\n        return reverse('profiles_tokens')\n\n\nclass TokenListView(TokenMixin, ListView):\n    pass\n\n\nclass TokenCreateView(TokenMixin, CreateView):\n\n    \"\"\"Simple view to generate a Token object for the logged in User.\"\"\"\n\n    http_method_names = ['post']\n\n    def post(self, request, *args, **kwargs):\n        _, created = Token.objects.get_or_create(user=self.request.user)\n        if created:\n            messages.info(request, 'API Token created successfully')\n        return HttpResponseRedirect(self.get_success_url())\n\n\nclass TokenDeleteView(TokenMixin, DeleteView):\n\n    \"\"\"View to delete/revoke the current Token of the logged in User.\"\"\"\n\n    http_method_names = ['post']\n\n    def get_object(self, queryset=None):  # noqa\n        return self.request.user.auth_token\n\n\nclass UserSecurityLogView(PrivateViewMixin, ListView):\n    model = AuditLog\n    template_name = 'profiles/private/security_log.html'\n    days_limit = settings.RTD_AUDITLOGS_DEFAULT_RETENTION_DAYS\n\n    def get(self, request, *args, **kwargs):\n        download_data = request.GET.get('download', False)\n        if download_data:\n            return self._get_csv_data()\n        return super().get(request, *args, **kwargs)\n\n    def _get_start_date(self):\n        \"\"\"Get the date to show logs from.\"\"\"\n        creation_date = self.request.user.date_joined.date()\n        start_date = timezone.now().date() - timezone.timedelta(days=self.days_limit)\n        # The max we can go back is to the creation of the user.\n        return max(start_date, creation_date)\n\n    def _get_csv_data(self):\n        current_timezone = settings.TIME_ZONE\n        values = [\n            (f\"Date ({current_timezone})\", \"created\"),\n            (\"User\", \"log_user_username\"),\n            (\"Project\", \"log_project_slug\"),\n            (\"Organization\", \"log_organization_slug\"),\n            (\"Action\", \"action\"),\n            (\"IP\", \"ip\"),\n            (\"Browser\", \"browser\"),\n            (\"Extra data\", \"data\"),\n        ]\n        data = self.get_queryset().values_list(*[value for _, value in values])\n\n        start_date = self._get_start_date()\n        end_date = timezone.now().date()\n        date_filter = self.filter.form.cleaned_data.get('date')\n        if date_filter:\n            start_date = date_filter.start or start_date\n            end_date = date_filter.stop or end_date\n\n        filename = 'readthedocs_user_security_logs_{username}_{start}_{end}.csv'.format(\n            username=self.request.user.username,\n            start=timezone.datetime.strftime(start_date, '%Y-%m-%d'),\n            end=timezone.datetime.strftime(end_date, '%Y-%m-%d'),\n        )\n        csv_data = [\n            [timezone.datetime.strftime(date, '%Y-%m-%d %H:%M:%S'), *rest]\n            for date, *rest in data\n        ]\n        csv_data.insert(0, [header for header, _ in values])\n        return get_csv_file(filename=filename, csv_data=csv_data)\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['days_limit'] = self.days_limit\n        context['filter'] = self.filter\n        context['AuditLog'] = AuditLog\n        return context\n\n    def _get_queryset(self):\n        \"\"\"Return the queryset without filters.\"\"\"\n        user = self.request.user\n        start_date = self._get_start_date()\n        queryset = AuditLog.objects.filter(\n            user=user,\n            action__in=[action for action, _ in UserSecurityLogFilter.allowed_actions],\n            created__gte=start_date,\n        )\n        return queryset\n\n    def get_queryset(self):\n        \"\"\"\n        Return the queryset with filters.\n\n        If you want the original queryset without filters,\n        use `_get_queryset`.\n        \"\"\"\n        queryset = self._get_queryset()\n        # Set filter on self, so we can use it in the context.\n        # Without executing it twice.\n        self.filter = UserSecurityLogFilter(\n            self.request.GET,\n            queryset=queryset,\n        )\n        return self.filter.qs\n", "path": "readthedocs/profiles/views.py"}]}