[IMP] auth_signup: extend the login form to allow signups
bzr revid: rco@openerp.com-20120925104013-f2vfqcjknx7zyo26
This commit is contained in:
parent
d19ea766fa
commit
aceae3501e
|
@ -1,25 +1,58 @@
|
|||
import logging
|
||||
|
||||
import werkzeug.urls
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2012-today OpenERP SA (<http://www.openerp.com>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.modules.registry import RegistryManager
|
||||
from openerp.addons.web.controllers.main import login_and_redirect
|
||||
import openerp.addons.web.common.http as openerpweb
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
import werkzeug
|
||||
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class OpenIDController(openerpweb.Controller):
|
||||
class Controller(openerpweb.Controller):
|
||||
_cp_path = '/auth_signup'
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def retrieve(self, req, dbname, token):
|
||||
""" retrieve the user info (name, login or email) corresponding to a signup token """
|
||||
registry = RegistryManager.get(dbname)
|
||||
user_info = None
|
||||
with registry.cursor() as cr:
|
||||
res_partner = registry.get('res.partner')
|
||||
user_info = res_partner.signup_retrieve_info(cr, SUPERUSER_ID, token)
|
||||
user_info.update(db=dbname, token=token)
|
||||
return user_info
|
||||
|
||||
@openerpweb.httprequest
|
||||
def signup(self, req, dbname, name, login, password):
|
||||
def signup(self, req, dbname, token, name, login, password):
|
||||
""" sign up a user (new or existing), and log it in """
|
||||
url = '/'
|
||||
registry = RegistryManager.get(dbname)
|
||||
with registry.cursor() as cr:
|
||||
try:
|
||||
Users = registry.get('res.users')
|
||||
credentials = Users.auth_signup(cr, SUPERUSER_ID, name, login, password)
|
||||
res_users = registry.get('res.users')
|
||||
values = {'name': name, 'login': login, 'password': password}
|
||||
credentials = res_users.signup(cr, SUPERUSER_ID, values, token)
|
||||
cr.commit()
|
||||
return login_and_redirect(req, *credentials)
|
||||
except AttributeError:
|
||||
|
|
|
@ -29,8 +29,8 @@ import random
|
|||
import urlparse
|
||||
|
||||
def random_token():
|
||||
# the token has an entropy of 120 bits (6 bits/char * 20 chars)
|
||||
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
# the token has an entropy of about 120 bits (6 bits/char * 20 chars)
|
||||
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||||
return ''.join(random.choice(chars) for i in xrange(20))
|
||||
|
||||
def now():
|
||||
|
@ -39,12 +39,25 @@ def now():
|
|||
|
||||
class res_partner(osv.Model):
|
||||
_inherit = 'res.partner'
|
||||
|
||||
def signup_get_url(self, cr, uid, partner_ids, name, arg, context=None):
|
||||
""" determine a url for the partner_id to sign up """
|
||||
base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
|
||||
res = {}
|
||||
for partner in self.browse(cr, uid, partner_ids, context):
|
||||
token = partner.signup_token
|
||||
if not token:
|
||||
token = self._signup_generate_token(cr, uid, partner.id, context=context)
|
||||
res[partner.id] = urlparse.urljoin(base_url, '#action=login&db=%s&token=%s' % (cr.dbname, token))
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'signup_token': fields.char(size=24, string='Signup Ticket'),
|
||||
'signup_expiration': fields.datetime(string='Signup Expiration'),
|
||||
'signup_url': fields.function(signup_get_url, type='char', string='Signup URL'),
|
||||
}
|
||||
|
||||
def signup_generate_token(self, cr, uid, partner_id, context=None):
|
||||
def _signup_generate_token(self, cr, uid, partner_id, expiration=False, context=None):
|
||||
""" generate a new token for a partner, and return it
|
||||
:param partner_id: the partner id
|
||||
:param expiration: the expiration datetime of the token (string, optional)
|
||||
|
@ -52,25 +65,45 @@ class res_partner(osv.Model):
|
|||
"""
|
||||
# generate a unique token
|
||||
token = random_token()
|
||||
while self.signup_retrieve_partner(cr, uid, token, context):
|
||||
while self._signup_retrieve_partner(cr, uid, token, context=context):
|
||||
token = random_token()
|
||||
self.write(cr, uid, [partner_id], {'signup_token': token, 'signup_expiration': expiration}, context=context)
|
||||
return token
|
||||
|
||||
def signup_retrieve_partner(self, cr, uid, token, raise_exception=False, context=None):
|
||||
""" find the partner corresponding to a token, and return its partner id or False """
|
||||
def _signup_retrieve_partner(self, cr, uid, token, raise_exception=False, context=None):
|
||||
""" find the partner corresponding to a token, and check its validity
|
||||
:return: partner (browse record) or False (if raise_exception is False)
|
||||
:raise: when token not valid (if raise_exception is True)
|
||||
"""
|
||||
partner_ids = self.search(cr, uid, [('signup_token', '=', token)], context=context)
|
||||
return partner_ids and partner_ids[0] or False
|
||||
if not partner_ids:
|
||||
if raise_exception:
|
||||
raise Exception("Signup token '%s' is not valid" % token)
|
||||
return False
|
||||
partner = self.browse(cr, uid, partner_ids[0], context)
|
||||
if partner.signup_expiration and partner.signup_expiration < now():
|
||||
if raise_exception:
|
||||
raise Exception("Signup token '%s' is no longer valid" % token)
|
||||
return False
|
||||
return partner
|
||||
|
||||
def signup_get_url(self, cr, uid, partner_id, context):
|
||||
""" determine a url for the partner_id to sign up """
|
||||
base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
|
||||
token = self.browse(cr, uid, partner_id, context).signup_token
|
||||
if not token:
|
||||
token = self.signup_generate_token(cr, uid, partner_id, context=context)
|
||||
return urlparse.urljoin(base_url, '/login?db=%s#action=signup&token=%s' % (cr.dbname, token))
|
||||
def signup_retrieve_info(self, cr, uid, token, context=None):
|
||||
""" retrieve the user info about the token
|
||||
:return: either {'name': ..., 'login': ...} if a user exists for that token,
|
||||
or {'name': ..., 'email': ...} otherwise
|
||||
"""
|
||||
partner = self._signup_retrieve_partner(cr, uid, token, raise_exception=True, context=None)
|
||||
if partner.user_ids:
|
||||
return {'name': partner.name, 'login': partner.user_ids[0].login}
|
||||
else:
|
||||
return {'name': partner.name, 'email': partner.email}
|
||||
|
||||
def signup(self, cr, values, token=None, context=None):
|
||||
|
||||
|
||||
class res_users(osv.Model):
|
||||
_inherit = 'res.users'
|
||||
|
||||
def signup(self, cr, uid, values, token=None, context=None):
|
||||
""" signup a user, to either:
|
||||
- create a new user (no token), or
|
||||
- create a user for a partner (with token, but no user for partner), or
|
||||
|
@ -84,13 +117,8 @@ class res_partner(osv.Model):
|
|||
|
||||
if token:
|
||||
# signup with a token: find the corresponding partner id
|
||||
partner_id = self.signup_retrieve_partner(cr, uid, token, context=None)
|
||||
if not partner_id:
|
||||
raise Exception('Signup token is not valid')
|
||||
partner = self.browse(cr, uid, partner_id, context)
|
||||
if partner.signup_expiration and partner.signup_expiration < now():
|
||||
raise Exception('Signup token is no longer valid')
|
||||
|
||||
res_partner = self.pool.get('res.partner')
|
||||
partner = res_partner._signup_retrieve_partner(cr, uid, token, raise_exception=True, context=None)
|
||||
if partner.user_ids:
|
||||
# user exists, modify its password and clear token
|
||||
partner.user_ids[0].write({
|
||||
|
@ -129,51 +157,6 @@ class res_partner(osv.Model):
|
|||
|
||||
template_user_id = ir_config_parameter.get_param(cr, uid, 'auth_signup.template_user_id')
|
||||
assert template_user_id, 'Signup: missing template user'
|
||||
values['active'] = True
|
||||
return self.pool.get('res.users').copy(cr, uid, template_user_id, values, context=context)
|
||||
values.update({'active': True, 'signup_token': False, 'signup_expiration': False})
|
||||
return self.copy(cr, uid, template_user_id, values, context=context)
|
||||
|
||||
|
||||
|
||||
class res_users(osv.Model):
|
||||
_inherit = 'res.users'
|
||||
|
||||
def auth_signup_create(self, cr, uid, new_user, context=None):
|
||||
# new_user:
|
||||
# login
|
||||
# email
|
||||
# name (optional)
|
||||
# partner_id (optional)
|
||||
# groups (optional)
|
||||
# sign (for partner_id and groups)
|
||||
#
|
||||
user_template_id = self.pool.get('ir.config_parameter').get_param(cr, uid, 'auth_signup.template_user_id', 0)
|
||||
if user_template_id:
|
||||
self.pool.get('res.users').copy(cr, SUPERUSER_ID, user_template_id, new_user, context=context)
|
||||
else:
|
||||
self.pool.get('res.users').create(cr, SUPERUSER_ID, new_user, context=context)
|
||||
|
||||
def auth_signup(self, cr, uid, name, login, password, context=None):
|
||||
r = (cr.dbname, login, password)
|
||||
res = self.search(cr, uid, [("login", "=", login)])
|
||||
if res:
|
||||
# Existing user
|
||||
user_id = res[0]
|
||||
try:
|
||||
self.check(cr.dbname, user_id, password)
|
||||
# Same password
|
||||
except openerp.exceptions.AccessDenied:
|
||||
# Different password
|
||||
raise
|
||||
else:
|
||||
# New user
|
||||
new_user = {
|
||||
'name': name,
|
||||
'login': login,
|
||||
'user_email': login,
|
||||
'password': password,
|
||||
'active': True,
|
||||
}
|
||||
self.auth_signup_create(cr, uid, new_user)
|
||||
return r
|
||||
|
||||
#
|
||||
|
|
|
@ -5,56 +5,68 @@ openerp.auth_signup = function(instance) {
|
|||
instance.web.Login.include({
|
||||
start: function() {
|
||||
var self = this;
|
||||
this.$('a.oe_signup').click(function() {
|
||||
var dbname = self.$("form [name=db]").val();
|
||||
self.do_action({
|
||||
type: 'ir.actions.client',
|
||||
tag: 'auth_signup.signup',
|
||||
params: {'dbname': dbname},
|
||||
target: 'new',
|
||||
name: 'Sign up'
|
||||
});
|
||||
return true;
|
||||
});
|
||||
return this._super();
|
||||
var d = this._super();
|
||||
// hide the signup fields in the case of a regular login
|
||||
self.on_change_mode()
|
||||
self.$("form input[name=signup]").click(self.on_change_mode);
|
||||
// in case of a signup, retrieve the user information from the token
|
||||
if (self.params.db && self.params.token) {
|
||||
d = self.rpc("/auth_signup/retrieve", {dbname: self.params.db, token: self.params.token})
|
||||
.done(self.on_token_loaded)
|
||||
.fail(self.on_token_failed);
|
||||
}
|
||||
return d;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
instance.auth_signup.Signup = instance.web.Widget.extend({
|
||||
template: 'auth_signup.signup',
|
||||
init: function(parent, params) {
|
||||
this.params = params;
|
||||
return this._super();
|
||||
on_token_loaded: function(result) {
|
||||
// set the name and login of user
|
||||
this.selected_db = result.db;
|
||||
this.on_db_loaded({db_list: [result.db]});
|
||||
this.$("form input[name=signup]").val(result.login ? [] : ["check_signup"]);
|
||||
this.$("form input[name=name]").val(result.name);
|
||||
this.$("form input[name=login]").val(result.login || result.email);
|
||||
this.$("form input[name=password]").val("");
|
||||
this.$("form input[name=confirm_password]").val("");
|
||||
this.on_change_mode();
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
this.$('input[name=password_confirmation]').keyup(function() {
|
||||
var v = $(this).val();
|
||||
var $b = self.$('button');
|
||||
if (_.isEmpty(v) || self.$('input[name=password]').val() === v) {
|
||||
$b.removeAttr('disabled');
|
||||
on_token_failed: function(result) {
|
||||
// currently does nothing
|
||||
},
|
||||
on_change_mode: function() {
|
||||
// 'mode' has changed: regular login, sign up, reset password
|
||||
var is_signup = this.$("input[name=signup]:checked").val();
|
||||
this.$(".oe_signup").toggleClass('oe_form_invisible', false && !is_signup);
|
||||
return true;
|
||||
},
|
||||
on_submit: function(ev) {
|
||||
if (ev) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
if (this.params.token || this.$("input[name=signup]:checked").val()) {
|
||||
// signup user (or reset password)
|
||||
var db = this.params.db;
|
||||
var name = this.$("form input[name=name]").val();
|
||||
var login = this.$("form input[name=login]").val();
|
||||
var password = this.$("form input[name=password]").val();
|
||||
var confirm_password = this.$("form input[name=confirm_password]").val();
|
||||
|
||||
if (password && password === confirm_password) {
|
||||
var params = {
|
||||
dbname : db,
|
||||
token: this.params.token,
|
||||
name: name,
|
||||
login: login,
|
||||
password: password,
|
||||
};
|
||||
var url = "/auth_signup/signup?" + $.param(params);
|
||||
window.location = url;
|
||||
} else {
|
||||
$b.attr('disabled', 'disabled');
|
||||
alert('Incorrect password; please retype your password.');
|
||||
}
|
||||
});
|
||||
|
||||
this.$('form').submit(function(ev) {
|
||||
if(ev) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
var params = {
|
||||
dbname : self.params.dbname,
|
||||
name: self.$('input[name=name]').val(),
|
||||
login: self.$('input[name=email]').val(),
|
||||
password: self.$('input[name=password]').val(),
|
||||
};
|
||||
var url = "/auth_signup/signup?" + $.param(params);
|
||||
window.location = url;
|
||||
});
|
||||
return this._super();
|
||||
}
|
||||
} else {
|
||||
// regular login
|
||||
this._super(ev);
|
||||
}
|
||||
},
|
||||
});
|
||||
instance.web.client_actions.add("auth_signup.signup", "instance.auth_signup.Signup");
|
||||
|
||||
};
|
||||
|
|
|
@ -1,28 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- vim:fdl=1:
|
||||
-->
|
||||
<!-- vim:fdl=1: -->
|
||||
<templates id="template" xml:space="preserve">
|
||||
|
||||
<t t-extend="Login">
|
||||
<t t-jquery="form ul:first li:last" t-operation="after">
|
||||
<li>
|
||||
<a class="oe_signup" href="#">Sign Up</a>
|
||||
</li>
|
||||
<t t-extend="Login">
|
||||
<t t-jquery="form ul:first li:first" t-operation="before">
|
||||
<li class="oe_signup">
|
||||
<input name="signup" type="checkbox" value="check_signup"/>
|
||||
Create a new account
|
||||
</li>
|
||||
<li class="oe_signup">Name</li>
|
||||
<li class="oe_signup">
|
||||
<input name="name" type="text"/>
|
||||
</li>
|
||||
</t>
|
||||
<t t-jquery="form ul:first li:contains('Username')" t-operation="replace">
|
||||
<li>Username <span class="oe_signup">(Email)</span></li>
|
||||
</t>
|
||||
<t t-jquery="form ul:first li:last" t-operation="before">
|
||||
<li class="oe_signup">Confirm Password</li>
|
||||
<li class="oe_signup">
|
||||
<input name="confirm_password" type="password"/>
|
||||
</li>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="auth_signup.signup">
|
||||
<div>
|
||||
<form>
|
||||
Name = <input type="text" name="name"/><br/>
|
||||
Email = <input type="email" name="email"/><br/>
|
||||
Password = <input type="password" name="password"/><br/>
|
||||
Confirmation = <input type="password" name="password_confirmation"/><br/>
|
||||
<button type="submit" disabled="disabled">Signup</button>
|
||||
</form>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
|
||||
|
||||
</templates>
|
||||
|
|
Loading…
Reference in New Issue