[IMP] [FIX] website_forum: cleaned and improved the management of available actions based on the user's karma. The karma levels are now stored on the forum itself, allowing customization. The various check of karma are done at model level and not at controller level anymore, leading to a more secure and easier to inherit behavior.
This commit is contained in:
parent
9132b1d306
commit
2a4ec367a9
|
@ -12,7 +12,6 @@ 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
|
||||
from openerp.tools import html2plaintext
|
||||
|
||||
controllers = controllers()
|
||||
|
||||
|
@ -33,20 +32,12 @@ class WebsiteForum(http.Controller):
|
|||
return msg
|
||||
|
||||
def _prepare_forum_values(self, forum=None, **kwargs):
|
||||
Forum = request.registry['forum.forum']
|
||||
user = request.registry['res.users'].browse(request.cr, request.uid, request.uid, context=request.context)
|
||||
values = {'user': user,
|
||||
'is_public_user': user.id == request.website.user_id.id,
|
||||
'notifications': self._get_notifications(),
|
||||
'header': kwargs.get('header', dict()),
|
||||
'searches': kwargs.get('searches', dict()),
|
||||
'can_edit_own': True,
|
||||
'can_edit_all': user.karma > Forum._karma_modo_edit_all,
|
||||
'can_close_own': user.karma > Forum._karma_modo_close_own,
|
||||
'can_close_all': user.karma > Forum._karma_modo_close_all,
|
||||
'can_unlink_own': user.karma > Forum._karma_modo_unlink_own,
|
||||
'can_unlink_all': user.karma > Forum._karma_modo_unlink_all,
|
||||
'can_unlink_comment': user.karma > Forum._karma_modo_unlink_comment,
|
||||
}
|
||||
if forum:
|
||||
values['forum'] = forum
|
||||
|
@ -55,14 +46,6 @@ class WebsiteForum(http.Controller):
|
|||
values.update(kwargs)
|
||||
return values
|
||||
|
||||
def _has_enough_karma(self, karma_name, uid=None):
|
||||
Forum = request.registry['forum.forum']
|
||||
karma = hasattr(Forum, karma_name) and getattr(Forum, karma_name) or 0
|
||||
user = request.registry['res.users'].browse(request.cr, SUPERUSER_ID, uid or request.uid, context=request.context)
|
||||
if user.karma < karma:
|
||||
return False, {'error': 'not_enough_karma', 'karma': karma}
|
||||
return True, {}
|
||||
|
||||
# Forum
|
||||
# --------------------------------------------------
|
||||
|
||||
|
@ -244,10 +227,6 @@ class WebsiteForum(http.Controller):
|
|||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/ask_for_close', type='http', auth="user", methods=['POST'], website=True)
|
||||
def question_ask_for_close(self, forum, question, **post):
|
||||
check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_close_own' or '_karma_modo_close_all')
|
||||
if not check_res[0]:
|
||||
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
|
||||
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
Reason = request.registry['forum.post.reason']
|
||||
reason_ids = Reason.search(cr, uid, [], context=context)
|
||||
|
@ -272,42 +251,21 @@ class WebsiteForum(http.Controller):
|
|||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/close', type='http', auth="user", methods=['POST'], website=True)
|
||||
def question_close(self, forum, question, **post):
|
||||
check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_close_own' or '_karma_modo_close_all')
|
||||
if not check_res[0]:
|
||||
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
|
||||
|
||||
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {
|
||||
'state': 'close',
|
||||
'closed_uid': request.uid,
|
||||
'closed_date': datetime.today().strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT),
|
||||
'closed_reason_id': int(post.get('reason_id', False)),
|
||||
}, context=request.context)
|
||||
request.registry['forum.post'].close(request.cr, request.uid, [question.id], reason_id=int(post.get('reason_id', False)), context=request.context)
|
||||
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/reopen', type='http', auth="user", methods=['POST'], website=True)
|
||||
def question_reopen(self, forum, question, **kwarg):
|
||||
check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_close_own' or '_karma_modo_close_all')
|
||||
if not check_res[0]:
|
||||
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
|
||||
|
||||
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'state': 'active'}, context=request.context)
|
||||
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/delete', type='http', auth="user", methods=['POST'], website=True)
|
||||
def question_delete(self, forum, question, **kwarg):
|
||||
check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_unlink_own' or '_karma_modo_unlink_all')
|
||||
if not check_res[0]:
|
||||
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
|
||||
|
||||
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'active': False}, context=request.context)
|
||||
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/undelete', type='http', auth="user", methods=['POST'], website=True)
|
||||
def question_undelete(self, forum, question, **kwarg):
|
||||
check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_unlink_own' or '_karma_modo_unlink_all')
|
||||
if not check_res[0]:
|
||||
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
|
||||
|
||||
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'active': True}, context=request.context)
|
||||
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
|
||||
|
||||
|
@ -349,11 +307,6 @@ class WebsiteForum(http.Controller):
|
|||
return request.redirect('/')
|
||||
if not request.session.uid:
|
||||
return {'error': 'anonymous_user'}
|
||||
user = request.registry['res.users'].browse(request.cr, SUPERUSER_ID, request.uid, context=request.context)
|
||||
if post.parent_id.create_uid.id != uid and user.karma < request.registry['forum.forum']._karma_answer_accept_all:
|
||||
return {'error': 'not_enough_karma', 'karma': request.registry['forum.forum']._karma_answer_accept_all}
|
||||
if post.create_uid.id == user.id and user.karma < request.registry['forum.forum']._karma_answer_accept_own:
|
||||
return {'error': 'not_enough_karma', 'karma': request.registry['forum.forum']._karma_answer_accept_own}
|
||||
|
||||
# set all answers to False, only one can be accepted
|
||||
request.registry['forum.post'].write(cr, uid, [c.id for c in post.parent_id.child_ids], {'is_correct': False}, context=context)
|
||||
|
@ -362,10 +315,6 @@ class WebsiteForum(http.Controller):
|
|||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/delete', type='http', auth="user", methods=['POST'], website=True)
|
||||
def post_delete(self, forum, post, **kwargs):
|
||||
check_res = self._has_enough_karma(post.create_uid.id == request.uid and '_karma_modo_unlink_own' or '_karma_modo_unlink_all')
|
||||
if not check_res[0]:
|
||||
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
|
||||
|
||||
question = post.parent_id
|
||||
request.registry['forum.post'].unlink(request.cr, request.uid, [post.id], context=request.context)
|
||||
if question:
|
||||
|
@ -374,10 +323,6 @@ class WebsiteForum(http.Controller):
|
|||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/edit', type='http', auth="user", website=True)
|
||||
def post_edit(self, forum, post, **kwargs):
|
||||
check_res = self._has_enough_karma(post.create_uid.id == request.uid and '_karma_modo_edit_own' or '_karma_modo_edit_all')
|
||||
if not check_res[0]:
|
||||
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
|
||||
|
||||
tags = ""
|
||||
for tag_name in post.tag_ids:
|
||||
tags += tag_name.name + ","
|
||||
|
@ -419,9 +364,6 @@ class WebsiteForum(http.Controller):
|
|||
return {'error': 'anonymous_user'}
|
||||
if request.uid == post.create_uid.id:
|
||||
return {'error': 'own_post'}
|
||||
check_res = self._has_enough_karma('_karma_upvote')
|
||||
if not check_res[0]:
|
||||
return check_res[1]
|
||||
upvote = True if not post.user_vote > 0 else False
|
||||
return request.registry['forum.post'].vote(request.cr, request.uid, [post.id], upvote=upvote, context=request.context)
|
||||
|
||||
|
@ -431,9 +373,6 @@ class WebsiteForum(http.Controller):
|
|||
return {'error': 'anonymous_user'}
|
||||
if request.uid == post.create_uid.id:
|
||||
return {'error': 'own_post'}
|
||||
check_res = self._has_enough_karma('_karma_downvote')
|
||||
if not check_res[0]:
|
||||
return check_res[1]
|
||||
upvote = True if post.user_vote < 0 else False
|
||||
return request.registry['forum.post'].vote(request.cr, request.uid, [post.id], upvote=upvote, context=request.context)
|
||||
|
||||
|
@ -625,26 +564,25 @@ class WebsiteForum(http.Controller):
|
|||
# Messaging
|
||||
# --------------------------------------------------
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/comment/<model("mail.message"):comment>/convert_to_answer', type='http', auth="public", methods=['POST'], website=True)
|
||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/comment/<model("mail.message"):comment>/convert_to_answer', type='http', auth="user", methods=['POST'], website=True)
|
||||
def convert_comment_to_answer(self, forum, post, comment, **kwarg):
|
||||
body = comment.body
|
||||
request.registry['mail.message'].unlink(request.cr, request.uid, [comment.id], context=request.context)
|
||||
new_post_id = request.registry['forum.post'].convert_comment_to_answer(request.cr, request.uid, comment.id, context=request.context)
|
||||
if not new_post_id:
|
||||
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
|
||||
post = request.registry['forum.post'].browse(request.cr, request.uid, new_post_id, context=request.context)
|
||||
question = post.parent_id if post.parent_id else post
|
||||
for answer in question.child_ids:
|
||||
if answer.create_uid.id == request.uid:
|
||||
return self.post_comment(forum, answer, comment=html2plaintext(body))
|
||||
return self.post_new(forum, question, content=body)
|
||||
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/convert_to_comment', type='http', auth="user", methods=['POST'], website=True)
|
||||
def convert_answer_to_comment(self, forum, post, **kwarg):
|
||||
values = {
|
||||
'comment': html2plaintext(post.content),
|
||||
}
|
||||
question = post.parent_id
|
||||
request.registry['forum.post'].unlink(request.cr, SUPERUSER_ID, [post.id], context=request.context)
|
||||
return self.post_comment(forum, question, **values)
|
||||
new_msg_id = request.registry['forum.post'].convert_answer_to_comment(request.cr, request.uid, post.id, context=request.context)
|
||||
if not new_msg_id:
|
||||
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
|
||||
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
|
||||
|
||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/comment/<model("mail.message"):comment>/delete', type='json', auth="user", website=True)
|
||||
def delete_comment(self, forum, post, comment, **kwarg):
|
||||
request.registry['mail.message'].unlink(request.cr, SUPERUSER_ID, [comment.id], context=request.context)
|
||||
return True
|
||||
if not request.session.uid:
|
||||
return {'error': 'anonymous_user'}
|
||||
return request.registry['forum.post'].unlink(request.cr, request.uid, post.id, comment.id, context=request.context)
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
<record id="mt_question_new" model="mail.message.subtype">
|
||||
<field name="name">New Question</field>
|
||||
<field name="res_model">forum.post</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="description">New Question</field>
|
||||
</record>
|
||||
<record id="mt_question_edit" model="mail.message.subtype">
|
||||
|
@ -57,7 +57,7 @@
|
|||
<record id="mt_forum_answer_new" model="mail.message.subtype">
|
||||
<field name="name">New Answer</field>
|
||||
<field name="res_model">forum.forum</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="hidden" eval="False"/>
|
||||
<field name="parent_id" eval="ref('mt_answer_new')"/>
|
||||
<field name="relation_field">forum_id</field>
|
||||
|
|
|
@ -1,50 +1,63 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import openerp
|
||||
from openerp import tools
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.addons.website.models.website import slug
|
||||
from openerp.osv import osv, fields
|
||||
from openerp.tools import html2plaintext
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
class KarmaError(ValueError):
|
||||
""" Karma-related error, used for forum and posts. """
|
||||
pass
|
||||
|
||||
|
||||
class Forum(osv.Model):
|
||||
"""TDE TODO: set karma values for actions dynamic for a given forum"""
|
||||
_name = 'forum.forum'
|
||||
_description = 'Forums'
|
||||
_inherit = ['mail.thread', 'website.seo.metadata']
|
||||
# karma values
|
||||
_karma_upvote = 5 # done
|
||||
_karma_downvote = 50 # done
|
||||
_karma_answer_accept_own = 20 # done
|
||||
_karma_answer_accept_own_now = 50
|
||||
_karma_answer_accept_all = 500
|
||||
_karma_editor_link_files = 30 # done
|
||||
_karma_editor_clickable_link = 50
|
||||
_karma_comment = 1
|
||||
_karma_modo_retag = 75
|
||||
_karma_modo_flag = 100
|
||||
_karma_modo_flag_see_all = 300
|
||||
_karma_modo_unlink_comment = 750
|
||||
_karma_modo_edit_own = 1 # done
|
||||
_karma_modo_edit_all = 300 # done
|
||||
_karma_modo_close_own = 100 # done
|
||||
_karma_modo_close_all = 900 # done
|
||||
_karma_modo_unlink_own = 500 # done
|
||||
_karma_modo_unlink_all = 1000 # done
|
||||
# karma generation
|
||||
_karma_gen_quest_new = 2 # done
|
||||
_karma_gen_upvote_quest = 5 # done
|
||||
_karma_gen_downvote_quest = -2 # done
|
||||
_karma_gen_upvote_ans = 10 # done
|
||||
_karma_gen_downvote_ans = -2 # done
|
||||
_karma_gen_ans_accept = 2 # done
|
||||
_karma_gen_ans_accepted = 15 # done
|
||||
_karma_gen_ans_flagged = -100
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Name', required=True, translate=True),
|
||||
'faq': fields.html('Guidelines'),
|
||||
'description': fields.html('Description'),
|
||||
# karma generation
|
||||
'karma_gen_question_new': fields.integer('Karma earned for new questions'),
|
||||
'karma_gen_question_upvote': fields.integer('Karma earned for upvoting a question'),
|
||||
'karma_gen_question_downvote': fields.integer('Karma earned for downvoting a question'),
|
||||
'karma_gen_answer_upvote': fields.integer('Karma earned for upvoting an answer'),
|
||||
'karma_gen_answer_downvote': fields.integer('Karma earned for downvoting an answer'),
|
||||
'karma_gen_answer_accept': fields.integer('Karma earned for accepting an anwer'),
|
||||
'karma_gen_answer_accepted': fields.integer('Karma earned for having an answer accepted'),
|
||||
'karma_gen_answer_flagged': fields.integer('Karma earned for having an answer flagged'),
|
||||
# karma-based actions
|
||||
'karma_ask': fields.integer('Karma to ask a new question'),
|
||||
'karma_answer': fields.integer('Karma to answer a question'),
|
||||
'karma_edit_own': fields.integer('Karma to edit its own posts'),
|
||||
'karma_edit_all': fields.integer('Karma to edit all posts'),
|
||||
'karma_close_own': fields.integer('Karma to close its own posts'),
|
||||
'karma_close_all': fields.integer('Karma to close all posts'),
|
||||
'karma_unlink_own': fields.integer('Karma to delete its own posts'),
|
||||
'karma_unlink_all': fields.integer('Karma to delete all posts'),
|
||||
'karma_upvote': fields.integer('Karma to upvote'),
|
||||
'karma_downvote': fields.integer('Karma to downvote'),
|
||||
'karma_answer_accept_own': fields.integer('Karma to accept an answer on its own questions'),
|
||||
'karma_answer_accept_all': fields.integer('Karma to accept an answers to all questions'),
|
||||
'karma_editor_link_files': fields.integer('Karma for linking files (Editor)'),
|
||||
'karma_editor_clickable_link': fields.integer('Karma for clickable links (Editor)'),
|
||||
'karma_comment_own': fields.integer('Karma to comment its own posts'),
|
||||
'karma_comment_all': fields.integer('Karma to comment all posts'),
|
||||
'karma_comment_convert_own': fields.integer('Karma to convert its own answers to comments and vice versa'),
|
||||
'karma_comment_convert_all': fields.integer('Karma to convert all answers to answers and vice versa'),
|
||||
'karma_comment_unlink_own': fields.integer('Karma to unlink its own comments'),
|
||||
'karma_comment_unlink_all': fields.integer('Karma to unlinnk all comments'),
|
||||
'karma_retag': fields.integer('Karma to change question tags'),
|
||||
'karma_flag': fields.integer('Karma to flag a post as offensive'),
|
||||
}
|
||||
|
||||
def _get_default_faq(self, cr, uid, context=None):
|
||||
|
@ -56,6 +69,36 @@ class Forum(osv.Model):
|
|||
_defaults = {
|
||||
'description': 'This community is for professionals and enthusiasts of our products and services.',
|
||||
'faq': _get_default_faq,
|
||||
'karma_gen_question_new': 2,
|
||||
'karma_gen_question_upvote': 5,
|
||||
'karma_gen_question_downvote': -2,
|
||||
'karma_gen_answer_upvote': 10,
|
||||
'karma_gen_answer_downvote': -2,
|
||||
'karma_gen_answer_accept': 2,
|
||||
'karma_gen_answer_accepted': 15,
|
||||
'karma_gen_answer_flagged': -100,
|
||||
'karma_ask': 0,
|
||||
'karma_answer': 0,
|
||||
'karma_edit_own': 1,
|
||||
'karma_edit_all': 300,
|
||||
'karma_close_own': 100,
|
||||
'karma_close_all': 500,
|
||||
'karma_unlink_own': 500,
|
||||
'karma_unlink_all': 1000,
|
||||
'karma_upvote': 5,
|
||||
'karma_downvote': 50,
|
||||
'karma_answer_accept_own': 20,
|
||||
'karma_answer_accept_all': 500,
|
||||
'karma_editor_link_files': 20,
|
||||
'karma_editor_clickable_link': 20,
|
||||
'karma_comment_own': 1,
|
||||
'karma_comment_all': 1,
|
||||
'karma_comment_convert_own': 50,
|
||||
'karma_comment_convert_all': 500,
|
||||
'karma_comment_unlink_own': 50,
|
||||
'karma_comment_unlink_all': 500,
|
||||
'karma_retag': 75,
|
||||
'karma_flag': 500,
|
||||
}
|
||||
|
||||
def create(self, cr, uid, values, context=None):
|
||||
|
@ -139,6 +182,36 @@ class Post(osv.Model):
|
|||
res[post.id] = post.parent_id and post.parent_id.create_uid == post.create_uid or False
|
||||
return res
|
||||
|
||||
def _get_post_karma_rights(self, cr, uid, ids, field_name, arg, context=None):
|
||||
user = self.pool['res.users'].browse(cr, uid, uid, context=context)
|
||||
res = dict.fromkeys(ids, False)
|
||||
for post in self.browse(cr, uid, ids, context=context):
|
||||
res[post.id] = {
|
||||
'karma_ask': post.forum_id.karma_ask,
|
||||
'karma_answer': post.forum_id.karma_answer,
|
||||
'karma_accept': post.parent_id and post.parent_id.create_uid.id == uid and post.forum_id.karma_answer_accept_own or post.forum_id.karma_answer_accept_all,
|
||||
'karma_edit': post.create_uid.id == uid and post.forum_id.karma_edit_own or post.forum_id.karma_edit_all,
|
||||
'karma_close': post.create_uid.id == uid and post.forum_id.karma_close_own or post.forum_id.karma_close_all,
|
||||
'karma_unlink': post.create_uid.id == uid and post.forum_id.karma_unlink_own or post.forum_id.karma_unlink_all,
|
||||
'karma_upvote': post.forum_id.karma_upvote,
|
||||
'karma_downvote': post.forum_id.karma_downvote,
|
||||
'karma_comment': post.create_uid.id == uid and post.forum_id.karma_comment_own or post.forum_id.karma_comment_all,
|
||||
'karma_comment_convert': post.create_uid.id == uid and post.forum_id.karma_comment_convert_own or post.forum_id.karma_comment_convert_all,
|
||||
}
|
||||
res[post.id].update({
|
||||
'can_ask': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_ask'],
|
||||
'can_answer': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_answer'],
|
||||
'can_accept': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_accept'],
|
||||
'can_edit': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_edit'],
|
||||
'can_close': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_close'],
|
||||
'can_unlink': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_unlink'],
|
||||
'can_upvote': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_upvote'],
|
||||
'can_downvote': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_downvote'],
|
||||
'can_comment': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_comment'],
|
||||
'can_comment_convert': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_comment_convert'],
|
||||
})
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Title'),
|
||||
'forum_id': fields.many2one('forum.forum', 'Forum', required=True),
|
||||
|
@ -151,7 +224,7 @@ class Post(osv.Model):
|
|||
'website_message_ids': fields.one2many(
|
||||
'mail.message', 'res_id',
|
||||
domain=lambda self: [
|
||||
'&', ('model', '=', self._name), ('type', '=', 'comment')
|
||||
'&', ('model', '=', self._name), ('type', 'in', ['email', 'comment'])
|
||||
],
|
||||
string='Post Messages', help="Comments on forum post",
|
||||
),
|
||||
|
@ -203,6 +276,26 @@ class Post(osv.Model):
|
|||
'closed_reason_id': fields.many2one('forum.post.reason', 'Reason'),
|
||||
'closed_uid': fields.many2one('res.users', 'Closed by', select=1),
|
||||
'closed_date': fields.datetime('Closed on', readonly=True),
|
||||
# karma
|
||||
'karma_ask': fields.function(_get_post_karma_rights, string='Karma to ask', type='integer', multi='_get_post_karma_rights'),
|
||||
'karma_accept': fields.function(_get_post_karma_rights, string='Karma to accept this answer', type='integer', multi='_get_post_karma_rights'),
|
||||
'karma_edit': fields.function(_get_post_karma_rights, string='Karma to edit', type='integer', multi='_get_post_karma_rights'),
|
||||
'karma_close': fields.function(_get_post_karma_rights, string='Karma to close', type='integer', multi='_get_post_karma_rights'),
|
||||
'karma_unlink': fields.function(_get_post_karma_rights, string='Karma to unlink', type='integer', multi='_get_post_karma_rights'),
|
||||
'karma_upvote': fields.function(_get_post_karma_rights, string='Karma to upvote', type='integer', multi='_get_post_karma_rights'),
|
||||
'karma_downvote': fields.function(_get_post_karma_rights, string='Karma to downvote', type='integer', multi='_get_post_karma_rights'),
|
||||
'karma_comment': fields.function(_get_post_karma_rights, string='Karma to comment', type='integer', multi='_get_post_karma_rights'),
|
||||
'karma_comment_convert': fields.function(_get_post_karma_rights, string='karma to convert as a comment', type='integer', multi='_get_post_karma_rights'),
|
||||
# access rights
|
||||
'can_ask': fields.function(_get_post_karma_rights, string='Can Ask', type='boolean', multi='_get_post_karma_rights'),
|
||||
'can_accept': fields.function(_get_post_karma_rights, string='Can Accept', type='boolean', multi='_get_post_karma_rights'),
|
||||
'can_edit': fields.function(_get_post_karma_rights, string='Can Edit', type='boolean', multi='_get_post_karma_rights'),
|
||||
'can_close': fields.function(_get_post_karma_rights, string='Can Close', type='boolean', multi='_get_post_karma_rights'),
|
||||
'can_unlink': fields.function(_get_post_karma_rights, string='Can Unlink', type='boolean', multi='_get_post_karma_rights'),
|
||||
'can_upvote': fields.function(_get_post_karma_rights, string='Can Upvote', type='boolean', multi='_get_post_karma_rights'),
|
||||
'can_downvote': fields.function(_get_post_karma_rights, string='Can Downvote', type='boolean', multi='_get_post_karma_rights'),
|
||||
'can_comment': fields.function(_get_post_karma_rights, string='Can Comment', type='boolean', multi='_get_post_karma_rights'),
|
||||
'can_comment_convert': fields.function(_get_post_karma_rights, string='Can Convert to Comment', type='boolean', multi='_get_post_karma_rights'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
|
@ -219,41 +312,93 @@ class Post(osv.Model):
|
|||
context = {}
|
||||
create_context = dict(context, mail_create_nolog=True)
|
||||
post_id = super(Post, self).create(cr, uid, vals, context=create_context)
|
||||
# post message + subtype depending on parent_id
|
||||
if vals.get("parent_id"):
|
||||
parent = self.browse(cr, SUPERUSER_ID, vals['parent_id'], context=context)
|
||||
body = _('<p><a href="forum/%s/question/%s">New Answer Posted</a></p>' % (slug(parent.forum_id), slug(parent)))
|
||||
self.message_post(cr, uid, parent.id, subject=_('Re: %s') % parent.name, body=body, subtype='website_forum.mt_answer_new', context=context)
|
||||
post = self.browse(cr, SUPERUSER_ID, post_id, context=context) # SUPERUSER_ID to avoid read access rights issues when creating
|
||||
# karma-based access
|
||||
if post.parent_id and not post.can_ask:
|
||||
raise KarmaError('Not enough karma to create a new question')
|
||||
elif not post.parent_id and not post.can_answer:
|
||||
raise KarmaError('Not enough karma to answer to a question')
|
||||
# messaging and chatter
|
||||
base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
|
||||
if post.parent_id:
|
||||
body = _(
|
||||
'<p>A new answer for <i>%s</i> has been posted. <a href="%s/forum/%s/question/%s">Click here to access the post.</a></p>' %
|
||||
(post.parent_id.name, base_url, slug(post.parent_id.forum_id), slug(post.parent_id))
|
||||
)
|
||||
self.message_post(cr, uid, post.parent_id.id, subject=_('Re: %s') % post.parent_id.name, body=body, subtype='website_forum.mt_answer_new', context=context)
|
||||
else:
|
||||
self.message_post(cr, uid, post_id, subject=vals.get('name', ''), body=_('New Question Created'), subtype='website_forum.mt_question_new', context=context)
|
||||
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], self.pool['forum.forum']._karma_gen_quest_new, context=context)
|
||||
body = _(
|
||||
'<p>A new question <i>%s</i> has been asked on %s. <a href="%s/forum/%s/question/%s">Click here to access the question.</a></p>' %
|
||||
(post.name, post.forum_id.name, base_url, slug(post.forum_id), slug(post))
|
||||
)
|
||||
self.message_post(cr, uid, post_id, subject=post.name, body=body, subtype='website_forum.mt_question_new', context=context)
|
||||
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], post.forum_id.karma_gen_question_new, context=context)
|
||||
return post_id
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
Forum = self.pool['forum.forum']
|
||||
# update karma when accepting/rejecting answers
|
||||
posts = self.browse(cr, uid, ids, context=context)
|
||||
if 'state' in vals:
|
||||
if vals['state'] in ['active', 'close'] and any(not post.can_close for post in posts):
|
||||
raise KarmaError('Not enough karma to close or reopen a post.')
|
||||
if 'active' in vals:
|
||||
if any(not post.can_unlink for post in posts):
|
||||
raise KarmaError('Not enough karma to delete or reactivate a post')
|
||||
if 'is_correct' in vals:
|
||||
if any(not post.can_accept for post in posts):
|
||||
raise KarmaError('Not enough karma to accept or refuse an answer')
|
||||
# update karma except for self-acceptance
|
||||
mult = 1 if vals['is_correct'] else -1
|
||||
for post in self.browse(cr, uid, ids, context=context):
|
||||
if vals['is_correct'] != post.is_correct:
|
||||
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [post.create_uid.id], Forum._karma_gen_ans_accepted * mult, context=context)
|
||||
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], Forum._karma_gen_ans_accept * mult, context=context)
|
||||
if vals['is_correct'] != post.is_correct and post.create_uid.id != uid:
|
||||
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [post.create_uid.id], post.forum_id.karma_gen_answer_accepted * mult, context=context)
|
||||
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], post.forum_id.karma_gen_answer_accept * mult, context=context)
|
||||
if any(key not in ['state', 'active', 'is_correct', 'closed_uid', 'closed_date', 'closed_reason_id'] for key in vals.keys()) and any(not post.can_edit for post in posts):
|
||||
raise KarmaError('Not enough karma to edit a post.')
|
||||
|
||||
res = super(Post, self).write(cr, uid, ids, vals, context=context)
|
||||
# if post content modify, notify followers
|
||||
if 'content' in vals or 'name' in vals:
|
||||
for post in self.browse(cr, uid, ids, context=context):
|
||||
for post in posts:
|
||||
if post.parent_id:
|
||||
body, subtype = _('Answer Edited'), 'website_forum.mt_answer_edit'
|
||||
obj_id = post.parent_id.id
|
||||
else:
|
||||
body, subtype = _('Question Edited'), 'website_forum.mt_question_edit'
|
||||
obj_id = post.id
|
||||
self.message_post(cr, uid, obj_id, body=_(body), subtype=subtype, context=context)
|
||||
self.message_post(cr, uid, obj_id, body=body, subtype=subtype, context=context)
|
||||
return res
|
||||
|
||||
def close(self, cr, uid, ids, reason_id, context=None):
|
||||
if any(post.parent_id for post in self.browse(cr, uid, ids, context=context)):
|
||||
return False
|
||||
return self.pool['forum.post'].write(cr, uid, ids, {
|
||||
'state': 'close',
|
||||
'closed_uid': uid,
|
||||
'closed_date': datetime.today().strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT),
|
||||
'closed_reason_id': reason_id,
|
||||
}, context=context)
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
posts = self.browse(cr, uid, ids, context=context)
|
||||
if any(not post.can_unlink for post in posts):
|
||||
raise KarmaError('Not enough karma to unlink a post')
|
||||
# if unlinking an answer with accepted answer: remove provided karma
|
||||
for post in posts:
|
||||
if post.is_correct:
|
||||
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [post.create_uid.id], post.forum_id.karma_gen_answer_accepted * -1, context=context)
|
||||
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], post.forum_id.karma_gen_answer_accept * -1, context=context)
|
||||
return super(Post, self).unlink(cr, uid, ids, context=context)
|
||||
|
||||
def vote(self, cr, uid, ids, upvote=True, context=None):
|
||||
posts = self.browse(cr, uid, ids, context=context)
|
||||
|
||||
if upvote and any(not post.can_upvote for post in posts):
|
||||
raise KarmaError('Not enough karma to upvote.')
|
||||
elif not upvote and any(not post.can_downvote for post in posts):
|
||||
raise KarmaError('Not enough karma to downvote.')
|
||||
|
||||
Vote = self.pool['forum.post.vote']
|
||||
vote_ids = Vote.search(cr, uid, [('post_id', 'in', ids), ('user_id', '=', uid)], context=context)
|
||||
vote_ids = Vote.search(cr, uid, [('post_id', 'in', ids), ('user_id', '=', uid)], limit=1, context=context)
|
||||
if vote_ids:
|
||||
for vote in Vote.browse(cr, uid, vote_ids, context=context):
|
||||
if upvote:
|
||||
|
@ -267,6 +412,89 @@ class Post(osv.Model):
|
|||
Vote.create(cr, uid, {'post_id': post_id, 'vote': new_vote}, context=context)
|
||||
return {'vote_count': self._get_vote_count(cr, uid, ids, None, None, context=context)[ids[0]]}
|
||||
|
||||
def convert_answer_to_comment(self, cr, uid, id, context=None):
|
||||
""" Tools to convert an answer (forum.post) to a comment (mail.message).
|
||||
The original post is unlinked and a new comment is posted on the question
|
||||
using the post create_uid as the comment's author. """
|
||||
post = self.browse(cr, uid, id, context=context)
|
||||
if not post.parent_id:
|
||||
return False
|
||||
|
||||
# karma-based action check: use the post field that computed own/all value
|
||||
if not post.can_comment_convert:
|
||||
raise KarmaError('Not enough karma to convert an answer to a comment')
|
||||
|
||||
# post the message
|
||||
question = post.parent_id
|
||||
values = {
|
||||
'author_id': post.create_uid.partner_id.id,
|
||||
'body': html2plaintext(post.content),
|
||||
'type': 'comment',
|
||||
'subtype': 'mail.mt_comment',
|
||||
'date': post.create_date,
|
||||
}
|
||||
message_id = self.pool['forum.post'].message_post(
|
||||
cr, uid, question.id,
|
||||
context=dict(context, mail_create_nosubcribe=True),
|
||||
**values)
|
||||
|
||||
# unlink the original answer, using SUPERUSER_ID to avoid karma issues
|
||||
self.pool['forum.post'].unlink(cr, SUPERUSER_ID, [post.id], context=context)
|
||||
|
||||
return message_id
|
||||
|
||||
def convert_comment_to_answer(self, cr, uid, message_id, default=None, context=None):
|
||||
""" Tool to convert a comment (mail.message) into an answer (forum.post).
|
||||
The original comment is unlinked and a new answer from the comment's author
|
||||
is created. Nothing is done if the comment's author already answered the
|
||||
question. """
|
||||
comment = self.pool['mail.message'].browse(cr, SUPERUSER_ID, message_id, context=context)
|
||||
post = self.pool['forum.post'].browse(cr, uid, comment.res_id, context=context)
|
||||
user = self.pool['res.users'].browse(cr, uid, uid, context=context)
|
||||
if not comment.author_id or not comment.author_id.user_ids: # only comment posted by users can be converted
|
||||
return False
|
||||
|
||||
# karma-based action check: must check the message's author to know if own / all
|
||||
karma_convert = comment.author_id.id == user.partner_id.id and post.forum_id.karma_comment_convert_own or post.forum_id.karma_comment_convert_all
|
||||
can_convert = uid == SUPERUSER_ID or user.karma >= karma_convert
|
||||
if not can_convert:
|
||||
raise KarmaError('Not enough karma to convert a comment to an answer')
|
||||
|
||||
# check the message's author has not already an answer
|
||||
question = post.parent_id if post.parent_id else post
|
||||
post_create_uid = comment.author_id.user_ids[0]
|
||||
if any(answer.create_uid.id == post_create_uid.id for answer in question.child_ids):
|
||||
return False
|
||||
|
||||
# create the new post
|
||||
post_values = {
|
||||
'forum_id': question.forum_id.id,
|
||||
'content': comment.body,
|
||||
'parent_id': question.id,
|
||||
}
|
||||
# done with the author user to have create_uid correctly set
|
||||
new_post_id = self.pool['forum.post'].create(cr, post_create_uid.id, post_values, context=context)
|
||||
|
||||
# delete comment
|
||||
self.pool['mail.message'].unlink(cr, SUPERUSER_ID, [comment.id], context=context)
|
||||
|
||||
return new_post_id
|
||||
|
||||
def unlink_comment(self, cr, uid, id, message_id, context=None):
|
||||
comment = self.pool['mail.message'].browse(cr, SUPERUSER_ID, message_id, context=context)
|
||||
post = self.pool['forum.post'].browse(cr, uid, id, context=context)
|
||||
user = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context)
|
||||
if not comment.model == 'forum.post' or not comment.res_id == id:
|
||||
return False
|
||||
|
||||
# karma-based action check: must check the message's author to know if own or all
|
||||
karma_unlink = comment.author_id.id == user.partner_id.id and post.forum_id.karma_comment_unlink_own or post.forum_id.karma_comment_unlink_all
|
||||
can_unlink = uid == SUPERUSER_ID or user.karma >= karma_unlink
|
||||
if not can_unlink:
|
||||
raise KarmaError('Not enough karma to unlink a comment')
|
||||
|
||||
return self.pool['mail.message'].unlink(cr, SUPERUSER_ID, [message_id], context=context)
|
||||
|
||||
def set_viewed(self, cr, uid, ids, context=None):
|
||||
cr.execute("""UPDATE forum_post SET views = views+1 WHERE id IN %s""", (tuple(ids),))
|
||||
return True
|
||||
|
@ -300,31 +528,31 @@ class Vote(osv.Model):
|
|||
'vote': lambda *args: '1',
|
||||
}
|
||||
|
||||
def _get_karma_value(self, old_vote, new_vote, up_karma, down_karma):
|
||||
_karma_upd = {
|
||||
'-1': {'-1': 0, '0': -1 * down_karma, '1': -1 * down_karma + up_karma},
|
||||
'0': {'-1': 1 * down_karma, '0': 0, '1': up_karma},
|
||||
'1': {'-1': -1 * up_karma + down_karma, '0': -1 * up_karma, '1': 0}
|
||||
}
|
||||
return _karma_upd[old_vote][new_vote]
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
vote_id = super(Vote, self).create(cr, uid, vals, context=context)
|
||||
if vals.get('vote', '1') == '1':
|
||||
karma = self.pool['forum.forum']._karma_upvote
|
||||
elif vals.get('vote', '1') == '-1':
|
||||
karma = self.pool['forum.forum']._karma_downvote
|
||||
post = self.pool['forum.post'].browse(cr, uid, vals['post_id'], context=context)
|
||||
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [post.create_uid.id], karma, context=context)
|
||||
vote = self.browse(cr, uid, vote_id, context=context)
|
||||
if vote.post_id.parent_id:
|
||||
karma_value = self._get_karma_value('0', vote.vote, vote.post_id.forum_id.karma_gen_answer_upvote, vote.post_id.forum_id.karma_gen_answer_downvote)
|
||||
else:
|
||||
karma_value = self._get_karma_value('0', vote.vote, vote.post_id.forum_id.karma_gen_question_upvote, vote.post_id.forum_id.karma_gen_question_downvote)
|
||||
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [vote.post_id.create_uid.id], karma_value, context=context)
|
||||
return vote_id
|
||||
|
||||
def write(self, cr, uid, ids, values, context=None):
|
||||
def _get_karma_value(old_vote, new_vote, up_karma, down_karma):
|
||||
_karma_upd = {
|
||||
'-1': {'-1': 0, '0': -1 * down_karma, '1': -1 * down_karma + up_karma},
|
||||
'0': {'-1': 1 * down_karma, '0': 0, '1': up_karma},
|
||||
'1': {'-1': -1 * up_karma + down_karma, '0': -1 * up_karma, '1': 0}
|
||||
}
|
||||
return _karma_upd[old_vote][new_vote]
|
||||
if 'vote' in values:
|
||||
Forum = self.pool['forum.forum']
|
||||
for vote in self.browse(cr, uid, ids, context=context):
|
||||
if vote.post_id.parent_id:
|
||||
karma_value = _get_karma_value(vote.vote, values['vote'], Forum._karma_gen_upvote_ans, Forum._karma_gen_downvote_ans)
|
||||
karma_value = self._get_karma_value(vote.vote, values['vote'], vote.post_id.forum_id.karma_gen_answer_upvote, vote.post_id.forum_id.karma_gen_answer_downvote)
|
||||
else:
|
||||
karma_value = _get_karma_value(vote.vote, values['vote'], Forum._karma_gen_upvote_quest, Forum._karma_gen_downvote_quest)
|
||||
karma_value = self._get_karma_value(vote.vote, values['vote'], vote.post_id.forum_id.karma_gen_question_upvote, vote.post_id.forum_id.karma_gen_question_downvote)
|
||||
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [vote.post_id.create_uid.id], karma_value, context=context)
|
||||
res = super(Vote, self).write(cr, uid, ids, values, context=context)
|
||||
return res
|
||||
|
|
|
@ -104,6 +104,14 @@ a.no-decoration {
|
|||
height: 1.2em !important;
|
||||
}
|
||||
|
||||
.oe_forum_alert {
|
||||
position: absolute;
|
||||
margin-top: -30px;
|
||||
margin-left: 90px;
|
||||
width: 300px;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
button.btn-link.text-muted {
|
||||
color: #999999;
|
||||
}
|
||||
|
|
|
@ -84,5 +84,12 @@ a.no-decoration
|
|||
font: 1.2em "Helvetica Neue", Helvetica, Arial, sans-serif !important
|
||||
height: 1.2em !important
|
||||
|
||||
.oe_forum_alert
|
||||
position: absolute
|
||||
margin-top: -30px
|
||||
margin-left: 90px
|
||||
width: 300px
|
||||
z-index: 9999
|
||||
|
||||
button.btn-link.text-muted
|
||||
color: #999
|
||||
|
|
|
@ -1,28 +1,37 @@
|
|||
$(document).ready(function () {
|
||||
|
||||
$('.vote_up ,.vote_down').on('click', function (ev) {
|
||||
$('.karma_required').on('click', function (ev) {
|
||||
var karma = $(ev.currentTarget).data('karma');
|
||||
if (karma) {
|
||||
ev.preventDefault();
|
||||
var $warning = $('<div class="alert alert-danger alert-dismissable oe_forum_alert" id="karma_alert">'+
|
||||
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">×</button>'+
|
||||
karma + ' karma is required to perform this action. You can earn karma by answering questions or having '+
|
||||
'your answers upvoted by the community.</div>');
|
||||
var vote_alert = $(ev.currentTarget).parent().find("#vote_alert");
|
||||
if (vote_alert.length == 0) {
|
||||
$(ev.currentTarget).parent().append($warning);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('.vote_up,.vote_down').not('.karma_required').on('click', function (ev) {
|
||||
ev.preventDefault();
|
||||
var $link = $(ev.currentTarget);
|
||||
openerp.jsonRpc($link.data('href'), 'call', {})
|
||||
.then(function (data) {
|
||||
if (data['error']){
|
||||
if (data['error'] == 'own_post'){
|
||||
var $warning = $('<div class="alert alert-danger alert-dismissable" id="vote_alert" style="position:absolute; margin-top: -30px; margin-left: 90px;">'+
|
||||
var $warning = $('<div class="alert alert-danger alert-dismissable oe_forum_alert" id="vote_alert">'+
|
||||
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">×</button>'+
|
||||
'Sorry, you cannot vote for your own posts'+
|
||||
'</div>');
|
||||
} else if (data['error'] == 'anonymous_user'){
|
||||
var $warning = $('<div class="alert alert-danger alert-dismissable" id="vote_alert" style="position:absolute; margin-top: -30px; margin-left: 90px;">'+
|
||||
var $warning = $('<div class="alert alert-danger alert-dismissable oe_forum_alert" id="vote_alert">'+
|
||||
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">×</button>'+
|
||||
'Sorry you must be logged to vote'+
|
||||
'</div>');
|
||||
}
|
||||
else if (data['error'] == 'not_enough_karma') {
|
||||
var $warning = $('<div class="alert alert-danger alert-dismissable" id="vote_alert" style="max-width: 500px; position:absolute; margin-top: -30px; margin-left: 90px;">'+
|
||||
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">×</button>'+
|
||||
'Sorry, at least ' + data['karma'] + ' karma is required to vote. You can gain karma by answering questions and receiving votes.'+
|
||||
'</div>');
|
||||
}
|
||||
vote_alert = $link.parent().find("#vote_alert");
|
||||
if (vote_alert.length == 0) {
|
||||
$link.parent().append($warning);
|
||||
|
@ -44,21 +53,16 @@ $(document).ready(function () {
|
|||
return true;
|
||||
});
|
||||
|
||||
$('.accept_answer').on('click', function (ev) {
|
||||
$('.accept_answer').not('.karma_required').on('click', function (ev) {
|
||||
ev.preventDefault();
|
||||
var $link = $(ev.currentTarget);
|
||||
openerp.jsonRpc($link.data('href'), 'call', {}).then(function (data) {
|
||||
if (data['error']) {
|
||||
if (data['error'] == 'anonymous_user'){
|
||||
if (data['error'] == 'anonymous_user') {
|
||||
var $warning = $('<div class="alert alert-danger alert-dismissable" id="correct_answer_alert" style="position:absolute; margin-top: -30px; margin-left: 90px;">'+
|
||||
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">×</button>'+
|
||||
'Sorry, anonymous users cannot choose correct answer.'+
|
||||
'</div>');
|
||||
} else if (data['error'] == 'not_enough_karma') {
|
||||
var $warning = $('<div class="alert alert-danger alert-dismissable" id="vote_alert" style="max-width: 500px; position:absolute; margin-top: -30px; margin-left: 90px;">'+
|
||||
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">×</button>'+
|
||||
'Sorry, at least ' + data['karma'] + ' karma is required to accept this answer. You can gain karma by answering questions and receiving votes.'+
|
||||
'</div>');
|
||||
}
|
||||
correct_answer_alert = $link.parent().find("#correct_answer_alert");
|
||||
if (correct_answer_alert.length == 0) {
|
||||
|
|
|
@ -24,6 +24,27 @@
|
|||
<sheet>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="karma_ask"/>
|
||||
<field name="karma_edit_own"/>
|
||||
<field name="karma_edit_all"/>
|
||||
<field name="karma_close_own"/>
|
||||
<field name="karma_close_all"/>
|
||||
<field name="karma_unlink_own"/>
|
||||
<field name="karma_unlink_all"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="karma_upvote"/>
|
||||
<field name="karma_downvote"/>
|
||||
<field name="karma_answer_accept_own"/>
|
||||
<field name="karma_answer_accept_all"/>
|
||||
<field name="karma_editor_link_files"/>
|
||||
<field name="karma_editor_clickable_link"/>
|
||||
<field name="karma_comment_own"/>
|
||||
<field name="karma_comment_all"/>
|
||||
<field name="karma_comment_convert_own"/>
|
||||
<field name="karma_comment_convert_all"/>
|
||||
<field name="karma_comment_unlink_own"/>
|
||||
<field name="karma_comment_unlink_all"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<!-- helper -->
|
||||
<template id="link_button">
|
||||
<form method="POST" t-att-action="url">
|
||||
<button t-attf-class="fa btn-link #{classes}">
|
||||
<button t-attf-class="fa btn-link #{classes} #{karma and 'karma_required text-muted' or ''}" t-attf-data-karma="#{karma}">
|
||||
<t t-esc="label"/></button>
|
||||
</form>
|
||||
</template>
|
||||
|
@ -163,7 +163,7 @@
|
|||
<div t-if="question.child_count<=1" class="subtitle">Answer</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<div class="col-md-10 clearfix">
|
||||
<div class="question-name">
|
||||
<a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }" t-field="question.name"/>
|
||||
<span t-if="not question.active"><b> [Deleted]</b></span>
|
||||
|
@ -419,10 +419,12 @@
|
|||
|
||||
<template id="vote">
|
||||
<div t-attf-class="box oe_grey">
|
||||
<a t-attf-class="vote_up fa fa-thumbs-up no-decoration #{post.user_vote == 1 and 'text-success' or ''}"
|
||||
<a t-attf-class="vote_up fa fa-thumbs-up no-decoration #{post.user_vote == 1 and 'text-success' or ''} #{((post.user_vote == 1 and not post.can_downvote) or not post.can_upvote) and 'karma_required' or ''}"
|
||||
t-attf-data-karma="#{post.user_vote == 1 and post.karma_downvote or post.karma_upvote}"
|
||||
t-attf-data-href="/forum/#{slug(post.forum_id)}/post/#{slug(post)}/upvote"/>
|
||||
<span id="vote_count" t-esc="post.vote_count"/>
|
||||
<a t-attf-class="vote_down fa fa-thumbs-down no-decoration #{post.user_vote == -1 and 'text-warning' or ''}"
|
||||
<a t-attf-class="vote_down fa fa-thumbs-down no-decoration #{post.user_vote == -1 and 'text-warning' or ''} #{((post.user_vote == -1 and not post.can_upvote) or not post.can_downvote) and 'karma_required' or ''}"
|
||||
t-attf-data-karma="#{post.user_vote == -1 and post.karma_uovote or post.karma_downvote}"
|
||||
t-attf-data-href="/forum/#{slug(post.forum_id)}/post/#{slug(post)}/downvote"/>
|
||||
<div t-if="vote_count > 1" class="subtitle">
|
||||
votes
|
||||
|
@ -449,7 +451,7 @@
|
|||
t-attf-class="favourite_question no-decoration fa fa-2x fa-star #{question.user_favourite and 'forum_favourite_question' or ''}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div style="col-md-10">
|
||||
<div class="col-md-10">
|
||||
<h1 class="mt0">
|
||||
<a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }" t-field="question.name"/>
|
||||
<span t-if="not question.active"><b> [Deleted]</b></span>
|
||||
|
@ -466,11 +468,12 @@
|
|||
style="display: inline-block;"/></b>
|
||||
</t>
|
||||
<b>on <span t-field="question.closed_date"/></b>
|
||||
<div t-if="question.state == 'close' and user.karma>=500" class="mt16 mb24 text-center">
|
||||
<div class="mt16 mb24 text-center">
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) + '/question/' + slug(question) + '/reopen'"/>
|
||||
<t t-set="label" t-value="'Reopen'"/>
|
||||
<t t-set="classes" t-value="'fa-arrow-right'"/>
|
||||
<t t-set="karma" t-value="not question.can_close and question.karma_close or 0"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -483,45 +486,52 @@
|
|||
</t>
|
||||
</div>
|
||||
<ul class="list-inline" id="options">
|
||||
<li t-if="user.id == question.create_uid.id or user.karma>=50">
|
||||
<a style="cursor: pointer" data-toggle="collapse" class="text-muted fa fa-comment-o"
|
||||
t-attf-data-target="#comment#{ question._name.replace('.','') + '-' + str(question.id) }">
|
||||
<li>
|
||||
<a style="cursor: pointer" data-toggle="collapse"
|
||||
t-attf-class="fa fa-comment-o #{not question.can_comment and 'karma_required text-muted' or ''}"
|
||||
t-attf-data-karma="#{not question.can_comment and question.karma_comment or 0}"
|
||||
t-attf-data-target="#comment#{ question._name.replace('.','') + '-' + str(question.id) }">
|
||||
Comment
|
||||
</a>
|
||||
</li>
|
||||
<li t-if="question.state != 'close' and ((user.id == question.create_uid.id and can_close_own) or can_close_all)">
|
||||
<li t-if="question.state != 'close'">
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/ask_for_close'"/>
|
||||
<t t-set="label" t-value="'Close'"/>
|
||||
<t t-set="classes" t-vaoue="'text-muted fa-times'"/>
|
||||
<t t-set="classes" t-value="'fa-times'"/>
|
||||
<t t-set="karma" t-value="not question.can_close and question.karma_close or 0"/>
|
||||
</t>
|
||||
</li>
|
||||
<li t-if="question.state == 'close' and ((user.id == question.create_uid.id and can_close_own) or can_close_all)">
|
||||
<li t-if="question.state == 'close'">
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/reopen'"/>
|
||||
<t t-set="label" t-value="'Reopen'"/>
|
||||
<t t-set="classes" t-value="'text-muted fa-undo'"/>
|
||||
<t t-set="classes" t-value="'fa-undo'"/>
|
||||
<t t-set="karma" t-value="not question.can_close and question.karma_close or 0"/>
|
||||
</t>
|
||||
</li>
|
||||
<li t-if="(user.id == question.create_uid.id and can_edit_own) or can_edit_all">
|
||||
<li>
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) +'/post/' + slug(question) + '/edit'"/>
|
||||
<t t-set="label" t-value="'Edit'"/>
|
||||
<t t-set="classes" t-value="'text-muted fa-edit'"/>
|
||||
<t t-set="classes" t-value="'fa-edit'"/>
|
||||
<t t-set="karma" t-value="not question.can_edit and question.karma_edit or 0"/>
|
||||
</t>
|
||||
</li>
|
||||
<li t-if="question.active and ((user.id == question.create_uid.id and can_unlink_own) or can_unlink_all)">
|
||||
<li t-if="question.active">
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/delete'"/>
|
||||
<t t-set="label" t-value="'Delete'"/>
|
||||
<t t-set="classes" t-value="'text-muted fa-trash-o'"/>
|
||||
<t t-set="classes" t-value="'fa-trash-o'"/>
|
||||
<t t-set="karma" t-value="not question.can_unlink and question.karma_unlink or 0"/>
|
||||
</t>
|
||||
</li>
|
||||
<li t-if="not question.active and ((user.id == question.create_uid.id and can_unlink_own) or can_unlink_all)">
|
||||
<li t-if="not question.active">
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/undelete'"/>
|
||||
<t t-set="label" t-value="'Undelete'"/>
|
||||
<t t-set="classes" t-value="'text-muted fa-trash-o'"/>
|
||||
<t t-set="classes" t-value="'fa-trash-o'"/>
|
||||
<t t-set="karma" t-value="not question.can_unlink and question.karma_unlink or 0"/>
|
||||
</t>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -565,7 +575,8 @@
|
|||
<t t-set="post" t-value="answer"/>
|
||||
</t>
|
||||
<div class="text-muted mt8">
|
||||
<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'}"
|
||||
<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}"
|
||||
t-attf-data-href="/forum/#{slug(question.forum_id)}/post/#{slug(answer)}/toggle_correct"/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -573,26 +584,32 @@
|
|||
<t t-raw="answer.content"/>
|
||||
<div class="mt16">
|
||||
<ul class="list-inline pull-right">
|
||||
<li t-if="user.id == answer.create_uid.id or user.karma>=50">
|
||||
<a style="cursor: pointer" data-toggle="collapse" class="text-muted fa fa-comment-o"
|
||||
t-attf-data-target="#comment#{ answer._name.replace('.','') + '-' + str(answer.id) }"> Comment
|
||||
<li>
|
||||
<a t-attf-class="fa fa-comment-o #{not answer.can_comment and 'karma_required text-muted' or ''}"
|
||||
t-attf-data-karma="#{not answer.can_comment and answer.karma_comment or 0}"
|
||||
style="cursor: pointer" data-toggle="collapse"
|
||||
t-attf-data-target="#comment#{ answer._name.replace('.','') + '-' + str(answer.id) }"> Comment
|
||||
</a>
|
||||
</li>
|
||||
<li t-if="(user.id == answer.create_uid.id and can_edit_own) or can_edit_all">
|
||||
<a class="text-muted fa fa-edit" t-attf-href="/forum/#{slug(forum)}/post/#{slug(answer)}/edit"> Edit</a>
|
||||
<li>
|
||||
<a t-attf-class="fa fa-edit #{not answer.can_edit and 'karma_required text-muted' or ''}"
|
||||
t-attf-data-karma="#{not answer.can_edit and answer.karma_edit or 0}"
|
||||
t-attf-href="/forum/#{slug(forum)}/post/#{slug(answer)}/edit"> Edit</a>
|
||||
</li>
|
||||
<li t-if="(user.id == answer.create_uid.id and can_unlink_own) or can_unlink_all">
|
||||
<li>
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/delete'"/>
|
||||
<t t-set="label" t-value="'Delete'"/>
|
||||
<t t-set="classes" t-value="'text-muted fa-trash-o'"/>
|
||||
<t t-set="classes" t-value="'fa-trash-o'"/>
|
||||
<t t-set="karma" t-value="not answer.can_unlink and answer.karma_unlink or 0"/>
|
||||
</t>
|
||||
</li>
|
||||
<li t-if="user.id == answer.create_uid.id">
|
||||
<li>
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/convert_to_comment'"/>
|
||||
<t t-set="label" t-value="'Convert as a comment'"/>
|
||||
<t t-set="classes" t-value="'text-muted fa-magic'"/>
|
||||
<t t-set="classes" t-value="'fa-magic'"/>
|
||||
<t t-set="karma" t-value="not answer.can_comment_convert and answer.karma_comment_convert or 0"/>
|
||||
</t>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -610,7 +627,8 @@
|
|||
<t t-set="post" t-value="answer"/>
|
||||
</t>
|
||||
<div class="text-muted mt8">
|
||||
<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'}"
|
||||
<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}"
|
||||
t-attf-data-href="/forum/#{slug(question.forum_id)}/post/#{slug(answer)}/toggle_correct"/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -641,10 +659,12 @@
|
|||
t-attf-data-href="/forum/#{slug(forum)}/post/#{slug(object)}/comment/#{slug(message)}/delete"
|
||||
class="close comment_delete">&times;</button>
|
||||
<span t-field="message.body"/>
|
||||
<t t-set="required_karma" t-value="message.author_id.id == user.partner_id.id and object.forum_id.karma_comment_convert_own or object.forum_id.karma_comment_convert_all"/>
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(object) + '/comment/' + slug(message) + '/convert_to_answer'"/>
|
||||
<t t-set="label" t-value="'Convert as an answer'"/>
|
||||
<t t-set="classes" t-value="'text-muted fa-magic pull-right'"/>
|
||||
<t t-set="karma" t-value="user.karma<required_karma and required_karma or 0"/>
|
||||
<t t-set="classes" t-value="'fa-magic pull-right'"/>
|
||||
</t>
|
||||
<a t-attf-href="/forum/#{slug(forum)}/partner/#{message.author_id.id}"
|
||||
t-field="message.author_id" t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
|
||||
|
|
Loading…
Reference in New Issue