From f9c2716b3e76ce9bc36d87d69a37a897391c9cdb Mon Sep 17 00:00:00 2001
From: Andrea Ulliana <aul@odoo.com>
Date: Thu, 13 Jun 2019 10:48:12 +0000
Subject: [PATCH] [IMP] website_forum: bring forum modes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

It is now possible to specify the forum mode : Questions and Answers or
Discussions. In Q&A mode, a user can only reply once while there is no
limit in Discussions mode.

task-2008910

closes odoo/odoo#34097

Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
---
 addons/website/static/src/xml/website.xml     |  2 +-
 addons/website_forum/controllers/main.py      |  4 +-
 addons/website_forum/models/forum.py          |  7 +-
 .../static/src/js/website_forum.editor.js     | 92 ++++++++++++-------
 .../src/xml/website_forum_templates.xml       | 30 ++++++
 addons/website_forum/tests/test_forum.py      | 46 ++++++++++
 addons/website_forum/views/forum.xml          | 13 ++-
 addons/website_forum/views/website_forum.xml  |  8 +-
 8 files changed, 154 insertions(+), 48 deletions(-)
 create mode 100644 addons/website_forum/static/src/xml/website_forum_templates.xml

diff --git a/addons/website/static/src/xml/website.xml b/addons/website/static/src/xml/website.xml
index 5f85f6d5d096..61528303768f 100644
--- a/addons/website/static/src/xml/website.xml
+++ b/addons/website/static/src/xml/website.xml
@@ -11,7 +11,7 @@
                     <main class="modal-body">
                         <form role="form" t-att-id="id">
                             <div class="form-group row mb0">
-                                <label for="page-name" class="col-md-3 col-form-label">
+                                <label for="page-name" class="col-md-4 col-form-label">
                                     <t t-esc="field_name"/>:
                                 </label>
                                 <div class="col-md-8">
diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py
index 272e119f94ca..dd247fbca147 100644
--- a/addons/website_forum/controllers/main.py
+++ b/addons/website_forum/controllers/main.py
@@ -48,8 +48,8 @@ class WebsiteForum(WebsiteProfile):
         return request.render("website_forum.forum_all", {'forums': forums})
 
     @http.route('/forum/new', type='json', auth="user", methods=['POST'], website=True)
-    def forum_create(self, forum_name="New Forum", add_menu=False):
-        forum_id = request.env['forum.forum'].create({'name': forum_name})
+    def forum_create(self, forum_name="New Forum", forum_mode="questions", add_menu=False):
+        forum_id = request.env['forum.forum'].create({'name': forum_name, 'mode': forum_mode})
         if add_menu:
             request.env['website.menu'].create({
                 'name': forum_name,
diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py
index 8056381da960..2092008b5ca2 100644
--- a/addons/website_forum/models/forum.py
+++ b/addons/website_forum/models/forum.py
@@ -30,6 +30,11 @@ class Forum(models.Model):
     # description and use
     name = fields.Char('Forum Name', required=True, translate=True)
     sequence = fields.Integer('Sequence', default=1)
+    mode = fields.Selection([
+        ('questions', 'Questions'),
+        ('discussions', 'Discussions')],
+        string='Forum Mode', required=True, default='questions',
+        help='Questions mode: only one answer allowed\n Discussions mode: multiple answers allowed')
     active = fields.Boolean(default=True)
     faq = fields.Html('Guidelines', default=_get_default_faq, translate=html_translate, sanitize=False)
     description = fields.Text(
@@ -64,7 +69,7 @@ class Forum(models.Model):
         ('vote_count desc', 'Most Voted'),
         ('relevancy desc', 'Relevance'),
         ('child_count desc', 'Answered')],
-        string='Default Order', required=True, default='write_date desc')
+        string='Default', required=True, default='write_date desc')
     relevancy_post_vote = fields.Float('First Relevance Parameter', default=0.8, help="This formula is used in order to sort by relevance. The variable 'votes' represents number of votes for a post, and 'days' is number of days since the post creation")
     relevancy_time_decay = fields.Float('Second Relevance Parameter', default=1.8)
     allow_bump = fields.Boolean('Allow Bump', default=True,
diff --git a/addons/website_forum/static/src/js/website_forum.editor.js b/addons/website_forum/static/src/js/website_forum.editor.js
index e2b19ba681f3..2f6d61791c8a 100644
--- a/addons/website_forum/static/src/js/website_forum.editor.js
+++ b/addons/website_forum/static/src/js/website_forum.editor.js
@@ -3,10 +3,61 @@ odoo.define('website_forum.editor', function (require) {
 
 var core = require('web.core');
 var WebsiteNewMenu = require('website.newMenu');
-var wUtils = require('website.utils');
+var Dialog = require('web.Dialog');
 
 var _t = core._t;
 
+var ForumCreateDialog = Dialog.extend({
+    xmlDependencies: Dialog.prototype.xmlDependencies.concat(
+        ['/website_forum/static/src/xml/website_forum_templates.xml']
+    ),
+    template: 'website_forum.add_new_forum',
+
+    /**
+     * @override
+     * @param {Object} parent
+     * @param {Object} options
+     */
+    init: function (parent, options) {
+        options = _.defaults(options || {}, {
+            title: _t("New Forum"),
+            size: 'medium',
+            buttons: [
+                {
+                    text: _t("Create"),
+                    classes: 'btn-primary',
+                    click: this.onCreateClick.bind(this),
+                },
+                {
+                    text: _t("Discard"),
+                    close: true
+                },
+            ]
+        });
+        this._super(parent, options);
+    },
+    onCreateClick: function () {
+        var $dialog = this.$el;
+        var forumName = $dialog.find('input[name=forum_name]').val();;
+        if (!forumName) {
+            return;
+        }
+        var addMenu = ($dialog.find('input[type="checkbox"]').is(':checked'));
+        var forumMode = $dialog.find('input[type="radio"]:checked').val();
+        return this._rpc({
+            route: '/forum/new',
+            params: {
+                forum_name: forumName,
+                forum_mode: forumMode,
+                add_menu: addMenu || "",
+            },
+        }).then(function (url) {
+            window.location.href = url;
+            return new Promise(function () {});
+        });
+    },
+});
+
 WebsiteNewMenu.include({
     actions: _.extend({}, WebsiteNewMenu.prototype.actions || {}, {
         new_forum: '_createNewForum',
@@ -25,41 +76,12 @@ WebsiteNewMenu.include({
      */
     _createNewForum: function () {
         var self = this;
-        return wUtils.prompt({
-            id: "editor_new_forum",
-            window_title: _t("New Forum"),
-            input: _t("Forum Name"),
-            init: function () {
-                var $group = this.$dialog.find("div.form-group");
-                $group.removeClass("mb0");
-
-                var $add = $(
-                    '<div class="form-group mb0">'+
-                        '<label class="offset-md-3 col-md-9 text-left">'+
-                        '    <input type="checkbox" required="required"/> '+
-                        '</label>'+
-                    '</div>');
-                $add.find('label').append(_t("Add to menu"));
-                $group.after($add);
-            }
-        }).then(function (result) {
-            var forum_name = result.val;
-            var $dialog = result.dialog;
-            if (!forum_name) {
-                return;
-            }
-            var add_menu = ($dialog.find('input[type="checkbox"]').is(':checked'));
-            return self._rpc({
-                route: '/forum/new',
-                params: {
-                    forum_name: forum_name,
-                    add_menu: add_menu || "",
-                },
-            }).then(function (url) {
-                window.location.href = url;
-                return new Promise(function () {});
-            });
+        var def = new Promise(function (resolve) {
+            var dialog = new ForumCreateDialog(self, {});
+            dialog.open();
+            dialog.on('closed', self, resolve);
         });
+        return def;
     },
 });
 });
diff --git a/addons/website_forum/static/src/xml/website_forum_templates.xml b/addons/website_forum/static/src/xml/website_forum_templates.xml
new file mode 100644
index 000000000000..0d3ce2407d0b
--- /dev/null
+++ b/addons/website_forum/static/src/xml/website_forum_templates.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates xml:space="preserve">
+    <t t-name="website_forum.add_new_forum">
+        <form id="editor_new_forum">
+            <div class="form-group row">
+                <label for="page-name" class="col-md-4 col-form-label">Forum Name:</label>
+                <div class="col-md-8">
+                    <input type="text" name="forum_name" class="form-control" required="required"/>
+                    <div class="custom-control custom-checkbox mt-2">
+                        <input type="checkbox" class="custom-control-input" id="add_to_menu" required="required"/>
+                        <label class="custom-control-label" for="add_to_menu">Add to menu</label>
+                    </div>
+                </div>
+            </div>
+            <div class="form-group row mt-2">
+                <label class="col-md-4 col-form-label">Forum Mode:</label>
+                <div class="col-md-8">
+                    <div class="custom-control custom-radio">
+                        <input type="radio" id="questions" name="mode" class="custom-control-input" value="questions" checked="checked"/>
+                        <label class="custom-control-label" for="questions">Questions and Answers</label>
+                    </div>
+                    <div class="custom-control custom-radio">
+                        <input type="radio" id="discussions" name="mode" class="custom-control-input" value="discussions"/>
+                        <label class="custom-control-label" for="discussions">Discussions</label>
+                    </div>
+                </div>
+            </div>
+        </form>
+    </t>
+</templates>
diff --git a/addons/website_forum/tests/test_forum.py b/addons/website_forum/tests/test_forum.py
index ab05ff003928..f52deea315a4 100644
--- a/addons/website_forum/tests/test_forum.py
+++ b/addons/website_forum/tests/test_forum.py
@@ -391,3 +391,49 @@ class TestForum(TestForumCommon):
     def test_unlink_post_all(self):
         self.user_portal.karma = KARMA['unlink_all']
         self.post.with_user(self.user_portal).unlink()
+
+    def test_forum_mode_questions(self):
+        Forum = self.env['forum.forum']
+        forum_questions = Forum.create({
+            'name': 'Questions Forum',
+            'mode': 'questions',
+            'active': True
+        })
+        Post = self.env['forum.post']
+        questions_post = Post.create({
+            'name': 'My First Post',
+            'forum_id': forum_questions.id,
+            'parent_id': self.post.id,
+        })
+        answer_to_questions_post = Post.create({
+            'name': 'This is an answer',
+            'forum_id': forum_questions.id,
+            'parent_id': questions_post.id,
+        })
+        self.assertEqual(
+            not questions_post.uid_has_answered or questions_post.forum_id.mode == 'discussions', False)
+        self.assertEqual(
+            questions_post.uid_has_answered and questions_post.forum_id.mode == 'questions', True)
+
+    def test_forum_mode_discussions(self):
+        Forum = self.env['forum.forum']
+        forum_discussions = Forum.create({
+            'name': 'Discussions Forum',
+            'mode': 'discussions',
+            'active': True
+        })
+        Post = self.env['forum.post']
+        discussions_post = Post.create({
+            'name': 'My First Post',
+            'forum_id': forum_discussions.id,
+            'parent_id': self.post.id,
+        })
+        answer_to_discussions_post = Post.create({
+            'name': 'This is an answer',
+            'forum_id': forum_discussions.id,
+            'parent_id': discussions_post.id,
+        })
+        self.assertEqual(
+            not discussions_post.uid_has_answered or discussions_post.forum_id.mode == 'discussions', True)
+        self.assertEqual(
+            discussions_post.uid_has_answered and discussions_post.forum_id.mode == 'questions', False)
diff --git a/addons/website_forum/views/forum.xml b/addons/website_forum/views/forum.xml
index 1c46079b5187..4e8cfc61e635 100644
--- a/addons/website_forum/views/forum.xml
+++ b/addons/website_forum/views/forum.xml
@@ -28,6 +28,7 @@
             <field name="arch" type="xml">
                 <form string="Forum">
                     <sheet>
+                        <field name="active" invisible="1"/>
                         <widget name="web_ribbon" text="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
                         <field name="image_1920" widget="image" options="{'preview_image': 'image_128'}" class="oe_avatar"/>
                         <div class="oe_title">
@@ -37,16 +38,15 @@
                             </h1>
                         </div>
                         <group>
-                            <field name="active" invisible="1"/>
-                            <field name="description"/>
+                            <field name="mode" widget="radio" required="True"/>
                             <field name="website_id" options="{'no_create': True}" groups="website.group_multi_website"/>
                         </group>
                         <notebook>
                             <page string="Options">
-                              <group string="Orders">
+                              <group string="Order">
                                 <field name="default_order"/>
-                                <label for="relevancy_post_vote" string="Relevance Computation" groups="base.group_no_one"/>
-                                <div groups="base.group_no_one" class="o_row">
+                                <label for="relevancy_post_vote" string="Relevance Computation" groups="base.group_no_one" attrs="{'invisible':[('default_order','!=','relevancy desc')]}"/>
+                                <div groups="base.group_no_one" class="o_row" attrs="{'invisible':[('default_order','!=','relevancy desc')]}">
                                     (votes - 1) ** <field name="relevancy_post_vote"/> / (days + 2) ** <field name="relevancy_time_decay"/>
                                 </div>
                               </group>
@@ -97,6 +97,9 @@
                                 </group>
                             </page>
                         </notebook>
+                        <group>
+                            <field name="description"/>
+                        </group>
                     </sheet>
                     <div class="oe_chatter">
                         <field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
diff --git a/addons/website_forum/views/website_forum.xml b/addons/website_forum/views/website_forum.xml
index e5737e037d1c..15ad892fa10b 100644
--- a/addons/website_forum/views/website_forum.xml
+++ b/addons/website_forum/views/website_forum.xml
@@ -830,10 +830,10 @@
             </t>
         </div>
         <div id="post_reply"
-                t-if="not question.uid_has_answered and question.state != 'close' and question.active != False and question.can_answer">
+                t-if="(not question.uid_has_answered or question.forum_id.mode == 'discussions') and question.state != 'close' and question.active != False and question.can_answer">
             <t t-call="website_forum.post_answer"/>
         </div>
-        <div t-if="question.uid_has_answered" class="mb16">
+        <div t-if="question.uid_has_answered and question.forum_id.mode == 'questions'" class="mb16">
             <a role="button" class="btn btn-primary" t-attf-href="/forum/#{slug(forum)}/question/#{slug(question)}/edit_answer">Edit Your Answer</a>
             <span class="text-muted">(only one answer per question is allowed)</span>
         </div>
@@ -852,10 +852,10 @@
                 <div class="col-1">
                     <t t-call="website_forum.vote">
                         <t t-set="post" t-value="answer"/>
-                        <div t-if="question.can_answer" class="mt4">
+                        <div t-if="question.can_answer and question.forum_id.mode == 'questions'" class="mt4">
                             <a t-attf-class="accept_answer fa fa-2x fa-check-circle no-decoration #{answer.is_correct and 'oe_answer_true' or 'oe_answer_false'} #{not answer.can_accept and 'karma_required' or ''}"
                                 t-attf-data-karma="#{answer.karma_accept}"
-                                aria-label="Send answer" title="Send answer"
+                                aria-label="Accept this answer as the best" title="Accept this answer as the best"
                                 t-attf-data-href="/forum/#{slug(question.forum_id)}/post/#{slug(answer)}/toggle_correct"
                                 t-if="not question.has_validated_answer"/>
                         </div>
-- 
GitLab