From f76ca21b15cfa67c04d5931efb4ac53a34a33e71 Mon Sep 17 00:00:00 2001
From: Parth Gajjar
Date: Thu, 29 Jan 2015 16:59:25 +0100
Subject: [PATCH] [IMP] website_forum : improve tag ordering, add 'in menu'
checkox when create a forum, customize welcome_message on a forum, better
fetch link title when insert it, display answers of a question on form view,
ans some changes in faq
---
addons/website_forum/controllers/main.py | 56 +++++--
.../website_forum/data/forum_default_faq.html | 44 +----
addons/website_forum/models/forum.py | 36 ++++-
.../static/src/css/website_forum.css | 12 +-
.../static/src/css/website_forum.sass | 6 +
.../static/src/js/website_forum.editor.js | 20 ++-
.../static/src/js/website_forum.js | 38 +++--
addons/website_forum/views/forum.xml | 48 +++---
addons/website_forum/views/website_forum.xml | 152 +++++++++++++-----
9 files changed, 272 insertions(+), 140 deletions(-)
diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py
index 828bcbbfa98..5daa2ddfb7c 100644
--- a/addons/website_forum/controllers/main.py
+++ b/addons/website_forum/controllers/main.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-
from datetime import datetime
import werkzeug.exceptions
import werkzeug.urls
@@ -8,15 +7,12 @@ import simplejson
import lxml
from urllib2 import urlopen, URLError
-from openerp import tools
+from openerp import tools, _
from openerp.addons.web import http
from openerp.addons.web.controllers.main import login_redirect
from openerp.addons.web.http import request
-from openerp.addons.website.controllers.main import Website as controllers
from openerp.addons.website.models.website import slug
-controllers = controllers()
-
class WebsiteForum(http.Controller):
_post_per_page = 10
@@ -37,7 +33,7 @@ class WebsiteForum(http.Controller):
'notifications': self._get_notifications(),
'header': kwargs.get('header', dict()),
'searches': kwargs.get('searches', dict()),
- 'no_introduction_message': request.httprequest.cookies.get('no_introduction_message', False),
+ 'forum_welcome_message': request.httprequest.cookies.get('forum_welcome_message', False),
'validation_email_sent': request.session.get('validation_email_sent', False),
'validation_email_done': request.session.get('validation_email_done', False),
}
@@ -86,8 +82,15 @@ class WebsiteForum(http.Controller):
return request.website.render("website_forum.forum_all", {'forums': forums})
@http.route('/forum/new', type='http', auth="user", methods=['POST'], website=True)
- def forum_create(self, forum_name="New Forum", **kwargs):
+ def forum_create(self, forum_name="New Forum", add_menu=False):
forum_id = request.env['forum.forum'].create({'name': forum_name})
+ if add_menu:
+ request.env['website.menu'].create({
+ 'name': forum_name,
+ 'url': "/forum/%s" % slug(forum_id),
+ 'parent_id': request.website.menu_id.id,
+ 'website_id': request.website.id,
+ })
return request.redirect("/forum/%s" % slug(forum_id))
@http.route('/forum/notification_read', type='json', auth="user", methods=['POST'], website=True)
@@ -166,16 +169,37 @@ class WebsiteForum(http.Controller):
)
return simplejson.dumps(data)
- @http.route(['/forum//tag'], type='http', auth="public", website=True)
- def tags(self, forum, page=1, **post):
- tags = request.env['forum.tag'].search([('forum_id', '=', forum.id), ('posts_count', '>', 0)], limit=None, order='posts_count DESC')
+ @http.route(['/forum//tag', '/forum//tag/'], type='http', auth="public", website=True)
+ def tags(self, forum, tag_char=None, **post):
+ # build the list of tag first char, with their value as tag_char param Ex : [('All', 'all'), ('C', 'c'), ('G', 'g'), ('Z', z)]
+ first_char_tag = forum.get_tags_first_char()
+ first_char_list = [(t, t.lower()) for t in first_char_tag]
+ first_char_list.insert(0, (_('All'), 'all'))
+ # get active first char tag
+ active_char_tag = first_char_list[1][1] if len(first_char_list) > 1 else 'all'
+ if tag_char:
+ active_char_tag = tag_char.lower()
+ # generate domain for searched tags
+ domain = [('forum_id', '=', forum.id), ('posts_count', '>', 0)]
+ order_by = 'name'
+ if active_char_tag and active_char_tag != 'all':
+ domain.append(('name', '=ilike', active_char_tag+'%'))
+ order_by = 'posts_count DESC'
+ tags = request.env['forum.tag'].search(domain, limit=None, order=order_by)
+ # prepare values and render template
values = self._prepare_forum_values(forum=forum, searches={'tags': True}, **post)
values.update({
'tags': tags,
- 'main_object': forum,
+ 'pager_tag_chars': first_char_list,
+ 'active_char_tag': active_char_tag,
})
return request.website.render("website_forum.tag", values)
+
+ @http.route('/forum//edit_welcome_message', auth="user", website=True)
+ def edit_welcome_message(self, forum, **kw):
+ return request.website.render("website_forum.edit_welcome_message", {'forum': forum})
+
# Questions
# --------------------------------------------------
@@ -339,17 +363,21 @@ class WebsiteForum(http.Controller):
'tags': tags,
'post': post,
'is_answer': bool(post.parent_id),
- 'searches': kwargs
+ 'searches': kwargs,
+ 'post_name': post.content_link,
+ 'content': post.name,
})
- return request.website.render("website_forum.edit_post", values)
+ template = "website_forum.new_link" if post.post_type == 'link' and not post.parent_id else "website_forum.edit_post"
+ return request.website.render(template, values)
@http.route('/forum//post//save', type='http', auth="user", methods=['POST'], website=True)
def post_save(self, forum, post, **kwargs):
- post_tags = forum._tag_to_write_vals(kwargs.get('post_tag', ''))
+ post_tags = forum._tag_to_write_vals(kwargs.get('post_tags', ''))
vals = {
'tag_ids': post_tags,
'name': kwargs.get('post_name'),
'content': kwargs.get('content'),
+ 'content_link': kwargs.get('content_link'),
}
post.write(vals)
question = post.parent_id if post.parent_id else post
diff --git a/addons/website_forum/data/forum_default_faq.html b/addons/website_forum/data/forum_default_faq.html
index 9891c930a21..f2169cd2616 100644
--- a/addons/website_forum/data/forum_default_faq.html
+++ b/addons/website_forum/data/forum_default_faq.html
@@ -86,52 +86,10 @@
input will be upvoted. On the other hand if the answer is misleading - it will
be downvoted. Each vote in favor will generate 10 points, each vote against
will subtract 10 points. There is a limit of 200 points that can be accumulated
- for a question or answer per day. The table below explains reputation point
+ for a question or answer per day. The table given at the end explains reputation point
requirements for each type of moderation task.
-
-
-
- 1
- upvote, add comments
-
- 10
- downvote
-
- 30
- insert text link, upload files
-
- 50
- insert clickable link, answer own question immediately
-
- 75
- retag, edit wiki questions and answers
-
- 100
- flag offensive, close own questions
-
- 200
- answer/comment by email
-
- 300
- edit any post, view offensive flags
-
- 500
- accept any answer (after 1 week)
-
- 750
- delete any comment
-
- 900
- lock posts
-
- 1000
- delete any question or answer
-
-
-
-
The goal of this site is create a relevant knowledge base that would answer
diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py
index db57629611c..10fc95d3c3b 100644
--- a/addons/website_forum/models/forum.py
+++ b/addons/website_forum/models/forum.py
@@ -46,12 +46,25 @@ class Forum(models.Model):
# description and use
name = fields.Char('Forum Name', required=True, translate=True)
faq = fields.Html('Guidelines', default=_get_default_faq, translate=True)
- description = fields.Html(
+ description = fields.Text(
'Description',
translate=True,
- default='
This community is for professionals and enthusiasts of our products and services.'
+ default='This community is for professionals and enthusiasts of our products and services.'
'Share and discuss the best content and new marketing ideas,'
- 'build your professional profile and become a better marketer together.
')
+ 'build your professional profile and become a better marketer together.')
+ welcome_message = fields.Html(
+ 'Welcome Message',
+ default = """
+
+
+
Welcome!
+
This community is for professionals and enthusiasts of our products and services. Share and discuss the best content and new marketing ideas, build your professional profile and become a better marketer together.
+
+
+
+
+ """)
default_order = fields.Selection([
('create_date desc', 'Newest'),
('write_date desc', 'Last Updated'),
@@ -59,7 +72,7 @@ class Forum(models.Model):
('relevancy desc', 'Relevancy'),
('child_count desc', 'Answered')],
string='Default Order', required=True, default='write_date desc')
- relevancy_post_vote = fields.Float('First Relevancy Parameter', default=0.8)
+ relevancy_post_vote = fields.Float('First Relevancy Parameter', default=0.8, help="This formula is used in order to sort by relevancy. 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 Relevancy Parameter', default=1.8)
default_post_type = fields.Selection([
('question', 'Question'),
@@ -119,6 +132,13 @@ class Forum(models.Model):
or (self.default_post_type == 'link' and not self.allow_link):
raise UserError(_('You cannot choose %s as default post since the forum does not allow it.' % self.default_post_type))
+ @api.one
+ @api.constrains('allow_link', 'allow_question', 'allow_discussion', 'default_post_type')
+ def _check_default_post_type(self):
+ if self.default_post_type == 'link' and not self.allow_link or self.default_post_type == 'question' and not self.allow_question or self.default_post_type == 'discussion' and not self.allow_discussion:
+ raise Warning(_('Post type in "Default post" must be activated'))
+
+
@api.model
def create(self, values):
return super(Forum, self.with_context(mail_create_nolog=True)).create(values)
@@ -145,8 +165,14 @@ class Forum(models.Model):
post_tags.insert(0, [6, 0, existing_keep])
return post_tags
+ def get_tags_first_char(self):
+ """ get set of first letter of forum tags """
+ tags = self.env['forum.tag'].search([('forum_id', '=', self.id), ('posts_count', '>', 0)])
+ return sorted(set([tag.name[0].upper() for tag in tags]))
+
class Post(models.Model):
+
_name = 'forum.post'
_description = 'Forum Post'
_inherit = ['mail.thread', 'website.seo.metadata']
@@ -210,7 +236,7 @@ class Post(models.Model):
vote.user_vote = mapped_vote.get(vote.id, 0)
@api.multi
- @api.depends('vote_ids')
+ @api.depends('vote_ids.vote')
def _get_vote_count(self):
read_group_res = self.env['forum.post.vote'].read_group([('post_id', 'in', self._ids)], ['post_id', 'vote'], ['post_id', 'vote'], lazy=False)
result = dict.fromkeys(self._ids, 0)
diff --git a/addons/website_forum/static/src/css/website_forum.css b/addons/website_forum/static/src/css/website_forum.css
index 79fd7dd330c..395167cf615 100644
--- a/addons/website_forum/static/src/css/website_forum.css
+++ b/addons/website_forum/static/src/css/website_forum.css
@@ -50,9 +50,17 @@ img.img-avatar {
.oe_answer_true {
color: #3c763d; }
+.forum_answer .oe_answer_true:hover {
+ color: #4D964E;
+}
+
.oe_answer_false {
color: #bbbbbb; }
+.oe_answer_false:hover {
+ color: #9E9C9C;
+}
+
.favourite_question {
color: #bbbbbb !important; }
@@ -100,4 +108,6 @@ a.no-decoration {
z-index: 5; }
button.btn-link.text-muted {
- color: #999999; }
+ color: #999999;
+}
+
diff --git a/addons/website_forum/static/src/css/website_forum.sass b/addons/website_forum/static/src/css/website_forum.sass
index 8ade74975ea..1313516a084 100644
--- a/addons/website_forum/static/src/css/website_forum.sass
+++ b/addons/website_forum/static/src/css/website_forum.sass
@@ -51,9 +51,15 @@ img.img-avatar
.oe_answer_true
color: #3c763d
+ &:hover {
+ color: #4D964E;
+ }
.oe_answer_false
color: #bbbbbb
+ &:hover {
+ color: #9E9C9C;
+ }
.favourite_question
color: #bbbbbb !important
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 6687ed5e3f2..b14191b3557 100644
--- a/addons/website_forum/static/src/js/website_forum.editor.js
+++ b/addons/website_forum/static/src/js/website_forum.editor.js
@@ -9,10 +9,24 @@
website.prompt({
id: "editor_new_forum",
window_title: _t("New Forum"),
- input: "Forum Name",
- }).then(function (forum_name) {
+ input: "Forum Name",init: function () {
+ var $group = this.$dialog.find("div.form-group");
+ $group.removeClass("mb0");
+
+ var $add = $(
+ ''+
+ ''+
+ ' '+
+ ' '+
+ '
');
+ $add.find('label').append(_t("Add page in menu"));
+ $group.after($add);
+ }
+ }).then(function (forum_name, field, $dialog) {
+ var add_menu = ($dialog.find('input[type="checkbox"]').is(':checked'));
website.form('/forum/new', 'POST', {
- forum_name: forum_name
+ forum_name: forum_name,
+ add_menu: add_menu || ""
});
});
},
diff --git a/addons/website_forum/static/src/js/website_forum.js b/addons/website_forum/static/src/js/website_forum.js
index 3d7ec8c8559..6abe4b97ffc 100644
--- a/addons/website_forum/static/src/js/website_forum.js
+++ b/addons/website_forum/static/src/js/website_forum.js
@@ -1,4 +1,6 @@
+
openerp.website.if_dom_contains('.website_forum', function () {
+ var _t = openerp._t;
$("[data-toggle='popover']").popover();
$('.karma_required').on('click', function (ev) {
var karma = $(ev.currentTarget).data('karma');
@@ -6,8 +8,8 @@
ev.preventDefault();
var $warning = $(''+
'× '+
- karma + ' karma is required to perform this action. You can earn karma by having '+
- 'your answers upvoted by the community.
');
+ karma + _t(' karma is required to perform this action. You can earn karma by having your answers upvoted by the community.')+
+ '');
var vote_alert = $(ev.currentTarget).parent().find("#vote_alert");
if (vote_alert.length == 0) {
$(ev.currentTarget).parent().append($warning);
@@ -24,12 +26,12 @@
if (data['error'] == 'own_post'){
var $warning = $(''+
'× '+
- 'Sorry, you cannot vote for your own posts'+
+ _t('Sorry, you cannot vote for your own posts')+
'
');
} else if (data['error'] == 'anonymous_user'){
var $warning = $(''+
'× '+
- 'Sorry you must be logged to vote'+
+ _t('Sorry you must be logged to vote')+
'
');
}
vote_alert = $link.parent().find("#vote_alert");
@@ -37,7 +39,7 @@
$link.parent().append($warning);
}
} else {
- $link.parent().find("#vote_count").html(data['vote_count']);
+ $link.parent().find(".vote_count").html(data['vote_count']);
if (data['user_vote'] == 0) {
$link.parent().find(".text-success").removeClass("text-success");
$link.parent().find(".text-warning").removeClass("text-warning");
@@ -60,7 +62,7 @@
if (data['error'] == 'anonymous_user') {
var $warning = $(''+
'× '+
- 'Sorry, anonymous users cannot choose correct answer.'+
+ _t('Sorry, anonymous users cannot choose correct answer.')+
'
');
}
correct_answer_alert = $link.parent().find("#correct_answer_alert");
@@ -69,6 +71,7 @@
}
} else {
if (data) {
+ $(".oe_answer_true").addClass('oe_answer_false').removeClass("oe_answer_true");
$link.addClass("oe_answer_true").removeClass('oe_answer_false');
} else {
$link.removeClass("oe_answer_true").addClass('oe_answer_false');
@@ -120,15 +123,22 @@
openerp.jsonRpc("/forum/validate_email/close", 'call', {});
});
+ // welcome message action button
+ var forum_login = _.string.sprintf('%s/web?redirect=%s',
+ window.location.origin, escape(window.location.href));
+ $('.forum_register_url').attr('href',forum_login);
$('.js_close_intro').on('click', function (ev) {
ev.preventDefault();
- document.cookie = "no_introduction_message = false";
+ document.cookie = "forum_welcome_message = false";
+ $('.forum_intro').slideUp();
return true;
});
+
$('.link_url').on('change', function (ev) {
ev.preventDefault();
+ var $link = $(ev.currentTarget);
var display_error = function(){
var $warning = $(''+
'
× '+
@@ -137,11 +147,13 @@
$link.parent().append($warning);
$("button#btn_post_your_article")[0].disabled = true;
};
- var $link = $(ev.currentTarget);
- if ($link.val().search("^http(s?)://.*")) {
- display_error();
- } else {
- openerp.jsonRpc("/forum/get_url_title", 'call', {'url': $link.val()}).then(function (data) {
+ var url = $link.val();
+ if (url.search("^http(s?)://.*")) {
+ url = 'http://'+url;
+ }
+ var regex = new RegExp("(http(s)?://.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)");
+ if(regex.test(url)){
+ openerp.jsonRpc("/forum/get_url_title", 'call', {'url': url}).then(function (data) {
if(data){
$("input[name='post_name']")[0].value = data;
$('button#btn_post_your_article').prop('disabled', false);
@@ -149,6 +161,8 @@
display_error();
}
});
+ }else{
+ display_error();
}
});
diff --git a/addons/website_forum/views/forum.xml b/addons/website_forum/views/forum.xml
index d9cbde28bd2..fd90550dd9d 100644
--- a/addons/website_forum/views/forum.xml
+++ b/addons/website_forum/views/forum.xml
@@ -32,27 +32,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- (votes - 1) ** / (days + 2) **
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ (votes - 1) ** / (days + 2) **
+
+
@@ -158,6 +150,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -176,13 +178,14 @@
-
+
+
@@ -206,6 +209,7 @@
tree,form,graph
+ {'search_default_questions':1}
diff --git a/addons/website_forum/views/website_forum.xml b/addons/website_forum/views/website_forum.xml
index 0ef3bb3d71c..b5c0615a2e1 100644
--- a/addons/website_forum/views/website_forum.xml
+++ b/addons/website_forum/views/website_forum.xml
@@ -45,15 +45,10 @@