views: add a delete_account view on /accounts/delete
It desactivate then logout the requesting user. A model DeletedUser is created. The cleanup() method of the DeletedUser manager will delete the user account and the deleted user object.
This commit is contained in:
parent
892502e3d5
commit
67ce8619ad
|
@ -376,6 +376,15 @@ object is created. By default this new ``User`` has both ``is_staff`` and
|
|||
The default PAM service used is ``login`` but you can change it by setting the
|
||||
``PAM_SERVICE`` variable in your ``settings.py`` file.
|
||||
|
||||
Cronjobs
|
||||
========
|
||||
|
||||
The following cronjob must be run to clean deleted accounts and temporary objects::
|
||||
|
||||
5 0 * * * athentic2-ctl cleanup
|
||||
|
||||
It's made to run every day at 00:05.
|
||||
|
||||
Roadmap
|
||||
=======
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
{% endfor %}
|
||||
</dl>
|
||||
{% endif %}
|
||||
<p> <a href="{% url 'profile_edit' %}">{% trans "Edit profile" %}</a></p>
|
||||
<p><a href="{% url 'profile_edit' %}">{% trans "Edit profile" %}</a></p>
|
||||
<p><a href="{% url 'delete_account' %}">{% trans "Delete profile" %}</a></p>
|
||||
</div>
|
||||
<h3>{% trans "Credentials" %}</h3>
|
||||
{% for html_block in frontends_block %}
|
||||
|
|
|
@ -78,8 +78,12 @@ def profile(request):
|
|||
# Credentials management
|
||||
blocks = [ frontend.profile(request, next='/profile') for frontend in frontends \
|
||||
if hasattr(frontend, 'profile') ]
|
||||
return render_to_response('idp/account_management.html', { 'frontends_block': blocks, 'profile': profile },
|
||||
RequestContext(request))
|
||||
return render_to_response('idp/account_management.html', {
|
||||
'frontends_block': blocks,
|
||||
'profile': profile,
|
||||
'allow_account_deletion': settings.AUTHENTIC2_ALLOW_ACCOUNT_DELETION,
|
||||
},
|
||||
RequestContext(request))
|
||||
|
||||
def logout_list(request):
|
||||
'''Return logout links from idp backends'''
|
||||
|
|
|
@ -14,6 +14,9 @@ from django.utils.http import urlquote
|
|||
from django.conf import settings
|
||||
|
||||
|
||||
import managers
|
||||
|
||||
|
||||
class UserManager(BaseUserManager):
|
||||
def create_user(self, username, email=None, password=None, **extra_fields):
|
||||
"""
|
||||
|
@ -163,6 +166,19 @@ class AbstractUser(AbstractBaseUser, PermissionsMixin):
|
|||
roles = property(get_roles)
|
||||
|
||||
|
||||
class DeletedUser(models.Model):
|
||||
'''Record users to delete'''
|
||||
|
||||
objects = managers.DeletedUserManager()
|
||||
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL)
|
||||
creation = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('user to delete')
|
||||
verbose_name_plural = _('users to delete')
|
||||
|
||||
|
||||
if settings.AUTH_USER_MODEL == 'authentic2.User':
|
||||
class User(AbstractUser):
|
||||
first_name = models.CharField(_('first name'), max_length=30, blank=True)
|
||||
|
|
|
@ -116,6 +116,7 @@ MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
|
|||
# Registration settings
|
||||
ACCOUNT_ACTIVATION_DAYS = int(os.environ.get('ACCOUNT_ACTIVATION_DAYS', 3))
|
||||
PASSWORD_RESET_TIMEOUT_DAYS = int(os.environ.get('PASSWORD_RESET_TIMEOUT_DAYS', 3))
|
||||
AUTHENTIC2_ALLOW_ACCOUNT_DELETION = True
|
||||
|
||||
# authentication
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
|
|
|
@ -17,8 +17,9 @@ urlpatterns = patterns('',
|
|||
(r'^$', login_required(authentic2.idp.views.homepage), {}, 'index'))
|
||||
|
||||
not_homepage_patterns = patterns('',
|
||||
(r'^', include('authentic2.auth2_auth.urls')),
|
||||
(r'^redirect/(.*)', 'authentic2.views.redirect'),
|
||||
url(r'^', include('authentic2.auth2_auth.urls')),
|
||||
url(r'^redirect/(.*)', 'authentic2.views.redirect'),
|
||||
url(r'^accounts/delete/', 'authentic2.views.delete_account', name='delete_account'),
|
||||
url(r'^accounts/password/change/done/', 'authentic2.views.password_change_done'),
|
||||
url(r'^accounts/register/complete/', 'authentic2.views.registration_success', name='registration_complete'),
|
||||
url(r'^accounts/register/',
|
||||
|
@ -28,18 +29,16 @@ not_homepage_patterns = patterns('',
|
|||
'form_class': AuthenticRegistrationForm },
|
||||
name='registration_register',
|
||||
),
|
||||
(r'^accounts/', include('registration.backends.simple.urls')),
|
||||
url(r'^logout$', 'authentic2.idp.views.logout', name='auth_logout'),
|
||||
(r'^admin/admin_log_view/log/', 'authentic2.admin_log_view.views.admin_view'),
|
||||
(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^accounts/', include('registration.backends.simple.urls')),
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^admin_tools/', include('admin_tools.urls')),
|
||||
(r'^idp/', include('authentic2.idp.urls')),
|
||||
(r'^logout$', 'authentic2.idp.views.logout'),
|
||||
(r'^profile/$',
|
||||
prevent_access_to_transient_users(authentic2.idp.views.profile), {},
|
||||
'account_management'),
|
||||
url(r'^idp/', include('authentic2.idp.urls')),
|
||||
url(r'^logout/$', 'authentic2.idp.views.logout', name='auth_logout'),
|
||||
url(r'^profile/edit/$', 'authentic2.views.edit_profile',
|
||||
name='profile_edit'),
|
||||
url(r'^profile/$',
|
||||
prevent_access_to_transient_users(authentic2.idp.views.profile), {},
|
||||
'account_management'),
|
||||
)
|
||||
|
||||
urlpatterns += not_homepage_patterns
|
||||
|
|
|
@ -2,11 +2,13 @@ import logging
|
|||
import lasso
|
||||
import thread
|
||||
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.shortcuts import render_to_response, redirect as shortcuts_redirect
|
||||
from django.shortcuts import render_to_response, redirect as shortcuts_redirect, render
|
||||
from django.template import RequestContext
|
||||
from django.views.generic.edit import UpdateView
|
||||
from django.contrib import messages
|
||||
|
@ -14,15 +16,21 @@ from django.contrib.auth import get_user_model
|
|||
from django.shortcuts import get_object_or_404
|
||||
from django.contrib.auth import SESSION_KEY
|
||||
from django import http
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
|
||||
from authentic2.idp.decorators import prevent_access_to_transient_users
|
||||
from authentic2.idp.saml import saml2_endpoints
|
||||
from authentic2.saml import models
|
||||
from authentic2.saml import models as saml_models
|
||||
|
||||
|
||||
import forms
|
||||
import models
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def redirect(request, next, template_name='redirect.html'):
|
||||
'''Show a simple page which does a javascript redirect, closing any popup
|
||||
enclosing us'''
|
||||
|
@ -31,6 +39,7 @@ def redirect(request, next, template_name='redirect.html'):
|
|||
logging.info('Redirect to %r' % next)
|
||||
return render_to_response(template_name, { 'next': next })
|
||||
|
||||
|
||||
def server_error(request, template_name='500.html'):
|
||||
"""
|
||||
500 error handler.
|
||||
|
@ -42,6 +51,7 @@ def server_error(request, template_name='500.html'):
|
|||
context_instance = RequestContext(request)
|
||||
)
|
||||
|
||||
|
||||
def registration_success(request, template_name='registration/registration_complete.html'):
|
||||
"""
|
||||
Return page after a successful registration.
|
||||
|
@ -50,6 +60,7 @@ def registration_success(request, template_name='registration/registration_compl
|
|||
context_instance = RequestContext(request)
|
||||
)
|
||||
|
||||
|
||||
class EditProfile(UpdateView):
|
||||
model = get_user_model()
|
||||
form_class = forms.UserProfileForm
|
||||
|
@ -63,7 +74,7 @@ class EditProfile(UpdateView):
|
|||
# Push attributes to SP
|
||||
# Policy must not require user consent
|
||||
federations = \
|
||||
models.LibertyFederation.objects.filter(user=self.request.user)
|
||||
saml_models.LibertyFederation.objects.filter(user=self.request.user)
|
||||
for federation in federations:
|
||||
sp_id = federation.sp_id
|
||||
login = saml2_endpoints.idp_sso(self.request,
|
||||
|
@ -88,16 +99,19 @@ class EditProfile(UpdateView):
|
|||
thread.start_new_thread(self.push_attributes, ())
|
||||
return super(EditProfile, self).form_valid(form)
|
||||
|
||||
|
||||
edit_profile = prevent_access_to_transient_users(EditProfile.as_view())
|
||||
|
||||
|
||||
def password_change_done(request):
|
||||
'''Redirect user to homepage and display a success message'''
|
||||
messages.info(request, _('Your password has been changed'))
|
||||
return shortcuts_redirect('account_management')
|
||||
|
||||
|
||||
def su(request, username, redirect_url='/'):
|
||||
'''To use this view add:
|
||||
|
||||
|
||||
url(r'^su/(?P<username>.*)/$', 'authentic2.views.su', {'redirect_url': '/'}),
|
||||
'''
|
||||
if request.user.is_superuser or request.session.get('has_superuser_power'):
|
||||
|
@ -108,3 +122,18 @@ def su(request, username, redirect_url='/'):
|
|||
return http.HttpResponseRedirect(redirect_url)
|
||||
else:
|
||||
return http.HttpResponseRedirect('/')
|
||||
|
||||
|
||||
@login_required
|
||||
def delete_account(request, next_url='/'):
|
||||
next_url = request.build_absolute_uri(request.META.get('HTTP_REFERER') or next_url)
|
||||
if not settings.AUTHENTIC2_ALLOW_ACCOUNT_DELETION:
|
||||
return shortcuts_redirect(next_url)
|
||||
if request.method == 'POST':
|
||||
if 'submit' in request.POST:
|
||||
models.DeletedUser.objects.delete_user(request.user)
|
||||
logger.info(u'deletion of account %s requested' % request.user)
|
||||
return shortcuts_redirect('auth_logout')
|
||||
else:
|
||||
return shortcuts_redirect(next_url)
|
||||
return render(request, 'registration/delete_account.html')
|
||||
|
|
Loading…
Reference in New Issue