[IMP] website_event_exhibitor: use a POST method to set the tag filters

PURPOSE

It has been reported that the page showing the exhibitors is slow because of the
partner table used behind the scene. It turns out that the page can generate many
links for the filters which can trick the crawlers to explore them all. As the
page is slow, the crawlers can put a high pressure on the server by exploring
those links.

SPECS

- Use a POST method to set the tag filters.

By using a POST method, the page will not longer generate links and the crawlers
will no longer explore them. This technique is actually more reliable than simply
defining a `rel="nofollow"` rule on the links.

LINKS

Task id: 2466072

closes odoo/odoo#68192

Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Julien Banken
2021-07-05 07:46:49 +00:00
parent dfbe4ab655
commit e17e07030d
6 changed files with 133 additions and 54 deletions
@@ -37,6 +37,7 @@
'website_event_exhibitor/static/src/scss/event_templates_sponsor.scss',
'website_event_exhibitor/static/src/scss/event_exhibitor_templates.scss',
'website_event_exhibitor/static/src/js/event_exhibitor_connect.js',
'website_event_exhibitor/static/src/js/event_sponsor_search.js',
],
}
}
@@ -32,7 +32,7 @@ class ExhibitorController(WebsiteEventController):
'/event/<model("event.event"):event>/exhibitors',
# TDE BACKWARD: matches event/event-1/exhibitor/exhib-1 sub domain
'/event/<model("event.event"):event>/exhibitor'
], type='http', auth="public", website=True, sitemap=False)
], type='http', auth="public", website=True, sitemap=False, methods=['GET', 'POST'])
def event_exhibitors(self, event, **searches):
return request.render(
"website_event_exhibitor.event_exhibitors",
@@ -209,22 +209,20 @@ class ExhibitorController(WebsiteEventController):
def _get_search_countries(self, country_search):
# TDE FIXME: make me generic (slides, event, ...)
country_ids = set(request.httprequest.form.getlist('sponsor_country'))
try:
country_ids = literal_eval(country_search)
country_ids.update(literal_eval(country_search))
except Exception:
countries = request.env['res.country'].sudo()
else:
# perform a search to filter on existing / valid tags implicitly
countries = request.env['res.country'].sudo().search([('id', 'in', country_ids)])
return countries
pass
# perform a search to filter on existing / valid tags implicitly
return request.env['res.country'].sudo().search([('id', 'in', list(country_ids))])
def _get_search_sponsorships(self, sponsorship_search):
# TDE FIXME: make me generic (slides, event, ...)
sponsorship_ids = set(request.httprequest.form.getlist('sponsor_type'))
try:
sponsorship_ids = literal_eval(sponsorship_search)
sponsorship_ids.update(literal_eval(sponsorship_search))
except Exception:
sponsorships = request.env['event.sponsor.type'].sudo()
else:
# perform a search to filter on existing / valid tags implicitly
sponsorships = request.env['event.sponsor.type'].sudo().search([('id', 'in', sponsorship_ids)])
return sponsorships
pass
# perform a search to filter on existing / valid tags implicitly
return request.env['event.sponsor.type'].sudo().search([('id', 'in', list(sponsorship_ids))])
@@ -31,7 +31,7 @@ class Sponsor(models.Model):
event_id = fields.Many2one('event.event', 'Event', required=True)
sponsor_type_id = fields.Many2one(
'event.sponsor.type', 'Sponsoring Level',
default=lambda self: self._default_sponsor_type_id(), required=True)
default=lambda self: self._default_sponsor_type_id(), required=True, auto_join=True)
url = fields.Char('Sponsor Website', compute='_compute_url', readonly=False, store=True)
sequence = fields.Integer('Sequence')
active = fields.Boolean(default=True)
@@ -0,0 +1,69 @@
odoo.define('website_event_exhibitor.event_sponsor_search', function (require) {
'use strict';
const publicWidget = require('web.public.widget');
publicWidget.registry.websiteEventSearchSponsor = publicWidget.Widget.extend({
selector: '.o_wesponsor_index',
events: {
'click .o_wevent_event_search_box .btn': '_onSearch',
'click .o_search_tag .btn': '_onTagRemove',
'click .o_dropdown_reset_tags': '_onTagReset',
'change .o_wevent_event_tags_form input': '_onTagAdd',
},
start: function () {
this.form = this.$el.find('.o_wevent_event_tags_form');
return this._super.apply(this, arguments);
},
_onSearch: function () {
const input = this.$el.find('.o_wevent_event_search_box input');
const params = new URLSearchParams(window.location.search);
params.set('search', input.val());
const url = window.location.pathname + '?' + params.toString();
this.form.attr('action', url);
this.form.submit();
},
_onTagAdd: function () {
this.form.submit();
},
_onTagRemove: function (event) {
const tag = $(event.target).parent();
const data = tag.data();
const selector = 'input[name="' + data.field + '"][value="' + data.value + '"]';
this._updateFormActionURL(data);
this.form.find(selector).prop('checked', false);
this.form.submit();
},
_onTagReset: function (event) {
const dropdown = $(event.target).parent();
dropdown.find('input').prop('checked', false);
this.form.submit();
},
_updateFormActionURL: function (data) {
const mapping = new Map([
['sponsor_country', 'countries'],
['sponsor_type', 'sponsorships']
]);
if (!mapping.has(data.field)) {
return
}
const name = mapping.get(data.field);
const params = new URLSearchParams(window.location.search);
try {
const ids = JSON.parse(params.get(name));
params.set(name, JSON.stringify(ids.filter(id => id !== data.value)));
this.form.attr('action', `${window.location.href.split('?')[0]}?${params.toString()}`);
} catch (e) {
return;
}
},
});
return publicWidget.registry.websiteEventSearchSponsor;
});
@@ -9,6 +9,10 @@
opacity: 0.8;
}
.o_wesponsor_topbar_filters .dropdown-item {
cursor: pointer;
}
/*
* MAIN PAGE: LIST
*/
@@ -30,17 +30,18 @@
<!-- TOPBAR: BASE NAVIGATION -->
<!-- Main topbar -->
<template id="exhibitors_topbar"
name="Exhibitor Tools">
<template id="exhibitors_topbar" name="Exhibitor Tools">
<nav class="navbar navbar-light border-top shadow-sm d-print-none">
<div class="container">
<div class="d-flex flex-column flex-sm-row justify-content-between w-100">
<ul class="o_wesponsor_topbar_filters o_wevent_index_topbar_filters nav"/>
<div class="d-flex align-items-center flex-wrap pl-sm-3 pr-0">
<t t-call="website_event.events_search_box">
<t t-set="_searches" t-value="searches"/>
<t t-set="action" t-value="'/event/%s/exhibitors' % (slug(event))"/>
<t t-set="_placeholder" t-value="'Search an exhibitor ...'"/>
<form class="o_wevent_event_tags_form" action="#" method="POST">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<ul class="o_wesponsor_topbar_filters o_wevent_index_topbar_filters nav"/>
</form>
<div class="o_wevent_event_search_box d-flex align-items-center flex-wrap pl-sm-3 pr-0">
<t t-call="website_event_exhibitor.exhibitor_search_box">
<t t-set="search" t-value="search_key" />
<t t-set="placeholder" t-value="'Search an exhibitor ...'"/>
</t>
</div>
</div>
@@ -61,18 +62,16 @@
By Country
</a>
<div class="dropdown-menu">
<a t-att-href="'/event/%s/exhibitors?%s' % (slug(event), keep_query('*', countries=''))"
t-attf-class="dropdown-item d-flex align-items-center justify-content-between #{'active' if not search_countries else ''}">
<a class="dropdown-item o_dropdown_reset_tags">
All Countries
</a>
<t t-foreach="sponsor_countries" t-as="sponsor_country">
<a t-att-href="'/event/%s/exhibitors?%s' % (
slug(event),
keep_query('*', countries=str((search_countries - sponsor_country).ids if sponsor_country in search_countries else (sponsor_country | search_countries).ids))
)"
t-attf-class="dropdown-item d-flex align-items-center justify-content-between #{'active' if sponsor_country in search_countries else ''}">
<label t-attf-class="dropdown-item {{ 'active' if sponsor_country.id in search_countries.ids else '' }}">
<input class="d-none" type="checkbox" name="sponsor_country" multiple="multiple"
t-att-value="sponsor_country.id"
t-att-checked="'checked' if sponsor_country.id in search_countries.ids else None"/>
<t t-esc="sponsor_country.name"/>
</a>
</label>
</t>
</div>
</li>
@@ -92,24 +91,29 @@
By Level
</a>
<div class="dropdown-menu">
<a t-att-href="'/event/%s/exhibitors?%s' % (slug(event), keep_query('*', sponsorships=''))"
t-attf-class="dropdown-item d-flex align-items-center justify-content-between #{'active' if not search_sponsorships else ''}">
<a class="dropdown-item o_dropdown_reset_tags">
All Levels
</a>
<t t-foreach="sponsor_types" t-as="sponsor_type">
<a t-att-href="'/event/%s/exhibitors?%s' % (
slug(event),
keep_query('*', sponsorships=str((search_sponsorships - sponsor_type).ids if sponsor_type in search_sponsorships else (sponsor_type | search_sponsorships).ids))
)"
t-attf-class="dropdown-item d-flex align-items-center justify-content-between #{'active' if sponsor_type in search_sponsorships else ''}">
<label t-attf-class="dropdown-item {{ 'active' if sponsor_type.id in search_sponsorships.ids else '' }}">
<input class="d-none" type="checkbox" name="sponsor_type" multiple="multiple"
t-att-value="sponsor_type.id"
t-att-checked="'checked' if sponsor_type.id in search_sponsorships.ids else None"/>
<t t-esc="sponsor_type.name"/>
</a>
</label>
</t>
</div>
</li>
</xpath>
</template>
<!-- Search Box -->
<template id="exhibitor_search_box" inherit_id="website.website_search_box" primary="True" name="Exhibitors: Search Box">
<xpath expr="//button" position="attributes">
<attribute name="type">button</attribute>
</xpath>
</template>
<!-- ============================================================ -->
<!-- CONTENT: MAIN TEMPLATES -->
<!-- ============================================================ -->
@@ -222,26 +226,29 @@
<template id="exhibitors_search" name="Exhibitors: search terms">
<div class="d-flex align-items-center mb-3">
<t t-foreach="search_countries" t-as="country">
<span class="align-items-baseline border d-inline-flex pl-2 mt-3 rounded ml16 mb-2 bg-white">
<i class="fa fa-tag mr-2 text-muted"/>
<t t-esc="country.display_name"/>
<a t-att-href="'/event/%s/exhibitors?%s' % (
slug(event),
keep_query('*', countries=str((search_countries - country).ids)))"
class="btn border-0 py-1">&#215;</a>
</span>
<t t-call="website_event_exhibitor.exhibitors_search_tag">
<t t-set="value" t-value="country.id"/>
<t t-set="field" t-value="'sponsor_country'"/>
<t t-set="label" t-value="country.display_name"/>
</t>
</t>
<t t-foreach="search_sponsorships" t-as="sponsorship">
<span class="align-items-baseline border d-inline-flex pl-2 mt-3 rounded ml16 mb-2 bg-white">
<i class="fa fa-tag mr-2 text-muted"/>
<t t-esc="sponsorship.display_name"/>
<a t-att-href="'/event/%s/exhibitors?%s' % (
slug(event),
keep_query('*', sponsorships=str((search_sponsorships - sponsorship).ids)))"
class="btn border-0 py-1">&#215;</a>
</span>
<t t-call="website_event_exhibitor.exhibitors_search_tag">
<t t-set="value" t-value="sponsorship.id"/>
<t t-set="field" t-value="'sponsor_type'"/>
<t t-set="label" t-value="sponsorship.display_name"/>
</t>
</t>
</div>
</template>
<template id="exhibitors_search_tag" name="Exhibitors: term">
<span t-att-data-field="field" t-att-data-value="value"
class="o_search_tag align-items-baseline border d-inline-flex pl-2 mt-3 rounded ml16 mb-2 bg-white">
<i class="fa fa-tag mr-2 text-muted"/>
<t t-esc="label"/>
<span class="btn border-0 py-1">&#215;</span>
</span>
</template>
</odoo>