From 1cb7290c2037dbd77caff71363756f3aaf042045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Warnon?= Date: Wed, 13 Feb 2019 09:10:50 +0000 Subject: [PATCH 1/6] [IMP] website_slides: add visibility criteria to some slide fields Task #1940360 Subtask of #1902304 Purpose ======= Some fields displayed on the slide.slide form view are not relevant for all slide_types and should be hidden. --- addons/website_slides/views/slide_slide_views.xml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/addons/website_slides/views/slide_slide_views.xml b/addons/website_slides/views/slide_slide_views.xml index 93eb04e9bb5..cad8d8ef74d 100644 --- a/addons/website_slides/views/slide_slide_views.xml +++ b/addons/website_slides/views/slide_slide_views.xml @@ -73,10 +73,13 @@ - + - - + + From 949f6412543ea030890f1b9090473264a1d20f04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Warnon?= Date: Fri, 15 Feb 2019 13:53:30 +0000 Subject: [PATCH 2/6] [FIX] website_slides: fix publisher slides frontend access Purpose ======= Website publisher should be allowed to access slides on the frontend even if he's not a member of the channel. --- addons/website_slides/controllers/main.py | 1 + addons/website_slides/views/website_slides_templates.xml | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py index 4b0db549ef6..b097c227f6b 100644 --- a/addons/website_slides/controllers/main.py +++ b/addons/website_slides/controllers/main.py @@ -244,6 +244,7 @@ class WebsiteSlides(WebsiteProfile): 'user': request.env.user, 'pager': pager, 'is_public_user': request.website.is_public_user(), + 'is_slides_publisher': request.env.user.has_group('website.group_website_publisher'), } if not request.env.user._is_public(): last_message_values = request.env['mail.message'].search([ diff --git a/addons/website_slides/views/website_slides_templates.xml b/addons/website_slides/views/website_slides_templates.xml index 6bbd8d91292..a8089a1ef93 100644 --- a/addons/website_slides/views/website_slides_templates.xml +++ b/addons/website_slides/views/website_slides_templates.xml @@ -273,7 +273,7 @@

- + @@ -324,7 +324,7 @@ t-att-alt="channel.name"/>
- + From b5c90c7866ebeb7d30d0ff0b0619dea874c35c4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Warnon?= Date: Wed, 13 Feb 2019 09:50:53 +0000 Subject: [PATCH 3/6] [IMP] survey: add a route to download a certification pdf Task #1940360 Subtask of #1902304 Purpose ======= This commit adds a route allowing to download a certification for a user that has succeeded it. It's currently not used in any views but it's a preliminary work for the future slide bridge. --- addons/survey/controllers/main.py | 33 +++++++++++++++++++++++++- addons/survey/views/survey_reports.xml | 2 +- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/addons/survey/controllers/main.py b/addons/survey/controllers/main.py index 488250ce4a1..1fca997541f 100644 --- a/addons/survey/controllers/main.py +++ b/addons/survey/controllers/main.py @@ -12,7 +12,7 @@ from math import ceil from odoo import fields, http, _ from odoo.addons.base.models.ir_ui_view import keep_query from odoo.exceptions import UserError -from odoo.http import request +from odoo.http import request, content_disposition from odoo.tools import ustr _logger = logging.getLogger(__name__) @@ -501,6 +501,37 @@ class Survey(http.Controller): # filter_finish: boolean => only finished surveys or not # + @http.route(['/survey//get_certification'], type='http', auth='user', methods=['POST'], website=True) + def survey_get_certification(self, survey_id, **kwargs): + """ The certification document can be downloaded as long as the user has succeeded the certification """ + survey = request.env['survey.survey'].sudo().search([ + ('id', '=', survey_id), + ('certificate', '=', True) + ]) + + if not survey: + # no certification found + return werkzeug.utils.redirect("/") + + succeeded_attempt = request.env['survey.user_input'].sudo().search([ + ('partner_id', '=', request.env.user.partner_id.id), + ('survey_id', '=', survey_id), + ('quizz_passed', '=', True) + ], limit=1) + + if not succeeded_attempt: + raise UserError(_("The user has not succeeded the certification")) + + report_sudo = request.env.ref('survey.certification_report').sudo() + + report = report_sudo.render_qweb_pdf([succeeded_attempt.id], data={'report_type': 'pdf'})[0] + reporthttpheaders = [ + ('Content-Type', 'application/pdf'), + ('Content-Length', len(report)), + ] + reporthttpheaders.append(('Content-Disposition', content_disposition('Certification.pdf'))) + return request.make_response(report, headers=reporthttpheaders) + def _prepare_result_dict(self, survey, current_filters=None): """Returns dictionary having values for rendering template""" current_filters = current_filters if current_filters else [] diff --git a/addons/survey/views/survey_reports.xml b/addons/survey/views/survey_reports.xml index fb8783b5136..28a41c6bffe 100644 --- a/addons/survey/views/survey_reports.xml +++ b/addons/survey/views/survey_reports.xml @@ -10,7 +10,7 @@ name="survey.certification_report_view" file="survey.certification_report_view" attachment="'certification.pdf'" - print_report_name="'Certification - %s' % (object.survey_id.name)" + print_report_name="'Certification - %s' % (object.survey_id.display_name)" /> From dcce7716b3202eabd77666bcaaee9040e6a5e5b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Warnon?= Date: Fri, 15 Feb 2019 11:16:16 +0000 Subject: [PATCH 4/6] [IMP] website_slides: support slide_type param in slides/all route Task #1940360 Subtask of #1902304 Purpose ======= The slide/all route now supports a 'slide_type' param that will filter channels to contain at least one slide of type 'slide_type'. This is a preliminary work for the slides_survey bridge. --- addons/website_slides/controllers/main.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py index b097c227f6b..df122e9d90c 100644 --- a/addons/website_slides/controllers/main.py +++ b/addons/website_slides/controllers/main.py @@ -75,7 +75,7 @@ class WebsiteSlides(WebsiteProfile): tags |= search_tag return tags - def _build_channel_domain(self, base_domain, **post): + def _build_channel_domain(self, base_domain, slide_type=None, **post): search_term = post.get('search') category_id = post.get('category_id') channel_tag_id = post.get('channel_tag_id') @@ -92,6 +92,9 @@ class WebsiteSlides(WebsiteProfile): domain = expression.AND([domain, [('tag_ids', 'in', [channel_tag_id])]]) elif tags: domain = expression.AND([domain, [('tag_ids', 'in', tags.ids)]]) + + if slide_type and 'nbr_%ss' % slide_type in request.env['slide.channel']: + domain = expression.AND([domain, [('nbr_%ss' % slide_type, '>', 0)]]) return domain # -------------------------------------------------- @@ -144,17 +147,19 @@ class WebsiteSlides(WebsiteProfile): }) @http.route('/slides/all', type='http', auth="public", website=True) - def slides_channel_all(self, **post): + def slides_channel_all(self, slide_type=None, **post): """ Home page displaying a list of courses displayed according to some criterion and search terms. + : param string slide_type: if provided, filter the slide.channels + to contain at least one slide of type 'slide_type' : param dict post: post parameters, including * search_term: keywords entered in the search box, used to filter on slide content; * category_id: id of a slide.category; * channel_tag_id: id of a channel.tag; """ domain = request.website.website_domain() - domain = self._build_channel_domain(domain, **post) + domain = self._build_channel_domain(domain, slide_type=slide_type, **post) order = self._channel_order_by_criterion.get(post.get('sorting', 'date'), 'create_date desc') From f322816ae826f14eafd6f1d4855b0e2a741530d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Warnon?= Date: Mon, 11 Feb 2019 14:03:02 +0000 Subject: [PATCH 5/6] [ADD] website_slides_survey: add a new bridge between slide and survey Task #1940360 Subtask of #1902304 Purpose ======= Adds certification capabilities to the website_slides module. Channel/courses can now include certifications as a new type of slide. This new type of slide is available as a "Certification" button on the slide creation frontend view (next to "Video", "Presentation", ...). Users have to link the slide to an actual survey that has the 'certificate' field set to true (that will populate the slide's survey_id field). Slides of type certification are handled in frontend in a very simple way for now: - A button "Begin certification" that redirects the user to the related survey frontend. - A button "Download certification" when the user has succeeded the certification. - When the survey is done, if it's linked to a slide, a button "Go back to course" allows the user to go back to the slide frontend. (There is a special use case for when the website_publisher designing the survey lands on a certification slide: he is allowed to test the survey with a survey_input created as test_entry) Survey creation as well as limited time, limited number of attempts, ... are still completely handled in the survey module. That means that the user will have to first create a suitable survey that is a certification and only then create a slide of type "certification" and link the created survey to it. Ideally, the taking of the survey should be transparently included in the slide frontend but it requires a full refactoring of the way surveys are submitted. This will most likely come in a later commit. This commit is an advanced merge of full eLearning module (see task #1902304). --- addons/survey/controllers/main.py | 28 +++-- addons/survey/models/survey_user.py | 5 + addons/website_slides/controllers/main.py | 20 ++-- .../website_slides/data/gamification_data.xml | 4 +- addons/website_slides/models/slide_channel.py | 53 ++++++--- addons/website_slides/models/slide_slide.py | 15 +++ addons/website_slides/static/src/js/slides.js | 4 + .../static/src/js/slides_upload.js | 40 +++++-- .../views/slide_slide_views.xml | 4 +- .../views/website_slides_templates.xml | 2 +- .../website_slides_templates_homepage.xml | 5 +- addons/website_slides_survey/__init__.py | 4 + addons/website_slides_survey/__manifest__.py | 26 +++++ .../controllers/__init__.py | 5 + .../website_slides_survey/controllers/main.py | 13 +++ .../controllers/slides.py | 49 ++++++++ .../controllers/survey.py | 22 ++++ .../data/gamification_data.xml | 12 ++ .../data/slide_slide_demo.xml | 13 +++ .../data/survey_demo.xml | 108 ++++++++++++++++++ .../website_slides_survey/models/__init__.py | 6 + .../models/slide_channel.py | 32 ++++++ .../models/slide_slide.py | 54 +++++++++ .../models/survey_survey.py | 16 +++ .../models/survey_user.py | 13 +++ .../security/ir.model.access.csv | 2 + .../src/js/slides_certification_download.js | 23 ++++ .../static/src/js/slides_upload.js | 96 ++++++++++++++++ .../static/src/xml/website_slide_upload.xml | 36 ++++++ addons/website_slides_survey/views/assets.xml | 12 ++ .../views/slide_channel_views.xml | 13 +++ .../views/slide_slide_views.xml | 15 +++ .../views/survey_templates.xml | 16 +++ .../views/website_slides_templates.xml | 28 +++++ .../website_slides_templates_homepage.xml | 12 ++ 35 files changed, 757 insertions(+), 49 deletions(-) create mode 100644 addons/website_slides_survey/__init__.py create mode 100644 addons/website_slides_survey/__manifest__.py create mode 100644 addons/website_slides_survey/controllers/__init__.py create mode 100644 addons/website_slides_survey/controllers/main.py create mode 100644 addons/website_slides_survey/controllers/slides.py create mode 100644 addons/website_slides_survey/controllers/survey.py create mode 100644 addons/website_slides_survey/data/gamification_data.xml create mode 100644 addons/website_slides_survey/data/slide_slide_demo.xml create mode 100644 addons/website_slides_survey/data/survey_demo.xml create mode 100644 addons/website_slides_survey/models/__init__.py create mode 100644 addons/website_slides_survey/models/slide_channel.py create mode 100644 addons/website_slides_survey/models/slide_slide.py create mode 100644 addons/website_slides_survey/models/survey_survey.py create mode 100644 addons/website_slides_survey/models/survey_user.py create mode 100644 addons/website_slides_survey/security/ir.model.access.csv create mode 100644 addons/website_slides_survey/static/src/js/slides_certification_download.js create mode 100644 addons/website_slides_survey/static/src/js/slides_upload.js create mode 100644 addons/website_slides_survey/static/src/xml/website_slide_upload.xml create mode 100644 addons/website_slides_survey/views/assets.xml create mode 100644 addons/website_slides_survey/views/slide_channel_views.xml create mode 100644 addons/website_slides_survey/views/slide_slide_views.xml create mode 100644 addons/website_slides_survey/views/survey_templates.xml create mode 100644 addons/website_slides_survey/views/website_slides_templates.xml create mode 100644 addons/website_slides_survey/views/website_slides_templates_homepage.xml diff --git a/addons/survey/controllers/main.py b/addons/survey/controllers/main.py index 1fca997541f..446caf6a55e 100644 --- a/addons/survey/controllers/main.py +++ b/addons/survey/controllers/main.py @@ -136,7 +136,7 @@ class Survey(http.Controller): elif error_key == 'answer_deadline' and answer_sudo.token: return request.render("survey.survey_expired", {'survey': survey_sudo}) elif error_key == 'answer_done' and answer_sudo.token: - return request.render("survey.sfinished", {'survey': survey_sudo, 'token': answer_sudo.token, 'answer': answer_sudo}) + return request.render("survey.sfinished", self._prepare_survey_finished_values(survey_sudo, answer_sudo, token=answer_sudo.token)) return werkzeug.utils.redirect("/") @@ -165,14 +165,23 @@ class Survey(http.Controller): return werkzeug.utils.redirect("/") try: - retry_answer_sudo = survey_sudo._create_answer(user=request.env.user, partner=answer_sudo.partner_id, email=answer_sudo.email, invite_token=answer_sudo.invite_token, **{ - 'input_type': answer_sudo.input_type, - 'deadline': answer_sudo.deadline, - }) + retry_answer_sudo = survey_sudo._create_answer( + user=request.env.user, + partner=answer_sudo.partner_id, + email=answer_sudo.email, + invite_token=answer_sudo.invite_token, + **self._prepare_retry_additional_values(answer_sudo) + ) except: return werkzeug.utils.redirect("/") return request.redirect('/survey/start/%s?%s' % (survey_sudo.access_token, keep_query('*', answer_token=retry_answer_sudo.token))) + def _prepare_retry_additional_values(self, answer): + return { + 'input_type': answer.input_type, + 'deadline': answer.deadline, + } + @http.route('/survey/start/', type='http', auth='public', website=True) def survey_start(self, survey_token, answer_token=None, email=False, **post): """ Start a survey by providing @@ -256,8 +265,7 @@ class Survey(http.Controller): data.update({'last': True}) return request.render('survey.survey', data) elif answer_sudo.state == 'done': # Display success message - return request.render('survey.sfinished', {'survey': survey_sudo, - 'answer': answer_sudo}) + return request.render('survey.sfinished', self._prepare_survey_finished_values(survey_sudo, answer_sudo)) elif answer_sudo.state == 'skip': flag = (True if prev and prev == 'prev' else False) page_or_question_id, last = survey_sudo.next_page_or_question(answer_sudo, answer_sudo.last_displayed_page_id.id, go_back=flag) @@ -627,3 +635,9 @@ class Survey(http.Controller): 'success_rate': round((quizz_passed_count / total_quizz_passed) * 100, 1) if total_quizz_passed > 0 else 0, 'graph_data': graph_data } + + def _prepare_survey_finished_values(self, survey, answer, token=False): + values = {'survey': survey, 'answer': answer} + if token: + values['token'] = token + return values diff --git a/addons/survey/models/survey_user.py b/addons/survey/models/survey_user.py index bf79968b381..86d810ca588 100644 --- a/addons/survey/models/survey_user.py +++ b/addons/survey/models/survey_user.py @@ -145,6 +145,11 @@ class SurveyUserInput(models.Model): if user_input.survey_id.certificate and user_input.quizz_passed and user_input.survey_id.certification_mail_template_id: user_input.survey_id.certification_mail_template_id.send_mail(user_input.id, notif_layout="mail.mail_notification_light") + @api.multi + def _get_survey_url(self): + self.ensure_one() + return '/survey/start/%s?answer_token=%s' % (self.survey_id.access_token, self.token) + class SurveyUserInputLine(models.Model): _name = 'survey.user_input_line' diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py index df122e9d90c..6a75730daa0 100644 --- a/addons/website_slides/controllers/main.py +++ b/addons/website_slides/controllers/main.py @@ -115,15 +115,19 @@ class WebsiteSlides(WebsiteProfile): # fetch 'latests achievements' for non logged people if request.env.user._is_public(): - achievements = request.env['gamification.badge.user'].sudo().search([], limit=5) + achievements = request.env['gamification.badge.user'].sudo().search([('badge_id.is_published', '=', True)], limit=5) challenges = None challenges_done = None else: achievements = None - challenges = request.env['gamification.challenge'].sudo().search([('category', '=', 'slides')], order='id asc', limit=5) + challenges = request.env['gamification.challenge'].sudo().search([ + ('category', '=', 'slides'), + ('reward_id.is_published', '=', True) + ], order='id asc', limit=5) challenges_done = request.env['gamification.badge.user'].sudo().search([ ('challenge_id', 'in', challenges.ids), - ('user_id', '=', request.env.user.id) + ('user_id', '=', request.env.user.id), + ('badge_id.is_published', '=', True) ]).mapped('challenge_id') # fetch 'heroes of the week' for non logged people @@ -325,8 +329,8 @@ class WebsiteSlides(WebsiteProfile): if not slide.channel_id.can_access_from_current_website(): raise werkzeug.exceptions.NotFound() - values = self._get_slide_detail(slide) self._set_viewed_slide(slide) + values = self._get_slide_detail(slide) # allow rating and comments if slide.channel_id.allow_comment: values.update({ @@ -422,9 +426,7 @@ class WebsiteSlides(WebsiteProfile): if (file_size / 1024.0 / 1024.0) > 25: return {'error': _('File is too big. File size cannot exceed 25MB')} - values = dict((fname, post[fname]) for fname in [ - 'name', 'url', 'tag_ids', 'slide_type', 'channel_id', - 'mime_type', 'datas', 'description', 'image', 'index_content', 'website_published'] if post.get(fname)) + values = dict((fname, post[fname]) for fname in self._get_valid_slide_post_values() if post.get(fname)) if post.get('category_id'): if post['category_id'][0] == 0: @@ -465,6 +467,10 @@ class WebsiteSlides(WebsiteProfile): redirect_url += "?enable_editor=1" return {'url': redirect_url} + def _get_valid_slide_post_values(self): + return ['name', 'url', 'tag_ids', 'slide_type', 'channel_id', + 'mime_type', 'datas', 'description', 'image', 'index_content', 'website_published'] + @http.route(['/slides/channel/tag/search_read'], type='json', auth='user', methods=['POST'], website=True) def slide_channel_tag_search_read(self, fields, domain): can_create = request.env['slide.channel.tag'].check_access_rights('create', raise_exception=False) diff --git a/addons/website_slides/data/gamification_data.xml b/addons/website_slides/data/gamification_data.xml index 3a82e567393..4bf7a829b9d 100644 --- a/addons/website_slides/data/gamification_data.xml +++ b/addons/website_slides/data/gamification_data.xml @@ -138,14 +138,14 @@ Get a certification count boolean - + higher [ ('completed', '=', True), (0, '=', 1) ] True - + user.partner_id.id diff --git a/addons/website_slides/models/slide_channel.py b/addons/website_slides/models/slide_channel.py index c94cda59b8c..ead43565bcb 100644 --- a/addons/website_slides/models/slide_channel.py +++ b/addons/website_slides/models/slide_channel.py @@ -157,9 +157,7 @@ class Channel(models.Model): @api.depends('slide_ids.slide_type', 'slide_ids.is_published', 'slide_ids.likes', 'slide_ids.dislikes', 'slide_ids.total_views') def _compute_slides_statistics(self): - result = dict.fromkeys(self.ids, dict( - nbr_presentations=0, nbr_documents=0, nbr_videos=0, nbr_infographics=0, nbr_webpages=0, - total_slides=0, total_views=0, total_votes=0, total_time=0)) + result = dict.fromkeys(self.ids, dict(total_slides=0, total_views=0, total_votes=0, total_time=0)) read_group_res = self.env['slide.slide'].read_group( [('is_published', '=', True), ('channel_id', 'in', self.ids)], ['channel_id', 'slide_type', 'likes', 'dislikes', 'total_views', 'completion_time'], @@ -167,19 +165,31 @@ class Channel(models.Model): lazy=False) for res_group in read_group_res: cid = res_group['channel_id'][0] - result[cid]['nbr_presentations'] += res_group.get('slide_type', '') == 'presentation' and res_group['__count'] or 0 - result[cid]['nbr_documents'] += res_group.get('slide_type', '') == 'document' and res_group['__count'] or 0 - result[cid]['nbr_videos'] += res_group.get('slide_type', '') == 'video' and res_group['__count'] or 0 - result[cid]['nbr_infographics'] += res_group.get('slide_type', '') == 'infographic' and res_group['__count'] or 0 - result[cid]['nbr_webpages'] += res_group.get('slide_type', '') == 'webpage' and res_group['__count'] or 0 result[cid]['total_slides'] += res_group['__count'] result[cid]['total_views'] += res_group.get('total_views', 0) result[cid]['total_votes'] += res_group.get('likes', 0) 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(): + result[cid].update(cdata) + for record in self: record.update(result[record.id]) + def _compute_slides_statistics_type(self, read_group_res): + """ Can be overridden to compute stats on added slide_types """ + result = dict.fromkeys(self.ids, dict(nbr_presentations=0, nbr_documents=0, nbr_videos=0, nbr_infographics=0, nbr_webpages=0)) + for res_group in read_group_res: + cid = res_group['channel_id'][0] + result[cid]['nbr_presentations'] += res_group.get('slide_type', '') == 'presentation' and res_group['__count'] or 0 + result[cid]['nbr_documents'] += res_group.get('slide_type', '') == 'document' and res_group['__count'] or 0 + result[cid]['nbr_videos'] += res_group.get('slide_type', '') == 'video' and res_group['__count'] or 0 + result[cid]['nbr_infographics'] += res_group.get('slide_type', '') == 'infographic' and res_group['__count'] or 0 + result[cid]['nbr_webpages'] += res_group.get('slide_type', '') == 'webpage' and res_group['__count'] or 0 + return result + @api.depends('slide_partner_ids') def _compute_user_statistics(self): current_user_info = self.env['slide.channel.partner'].sudo().search( @@ -382,10 +392,25 @@ class Category(models.Model): lazy=False) for res_group in res: result[res_group['category_id'][0]][res_group['slide_type']] = result[res_group['category_id'][0]].get(res_group['slide_type'], 0) + res_group['__count'] + for record in self: - record.nbr_presentations = result[record.id].get('presentation', 0) - record.nbr_documents = result[record.id].get('document', 0) - record.nbr_videos = result[record.id].get('video', 0) - record.nbr_infographics = result[record.id].get('infographic', 0) - record.nbr_webpages = result[record.id].get('webpage', 0) - record.total_slides = record.nbr_presentations + record.nbr_documents + record.nbr_videos + record.nbr_infographics + record.nbr_webpages + record.update(self._extract_count_presentations_type(result, record.id)) + + def _extract_count_presentations_type(self, result, record_id): + """ Can be overridden to compute stats on added slide_types """ + statistics = { + 'nbr_presentations': result[record_id].get('presentation', 0), + 'nbr_documents': result[record_id].get('document', 0), + 'nbr_videos': result[record_id].get('video', 0), + 'nbr_infographics': result[record_id].get('infographic', 0), + 'nbr_webpages': result[record_id].get('webpage', 0), + 'total_slides': 0 + } + + statistics['total_slides'] += statistics['nbr_presentations'] + statistics['total_slides'] += statistics['nbr_documents'] + statistics['total_slides'] += statistics['nbr_videos'] + statistics['total_slides'] += statistics['nbr_infographics'] + statistics['total_slides'] += statistics['nbr_webpages'] + + return statistics diff --git a/addons/website_slides/models/slide_slide.py b/addons/website_slides/models/slide_slide.py index 5ac61bbec39..5dc5dcc4d5a 100644 --- a/addons/website_slides/models/slide_slide.py +++ b/addons/website_slides/models/slide_slide.py @@ -126,6 +126,8 @@ class Slide(models.Model): partner_ids = fields.Many2many('res.partner', 'slide_slide_partner', 'slide_id', 'partner_id', string='Subscribers', groups='base.group_website_publisher') slide_partner_ids = fields.One2many('slide.slide.partner', 'slide_id', string='Subscribers information', groups='base.group_website_publisher') + user_membership_id = fields.Many2one('slide.slide.partner', string="Subscriber information", compute='_compute_user_membership_id', + help="Subscriber information for the current logged in user") # content slide_type = fields.Selection([ ('infographic', 'Infographic'), @@ -191,6 +193,19 @@ class Slide(models.Model): for slide in self: slide.slide_views = mapped_data.get(slide.id, 0) + @api.depends('slide_partner_ids.partner_id') + def _compute_user_membership_id(self): + slide_partners = self.env['slide.slide.partner'].sudo().search([ + ('slide_id', 'in', self.ids), + ('partner_id', '=', self.env.user.partner_id.id), + ]) + + for record in self: + record.user_membership_id = next( + (slide_partner for slide_partner in slide_partners if slide_partner.slide_id == record), + self.env['slide.slide.partner'] + ) + def _get_embed_code(self): base_url = request and request.httprequest.url_root or self.env['ir.config_parameter'].sudo().get_param('web.base.url') if base_url[-1] == '/': diff --git a/addons/website_slides/static/src/js/slides.js b/addons/website_slides/static/src/js/slides.js index 8692dd67a46..bda80f1e689 100644 --- a/addons/website_slides/static/src/js/slides.js +++ b/addons/website_slides/static/src/js/slides.js @@ -33,6 +33,9 @@ sAnimations.registry.websiteSlides = sAnimations.Class.extend({ return $.when.apply($, defs); }, }); + +return sAnimations.registry.websiteSlides; + }); //============================================================================== @@ -120,4 +123,5 @@ sAnimations.registry.websiteSlidesEmbed = sAnimations.Class.extend({ new SlideSocialEmbed(this, maxPage).attachTo($('.oe_slide_js_embed_code_widget')); }, }); + }); diff --git a/addons/website_slides/static/src/js/slides_upload.js b/addons/website_slides/static/src/js/slides_upload.js index 30901d80640..855b7e52932 100644 --- a/addons/website_slides/static/src/js/slides_upload.js +++ b/addons/website_slides/static/src/js/slides_upload.js @@ -150,11 +150,17 @@ var SlideUploadDialog = Dialog.extend({ 'image': this.file.type === 'image/svg+xml' ? this._svgToPng() : this.file.data, }); } else if (/^image\/.*/.test(this.file.type)) { - _.extend(values, { - 'slide_type': 'infographic', - 'mime_type': this.file.type === 'image/svg+xml' ? 'image/png' : this.file.type, - 'datas': this.file.type === 'image/svg+xml' ? this._svgToPng() : this.file.data - }); + if (values['slide_type'] === 'presentation') { + _.extend(values, { + 'slide_type': 'infographic', + 'mime_type': this.file.type === 'image/svg+xml' ? 'image/png' : this.file.type, + 'datas': this.file.type === 'image/svg+xml' ? this._svgToPng() : this.file.data + }); + } else { + _.extend(values, { + 'image': this.file.type === 'image/svg+xml' ? this._svgToPng() : this.file.data, + }); + } } return values; }, @@ -229,15 +235,18 @@ var SlideUploadDialog = Dialog.extend({ * @param {bool} true for multiple selection box, false for single selection * @param {Function} Function to fetch data from remote location should return $.deferred object * resolved data should be array of object with id and name. eg. [{'id': id, 'name': 'text'}, ...] + * @param {String} [nameKey='name'] (optional) the name key of the returned record + * ('name' if not provided) * @returns {Object} select2 wrapper object */ - _select2Wrapper: function (tag, multi, fetchFNC) { - return { + _select2Wrapper: function (tag, multi, fetchFNC, nameKey) { + nameKey = nameKey || 'name'; + + var values = { width: '100%', placeholder: tag, allowClear: true, formatNoMatches: false, - multiple: multi, selection_data: false, fetch_rpc_fnc: fetchFNC, formatSelection: function (data) { @@ -267,8 +276,8 @@ var SlideUploadDialog = Dialog.extend({ var that = this, tags = {results: []}; _.each(data, function (obj) { - if (that.matcher(query.term, obj.name)) { - tags.results.push({id: obj.id, text: obj.name}); + if (that.matcher(query.term, obj[nameKey])) { + tags.results.push({id: obj.id, text: obj[nameKey]}); } }); query.callback(tags); @@ -287,6 +296,12 @@ var SlideUploadDialog = Dialog.extend({ } } }; + + if (multi) { + values['multiple'] = true; + } + + return values; }, /** * Init the data relative to the support slide type to upload @@ -550,6 +565,9 @@ sAnimations.registry.websiteSlidesUpload = sAnimations.Class.extend({ }, }); -return SlideUploadDialog; +return { + SlideUploadDialog: SlideUploadDialog, + websiteSlidesUpload: sAnimations.registry.websiteSlidesUpload +}; }); diff --git a/addons/website_slides/views/slide_slide_views.xml b/addons/website_slides/views/slide_slide_views.xml index cad8d8ef74d..7e7fcdf92e4 100644 --- a/addons/website_slides/views/slide_slide_views.xml +++ b/addons/website_slides/views/slide_slide_views.xml @@ -47,9 +47,7 @@
diff --git a/addons/website_slides/views/website_slides_templates.xml b/addons/website_slides/views/website_slides_templates.xml index a8089a1ef93..af82d23701c 100644 --- a/addons/website_slides/views/website_slides_templates.xml +++ b/addons/website_slides/views/website_slides_templates.xml @@ -392,7 +392,7 @@
-
+
Slide image diff --git a/addons/website_slides/views/website_slides_templates_homepage.xml b/addons/website_slides/views/website_slides_templates_homepage.xml index 1366547b68b..caeab4f77df 100644 --- a/addons/website_slides/views/website_slides_templates_homepage.xml +++ b/addons/website_slides/views/website_slides_templates_homepage.xml @@ -22,12 +22,9 @@