[IMP] website_forum: bring forum modes

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>
This commit is contained in:
Andrea Ulliana
2019-08-02 16:32:29 +00:00
committed by Jeremy Kersten
parent cfeb8a5185
commit f9c2716b3e
8 changed files with 154 additions and 48 deletions
+1 -1
View File
@@ -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">
+2 -2
View File
@@ -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,
+6 -1
View File
@@ -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,
@@ -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;
},
});
});
@@ -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>
+46
View File
@@ -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)
+8 -5
View File
@@ -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"/>
+4 -4
View File
@@ -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>