[FIX] website_profile, website_slides: clean user avatar controller and add one for slides
Purpose of this commit is to * clean user avatar controller and its calls; * extract default image computation; * add a controller to get slide image even when not having access to the slide as all slide name and images are displayed even if not available to the current user; Commit linked to task ID 1941250 and PR #31133.
This commit is contained in:
@@ -10,7 +10,6 @@ import werkzeug.wrappers
|
||||
from odoo import http, modules, tools
|
||||
from odoo.http import request
|
||||
from odoo.osv import expression
|
||||
from odoo.tools import limited_image_resize
|
||||
|
||||
|
||||
class WebsiteProfile(http.Controller):
|
||||
@@ -30,6 +29,20 @@ class WebsiteProfile(http.Controller):
|
||||
return user.website_published and user.karma > 0
|
||||
return False
|
||||
|
||||
def _get_default_avatar(self, field, headers, width, height):
|
||||
img_path = modules.get_module_resource('web', 'static/src/img', 'placeholder.png')
|
||||
with open(img_path, 'rb') as f:
|
||||
image = f.read()
|
||||
content = base64.b64encode(image)
|
||||
dictheaders = dict(headers) if headers else {}
|
||||
dictheaders['Content-Type'] = 'image/png'
|
||||
headers = list(dictheaders.items())
|
||||
if not (width or height):
|
||||
suffix = field.split('_')[-1] if '_' in field else 'large'
|
||||
if suffix in ('small', 'medium', 'large', 'big'):
|
||||
content = getattr(tools, 'image_resize_image_%s' % suffix)(content)
|
||||
return content
|
||||
|
||||
def _check_user_profile_access(self, user_id):
|
||||
user_sudo = request.env['res.users'].sudo().browse(user_id)
|
||||
if user_sudo.karma == 0 or not user_sudo.website_published or \
|
||||
@@ -60,16 +73,18 @@ class WebsiteProfile(http.Controller):
|
||||
@http.route([
|
||||
'/profile/avatar/<int:user_id>',
|
||||
], type='http', auth="public", website=True, sitemap=False)
|
||||
def get_user_profile_avatar(self, user_id=0, width=0, height=0, crop=False, avoid_if_small=False, upper_limit=False, **post):
|
||||
def get_user_profile_avatar(self, user_id, field='image_large', width=0, height=0, crop=False, avoid_if_small=False, upper_limit=False, **post):
|
||||
if field not in ('image_small', 'image_medium', 'image_large'):
|
||||
return werkzeug.exceptions.Forbidden()
|
||||
|
||||
can_sudo = self._check_avatar_access(user_id, **post)
|
||||
fname = post.get('field', 'image_medium')
|
||||
if can_sudo:
|
||||
status, headers, content = request.env['ir.http'].sudo().binary_content(
|
||||
model='res.users', id=user_id, field=fname,
|
||||
model='res.users', id=user_id, field=field,
|
||||
default_mimetype='image/png')
|
||||
else:
|
||||
status, headers, content = request.env['ir.http'].binary_content(
|
||||
model='res.users', id=user_id, field=fname,
|
||||
model='res.users', id=user_id, field=field,
|
||||
default_mimetype='image/png')
|
||||
if status == 301:
|
||||
return request.env['ir.http']._response_by_status(status, headers, content)
|
||||
@@ -77,19 +92,9 @@ class WebsiteProfile(http.Controller):
|
||||
return werkzeug.wrappers.Response(status=304)
|
||||
|
||||
if not content:
|
||||
img_path = modules.get_module_resource('web', 'static/src/img', 'placeholder.png')
|
||||
with open(img_path, 'rb') as f:
|
||||
image = f.read()
|
||||
content = base64.b64encode(image)
|
||||
dictheaders = dict(headers) if headers else {}
|
||||
dictheaders['Content-Type'] = 'image/png'
|
||||
headers = list(dictheaders.items())
|
||||
if not (width or height):
|
||||
suffix = fname.split('_')[-1]
|
||||
if suffix in ('small', 'medium', 'big'):
|
||||
content = getattr(tools, 'image_resize_image_%s' % suffix)(content)
|
||||
content = self._get_default_avatar(field, headers, width, height)
|
||||
|
||||
content = limited_image_resize(
|
||||
content = tools.limited_image_resize(
|
||||
content, width=width, height=height, crop=crop, upper_limit=upper_limit, avoid_if_small=avoid_if_small)
|
||||
|
||||
image_base64 = base64.b64decode(content)
|
||||
@@ -159,6 +164,7 @@ class WebsiteProfile(http.Controller):
|
||||
ranks = ranks.sorted(key=lambda b: b.karma_min)
|
||||
values = {
|
||||
'ranks': ranks,
|
||||
'user': request.env.user,
|
||||
}
|
||||
return request.render("website_profile.rank_main", values)
|
||||
|
||||
|
||||
@@ -299,7 +299,7 @@
|
||||
Ranks & Badges
|
||||
</h1>
|
||||
<p>
|
||||
Do not stop learning with Odoo. Collects points on the forum or the eLearning platform. Those points will make you reach new ranks.
|
||||
Do not stop learning with <t t-esc="user.company_id.name"/>. Collects points on the forum or the eLearning platform. Those points will make you reach new ranks.
|
||||
</p>
|
||||
<p>
|
||||
<b>How do I earn badges?</b> When you finish a course, reach milestones, you're awarded badges.
|
||||
|
||||
@@ -6,7 +6,7 @@ import itertools
|
||||
import logging
|
||||
import werkzeug
|
||||
|
||||
from odoo import http, _
|
||||
from odoo import http, modules, tools, _
|
||||
from odoo.exceptions import AccessError, UserError
|
||||
from odoo.http import request
|
||||
from odoo.osv import expression
|
||||
@@ -14,7 +14,6 @@ from odoo.osv import expression
|
||||
from odoo.addons.http_routing.models.ir_http import slug
|
||||
from odoo.addons.website_profile.controllers.main import WebsiteProfile
|
||||
from odoo.addons.website.models.ir_http import sitemap_qs2dom
|
||||
from odoo.tools import html2plaintext
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -267,7 +266,7 @@ class WebsiteSlides(WebsiteProfile):
|
||||
'message_post_hash': channel._sign_token(request.env.user.partner_id.id),
|
||||
'message_post_pid': request.env.user.partner_id.id,
|
||||
'last_message_id': last_message_data.get('id'),
|
||||
'last_message': html2plaintext(last_message_data.get('body', '')),
|
||||
'last_message': tools.html2plaintext(last_message_data.get('body', '')),
|
||||
'last_rating_value': last_message_data.get('rating_value'),
|
||||
})
|
||||
|
||||
@@ -362,6 +361,36 @@ class WebsiteSlides(WebsiteProfile):
|
||||
return request.redirect('/web/login?redirect=/slides/slide/%s' % (slide.id))
|
||||
return request.render("website.403")
|
||||
|
||||
@http.route('/slides/slide/<int:slide_id>/get_image', type='http', auth="public", website=True, sitemap=False)
|
||||
def slide_get_image(self, slide_id, field='image_medium', width=0, height=0, crop=False, avoid_if_small=False, upper_limit=False):
|
||||
# Protect infographics by limiting access to 256px (large) images
|
||||
if field not in ('image_small', 'image_medium', 'image_large'):
|
||||
return werkzeug.exceptions.Forbidden()
|
||||
|
||||
slide = request.env['slide.slide'].sudo().browse(slide_id).exists()
|
||||
if not slide:
|
||||
raise werkzeug.exceptions.NotFound()
|
||||
|
||||
status, headers, content = request.env['ir.http'].sudo().binary_content(
|
||||
model='slide.slide', id=slide.id, field=field,
|
||||
default_mimetype='image/png')
|
||||
if status == 301:
|
||||
return request.env['ir.http']._response_by_status(status, headers, content)
|
||||
if status == 304:
|
||||
return werkzeug.wrappers.Response(status=304)
|
||||
|
||||
if not content:
|
||||
content = self._get_default_avatar(field, headers, width, height)
|
||||
|
||||
content = tools.limited_image_resize(
|
||||
content, width=width, height=height, crop=crop, upper_limit=upper_limit, avoid_if_small=avoid_if_small)
|
||||
|
||||
image_base64 = base64.b64decode(content)
|
||||
headers.append(('Content-Length', len(image_base64)))
|
||||
response = request.make_response(image_base64, headers)
|
||||
response.status_code = status
|
||||
return response
|
||||
|
||||
# JSONRPC
|
||||
@http.route('/slides/slide/like', type='json', auth="user", website=True)
|
||||
def slide_like(self, slide_id, upvote):
|
||||
|
||||
@@ -268,7 +268,9 @@
|
||||
</div>
|
||||
<div class="row" t-if="slide_promoted">
|
||||
<div class="col-4">
|
||||
<img class="img img-fluid" t-att-src="'/web/image/slide.slide/%s/image' % slide_promoted.id"/>
|
||||
<img class="img img-fluid" style=""
|
||||
t-att-src="'/slides/slide/%s/get_image?field=image_large' % slide_promoted.id"
|
||||
t-att-alt="slide_promoted.name"/>
|
||||
</div>
|
||||
<div class="col-8">
|
||||
<div class="row">
|
||||
@@ -318,10 +320,9 @@
|
||||
<div class="row o_wslides_row mt8">
|
||||
<div class="col-lg-3 col-md-6 col-12" t-foreach="slides" t-as="slide">
|
||||
<div class="card o_wslides_lesson_card">
|
||||
<img class="card-img-top img-fuild"
|
||||
style="max-height: 160px;"
|
||||
t-att-src="'/web/image/slide.slide/%s/image_large' % slide.id if slide.image else '/website_slides/static/src/img/channel-default.jpg'"
|
||||
t-att-alt="channel.name"/>
|
||||
<img class="card-img-top img-fuild" style="max-height: 160px;"
|
||||
t-att-src="'/slides/slide/%s/get_image?field=image_large' % slide.id"
|
||||
t-att-alt="slide.name"/>
|
||||
<div class="card-body">
|
||||
<h5 class="card-title" t-att-title="slide.name">
|
||||
<t t-if="slide.is_preview or channel.is_member or is_slides_publisher">
|
||||
|
||||
@@ -312,7 +312,6 @@
|
||||
<div class="col-2">
|
||||
<t t-call="website_slides.slides_misc_user_image">
|
||||
<t t-set="user" t-value="achievement.user_id"/>
|
||||
<t t-set="record" t-value="channels_popular[:1]"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="col">
|
||||
@@ -353,9 +352,7 @@
|
||||
<span class="font-weight-bold text-muted o_wslides_home_circled" t-esc="counter"/>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<t t-call="website_slides.slides_misc_user_image">
|
||||
<t t-set="record" t-value="channels_popular[:1]"/>
|
||||
</t>
|
||||
<t t-call="website_slides.slides_misc_user_image"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="font-weight-bold" t-esc="user.name"/>
|
||||
@@ -370,9 +367,7 @@
|
||||
<div class="o_wslides_home_aside">
|
||||
<div class="row mt16 o_wslides_home_aside_title align-items-center">
|
||||
<div class="col">
|
||||
<t t-call="website_slides.slides_misc_user_image">
|
||||
<t t-set="record" t-value="channels_popular[:1]"/>
|
||||
</t>
|
||||
<t t-call="website_slides.slides_misc_user_image"/>
|
||||
<a t-att-href="'/slides'" class="float-right">Edit</a>
|
||||
<h4 t-esc="user.name" class="font-weight-bold"/>
|
||||
<hr/>
|
||||
@@ -407,10 +402,10 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id='slides_misc_user_image' name="Float Time">
|
||||
<template id='slides_misc_user_image' name="User Avatar">
|
||||
<img t-att-class="img_class if img_class else 'rounded-circle float-left'"
|
||||
t-att-style="img_style if img_style else 'max-height: 32px;'"
|
||||
t-att-src="'/profile/avatar/%s?field=image_medium%s' % (user.id, '&res_model=%s&res_id=%s' % (record._name, record.id) if record else '')"
|
||||
t-att-src="'/profile/avatar/%s?field=image_medium' % user.id"
|
||||
t-att-alt="user.name"/>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user