[IMP] link_tracker, http_routing: ignore requests from social bots for link tracker

Purpose
=======
Avoid counting requests from social bots (twitter, facebook, linkedin...)
when tracking a link.

Specifications
=============
Social media platforms have a specific user agent in the HTTP headers that
can be used to detect them and to not increment the click count in that case.

Task-2578902

closes odoo/odoo#78806

Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Fabio Barbero
2021-12-14 09:11:15 +00:00
committed by Thibault Delavallée
parent 66ba1c3c4a
commit a66cdf3f7f
3 changed files with 24 additions and 21 deletions
+2 -14
View File
@@ -327,18 +327,6 @@ class IrHttp(models.AbstractModel):
"""
return ['web']
bots = "bot|crawl|slurp|spider|curl|wget|facebookexternalhit".split("|")
@classmethod
def is_a_bot(cls):
# We don't use regexp and ustr voluntarily
# timeit has been done to check the optimum method
user_agent = request.httprequest.environ.get('HTTP_USER_AGENT', '').lower()
try:
return any(bot in user_agent for bot in cls.bots)
except UnicodeDecodeError:
return any(bot in user_agent.encode('ascii', 'ignore') for bot in cls.bots)
@classmethod
def _get_frontend_langs(cls):
return [code for code, _ in request.env['res.lang'].get_installed()]
@@ -385,7 +373,7 @@ class IrHttp(models.AbstractModel):
if request.routing_iteration == 1:
context = dict(request.context)
path = request.httprequest.path.split('/')
is_a_bot = cls.is_a_bot()
is_a_bot = request.env['ir.http'].is_a_bot()
lang_codes = [code for code, *_ in Lang.get_available()]
nearest_lang = not func and cls.get_nearest_lang(Lang._lang_get_code(path[1]))
@@ -462,7 +450,7 @@ class IrHttp(models.AbstractModel):
path = request.httprequest.path.split('/')
default_lg_id = cls._get_default_lang()
if request.routing_iteration == 1:
is_a_bot = cls.is_a_bot()
is_a_bot = request.env['ir.http'].is_a_bot()
nearest_lang = not func and cls.get_nearest_lang(request.env['res.lang']._lang_get_code(path[1]))
url_lg = nearest_lang and path[1]
+13 -7
View File
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from werkzeug.exceptions import NotFound
from odoo import http
from odoo.http import request
@@ -9,11 +11,15 @@ class LinkTracker(http.Controller):
@http.route('/r/<string:code>', type='http', auth='public', website=True)
def full_url_redirect(self, code, **post):
country_code = request.session.geoip and request.session.geoip.get('country_code') or False
request.env['link.tracker.click'].sudo().add_click(
code,
ip=request.httprequest.remote_addr,
country_code=country_code
)
if not request.env['ir.http'].is_a_bot():
country_code = request.session.geoip and request.session.geoip.get(
'country_code') or False
request.env['link.tracker.click'].sudo().add_click(
code,
ip=request.httprequest.remote_addr,
country_code=country_code,
)
redirect_url = request.env['link.tracker'].get_url_from_code(code)
return request.redirect(redirect_url or '', code=301, local=False)
if not redirect_url:
raise NotFound()
return request.redirect(redirect_url, code=301, local=False)
+9
View File
@@ -16,6 +16,15 @@ from odoo.addons.web.controllers.main import HomeStaticTemplateHelpers
class Http(models.AbstractModel):
_inherit = 'ir.http'
bots = ["bot", "crawl", "slurp", "spider", "curl", "wget", "facebookexternalhit", "whatsapp", "trendsmapresolver", "pinterest", "instagram"]
@classmethod
def is_a_bot(cls):
user_agent = request.httprequest.user_agent.string.lower()
# We don't use regexp and ustr voluntarily
# timeit has been done to check the optimum method
return any(bot in user_agent for bot in cls.bots)
def webclient_rendering_context(self):
return {
'menu_data': request.env['ir.ui.menu'].load_menus(request.session.debug),