mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-02 23:48:47 +00:00
Impove registration process and add user admin page
This commit is contained in:
81
HACKING
Normal file
81
HACKING
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
|
||||||
|
About Registration
|
||||||
|
==================
|
||||||
|
|
||||||
|
We use a customized registration process based on thirdpart/registration.
|
||||||
|
The customization begins with:
|
||||||
|
|
||||||
|
(r'^accounts/', include('base.registration_urls'))
|
||||||
|
|
||||||
|
See base.registration_urls to follow the code.
|
||||||
|
|
||||||
|
Registration is seperated into two phase: registration and activation.
|
||||||
|
|
||||||
|
Registration Page with Form -----> Registration Complete Page
|
||||||
|
(Notify User to check mail)
|
||||||
|
|
|
||||||
|
|
|
||||||
|
V
|
||||||
|
User check email and click activate link
|
||||||
|
|
|
||||||
|
|
|
||||||
|
V
|
||||||
|
User Home Page <----- Activate and login User.
|
||||||
|
|
||||||
|
|
||||||
|
The registration app provide two view functions, i.e., `register` and `activate`.
|
||||||
|
|
||||||
|
### Register
|
||||||
|
|
||||||
|
The actual registration of the account will be delegated to the
|
||||||
|
backend; it will be used as follows:
|
||||||
|
|
||||||
|
1. The backend's ``registration_allowed()`` method will be called,
|
||||||
|
passing the ``HttpRequest``, to determine whether registration of
|
||||||
|
an account is to be allowed; if not, a redirect is issued to the
|
||||||
|
view corresponding to the named URL pattern
|
||||||
|
``registration_disallowed``.
|
||||||
|
|
||||||
|
2. The form to use for account registration will be obtained by
|
||||||
|
calling the backend's ``get_form_class()`` method, passing the
|
||||||
|
``HttpRequest``.
|
||||||
|
|
||||||
|
3. If valid, the form's ``cleaned_data`` will be passed (as keyword
|
||||||
|
arguments, and along with the ``HttpRequest``) to the backend's
|
||||||
|
``register()`` method, which should return the new ``User`` object.
|
||||||
|
|
||||||
|
4. Upon successful registration, the backend's
|
||||||
|
``post_registration_redirect()`` method will be called, passing the
|
||||||
|
``HttpRequest`` and the new ``User``, to determine the URL to
|
||||||
|
redirect the user to.
|
||||||
|
|
||||||
|
|
||||||
|
We use a customized backend: seahub.base.accounts.RegistrationBackend
|
||||||
|
|
||||||
|
### Registration Process
|
||||||
|
|
||||||
|
Process 1:
|
||||||
|
1. User register
|
||||||
|
2. Admin activate
|
||||||
|
3. User login and bind ccnet ID
|
||||||
|
|
||||||
|
To Enable this process, just set
|
||||||
|
|
||||||
|
EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
|
||||||
|
EMAIL_FILE_PATH = '/tmp/app-messages'
|
||||||
|
|
||||||
|
|
||||||
|
Process 2:
|
||||||
|
1. User register and active account and bind ccnet ID
|
||||||
|
|
||||||
|
|
||||||
|
About Authentication
|
||||||
|
====================
|
||||||
|
|
||||||
|
We use a custimized authentication method. See
|
||||||
|
seahub.base.accounts.EmailOrUsernameModelBackend
|
||||||
|
|
||||||
|
AUTHENTICATION_BACKENDS = (
|
||||||
|
'seahub.base.accounts.EmailOrUsernameModelBackend',
|
||||||
|
'django.contrib.auth.backends.ModelBackend'
|
||||||
|
)
|
@@ -14,7 +14,7 @@ from django import forms
|
|||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from seahub.profile.models import UserProfile
|
from seahub.profile.models import UserProfile
|
||||||
|
from seaserv import ccnet_rpc
|
||||||
|
|
||||||
class EmailOrUsernameModelBackend(object):
|
class EmailOrUsernameModelBackend(object):
|
||||||
def authenticate(self, username=None, password=None):
|
def authenticate(self, username=None, password=None):
|
||||||
@@ -109,8 +109,9 @@ class RegistrationBackend(object):
|
|||||||
password, site)
|
password, site)
|
||||||
|
|
||||||
userid = kwargs['userid']
|
userid = kwargs['userid']
|
||||||
profile = UserProfile(user=new_user, ccnet_user_id=userid)
|
if userid:
|
||||||
profile.save()
|
profile = UserProfile(user=new_user, ccnet_user_id=userid)
|
||||||
|
profile.save()
|
||||||
|
|
||||||
signals.user_registered.send(sender=self.__class__,
|
signals.user_registered.send(sender=self.__class__,
|
||||||
user=new_user,
|
user=new_user,
|
||||||
@@ -136,6 +137,12 @@ class RegistrationBackend(object):
|
|||||||
# login the user
|
# login the user
|
||||||
activated.backend='django.contrib.auth.backends.ModelBackend'
|
activated.backend='django.contrib.auth.backends.ModelBackend'
|
||||||
login(request, activated)
|
login(request, activated)
|
||||||
|
try:
|
||||||
|
profile = request.user.get_profile()
|
||||||
|
if profile.ccnet_user_id:
|
||||||
|
ccnet_rpc.add_client(ccnet_user_id)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
return activated
|
return activated
|
||||||
|
|
||||||
@@ -192,7 +199,8 @@ class RegistrationForm(forms.Form):
|
|||||||
label=_("Email address"))
|
label=_("Email address"))
|
||||||
userid = forms.RegexField(regex=r'^\w+$',
|
userid = forms.RegexField(regex=r'^\w+$',
|
||||||
max_length=40,
|
max_length=40,
|
||||||
widget=forms.TextInput(attrs=attrs_dict),
|
required=False,
|
||||||
|
widget=forms.TextInput(),
|
||||||
label=_("Username"),
|
label=_("Username"),
|
||||||
error_messages={ 'invalid': _("This value must be of length 40") })
|
error_messages={ 'invalid': _("This value must be of length 40") })
|
||||||
|
|
||||||
@@ -209,11 +217,9 @@ class RegistrationForm(forms.Form):
|
|||||||
|
|
||||||
raise forms.ValidationError(_("A user with this email alread"))
|
raise forms.ValidationError(_("A user with this email alread"))
|
||||||
|
|
||||||
|
|
||||||
def clean_userid(self):
|
def clean_userid(self):
|
||||||
if len(self.cleaned_data['userid']) != 40:
|
if self.cleaned_data['userid'] and len(self.cleaned_data['userid']) != 40:
|
||||||
raise forms.ValidationError(_("Invalid user id."))
|
raise forms.ValidationError(_("Invalid user id."))
|
||||||
|
|
||||||
return self.cleaned_data['userid']
|
return self.cleaned_data['userid']
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
@@ -147,3 +147,5 @@ div.home-page h2 { font-style: italic; }
|
|||||||
.help-page img { display: block; margin: 20px auto; }
|
.help-page img { display: block; margin: 20px auto; }
|
||||||
|
|
||||||
#id_repo_id { width:300px; }
|
#id_repo_id { width:300px; }
|
||||||
|
|
||||||
|
span.role-remove-link { font-size: 9px; }
|
@@ -10,7 +10,7 @@
|
|||||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.simplemodal.1.4.1.min.js"></script>
|
<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.simplemodal.1.4.1.min.js"></script>
|
||||||
|
|
||||||
{% block extra_style %}{% endblock %}
|
{% block extra_style %}{% endblock %}
|
||||||
{% block extra_script %}{% endblock %}
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -96,5 +96,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div><!-- wrapper -->
|
</div><!-- wrapper -->
|
||||||
|
|
||||||
|
{% block extra_script %}{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@@ -4,16 +4,13 @@
|
|||||||
<li>
|
<li>
|
||||||
<a href="{{ SITE_ROOT }}home/my/">我的页面</a>
|
<a href="{{ SITE_ROOT }}home/my/">我的页面</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<a href="{{ SITE_ROOT }}share/">共享</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="{{ SITE_ROOT }}contacts/">联系人</a>
|
|
||||||
</li>
|
|
||||||
{% if request.user.is_staff %}
|
{% if request.user.is_staff %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ SITE_ROOT }}seafadmin/">中继管理</a>
|
<a href="{{ SITE_ROOT }}seafadmin/">中继管理</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ SITE_ROOT }}useradmin/">用户管理</a>
|
||||||
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li>
|
<li>
|
||||||
<a href="http://www.gonggeng.org/seasite/help/">使用帮助</a>
|
<a href="http://www.gonggeng.org/seasite/help/">使用帮助</a>
|
||||||
|
@@ -3,8 +3,8 @@
|
|||||||
{% block main_panel %}
|
{% block main_panel %}
|
||||||
<h2>用户注册</h2>
|
<h2>用户注册</h2>
|
||||||
<form action="" method="post" class="reg">
|
<form action="" method="post" class="reg">
|
||||||
<label for="id_username">用户 ID:</label>
|
<label for="id_username">Ccnet 公钥 ID:</label>
|
||||||
{{ form.userid }}
|
{{ form.userid }} (可以以后再绑定)
|
||||||
{% if form.userid.errors %}
|
{% if form.userid.errors %}
|
||||||
{{ form.userid.errors }}
|
{{ form.userid.errors }}
|
||||||
{% endif %}<br />
|
{% endif %}<br />
|
||||||
|
59
templates/useradmin.html
Normal file
59
templates/useradmin.html
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
{% extends "myhome_base.html" %}
|
||||||
|
|
||||||
|
{% block right_panel %}
|
||||||
|
|
||||||
|
<h2>所有用户</h2>
|
||||||
|
<table class="user-list default">
|
||||||
|
<tr>
|
||||||
|
<th>邮件</th>
|
||||||
|
<td>激活</td>
|
||||||
|
<td>Ccnet ID</td>
|
||||||
|
<td>角色</td>
|
||||||
|
<td>操作</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% for user in users %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ user.email }}</td>
|
||||||
|
<td>{{ user.is_active }}</td>
|
||||||
|
{% if user.profile %}
|
||||||
|
<td>{{ user.profile.ccnet_user_id }}</td>
|
||||||
|
<td>
|
||||||
|
{% for role in user.role_list %}
|
||||||
|
{{ role }}<span class="role-remove-link">(<a href="{{ SITE_ROOT }}useradmin/{{ user.profile.ccnet_user_id }}/role/remove/?role={{ role }}">删除</a>)</span>
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
<td><button class="add-role-btn" userid="{{ user.profile.ccnet_user_id }}" email="{{ user.email }}">添加角色</button></td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="hidden">
|
||||||
|
|
||||||
|
<form id="add-role-form" action="" method="post">
|
||||||
|
<p><span id="user_email"></span> 的新角色 (即 MyClient 等):</p>
|
||||||
|
<input id="id_role" type="text" name="role" /><br/>
|
||||||
|
<input id="id_summit" type="submit" value="Submit" />
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_script %}
|
||||||
|
<script>
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
|
||||||
|
$(".add-role-btn").each(function(index, item) {
|
||||||
|
item.onclick = function() {
|
||||||
|
url = "{{ SITE_ROOT }}useradmin/" + $(item).attr("userid") + "/role/add/";
|
||||||
|
$("#add-role-form").attr( { action: url } );
|
||||||
|
$("#add-role-form #user_email").html($(item).attr("email"));
|
||||||
|
$("#add-role-form").modal({appendTo: "#main"});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
6
urls.py
6
urls.py
@@ -3,7 +3,8 @@ from django.conf import settings
|
|||||||
from django.views.generic.simple import direct_to_template
|
from django.views.generic.simple import direct_to_template
|
||||||
|
|
||||||
from seahub.views import root, peers, groups, myhome, \
|
from seahub.views import root, peers, groups, myhome, \
|
||||||
repo, group, modify_token, remove_repo, seafadmin
|
repo, group, modify_token, remove_repo, seafadmin, useradmin, \
|
||||||
|
role_add, role_remove
|
||||||
|
|
||||||
# Uncomment the next two lines to enable the admin:
|
# Uncomment the next two lines to enable the admin:
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
@@ -30,6 +31,9 @@ urlpatterns = patterns('',
|
|||||||
(r'^repo/remove/(?P<repo_id>[^/]+)/$', remove_repo),
|
(r'^repo/remove/(?P<repo_id>[^/]+)/$', remove_repo),
|
||||||
|
|
||||||
(r'^seafadmin/$', seafadmin),
|
(r'^seafadmin/$', seafadmin),
|
||||||
|
(r'^useradmin/$', useradmin),
|
||||||
|
(r'^useradmin/(?P<user_id>[^/]+)/role/add/$', role_add),
|
||||||
|
(r'^useradmin/(?P<user_id>[^/]+)/role/remove/$', role_remove),
|
||||||
(r'^avatar/', include('avatar.urls')),
|
(r'^avatar/', include('avatar.urls')),
|
||||||
(r'^profile/', include('seahub.profile.urls')),
|
(r'^profile/', include('seahub.profile.urls')),
|
||||||
|
|
||||||
|
47
views.py
47
views.py
@@ -4,6 +4,7 @@ from django.core.urlresolvers import reverse
|
|||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
from seaserv import cclient, ccnet_rpc, get_groups, get_users, get_repos, \
|
from seaserv import cclient, ccnet_rpc, get_groups, get_users, get_repos, \
|
||||||
get_repo, get_commits, get_branches, \
|
get_repo, get_commits, get_branches, \
|
||||||
@@ -176,3 +177,49 @@ def seafadmin(request):
|
|||||||
'repos': repos,
|
'repos': repos,
|
||||||
},
|
},
|
||||||
context_instance=RequestContext(request))
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def useradmin(request):
|
||||||
|
if not request.user.is_staff:
|
||||||
|
raise Http404
|
||||||
|
|
||||||
|
users = User.objects.all()
|
||||||
|
for user in users:
|
||||||
|
try:
|
||||||
|
user.profile = user.get_profile()
|
||||||
|
user.ccnet_user = ccnet_rpc.get_user(user.profile.ccnet_user_id)
|
||||||
|
user.role_list = user.ccnet_user.props.role_list.split(',')
|
||||||
|
except UserProfile.DoesNotExist:
|
||||||
|
user.profile = None
|
||||||
|
user.ccnet_user = None
|
||||||
|
|
||||||
|
return render_to_response(
|
||||||
|
'useradmin.html', {
|
||||||
|
'users': users,
|
||||||
|
},
|
||||||
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def role_add(request, user_id):
|
||||||
|
if not request.user.is_staff:
|
||||||
|
raise Http404
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
role = request.POST.get('role', '')
|
||||||
|
if role and len(role) <= 16:
|
||||||
|
ccnet_rpc.add_role(user_id, role)
|
||||||
|
|
||||||
|
return HttpResponseRedirect(request.META['HTTP_REFERER'])
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def role_remove(request, user_id):
|
||||||
|
if not request.user.is_staff:
|
||||||
|
raise Http404
|
||||||
|
|
||||||
|
role = request.REQUEST.get('role', '')
|
||||||
|
if role and len(role) <= 16:
|
||||||
|
ccnet_rpc.remove_role(user_id, role)
|
||||||
|
|
||||||
|
return HttpResponseRedirect(request.META['HTTP_REFERER'])
|
||||||
|
Reference in New Issue
Block a user