import werkzeug.wrappers
import re
import simplejson
+import lxml
+from urllib2 import urlopen
from openerp import tools
from openerp import SUPERUSER_ID
'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),
}
if forum:
values['forum'] = forum
'''/forum/<model("forum.forum"):forum>/tag/<model("forum.tag", "[('forum_id','=',forum[0])]"):tag>/questions''',
'''/forum/<model("forum.forum"):forum>/tag/<model("forum.tag", "[('forum_id','=',forum[0])]"):tag>/questions/page/<int:page>''',
], type='http', auth="public", website=True)
- def questions(self, forum, tag=None, page=1, filters='all', sorting='date', search='', **post):
+ def questions(self, forum, tag=None, page=1, filters='all', sorting='relevancy', search='', post_type='all', **post):
cr, uid, context = request.cr, request.uid, request.context
Post = request.registry['forum.post']
user = request.registry['res.users'].browse(cr, uid, uid, context=context)
else:
filters = 'all'
+ if post_type == 'link':
+ domain += [('type', '=', 'link')]
+ elif post_type == 'question':
+ domain += [('type', '=', 'question')]
+ elif post_type == 'discussion':
+ domain += [('type', '=', 'discussion')]
+
if sorting == 'answered':
order = 'child_count desc'
elif sorting == 'vote':
order = 'vote_count desc'
elif sorting == 'date':
order = 'write_date desc'
- else:
- sorting = 'creation'
+ elif sorting == 'creation':
order = 'create_date desc'
+ else:
+ sorting == 'relevancy'
+ order = 'relevancy'
question_count = Post.search(cr, uid, domain, count=True, context=context)
if tag:
'filters': filters,
'sorting': sorting,
'search': search,
+ 'post_type': post_type,
})
return request.website.render("website_forum.forum_index", values)
# Questions
# --------------------------------------------------
- @http.route(['/forum/<model("forum.forum"):forum>/ask'], type='http', auth="public", website=True)
- def question_ask(self, forum, **post):
- if not request.session.uid:
- return login_redirect()
- values = self._prepare_forum_values(forum=forum, searches={}, header={'ask_hide': True})
- return request.website.render("website_forum.ask_question", values)
-
- @http.route('/forum/<model("forum.forum"):forum>/question/new', type='http', auth="user", methods=['POST'], website=True)
- def question_create(self, forum, **post):
- cr, uid, context = request.cr, request.uid, request.context
- Tag = request.registry['forum.tag']
- question_tag_ids = []
- if post.get('question_tags').strip('[]'):
- tags = post.get('question_tags').strip('[]').replace('"', '').split(",")
- for tag in tags:
- tag_ids = Tag.search(cr, uid, [('name', '=', tag)], context=context)
- if tag_ids:
- question_tag_ids.append((4, tag_ids[0]))
- else:
- question_tag_ids.append((0, 0, {'name': tag, 'forum_id': forum.id}))
-
- new_question_id = request.registry['forum.post'].create(
- request.cr, request.uid, {
- 'forum_id': forum.id,
- 'name': post.get('question_name'),
- 'content': post.get('content'),
- 'tag_ids': question_tag_ids,
- }, context=context)
- return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), new_question_id))
+ @http.route('/forum/get_url_title', type='json', auth="user", methods=['POST'], website=True)
+ def get_url_title(self, **kwargs):
+ arch = lxml.html.parse(urlopen(kwargs.get('url')))
+ return arch.find(".//title").text
@http.route(['''/forum/<model("forum.forum"):forum>/question/<model("forum.post", "[('forum_id','=',forum[0]),('parent_id','=',False)]"):question>'''], type='http', auth="public", website=True)
def question(self, forum, question, **post):
'forum': forum,
'reasons': reasons,
})
- return request.website.render("website_forum.close_question", values)
+ return request.website.render("website_forum.close_post", values)
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/edit_answer', type='http', auth="user", website=True)
def question_edit_answer(self, forum, question, **kwargs):
# Post
# --------------------------------------------------
- @http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/new', type='http', auth="public", methods=['POST'], website=True)
- def post_new(self, forum, post, **kwargs):
+ @http.route(['/forum/<model("forum.forum"):forum>/<post_type>'], type='http', auth="public", website=True)
+ def forum_post(self, forum, post_type, **post):
if not request.session.uid:
return login_redirect()
cr, uid, context = request.cr, request.uid, request.context
user = request.registry['res.users'].browse(cr, SUPERUSER_ID, uid, context=context)
if not user.email or not tools.single_email_re.match(user.email):
return werkzeug.utils.redirect("/forum/%s/user/%s/edit?email_required=1" % (slug(forum), uid))
- request.registry['forum.post'].create(
- request.cr, request.uid, {
+ values = self._prepare_forum_values(forum=forum, searches={}, header={'ask_hide': True})
+ return request.website.render("website_forum.%s" % post_type, values)
+
+ @http.route(['/forum/<model("forum.forum"):forum>/<post_type>/new',
+ '/forum/<model("forum.forum"):forum>/<model("forum.post"):post_parent>/reply']
+ , type='http', auth="public", methods=['POST'], website=True)
+ def post_create(self, forum, post_parent='', post_type='', **post):
+ cr, uid, context = request.cr, request.uid, request.context
+ if not request.session.uid:
+ return login_redirect()
+
+ post_tag_ids = []
+ Tag = request.registry['forum.tag']
+ if post.get('post_tags', False) and post.get('post_tags').strip('[]'):
+ tags = post.get('post_tags').strip('[]').replace('"', '').split(",")
+ for tag in tags:
+ tag_ids = Tag.search(cr, uid, [('name', '=', tag)], context=context)
+ if tag_ids:
+ post_tag_ids.append((4, tag_ids[0]))
+ else:
+ post_tag_ids.append((0, 0, {'name': tag, 'forum_id': forum.id}))
+
+ new_question_id = request.registry['forum.post'].create(cr, uid, {
'forum_id': forum.id,
- 'parent_id': post.id,
- 'content': kwargs.get('content'),
- }, context=request.context)
- return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(post)))
+ 'name': post.get('post_name', ''),
+ 'content': post.get('content'),
+ 'parent_id': post_parent and post_parent.id or False,
+ 'tag_ids': post_tag_ids,
+ 'type': post_parent and post_parent.type or post_type,
+ }, context=context)
+ return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), post_parent and slug(post_parent) or new_question_id))
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/comment', type='http', auth="public", methods=['POST'], website=True)
def post_comment(self, forum, post, **kwargs):
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/save', type='http', auth="user", methods=['POST'], website=True)
def post_save(self, forum, post, **kwargs):
cr, uid, context = request.cr, request.uid, request.context
- question_tags = []
- if kwargs.get('question_tag') and kwargs.get('question_tag').strip('[]'):
+ post_tags = []
+ if kwargs.get('post_tag') and kwargs.get('post_tag').strip('[]'):
Tag = request.registry['forum.tag']
- tags = kwargs.get('question_tag').strip('[]').replace('"', '').split(",")
+ tags = kwargs.get('post_tag').strip('[]').replace('"', '').split(",")
for tag in tags:
tag_ids = Tag.search(cr, uid, [('name', '=', tag)], context=context)
if tag_ids:
- question_tags += tag_ids
+ post_tags += tag_ids
else:
new_tag = Tag.create(cr, uid, {'name': tag, 'forum_id': forum.id}, context=context)
- question_tags.append(new_tag)
+ post_tags.append(new_tag)
vals = {
- 'tag_ids': [(6, 0, question_tags)],
- 'name': kwargs.get('question_name'),
+ 'tag_ids': [(6, 0, post_tags)],
+ 'name': kwargs.get('post_name'),
'content': kwargs.get('content'),
}
request.registry['forum.post'].write(cr, uid, [post.id], vals, context=context)
<!-- Reasons for closing Post -->
<record id="reason_1" model="forum.post.reason">
- <field name="name">duplicate question</field>
+ <field name="name">duplicate post</field>
</record>
<record id="reason_2" model="forum.post.reason">
<field name="name">off-topic or not relevant</field>
<field name="name">too subjective and argumentative</field>
</record>
<record id="reason_4" model="forum.post.reason">
- <field name="name">not a real question</field>
+ <field name="name">not a real post</field>
</record>
<record id="reason_6" model="forum.post.reason">
<field name="name">not relevant or out dated</field>
<field name="name">ecommerce</field>
<field name="forum_id" ref="website_forum.forum_help"/>
</record>
+ <record id="tags_3" model="forum.tag">
+ <field name="name">Development</field>
+ <field name="forum_id" ref="website_forum.forum_help"/>
+ </record>
<!-- Questions -->
<record id="question_0" model="forum.post">
<field name="name">How to configure alerts for employee contract expiration</field>
<field name="forum_id" ref="website_forum.forum_help"/>
+ <field name="type">question</field>
<field name="views">3</field>
<field name="tag_ids" eval="[(4,ref('website_forum.tags_0')), (4,ref('website_forum.tags_1'))]"/>
</record>
Can I use Odoo as a replacement CMS of Wordpress + eCommerce plugin?
In simple words does Odoo became CMS+ERP platform?</p>]]></field>
+ <field name="type">question</field>
<field name="tag_ids" eval="[(4,ref('website_forum.tags_2'))]"/>
</record>
<li>Step 4. To test, set a contract to expire tomorrow under one of your fleets vehicles. Then Save it.</li>
<li>Step 5. Go to Scheduled Actions.. Set interval number to 1. Interval Unit to Minutes. Then Set the Next Execution date to 2 minutes from now. If your SMTP is configured correctly you will start to get a mail every minute with the reminder.</li></ul>]]></field>
<field name="parent_id" ref="question_0" />
+ <field name="type">question</field>
</record>
<record id="answer_1" model="forum.post">
<field name="forum_id" ref="website_forum.forum_help"/>
The CMS editor in Odoo web is nice but I prefer Drupal for customization and there is a Drupal module for Odoo. I think WP is better than Odoo web too.
</field>
<field name="parent_id" ref="question_1"/>
+ <field name="type">question</field>
+ </record>
+
+ <!-- Article-->
+ <record id="article_0" model="forum.post">
+ <field name="name">https://www.odoo.com/forum/how-to/developers-13/the-different-openerp-model-inheritance-mechanisms-whats-the-difference-between-them-and-when-should-they-be-used-46</field>
+ <field name="content">OpenERP S.A. - The different "openerp model inheritance" mechanisms: what's the difference between them, and when should they be used ?</field>
+ <field name="forum_id" ref="website_forum.forum_help"/>
+ <field name="type">link</field>
+ <field name="views">6</field>
+ <field name="tag_ids" eval="[(4,ref('website_forum.tags_3'))]"/>
+ </record>
+
+ <!-- Discussion-->
+ <record id="discussion_0" model="forum.post">
+ <field name="name">How to setup a regular PostgreSQL database backup</field>
+ <field name="content">I'm not familiar with PostgreSQL database administration , so I figured I might ask for help from someone more knowledgeable on the subject.
+
+What would you recommend in order to setup a regular (daily) OpenERP database backup?
+
+Ideally, this would be done without stopping the database (hot backup). Is it possible to setup incremental backups, e.g., one weekly reference backup and daily incremental backups?
+
+Are there any automation scripts available I might use?
+
+(I'm using Ubuntu Server.)</field>
+ <field name="forum_id" ref="website_forum.forum_help"/>
+ <field name="type">discussion</field>
+ <field name="views">5</field>
+ </record>
+
+ <record id="reply_1" model="forum.post">
+ <field name="forum_id" ref="website_forum.forum_help"/>
+ <field name="content"><![CDATA[<p>I use the following setup:</p>
+ <ol>
+ <li>Backup-Script</li>
+ <li>Housekeeping script (deletes backups which are older than 30 days)</li>
+ <li>Create daily cronjobs in to run Backup and Housekeeping Script. The backup runs daily at 1am and the housekeeping job runs daily at 5am.</li>
+ </ol>]]>
+ </field>
+ <field name="parent_id" ref="discussion_0"/>
+ <field name="type">discussion</field>
</record>
<!-- Post Vote -->
<field name="user_id" ref="base.user_demo"/>
<field name="vote">1</field>
</record>
+ <record id="post_vote_3" model="forum.post.vote">
+ <field name="post_id" ref="article_0"/>
+ <field name="user_id" ref="base.user_demo"/>
+ <field name="vote">1</field>
+ </record>
<!-- Run Scheduler -->
<function model="gamification.challenge" name="_cron_update"/>
_inherit = ['mail.thread', 'website.seo.metadata']
_columns = {
- 'name': fields.char('Name', required=True, translate=True),
+ 'name': fields.char('Forum Name', required=True, translate=True),
'faq': fields.html('Guidelines'),
'description': fields.html('Description'),
+ 'introduction_message': fields.html('Introduction Message'),
+ 'relevancy_option_first': fields.float('First Relevancy Parameter'),
+ 'relevancy_option_second': fields.float('Second Relevancy Parameter'),
+ 'default_order': fields.selection([
+ ('creation','Newest'),
+ ('date','Last Updated'),
+ ('vote','Most Voted'),
+ ('relevancy','Relevancy'),
+ ], 'Default Order', required=True),
+ 'default_allow': fields.selection([('post_link','Link'),('ask_question','Question'),('post_discussion','Discussion')], 'Default Post', required=True),
+ 'allow_link': fields.boolean('Links', help="When clicking on the post, it redirects to an external link"),
+ 'allow_question': fields.boolean('Questions', help="Users can answer only once per question. Contributors can edit answers and mark the right ones."),
+ 'allow_discussion': fields.boolean('Discussions'),
# 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_gen_question_new': fields.integer('Post a Questions'),
+ 'karma_gen_question_upvote': fields.integer('Upvote a Question'),
+ 'karma_gen_question_downvote': fields.integer('Downvote a Question'),
+ 'karma_gen_answer_upvote': fields.integer('Upvote an Answer'),
+ 'karma_gen_answer_downvote': fields.integer('Downvote an answer'),
+ 'karma_gen_answer_accept': fields.integer('Accept an Answer'),
+ 'karma_gen_answer_accepted': fields.integer('Have Your Answer Accepted'),
+ 'karma_gen_answer_flagged': fields.integer('Have Your 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'),
+ 'karma_ask': fields.integer('Ask a new question'),
+ 'karma_answer': fields.integer('Answer a question'),
+ 'karma_edit_own': fields.integer('Edit its own posts'),
+ 'karma_edit_all': fields.integer('Edit all posts'),
+ 'karma_close_own': fields.integer('Close its own posts'),
+ 'karma_close_all': fields.integer('Close all posts'),
+ 'karma_unlink_own': fields.integer('Delete its own posts'),
+ 'karma_unlink_all': fields.integer('Delete all posts'),
+ 'karma_upvote': fields.integer('Upvote'),
+ 'karma_downvote': fields.integer('Downvote'),
+ 'karma_answer_accept_own': fields.integer('Accept an answer on its own questions'),
+ 'karma_answer_accept_all': fields.integer('Accept an answers to all questions'),
+ 'karma_editor_link_files': fields.integer('Linking files (Editor)'),
+ 'karma_editor_clickable_link': fields.integer('Add clickable links (Editor)'),
+ 'karma_comment_own': fields.integer('Comment its own posts'),
+ 'karma_comment_all': fields.integer('Comment all posts'),
+ 'karma_comment_convert_own': fields.integer('Convert its own answers to comments and vice versa'),
+ 'karma_comment_convert_all': fields.integer('Convert all answers to answers and vice versa'),
+ 'karma_comment_unlink_own': fields.integer('Unlink its own comments'),
+ 'karma_comment_unlink_all': fields.integer('Unlink all comments'),
+ 'karma_retag': fields.integer('Change question tags'),
+ 'karma_flag': fields.integer('Flag a post as offensive'),
}
def _get_default_faq(self, cr, uid, context=None):
return False
_defaults = {
+ 'default_order': 'date',
+ 'allow_question': True,
+ 'default_allow': 'ask_question',
+ 'allow_link': False,
+ 'allow_discussion': False,
'description': 'This community is for professionals and enthusiasts of our products and services.',
'faq': _get_default_faq,
+ 'introduction_message': """<h1>Welcome to Odoo Forum</h1>
+ <p> 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.
+ </p>""",
+ 'relevancy_option_first': 0.8,
+ 'relevancy_option_second': 1.8,
'karma_gen_question_new': 2,
'karma_gen_question_upvote': 5,
'karma_gen_question_downvote': -2,
_inherit = ['mail.thread', 'website.seo.metadata']
_order = "is_correct DESC, vote_count DESC, write_date DESC"
+ def _get_post_relevancy(self, cr, uid, ids, field_name, arg, context):
+ res = dict.fromkeys(ids, 0)
+ for post in self.browse(cr, uid, ids, context=context):
+ days = (datetime.today() - datetime.strptime(post.create_date, tools.DEFAULT_SERVER_DATETIME_FORMAT)).days
+ relavency = abs(post.vote_count - 1) ** post.forum_id.relevancy_option_first / ( days + 2) ** post.forum_id.relevancy_option_second
+ res[post.id] = relavency if (post.vote_count - 1) >= 0 else -relavency
+ return res
+
def _get_user_vote(self, cr, uid, ids, field_name, arg, context):
res = dict.fromkeys(ids, 0)
vote_ids = self.pool['forum.post.vote'].search(cr, uid, [('post_id', 'in', ids), ('user_id', '=', uid)], context=context)
'state': fields.selection([('active', 'Active'), ('close', 'Close'), ('offensive', 'Offensive')], 'Status'),
'views': fields.integer('Number of Views'),
'active': fields.boolean('Active'),
+ 'type': fields.selection([('question', 'Question'), ('link', 'Article'), ('discussion', 'Discussion')], 'Type'),
+ 'relevancy': fields.function(
+ _get_post_relevancy, string="Relevancy", type='float',
+ store={
+ 'forum.post': (lambda self, cr, uid, ids, c={}: ids, ['vote_ids'], 10),
+ 'forum.post.vote': (_get_post_from_vote, [], 10),
+ }),
'is_correct': fields.boolean('Valid Answer', help='Correct Answer or Answer on this question accepted.'),
'website_message_ids': fields.one2many(
'mail.message', 'res_id',
'state': 'active',
'views': 0,
'active': True,
+ 'type': 'question',
'vote_ids': list(),
'favourite_ids': list(),
'child_ids': list(),
return true;
});
+ $('.js_close_intro').on('click', function (ev) {
+ ev.preventDefault();
+ document.cookie = "no_introduction_message = false";
+ return true;
+ });
+
+ $('.link_url').on('change', function (ev) {
+ ev.preventDefault();
+ var $link = $(ev.currentTarget);
+ if ($link.attr("value").search("^http(s?)://.*")) {
+ var $warning = $('<div class="alert alert-danger alert-dismissable" style="position:absolute; margin-top: -180px; margin-left: 90px;">'+
+ '<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">×</button>'+
+ 'Please enter valid URl.'+
+ '</div>');
+ $link.parent().append($warning);
+ $link.parent().find("button#btn_post_your_article")[0].disabled = true;
+ $link.parent().find("input[name='content']")[0].value = '';
+ } else {
+ openerp.jsonRpc("/forum/get_url_title", 'call', {'url': $link.attr("value")}).then(function (data) {
+ $link.parent().find("input[name='content']")[0].value = data;
+ $('button').prop('disabled', false);
+ $('input').prop('readonly', false);
+ });
+ }
+ });
+
if($('input.load_tags').length){
var tags = $("input.load_tags").val();
$("input.load_tags").val("");
}
if ($('textarea.load_editor').length) {
- var editor = CKEDITOR.instances['content'];
- editor.on('instanceReady', CKEDITORLoadComplete);
+ $('textarea.load_editor').each(function () {
+ if (this['id']) {
+ CKEDITOR.replace(this['id']).on('instanceReady', CKEDITORLoadComplete);
+ }
+ });
}
}
});
<field name="arch" type="xml">
<tree string="Forums">
<field name="name"/>
+ <field name="allow_question"/>
+ <field name="allow_link"/>
+ <field name="allow_discussion"/>
</tree>
</field>
</record>
<field name="arch" type="xml">
<form string="Forum">
<sheet>
- <group>
+ <label for="name" class="oe_edit_only"/>
+ <h1>
<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"/>
+ </h1>
+ <group>
+ <group string="Post Types">
+ <field name="allow_question"/>
+ <field name="allow_link"/>
+ <field name="allow_discussion"/>
+ <field name="default_allow"/>
+ </group>
+ <group string="Orders">
+ <field name="default_order"/>
+ <label for="relevancy_option_first" string="Relevancy Computation"/>
+ <div>
+ (votes - 1) ** <field name="relevancy_option_first" class="oe_inline"/> / (days + 2) ** <field name="relevancy_option_second" class="oe_inline"/>
+ </div>
+ </group>
</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 string="Earn Karma">
+ <field name="karma_gen_question_new"/>
+ <field name="karma_gen_question_upvote"/>
+ <field name="karma_gen_question_downvote"/>
+ <field name="karma_gen_answer_upvote"/>
+ <field name="karma_gen_answer_downvote"/>
+ <field name="karma_gen_answer_accept"/>
+ <field name="karma_gen_answer_accepted"/>
+ <field name="karma_gen_answer_flagged"/>
+ </group>
+ <group string="Karma Related Rights">
+ <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"/>
+ <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>
</group>
</sheet>
<div class="oe_chatter">
<field name="vote_count"/>
<field name="favourite_count"/>
<field name="child_count"/>
+ <field name="relevancy"/>
</group>
</group>
</sheet>
<t t-set="head">
<t t-call-assets="website_forum.assets_forum"/>
</t>
+ <div t-if="is_public_user and not no_introduction_message" class="alert alert-success alert-dismissable">
+ <div class="container">
+ <div t-field="forum.introduction_message"/>
+ <a class='btn btn-primary' t-attf-href="/web?redirect=#{ request.httprequest.url }">Register</a>
+ <button type="button" class="btn btn-link js_close_intro" data-dismiss="alert" aria-hidden="true">Hide Intro</button>
+ </div>
+ </div>
<div class="container mt16 website_forum">
<div class="navbar navbar-default">
<div class="navbar-header">
</div>
<div class="collapse navbar-collapse" id="oe-help-navbar-collapse">
<ul class="nav navbar-nav">
- <li t-att-class="filters in ('all', 'unanswered','followed','question','tag') and 'active' or '' ">
- <a t-attf-href="/forum/#{ slug(forum) }">Questions</a>
+ <li t-att-class="sorting == 'relevancy' and 'active' or '' ">
+ <a t-attf-href="/forum/#{ slug(forum) }?{{ keep_query( 'search', 'post_type', 'filters', sorting='relevancy') }}">Trending</a>
+ </li>
+ <li t-att-class="sorting == 'creation' and 'active' or '' ">
+ <a t-attf-href="/forum/#{ slug(forum) }?{{ keep_query( 'search', 'post_type', 'filters', sorting='creation') }}">Newest</a>
</li>
<li t-att-class="searches.get('users') and 'active' or '' ">
<a t-attf-href="/forum/#{ slug(forum) }/users">People</a>
</li>
</ul>
<form class="navbar-form navbar-right" role="search" t-attf-action="/forum/#{ slug(forum) }" method="get">
- <div class="form-group">
- <input type="search" class="form-control"
- name="search" placeholder="Search a question..."
- t-att-value="search or ''"/>
- <button type="submit" class="btn btn-default">Search</button>
+ <div class="input-group">
+ <input type="search" class="form-control" name="search" t-att-value="search or ''"/>
+ <span class="input-group-btn">
+ <button type="submit" class="btn btn-default">Search</button>
+ </span>
</div>
</form>
</div>
<t t-raw="0"/>
</div>
<div class="col-sm-3" id="right-column">
- <a t-if="not header.get('ask_hide')" class="btn btn-primary btn-lg btn-block mb16" t-attf-href="/forum/#{slug(forum)}/ask">Ask a Question</a>
+ <div t-if="not header.get('ask_hide')" class="btn-group btn-block mb16">
+ <a type="button" class="btn btn-primary btn-lg col-sm-10" t-attf-href="/forum/#{slug(forum)}/#{forum.default_allow}">
+ <t t-if="forum.default_allow == 'ask_question'">Ask a Question</t>
+ <t t-if="forum.default_allow == 'post_link'">Submit a Post</t>
+ <t t-if="forum.default_allow == 'post_discussion'">New Discussion</t>
+ </a>
+ <button type="button" class="btn btn-primary btn-lg col-sm-2 dropdown-toggle" data-toggle="dropdown">
+ <span class="caret"></span>
+ <span class="sr-only">Select Post</span>
+ </button>
+ <ul class="dropdown-menu" role="menu">
+ <li t-if="forum.allow_link"><a t-attf-href="/forum/#{slug(forum)}/post_link">Submit a Post</a></li>
+ <li t-if="forum.allow_question"><a t-attf-href="/forum/#{slug(forum)}/ask_question">Ask a Question</a></li>
+ <li t-if="forum.allow_discussion"><a t-attf-href="/forum/#{slug(forum)}/post_discussion">Launch a Discussion</a></li>
+ </ul>
+ </div>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Keep Informed</h3>
</div>
<div class="panel panel-default" id="about_forum">
<div class="panel-heading">
- <h3 class="panel-title">About This Forum</h3>
+ <h3 class="panel-title">About This Community</h3>
</div>
<div class="panel-body">
<t t-raw="forum.description"/>
<template id="display_post">
<div class="question row">
<div class="col-md-2 hidden-xs text-center">
- <div t-attf-class="box #{question.is_correct and 'oe_green' or 'oe_grey'} #{(question.child_count == 0) and 'text-muted' or ''}">
- <span t-esc="question.child_count"/>
- <div t-if="question.child_count>1" class="subtitle">Answers</div>
- <div t-if="question.child_count<=1" class="subtitle">Answer</div>
- </div>
+ <t t-call="website_forum.vote">
+ <t t-set="post" t-value="question"/>
+ </t>
</div>
<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>
- <span t-if="question.state == 'close'"><b> [Closed]</b></span>
+ <t t-if="question.type == 'link'">
+ <a t-att-href="question.name" t-raw="question.content"/>
+ </t>
+ <t t-if="question.type in ('question', 'discussion')">
+ <a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }" t-field="question.name"/>
+ </t>
+ <span t-if="not question.active"><b> [Deleted]</b></span>
+ <span t-if="question.state == 'close'"><b> [Closed]</b></span>
</div>
<t t-foreach="question.tag_ids" t-as="question_tag">
<a t-attf-href="/forum/#{ slug(forum) }/tag/#{slug(question_tag)}/questions">
- <span t-attf-class="pull-right badge #{tag and tag.name == question_tag.name and 'badge-active' ''}" t-field="question_tag.name"
+ <span t-attf-class="pull-right label #{tag and tag.name == question_tag.name and 'label-primary' or 'label-default'}" t-field="question_tag.name"
style="margin-right: 4px;"/>
</a>
</t>
- <div class="text-muted">
- by <a t-attf-href="/forum/#{ slug(forum) }/user/#{ question.create_uid.id }"
- t-field="question.create_uid" t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
- style="display: inline-block;"/>
- on <span t-field="question.write_date" t-field-options='{"format":"short"}'/>
- <span class="visible-xs">
- <b t-esc="question.child_count or 0"/>
- <t t-if="question.child_count>1">answers</t>
- <t t-if="question.child_count==1">answers</t>
- </span>
- with <b t-field="question.views"/> views
- <span t-if="question.vote_count>0"> and
- <b t-esc="question.vote_count or 0"/>
- <t t-if="question.vote_count>1">votes</t>
- <t t-if="question.vote_count==1">vote</t>
- </span>
- </div>
+ <small class="text-muted">
+ By <span t-field="question.create_uid" t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}' style="display: inline-block;"/>
+ • <span t-field="question.write_date" t-field-options='{"format":"short"}'/>
+ • <a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }">
+ <t t-esc="question.child_count"/>
+ <t t-if="question.child_count>1">comments</t>
+ <t t-if="question.child_count<=1">comment</t>
+ </a>
+ </small>
</div>
</div>
</template>
<!-- Specific Forum Layout -->
<template id="forum_index" name="Forum">
<t t-call="website_forum.header">
- <h1 class="page-header mt0">
- <t t-esc="question_count"/> <span>Questions</span>
+ <h2 class="page-header mt0">
+ <t t-esc="question_count"/>
+ <span t-if="post_type == 'all'">Posts</span>
+ <span t-if="post_type == 'question'">Questions</span>
+ <span t-if="post_type == 'link'">Posts</span>
+ <span t-if="post_type == 'discussion'">Discussions</span>
<t t-esc="search"/>
<small class="dropdown" t-if="filters in ('all', 'unanswered','followed', 'tag')">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
- <t t-if="filters == 'all'">All</t>
<t t-if="filters == 'unanswered'">Unanswered</t>
<t t-if="filters == 'followed'">Followed</t>
<t t-if="tag"><span t-field="tag.name"/></t>
+ <t t-if="sorting == 'relevancy'"> by relevancy</t>
<t t-if="sorting == 'date'"> by activity date</t>
- <t t-if="sorting == 'creation'"> by creation date</t>
+ <t t-if="sorting == 'creation'"> by newest</t>
<t t-if="sorting == 'answered'"> by most answered</t>
<t t-if="sorting == 'vote'"> by most voted</t>
<b class="caret"/>
<a href=""><t t-esc="tag.name"/></a>
</li>
<li class="dropdown-header">Sort by</li>
+ <li t-att-class="sorting == 'relevancy' and 'active' or '' ">
+ <a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='relevancy')">Relevancy</a>
+ </li>
<li t-att-class="sorting == 'date' and 'active' or '' ">
<a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='date')">Last activity date</a>
</li>
</li>
</ul>
</small>
- </h1>
+ </h2>
<div t-foreach="question_ids" t-as="question" class="mb16">
<t t-call="website_forum.display_post"/>
</div>
</t>
</template>
+<!-- Edition: Post Article -->
+<template id="post_link">
+ <t t-call="website_forum.header">
+ <h1 class="mt0">Submit a Link</h1>
+ <p class="mb32">
+ Share an awesome link. Your post will appear in the 'Newest' top-menu.
+ If the community vote on your post, it will get traction by being promoted
+ in the homepage.
+ </p><p>
+ We keep a high level of quality in showcased posts, only 20% of the submited
+ posts will be featured.
+ </p>
+ <form t-attf-action="/forum/#{ slug(forum) }/link/new" method="post" role="form" class="tag_text form-horizontal">
+ <input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="post_name">URL to Share</label>
+ <div class="col-sm-8">
+ <input type="text" name="post_name" required="True" t-attf-value="#{post_name}"
+ class="form-control mb16 link_url" placeholder="e.g. https://www.odoo.com"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="post_name">Post Title</label>
+ <div class="col-sm-8">
+ <input type="text" name="content" readonly="True" required="True" t-attf-value="#{content}"
+ class="form-control"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="post_name">Tags</label>
+ <div class="col-sm-8">
+ <input type="text" name="post_tags" readonly="True" class="form-control load_tags"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-8">
+ <button class="btn btn-primary" disabled="True" id="btn_post_your_article">Post Your Article</button>
+ </div>
+ </div>
+ </form>
+ </t>
+</template>
+
+<!-- Edition: Post your Discussion Topic -->
+<template id="post_discussion">
+ <t t-call="website_forum.header">
+ <h1 class="mt0">Post Your Discussion Topic</h1>
+ <p>
+ <b>Share</b> Start Something Awesome
+ </p>
+ <form t-attf-action="/forum/#{ slug(forum) }/discussion/new" method="post" role="form" class="tag_text">
+ <input type="text" name="post_name" required="True" t-attf-value="#{post_name}"
+ class="form-control mb16" placeholder="Your Discussion Title..."/>
+ <input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
+ <textarea name="content" id="content" required="True" class="form-control load_editor">
+ <t t-esc="question_content"/>
+ </textarea>
+ <br/>
+ <input type="text" name="post_tags" placeholder="Tags" class="form-control load_tags"/>
+ <br/>
+ <button class="btn btn-primary" id="btn_ask_your_question">Post Your Topic</button>
+ </form>
+ </t>
+</template>
+
<!-- Edition: ask your question -->
<template id="ask_question">
<t t-call="website_forum.header">
});
</script>
<form t-attf-action="/forum/#{ slug(forum) }/question/new" method="post" role="form" class="tag_text">
- <input type="text" name="question_name" required="True" t-attf-value="#{question_name}"
+ <input type="text" name="post_name" required="True" t-attf-value="#{post_name}"
class="form-control mb16" placeholder="Your Question Title..."/>
<input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
- <textarea name="content" required="True" class="form-control load_editor">
+ <textarea name="content" required="True" id="content" class="form-control load_editor">
<t t-esc="question_content"/>
</textarea>
<br/>
- <input type="text" name="question_tags" placeholder="Tags" class="form-control load_tags"/>
+ <input type="text" name="post_tags" placeholder="Tags" class="form-control load_tags"/>
<br/>
<button class="btn btn-primary" id="btn_ask_your_question">Post Your Question</button>
</form>
- <script type="text/javascript">
- CKEDITOR.replace("content");
- </script>
</t>
</template>
<!-- Edition: edit a post -->
<template id="edit_post">
<t t-call="website_forum.header">
- <h3 t-if="not is_answer">Edit question</h3>
- <h3 t-if="is_answer">Edit answer</h3>
+ <h3 t-if="not is_answer">Edit <span t-field="post.type"/></h3>
+ <h3 t-if="is_answer">Edit reply</h3>
<form t-attf-action="/forum/#{slug(forum)}/post/#{slug(post)}/save" method="post" role="form" class="tag_text">
<div t-if="not is_answer">
- <input type="text" name="question_name" id="question_name" required="True"
- t-attf-value="#{post.name}" class="form-control" placeholder="Edit your Question"/>
- <h5 class="mt20">Please enter a descriptive question (should finish by a '?')</h5>
+ <input type="text" name="post_name" required="True"
+ t-attf-value="#{post.name}" class="form-control mb8" placeholder="Edit your Post"/>
+ <h5 t-if="post.type == 'question'" class="mt20">Please enter a descriptive question (should finish by a '?')</h5>
</div>
<input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
- <textarea name="content" required="True" class="form-control load_editor">
+ <textarea name="content" id="content" required="True" class="form-control load_editor">
<t t-esc="post.content"/>
</textarea>
<div t-if="not is_answer">
<br/>
- <input type="text" name="question_tag" class="form-control col-md-9 load_tags" placeholder="Tags" t-attf-value="#{tags}"/>
+ <input type="text" name="post_tag" class="form-control col-md-9 load_tags" placeholder="Tags" t-attf-value="#{tags}"/>
<br/>
</div>
<button class="btn btn-primary btn-lg">Save</button>
</form>
- <script type="text/javascript">
- CKEDITOR.replace("content");
- </script>
</t>
</template>
-<!-- Moderation: close a question -->
-<template id="close_question">
+<!-- Moderation: close a post -->
+<template id="close_post">
<t t-call="website_forum.header">
- <h1 class="mt0">Close question</h1>
+ <h1 class="mt0">Close Post</h1>
<p class="text-muted">
- If you close this question, it will be hidden for most users. Only
- users having a high karma can see closed questions to moderate
+ If you close this post, it will be hidden for most users. Only
+ users having a high karma can see closed posts to moderate
them.
</p>
<form t-attf-action="/forum/#{ slug(forum) }/question/#{slug(question)}/close" method="post" role="form" class="form-horizontal mt32 mb64">
<input name="post_id" t-att-value="question.id" type="hidden"/>
<div class="form-group">
- <label class="col-md-3 control-label" for="reason">Question:</label>
+ <label class="col-md-3 control-label" for="reason">Post:</label>
<div class="col-md-8 mt8">
<span t-field="question.name"/>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-3 col-md-8">
- <button class="btn btn-primary">Close question</button>
+ <button class="btn btn-primary">Close post</button>
<span class="text-muted">or</span>
- <a class="btn btn-link" t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }">back to question</a>
+ <a class="btn btn-link" t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }">back to post</a>
</div>
</div>
</form>
</t>
</template>
+<!-- Edition: post a reply -->
+<template id="post_reply">
+ <div class="css_editable_mode_hidden">
+ <form t-attf-id="reply#{ object._name.replace('.','') + '-' + str(object.id) }" class="collapse oe_comment_grey"
+ t-attf-action="/forum/#{ slug(forum) }/#{slug(object)}/reply" method="post" role="form">
+ <h3 class="mt10">Your Reply</h3>
+ <input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
+ <textarea name="content" t-attf-id="content-#{str(object.id)}" class="form-control load_editor" required="True"/>
+ <button class="btn btn-primary" id="btn_ask_your_question">Post Your Reply</button>
+ </form>
+ </div>
+</template>
+
<!-- Edition: post an answer -->
<template id="post_answer">
- <h3 class="mt10">Your answer</h3>
- <p>
+ <h3 class="mt10">Your Reply</h3>
+ <p t-if="question.type == 'question'">
<b>Please try to give a substantial answer.</b> If you wanted to comment on the question or answer, just
<b>use the commenting tool.</b> Please remember that you can always <b>revise your answers</b>
- no need to answer the same question twice. Also, please <b>don't forget to vote</b>
- it really helps to select the best questions and answers!
</p>
- <form t-attf-action="/forum/#{ slug(forum) }/post/#{slug(question)}/new" method="post" role="form">
+ <form t-attf-action="/forum/#{ slug(forum) }/#{slug(question)}/reply" method="post" role="form">
<input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
- <textarea name="content" class="form-control load_editor" required="True"/>
- <button class="btn btn-primary mt16" id="btn_ask_your_question">Post Your Answer</button>
+ <textarea name="content" t-attf-id="content-#{str(question.id)}" class="form-control load_editor" required="True"/>
+ <button class="btn btn-primary mt16" id="btn_ask_your_question">Post Your Reply</button>
</form>
- <script type="text/javascript">
- CKEDITOR.replace("content");
- </script>
</template>
<template id="vote">
</div>
<div t-attf-class="col-md-10 #{not question.active and 'alert alert-danger' or ''}">
<h1 class="mt0">
- <a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }" t-field="question.name"/>
+ <t t-if="question.type == 'link'">
+ <a t-att-href="question.name" t-raw="question.content"/>
+ </t>
+ <t t-if="question.type in ('question', 'discussion')">
+ <a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }" t-field="question.name"/>
+ </t>
<span t-if="not question.active"><b> [Deleted]</b></span>
<span t-if="question.state == 'close'"><b> [Closed]</b></span>
</h1>
<div class="alert alert-info text-center" t-if="question.state == 'close'">
<p class="mt16">
- <b>The question has been closed<t t-if="question.closed_reason_id"> for reason: <i t-esc="question.closed_reason_id.name"/></t></b>
+ <b>The <i t-field="question.type"/> has been closed<t t-if="question.closed_reason_id"> for reason: <i t-esc="question.closed_reason_id.name"/></t></b>
</p>
<t t-if="question.closed_uid">
<b>by <a t-attf-href="/forum/#{ slug(forum) }/user/#{ question.closed_uid.id }"
</t>
</div>
</div>
- <t t-raw="question.content"/>
+ <div t-if="question.type != 'link'"><t t-raw="question.content"/></div>
<div class="mt16 clearfix">
<div class="pull-right">
<div class="text-right">
<t t-foreach="question.tag_ids" t-as="tag">
- <a t-attf-href="/forum/#{ slug(forum) }/tag/#{ tag.id }/questions" class="badge" t-field="tag.name"/>
+ <a t-attf-href="/forum/#{ slug(forum) }/tag/#{ tag.id }/questions" class="label lebel-default" t-field="tag.name"/>
</t>
</div>
<ul class="list-inline" id="options">
- <li>
+ <li t-if="question.type == 'question'">
<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}"
</div>
</div>
<hr/>
+ <div t-foreach="question.child_ids" t-as="post_answer" class="mt16 mb32">
+ <t t-call="website_forum.post_answers">
+ <t t-set="answer" t-value="post_answer"/>
+ </t>
+ </div>
+ <div t-if="question.type != 'question' or question.type == 'question' and not question.uid_has_answered and question.state != 'close' and question.active != False">
+ <t t-call="website_forum.post_answer"/>
+ </div>
+ <div t-if="question.type == 'question' and question.uid_has_answered" class="mb16">
+ <a class="btn btn-primary" t-attf-href="/forum/#{slug(forum)}/question/#{slug(question)}/edit_answer">Edit Your Previous Answer</a>
+ <span class="text-muted">(only one answer per question is allowed)</span>
+ </div>
+ </t>
+</template>
- <div t-foreach="question.child_ids" t-as="answer" class="mt16 mb32">
- <a t-attf-id="answer-#{str(answer.id)}"/>
- <div t-attf-class="forum_answer row" t-attf-id="answer_#{answer.id}" >
- <div class="col-md-2 hidden-xs text-center">
+<template id="post_answers">
+ <a t-attf-id="answer-#{str(answer.id)}"/>
+ <div t-attf-class="forum_answer row" t-attf-id="answer_#{answer.id}" >
+ <div class="col-md-2 hidden-xs text-center">
+ <t t-call="website_forum.vote">
+ <t t-set="post" t-value="answer"/>
+ </t>
+ <div t-if="question.type == 'question'" 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'} #{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>
+ <div class="col-md-10 clearfix">
+ <t t-raw="answer.content"/>
+ <div class="mt16">
+ <ul class="list-inline pull-right">
+ <li t-if="question.type == 'question'">
+ <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="question.type != 'question' and not answer.parent_id or answer.parent_id and not answer.parent_id.parent_id">
+ <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="#reply#{ answer._name.replace('.','') + '-' + str(answer.id) }"> Reply
+ </a>
+ </li>
+ <li>
+ <t t-call="website_forum.link_button">
+ <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/edit'"/>
+ <t t-set="label" t-value="'Edit'"/>
+ <t t-set="classes" t-value="'fa fa-edit'"/>
+ <t t-set="karma" t-value="not answer.can_edit and answer.karma_edit or 0"/>
+ </t>
+ </li>
+ <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="'fa-trash-o'"/>
+ <t t-set="karma" t-value="not answer.can_unlink and answer.karma_unlink or 0"/>
+ </t>
+ </li>
+ <li t-if="question.type == 'question'">
+ <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="'fa-magic'"/>
+ <t t-set="karma" t-value="not answer.can_comment_convert and answer.karma_comment_convert or 0"/>
+ </t>
+ </li>
+ </ul>
+ <img class="pull-left img img-circle img-avatar" t-attf-src="/forum/user/#{answer.create_uid.id}/avatar"/>
+ <div>
+ <a t-attf-href="/forum/#{ slug(forum) }/user/#{ answer.create_uid.id }"
+ t-field="answer.create_uid"
+ t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
+ style="display: inline-block;"/>
+ <div t-field="answer.create_uid" t-field-options='{"widget": "contact", "badges": true, "fields": ["karma"]}'/>
+ <span class="text-muted">Answered on <span t-field="answer.create_date" t-field-options='{"format":"short"}'/></span>
+ </div>
+ <div class="visible-xs text-center">
<t t-call="website_forum.vote">
<t t-set="post" t-value="answer"/>
</t>
t-attf-data-href="/forum/#{slug(question.forum_id)}/post/#{slug(answer)}/toggle_correct"/>
</div>
</div>
- <div class="col-md-10 clearfix">
- <t t-raw="answer.content"/>
- <div class="mt16">
- <ul class="list-inline pull-right">
- <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 t-call="website_forum.link_button">
- <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/edit'"/>
- <t t-set="label" t-value="'Edit'"/>
- <t t-set="classes" t-value="'fa fa-edit'"/>
- <t t-set="karma" t-value="not answer.can_edit and answer.karma_edit or 0"/>
- </t>
- </li>
- <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="'fa-trash-o'"/>
- <t t-set="karma" t-value="not answer.can_unlink and answer.karma_unlink or 0"/>
- </t>
- </li>
- <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="'fa-magic'"/>
- <t t-set="karma" t-value="not answer.can_comment_convert and answer.karma_comment_convert or 0"/>
- </t>
- </li>
- </ul>
- <img class="pull-left img img-circle img-avatar" t-attf-src="/forum/user/#{answer.create_uid.id}/avatar"/>
- <div>
- <a t-attf-href="/forum/#{ slug(forum) }/user/#{ answer.create_uid.id }"
- t-field="answer.create_uid"
- t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
- style="display: inline-block;"/>
- <div t-field="answer.create_uid" t-field-options='{"widget": "contact", "badges": true, "fields": ["karma"]}'/>
- <span class="text-muted">Answered on <span t-field="answer.create_date" t-field-options='{"format":"short"}'/></span>
- </div>
- <div class="visible-xs text-center">
- <t t-call="website_forum.vote">
- <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'} #{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>
- </div>
- <t t-call="website_forum.post_comment">
- <t t-set="object" t-value="answer"/>
- </t>
- </div>
+ </div>
+ <t t-if="answer.type == 'question'" t-call="website_forum.post_comment">
+ <t t-set="object" t-value="answer"/>
+ </t>
+ <div t-if="answer.type != 'question' and question.state != 'close' and question.active != False">
+ <t t-call="website_forum.post_reply">
+ <t t-set="object" t-value="answer"/>
+ </t>
+ </div>
+ <div t-foreach="answer.child_ids" t-as="child_answer" class="mt16 mb16">
+ <t t-call="website_forum.post_answers">
+ <t t-set="answer" t-value="child_answer"/>
+ </t>
</div>
</div>
- <div t-if="not question.uid_has_answered and question.state != 'close' and question.active != False">
- <t t-call="website_forum.post_answer"/>
- </div>
- <div t-if="question.uid_has_answered" class="mb16">
- <a class="btn btn-primary" t-attf-href="/forum/#{slug(forum)}/question/#{slug(question)}/edit_answer">Edit Your Previous Answer</a>
- <span class="text-muted">(only one answer per question is allowed)</span>
- </div>
- </t>
+ </div>
</template>
<!-- Utility template: Post a Comment -->
</p>
<div class="row">
<div class="col-sm-3 mt16" t-foreach="tags" t-as="tag">
- <a t-attf-href="/forum/#{ slug(forum) }/tag/#{ slug(tag) }/questions?{{ keep_query( filters='tag') }}" class="badge">
+ <a t-attf-href="/forum/#{ slug(forum) }/tag/#{ slug(tag) }/questions?{{ keep_query( filters='tag') }}" class="label label-default">
<span t-field="tag.name"/>
</a>
<span>