RATIONALE
Event will soon gain a major update called Event Online, allowing to better
support full-online events. In order to prepare its merge, preparatory merge
are done to lessen the final diff and have a smooth integration in a stable
version (13.3).
PURPOSE
Purpose of this merge is to clean visitor synchronization and tests. It
prepares further improvements to visitor model linked to Event Online.
SPECIFICATIONS
Add anchor methods to somehow merge visitors and update partner linked
to visitors and their sub records.
Main idea would be to be able to
* avoid unlinking visitors, notably because we have keys linked to them
allowing push notifications. As a given user may be linked to several
devices (different keys / different visitors) keeping them in database
improves push efficiency;
* allow to link sub-records to a main visitor, like tracked pages history,
even if multiple visitors are linked to the same identity;
In this stable we cannot remove current unlink of duplicate visitors due
to constraint of partner_id / visitor_id. However those methods allow to
tweak behavior by override. This will be done in future tasks.
LINKS
Task ID 2290016 (improve visitor synchronization and tests)
Prepares Task ID 2252655 (main Online Event task)
Prepares Task ID 2284043 (Visitor-based track wishlist)
PR #54036
X-original-commit: 8a8d2d4412d1b58545ee4f0240cca5114e541b6a
Co-authored-by: Aurélien Warnon <awa@odoo.com>
Co-authored-by: David Beguin <dbe@odoo.com>
Co-authored-by: Thibault Delavallée <tde@odoo.com>
101 lines
4.5 KiB
Python
101 lines
4.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
import logging
|
|
|
|
from odoo import api, fields, models, tools, _
|
|
from odoo.exceptions import ValidationError
|
|
from odoo.http import request
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class ResUsers(models.Model):
|
|
_inherit = 'res.users'
|
|
|
|
website_id = fields.Many2one('website', related='partner_id.website_id', store=True, related_sudo=False, readonly=False)
|
|
|
|
_sql_constraints = [
|
|
# Partial constraint, complemented by a python constraint (see below).
|
|
('login_key', 'unique (login, website_id)', 'You can not have two users with the same login!'),
|
|
]
|
|
|
|
def _has_unsplash_key_rights(self):
|
|
self.ensure_one()
|
|
if self.has_group('website.group_website_designer'):
|
|
return True
|
|
return super(ResUsers, self)._has_unsplash_key_rights()
|
|
|
|
@api.constrains('login', 'website_id')
|
|
def _check_login(self):
|
|
""" Do not allow two users with the same login without website """
|
|
self.flush(['login', 'website_id'])
|
|
self.env.cr.execute(
|
|
"""SELECT login
|
|
FROM res_users
|
|
WHERE login IN (SELECT login FROM res_users WHERE id IN %s AND website_id IS NULL)
|
|
AND website_id IS NULL
|
|
GROUP BY login
|
|
HAVING COUNT(*) > 1
|
|
""",
|
|
(tuple(self.ids),)
|
|
)
|
|
if self.env.cr.rowcount:
|
|
raise ValidationError(_('You can not have two users with the same login!'))
|
|
|
|
@api.model
|
|
def _get_login_domain(self, login):
|
|
website = self.env['website'].get_current_website()
|
|
return super(ResUsers, self)._get_login_domain(login) + website.website_domain()
|
|
|
|
@api.model
|
|
def _get_login_order(self):
|
|
return 'website_id, ' + super(ResUsers, self)._get_login_order()
|
|
|
|
@api.model
|
|
def _signup_create_user(self, values):
|
|
current_website = self.env['website'].get_current_website()
|
|
if request and current_website.specific_user_account:
|
|
values['company_id'] = current_website.company_id.id
|
|
values['company_ids'] = [(4, current_website.company_id.id)]
|
|
values['website_id'] = current_website.id
|
|
new_user = super(ResUsers, self)._signup_create_user(values)
|
|
return new_user
|
|
|
|
@api.model
|
|
def _get_signup_invitation_scope(self):
|
|
current_website = self.env['website'].get_current_website()
|
|
return current_website.auth_signup_uninvited or super(ResUsers, self)._get_signup_invitation_scope()
|
|
|
|
@classmethod
|
|
def authenticate(cls, db, login, password, user_agent_env):
|
|
""" Override to link the logged in user's res.partner to website.visitor.
|
|
If both a request-based visitor and a user-based visitor exist we try
|
|
to update them (have same partner_id), and move sub records to the main
|
|
visitor (user one). Purpose is to try to keep a main visitor with as
|
|
much sub-records (tracked pages, leads, ...) as possible. """
|
|
uid = super(ResUsers, cls).authenticate(db, login, password, user_agent_env)
|
|
if uid:
|
|
with cls.pool.cursor() as cr:
|
|
env = api.Environment(cr, uid, {})
|
|
visitor_sudo = env['website.visitor']._get_visitor_from_request()
|
|
if visitor_sudo:
|
|
user_partner = env.user.partner_id
|
|
other_user_visitor_sudo = env['website.visitor'].with_context(active_test=False).sudo().search(
|
|
[('partner_id', '=', user_partner.id), ('id', '!=', visitor_sudo.id)],
|
|
order='last_connection_datetime DESC',
|
|
) # current 13.3 state: 1 result max as unique visitor / partner
|
|
if other_user_visitor_sudo:
|
|
visitor_main = other_user_visitor_sudo[0]
|
|
other_visitors = other_user_visitor_sudo[1:] # normally void
|
|
(visitor_sudo + other_visitors)._link_to_visitor(visitor_main, keep_unique=True)
|
|
visitor_main.name = user_partner.name
|
|
visitor_main.active = True
|
|
visitor_main._update_visitor_last_visit()
|
|
else:
|
|
if visitor_sudo.partner_id != user_partner:
|
|
visitor_sudo._link_to_partner(
|
|
user_partner,
|
|
update_values={'partner_id': user_partner.id})
|
|
visitor_sudo._update_visitor_last_visit()
|
|
return uid
|