зеркало из https://github.com/mozilla/kitsune.git
[bug 783707] Allow disabling of users
This commit is contained in:
Родитель
238ec06c87
Коммит
a2a85134db
|
@ -70,7 +70,8 @@ class Profile(ModelBase):
|
||||||
verbose_name=_lazy(u'Preferred language for email'))
|
verbose_name=_lazy(u'Preferred language for email'))
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
permissions = (('view_karma_points', 'Can view karma points'),)
|
permissions = (('view_karma_points', 'Can view karma points'),
|
||||||
|
('deactivate_users', 'Can deactivate users'),)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return unicode(self.user)
|
return unicode(self.user)
|
||||||
|
|
|
@ -44,6 +44,17 @@
|
||||||
{{ private_message(profile.user) }}
|
{{ private_message(profile.user) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% if user.id != profile.user.id and user.has_perm('users.deactivate_users') %}
|
||||||
|
{% if profile.user.is_active %}
|
||||||
|
<form id="deactivate-form" method="post" action="{{ url('users.deactivate') }}">
|
||||||
|
{{ csrf() }}
|
||||||
|
<input type="hidden" name="user_id" value="{{ profile.user.id }}">
|
||||||
|
<input type="submit" value="{{ _('Deactivate this user') }}">
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<div id="deactivated-msg">{{ _('This user has been deactivated.') }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
{% if num_answers or num_questions or num_solutions or num_documents %}
|
{% if num_answers or num_questions or num_solutions or num_documents %}
|
||||||
<section class="contributions">
|
<section class="contributions">
|
||||||
<h2>Contributions</h2>
|
<h2>Contributions</h2>
|
||||||
|
|
|
@ -382,6 +382,24 @@ class ViewProfileTests(TestCaseBase):
|
||||||
eq_(200, r.status_code)
|
eq_(200, r.status_code)
|
||||||
assert '2 documents' in r.content
|
assert '2 documents' in r.content
|
||||||
|
|
||||||
|
def test_deactivate_button(self):
|
||||||
|
"""Check that the deactivate button is shown appropriately"""
|
||||||
|
p = profile()
|
||||||
|
r = self.client.get(reverse('users.profile', args=[p.user.id]))
|
||||||
|
assert 'Deactivate this user' not in r.content
|
||||||
|
|
||||||
|
add_permission(self.u, Profile, 'deactivate_users')
|
||||||
|
self.client.login(username=self.u.username, password='testpass')
|
||||||
|
r = self.client.get(reverse('users.profile', args=[p.user.id]))
|
||||||
|
assert 'Deactivate this user' in r.content
|
||||||
|
|
||||||
|
p.user.is_active = False
|
||||||
|
p.user.save()
|
||||||
|
r = self.client.get(reverse('users.profile', args=[p.user.id]))
|
||||||
|
assert 'This user has been deactivated.' in r.content
|
||||||
|
|
||||||
|
r = self.client.get(reverse('users.profile', args=[self.u.id]))
|
||||||
|
assert 'Deactivate this user' not in r.content
|
||||||
|
|
||||||
class PasswordChangeTests(TestCaseBase):
|
class PasswordChangeTests(TestCaseBase):
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ from sumo.tests import TestCase, LocalizingClient, send_mail_raise_smtp
|
||||||
from sumo.urlresolvers import reverse
|
from sumo.urlresolvers import reverse
|
||||||
from users import ERROR_SEND_EMAIL
|
from users import ERROR_SEND_EMAIL
|
||||||
from users.models import Profile, RegistrationProfile, EmailChange, Setting
|
from users.models import Profile, RegistrationProfile, EmailChange, Setting
|
||||||
from users.tests import profile, user, group
|
from users.tests import profile, user, group, add_permission
|
||||||
|
|
||||||
|
|
||||||
class RegisterTests(TestCase):
|
class RegisterTests(TestCase):
|
||||||
|
@ -453,3 +453,22 @@ class UserProfileTests(TestCase):
|
||||||
def test_profile_post(self):
|
def test_profile_post(self):
|
||||||
res = self.client.post(self.url)
|
res = self.client.post(self.url)
|
||||||
eq_(405, res.status_code)
|
eq_(405, res.status_code)
|
||||||
|
|
||||||
|
def test_profile_deactivate(self):
|
||||||
|
"""Test user deactivation"""
|
||||||
|
p = profile()
|
||||||
|
|
||||||
|
self.client.login(username=self.u.username, password='testpass')
|
||||||
|
res = self.client.post(reverse('users.deactivate', locale='en-US'),
|
||||||
|
{'user_id': p.user.id})
|
||||||
|
|
||||||
|
eq_(403, res.status_code)
|
||||||
|
|
||||||
|
add_permission(self.u, Profile, 'deactivate_users')
|
||||||
|
res = self.client.post(reverse('users.deactivate', locale='en-US'),
|
||||||
|
{'user_id': p.user.id})
|
||||||
|
|
||||||
|
eq_(302, res.status_code)
|
||||||
|
|
||||||
|
p = Profile.objects.get(user_id=p.user_id)
|
||||||
|
assert not p.user.is_active
|
||||||
|
|
|
@ -40,6 +40,7 @@ users_patterns = patterns('',
|
||||||
url(r'^/settings$', views.edit_settings, name='users.edit_settings'),
|
url(r'^/settings$', views.edit_settings, name='users.edit_settings'),
|
||||||
url(r'^/avatar$', views.edit_avatar, name='users.edit_avatar'),
|
url(r'^/avatar$', views.edit_avatar, name='users.edit_avatar'),
|
||||||
url(r'^/avatar/delete$', views.delete_avatar, name='users.delete_avatar'),
|
url(r'^/avatar/delete$', views.delete_avatar, name='users.delete_avatar'),
|
||||||
|
url(r'^/deactivate$', views.deactivate, name='users.deactivate'),
|
||||||
|
|
||||||
# Password reset
|
# Password reset
|
||||||
url(r'^/pwreset$', views.password_reset, name='users.pw_reset'),
|
url(r'^/pwreset$', views.password_reset, name='users.pw_reset'),
|
||||||
|
|
|
@ -10,7 +10,8 @@ from django.contrib.sites.models import Site
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
from django.http import (HttpResponsePermanentRedirect, HttpResponseRedirect,
|
from django.http import (HttpResponsePermanentRedirect, HttpResponseRedirect,
|
||||||
Http404)
|
Http404)
|
||||||
from django.views.decorators.http import require_http_methods, require_GET
|
from django.views.decorators.http import (require_http_methods, require_GET,
|
||||||
|
require_POST)
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils.http import base36_to_int
|
from django.utils.http import base36_to_int
|
||||||
|
@ -22,7 +23,8 @@ from statsd import statsd
|
||||||
from tidings.tasks import claim_watches
|
from tidings.tasks import claim_watches
|
||||||
from tower import ugettext as _
|
from tower import ugettext as _
|
||||||
|
|
||||||
from access.decorators import logout_required, login_required
|
from access.decorators import (logout_required, login_required,
|
||||||
|
permission_required)
|
||||||
from questions.models import (Question, user_num_answers, user_num_questions,
|
from questions.models import (Question, user_num_answers, user_num_questions,
|
||||||
user_num_solutions)
|
user_num_solutions)
|
||||||
from sumo import email_utils
|
from sumo import email_utils
|
||||||
|
@ -35,6 +37,7 @@ from users.forms import (ProfileForm, AvatarForm, EmailConfirmationForm,
|
||||||
AuthenticationForm, EmailChangeForm, SetPasswordForm,
|
AuthenticationForm, EmailChangeForm, SetPasswordForm,
|
||||||
PasswordChangeForm, SettingsForm, ForgotUsernameForm,
|
PasswordChangeForm, SettingsForm, ForgotUsernameForm,
|
||||||
RegisterForm)
|
RegisterForm)
|
||||||
|
from users.helpers import profile_url
|
||||||
from users.models import (Profile, RegistrationProfile,
|
from users.models import (Profile, RegistrationProfile,
|
||||||
EmailChange)
|
EmailChange)
|
||||||
from users.utils import (handle_login, handle_register,
|
from users.utils import (handle_login, handle_register,
|
||||||
|
@ -287,7 +290,11 @@ def confirm_change_email(request, activation_key):
|
||||||
@mobile_template('users/{mobile/}profile.html')
|
@mobile_template('users/{mobile/}profile.html')
|
||||||
def profile(request, template, user_id):
|
def profile(request, template, user_id):
|
||||||
user_profile = get_object_or_404(
|
user_profile = get_object_or_404(
|
||||||
Profile, user__id=user_id, user__is_active=True)
|
Profile, user__id=user_id)
|
||||||
|
|
||||||
|
if not (request.user.has_perm('users.deactivate_users')
|
||||||
|
or user_profile.user.is_active):
|
||||||
|
raise Http404('No Profile matches the given query.')
|
||||||
|
|
||||||
groups = user_profile.user.groups.all()
|
groups = user_profile.user.groups.all()
|
||||||
return jingo.render(request, template, {
|
return jingo.render(request, template, {
|
||||||
|
@ -299,6 +306,15 @@ def profile(request, template, user_id):
|
||||||
'num_documents': user_num_documents(user_profile.user),})
|
'num_documents': user_num_documents(user_profile.user),})
|
||||||
|
|
||||||
|
|
||||||
|
@require_POST
|
||||||
|
@permission_required('users.deactivate_users')
|
||||||
|
def deactivate(request):
|
||||||
|
user = get_object_or_404(User, id=request.POST['user_id'], is_active=True)
|
||||||
|
user.is_active = False
|
||||||
|
user.save()
|
||||||
|
return HttpResponseRedirect(profile_url(user))
|
||||||
|
|
||||||
|
|
||||||
@require_GET
|
@require_GET
|
||||||
def documents_contributed(request, user_id):
|
def documents_contributed(request, user_id):
|
||||||
user_profile = get_object_or_404(
|
user_profile = get_object_or_404(
|
||||||
|
|
|
@ -11,6 +11,11 @@ article {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#deactivated-msg {
|
||||||
|
color: #cc0000;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
#user-nav {
|
#user-nav {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
SET @ct = (SELECT id from django_content_type WHERE name='profile' AND app_label='users');
|
||||||
|
|
||||||
|
INSERT INTO auth_permission (`name`, `content_type_id`, `codename`) VALUES
|
||||||
|
('Can deactivate users', @ct, 'deactivate_users');
|
Загрузка…
Ссылка в новой задаче