[IMP] website_slides: refactor slide.slide embed detection
This commit slightly changes the embed detection for slides. Currently, we use the same URL to embed slide content within the e-learning module and when the end-user wants to embed that content on an external website. However, we want to know whether the slide is embedded externally or not to show different controls and update some statistics. The code previously relied on the presence of the "referer" header to achieve that detection, if the referer URL comes from a domain that is not this Odoo website -> then it's embedded externally. The issue with that strategy is that it's not very reliable, indeed some modern browsers now completely avoid passing the referer header (mostly for security and privacy reasons). Instead, we change this to let users embed on external websites with a *different* URL. When the embed comes from '/embed_external/', we now easily know that it comes from an external embed and don't have to do some further and potentially tricky processing. We introduced a computed 'embed_code_external' field that is computed the same way as the embed_code except for that small route distinction. This also easily solves any issue that could come with multi-website / different root URLs etc. Task-2654009 Part-of: odoo/odoo#77736
This commit is contained in:
@@ -1133,22 +1133,36 @@ class WebsiteSlides(WebsiteProfile):
|
||||
|
||||
@http.route('/slides/embed/<int:slide_id>', type='http', auth='public', website=True, sitemap=False)
|
||||
def slides_embed(self, slide_id, page="1", **kw):
|
||||
# Note : don't use the 'model' in the route (use 'slide_id'), otherwise if public cannot access the embedded
|
||||
# slide, the error will be the website.403 page instead of the one of the website_slides.embed_slide.
|
||||
# Do not forget the rendering here will be displayed in the embedded iframe
|
||||
return self._slide_embed(slide_id, page=page, is_external_embed=False, **kw)
|
||||
|
||||
@http.route('/slides/embed_external/<int:slide_id>', type='http', auth='public', website=True, sitemap=False)
|
||||
def slides_embed_external(self, slide_id, page="1", **kw):
|
||||
return self._slide_embed(slide_id, page=page, is_external_embed=True, **kw)
|
||||
|
||||
def _slide_embed(self, slide_id, page="1", is_external_embed=False, **kw):
|
||||
""" Note : don't use the 'model' in the route (use 'slide_id'), otherwise if public cannot
|
||||
access the embedded slide, the error will be the website.403 page instead of the one of the
|
||||
website_slides.embed_slide.
|
||||
|
||||
Do not forget the rendering here will be displayed in the embedded iframe
|
||||
|
||||
Try accessing slide, and display to corresponding template.
|
||||
|
||||
When the content is embedded *externally*, meaning on a third party website, we do some
|
||||
additional steps like displaying sharing controls and also updating some KPIs. """
|
||||
|
||||
# try accessing slide, and display to corresponding template
|
||||
try:
|
||||
slide = request.env['slide.slide'].browse(slide_id)
|
||||
# determine if it is embedded from external web page
|
||||
referrer_url = request.httprequest.headers.get('Referer', '')
|
||||
base_url = slide.get_base_url()
|
||||
is_embedded = referrer_url and not bool(base_url in referrer_url) or False
|
||||
if is_embedded:
|
||||
request.env['slide.embed'].sudo()._add_embed_url(slide.id, referrer_url)
|
||||
referer_url = request.httprequest.headers.get('Referer', '')
|
||||
if is_external_embed and referer_url:
|
||||
request.env['slide.embed'].sudo()._add_embed_url(
|
||||
slide.id,
|
||||
referer_url
|
||||
)
|
||||
|
||||
values = self._get_slide_detail(slide)
|
||||
values['page'] = page
|
||||
values['is_embedded'] = is_embedded
|
||||
values['is_external_embed'] = is_external_embed
|
||||
self._set_viewed_slide(slide)
|
||||
return request.render('website_slides.embed_slide', values)
|
||||
except AccessError: # TODO : please, make it clean one day, or find another secure way to detect
|
||||
|
||||
@@ -10,6 +10,7 @@ import PyPDF2
|
||||
import json
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from markupsafe import Markup
|
||||
from PIL import Image
|
||||
from werkzeug import urls
|
||||
|
||||
@@ -165,6 +166,8 @@ class Slide(models.Model):
|
||||
dislikes = fields.Integer('Dislikes', compute='_compute_user_info', store=True, compute_sudo=False)
|
||||
user_vote = fields.Integer('User vote', compute='_compute_user_info', compute_sudo=False)
|
||||
embed_code = fields.Html('Embed Code', readonly=True, compute='_compute_embed_code', sanitize=False)
|
||||
embed_code_external = fields.Html('External Embed Code', readonly=True, compute='_compute_embed_code', sanitize=False,
|
||||
help="Same as 'Embed Code' but used to embed the content on an external website.")
|
||||
# views
|
||||
embedcount_ids = fields.One2many('slide.embed', 'slide_id', string="Embed Count")
|
||||
slide_views = fields.Integer('# of Website Views', store=True, compute="_compute_slide_views")
|
||||
@@ -320,26 +323,34 @@ class Slide(models.Model):
|
||||
@api.depends('document_id', 'slide_type', 'mime_type')
|
||||
def _compute_embed_code(self):
|
||||
base_url = request and request.httprequest.url_root
|
||||
|
||||
for record in self:
|
||||
embed_code_external = False
|
||||
|
||||
if not base_url:
|
||||
base_url = record.get_base_url()
|
||||
if base_url[-1] == '/':
|
||||
base_url = base_url[:-1]
|
||||
if record.datas and (not record.document_id or record.slide_type in ['document', 'presentation']):
|
||||
slide_url = base_url + url_for('/slides/embed/%s?page=1' % record.id)
|
||||
record.embed_code = '<iframe src="%s" class="o_wslides_iframe_viewer" allowFullScreen="true" height="%s" width="%s" frameborder="0"></iframe>' % (slide_url, 315, 420)
|
||||
slide_url_external = base_url + url_for('/slides/embed_external/%s?page=1' % record.id)
|
||||
base_embed_code = Markup('<iframe src="%s" class="o_wslides_iframe_viewer" allowFullScreen="true" height="%s" width="%s" frameborder="0"></iframe>')
|
||||
record.embed_code = base_embed_code % (slide_url, 315, 420)
|
||||
embed_code_external = base_embed_code % (slide_url_external, 315, 420)
|
||||
elif record.slide_type == 'video' and record.document_id:
|
||||
if not record.mime_type:
|
||||
# embed youtube video
|
||||
query = urls.url_parse(record.url).query
|
||||
query = query + '&theme=light' if query else 'theme=light'
|
||||
record.embed_code = '<iframe src="//www.youtube-nocookie.com/embed/%s?%s" allowFullScreen="true" frameborder="0"></iframe>' % (record.document_id, query)
|
||||
record.embed_code = Markup('<iframe src="//www.youtube-nocookie.com/embed/%s?%s" allowFullScreen="true" frameborder="0"></iframe>') % (record.document_id, query)
|
||||
else:
|
||||
# embed google doc video
|
||||
record.embed_code = '<iframe src="//drive.google.com/file/d/%s/preview" allowFullScreen="true" frameborder="0"></iframe>' % (record.document_id)
|
||||
record.embed_code = Markup('<iframe src="//drive.google.com/file/d/%s/preview" allowFullScreen="true" frameborder="0"></iframe>') % (record.document_id)
|
||||
else:
|
||||
record.embed_code = False
|
||||
|
||||
record.embed_code_external = embed_code_external or record.embed_code
|
||||
|
||||
@api.onchange('url')
|
||||
def _on_change_url(self):
|
||||
self.ensure_one()
|
||||
|
||||
@@ -552,7 +552,10 @@
|
||||
<div class="oe_slide_js_embed_code_widget mt-4">
|
||||
<h5 class="mt0">Embed in your website</h5>
|
||||
<div class="form-group">
|
||||
<textarea class="form-control slide_embed_code" readonly="readonly" onClick="this.select();"><t t-esc="slide.embed_code"/></textarea>
|
||||
<textarea class="form-control slide_embed_code" readonly="readonly" onClick="this.select();">
|
||||
<!-- Use the external embedding URL here, see python controller '_slide_embed' method for more details. -->
|
||||
<t t-esc="slide.embed_code_external"/>
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="form-group d-flex" t-if="slide.slide_type in ('presentation', 'document')">
|
||||
<div class="form-text p-0 col-xs-5 col-sm-5 col-md-5 col-lg-5">Select page to start with</div>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<body>
|
||||
<div id="PDFViewer" class="o_wslides_fs_pdf_viewer d-flex flex-column h-100">
|
||||
<!-- PDF Viewer Header : contains the name, and the share links -->
|
||||
<div t-if="is_embedded" class="oe_slides_share_bar">
|
||||
<div t-if="is_external_embed" class="oe_slides_share_bar">
|
||||
<div class="container-fluid">
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
@@ -41,7 +41,7 @@
|
||||
t-attf-data-slideurl="/slides/slide/#{slug(slide)}/pdf_content"
|
||||
t-attf-data-downloadable="#{False}"
|
||||
t-att-data-defaultpage="page">
|
||||
<t t-if="is_embedded">
|
||||
<t t-if="is_external_embed">
|
||||
<div id="slide_share" class="oe_slide_embed_option" style="display: none;">
|
||||
<t t-call="website_slides.slide_share_modal">
|
||||
<t t-set="record" t-value="slide"/>
|
||||
|
||||
Reference in New Issue
Block a user