diff --git a/addons/test_website_slides_full/tests/test_ui_wslides.py b/addons/test_website_slides_full/tests/test_ui_wslides.py index 3943cd6daa1..689825f674d 100644 --- a/addons/test_website_slides_full/tests/test_ui_wslides.py +++ b/addons/test_website_slides_full/tests/test_ui_wslides.py @@ -148,7 +148,7 @@ class TestUi(TestUICommon): (0, 0, { 'name': 'DIY Furniture Certification', 'sequence': 1, - 'slide_type': 'certification', + 'slide_category': 'certification', 'category_id': False, 'is_published': True, 'is_preview': False, diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py index d3902452fe3..e52856146dc 100644 --- a/addons/website_slides/controllers/main.py +++ b/addons/website_slides/controllers/main.py @@ -67,7 +67,7 @@ class WebsiteSlides(WebsiteProfile): def _set_completed_slide(self, slide): # quiz use their specific mechanism to be marked as done - if slide.slide_type == 'quiz' or slide.question_ids: + if slide.slide_category == 'quiz' or slide.question_ids: raise werkzeug.exceptions.Forbidden(_("Slide with questions must be marked as done when submitting all good answers ")) if slide.website_published and slide.channel_id.is_member: slide.action_set_completed() @@ -331,12 +331,12 @@ class WebsiteSlides(WebsiteProfile): return request.render('website_slides.courses_home', values) @http.route(['/slides/all', '/slides/all/tag/'], type='http', auth="public", website=True, sitemap=True) - def slides_channel_all(self, slide_type=None, slug_tags=None, my=False, **post): + def slides_channel_all(self, slide_category=None, slug_tags=None, my=False, **post): """ Home page displaying a list of courses displayed according to some criterion and search terms. - :param string slide_type: if provided, filter the course to contain at - least one slide of type 'slide_type'. Used notably to display courses + :param string slide_category: if provided, filter the course to contain at + least one slide of type 'slide_category'. Used notably to display courses with certifications; :param string slug_tags: if provided, filter the slide.channels having the tag(s) (in comma separated slugified form); @@ -347,6 +347,10 @@ class WebsiteSlides(WebsiteProfile): * ``search``: filter on course description / name; """ + # retro-compatibility for older links, 'slide_category' field was previously named 'slide_type' + # can be safely removed after 15.3 (I swear though, don't be afraid, remove it!) + slide_category = slide_category or post.get('slide_type') + if slug_tags and request.httprequest.method == 'GET': # Redirect `tag-1,tag-2` to `tag-1` to disallow multi tags # in GET request for proper bot indexation; @@ -355,7 +359,7 @@ class WebsiteSlides(WebsiteProfile): # request and so clearly it's not SEO bot. tag_list = slug_tags.split(',') if len(tag_list) > 1 and not post.get('search'): - url = QueryURL('/slides/all', ['tag'], tag=tag_list[0], my=my, slide_type=slide_type)() + url = QueryURL('/slides/all', ['tag'], tag=tag_list[0], my=my, slide_category=slide_category)() return request.redirect(url, code=302) options = { @@ -367,7 +371,7 @@ class WebsiteSlides(WebsiteProfile): 'allowFuzzy': not post.get('noFuzzy'), 'my': my, 'tag': slug_tags or post.get('tag'), - 'slide_type': slide_type, + 'slide_category': slide_category, } search = post.get('search') order = self._channel_order_by_criterion.get(post.get('sorting')) @@ -390,7 +394,7 @@ class WebsiteSlides(WebsiteProfile): 'tag_groups': tag_groups, 'search_term': fuzzy_search_term or search, 'original_search': fuzzy_search_term and search, - 'search_slide_type': slide_type, + 'search_slide_category': slide_category, 'search_my': my, 'search_tags': search_tags, 'top3_users': self._get_top3_users(), @@ -416,15 +420,20 @@ class WebsiteSlides(WebsiteProfile): '/slides//category/', '/slides//category//page/', ], type='http', auth="public", website=True, sitemap=sitemap_slide) - def channel(self, channel, category=None, tag=None, page=1, slide_type=None, uncategorized=False, sorting=None, search=None, **kw): + def channel(self, channel, category=None, tag=None, page=1, slide_category=None, uncategorized=False, sorting=None, search=None, **kw): """ Will return all necessary data to display the requested slide_channel along with a possible category. """ + + # retro-compatibility for older links, 'slide_category' field was previously named 'slide_type' + # can be safely removed after 15.3 (I swear though, don't be afraid, remove it!) + slide_category = slide_category or kw.get('slide_type') + domain = self._get_channel_slides_base_domain(channel) pager_url = "/slides/%s" % (channel.id) pager_args = {} - slide_types = dict(request.env['slide.slide']._fields['slide_type']._description_selection(request.env)) + slide_categories = dict(request.env['slide.slide']._fields['slide_category']._description_selection(request.env)) if search: domain += [ @@ -443,9 +452,9 @@ class WebsiteSlides(WebsiteProfile): if uncategorized: domain += [('category_id', '=', False)] pager_args['uncategorized'] = 1 - elif slide_type: - domain += [('slide_type', '=', slide_type)] - pager_url += "?slide_type=%s" % slide_type + elif slide_category: + domain += [('slide_category', '=', slide_category)] + pager_url += "?slide_category=%s" % slide_category # sorting criterion if channel.channel_type == 'documentation': @@ -467,8 +476,8 @@ class WebsiteSlides(WebsiteProfile): query_string = "?search_category=%s" % category.id elif tag: query_string = "?search_tag=%s" % tag.id - elif slide_type: - query_string = "?search_slide_type=%s" % slide_type + elif slide_category: + query_string = "?search_slide_category=%s" % slide_category elif uncategorized: query_string = "?search_uncategorized=1" @@ -479,10 +488,10 @@ class WebsiteSlides(WebsiteProfile): # search 'search_category': category, 'search_tag': tag, - 'search_slide_type': slide_type, + 'search_slide_category': slide_category, 'search_uncategorized': uncategorized, 'query_string': query_string, - 'slide_types': slide_types, + 'slide_categories': slide_categories, 'sorting': actual_sorting, 'search': search, # display data @@ -704,8 +713,8 @@ class WebsiteSlides(WebsiteProfile): values.update({ 'search_category': slide.category_id if kwargs.get('search_category') else None, 'search_tag': request.env['slide.tag'].browse(int(kwargs.get('search_tag'))) if kwargs.get('search_tag') else None, - 'slide_types': dict(request.env['slide.slide']._fields['slide_type']._description_selection(request.env)) if kwargs.get('search_slide_type') else None, - 'search_slide_type': kwargs.get('search_slide_type'), + 'slide_categories': dict(request.env['slide.slide']._fields['slide_category']._description_selection(request.env)) if kwargs.get('search_slide_category') else None, + 'search_slide_category': kwargs.get('search_slide_category'), 'search_uncategorized': kwargs.get('search_uncategorized') }) @@ -724,7 +733,7 @@ class WebsiteSlides(WebsiteProfile): type='http', auth="public", website=True, sitemap=False) def slide_get_pdf_content(self, slide): response = werkzeug.wrappers.Response() - response.data = slide.datas and base64.b64decode(slide.datas) or b'' + response.data = slide.binary_content and base64.b64decode(slide.binary_content) or b'' response.mimetype = 'application/pdf' return response @@ -1064,8 +1073,8 @@ class WebsiteSlides(WebsiteProfile): @http.route(['/slides/add_slide'], type='json', auth='user', methods=['POST'], website=True) def create_slide(self, *args, **post): # check the size only when we upload a file. - if post.get('datas'): - file_size = len(post['datas']) * 3 / 4 # base64 + if post.get('binary_content'): + file_size = len(post['binary_content']) * 3 / 4 # base64 if (file_size / 1024.0 / 1024.0) > 25: return {'error': _('File is too big. File size cannot exceed 25MB')} @@ -1117,9 +1126,9 @@ class WebsiteSlides(WebsiteProfile): channel._resequence_slides(slide, force_category=category) redirect_url = "/slides/slide/%s" % (slide.id) - if channel.channel_type == "training" and not slide.slide_type == "webpage": + if channel.channel_type == "training" and not slide.slide_category == "webpage": redirect_url = "/slides/%s" % (slug(channel)) - if slide.slide_type == 'webpage': + if slide.slide_category == 'webpage': redirect_url += "?enable_editor=1" return { 'url': redirect_url, @@ -1129,8 +1138,8 @@ class WebsiteSlides(WebsiteProfile): } def _get_valid_slide_post_values(self): - return ['name', 'url', 'tag_ids', 'slide_type', 'channel_id', 'is_preview', - 'mime_type', 'datas', 'description', 'image_1920', 'is_published'] + return ['name', 'url', 'tag_ids', 'slide_category', 'channel_id', 'is_preview', + 'mime_type', 'binary_content', 'description', 'image_1920', 'is_published'] @http.route(['/slides/tag/search_read'], type='json', auth='user', methods=['POST'], website=True) def slide_tag_search_read(self, fields, domain): diff --git a/addons/website_slides/data/mail_template_data.xml b/addons/website_slides/data/mail_template_data.xml index c1c27b69103..6e67cbe762c 100644 --- a/addons/website_slides/data/mail_template_data.xml +++ b/addons/website_slides/data/mail_template_data.xml @@ -4,7 +4,7 @@ Slide Published - New {{ object.slide_type }} published on {{ object.channel_id.name }} + New {{ object.slide_category }} published on {{ object.channel_id.name }}

@@ -36,14 +36,14 @@ Slide Shared - {{ user.name }} shared a {{ object.slide_type }} with you! + {{ user.name }} shared a {{ object.slide_category }} with you! {{ user.email_formatted }} {{ ctx.get('email', '') }}

Hello

- Mitchell Admin shared the document Trees with you! + Mitchell Admin shared the document Trees with you!

diff --git a/addons/website_slides/data/slide_slide_demo.xml b/addons/website_slides/data/slide_slide_demo.xml index 7817d5db91c..0873542073d 100644 --- a/addons/website_slides/data/slide_slide_demo.xml +++ b/addons/website_slides/data/slide_slide_demo.xml @@ -6,9 +6,9 @@ Gardening: The Know-How 1 - + - presentation + presentation @@ -29,7 +29,7 @@ Home Gardening 2 - infographic + infographic @@ -43,7 +43,7 @@ Mighty Carrots 3 - infographic + infographic @@ -56,9 +56,9 @@ How to Grow and Harvest The Best Strawberries | Basics 4 - + - document + document @@ -72,7 +72,7 @@ Test your knowledge 5 - quiz + quiz @@ -149,7 +149,7 @@ Tree Infographic 1 - infographic + infographic @@ -163,7 +163,7 @@ Interesting Tree Facts 2 - infographic + infographic @@ -177,7 +177,7 @@ Energy Efficiency Facts 3 - infographic + infographic @@ -212,7 +212,7 @@ https://www.youtube.com/watch?v=QYmgrw0PgLU QYmgrw0PgLU - video + video @@ -226,7 +226,7 @@ A little chat with Harry Potted 6 - webpage + webpage
@@ -327,9 +327,9 @@ 3 Main Methodologies 6 - + - presentation + presentation @@ -345,7 +345,7 @@ https://www.youtube.com/watch?v=l0JZ25VvbwE l0JZ25VvbwE - video + video @@ -378,9 +378,9 @@ Main Trees Categories 1 - + - presentation + presentation @@ -464,7 +464,7 @@ A Mighty Forest from Ages 2 - webpage + webpage
@@ -513,7 +513,7 @@ https://www.youtube.com/watch?v=ebBez6bcSEc ebBez6bcSEc - video + video @@ -527,9 +527,9 @@ Wood Characteristics 5 - + - presentation + presentation @@ -561,7 +561,7 @@ Comparing Hardness of Wood Species 2 - infographic + infographic @@ -577,7 +577,7 @@ https://www.youtube.com/watch?v=PYr1rK8pS30 PYr1rK8pS30 - video + video @@ -609,7 +609,7 @@ Foreword 1 - webpage + webpage
@@ -656,7 +656,7 @@ https://www.youtube.com/watch?v=bvSe6r5BpaY bvSe6r5BpaY - video + video @@ -670,7 +670,7 @@ Drawing 1 11 - infographic + infographic @@ -684,7 +684,7 @@ Drawing 2 12 - infographic + infographic @@ -697,9 +697,9 @@ Presentation 13 - + - document + document @@ -739,9 +739,9 @@ Unforgettable Tools 1 - + - presentation + presentation @@ -769,7 +769,7 @@ https://www.youtube.com/watch?v=5WMqwTnZ-qs 5WMqwTnZ-qs - video + video @@ -784,7 +784,7 @@ https://www.youtube.com/watch?v=grrXe1QZNzQ grrXe1QZNzQ - video + video @@ -797,7 +797,7 @@ Test your knowledge ! 6 - quiz + quiz diff --git a/addons/website_slides/models/slide_channel.py b/addons/website_slides/models/slide_channel.py index f1da46902d8..111fd812ebf 100644 --- a/addons/website_slides/models/slide_channel.py +++ b/addons/website_slides/models/slide_channel.py @@ -300,18 +300,18 @@ class Channel(models.Model): channel.slide_category_ids = channel.slide_ids.filtered(lambda slide: slide.is_category) channel.slide_content_ids = channel.slide_ids - channel.slide_category_ids - @api.depends('slide_ids.slide_type', 'slide_ids.is_published', 'slide_ids.completion_time', + @api.depends('slide_ids.slide_category', 'slide_ids.is_published', 'slide_ids.completion_time', 'slide_ids.likes', 'slide_ids.dislikes', 'slide_ids.total_views', 'slide_ids.is_category', 'slide_ids.active') def _compute_slides_statistics(self): default_vals = dict(total_views=0, total_votes=0, total_time=0, total_slides=0) - keys = ['nbr_%s' % slide_type for slide_type in self.env['slide.slide']._fields['slide_type'].get_values(self.env)] + keys = ['nbr_%s' % slide_category for slide_category in self.env['slide.slide']._fields['slide_category'].get_values(self.env)] default_vals.update(dict((key, 0) for key in keys)) result = dict((cid, dict(default_vals)) for cid in self.ids) read_group_res = self.env['slide.slide'].read_group( [('active', '=', True), ('is_published', '=', True), ('channel_id', 'in', self.ids), ('is_category', '=', False)], - ['channel_id', 'slide_type', 'likes', 'dislikes', 'total_views', 'completion_time'], - groupby=['channel_id', 'slide_type'], + ['channel_id', 'slide_category', 'likes', 'dislikes', 'total_views', 'completion_time'], + groupby=['channel_id', 'slide_category'], lazy=False) for res_group in read_group_res: cid = res_group['channel_id'][0] @@ -320,25 +320,25 @@ class Channel(models.Model): result[cid]['total_votes'] -= res_group.get('dislikes', 0) result[cid]['total_time'] += res_group.get('completion_time', 0) - type_stats = self._compute_slides_statistics_type(read_group_res) - for cid, cdata in type_stats.items(): + category_stats = self._compute_slides_statistics_category(read_group_res) + for cid, cdata in category_stats.items(): result[cid].update(cdata) for record in self: record.update(result.get(record.id, default_vals)) - def _compute_slides_statistics_type(self, read_group_res): - """ Compute statistics based on all existing slide types """ - slide_types = self.env['slide.slide']._fields['slide_type'].get_values(self.env) - keys = ['nbr_%s' % slide_type for slide_type in slide_types] + def _compute_slides_statistics_category(self, read_group_res): + """ Compute statistics based on all existing slide categories """ + slide_categories = self.env['slide.slide']._fields['slide_category'].get_values(self.env) + keys = ['nbr_%s' % slide_category for slide_category in slide_categories] result = dict((cid, dict((key, 0) for key in keys + ['total_slides'])) for cid in self.ids) for res_group in read_group_res: cid = res_group['channel_id'][0] - slide_type = res_group.get('slide_type') - if slide_type: - slide_type_count = res_group.get('__count', 0) - result[cid]['nbr_%s' % slide_type] = slide_type_count - result[cid]['total_slides'] += slide_type_count + slide_category = res_group.get('slide_category') + if slide_category: + slide_category_count = res_group.get('__count', 0) + result[cid]['nbr_%s' % slide_category] = slide_category_count + result[cid]['total_slides'] += slide_category_count return result def _compute_rating_stats(self): @@ -847,7 +847,7 @@ class Channel(models.Model): with_date = options['displayDetail'] my = options.get('my') search_tags = options.get('tag') - slide_type = options.get('slide_type') + slide_category = options.get('slide_category') domain = [website.website_domain()] if my: domain.append([('partner_ids', '=', self.env.user.partner_id.id)]) @@ -865,8 +865,8 @@ class Channel(models.Model): # OR inside a group, AND between groups. for group in grouped_tags: domain.append([('tag_ids', 'in', [tag.id for tag in grouped_tags[group]])]) - if slide_type and 'nbr_%s' % slide_type in self: - domain.append([('nbr_%s' % slide_type, '>', 0)]) + if slide_category and 'nbr_%s' % slide_category in self: + domain.append([('nbr_%s' % slide_category, '>', 0)]) search_fields = ['name'] fetch_fields = ['name', 'website_url'] mapping = { diff --git a/addons/website_slides/models/slide_slide.py b/addons/website_slides/models/slide_slide.py index 8a70d94a409..d5bf601544d 100644 --- a/addons/website_slides/models/slide_slide.py +++ b/addons/website_slides/models/slide_slide.py @@ -118,23 +118,23 @@ class Slide(models.Model): quiz_third_attempt_reward = fields.Integer("Reward: third attempt", default=5,) quiz_fourth_attempt_reward = fields.Integer("Reward: every attempt after the third try", default=2) # content - slide_type = fields.Selection([ + slide_category = fields.Selection([ ('infographic', 'Infographic'), ('webpage', 'Web Page'), ('presentation', 'Presentation'), ('document', 'Document'), ('video', 'Video'), ('quiz', "Quiz")], - string='Type', required=True, + string='Category', required=True, default='document', - help="The document type will be set automatically based on the document URL and properties (e.g. height and width for presentation and document).") - datas = fields.Binary('File', attachment=True) + help="The document category will be set automatically based on the document URL and properties (e.g. height and width for presentation and document).") + binary_content = 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") 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') - html_content = fields.Html("HTML Content", help="Custom HTML content for slides of type 'Web Page'.", translate=True, sanitize_attributes=False, sanitize_form=False) + html_content = fields.Html("HTML Content", help="Custom HTML content for slides of category 'Web Page'.", translate=True, sanitize_attributes=False, sanitize_form=False) # website website_id = fields.Many2one(related='channel_id.website_id', readonly=True) date_published = fields.Datetime('Publish Date', readonly=True, tracking=False) @@ -270,35 +270,35 @@ class Slide(models.Model): for slide in self: slide.embed_count = mapped_data.get(slide.id, 0) - @api.depends('slide_ids.sequence', 'slide_ids.slide_type', 'slide_ids.is_published', 'slide_ids.is_category') + @api.depends('slide_ids.sequence', 'slide_ids.slide_category', 'slide_ids.is_published', 'slide_ids.is_category') def _compute_slides_statistics(self): # Do not use dict.fromkeys(self.ids, dict()) otherwise it will use the same dictionnary for all keys. # Therefore, when updating the dict of one key, it updates the dict of all keys. - keys = ['nbr_%s' % slide_type for slide_type in self.env['slide.slide']._fields['slide_type'].get_values(self.env)] + keys = ['nbr_%s' % slide_category for slide_category in self.env['slide.slide']._fields['slide_category'].get_values(self.env)] default_vals = dict((key, 0) for key in keys + ['total_slides']) res = self.env['slide.slide'].read_group( [('is_published', '=', True), ('category_id', 'in', self.ids), ('is_category', '=', False)], - ['category_id', 'slide_type'], ['category_id', 'slide_type'], + ['category_id', 'slide_category'], ['category_id', 'slide_category'], lazy=False) - type_stats = self._compute_slides_statistics_type(res) + category_stats = self._compute_slides_statistics_category(res) for record in self: - record.update(type_stats.get(record._origin.id, default_vals)) + record.update(category_stats.get(record._origin.id, default_vals)) - def _compute_slides_statistics_type(self, read_group_res): - """ Compute statistics based on all existing slide types """ - slide_types = self.env['slide.slide']._fields['slide_type'].get_values(self.env) - keys = ['nbr_%s' % slide_type for slide_type in slide_types] + def _compute_slides_statistics_category(self, read_group_res): + """ Compute statistics based on all existing slide categories """ + slide_categories = self.env['slide.slide']._fields['slide_category'].get_values(self.env) + keys = ['nbr_%s' % slide_category for slide_category in slide_categories] result = dict((cid, dict((key, 0) for key in keys + ['total_slides'])) for cid in self.ids) for res_group in read_group_res: cid = res_group['category_id'][0] - slide_type = res_group.get('slide_type') - if slide_type: - slide_type_count = res_group.get('__count', 0) - result[cid]['nbr_%s' % slide_type] = slide_type_count - result[cid]['total_slides'] += slide_type_count + slide_category = res_group.get('slide_category') + if slide_category: + slide_category_count = res_group.get('__count', 0) + result[cid]['nbr_%s' % slide_category] = slide_category_count + result[cid]['total_slides'] += slide_category_count return result @api.depends('slide_partner_ids.partner_id') @@ -315,7 +315,7 @@ class Slide(models.Model): self.env['slide.slide.partner'] ) - @api.depends('document_id', 'slide_type', 'mime_type') + @api.depends('document_id', 'slide_category', 'mime_type') def _compute_embed_code(self): base_url = request and request.httprequest.url_root @@ -326,13 +326,13 @@ class Slide(models.Model): 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']): + if record.binary_content and (not record.document_id or record.slide_category in ['document', 'presentation']): slide_url = base_url + url_for('/slides/embed/%s?page=1' % record.id) slide_url_external = base_url + url_for('/slides/embed_external/%s?page=1' % record.id) base_embed_code = Markup('') 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: + elif record.slide_category == 'video' and record.document_id: if not record.mime_type: # embed youtube video query = urls.url_parse(record.url).query @@ -359,15 +359,15 @@ class Slide(models.Model): for key, value in values.items(): self[key] = value - @api.onchange('datas') - def _on_change_datas(self): + @api.onchange('binary_content') + def _on_change_binary_content(self): """ For PDFs, we assume that it takes 5 minutes to read a page. If the selected file is not a PDF, it is an image (You can - only upload PDF or Image file) then the slide_type is changed - into infographic and the uploaded dataS is transfered to the + only upload PDF or Image file) then the slide_category is changed + into infographic and the uploaded binary_content is transfered to the image field. (It avoids the infinite loading in PDF viewer)""" - if self.datas: - data = base64.b64decode(self.datas) + if self.binary_content: + data = base64.b64decode(self.binary_content) if data.startswith(b'%PDF-'): pdf = PyPDF2.PdfFileReader(io.BytesIO(data), overwriteWarnings=False, strict=False) try: @@ -376,9 +376,9 @@ class Slide(models.Model): return self.completion_time = (5 * len(pdf.pages)) / 60 else: - self.slide_type = 'infographic' - self.image_1920 = self.datas - self.datas = None + self.slide_category = 'infographic' + self.image_1920 = self.binary_content + self.binary_content = None @api.depends('name', 'channel_id.website_id.domain') def _compute_website_url(self): @@ -409,8 +409,8 @@ class Slide(models.Model): # 'website_published' is handled by mixin values['date_published'] = False - if values.get('slide_type') == 'infographic' and not values.get('image_1920'): - values['image_1920'] = values['datas'] + if values.get('slide_category') == 'infographic' and not values.get('image_1920'): + values['image_1920'] = values['binary_content'] if values.get('is_category'): values['is_preview'] = True values['is_published'] = True @@ -794,7 +794,7 @@ class Slide(models.Model): if fetch_res.get('error'): return {'error': self._extract_google_error_message(fetch_res.get('error'))} - values = {'slide_type': 'video', 'document_id': document_id} + values = {'slide_category': 'video', 'document_id': document_id} items = fetch_res['values'].get('items') if not items: return {'error': _('Please enter valid Youtube or Google Doc URL')} @@ -845,15 +845,15 @@ class Slide(models.Model): @api.model def _parse_google_document(self, document_id, only_preview_fields): - def get_slide_type(vals): + def get_slide_category(vals): # TDE FIXME: WTF ?? - slide_type = 'presentation' + slide_category = 'presentation' if vals.get('image_1920'): image = Image.open(io.BytesIO(base64.b64decode(vals['image_1920']))) width, height = image.size if height > width: return 'document' - return slide_type + return slide_category # Google drive doesn't use a simple API key to access the data, but requires an access # token. However, this token is generated in module google_drive, which is not in the @@ -886,18 +886,18 @@ class Slide(models.Model): 'document_id': document_id, } if google_values['mimeType'].startswith('video/'): - values['slide_type'] = 'video' + values['slide_category'] = 'video' elif google_values['mimeType'].startswith('image/'): - values['datas'] = values['image_1920'] - values['slide_type'] = 'infographic' + values['binary_content'] = values['image_1920'] + values['slide_category'] = 'infographic' elif google_values['mimeType'].startswith('application/vnd.google-apps'): - values['slide_type'] = get_slide_type(values) + values['slide_category'] = get_slide_category(values) if 'exportLinks' in google_values: - values['datas'] = self._fetch_data(google_values['exportLinks']['application/pdf'], params, 'pdf')['values'] + values['binary_content'] = self._fetch_data(google_values['exportLinks']['application/pdf'], params, 'pdf')['values'] elif google_values['mimeType'] == 'application/pdf': # TODO: Google Drive PDF document doesn't provide plain text transcript - values['datas'] = self._fetch_data(google_values['webContentLink'], {}, 'pdf')['values'] - values['slide_type'] = get_slide_type(values) + values['binary_content'] = self._fetch_data(google_values['webContentLink'], {}, 'pdf')['values'] + values['slide_category'] = get_slide_category(values) return {'values': values} @@ -942,7 +942,7 @@ class Slide(models.Model): } def _search_render_results(self, fetch_fields, mapping, icon, limit): - icon_per_type = { + icon_per_category = { 'infographic': 'fa-file-picture-o', 'webpage': 'fa-file-text', 'presentation': 'fa-file-pdf-o', @@ -953,7 +953,7 @@ class Slide(models.Model): } results_data = super()._search_render_results(fetch_fields, mapping, icon, limit) for slide, data in zip(self, results_data): - data['_fa'] = icon_per_type.get(slide.slide_type, 'fa-file-pdf-o') + data['_fa'] = icon_per_category.get(slide.slide_category, 'fa-file-pdf-o') data['url'] = slide.website_url data['course'] = _('Course: %s', slide.channel_id.name) data['course_url'] = slide.channel_id.website_url diff --git a/addons/website_slides/static/src/js/slides_course_fullscreen_player.js b/addons/website_slides/static/src/js/slides_course_fullscreen_player.js index e8cad60594f..5e4974c0437 100644 --- a/addons/website_slides/static/src/js/slides_course_fullscreen_player.js +++ b/addons/website_slides/static/src/js/slides_course_fullscreen_player.js @@ -225,7 +225,7 @@ //-------------------------------------------------------------------------- /** * Handler called whenever the user clicks on a sub-quiz which is linked to a slide. - * This does NOT handle the case of a slide of type "quiz". + * This does NOT handle the case of a slide of category "quiz". * By going through this handler, the widget will be able to determine that it has to render * the associated quiz and not the main content. * @@ -455,7 +455,7 @@ // Private //-------------------------------------------------------------------------- /** - * Fetches content with an rpc call for slides of type "webpage" + * Fetches content with an rpc call for slides of category "webpage" * * @private */ @@ -474,14 +474,14 @@ }); }, /** - * Fetches slide content depending on its type. + * Fetches slide content depending on its category. * If the slide doesn't need to fetch any content, return a resolved deferred * * @private */ _fetchSlideContent: function (){ var slide = this.get('slide'); - if (slide.type === 'webpage' && !slide.isQuiz) { + if (slide.category === 'webpage' && !slide.isQuiz) { return this._fetchHtmlContent(); } return Promise.resolve(); @@ -494,14 +494,14 @@ }, /** * Extend the slide data list to add informations about rendering method, and other - * specific values according to their slide_type. + * specific values according to their slide_category. */ _preprocessSlideData: function (slidesDataList) { slidesDataList.forEach(function (slideData, index) { // compute hasNext slide slideData.hasNext = index < slidesDataList.length-1; // compute embed url - if (slideData.type === 'video') { + if (slideData.category === 'video') { slideData.embedCode = $(slideData.embedCode).attr('src') || ""; // embedCode contains an iframe tag, where src attribute is the url (youtube or embed document from odoo) var separator = slideData.embedCode.indexOf("?") !== -1 ? "&" : "?"; var scheme = slideData.embedCode.indexOf('//') === 0 ? 'https:' : ''; @@ -510,16 +510,16 @@ params.autoplay = 1; } slideData.embedUrl = slideData.embedCode ? scheme + slideData.embedCode + separator + $.param(params) : ""; - } else if (slideData.type === 'infographic') { + } else if (slideData.category === 'infographic') { slideData.embedUrl = _.str.sprintf('/web/image/slide.slide/%s/image_1024', slideData.id); - } else if (_.contains(['document', 'presentation'], slideData.type)) { + } else if (_.contains(['document', 'presentation'], slideData.category)) { slideData.embedUrl = $(slideData.embedCode).attr('src'); } // fill empty property to allow searching on it with _.filter(list, matcher) slideData.isQuiz = !!slideData.isQuiz; slideData.hasQuestion = !!slideData.hasQuestion; // technical settings for the Fullscreen to work - slideData._autoSetDone = _.contains(['infographic', 'presentation', 'document', 'webpage'], slideData.type) && !slideData.hasQuestion; + slideData._autoSetDone = _.contains(['infographic', 'presentation', 'document', 'webpage'], slideData.category) && !slideData.hasQuestion; }); return slidesDataList; }, @@ -542,7 +542,7 @@ history.pushState(null, '', fullscreenUrl); }, /** - * Render the current slide content using specific mecanism according to slide type: + * Render the current slide content using specific mecanism according to slide category: * - simply append content (for webpage) * - template rendering (for image, document, ....) * - using a sub widget (quiz and video) @@ -556,19 +556,19 @@ $content.empty(); // display quiz slide, or quiz attached to a slide - if (slide.type === 'quiz' || slide.isQuiz) { + if (slide.category === 'quiz' || slide.isQuiz) { $content.addClass('bg-white'); var QuizWidget = new Quiz(this, slide, this.channel); return QuizWidget.appendTo($content); } // render slide content - if (_.contains(['document', 'presentation', 'infographic'], slide.type)) { + if (_.contains(['document', 'presentation', 'infographic'], slide.category)) { $content.html(QWeb.render('website.slides.fullscreen.content', {widget: this})); - } else if (slide.type === 'video') { + } else if (slide.category === 'video') { this.videoPlayer = new VideoPlayer(this, slide); return this.videoPlayer.appendTo($content); - } else if (slide.type === 'webpage'){ + } else if (slide.category === 'webpage'){ var $wpContainer = $('
').addClass('o_wslide_fs_webpage_content bg-white block w-100 overflow-auto'); $(slide.htmlContent).appendTo($wpContainer); $content.append($wpContainer); @@ -608,7 +608,7 @@ * Triggered whenever the user changes slides. * When the current slide is changed, widget will be automatically updated * and allowed to: fetch the content if needed, render it, update the url, - * and set slide as "completed" according to its type requirements. In + * and set slide as "completed" according to its category requirements. In * mobile case (i.e. limited screensize), sidebar will be toggled since * sidebar will block most or all of new slide visibility. * @@ -627,7 +627,7 @@ return self._renderSlide(); }).then(function() { if (slide._autoSetDone && !session.is_website_user) { // no useless RPC call - if (['document', 'presentation'].includes(slide.type)) { + if (['document', 'presentation'].includes(slide.category)) { // only set the slide as completed after iFrame is loaded to avoid concurrent execution with 'embedUrl' controller self.el.querySelector('iframe.o_wslides_iframe_viewer').addEventListener('load', () => self._setCompleted(slide.id)); } else { diff --git a/addons/website_slides/static/src/js/slides_course_quiz.js b/addons/website_slides/static/src/js/slides_course_quiz.js index 1adaa2c440c..a02d907630d 100644 --- a/addons/website_slides/static/src/js/slides_course_quiz.js +++ b/addons/website_slides/static/src/js/slides_course_quiz.js @@ -18,7 +18,7 @@ * This widget is responsible of displaying quiz questions and propositions. Submitting the quiz will fetch the * correction and decorate the answers according to the result. Error message or modal can be displayed. * - * This widget can be attached to DOM rendered server-side by `website_slides.slide_type_quiz` or + * This widget can be attached to DOM rendered server-side by `website_slides.slide_category_quiz` or * used client side (Fullscreen). * * Triggered events are : diff --git a/addons/website_slides/static/src/js/slides_upload.js b/addons/website_slides/static/src/js/slides_upload.js index 6e488328124..14c605ee323 100644 --- a/addons/website_slides/static/src/js/slides_upload.js +++ b/addons/website_slides/static/src/js/slides_upload.js @@ -10,7 +10,7 @@ var SlideUploadDialog = Dialog.extend({ template: 'website.slide.upload.modal', events: _.extend({}, Dialog.prototype.events, { 'click .o_wslides_js_upload_install_button': '_onClickInstallModule', - 'click .o_wslides_select_type': '_onClickSlideTypeIcon', + 'click .o_wslides_select_category': '_onClickSlideCategoryIcon', 'change input#upload': '_onChangeSlideUpload', 'change input#url': '_onChangeSlideUrl', }), @@ -120,7 +120,7 @@ var SlideUploadDialog = Dialog.extend({ return form[0].checkValidity() && this.isValidUrl; }, /** - * Extract values to submit from form, force the slide_type according to + * Extract values to submit from form, force the slide_category according to * filled values. * * @private @@ -136,30 +136,30 @@ var SlideUploadDialog = Dialog.extend({ 'is_published': forcePublished, }, this._getSelect2DropdownValues()); // add tags and category - // default slide_type (for webpage for instance) - if (_.contains(this.slide_type_data), this.get('state')) { - values['slide_type'] = this.get('state'); + // default slide_category (for webpage for instance) + if (_.contains(this.slide_category_data), this.get('state')) { + values['slide_category'] = this.get('state'); } if (this.file.type === 'application/pdf') { _.extend(values, { 'image_1920': canvas.toDataURL().split(',')[1], - 'slide_type': canvas.height > canvas.width ? 'document' : 'presentation', + 'slide_category': canvas.height > canvas.width ? 'document' : 'presentation', 'mime_type': this.file.type, - 'datas': this.file.data + 'binary_content': this.file.data }); - } else if (values['slide_type'] === 'webpage') { + } else if (values['slide_category'] === 'webpage') { _.extend(values, { 'mime_type': 'text/html', 'image_1920': this.file.type === 'image/svg+xml' ? await this._svgToPNG() : this.file.data, }); } else if (/^image\/.*/.test(this.file.type)) { const fileData = this.file.type === 'image/svg+xml' ? await this._svgToPNG() : this.file.data; - if (values['slide_type'] === 'presentation') { + if (values['slide_category'] === 'presentation') { _.extend(values, { - 'slide_type': 'infographic', + 'slide_category': 'infographic', 'mime_type': this.file.type === 'image/svg+xml' ? 'image/png' : this.file.type, - 'datas': fileData, + 'binary_content': fileData, }); } else { _.extend(values, { @@ -321,12 +321,12 @@ var SlideUploadDialog = Dialog.extend({ return values; }, /** - * Init the data relative to the support slide type to upload + * Init the data relative to the support slide category to upload * * @private */ _setup: function () { - this.slide_type_data = { + this.slide_category_data = { presentation: { icon: 'fa-file-pdf-o', label: _t('Presentation'), @@ -393,7 +393,7 @@ var SlideUploadDialog = Dialog.extend({ } else if (currentType === '_import') { tmpl = 'website.slide.upload.modal.import'; } else { - tmpl = this.slide_type_data[currentType]['template']; + tmpl = this.slide_category_data[currentType]['template']; this.$modal.find('.modal-dialog').addClass('modal-lg'); } this.$('.o_w_slide_upload_modal_container').empty(); @@ -623,10 +623,10 @@ var SlideUploadDialog = Dialog.extend({ } }, - _onClickSlideTypeIcon: function (ev) { + _onClickSlideCategoryIcon: function (ev) { var $elem = this.$(ev.currentTarget); - var slideType = $elem.data('slideType'); - this.set('state', slideType); + var slideCategory = $elem.data('slideCategory'); + this.set('state', slideCategory); this._bindSelect2Dropdown(); // rebind select2 at each modal body rendering }, diff --git a/addons/website_slides/static/src/js/tours/slides_tour.js b/addons/website_slides/static/src/js/tours/slides_tour.js index 83b40c98b3c..6d5396defcc 100644 --- a/addons/website_slides/static/src/js/tours/slides_tour.js +++ b/addons/website_slides/static/src/js/tours/slides_tour.js @@ -45,7 +45,7 @@ tour.register('slides_tour', { content: Markup(_t("Your first section is created, now it's time to add lessons to your course. Click on Add Content to upload a document, create a web page or link a video.")), position: 'bottom', }, { - trigger: 'a[data-slide-type="presentation"]', + trigger: 'a[data-slide-category="presentation"]', content: Markup(_t("First, let's add a Presentation. It can be a .pdf or an image.")), position: 'bottom', }, { diff --git a/addons/website_slides/static/src/tests/tours/slides_tour_tools.js b/addons/website_slides/static/src/tests/tours/slides_tour_tools.js index 1b891a9a476..62f7f4b334d 100644 --- a/addons/website_slides/static/src/tests/tours/slides_tour_tools.js +++ b/addons/website_slides/static/src/tests/tours/slides_tour_tools.js @@ -29,7 +29,7 @@ var addVideoToSection = function (sectionName, saveAsDraft) { trigger: 'div.o_wslides_slide_list_category_header:contains("' + sectionName + '") a:contains("Add Content")', }, { content: 'eLearning: click on video', - trigger: 'a[data-slide-type=video]', + trigger: 'a[data-slide-category=video]', }, { content: 'eLearning: fill video link', trigger: 'input[name=url]', @@ -63,7 +63,7 @@ var addWebPageToSection = function (sectionName, pageName) { trigger: 'div.o_wslides_slide_list_category_header:contains("' + sectionName + '") a:contains("Add Content")', }, { content: 'eLearning: click on webpage', - trigger: 'a[data-slide-type=webpage]', + trigger: 'a[data-slide-category=webpage]', }, { content: 'eLearning: fill webpage title', trigger: 'input[name=name]', diff --git a/addons/website_slides/static/src/xml/website_slides_fullscreen.xml b/addons/website_slides/static/src/xml/website_slides_fullscreen.xml index ceebb9d246c..f22d109bfb2 100644 --- a/addons/website_slides/static/src/xml/website_slides_fullscreen.xml +++ b/addons/website_slides/static/src/xml/website_slides_fullscreen.xml @@ -1,12 +1,12 @@ - +