From 93c6f77799912942254e369f709395cac75f1190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 12 Sep 2019 11:15:19 +0000 Subject: [PATCH 01/10] [FIX] mail: remove channel and partner default context keys when creating followers Purpose of this commit is to avoid conflicts when creating new followers with existing context keys. Indeed some actions may propagate a default partner id or channel id that is not wanted. Example if when inviting someone on a slide.channel in eLearning, a default_channel_id is set in context that clashes with follower creation, thinking it is a mail.channel. Task 2067872 (eLearning internal testing) PR #36756 --- addons/mail/models/mail_followers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mail/models/mail_followers.py b/addons/mail/models/mail_followers.py index 6c2f7c8376e..14e38e314d4 100644 --- a/addons/mail/models/mail_followers.py +++ b/addons/mail/models/mail_followers.py @@ -241,7 +241,7 @@ GROUP BY fol.id%s""" % ( :param check_existing: see ``_add_followers``; :param existing_policy: see ``_add_followers``; """ - sudo_self = self.sudo() + sudo_self = self.sudo().with_context(default_partner_id=False, default_channel_id=False) if not partner_subtypes and not channel_subtypes: # no subtypes -> default computation, no force, skip existing new, upd = self._add_default_followers(res_model, res_ids, partner_ids, channel_ids, customer_ids=customer_ids) else: From e3828ec9cdf46737fa552c6056921a63db9b9802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 12 Sep 2019 12:40:05 +0000 Subject: [PATCH 02/10] [FIX] survey: fix another crashing computed field Still due to some recent ORM changes: finding a real ID, assigning values even in create mode with default values. Task 2058598 (survey internal testing) PR #36756 --- addons/survey/models/survey_survey.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/addons/survey/models/survey_survey.py b/addons/survey/models/survey_survey.py index 5418d414603..f7f5c0b50a6 100644 --- a/addons/survey/models/survey_survey.py +++ b/addons/survey/models/survey_survey.py @@ -123,7 +123,11 @@ class Survey(models.Model): @api.depends('user_input_ids.state', 'user_input_ids.test_entry', 'user_input_ids.quizz_score', 'user_input_ids.quizz_passed') def _compute_survey_statistic(self): - stat = dict((cid, dict(answer_count=0, answer_done_count=0, success_count=0, answer_score_avg_total=0.0)) for cid in self.ids) + default_vals = { + 'answer_count': 0, 'answer_done_count': 0, 'success_count': 0, + 'answer_score_avg': 0.0, 'success_ratio': 0.0 + } + stat = dict((cid, dict(default_vals, answer_score_avg_total=0.0)) for cid in self.ids) UserInput = self.env['survey.user_input'] base_domain = ['&', ('survey_id', 'in', self.ids), ('test_entry', '!=', True)] @@ -136,11 +140,13 @@ class Survey(models.Model): if item['quizz_passed']: stat[item['survey_id'][0]]['success_count'] += item['__count'] + for survey_id, values in stat.items(): + avg_total = stat[survey_id].pop('answer_score_avg_total') + stat[survey_id]['answer_score_avg'] = avg_total / (stat[survey_id]['answer_done_count'] or 1) + stat[survey_id]['success_ratio'] = (stat[survey_id]['success_count'] / (stat[survey_id]['answer_done_count'] or 1.0))*100 + for survey in self: - avg_total = stat[survey.id].pop('answer_score_avg_total') - stat[survey.id]['answer_score_avg'] = avg_total / (stat[survey.id]['answer_done_count'] or 1) - stat[survey.id]['success_ratio'] = (stat[survey.id]['success_count'] / (stat[survey.id]['answer_done_count'] or 1.0))*100 - survey.update(stat[survey.id]) + survey.update(stat.get(survey._origin.id, default_vals)) def _compute_survey_url(self): """ Computes a public URL for the survey """ From 65c3be37fd284f42855e42b14953ebd9e6d9e6e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 12 Sep 2019 15:22:08 +0000 Subject: [PATCH 03/10] [FIX] survey: set email_from on certification mail template Otherwise public users cannot receive their certification. Indeed email_from will be the one of public user which is probably not set. Task 2067872 (eLearning internal testing) Task 2058598 (survey internal testing) PR #36756 --- addons/survey/data/mail_template_data.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/survey/data/mail_template_data.xml b/addons/survey/data/mail_template_data.xml index 42ed3ee42f3..96506fb928a 100644 --- a/addons/survey/data/mail_template_data.xml +++ b/addons/survey/data/mail_template_data.xml @@ -2,7 +2,7 @@ - Survey: Send by email + Survey: Invite Participate to ${object.survey_id.title} survey ${(object.partner_id.email_formatted or object.email) |safe} @@ -39,9 +39,10 @@ - Certification: Send by email + Survey: Send certification by email Certification: ${object.survey_id.display_name} + ${(object.survey_id.create_uid.email_formatted or user.email_formatted or user.company_id.catchall) |safe} ${(object.partner_id.email_formatted or object.email) |safe}
From 1dbeaddeae7d35ea367ceb4a033e97c0e1924f33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 13 Sep 2019 08:45:07 +0000 Subject: [PATCH 04/10] [FIX] website_profile: fix another broken image thingy As image fields have been renamed recently [1] we have to update controllers of profile in order to write on image_1920, not image anymore. Task 2067872 (eLearning internal testing) Task 2058598 (survey internal testing) PR #36756 [1] See 58a2ffa26f1a3b0f9630ce16d11b758d18e20a21 --- addons/website_profile/controllers/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/website_profile/controllers/main.py b/addons/website_profile/controllers/main.py index e11d68fa835..aaae098513b 100644 --- a/addons/website_profile/controllers/main.py +++ b/addons/website_profile/controllers/main.py @@ -137,10 +137,10 @@ class WebsiteProfile(http.Controller): } if 'clear_image' in kwargs: - values['image'] = False + values['image_1920'] = False elif kwargs.get('ufile'): image = kwargs.get('ufile').read() - values['image'] = base64.b64encode(image) + values['image_1920'] = base64.b64encode(image) if request.uid == user.id: # the controller allows to edit only its own privacy settings; use partner management for other cases values['website_published'] = kwargs.get('website_published') == 'True' From 477b73ed316307644876287c4f06c79a7afcc339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 12 Sep 2019 08:50:14 +0000 Subject: [PATCH 05/10] [FIX] website_slides: make content stat button redirection match counters Course content counters count only published content while content stat button redirects to all contents. Solution to this mismatch is to apply a search filter on button action to display published ontent by default. Also remove unnecessary action. Using a type="edit" seems sufficient, no need to define a python method just for that purpose. Task 2067324 (counters / action on content mismatch) PR #36756 --- addons/website_slides/models/slide_channel.py | 14 ++++---------- .../website_slides/views/slide_channel_views.xml | 2 +- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/addons/website_slides/models/slide_channel.py b/addons/website_slides/models/slide_channel.py index 49289105cd3..11ddec93597 100644 --- a/addons/website_slides/models/slide_channel.py +++ b/addons/website_slides/models/slide_channel.py @@ -481,18 +481,12 @@ class Channel(models.Model): if removed_channel_partner_domain: self.env['slide.channel.partner'].sudo().search(removed_channel_partner_domain).unlink() - def action_view(self): - return { - 'type': 'ir.actions.act_window', - 'view_type': 'form', - 'view_mode': 'form', - 'res_model': 'slide.channel', - 'res_id': self.id, - } - def action_view_slides(self): action = self.env.ref('website_slides.slide_slide_action').read()[0] - action['context'] = {'default_channel_id': self.id} + action['context'] = { + 'search_default_published': 1, + 'default_channel_id': self.id + } action['domain'] = [('channel_id', "=", self.id), ('is_category', '=', False)] return action diff --git a/addons/website_slides/views/slide_channel_views.xml b/addons/website_slides/views/slide_channel_views.xml index 1c41e55576c..2d5e08adcdd 100644 --- a/addons/website_slides/views/slide_channel_views.xml +++ b/addons/website_slides/views/slide_channel_views.xml @@ -236,7 +236,7 @@
From 98f847be3a7e2d3e28db977085a577b8295cc620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 12 Sep 2019 09:47:09 +0000 Subject: [PATCH 06/10] [FIX] website_{slides, profile}: fix display of not square user image When having not square images for user avatar several issues appear * website_slides: heroes of the week banner is broken as circles are not circles anymore. They look more like UFOs or funny snowmen; * website_slides: my user status / leaderboard / achievements card display is broken as image may take much more width than planned; * website_slides: channel page view displays user avatar when having joined it, and it is broken; * website_profile: user avatars in top 3 of users karma ranking is broken. In this commit we apply strict rules on width / height combined to an object fit in order to always have a bioutifoul displayed circled image. Task 2065425 (avatar ratio badly displayed) PR #36756 --- addons/website_profile/views/website_profile.xml | 4 +++- .../views/website_slides_templates_course.xml | 2 +- .../views/website_slides_templates_homepage.xml | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/addons/website_profile/views/website_profile.xml b/addons/website_profile/views/website_profile.xml index 4d77af30669..40330800585 100644 --- a/addons/website_profile/views/website_profile.xml +++ b/addons/website_profile/views/website_profile.xml @@ -514,7 +514,9 @@
- + User rank

diff --git a/addons/website_slides/views/website_slides_templates_course.xml b/addons/website_slides/views/website_slides_templates_course.xml index 1b92f589a5f..1361166321e 100644 --- a/addons/website_slides/views/website_slides_templates_course.xml +++ b/addons/website_slides/views/website_slides_templates_course.xml @@ -300,7 +300,7 @@ t-att-data-enroll="channel.enroll"> - +
You're enrolled
diff --git a/addons/website_slides/views/website_slides_templates_homepage.xml b/addons/website_slides/views/website_slides_templates_homepage.xml index ee959eccca3..5270ad3c532 100644 --- a/addons/website_slides/views/website_slides_templates_homepage.xml +++ b/addons/website_slides/views/website_slides_templates_homepage.xml @@ -14,8 +14,8 @@
+ style="width: 140px; height: 140px; max-width: 40%; max-height: 40%; object-fit: cover; border: 6px solid white;" + t-attf-src="/web/image/res.users/#{user['id']}/image_256"/>
@@ -99,7 +99,7 @@
- +
View @@ -451,7 +451,7 @@ From 0eec4d22a2768836891e682ffc172de5a5a23b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 12 Sep 2019 11:27:44 +0000 Subject: [PATCH 07/10] [FIX] website_slides: avoid admin being twice member of courses Since admin is responsible of all created demo channels and then re-added manually as member in demo data of slide.channel.partner he is actually twice member of some channels. This commit fixes that by resetting its membership status before adding membership demo data. PR #36756 --- .../tests/test_ui_wslides.py | 2 +- addons/website_slides/data/slide_user_demo.xml | 14 ++++++++++++++ addons/website_slides/models/slide_channel.py | 2 +- addons/website_slides/tests/test_ui_wslides.py | 9 ++++----- addons/website_slides_survey/models/survey_user.py | 2 +- 5 files changed, 21 insertions(+), 8 deletions(-) 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 c3e4431037a..e8c604dc812 100644 --- a/addons/test_website_slides_full/tests/test_ui_wslides.py +++ b/addons/test_website_slides_full/tests/test_ui_wslides.py @@ -14,7 +14,7 @@ class TestUi(tests.HttpCase): user_demo.write({ 'groups_id': [(5, 0), (4, self.env.ref('base.group_user').id)] }) - self.env.ref('website_slides.slide_channel_demo_6_furn3')._remove_membership(self.env.ref('base.partner_demo')) + self.env.ref('website_slides.slide_channel_demo_6_furn3')._remove_membership(self.env.ref('base.partner_demo').ids) self.phantom_js( '/slides', diff --git a/addons/website_slides/data/slide_user_demo.xml b/addons/website_slides/data/slide_user_demo.xml index 847d2bfa297..263d3ea443b 100644 --- a/addons/website_slides/data/slide_user_demo.xml +++ b/addons/website_slides/data/slide_user_demo.xml @@ -1,6 +1,20 @@ + + + diff --git a/addons/website_slides/models/slide_channel.py b/addons/website_slides/models/slide_channel.py index 11ddec93597..ce37f9e2ce4 100644 --- a/addons/website_slides/models/slide_channel.py +++ b/addons/website_slides/models/slide_channel.py @@ -474,7 +474,7 @@ class Channel(models.Model): for channel in self: removed_channel_partner_domain = expression.OR([ removed_channel_partner_domain, - [('partner_id', 'in', partner_ids.ids), + [('partner_id', 'in', partner_ids), ('channel_id', '=', channel.id)] ]) diff --git a/addons/website_slides/tests/test_ui_wslides.py b/addons/website_slides/tests/test_ui_wslides.py index 7d7b93bcb78..50fd212e698 100644 --- a/addons/website_slides/tests/test_ui_wslides.py +++ b/addons/website_slides/tests/test_ui_wslides.py @@ -13,7 +13,7 @@ class TestUi(tests.HttpCase): user_demo.write({ 'groups_id': [(5, 0), (4, self.env.ref('base.group_user').id)] }) - self.env.ref('website_slides.slide_channel_demo_0_gard_0')._remove_membership(self.env.ref('base.partner_demo')) + self.env.ref('website_slides.slide_channel_demo_0_gard_0')._remove_membership(self.env.ref('base.partner_demo').ids) self.phantom_js( '/slides', @@ -29,7 +29,7 @@ class TestUi(tests.HttpCase): user_demo.write({ 'groups_id': [(5, 0), (4, self.env.ref('base.group_user').id), (4, self.env.ref('website.group_website_publisher').id)] }) - self.env.ref('website_slides.slide_channel_demo_0_gard_0')._remove_membership(self.env.ref('base.partner_demo')) + self.env.ref('website_slides.slide_channel_demo_0_gard_0')._remove_membership(self.env.ref('base.partner_demo').ids) self.phantom_js( '/slides', @@ -42,7 +42,7 @@ class TestUi(tests.HttpCase): # group_website_designer user_portal = self.env.ref('base.demo_user0') user_portal.flush() - self.env.ref('website_slides.slide_channel_demo_0_gard_0')._remove_membership(self.env.ref('base.partner_demo_portal')) + self.env.ref('website_slides.slide_channel_demo_0_gard_0')._remove_membership(self.env.ref('base.partner_demo_portal').ids) self.phantom_js( '/slides', @@ -61,7 +61,7 @@ class TestUiYoutube(tests.HttpCase): user_demo.write({ 'groups_id': [(5, 0), (4, self.env.ref('base.group_user').id)] }) - self.env.ref('website_slides.slide_channel_demo_0_gard_0')._remove_membership(self.env.ref('base.partner_demo')) + self.env.ref('website_slides.slide_channel_demo_3_furn0')._remove_membership(self.env.ref('base.partner_demo').ids) self.phantom_js( '/slides', @@ -77,7 +77,6 @@ class TestUiYoutube(tests.HttpCase): user_demo.write({ 'groups_id': [(5, 0), (4, self.env.ref('base.group_user').id), (4, self.env.ref('website.group_website_designer').id)] }) - self.env.ref('website_slides.slide_channel_demo_0_gard_0')._remove_membership(self.env.ref('base.partner_demo')) self.phantom_js( '/slides', diff --git a/addons/website_slides_survey/models/survey_user.py b/addons/website_slides_survey/models/survey_user.py index ec658874ff5..9824bf78bc7 100644 --- a/addons/website_slides_survey/models/survey_user.py +++ b/addons/website_slides_survey/models/survey_user.py @@ -61,4 +61,4 @@ class SurveyUserInput(models.Model): removed_memberships_per_partner[user_input.partner_id] = removed_memberships for partner_id, removed_memberships in removed_memberships_per_partner.items(): - removed_memberships._remove_membership(partner_id) + removed_memberships._remove_membership(partner_id.ids) From 290341b4555a96ac0bc698054e2944ccc7d43518 Mon Sep 17 00:00:00 2001 From: Lucas Lefevre Date: Thu, 12 Sep 2019 11:31:04 +0000 Subject: [PATCH 08/10] [FIX] website_slides: still another fix of computed fields This commit fixes 2 issues coming from the recent ORM changes: records are new records in onchange and compute methods must assign a value for all records. In an onchange method, self.ids is a list of integer (real records) whereas self.id is a NewId (virtual record) Here a result dict was built using the reals ids as keys but later NewIds are used as keys. Solution is to use record._origin to access the real record. Moreover, the two dicts `result` and `type_stats` are the same. Assigning one into the other is useless. Task 2067872 (eLearning internal testing) PR #36756 --- addons/website_slides/models/slide_slide.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/addons/website_slides/models/slide_slide.py b/addons/website_slides/models/slide_slide.py index 1a99c84129a..69206edd916 100644 --- a/addons/website_slides/models/slide_slide.py +++ b/addons/website_slides/models/slide_slide.py @@ -265,7 +265,8 @@ class Slide(models.Model): 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. - result = {_id: {} for _id in self.ids} + keys = ['nbr_%s' % slide_type for slide_type in self.env['slide.slide']._fields['slide_type'].get_values(self.env)] + default_vals = dict((key, 0) for key in keys) res = self.env['slide.slide'].read_group( [('is_published', '=', True), ('category_id', 'in', self.ids), ('is_category', '=', False)], @@ -273,11 +274,9 @@ class Slide(models.Model): lazy=False) type_stats = self._compute_slides_statistics_type(res) - for cid, cdata in type_stats.items(): - result[cid].update(cdata) for record in self: - record.update(result[record.id]) + record.update(type_stats.get(record._origin.id, default_vals)) def _compute_slides_statistics_type(self, read_group_res): """ Compute statistics based on all existing slide types """ From 0b4d052bb56d1e384f714d72ecd73624b4adb697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 12 Sep 2019 12:11:56 +0000 Subject: [PATCH 09/10] [FIX] website_sale_slides: synchronize publish status of a channel and its product Currently when creating a payment-based channel with its product and then publishing the channel public users cannot browse the channel as the product is not readable. This commit fixes that by synchronizing the publish status of channels and their products. Task 2067872 (eLearning internal testing) PR #36756 --- .../website_sale_slides/models/slide_channel.py | 17 +++++++++++++++++ .../tests/test_course_purchase_flow.py | 1 + 2 files changed, 18 insertions(+) diff --git a/addons/website_sale_slides/models/slide_channel.py b/addons/website_sale_slides/models/slide_channel.py index 685e0af9aa0..bb95e2e0ab5 100644 --- a/addons/website_sale_slides/models/slide_channel.py +++ b/addons/website_sale_slides/models/slide_channel.py @@ -31,6 +31,23 @@ class Channel(models.Model): for channel in self: channel.product_sale_revenues = rg_data.get(channel.product_id.id, 0) + @api.model + def create(self, vals): + channel = super(Channel, self).create(vals) + if channel.enroll == 'payment': + channel._synchronize_product_publish() + return channel + + def write(self, vals): + res = super(Channel, self).write(vals) + if 'is_published' in vals: + self.filtered(lambda channel: channel.enroll == 'payment')._synchronize_product_publish() + return res + + def _synchronize_product_publish(self): + self.filtered(lambda channel: channel.is_published and not channel.product_id.is_published).sudo().product_id.write({'is_published': True}) + self.filtered(lambda channel: not channel.is_published and channel.product_id.is_published).sudo().product_id.write({'is_published': False}) + def action_view_sales(self): action = self.env.ref('website_sale_slides.sale_report_action_slides').read()[0] action['domain'] = [('product_id', 'in', self.product_id.ids)] diff --git a/addons/website_sale_slides/tests/test_course_purchase_flow.py b/addons/website_sale_slides/tests/test_course_purchase_flow.py index 8bce4fea63a..09db54f7f21 100644 --- a/addons/website_sale_slides/tests/test_course_purchase_flow.py +++ b/addons/website_sale_slides/tests/test_course_purchase_flow.py @@ -13,6 +13,7 @@ class TestCoursePurchaseFlow(common.SlidesCase): 'list_price': 150, 'type': 'service', 'invoice_policy': 'order', + 'is_published': True, }) self.channel.write({ From 6e5b211f4efd2f29b8bf582465284527e38bc763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 12 Sep 2019 13:12:17 +0000 Subject: [PATCH 10/10] [FIX] website_slides_survey: create certificates with scoring by default Certificate field is not sufficient, scoring type should be set by default to avoid creating non certificates without knowing it. Task 2067872 (eLearning internal testing) Task 2058598 (survey internal testing) PR #36756 --- addons/website_slides_survey/views/survey_survey_views.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/website_slides_survey/views/survey_survey_views.xml b/addons/website_slides_survey/views/survey_survey_views.xml index ff1d42e302e..93f7fe105ed 100644 --- a/addons/website_slides_survey/views/survey_survey_views.xml +++ b/addons/website_slides_survey/views/survey_survey_views.xml @@ -5,7 +5,7 @@ survey.survey kanban,tree,form [('certificate', '=', True)] - {'default_certificate': True} + {'default_certificate': True, 'default_scoring_type': 'scoring_with_answers'}

Add a new certification