odoo/addons/portal/wizard/portal_wizard.py

265 lines
12 KiB
Python

# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2011 OpenERP S.A (<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/>.
#
##############################################################################
import logging
from openerp.osv import fields, osv
from openerp.tools.translate import _
from openerp.tools import email_split
from openerp import SUPERUSER_ID
_logger = logging.getLogger(__name__)
# welcome email sent to portal users
# (note that calling '_' has no effect except exporting those strings for translation)
WELCOME_EMAIL_SUBJECT = _("Your Odoo account at %(company)s")
WELCOME_EMAIL_BODY = _("""Dear %(name)s,
You have been given access to %(company)s's %(portal)s.
Your login account data is:
Username: %(login)s
Portal: %(portal_url)s
Database: %(db)s
You can set or change your password via the following url:
%(signup_url)s
%(welcome_message)s
--
Odoo - Open Source Business Applications
http://www.openerp.com
""")
def extract_email(email):
""" extract the email address from a user-friendly email address """
addresses = email_split(email)
return addresses[0] if addresses else ''
class wizard(osv.osv_memory):
"""
A wizard to manage the creation/removal of portal users.
"""
_name = 'portal.wizard'
_description = 'Portal Access Management'
_columns = {
'portal_id': fields.many2one('res.groups', domain=[('is_portal', '=', True)], required=True,
string='Portal', help="The portal that users can be added in or removed from."),
'user_ids': fields.one2many('portal.wizard.user', 'wizard_id', string='Users'),
'welcome_message': fields.text(string='Invitation Message',
help="This text is included in the email sent to new users of the portal."),
}
def _default_portal(self, cr, uid, context):
portal_ids = self.pool.get('res.groups').search(cr, uid, [('is_portal', '=', True)])
return portal_ids and portal_ids[0] or False
_defaults = {
'portal_id': _default_portal,
}
def onchange_portal_id(self, cr, uid, ids, portal_id, context=None):
# for each partner, determine corresponding portal.wizard.user records
res_partner = self.pool.get('res.partner')
partner_ids = context and context.get('active_ids') or []
contact_ids = set()
user_changes = []
for partner in res_partner.browse(cr, SUPERUSER_ID, partner_ids, context):
for contact in (partner.child_ids or [partner]):
# make sure that each contact appears at most once in the list
if contact.id not in contact_ids:
contact_ids.add(contact.id)
in_portal = False
if contact.user_ids:
in_portal = portal_id in [g.id for g in contact.user_ids[0].groups_id]
user_changes.append((0, 0, {
'partner_id': contact.id,
'email': contact.email,
'in_portal': in_portal,
}))
return {'value': {'user_ids': user_changes}}
def action_apply(self, cr, uid, ids, context=None):
wizard = self.browse(cr, uid, ids[0], context)
portal_user_ids = [user.id for user in wizard.user_ids]
self.pool.get('portal.wizard.user').action_apply(cr, uid, portal_user_ids, context)
return {'type': 'ir.actions.act_window_close'}
class wizard_user(osv.osv_memory):
"""
A model to configure users in the portal wizard.
"""
_name = 'portal.wizard.user'
_description = 'Portal User Config'
_columns = {
'wizard_id': fields.many2one('portal.wizard', string='Wizard', required=True, ondelete='cascade'),
'partner_id': fields.many2one(
'res.partner', string='Contact', required=True, readonly=True,
ondelete='cascade'),
'email': fields.char(string='Email', size=240),
'in_portal': fields.boolean('In Portal'),
}
def get_error_messages(self, cr, uid, ids, context=None):
res_users = self.pool.get('res.users')
emails = []
error_empty = []
error_emails = []
error_user = []
ctx = dict(context or {}, active_test=False)
for wizard_user in self.browse(cr, SUPERUSER_ID, ids, context):
if wizard_user.in_portal and not self._retrieve_user(cr, SUPERUSER_ID, wizard_user, context):
email = extract_email(wizard_user.email)
if not email:
error_empty.append(wizard_user.partner_id)
elif email in emails and email not in error_emails:
error_emails.append(wizard_user.partner_id)
user = res_users.search(cr, SUPERUSER_ID, [('login', '=', email)], context=ctx)
if user:
error_user.append(wizard_user.partner_id)
emails.append(email)
error_msg = []
if error_empty:
error_msg.append("%s\n- %s" % (_("Some contacts don't have a valid email: "),
'\n- '.join(['%s' % (p.display_name,) for p in error_empty])))
if error_emails:
error_msg.append("%s\n- %s" % (_("Several contacts have the same email: "),
'\n- '.join([p.email for p in error_emails])))
if error_user:
error_msg.append("%s\n- %s" % (_("Some contacts have the same email as an existing portal user:"),
'\n- '.join(['%s <%s>' % (p.display_name, p.email) for p in error_user])))
if error_msg:
error_msg.append(_("To resolve this error, you can: \n"
"- Correct the emails of the relevant contacts\n"
"- Grant access only to contacts with unique emails"))
return error_msg
def action_apply(self, cr, uid, ids, context=None):
self.pool['res.partner'].check_access_rights(cr, uid, 'write')
error_msg = self.get_error_messages(cr, uid, ids, context=context)
if error_msg:
raise osv.except_osv(_('Contacts Error'), "\n\n".join(error_msg))
for wizard_user in self.browse(cr, SUPERUSER_ID, ids, context):
portal = wizard_user.wizard_id.portal_id
if not portal.is_portal:
raise osv.except_osv("Error", "Not a portal: " + portal.name)
user = self._retrieve_user(cr, SUPERUSER_ID, wizard_user, context)
if wizard_user.partner_id.email != wizard_user.email:
wizard_user.partner_id.write({'email': wizard_user.email})
if wizard_user.in_portal:
# create a user if necessary, and make sure it is in the portal group
if not user:
user = self._create_user(cr, SUPERUSER_ID, wizard_user, context)
if (not user.active) or (portal not in user.groups_id):
user.write({'active': True, 'groups_id': [(4, portal.id)]})
# prepare for the signup process
user.partner_id.signup_prepare()
self._send_email(cr, uid, wizard_user, context)
wizard_user.refresh()
else:
# remove the user (if it exists) from the portal group
if user and (portal in user.groups_id):
# if user belongs to portal only, deactivate it
if len(user.groups_id) <= 1:
user.write({'groups_id': [(3, portal.id)], 'active': False})
else:
user.write({'groups_id': [(3, portal.id)]})
def _retrieve_user(self, cr, uid, wizard_user, context=None):
""" retrieve the (possibly inactive) user corresponding to wizard_user.partner_id
@param wizard_user: browse record of model portal.wizard.user
@return: browse record of model res.users
"""
context = dict(context or {}, active_test=False)
res_users = self.pool.get('res.users')
domain = [('partner_id', '=', wizard_user.partner_id.id)]
user_ids = res_users.search(cr, uid, domain, context=context)
return user_ids and res_users.browse(cr, uid, user_ids[0], context=context) or False
def _create_user(self, cr, uid, wizard_user, context=None):
""" create a new user for wizard_user.partner_id
@param wizard_user: browse record of model portal.wizard.user
@return: browse record of model res.users
"""
res_users = self.pool.get('res.users')
create_context = dict(context or {}, noshortcut=True, no_reset_password=True) # to prevent shortcut creation
values = {
'email': extract_email(wizard_user.email),
'login': extract_email(wizard_user.email),
'partner_id': wizard_user.partner_id.id,
'groups_id': [(6, 0, [])],
}
user_id = res_users.create(cr, uid, values, context=create_context)
return res_users.browse(cr, uid, user_id, context)
def _send_email(self, cr, uid, wizard_user, context=None):
""" send notification email to a new portal user
@param wizard_user: browse record of model portal.wizard.user
@return: the id of the created mail.mail record
"""
res_partner = self.pool['res.partner']
this_context = context
this_user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context)
if not this_user.email:
raise osv.except_osv(_('Email Required'),
_('You must have an email address in your User Preferences to send emails.'))
# determine subject and body in the portal user's language
user = self._retrieve_user(cr, SUPERUSER_ID, wizard_user, context)
context = dict(this_context or {}, lang=user.lang)
ctx_portal_url = dict(context, signup_force_type_in_url='')
portal_url = res_partner._get_signup_url_for_action(cr, uid,
[user.partner_id.id],
context=ctx_portal_url)[user.partner_id.id]
res_partner.signup_prepare(cr, uid, [user.partner_id.id], context=context)
data = {
'company': this_user.company_id.name,
'portal': wizard_user.wizard_id.portal_id.name,
'welcome_message': wizard_user.wizard_id.welcome_message or "",
'db': cr.dbname,
'name': user.name,
'login': user.login,
'signup_url': user.signup_url,
'portal_url': portal_url,
}
mail_mail = self.pool.get('mail.mail')
mail_values = {
'email_from': this_user.email,
'email_to': user.email,
'subject': _(WELCOME_EMAIL_SUBJECT) % data,
'body_html': '<pre>%s</pre>' % (_(WELCOME_EMAIL_BODY) % data),
'state': 'outgoing',
'type': 'email',
}
mail_id = mail_mail.create(cr, uid, mail_values, context=this_context)
return mail_mail.send(cr, uid, [mail_id], context=this_context)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: