From 81cebf3485684243b366a60741e45c4744ccf494 Mon Sep 17 00:00:00 2001
From: David Beguin <dbe@odoo.com>
Date: Tue, 26 Feb 2019 16:43:50 +0000
Subject: [PATCH] [FIX] website_slides : fix and add tests on karma gain

Fix karma channel completion computing and karma gain :
    set to complete only if not completed
    and handle eventual multi course completion
Removes unused karma gain rules.
Add karma unvote rule to loose the karma gained if user changes his mind.
Test karma gain on each users.
    Note : technically, public user could be member of a course,
    but functionally speaking, this case should and could never happen
    (it's a non sens anyway)
    -> public user has not been tested for this reason.

Task ID : 1943788
Closes PR #31321
---
 addons/website_slides/models/slide_channel.py | 20 ++--
 addons/website_slides/models/slide_slide.py   |  9 +-
 addons/website_slides/tests/__init__.py       |  1 +
 addons/website_slides/tests/test_karma.py     | 93 +++++++++++++++++++
 4 files changed, 114 insertions(+), 9 deletions(-)
 create mode 100644 addons/website_slides/tests/test_karma.py

diff --git a/addons/website_slides/models/slide_channel.py b/addons/website_slides/models/slide_channel.py
index 8f5e2918c0cd..941477e69b2c 100644
--- a/addons/website_slides/models/slide_channel.py
+++ b/addons/website_slides/models/slide_channel.py
@@ -46,15 +46,22 @@ class ChannelUsersRelation(models.Model):
             record.completion = math.ceil(100.0 * slide_done / slide_total)
 
     def _write(self, values):
+        partner_karma = False
         if 'completion' in values and values['completion'] >= 100:
             values['completed'] = True
-            result = super(ChannelUsersRelation, self)._write(values)
-            partner_has_completed = {channel_partner.partner_id.id: channel_partner.channel_id for channel_partner in self}
-            users = self.env['res.users'].sudo().search([('partner_id', 'in', list(partner_has_completed.keys()))])
+            incomplete_channel_partners = self.filtered(lambda cp: not cp.completed)
+            partner_karma = dict.fromkeys(incomplete_channel_partners.mapped('partner_id').ids, 0)
+            for channel_partner in incomplete_channel_partners:
+                partner_karma[channel_partner.partner_id.id] += channel_partner.channel_id.karma_gen_channel_finish
+            partner_karma = {partner_id: karma_to_add
+                             for partner_id, karma_to_add in partner_karma.items() if karma_to_add > 0}
+
+        result = super(ChannelUsersRelation, self)._write(values)
+
+        if partner_karma:
+            users = self.env['res.users'].sudo().search([('partner_id', 'in', list(partner_karma.keys()))])
             for user in users:
-                users.add_karma(partner_has_completed[user.partner_id.id].karma_gen_channel_finish)
-        else:
-            result = super(ChannelUsersRelation, self)._write(values)
+                users.add_karma(partner_karma[user.partner_id.id])
         return result
 
 
@@ -146,7 +153,6 @@ class Channel(models.Model):
     can_upload = fields.Boolean('Can Upload', compute='_compute_can_upload')
     # karma generation
     karma_gen_slide_vote = fields.Integer(string='Lesson voted', default=1)
-    karma_gen_channel_share = fields.Integer(string='Course shared', default=2)
     karma_gen_channel_rank = fields.Integer(string='Course ranked', default=5)
     karma_gen_channel_finish = fields.Integer(string='Course finished', default=10)
     # TODO DBE : Add karma based action rules (like in forum)
diff --git a/addons/website_slides/models/slide_slide.py b/addons/website_slides/models/slide_slide.py
index c98d0b9a69f9..2b4a13eefc18 100644
--- a/addons/website_slides/models/slide_slide.py
+++ b/addons/website_slides/models/slide_slide.py
@@ -395,7 +395,9 @@ class Slide(models.Model):
             ('slide_id', 'in', self.ids),
             ('partner_id', '=', self.env.user.partner_id.id)
         ])
-        new_slides = self_sudo - slide_partners.mapped('slide_id')
+        slide_id = slide_partners.mapped('slide_id')
+        new_slides = self_sudo - slide_id
+        channel = slide_id.channel_id
 
         for slide_partner in slide_partners:
             if upvote:
@@ -409,7 +411,10 @@ class Slide(models.Model):
             new_slide.write({
                 'slide_partner_ids': [(0, 0, {'vote': new_vote, 'partner_id': self.env.user.partner_id.id})]
             })
-            self.env.user.add_karma(new_slide.channel_id.karma_gen_slide_vote)
+        if new_vote != 0:
+            self.env.user.add_karma(channel.karma_gen_slide_vote)
+        else:
+            self.env.user.add_karma(-channel.karma_gen_slide_vote)
 
     def action_set_viewed(self, quiz_attempts_inc=False):
         if not all(slide.channel_id.is_member for slide in self):
diff --git a/addons/website_slides/tests/__init__.py b/addons/website_slides/tests/__init__.py
index c9a6c6174264..69bfc7de9e21 100644
--- a/addons/website_slides/tests/__init__.py
+++ b/addons/website_slides/tests/__init__.py
@@ -4,3 +4,4 @@
 from . import common
 from . import test_security
 from . import test_statistics
+from . import test_karma
diff --git a/addons/website_slides/tests/test_karma.py b/addons/website_slides/tests/test_karma.py
new file mode 100644
index 000000000000..df6d70823d4f
--- /dev/null
+++ b/addons/website_slides/tests/test_karma.py
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo.addons.website_slides.tests import common
+from odoo.tests import tagged
+from odoo.tools import mute_logger
+
+
+@tagged('functional')
+class TestKarmaGain(common.SlidesCase):
+
+    def setUp(self):
+        super(TestKarmaGain, self).setUp()
+
+        self.channel_2 = self.env['slide.channel'].sudo(self.user_publisher).create({
+            'name': 'Test Channel 2',
+            'channel_type': 'training',
+            'promote_strategy': 'most_voted',
+            'enroll': 'public',
+            'visibility': 'public',
+            'website_published': True,
+            'karma_gen_channel_finish': 100,
+        })
+
+        self.slide_2 = self.env['slide.slide'].sudo(self.user_publisher).create({
+            'name': 'How to travel through space and time',
+            'channel_id': self.channel_2.id,
+            'slide_type': 'presentation',
+            'website_published': True,
+            'completion_time': 2.0,
+        })
+
+        self.channel_3 = self.env['slide.channel'].sudo(self.user_publisher).create({
+            'name': 'Test Channel 3',
+            'channel_type': 'training',
+            'promote_strategy': 'most_voted',
+            'enroll': 'public',
+            'visibility': 'public',
+            'website_published': True,
+            'karma_gen_channel_finish': 50,
+        })
+
+        self.slide_3 = self.env['slide.slide'].sudo(self.user_publisher).create({
+            'name': 'How to duplicate yourself',
+            'channel_id': self.channel_3.id,
+            'slide_type': 'presentation',
+            'website_published': True,
+            'completion_time': 2.0,
+        })
+
+    def karma_gain_test(self, user):
+        # Add the user to the course
+        self.channel.sudo()._action_add_members(user.partner_id)
+
+        # Init user env
+        channel = self.channel.sudo(user)
+        slide = self.slide.sudo(user)
+        self.assertEqual(user.karma, 0)
+
+        # Finish the Course
+        karma = channel.karma_gen_channel_finish
+        slide.action_set_completed()
+        self.assertEqual(user.karma, karma)
+
+        # Vote for a slide
+        karma = karma + channel.karma_gen_slide_vote
+        slide.action_like()
+        self.assertEqual(user.karma, karma)
+        slide.action_dislike()
+        self.assertEqual(user.karma, karma - channel.karma_gen_slide_vote)
+        slide.action_dislike()
+        self.assertEqual(user.karma, karma)
+
+        # Finish two course at the same time (should not ever happen but hey, we never know)
+        self.channel_2.sudo()._action_add_members(user.partner_id)
+        self.channel_3.sudo()._action_add_members(user.partner_id)
+
+        karma = karma + self.channel_2.karma_gen_channel_finish + self.channel_3.karma_gen_channel_finish
+        slides = self.slide_2.sudo(user) | self.slide_3.sudo(user)
+        slides.action_set_completed()
+        self.assertEqual(user.karma, karma)
+
+    @mute_logger('odoo.models')
+    def test_users_karma_gain(self):
+        self.karma_gain_test(self.user_emp)
+
+    @mute_logger('odoo.models')
+    def test_user_publisher_karma_gain(self):
+        self.karma_gain_test(self.user_publisher)
+
+    @mute_logger('odoo.models')
+    def test_user_portal_karma_gain(self):
+        self.karma_gain_test(self.user_portal)
-- 
GitLab