-
Notifications
You must be signed in to change notification settings - Fork 24.4k
/
portal_wizard.py
198 lines (169 loc) · 8.84 KB
/
portal_wizard.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
from odoo.tools.translate import _
from odoo.tools import email_split
from odoo.exceptions import UserError
from odoo import api, fields, models
_logger = logging.getLogger(__name__)
# welcome email sent to portal users
# (note that calling '_' has no effect except exporting those strings for translation)
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 PortalWizard(models.TransientModel):
"""
A wizard to manage the creation/removal of portal users.
"""
_name = 'portal.wizard'
_description = 'Portal Access Management'
def _default_portal(self):
return self.env['res.groups'].search([('is_portal', '=', True)], limit=1)
portal_id = fields.Many2one('res.groups', domain=[('is_portal', '=', True)], required=True, string='Portal',
default=_default_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('Invitation Message', help="This text is included in the email sent to new users of the portal.")
@api.onchange('portal_id')
def onchange_portal_id(self):
# for each partner, determine corresponding portal.wizard.user records
partner_ids = self.env.context.get('active_ids', [])
contact_ids = set()
user_changes = []
for partner in self.env['res.partner'].sudo().browse(partner_ids):
contact_partners = partner.child_ids | partner
for contact in contact_partners:
# 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 = self.portal_id in contact.user_ids[0].groups_id
user_changes.append((0, 0, {
'partner_id': contact.id,
'email': contact.email,
'in_portal': in_portal,
}))
self.user_ids = user_changes
@api.multi
def action_apply(self):
self.ensure_one()
self.user_ids.action_apply()
return {'type': 'ir.actions.act_window_close'}
class PortalWizardUser(models.TransientModel):
"""
A model to configure users in the portal wizard.
"""
_name = 'portal.wizard.user'
_description = 'Portal User Config'
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('Email')
in_portal = fields.Boolean('In Portal')
user_id = fields.Many2one('res.users', string='Login User')
@api.multi
def get_error_messages(self):
emails = []
partners_error_empty = self.env['res.partner']
partners_error_emails = self.env['res.partner']
partners_error_user = self.env['res.partner']
for wizard_user in self.with_context(active_test=False).filtered(lambda w: w.in_portal and not w.partner_id.user_ids):
email = extract_email(wizard_user.email)
if not email:
partners_error_empty |= wizard_user.partner_id
elif email in emails:
partners_error_emails |= wizard_user.partner_id
user = self.env['res.users'].sudo().with_context(active_test=False).search([('login', '=', email)])
if user:
partners_error_user |= wizard_user.partner_id
emails.append(email)
error_msg = []
if partners_error_empty:
error_msg.append("%s\n- %s" % (_("Some contacts don't have a valid email: "),
'\n- '.join(partners_error_empty.mapped('display_name'))))
if partners_error_emails:
error_msg.append("%s\n- %s" % (_("Several contacts have the same email: "),
'\n- '.join(partners_error_emails.mapped('email'))))
if partners_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 partners_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
@api.multi
def action_apply(self):
self.env['res.partner'].check_access_rights('write')
""" From selected partners, add corresponding users to chosen portal group. It either granted
existing user, or create new one (and add it to the group).
"""
error_msg = self.get_error_messages()
if error_msg:
raise UserError("\n\n".join(error_msg))
for wizard_user in self.sudo().with_context(active_test=False):
group_portal = wizard_user.wizard_id.portal_id
if not group_portal.is_portal:
raise UserError(_('Group %s is not a portal') % group_portal.name)
user = wizard_user.partner_id.user_ids[0] if wizard_user.partner_id.user_ids else None
# update partner email, if a new one was introduced
if wizard_user.partner_id.email != wizard_user.email:
wizard_user.partner_id.write({'email': wizard_user.email})
# add portal group to relative user of selected partners
if wizard_user.in_portal:
user_portal = None
# create a user if necessary, and make sure it is in the portal group
if not user:
if wizard_user.partner_id.company_id:
company_id = wizard_user.partner_id.company_id.id
else:
company_id = self.env['res.company']._company_default_get('res.users').id
user_portal = wizard_user.sudo().with_context(company_id=company_id)._create_user()
else:
user_portal = user
wizard_user.write({'user_id': user_portal.id})
if not wizard_user.user_id.active or group_portal not in wizard_user.user_id.groups_id:
wizard_user.user_id.write({'active': True, 'groups_id': [(4, group_portal.id)]})
# prepare for the signup process
wizard_user.user_id.partner_id.signup_prepare()
wizard_user.with_context(active_test=True)._send_email()
wizard_user.refresh()
else:
# remove the user (if it exists) from the portal group
if user and group_portal in user.groups_id:
# if user belongs to portal only, deactivate it
if len(user.groups_id) <= 1:
user.write({'groups_id': [(3, group_portal.id)], 'active': False})
else:
user.write({'groups_id': [(3, group_portal.id)]})
@api.multi
def _create_user(self):
""" create a new user for wizard_user.partner_id
:returns record of res.users
"""
company_id = self.env.context.get('company_id')
return self.env['res.users'].with_context(no_reset_password=True).create({
'email': extract_email(self.email),
'login': extract_email(self.email),
'partner_id': self.partner_id.id,
'company_id': company_id,
'company_ids': [(6, 0, [company_id])],
'groups_id': [(6, 0, [])],
})
@api.multi
def _send_email(self):
""" send notification email to a new portal user """
if not self.env.user.email:
raise UserError(_('You must have an email address in your User Preferences to send emails.'))
# determine subject and body in the portal user's language
template = self.env.ref('portal.mail_template_data_portal_welcome')
for wizard_line in self:
lang = wizard_line.user_id.lang
partner = wizard_line.user_id.partner_id
portal_url = partner.with_context(signup_force_type_in_url='', lang=lang)._get_signup_url_for_action()[partner.id]
partner.signup_prepare()
if template:
template.with_context(dbname=self._cr.dbname, portal_url=portal_url, lang=lang).send_mail(wizard_line.id, force_send=True)
else:
_logger.warning("No email template found for sending email to the portal user")
return True