[IMP] auth_signup converted to server side module

bzr revid: fme@openerp.com-20140121152027-7wch4r7dt2ew0did
This commit is contained in:
Fabien Meghazi 2014-01-21 16:20:27 +01:00
parent 1e921cd03d
commit fff55213b5
6 changed files with 102 additions and 298 deletions

View File

@ -43,6 +43,5 @@ Allow users to sign up and reset their password
'views/auth_signup_login.xml', 'views/auth_signup_login.xml',
], ],
'js': ['static/src/js/auth_signup.js'], 'js': ['static/src/js/auth_signup.js'],
'qweb': ['static/src/xml/auth_signup.xml'],
'bootstrap': True, 'bootstrap': True,
} }

View File

@ -21,77 +21,71 @@
import logging import logging
import openerp import openerp
import openerp.addons.web.controllers.main as webmain
from openerp import http from openerp import http
from openerp.http import request, LazyResponse from openerp.http import request, LazyResponse
from openerp.modules.registry import RegistryManager from openerp.tools.translate import _
from ..res_users import SignupError
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class Home(openerp.addons.web.controllers.main.Home): class Home(openerp.addons.web.controllers.main.Home):
@http.route('/web/login', type='http', auth="none") @http.route()
def web_login(self, *args, **kw): def web_login(self, *args, **kw):
response = super(Home, self).web_login(*args, **kw) # TODO: ensure_db()
if isinstance(response, LazyResponse): request.disable_db = False
config = self.get_auth_signup_config(request.session.db)
response.params['values'].update(config) mode = request.params.get('mode')
if request.params.get('signup', None) and config['signup']: qcontext = request.params.copy()
response.params['template'] = 'auth_signup.signup' response = webmain.render_bootstrap_template(request.session.db, 'auth_signup.signup', qcontext, lazy=True)
if request.params.get('reset', None) and config['signup']: token = qcontext.get('token', None)
response.params['template'] = 'auth_signup.reset' token_infos = None
if token:
try:
# retrieve the user info (name, login or email) corresponding to a signup token
res_partner = request.registry.get('res.partner')
token_infos = res_partner.signup_retrieve_info(request.cr, openerp.SUPERUSER_ID, token)
for k, v in token_infos.items():
qcontext.setdefault(k, v)
except:
qcontext['error'] = _("Invalid signup token")
response.params['template'] = 'web.login'
return response
# retrieve the module config (which features are enabled) for the login page
icp = request.registry.get('ir.config_parameter')
config = {
'signup': icp.get_param(request.cr, openerp.SUPERUSER_ID, 'auth_signup.allow_uninvited') == 'True',
'reset': icp.get_param(request.cr, openerp.SUPERUSER_ID, 'auth_signup.reset_password') == 'True',
}
qcontext.update(config)
if 'error' in qcontext or mode not in ('reset', 'signup') or (not token and not config[mode]):
response = super(Home, self).web_login(*args, **kw)
if isinstance(response, LazyResponse):
response.params['values'].update(config)
return response
if request.httprequest.method == 'GET':
if token_infos:
qcontext.update(token_infos)
else:
res_users = request.registry.get('res.users')
login = request.params.get('login')
if mode == 'reset' and not token:
try:
res_users.reset_password(request.cr, openerp.SUPERUSER_ID, login)
qcontext['message'] = _("An email has been sent with credentials to reset your password")
response.params['template'] = 'web.login'
except:
qcontext['error'] = _("Could not reset your password")
_logger.exception('error when resetting password')
else:
values = {key: qcontext.get(key) for key in ('login', 'name', 'password')}
res_users.signup(request.cr, openerp.SUPERUSER_ID, values, token)
request.cr.commit()
return super(Home, self).web_login(*args, **kw)
return response return response
def get_auth_signup_config(self, dbname):
""" retrieve the module config (which features are enabled) for the login page """
registry = RegistryManager.get(dbname)
with registry.cursor() as cr:
icp = registry.get('ir.config_parameter')
config = {
'signup': icp.get_param(cr, openerp.SUPERUSER_ID, 'auth_signup.allow_uninvited') == 'True',
'reset_password': icp.get_param(cr, openerp.SUPERUSER_ID, 'auth_signup.reset_password') == 'True',
}
return config
class Controller(http.Controller):
@http.route('/auth_signup/retrieve', type='json', auth="none")
def retrieve(self, dbname, token):
""" retrieve the user info (name, login or email) corresponding to a signup token """
registry = RegistryManager.get(dbname)
with registry.cursor() as cr:
res_partner = registry.get('res.partner')
user_info = res_partner.signup_retrieve_info(cr, openerp.SUPERUSER_ID, token)
return user_info
@http.route('/auth_signup/signup', type='json', auth="none")
def signup(self, dbname, token, **values):
""" sign up a user (new or existing)"""
try:
self._signup_with_values(dbname, token, values)
except SignupError, e:
return {'error': openerp.tools.exception_to_unicode(e)}
return {}
def _signup_with_values(self, dbname, token, values):
registry = RegistryManager.get(dbname)
with registry.cursor() as cr:
res_users = registry.get('res.users')
res_users.signup(cr, openerp.SUPERUSER_ID, values, token)
@http.route('/auth_signup/reset_password', type='json', auth="none")
def reset_password(self, dbname, login):
""" retrieve user, and perform reset password """
registry = RegistryManager.get(dbname)
with registry.cursor() as cr:
try:
res_users = registry.get('res.users')
res_users.reset_password(cr, openerp.SUPERUSER_ID, login)
cr.commit()
except Exception as e:
# signup error
_logger.exception('error when resetting password')
raise(e)
return True
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -69,7 +69,8 @@ class res_partner(osv.Model):
# the parameters to encode for the query # the parameters to encode for the query
query = dict(db=cr.dbname) query = dict(db=cr.dbname)
signup_type = context.get('signup_force_type_in_url', partner.signup_type or '') signup_type = context.get('signup_force_type_in_url', partner.signup_type or '')
query[signup_type] = 1 if signup_type:
query['mode'] = signup_type
if partner.signup_token and signup_type: if partner.signup_token and signup_type:
query['token'] = partner.signup_token query['token'] = partner.signup_token

View File

@ -1,188 +1,19 @@
openerp.auth_signup = function(instance) { openerp.auth_signup = function(instance) {
instance.auth_signup = instance.auth_signup || {}; openerp.web.LoginForm.include({
var _t = instance.web._t; start: function () {
return;
instance.web.Login.include({
start: function() {
var self = this; var self = this;
this.signup_enabled = false; this.$el.on('submit', function () {
this.reset_password_enabled = false; var password = self.get_password_field('password');
return this._super().always(function() { var confirm_password = self.get_password_field('confirm_password');
if (password && confirm_password && (password.value != confirm_password.value)) {
// Switches the login box to the select mode whith mode == [default|signup|reset] alert("Passwords do not match; please retype them.");
self.on('change:login_mode', self, function() {
var mode = self.get('login_mode') || 'default';
self.$('*[data-modes]').each(function() {
var modes = $(this).data('modes').split(/\s+/);
$(this).toggle(modes.indexOf(mode) > -1);
});
self.$('a.oe_signup_signup:visible').toggle(self.signup_enabled);
self.$('a.oe_signup_reset_password:visible').toggle(self.reset_password_enabled);
});
// to switch between the signup and regular login form
self.$('a.oe_signup_signup').click(function(ev) {
self.set('login_mode', 'signup');
return false; return false;
});
self.$('a.oe_signup_back').click(function(ev) {
self.set('login_mode', 'default');
delete self.params.token;
return false;
});
var dbname = self.selected_db;
// if there is an error message in params, show it then forget it
if (self.params.error_message) {
self.show_error(self.params.error_message);
delete self.params.error_message;
}
if (dbname && self.params.login) {
self.$("form input[name=login]").val(self.params.login);
}
// bind reset password link
self.$('a.oe_signup_reset_password').click(self.do_reset_password);
if (dbname) {
self.rpc("/auth_signup/get_config", {dbname: dbname}).then(function(result) {
self.signup_enabled = result.signup;
self.reset_password_enabled = result.reset_password;
if (!self.signup_enabled || self.$("form input[name=login]").val()){
self.set('login_mode', self.params.type || 'default');
} else {
self.set('login_mode', 'signup');
}
// in case of a signup, retrieve the user information from the token
if (self.params.token) {
self.rpc("/auth_signup/retrieve", {dbname: dbname, token: self.params.token})
.then(self.on_token_loaded, self.on_token_failed);
}
});
} else {
// TODO: support multiple database mode
self.set('login_mode', self.params.type || 'default');
} }
}); });
}, },
get_password_field: function (field) {
on_token_loaded: function(result) { var selector = 'input[name="' + field + '"][type="password"]:visible';
// select the right the database return this.$(selector)[0];
this.selected_db = result.db;
this.on_db_loaded([result.db]);
if (result.token) {
// switch to signup mode, set user name and login
this.set('login_mode', (this.params.type === 'reset' ? 'reset' : 'signup'));
this.$("form input[name=name]").val(result.name).attr("readonly", "readonly");
if (result.login) {
this.$("form input[name=login]").val(result.login).attr("readonly", "readonly");
} else {
this.$("form input[name=login]").val(result.email);
}
} else {
// remain in login mode, set login if present
delete this.params.token;
this.set('login_mode', 'default');
this.$("form input[name=login]").val(result.login || "");
}
},
on_token_failed: function(result, ev) {
if (ev) {
ev.preventDefault();
}
this.show_error(_t("Invalid signup token"));
delete this.params.db;
delete this.params.token;
this.set('login_mode', 'default');
},
get_params: function(){
// signup user (or reset password)
var db = this.$("form [name=db]").val();
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 (!db) {
this.do_warn(_t("Login"), _t("No database selected !"));
return false;
} else if (!name) {
this.do_warn(_t("Login"), _t("Please enter a name."));
return false;
} else if (!login) {
this.do_warn(_t("Login"), _t("Please enter a username."));
return false;
} else if (!password || !confirm_password) {
this.do_warn(_t("Login"), _t("Please enter a password and confirm it."));
return false;
} else if (password !== confirm_password) {
this.do_warn(_t("Login"), _t("Passwords do not match; please retype them."));
return false;
}
var params = {
dbname : db,
token: this.params.token || "",
name: name,
login: login,
password: password,
};
return params;
},
on_submit: function(ev) {
if (ev) {
ev.preventDefault();
}
var login_mode = this.get('login_mode');
if (login_mode === 'signup' || login_mode === 'reset') {
var params = this.get_params();
if (_.isEmpty(params)){
return false;
}
var self = this,
super_ = this._super;
this.rpc('/auth_signup/signup', params)
.done(function(result) {
if (result.error) {
self.show_error(result.error);
} else {
super_.apply(self, [ev]);
}
});
} else {
// regular login
this._super(ev);
}
},
do_reset_password: function(ev) {
if (ev) {
ev.preventDefault();
}
var self = this;
var db = this.$("form [name=db]").val();
var login = this.$("form input[name=login]").val();
if (!db) {
this.do_warn(_t("Login"), _t("No database selected !"));
return $.Deferred().reject();
} else if (!login) {
this.do_warn(_t("Login"), _t("Please enter a username or email address."));
return $.Deferred().reject();
}
return self.rpc("/auth_signup/reset_password", { dbname: db, login: login }).done(function(result) {
self.show_error(_t("An email has been sent with credentials to reset your password"));
self.set('login_mode', 'default');
}).fail(function(result, ev) {
ev.preventDefault();
self.show_error(result.message);
});
}, },
}); });
}; };

View File

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- vim:fdl=1:
-->
<templates id="template" xml:space="preserve">
<t t-extend="Login">
<t t-jquery="form ul:first li:contains('Username')" t-operation="before">
<li data-modes="signup reset">Name</li>
<li data-modes="signup reset"><input name="name" type="text"/></li>
</t>
<t t-jquery="form ul:first li:contains('Username')" t-operation="replace">
<li data-modes="default">Username</li>
<li data-modes="signup reset">Username (Email)</li>
</t>
<t t-jquery="form ul:first li:has(input[name=login], input[name=password]), form ul:first li:contains('Password')">
this.attr('data-modes', 'default signup reset');
</t>
<t t-jquery="form ul:first li:has(input[name=password])" t-operation="after">
<li data-modes="signup reset">Confirm Password</li>
<li data-modes="signup reset"><input name="confirm_password" type="password"/></li>
</t>
<t t-jquery="form ul:first li:has(button[name=submit])" t-operation="replace">
<li>
<button name="submit">
<span data-modes="default">Log in</span>
<span data-modes="signup">Sign Up</span>
<span data-modes="reset">Reset password</span>
</button>
<a class="oe_signup_signup" data-modes="default" href="#">Sign Up</a>
<a class="oe_signup_back" data-modes="signup reset" href="#">Back to Login</a>
<a class="oe_signup_reset_password" data-modes="default" href="#">Reset password</a>
</li>
</t>
<t t-jquery=".oe_login_manage_db">
this.attr('data-modes', 'default');
</t>
</t>
</templates>

View File

@ -5,8 +5,8 @@
<data> <data>
<template id="auth_signup.login" inherit_id="web.login" name="Login (overloaded by auth_signup)"> <template id="auth_signup.login" inherit_id="web.login" name="Login (overloaded by auth_signup)">
<xpath expr="//button[@type='submit']" position="before"> <xpath expr="//button[@type='submit']" position="before">
<a t-if="signup" href="/web/login?signup=1" class="btn btn-default pull-left">Sign up</a> <a t-if="signup" t-attf-href="?mode=signup{{ '&amp;debug' if debug else '' }}" class="btn btn-default pull-left">Sign up</a>
<a t-if="reset_password" href="/web/login?reset=1" class="btn btn-default pull-left">Reset Password</a> <a t-if="reset" t-attf-href="?mode=reset{{ '&amp;debug' if debug else '' }}" class="btn btn-default pull-left">Reset Password</a>
</xpath> </xpath>
</template> </template>
@ -20,40 +20,58 @@
<script type="text/javascript" t-att-src="js_file"></script> <script type="text/javascript" t-att-src="js_file"></script>
</t> </t>
</t> </t>
<script type="text/javascript">
$(function() {
var s = new openerp.init(<t t-raw="modules"/>);
var login_form = new openerp.web.LoginForm($('.oe_signup_form'));
});
</script>
<t t-set="reset_without_token" t-value="mode == 'reset' and not token"/>
<form class="oe_signup_form" role="form" t-attf-action="/web/login{{ '?debug' if debug else '' }}" method="post"> <form class="oe_signup_form" role="form" t-attf-action="/web/login{{ '?debug' if debug else '' }}" method="post">
<div class="form-group field-name"> <div class="form-group field-name" t-if="not reset_without_token">
<label for="name" class="control-label">Name</label> <label for="name" class="control-label">Name</label>
<input type="text" name="name" t-att-value="name" id="name" class="form-control" placeholder="Enter your name" required="required" autofocus="autofocus"/> <input type="text" name="name" t-att-value="name" id="name" class="form-control" placeholder="Enter your name"
required="required" autofocus="autofocus" t-att-disabled="'disabled' if mode == 'reset' and token else None"/>
</div> </div>
<div class="form-group field-login"> <div class="form-group field-login">
<label for="login" class="control-label">Username (email)</label> <label for="login" class="control-label">Username (email)</label>
<input type="text" name="login" t-att-value="login" id="login" class="form-control" placeholder="Enter login" required="required"/> <input type="text" name="login" t-att-value="login" id="login" class="form-control" placeholder="Enter login"
t-att-autofocus="'autofocus' if reset_without_token else None"
required="required" t-att-disabled="'disabled' if mode == 'reset' and token else None"/>
<input type="hidden" name="login" t-att-value="login" t-if="mode == 'reset' and token"/>
</div> </div>
<div class="form-group field-password"> <div class="form-group field-password" t-if="not reset_without_token">
<label for="password" class="control-label">Password</label> <label for="password" class="control-label">Password</label>
<input type="password" name="password" id="password" class="form-control" placeholder="Password" required="required"/> <input type="password" name="password" id="password" class="form-control" placeholder="Password"
required="required" t-att-autofocus="'autofocus' if mode == 'reset' and token else None"/>
</div> </div>
<div class="form-group field-confirm_password"> <div class="form-group field-confirm_password" t-if="not reset_without_token">
<label for="confirm_password" class="control-label">Confirm Password</label> <label for="confirm_password" class="control-label">Confirm Password</label>
<input type="password" name="confirm_password" id="confirm_password" class="form-control" placeholder="Confirm your password" required="required"/> <input type="password" name="confirm_password" id="confirm_password" class="form-control" placeholder="Confirm your password" required="required"/>
</div> </div>
<div class="oe_login_messages"> <p class="alert alert-danger" t-if="error">
<p class="alert alert-danger" t-if="authentication_failed"> <t t-esc="error"/>
Wrong login/password </p>
</p> <p class="alert alert-success" t-if="message">
</div> <t t-esc="message"/>
</p>
<hr/> <hr/>
<input type="hidden" name="redirect" t-att-value="redirect"/> <input type="hidden" name="redirect" t-att-value="redirect"/>
<input type="hidden" name="signup" value="1"/> <input type="hidden" name="mode" t-att-value="mode"/>
<input type="hidden" name="token" t-att-value="token"/>
<div class="clearfix oe_login_buttons"> <div class="clearfix oe_login_buttons">
<a href="/web/login" class="btn btn-default pull-left">Back to Login</a> <a href="/web/login" class="btn btn-default pull-left">Back to Login</a>
<button type="submit" class="btn btn-primary pull-right">Signup</button> <button type="submit" class="btn btn-primary pull-right">
<t t-if="mode == 'signup'">Signup</t>
<t t-if="mode == 'reset'">Reset password</t>
</button>
</div> </div>
</form> </form>