1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2011 OpenERP S.A (<http://www.openerp.com>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
25 from osv import osv, fields
26 from tools.translate import _
27 from tools.misc import email_re
28 from openerp import SUPERUSER_ID
30 from base.res.res_partner import _lang_get
31 _logger = logging.getLogger(__name__)
33 # welcome email sent to new portal users (note that calling tools.translate._
34 # has no effect except exporting those strings for translation)
35 WELCOME_EMAIL_SUBJECT = _("Your OpenERP account at %(company)s")
36 WELCOME_EMAIL_BODY = _("""Dear %(name)s,
38 You have been created an OpenERP account of %(portal)s at %(url)s.
40 Your login account data is:
43 Password: %(password)s
48 OpenERP - Open Source Business Applications
49 http://www.openerp.com
52 # character sets for passwords, excluding 0, O, o, 1, I, l
53 _PASSU = 'ABCDEFGHIJKLMNPQRSTUVWXYZ'
54 _PASSL = 'abcdefghijkmnpqrstuvwxyz'
57 def random_password():
58 # get 3 uppercase letters, 3 lowercase letters, 2 digits, and shuffle them
59 chars = map(random.choice, [_PASSU] * 3 + [_PASSL] * 3 + [_PASSD] * 2)
63 def extract_email(email):
64 """ extract the email address from a user-friendly email address """
65 m = email_re.search(email or "")
66 return m and m.group(0) or ""
70 class wizard(osv.osv_memory):
72 A wizard to manage the creation/removal of portal users.
74 _name = 'portal.wizard'
75 _description = 'Portal Access Management'
78 'portal_id': fields.many2one('res.groups', domain=[('is_portal', '=', True)], required=True,
79 string='Portal', help="The portal that users can be added in or removed from."),
80 'user_ids': fields.one2many('portal.wizard.user', 'wizard_id', string='Users'),
81 'message': fields.text(string='Invitation Message',
82 help="This text is included in the welcome email sent to the users."),
85 def _default_portal(self, cr, uid, context):
86 portal_ids = self.pool.get('res.groups').search(cr, uid, [('is_portal', '=', True)])
87 return portal_ids and portal_ids[0] or False
90 'portal_id': _default_portal,
93 def onchange_portal_id(self, cr, uid, ids, portal_id, context=None):
94 # for each partner, determine corresponding portal.wizard.user records
95 res_partner = self.pool.get('res.partner')
96 partner_ids = context and context.get('active_ids') or []
98 for partner in res_partner.browse(cr, SUPERUSER_ID, partner_ids, context):
99 for contact in (partner.child_ids or [partner]):
102 in_portal = portal_id in [g.id for g in contact.user_ids[0].groups_id]
103 user_changes.append((0, 0, {
104 'partner_id': contact.id,
105 'email': contact.email,
106 'in_portal': in_portal,
108 return {'value': {'user_ids': user_changes}}
110 def action_apply(self, cr, uid, ids, context=None):
111 wizard = self.browse(cr, uid, ids[0], context)
112 portal_user_ids = [user.id for user in wizard.user_ids]
113 self.pool.get('portal.wizard.user').action_apply(cr, uid, portal_user_ids, context)
114 return {'type': 'ir.actions.act_window_close'}
116 class wizard_user(osv.osv_memory):
118 A model to configure users in the portal wizard.
120 _name = 'portal.wizard.user'
121 _description = 'Portal User Config'
124 'wizard_id': fields.many2one('portal.wizard', string='Wizard', required=True),
125 'partner_id': fields.many2one('res.partner', string='Contact', required=True, readonly=True),
126 'email': fields.related('partner_id', 'email', type='char', string='Email'),
127 'in_portal': fields.boolean('In Portal'),
130 def action_apply(self, cr, uid, ids, context=None):
131 res_users = self.pool.get('res.users')
132 for wizard_user in self.browse(cr, SUPERUSER_ID, ids, context):
133 portal = wizard_user.wizard_id.portal_id
134 user = self._retrieve_user(cr, SUPERUSER_ID, wizard_user, context)
135 if wizard_user.in_portal:
136 # create a user if necessary, and make sure it is in the portal group
138 user = self._create_user(cr, SUPERUSER_ID, wizard_user, context)
139 if (not user.active) or (portal not in user.groups_id):
140 user.write({'active': True, 'groups_id': [(4, portal.id)]})
141 wizard_user = self.browse(cr, SUPERUSER_ID, wizard_user.id, context)
142 self._send_email(cr, uid, wizard_user, context)
144 # remove the user (if it exists) from the portal group
146 if portal in user.groups_id:
147 values = {'groups_id': [(3, portal.id)]}
148 if len(user.groups_id) == 1:
149 values['active'] = False # deactivate user
152 def _retrieve_user(self, cr, uid, wizard_user, context=None):
153 """ retrieve the (possibly inactive) user corresponding to wizard_user.partner_id
154 @param wizard_user: browse record of model portal.wizard.user
155 @return: browse record of model res.users
157 if wizard_user.partner_id.user_ids:
158 return wizard_user.partner_id.user_ids[0]
159 # the user may be inactive, search for it
160 res_users = self.pool.get('res.users')
161 domain = [('partner_id', '=', wizard_user.partner_id.id), ('active', '=', False)]
162 user_ids = res_users.search(cr, uid, domain)
163 return user_ids and res_users.browse(cr, uid, user_ids[0], context) or False
165 def _create_user(self, cr, uid, wizard_user, context=None):
166 """ create a new user for wizard_user.partner_id
167 @param wizard_user: browse record of model portal.wizard.user
168 @return: browse record of model res.users
170 res_users = self.pool.get('res.users')
171 create_context = dict(context or {}, noshortcut=True) # to prevent shortcut creation
173 'login': extract_email(wizard_user.email),
174 'password': random_password(),
175 'partner_id': wizard_user.partner_id.id,
176 'groups_id': [(6, 0, [])],
179 user_id = res_users.create(cr, uid, values, context=create_context)
180 return res_users.browse(cr, uid, user_id, context)
182 def _send_email(self, cr, uid, wizard_user, context=None):
183 """ send invitation email to a new portal user
184 @param wizard_user: browse record of model portal.wizard.user
185 @return: the id of the created mail.mail record
187 this_context = context
188 this_user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context)
189 if not this_user.email:
190 raise osv.except_osv(_('Email required'),
191 _('You must have an email address in your User Preferences to send emails.'))
193 # determine subject and body in the portal user's language
194 url = self.pool.get('ir.config_parameter').get_param(cr, SUPERUSER_ID, 'web.base.url', context=this_context)
195 user = wizard_user.partner_id.user_ids[0]
196 context = dict(this_context or {}, lang=user.lang)
198 'company': this_user.company_id.name,
199 'portal': wizard_user.wizard_id.portal_id.name,
200 'message': wizard_user.wizard_id.message or "",
201 'url': url or _("(missing url)"),
204 'password': user.password,
207 subject = _(WELCOME_EMAIL_SUBJECT) % data
208 body = _(WELCOME_EMAIL_BODY) % data
210 mail_mail = self.pool.get('mail.mail')
212 'email_from': this_user.email,
213 'email_to': user.email,
215 'body_html': '<pre>%s</pre>' % body,
218 return mail_mail.create(cr, uid, mail_values, context=this_context)
220 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: