[ADD] website_slides: merging slide.slide.link into resource

Purpose
=======
This commit is used to merge 2 models into 1: `slide.slide.resource`
and `slide.slide.link`

Specifications
==============
These models are merged in order to create a unique table for the
*Additional Resources* of a Content.

In order to do that, we merged the models into `slide.slide.resource`
that will contain either a link or a file.

task-2597345

See odoo/enterprise#20480
See odoo/upgrade#2784

Part-of: odoo/odoo#75646
This commit is contained in:
Thomas Josse
2021-10-22 11:09:17 +00:00
parent 255cdfe4f6
commit 63285ce026
11 changed files with 153 additions and 44 deletions
@@ -20,6 +20,7 @@
</record>
<!--RESOURCE-->
<record id="slide_slide_demo_0_0_resource_0" model="slide.slide.resource">
<field name="resource_type">file</field>
<field name="name">Document</field>
<field name="data" type="base64" file="website_slides/static/src/img/document.png"/>
<field name="slide_id" ref="slide_slide_demo_0_0"/>
@@ -186,18 +187,21 @@
<field name="tag_ids" eval="[(4, ref('website_slides.slide_tag_demo_colorful')), (4, ref('website_slides.slide_tag_demo_theory'))]"/>
<field name="description">Just some basics Energy Efficiency Facts.</field>
</record>
<record id="slide_slide_demo_1_2_link_0" model="slide.slide.link">
<record id="slide_slide_demo_1_2_link_0" model="slide.slide.resource">
<field name="resource_type">url</field>
<field name="name">Energy Efficient Link 1</field>
<field name="link">http://www.example.com</field>
<field name="slide_id" ref="slide_slide_demo_1_2"/>
</record>
<record id="slide_slide_demo_1_2_link_1" model="slide.slide.link">
<record id="slide_slide_demo_1_2_link_1" model="slide.slide.resource">
<field name="resource_type">url</field>
<field name="name">Energy Efficient Link 2</field>
<field name="link">http://www.example.com</field>
<field name="slide_id" ref="slide_slide_demo_1_2"/>
</record>
<!--RESOURCE-->
<record id="slide_slide_demo_1_2_resource_0" model="slide.slide.resource">
<field name="resource_type">file</field>
<field name="name">Presentation</field>
<field name="data" type="base64" file="website_slides/static/src/img/presentation.pdf"/>
<field name="slide_id" ref="slide_slide_demo_1_2"/>
@@ -263,12 +267,14 @@
<field name="tag_ids" eval="[(4, ref('website_slides.slide_tag_demo_colorful'))]"/>
<field name="description">We had a little chat with Harry Potted, sure he had interesting things to say !</field>
</record>
<record id="slide_slide_demo_1_4_link_0" model="slide.slide.link">
<record id="slide_slide_demo_1_4_link_0" model="slide.slide.resource">
<field name="resource_type">url</field>
<field name="name">Know More Link 1</field>
<field name="link">http://www.example.com</field>
<field name="slide_id" ref="slide_slide_demo_1_4"/>
</record>
<record id="slide_slide_demo_1_4_link_1" model="slide.slide.link">
<record id="slide_slide_demo_1_4_link_1" model="slide.slide.resource">
<field name="resource_type">url</field>
<field name="name">Know More Link 2</field>
<field name="link">http://www.example.com</field>
<field name="slide_id" ref="slide_slide_demo_1_4"/>
@@ -389,18 +395,21 @@
<field name="description">A summary of know-how: what are the main trees categories and how to differentiate them.</field>
</record>
<!-- LINKS -->
<record id="slide_slide_demo_2_0_link_0" model="slide.slide.link">
<record id="slide_slide_demo_2_0_link_0" model="slide.slide.resource">
<field name="resource_type">url</field>
<field name="name">Trees Classification Link</field>
<field name="link">http://www.example.com</field>
<field name="slide_id" ref="slide_slide_demo_2_0"/>
</record>
<record id="slide_slide_demo_2_0_link_1" model="slide.slide.link">
<record id="slide_slide_demo_2_0_link_1" model="slide.slide.resource">
<field name="resource_type">url</field>
<field name="name">Main types of trees Link</field>
<field name="link">http://www.example.com</field>
<field name="slide_id" ref="slide_slide_demo_2_0"/>
</record>
<!--RESOURCE-->
<record id="slide_slide_demo_2_0_resource_0" model="slide.slide.resource">
<field name="resource_type">file</field>
<field name="name">Tree image</field>
<field name="data" type="base64" file="website_slides/static/src/img/slide_demo_tree_img_2.jpg"/>
<field name="slide_id" ref="slide_slide_demo_2_0"/>
@@ -742,12 +751,14 @@
<field name="tag_ids" eval="[(4, ref('website_slides.slide_tag_demo_tools'))]"/>
<field name="description">Tools you will need to complete this course.</field>
</record>
<record id="slide_slide_demo_5_0_link_0" model="slide.slide.link">
<record id="slide_slide_demo_5_0_link_0" model="slide.slide.resource">
<field name="resource_type">url</field>
<field name="name">Example Link 1</field>
<field name="link">http://www.example.com</field>
<field name="slide_id" ref="slide_slide_demo_5_0"/>
</record>
<record id="slide_slide_demo_5_0_link_1" model="slide.slide.link">
<record id="slide_slide_demo_5_0_link_1" model="slide.slide.resource">
<field name="resource_type">url</field>
<field name="name">Example Link 2</field>
<field name="link">http://www.example.com</field>
<field name="slide_id" ref="slide_slide_demo_5_0"/>
+1
View File
@@ -7,6 +7,7 @@ from . import slide_slide
from . import slide_question
from . import slide_channel
from . import slide_channel_tag
from . import slide_slide_resource
from . import res_config_settings
from . import website
from . import res_users
@@ -55,25 +55,6 @@ class SlidePartnerRelation(models.Model):
('partner_id', 'in', self.partner_id.ids),
])._recompute_completion()
class SlideLink(models.Model):
_name = 'slide.slide.link'
_description = "External URL for a particular slide"
slide_id = fields.Many2one('slide.slide', required=True, ondelete='cascade')
name = fields.Char('Title', required=True)
link = fields.Char('Link', required=True)
class SlideResource(models.Model):
_name = 'slide.slide.resource'
_description = "Additional resource for a particular slide"
slide_id = fields.Many2one('slide.slide', required=True, ondelete='cascade')
name = fields.Char('Name', required=True)
data = fields.Binary('Resource'
class EmbeddedSlide(models.Model):
""" Embedding in third party websites. Track view count, generate statistics. """
_name = 'slide.embed'
@@ -173,7 +154,6 @@ class Slide(models.Model):
datas = fields.Binary('File', attachment=True)
url = fields.Char('Document URL', help="Youtube or Google Document URL")
document_id = fields.Char('Document ID', help="Youtube or Google Document ID")
link_ids = fields.One2many('slide.slide.link', 'slide_id', string="External URL for this slide")
slide_resource_ids = fields.One2many('slide.slide.resource', 'slide_id', string="Additional Resource for this slide")
slide_resource_downloadable = fields.Boolean('Allow Download', default=True, help="Allow the user to download the content of the slide.")
mime_type = fields.Char('Mime-type')
@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
class SlideResource(models.Model):
_name = 'slide.slide.resource'
_description = "Additional resource for a particular slide"
slide_id = fields.Many2one('slide.slide', required=True, ondelete='cascade')
resource_type = fields.Selection([('file', 'File'), ('url', 'Link')], required=True)
name = fields.Char('Name', compute="_compute_name", readonly=False, store=True)
data = fields.Binary('Resource', compute='_compute_reset_resources', store=True, readonly=False)
file_name = fields.Char(store=True)
link = fields.Char('Link', compute='_compute_reset_resources', store=True, readonly=False)
_sql_constraints = [
('check_url', "CHECK (resource_type != 'url' OR link IS NOT NULL)", 'A resource of type url must contain a link.'),
('check_file_type', "CHECK (resource_type != 'file' OR link IS NULL)", 'A resource of type file cannot contain a link.'),
]
@api.depends('resource_type')
def _compute_reset_resources(self):
for resource in self:
if resource.resource_type == 'file':
resource.link = False
resource.data = resource.data
else:
resource.data = False
resource.link = resource.link
@api.depends('file_name', 'resource_type', 'data', 'link')
def _compute_name(self):
for resource in self:
to_update = not resource.name or resource.name == _("Resource")
if to_update:
new_name = _("Resource")
if resource.resource_type == 'file' and (resource.data or resource.file_name):
new_name = self.file_name
elif resource.resource_type == 'url':
new_name = self.link
resource.name = new_name
@api.constrains('data')
def _check_link_type(self):
for record in self:
if record.resource_type != 'file' and record.data:
raise ValidationError(_("Resource %(resource_name)s is a link and should not contain a data file", resource_name=record.name))
@@ -21,8 +21,6 @@ access_slide_channel_partners_all,slide.channel.users.all,model_slide_channel_pa
access_slide_channel_partners_system,slide.channel.users.system,model_slide_channel_partner,website_slides.group_website_slides_officer,1,1,1,1
access_slide_embed_all,slide.embed.all,model_slide_embed,,1,0,0,0
access_slide_embed_user,slide.embed.user,model_slide_embed,base.group_user,1,1,1,1
access_slide_slide_link_all,slide.slide.link.all,model_slide_slide_link,,1,0,0,0
access_slide_slide_link_officer,slide.slide.link.officer,model_slide_slide_link,website_slides.group_website_slides_officer,1,1,1,1
access_slide_slide_resource_all,slide.slide.resource.all,model_slide_slide_resource,,1,0,0,0
access_slide_slide_resource_public,slide.slide.resource.public,model_slide_slide_resource,base.group_public,0,0,0,0
access_slide_slide_resource_publisher,slide.slide.resource.publisher,model_slide_slide_resource,website_slides.group_website_slides_officer,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
21 access_slide_channel_partners_system slide.channel.users.system model_slide_channel_partner website_slides.group_website_slides_officer 1 1 1 1
22 access_slide_embed_all slide.embed.all model_slide_embed 1 0 0 0
23 access_slide_embed_user slide.embed.user model_slide_embed base.group_user 1 1 1 1
access_slide_slide_link_all slide.slide.link.all model_slide_slide_link 1 0 0 0
access_slide_slide_link_officer slide.slide.link.officer model_slide_slide_link website_slides.group_website_slides_officer 1 1 1 1
24 access_slide_slide_resource_all slide.slide.resource.all model_slide_slide_resource 1 0 0 0
25 access_slide_slide_resource_public slide.slide.resource.public model_slide_slide_resource base.group_public 0 0 0 0
26 access_slide_slide_resource_publisher slide.slide.resource.publisher model_slide_slide_resource website_slides.group_website_slides_officer 1 1 1 1
@@ -198,5 +198,16 @@
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
<record id="rule_slide_slide_resource_downloadable_manager" model="ir.rule">
<field name="name">Resource: manager: crud all</field>
<field name="model_id" ref="model_slide_slide_resource"/>
<field name="domain_force">[(1, '=', 1)]</field>
<field name="groups" eval="[(4, ref('group_website_slides_manager'))]"/>
<field name="perm_read" eval="1"/>
<field name="perm_write" eval="1"/>
<field name="perm_create" eval="1"/>
<field name="perm_unlink" eval="1"/>
</record>
</data>
</odoo>
+1
View File
@@ -3,6 +3,7 @@
from . import common
from . import test_karma
from . import test_resources
from . import test_security
from . import test_slide_utils
from . import test_statistics
@@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from psycopg2 import IntegrityError
from odoo.addons.website_slides.tests import common
from odoo.exceptions import ValidationError
from odoo.tests.common import users
from odoo.tools import mute_logger
class TestResources(common.SlidesCase):
@users('user_officer')
@mute_logger('odoo')
def test_constraints(self):
self.link = self.env["slide.slide.resource"].create({
'name': 'Test Link',
'resource_type': 'url',
'link': 'https://www.example.com',
'slide_id': self.slide.id,
})
self.resource = self.env["slide.slide.resource"].create({
'name': 'Test Resource',
'resource_type': 'file',
'data': '1111',
'slide_id': self.slide.id,
})
self.assertEqual(len(self.slide.slide_resource_ids), 2)
with self.assertRaises(ValidationError, msg="Cannot have a type link with a file"):
self.env["slide.slide.resource"].create({
'name': 'Raise Error Test Resource',
'resource_type': 'url',
'link': '1111',
'data': '1111',
'slide_id': self.slide.id,
})
self.assertEqual(len(self.slide.slide_resource_ids), 2)
with self.assertRaises(IntegrityError, msg="Cannot have a type file with a link"):
self.env["slide.slide.resource"].create({
'name': 'Raise Error Test File With Link',
'resource_type': 'file',
'link': '1111',
'slide_id': self.slide.id,
})
with self.assertRaises(IntegrityError, msg="Cannot have an empty link"):
self.env["slide.slide.resource"].create({
'name': 'Raise Error Test Empty URL',
'resource_type': 'url',
'slide_id': self.slide.id,
})
@@ -139,7 +139,7 @@
<field name="slide_resource_ids" widget="one2many" nolabel="1">
<tree editable="top">
<field name="resource_type"/>
<field name="name"/>
<field name="name" required="1"/>
<field name="file_name" invisible="1"/>
<field name="data" attrs="{'readonly': [('resource_type', '=', 'url')]}" filename="file_name"/>
<field name="link" string="Link"
@@ -162,10 +162,10 @@
</span>
</div>
</a>
<ul t-if="aside_slide.link_ids or aside_slide.slide_resource_ids or aside_slide.question_ids" class="list-group px-2 mb-1 list-unstyled">
<t t-foreach="aside_slide.link_ids" t-as="resource">
<ul t-if="aside_slide.slide_resource_ids or aside_slide.question_ids" class="list-group px-2 mb-1 list-unstyled">
<t t-foreach="aside_slide.slide_resource_ids" t-as="resource">
<li class="pl-4">
<a t-if="can_access" t-att-href="resource.link" target="new" class="text-decoration-none small">
<a t-if="can_access and resource.link" t-att-href="resource.link" target="new" class="text-decoration-none small">
<i class="fa fa-link mr-1"/><span t-field="resource.name"/>
</a>
<span t-else="" class="text-decoration-none text-muted small">
@@ -410,21 +410,23 @@
</div>
</div>
<div class="row mt-3 mb-3">
<div class="col-12 col-md d-flex align-items-start mb-4 mb-md-0" t-if="len(slide.link_ids)">
<span t-if="slide.link_ids" class="text-muted font-weight-bold mr-3">External sources</span>
<t t-set="links" t-value="slide.slide_resource_ids.filtered(lambda res: res.resource_type == 'url')"/>
<t t-set="files" t-value="slide.slide_resource_ids.filtered(lambda res: res.resource_type == 'file' and res.data)"/>
<div class="col-12 col-md d-flex align-items-start mb-4 mb-md-0" t-if="links">
<span class="text-muted font-weight-bold mr-3">External sources</span>
<div class="text-muted mr-auto border-left pl-3">
<t t-foreach="slide.link_ids" t-as="link">
<t t-foreach="links" t-as="link">
<a t-att-href="link.link" t-esc="link.name"/><br />
</t>
</div>
</div>
<group>
<div class="col-12 col-md d-flex align-items-start mb-4 mb-md-0 o_wslides_js_course_join" t-if="len(slide.slide_resource_ids)">
<div class="col-12 col-md d-flex align-items-start mb-4 mb-md-0 o_wslides_js_course_join" t-if="files">
<span t-if="slide.channel_id.is_member or slide.channel_id.can_publish or slide.is_preview or slide.channel_id.enroll in ['private', 'payment']" class="text-muted font-weight-bold mr-3">
Additional Resources
</span>
<div t-if="slide.channel_id.is_member or slide.channel_id.can_publish" class="text-muted mr-auto border-left pl-3">
<t t-foreach="slide.slide_resource_ids" t-as="resource">
<t t-foreach="files" t-as="resource">
<a t-attf-href="/web/content/slide.slide.resource/#{resource.id}/data?download=true" t-esc="resource.name"/><br />
</t>
</div>
@@ -135,18 +135,20 @@
<div class="o_wslides_fs_slide_name text-600" t-esc="slide.name"/>
</div>
</span>
<ul class="list-unstyled w-100 pt-2 small" t-if="slide.link_ids or slide.slide_resource_ids or (slide.question_ids and not slide.slide_type =='quiz')" >
<li t-if="slide.link_ids" t-foreach="slide.link_ids" t-as="link" class="pl-0 mb-1">
<ul class="list-unstyled w-100 pt-2 small" t-if="slide.slide_resource_ids or (slide.question_ids and not slide.slide_type =='quiz')" >
<t t-set="links" t-value="slide.slide_resource_ids.filtered(lambda res: res.resource_type == 'url')"/>
<li t-if="links" t-foreach="links" t-as="link" class="pl-0 mb-1">
<a t-if="can_access" class="o_wslides_fs_slide_link" t-att-href="link.link" target="_blank">
<i class="fa fa-link mr-2"/><span t-esc="link.name"/>
</a>
<span t-else="" class="o_wslides_fs_slide_link text-600">
<i class="fa fa-link mr-2"/><span t-esc="link.name"/>
<i class="fa fa-link mr-2"/><span t-esc="resource.name"/>
</span>
</li>
<div class="o_wslides_js_course_join pl-0" t-if="slide.slide_resource_ids">
<t t-set="resources" t-value="slide.slide_resource_ids.filtered(lambda res: res.resource_type == 'file')"/>
<div class="o_wslides_js_course_join pl-0" t-if="resources">
<t t-if="is_member or slide.channel_id.can_publish">
<li t-foreach="slide.slide_resource_ids" t-as="resource" class="mb-1">
<li t-foreach="resources" t-as="resource" class="mb-1">
<a class="o_wslides_fs_slide_link" t-attf-href="/web/content/slide.slide.resource/#{resource.id}/data?download=true">
<i class="fa fa-download mr-2"/><span t-esc="resource.name"/>
</a>