[REF] website_slides: remove promoted slide feature, add image and channel_type
Purpose of this commit is to clean a bit channel model. Promoted slide
feature is removed as people can already choose an order for a given
channel. Moreover promoted slide will not be used when having a eLearning
display of a channel.
Image field on channels is added as it is not depending on promoted slide
anymore.
To simplify future additions a search-specific template is removed to
have a unique template to display a channel content. It will ease future
merge.
This commit is linked to task ID 1936153 and PR #30985.
This commit is contained in:
@@ -148,6 +148,7 @@ class WebsiteSlides(http.Controller):
|
||||
'tag': tag,
|
||||
'slide_type': slide_type,
|
||||
'sorting': sorting,
|
||||
'search': search,
|
||||
'user': user,
|
||||
'pager': pager,
|
||||
'is_public_user': request.website.is_public_user(),
|
||||
@@ -164,9 +165,6 @@ class WebsiteSlides(http.Controller):
|
||||
'last_message': html2plaintext(last_message_data.get('body', '')),
|
||||
'last_rating_value': last_message_data.get('rating_value'),
|
||||
})
|
||||
if search:
|
||||
values['search'] = search
|
||||
return request.render('website_slides.slides_search', values)
|
||||
|
||||
# Display uncategorized slides
|
||||
if not slide_type and not category:
|
||||
@@ -221,11 +219,6 @@ class WebsiteSlides(http.Controller):
|
||||
return request.redirect('/web/login?redirect=/slides/slide/%s' % (slide.id))
|
||||
return request.render("website.403")
|
||||
|
||||
@http.route('''/slides/slide/<model("slide.slide"):slide>/promote''', type='http', auth='user', website=True)
|
||||
def slide_set_promoted(self, slide, **kwargs):
|
||||
slide.channel_id.promoted_slide_id = slide.id
|
||||
return request.redirect("/slides/%s" % slide.channel_id.id)
|
||||
|
||||
# JSONRPC
|
||||
@http.route('/slides/slide/like', type='json', auth="user", website=True)
|
||||
def slide_like(self, slide_id, upvote):
|
||||
|
||||
@@ -256,7 +256,6 @@ Discover Odoo Inventory: https://www.odoo.com/page/warehouse</field>
|
||||
|
||||
<record model="slide.channel" id="channel_public">
|
||||
<field name="promote_strategy">custom</field>
|
||||
<field name="custom_slide_id" ref="slide_0"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import math
|
||||
import uuid
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo import api, fields, models, tools, _
|
||||
from odoo.addons.http_routing.models.ir_http import slug
|
||||
from odoo.tools.translate import html_translate
|
||||
from odoo.osv import expression
|
||||
@@ -48,9 +48,7 @@ class ChannelUsersRelation(models.Model):
|
||||
|
||||
|
||||
class Channel(models.Model):
|
||||
""" A channel is a container of slides. It has group-based access configuration
|
||||
allowing to configure slide upload and access. Slides can be promoted in
|
||||
channels. """
|
||||
""" A channel is a container of slides. """
|
||||
_name = 'slide.channel'
|
||||
_description = 'Slide Channel'
|
||||
_inherit = ['mail.thread', 'website.seo.metadata', 'website.published.multi.mixin', 'rating.mixin']
|
||||
@@ -63,11 +61,17 @@ class Channel(models.Model):
|
||||
name = fields.Char('Name', translate=True, required=True)
|
||||
active = fields.Boolean(default=True)
|
||||
description = fields.Html('Description', translate=html_translate, sanitize_attributes=False)
|
||||
channel_type = fields.Selection([
|
||||
('documentation', 'Documentation'), ('training', 'Training')],
|
||||
string="Course type", default="documentation", required=True)
|
||||
sequence = fields.Integer(default=10, help='Display order')
|
||||
tag_ids = fields.Many2many(
|
||||
'slide.channel.tag', 'slide_channel_tag_rel', 'channel_id', 'tag_id',
|
||||
string='Tags', help='Used to categorize and filter displayed channels/courses')
|
||||
category_ids = fields.One2many('slide.category', 'channel_id', string="Categories")
|
||||
image = fields.Binary("Image", attachment=True)
|
||||
image_medium = fields.Binary("Medium image", attachment=True)
|
||||
image_small = fields.Binary("Small image", attachment=True)
|
||||
# slides: promote, statistics
|
||||
slide_ids = fields.One2many('slide.slide', 'channel_id', string="Slides")
|
||||
slide_partner_ids = fields.One2many('slide.slide.partner', 'channel_id', string="Slide User Data", groups='website.group_website_publisher')
|
||||
@@ -78,8 +82,7 @@ class Channel(models.Model):
|
||||
('most_viewed', 'Most Viewed'),
|
||||
('custom', 'Featured Presentation')],
|
||||
string="Featuring Policy", default='most_voted', required=True)
|
||||
custom_slide_id = fields.Many2one('slide.slide', string='Slide to Promote')
|
||||
promoted_slide_id = fields.Many2one('slide.slide', string='Featured Slide', compute='_compute_promoted_slide_id', store=True)
|
||||
|
||||
access_token = fields.Char("Security Token", copy=False, default=_default_access_token)
|
||||
nbr_presentations = fields.Integer('Number of Presentations', compute='_compute_slides_statistics', store=True)
|
||||
nbr_documents = fields.Integer('Number of Documents', compute='_compute_slides_statistics', store=True)
|
||||
@@ -119,20 +122,6 @@ class Channel(models.Model):
|
||||
can_upload = fields.Boolean('Can Upload', compute='_compute_access')
|
||||
can_publish = fields.Boolean('Can Publish', compute='_compute_access')
|
||||
|
||||
@api.depends('custom_slide_id', 'promote_strategy', 'slide_ids.likes',
|
||||
'slide_ids.total_views', "slide_ids.date_published")
|
||||
def _compute_promoted_slide_id(self):
|
||||
for record in self:
|
||||
if record.promote_strategy == 'none':
|
||||
record.promoted_slide_id = False
|
||||
elif record.promote_strategy == 'custom':
|
||||
record.promoted_slide_id = record.custom_slide_id
|
||||
elif record.promote_strategy:
|
||||
slides = self.env['slide.slide'].search(
|
||||
[('website_published', '=', True), ('channel_id', '=', record.id)],
|
||||
limit=1, order=self.env['slide.slide']._order_by_strategy[record.promote_strategy])
|
||||
record.promoted_slide_id = slides and slides[0] or False
|
||||
|
||||
@api.depends('channel_partner_ids.partner_id')
|
||||
@api.model
|
||||
def _compute_is_member(self):
|
||||
@@ -227,10 +216,14 @@ class Channel(models.Model):
|
||||
vals['channel_partner_ids'] = [(0, 0, {
|
||||
'partner_id': self.env.user.partner_id.id
|
||||
})]
|
||||
if 'image' in vals:
|
||||
tools.image_resize_images(vals)
|
||||
return super(Channel, self.with_context(mail_create_nosubscribe=True)).create(vals)
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
if 'image' in vals:
|
||||
tools.image_resize_images(vals)
|
||||
res = super(Channel, self).write(vals)
|
||||
if 'active' in vals:
|
||||
# archiving/unarchiving a channel does it on its slides, too
|
||||
|
||||
@@ -259,9 +259,7 @@ class Slide(models.Model):
|
||||
doc_data = self._parse_document_url(values['url']).get('values', dict())
|
||||
for key, value in doc_data.items():
|
||||
values.setdefault(key, value)
|
||||
if values.get('channel_id'):
|
||||
custom_channels = self.env['slide.channel'].search([('custom_slide_id', '=', self.id), ('id', '!=', values.get('channel_id'))])
|
||||
custom_channels.write({'custom_slide_id': False})
|
||||
|
||||
res = super(Slide, self).write(values)
|
||||
if values.get('website_published'):
|
||||
self.date_published = datetime.datetime.now()
|
||||
|
||||
@@ -57,42 +57,40 @@
|
||||
<field name="active" widget="boolean_button" options='{"terminology": "archive"}'/>
|
||||
</button>
|
||||
</div>
|
||||
<field name="image" widget="image" class="oe_avatar" options="{'preview_image': 'image_medium'}"/>
|
||||
<div class="oe_title">
|
||||
<div class="oe_edit_only">
|
||||
<label for="name" string="Name"/>
|
||||
</div>
|
||||
<h1>
|
||||
<field name="name" default_focus="1" placeholder="Name"/>
|
||||
</h1>
|
||||
<label for="name" class="oe_edit_only" string="Name"/>
|
||||
<h1><field name="name" default_focus="1" placeholder="Name"/></h1>
|
||||
</div>
|
||||
<field name="category_ids" widget="many2many_tags" placeholder="Categories" context="{'default_channel_id': active_id}"
|
||||
domain="[('channel_id','=', active_id)]"/>
|
||||
<field name="tag_ids" widget="many2many_tags" placeholder="Tags"/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="visibility" string="Enroll" widget="radio"/>
|
||||
<field name="category_ids" widget="many2many_tags" placeholder="Categories"
|
||||
context="{'default_channel_id': active_id}"
|
||||
domain="[('channel_id','=', active_id)]"/>
|
||||
<field name="tag_ids" widget="many2many_tags" placeholder="Tags"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="General">
|
||||
<page string="Description">
|
||||
<field name="description" colspan="4" nolabel="1"/>
|
||||
</page>
|
||||
<page string="Options">
|
||||
<group>
|
||||
<group>
|
||||
<field name="channel_type"/>
|
||||
<field name="website_id" options="{'no_create': True}" groups="website.group_multi_website"/>
|
||||
<field name="promote_strategy" widget="radio"/>
|
||||
<field name="custom_slide_id" class="oe_edit_only" attrs="{'invisible': [('promote_strategy', '!=', 'custom')]}" domain="[('channel_id','=',id), ('website_published','=',True)]"/>
|
||||
<field name="promoted_slide_id" attrs="{'invisible': [('promote_strategy', '!=', 'custom')]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="upload_group_ids" widget="many2many_tags"/>
|
||||
<field name="publish_template_id" domain="[('model','=','slide.slide')]"/>
|
||||
<field name="share_template_id" domain="[('model','=','slide.slide')]"/>
|
||||
</group>
|
||||
</group>
|
||||
<label for="description"/>
|
||||
<field name="description" colspan="4" nolabel="1"/>
|
||||
</page>
|
||||
<page string="Security">
|
||||
<group>
|
||||
<field name="upload_group_ids" widget="many2many_tags"/>
|
||||
<field name="visibility" string="Channel visibility" widget="radio"/>
|
||||
</group>
|
||||
<group colspan="4">
|
||||
<label for="enroll_msg"/>
|
||||
<field name="enroll_msg" colspan="4" nolabel="1"/>
|
||||
<label for="enroll_msg"/>
|
||||
<field name="enroll_msg" colspan="4" nolabel="1"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Statistics" groups="base.group_no_one">
|
||||
|
||||
@@ -39,8 +39,12 @@
|
||||
<div class="card card-body">
|
||||
<div>
|
||||
<a t-attf-href="/slides/#{slug(channel)}">
|
||||
<img t-if="channel.promoted_slide_id" t-attf-src="/web/image/slide.slide/#{channel.promoted_slide_id.id}/image_medium" class="img-fluid oe_slides_channel_thumbnail" alt="Promoted slide"/>
|
||||
<img t-if="not channel.promoted_slide_id" src="/website_slides/static/src/img/channel-default.jpg" class="img-fluid oe_slides_opacity" alt="Channel without promoted slide"/>
|
||||
<img t-if="channel.image" t-attf-src="/web/image/slide.channel/#{channel.id}/image_medium"
|
||||
class="img-fluid oe_slides_channel_thumbnail"
|
||||
t-att-alt="channel.name"/>
|
||||
<img t-if="not channel.image" src="/website_slides/static/src/img/channel-default.jpg"
|
||||
class="img-fluid oe_slides_opacity"
|
||||
t-att-alt="channel.name"/>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
@@ -219,7 +223,7 @@
|
||||
<t t-set="header_object" t-value="category"/>
|
||||
</t>
|
||||
</t>
|
||||
<section t-if="not channel.promoted_slide_id and not tag and not slide_type and not search and not is_public_user and not category" class="wrap mt16 mb0" groups="website.group_website_designer">
|
||||
<section t-if="not tag and not slide_type and not search and not is_public_user and not category" class="wrap mt16 mb0" groups="website.group_website_designer">
|
||||
<div class="container">
|
||||
<div class="alert alert-danger alert-dismissable mb0" role="alert">
|
||||
<p>
|
||||
@@ -231,26 +235,26 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="oe_slides_promote_box" t-if="channel.promoted_slide_id and not tag and not slide_type and not search and not category">
|
||||
<section class="oe_slides_promote_box" t-if="channel.slide_ids and not tag and not slide_type and not search and not category">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-5 mt16 mb16">
|
||||
<a t-attf-href="/slides/slide/#{slug(channel.promoted_slide_id)}">
|
||||
<img t-attf-src="/web/image/slide.slide/#{channel.promoted_slide_id.id}/image_medium" class="img-fluid shadow oe_slides_promote_image" alt="Promoted slide"/>
|
||||
<a t-attf-href="/slides/slide/#{slug(channel.slide_ids[0])}">
|
||||
<img t-attf-src="/web/image/slide.slide/#{channel.slide_ids[0].id}/image_medium" class="img-fluid shadow oe_slides_promote_image" alt="Promoted slide"/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-lg-7 mt16 mb16">
|
||||
<h3 class="row">
|
||||
<a t-attf-href="/slides/slide/#{slug(channel.promoted_slide_id)}">
|
||||
<t t-esc="channel.promoted_slide_id.name"/>
|
||||
<a t-attf-href="/slides/slide/#{slug(channel.slide_ids[0])}">
|
||||
<t t-esc="channel.slide_ids[0].name"/>
|
||||
</a>
|
||||
</h3>
|
||||
<div class="row mt8 mb8" t-if="channel.promoted_slide_id.tag_ids">
|
||||
<t t-foreach="channel.promoted_slide_id.tag_ids" t-as="slide_tag">
|
||||
<div class="row mt8 mb8" t-if="channel.slide_ids[0].tag_ids">
|
||||
<t t-foreach="channel.slide_ids[0].tag_ids" t-as="slide_tag">
|
||||
<a t-attf-href="/slides/#{slug(channel)}/tag/#{slug(slide_tag)}" t-attf-class="badge badge-secondary #{tag and tag.id == slide_tag.id and 'badge-primary' ''}" t-field="slide_tag.name"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="row oe_no_empty" t-esc="channel.promoted_slide_id.description"/>
|
||||
<div class="row oe_no_empty" t-esc="channel.slide_ids[0].description"/>
|
||||
<p class="row mt8">
|
||||
<t t-call="website_rating.rating_stars_static_popup_composer">
|
||||
<t t-set="rating_avg" t-value="rating_avg"/>
|
||||
@@ -267,7 +271,7 @@
|
||||
<p class="row mt8">
|
||||
<b>Share:</b>
|
||||
<t t-call="website_slides.slides_share">
|
||||
<t t-set="slide" t-value="channel.promoted_slide_id"/>
|
||||
<t t-set="slide" t-value="channel.slide_ids[0]"/>
|
||||
</t>
|
||||
</p>
|
||||
</div>
|
||||
@@ -291,6 +295,11 @@
|
||||
<section>
|
||||
<div class="container mt16">
|
||||
<div class="row">
|
||||
<div class="col-12" t-if="search and not slides">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
Sorry, but nothing matches your search criteria <b><t t-esc="search"/></b>. Please try again with different keywords.
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-12 col-lg-12 col-md-12 col-12" style="padding-left: 15px;padding-right: 15px;" t-if="channel.total_slides == 0">
|
||||
<div class="jumbotron">
|
||||
<h1>No presentation published yet.</h1>
|
||||
@@ -334,8 +343,13 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<t t-call="website_slides.slides_grid_view">
|
||||
<t t-set="slides" t-value="category['slides']"/>
|
||||
<t t-if="not search">
|
||||
<t t-call="website_slides.slides_grid_view">
|
||||
<t t-set="slides" t-value="category['slides']"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="website_slides.slides_grid_view"/>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
@@ -346,34 +360,6 @@
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- Channels: search result -->
|
||||
<template id='slides_search' name="Searching Slides">
|
||||
<t t-call="website.layout">
|
||||
<div class="wrap">
|
||||
<t t-set="main_object" t-value="channel"/>
|
||||
<t t-call="website_slides.slides_channel_header"/>
|
||||
<section>
|
||||
<div class="container mt16" t-if="not slides">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
Sorry, but nothing matches your search criteria <b><t t-esc="search"/></b>. Please try again with different keywords.
|
||||
</div>
|
||||
</div>
|
||||
<div class="container mt16" t-if="slides">
|
||||
<div class="alert alert-success mb0" role="status">
|
||||
<b t-esc="len(slides)"/> results found for the given criteria <b><t t-esc="search"/></b>
|
||||
</div>
|
||||
<div class="row mt0">
|
||||
<t t-call="website_slides.slides_grid_view"/>
|
||||
</div>
|
||||
<div class="row text-center">
|
||||
<t t-call="website.pager"/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- Embedded template: display a list of slides in a grid view -->
|
||||
<template id='slides_grid_view' name="Slides (Grid View)">
|
||||
<div class="row">
|
||||
@@ -383,17 +369,6 @@
|
||||
<img t-attf-src="/web/image/slide.slide/#{slide.id}/image_thumb" class="img-fluid img-thumbnail oe_slides_grid_thumbnail" alt="slide.name"/>
|
||||
</a>
|
||||
<span t-if="not slide.website_published" class="badge badge-danger" style="position: absolute;right: 20px;top: 7px;">Unpublished</span>
|
||||
<a t-if="not is_public_user and slide.website_published and slide.channel_id.promote_strategy == 'custom' and slide.channel_id.promoted_slide_id.id != slide.id"
|
||||
groups="website.group_website_publisher"
|
||||
t-attf-href="/slides/slide/#{slide.id}/promote"
|
||||
style="position: absolute;right: 20px;top: 7px;"
|
||||
t-attf-title="Promote this #{slide.slide_type}"
|
||||
t-attf-aria-label="Promote this #{slide.slide_type}">
|
||||
<span class="fa-stack fa-lg">
|
||||
<i class="fa fa-square fa-stack-2x oe_slides_opacity"></i>
|
||||
<i class="fa fa-bullhorn fa-stack-1x fa-inverse"></i>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<div style="padding: 5px;">
|
||||
<h4 class="mt4 mb8 oe_slides_ellipsis">
|
||||
|
||||
Reference in New Issue
Block a user