[ADD] New module: website_forum, a clone of askbot / stackoverflow.

This module models a forum: questions, answers, voting and comment system, karma
management. There is a link with gamification, allowing to use badges and reward
users for their participation to the forum.

Badges are temporarily commented out to ease the module beta-testing without having
to wait for some gamification improvements.

This merge also contains some fixes in access rights for gamification.

bzr revid: tde@openerp.com-20140411183646-fmkeng9fzixjrqy5
This commit is contained in:
Thibault Delavallée 2014-04-11 20:36:46 +02:00
commit 9640e839d8
31 changed files with 3870 additions and 2 deletions

View File

@ -23,7 +23,6 @@
<field name="active" eval="False" />
</record>
<record id="badge_idea" model="gamification.badge">
<field name="name">Brilliant</field>
<field name="description">With your brilliant ideas, you are an inspiration to others.</field>
@ -32,6 +31,16 @@
<field name="rule_max_number">2</field>
<field name="image" type="base64" file="gamification/static/img/badge_idea-image.png"/>
</record>
<!-- subtype for badge allocation -->
<record id="mt_badge_granted" model="mail.message.subtype">
<field name="name">Badge Granted</field>
<field name="res_model">res.users</field>
<field name="default" eval="True"/>
<field name="hidden" eval="True"/>
<field name="description">Badge Granted</field>
</record>
</data>

View File

@ -35,6 +35,7 @@ class gamification_badge_user(osv.Model):
_name = 'gamification.badge.user'
_description = 'Gamification user badge'
_order = "create_date desc"
_rec_name = "badge_name"
_columns = {
'user_id': fields.many2one('res.users', string="User", required=True),
@ -62,7 +63,12 @@ class gamification_badge_user(osv.Model):
template_id = self.pool['ir.model.data'].get_object(cr, uid, 'gamification', 'email_template_badge_received', context)
for badge_user in self.browse(cr, uid, ids, context=context):
body_html = temp_obj.render_template(cr, uid, template_id.body_html, 'gamification.badge.user', badge_user.id, context=context)
res = user_obj.message_post(cr, uid, badge_user.user_id.id, body=body_html, context=context)
res = user_obj.message_post(
cr, uid, badge_user.user_id.id,
body=body_html,
subtype='gamification.mt_badge_granted',
partner_ids=[badge_user.user_id.partner_id.id],
context=context)
return res
def create(self, cr, uid, vals, context=None):

View File

@ -4,4 +4,6 @@ goal_definition_portal,"Goal Definition Portal",gamification.model_gamification_
challenge_portal,"Goal Challenge Portal",gamification.model_gamification_challenge,base.group_portal,1,0,0,0
challenge_line_portal,"Challenge Line Portal",gamification.model_gamification_challenge_line,base.group_portal,1,0,0,0
badge_portal,"Badge Portal",gamification.model_gamification_badge,base.group_portal,1,0,0,0
badge_public,"Badge Public",gamification.model_gamification_badge,base.group_public,1,0,0,0
badge_user_portal,"Badge-user Portal",gamification.model_gamification_badge_user,base.group_portal,1,1,1,0
badge_user_public,"Badge-user Public",gamification.model_gamification_badge_user,base.group_public,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
4 challenge_portal Goal Challenge Portal gamification.model_gamification_challenge base.group_portal 1 0 0 0
5 challenge_line_portal Challenge Line Portal gamification.model_gamification_challenge_line base.group_portal 1 0 0 0
6 badge_portal Badge Portal gamification.model_gamification_badge base.group_portal 1 0 0 0
7 badge_public Badge Public gamification.model_gamification_badge base.group_public 1 0 0 0
8 badge_user_portal Badge-user Portal gamification.model_gamification_badge_user base.group_portal 1 1 1 0
9 badge_user_public Badge-user Public gamification.model_gamification_badge_user base.group_public 1 0 0 0

View File

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
import controllers
import models

View File

@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2014-Today OpenERP SA (<http://www.openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'name': 'Forum',
'category': 'Website',
'summary': 'Forum, FAQ, Q&A',
'version': '1.0',
'description': """
Ask questions, get answers, no distractions
""",
'author': 'OpenERP SA',
'depends': [
'auth_signup',
'gamification',
'website_mail',
'website_partner'
],
'data': [
'data/forum_data.xml',
'views/forum.xml',
'views/res_users.xml',
'views/website_forum.xml',
'views/ir_qweb.xml',
'security/ir.model.access.csv',
'data/badges_question.xml',
'data/badges_answer.xml',
'data/badges_participation.xml',
'data/badges_moderation.xml',
],
'qweb': [
'static/src/xml/*.xml'
],
'demo': [
'data/forum_demo.xml',
],
'css': ['static/src/css/website_forum.css'],
'installable': True,
'application': True,
}

View File

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
import main

View File

@ -0,0 +1,550 @@
# -*- coding: utf-8 -*-
from datetime import datetime
import werkzeug.urls
import simplejson
from openerp import tools
from openerp import SUPERUSER_ID
from openerp.addons.web import http
from openerp.addons.web.controllers.main import login_redirect
from openerp.addons.web.http import request
from openerp.addons.website.controllers.main import Website as controllers
from openerp.addons.website.models.website import slug
from openerp.tools import html2plaintext
controllers = controllers()
class WebsiteForum(http.Controller):
_post_per_page = 10
_user_per_page = 30
def _get_notifications(self):
cr, uid, context = request.cr, request.uid, request.context
Message = request.registry['mail.message']
badge_st_id = request.registry['ir.model.data'].xmlid_to_res_id(cr, uid, 'gamification.mt_badge_granted')
if badge_st_id:
msg_ids = Message.search(cr, uid, [('subtype_id', '=', badge_st_id), ('to_read', '=', True)], context=context)
msg = Message.browse(cr, uid, msg_ids, context=context)
else:
msg = list()
return msg
def _prepare_forum_values(self, forum=None, **kwargs):
user = request.registry['res.users'].browse(request.cr, request.uid, request.uid, context=request.context)
public_uid = request.registry['website'].get_public_user(request.cr, request.uid, request.context)
values = {'user': user, 'is_public_user': user.id == public_uid,
'notifications': self._get_notifications(),
'header': kwargs.get('header', dict()),
'searches': kwargs.get('searches', dict())}
if forum:
values['forum'] = forum
elif kwargs.get('forum_id'):
values['forum'] = request.registry['forum.forum'].browse(request.cr, request.uid, kwargs.pop('forum_id'), context=request.context)
values.update(kwargs)
return values
# Forum
# --------------------------------------------------
@http.route(['/forum'], type='http', auth="public", website=True, multilang=True)
def forum(self, **kwargs):
cr, uid, context = request.cr, request.uid, request.context
Forum = request.registry['forum.forum']
obj_ids = Forum.search(cr, uid, [], context=context)
forums = Forum.browse(cr, uid, obj_ids, context=context)
return request.website.render("website_forum.forum_all", {'forums': forums})
@http.route('/forum/new', type='http', auth="user", multilang=True, website=True)
def forum_create(self, forum_name="New Forum", **kwargs):
forum_id = request.registry['forum.forum'].create(request.cr, request.uid, {
'name': forum_name,
}, context=request.context)
return request.redirect("/forum/%s" % slug(forum_id))
@http.route('/forum/notification_read', type='json', auth="user", multilang=True, methods=['POST'], website=True)
def notification_read(self, **kwargs):
request.registry['mail.message'].set_message_read(request.cr, request.uid, [int(kwargs.get('notification_id'))], read=True, context=request.context)
return True
@http.route(['/forum/<model("forum.forum"):forum>',
'/forum/<model("forum.forum"):forum>/page/<int:page>',
'/forum/<model("forum.forum"):forum>/tag/<model("forum.tag"):tag>/questions'
], type='http', auth="public", website=True, multilang=True)
def questions(self, forum, tag=None, page=1, filters='all', sorting='date', search='', **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)
domain = [('forum_id', '=', forum.id), ('parent_id', '=', False)]
if search:
domain += ['|', ('name', 'ilike', search), ('content', 'ilike', search)]
if tag:
domain += [('tag_ids', 'in', tag.id)]
if filters == 'unanswered':
domain += [('child_ids', '=', False)]
elif filters == 'followed':
domain += [('message_follower_ids', '=', user.partner_id.id)]
else:
filters = 'all'
if sorting == 'answered':
order = 'child_count desc'
elif sorting == 'vote':
order = 'vote_count desc'
else:
sorting = 'date'
order = 'write_date desc'
question_count = Post.search(cr, uid, domain, count=True, context=context)
pager = request.website.pager(url="/forum/%s" % slug(forum), total=question_count, page=page, step=self._post_per_page, scope=self._post_per_page)
obj_ids = Post.search(cr, uid, domain, limit=self._post_per_page, offset=pager['offset'], order=order, context=context)
question_ids = Post.browse(cr, uid, obj_ids, context=context)
values = self._prepare_forum_values(forum=forum, searches=post)
values.update({
'question_ids': question_ids,
'pager': pager,
'tag': tag,
'filters': filters,
'sorting': sorting,
'search': search,
})
return request.website.render("website_forum.forum_index", values)
@http.route(['/forum/<model("forum.forum"):forum>/faq'], type='http', auth="public", website=True, multilang=True)
def forum_faq(self, forum, **post):
values = self._prepare_forum_values(forum=forum, searches=dict(), **post)
return request.website.render("website_forum.faq", values)
@http.route('/forum/get_tags', type='http', auth="public", multilang=True, methods=['GET'], website=True)
def tag_read(self, **post):
tags = request.registry['forum.tag'].search_read(request.cr, request.uid, [], ['name'], context=request.context)
data = [tag['name'] for tag in tags]
return simplejson.dumps(data)
@http.route(['/forum/<model("forum.forum"):forum>/tag'], type='http', auth="public", website=True, multilang=True)
def tags(self, forum, page=1, **post):
cr, uid, context = request.cr, request.uid, request.context
Tag = request.registry['forum.tag']
obj_ids = Tag.search(cr, uid, [('forum_id', '=', forum.id)], limit=None, context=context)
tags = Tag.browse(cr, uid, obj_ids, context=context)
values = self._prepare_forum_values(forum=forum, searches={'tags': True}, **post)
values.update({
'tags': tags,
})
return request.website.render("website_forum.tag", values)
# Questions
# --------------------------------------------------
@http.route(['/forum/<model("forum.forum"):forum>/ask'], type='http', auth="public", website=True, multilang=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", multilang=True, 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/<model("forum.forum"):forum>/question/<model("forum.post"):question>'], type='http', auth="public", website=True, multilang=True)
def question(self, forum, question, **post):
cr, uid, context = request.cr, request.uid, request.context
# increment view counter
request.registry['forum.post'].set_viewed(cr, SUPERUSER_ID, [question.id], context=context)
filters = 'question'
values = self._prepare_forum_values(forum=forum, searches=post)
values.update({
'question': question,
'header': {'question_data': True},
'filters': filters,
'reversed': reversed,
})
return request.website.render("website_forum.post_description_full", values)
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/toggle_favourite', type='json', auth="user", multilang=True, methods=['POST'], website=True)
def question_toggle_favorite(self, forum, question, **post):
if not request.session.uid:
return {'error': 'anonymous_user'}
# TDE: add check for not public
favourite = False if question.user_favourite else True
if favourite:
favourite_ids = [(4, request.uid)]
else:
favourite_ids = [(3, request.uid)]
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'favourite_ids': favourite_ids}, context=request.context)
return favourite
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/ask_for_close', type='http', auth="user", multilang=True, website=True)
def question_ask_for_close(self, forum, question, **post):
cr, uid, context = request.cr, request.uid, request.context
Reason = request.registry['forum.post.reason']
reason_ids = Reason.search(cr, uid, [], context=context)
reasons = Reason.browse(cr, uid, reason_ids, context)
values = self._prepare_forum_values(**post)
values.update({
'post': question,
'forum': forum,
'reasons': reasons,
})
return request.website.render("website_forum.close_question", values)
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/edit_answer', type='http', auth="user", website=True, multilang=True)
def question_edit_answer(self, forum, question, **kwargs):
for record in question.child_ids:
if record.create_uid.id == request.uid:
answer = record
break
return werkzeug.utils.redirect("/forum/%s/post/%s/edit" % (slug(forum), slug(answer)))
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/close', type='http', auth="user", multilang=True, methods=['POST'], website=True)
def question_close(self, forum, question, **post):
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': 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", multilang=True, website=True)
def question_reopen(self, forum, question, **kwarg):
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", multilang=True, website=True)
def question_delete(self, forum, question, **kwarg):
#instead of unlink record just change 'active' to false so user can undelete it.
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", multilang=True, website=True)
def question_undelete(self, forum, question, **kwarg):
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)))
# Post
# --------------------------------------------------
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/new', type='http', auth="public", multilang=True, methods=['POST'], website=True)
def post_new(self, forum, post, **kwargs):
if not request.session.uid:
return login_redirect()
request.registry['forum.post'].create(
request.cr, request.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)))
@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):
if not request.session.uid:
return login_redirect()
question = post.parent_id if post.parent_id else post
cr, uid, context = request.cr, request.uid, request.context
if kwargs.get('comment') and post.forum_id.id == forum.id:
# TDE FIXME: check that post_id is the question or one of its answers
if request.registry['res.users'].has_group(cr, uid, 'website_mail.group_comment'):
request.registry['forum.post'].message_post(
cr, uid, post.id,
body=kwargs.get('comment'),
type='comment',
subtype='mt_comment',
context=dict(context, mail_create_nosubcribe=True))
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/toggle_correct', type='json', auth="public", website=True)
def post_toggle_correct(self, forum, post, **kwargs):
cr, uid, context = request.cr, request.uid, request.context
if not request.session.uid:
return {'error': 'anonymous_user'}
# if user have not access to accept answer then reise warning
if post.parent_id is False or post.parent_id.create_uid.id != uid:
return {'error': 'own_post'}
# 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)
request.registry['forum.post'].write(cr, uid, [post.id, post.parent_id.id], {'is_correct': not post.is_correct}, context=context)
return not post.is_correct
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/delete', type='http', auth="user", multilang=True, website=True)
def post_delete(self, forum, post, **kwargs):
question = post.parent_id
request.registry['forum.post'].unlink(request.cr, request.uid, [post.id], context=request.context)
if question:
werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/edit', type='http', auth="user", website=True, multilang=True)
def post_edit(self, forum, post, **kwargs):
tags = ""
for tag_name in post.tag_ids:
tags += tag_name.name + ","
values = self._prepare_forum_values(forum=forum)
values.update({
'tags': tags,
'post': post,
'is_answer': bool(post.parent_id),
'searches': kwargs
})
return request.website.render("website_forum.edit_post", values)
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/save', type='http', auth="user", multilang=True, 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('[]'):
Tag = request.registry['forum.tag']
tags = kwargs.get('question_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
else:
new_tag = Tag.create(cr, uid, {'name': tag, 'forum_id': forum.id}, context=context)
question_tags.append(new_tag)
vals = {
'tag_ids': [(6, 0, question_tags)],
'name': kwargs.get('question_name'),
'content': kwargs.get('content'),
}
request.registry['forum.post'].write(cr, uid, [post.id], vals, context=context)
question = post.parent_id if post.parent_id else post
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/upvote', type='json', auth="public", multilang=True, website=True)
def post_upvote(self, forum, post, **kwargs):
# check for karma and not self vote
if not request.session.uid:
return {'error': 'anonymous_user'}
if request.uid == post.create_uid.id:
return {'error': 'own_post'}
user = request.registry['res.users'].browse(request.cr, SUPERUSER_ID, request.uid, context=request.context)
if user.karma <= 5:
return {'error': 'not_enough_karma', 'karma': 5}
return request.registry['forum.post'].vote(request.cr, request.uid, [post.id], upvote=True, context=request.context)
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/downvote', type='json', auth="public", multilang=True, website=True)
def post_downvote(self, forum, post, **kwargs):
if not request.session.uid:
return {'error': 'anonymous_user'}
if request.uid == post.create_uid.id:
return {'error': 'own_post'}
user = request.registry['res.users'].browse(request.cr, SUPERUSER_ID, request.uid, context=request.context)
if user.karma <= 50:
return {'error': 'not_enough_karma', 'karma': 50}
return request.registry['forum.post'].vote(request.cr, request.uid, [post.id], upvote=False, context=request.context)
# User
# --------------------------------------------------
@http.route('/forum/<model("forum.forum"):forum>/users', type='http', auth="public", website=True, multilang=True)
def users(self, forum, page=1, **searches):
cr, uid, context = request.cr, request.uid, request.context
User = request.registry['res.users']
step = 30
tag_count = User.search(cr, SUPERUSER_ID, [('karma', '>', 1)], count=True, context=context)
pager = request.website.pager(url="/forum/users", total=tag_count, page=page, step=step, scope=30)
obj_ids = User.search(cr, SUPERUSER_ID, [('karma', '>', 1)], limit=step, offset=pager['offset'], context=context)
users = User.browse(cr, SUPERUSER_ID, obj_ids, context=context)
searches['users'] = 'True'
values = self._prepare_forum_values(forum=forum, searches=searches)
values .update({
'users': users,
'notifications': self._get_notifications(),
'pager': pager,
})
return request.website.render("website_forum.users", values)
@http.route(['/forum/<model("forum.forum"):forum>/user/<int:user_id>'], type='http', auth="public", website=True, multilang=True)
def open_user(self, forum, user_id=0, **post):
cr, uid, context = request.cr, request.uid, request.context
User = request.registry['res.users']
Post = request.registry['forum.post']
Vote = request.registry['forum.post.vote']
Activity = request.registry['mail.message']
Followers = request.registry['mail.followers']
Data = request.registry["ir.model.data"]
user_id = User.search(cr, SUPERUSER_ID, [('id', '=', user_id), ('karma', '>', '1')], context=context)
if not user_id:
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
user = User.browse(cr, SUPERUSER_ID, user_id[0], context=context)
# questions and answers by user
user_questions, user_answers = [], []
user_post_ids = Post.search(
cr, uid, [
('forum_id', '=', forum.id), ('create_uid', '=', user.id),
'|', ('active', '=', False), ('active', '=', True)], context=context)
user_posts = Post.browse(cr, uid, user_post_ids, context=context)
for record in user_posts:
if record.parent_id:
user_answers.append(record)
else:
user_questions.append(record)
# showing questions which user following
obj_ids = Followers.search(cr, SUPERUSER_ID, [('res_model', '=', 'forum.post'), ('partner_id', '=', user.partner_id.id)], context=context)
post_ids = [follower.res_id for follower in Followers.browse(cr, SUPERUSER_ID, obj_ids, context=context)]
que_ids = Post.search(cr, uid, [('id', 'in', post_ids), ('forum_id', '=', forum.id), ('parent_id', '=', False)], context=context)
followed = Post.browse(cr, uid, que_ids, context=context)
#showing Favourite questions of user.
fav_que_ids = Post.search(cr, uid, [('favourite_ids', '=', user.id), ('forum_id', '=', forum.id), ('parent_id', '=', False)], context=context)
favourite = Post.browse(cr, uid, fav_que_ids, context=context)
#votes which given on users questions and answers.
data = Vote.read_group(cr, uid, [('post_id.forum_id', '=', forum.id), ('post_id.create_uid', '=', user.id)], ["vote"], groupby=["vote"], context=context)
up_votes, down_votes = 0, 0
for rec in data:
if rec['vote'] == '1':
up_votes = rec['vote_count']
elif rec['vote'] == '-1':
down_votes = rec['vote_count']
total_votes = up_votes + down_votes
#Votes which given by users on others questions and answers.
post_votes = Vote.search(cr, uid, [('user_id', '=', user.id)], context=context)
vote_ids = Vote.browse(cr, uid, post_votes, context=context)
#activity by user.
model, comment = Data.get_object_reference(cr, uid, 'mail', 'mt_comment')
activity_ids = Activity.search(cr, uid, [('res_id', 'in', user_post_ids), ('model', '=', 'forum.post'), ('subtype_id', '!=', comment)], context=context)
activities = Activity.browse(cr, uid, activity_ids, context=context)
posts = {}
for act in activities:
posts[act.res_id] = True
posts_ids = Post.browse(cr, uid, posts.keys(), context=context)
posts = dict(map(lambda x: (x.id, (x.parent_id or x, x.parent_id and x or False)), posts_ids))
post['users'] = 'True'
values = self._prepare_forum_values(**post)
values.update({
'uid': uid,
'user': user,
'main_object': user,
'searches': post,
'forum': forum,
'questions': user_questions,
'answers': user_answers,
'followed': followed,
'favourite': favourite,
'total_votes': total_votes,
'up_votes': up_votes,
'down_votes': down_votes,
'activities': activities,
'posts': posts,
'vote_post': vote_ids,
})
return request.website.render("website_forum.user_detail_full", values)
@http.route('/forum/<model("forum.forum"):forum>/user/<model("res.users"):user>/edit', type='http', auth="user", multilang=True, website=True)
def edit_profile(self, forum, user, **kwargs):
country = request.registry['res.country']
country_ids = country.search(request.cr, SUPERUSER_ID, [], context=request.context)
countries = country.browse(request.cr, SUPERUSER_ID, country_ids, context=request.context)
values = self._prepare_forum_values(forum=forum, searches=kwargs)
values.update({
'countries': countries,
'notifications': self._get_notifications(),
})
return request.website.render("website_forum.edit_profile", values)
@http.route('/forum/<model("forum.forum"):forum>/user/<model("res.users"):user>/save', type='http', auth="user", multilang=True, website=True)
def save_edited_profile(self, forum, user, **kwargs):
request.registry['res.users'].write(request.cr, request.uid, [user.id], {
'name': kwargs.get('name'),
'website': kwargs.get('website'),
'email': kwargs.get('email'),
'city': kwargs.get('city'),
'country_id': kwargs.get('country'),
'website_description': kwargs.get('description'),
}, context=request.context)
return werkzeug.utils.redirect("/forum/%s/user/%d" % (slug(forum), user.id))
# Badges
# --------------------------------------------------
@http.route('/forum/<model("forum.forum"):forum>/badge', type='http', auth="public", website=True, multilang=True)
def badges(self, forum, **searches):
cr, uid, context = request.cr, request.uid, request.context
Badge = request.registry['gamification.badge']
badge_ids = Badge.search(cr, SUPERUSER_ID, [('challenge_ids.category', '=', 'forum')], context=context)
badges = Badge.browse(cr, uid, badge_ids, context=context)
values = self._prepare_forum_values(forum=forum, searches={'badges': True})
values.update({
'badges': badges,
})
return request.website.render("website_forum.badge", values)
@http.route(['/forum/<model("forum.forum"):forum>/badge/<model("gamification.badge"):badge>'], type='http', auth="public", website=True, multilang=True)
def badge_users(self, forum, badge, **kwargs):
user_ids = [badge_user.user_id.id for badge_user in badge.owner_ids]
users = request.registry['res.users'].browse(request.cr, SUPERUSER_ID, user_ids, context=request.context)
values = self._prepare_forum_values(forum=forum, searches={'badges': True})
values.update({
'badge': badge,
'users': users,
})
return request.website.render("website_forum.badge_user", values)
# 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", multilang=True, website=True)
def convert_comment_to_answer(self, forum, post, comment, **kwarg):
values = {
'content': comment.body,
}
request.registry['mail.message'].unlink(request.cr, request.uid, [comment.id], context=request.context)
question = post.parent_id if post.parent_id else post
return self.post_new(forum, question, **values)
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/convert_to_comment', type='http', auth="user", multilang=True, 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)
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/comment/<model("mail.message"):comment>/delete', type='json', auth="user", multilang=True, 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

View File

@ -0,0 +1,263 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- QUALITY (VOTES) -->
<!-- Teacher: at least 3 upvotes -->
<!-- <record id="badge_a_1" model="gamification.badge">
<field name="name">Teacher</field>
<field name="description">Received at least 3 upvote for an answer for the first time</field>
<field name="level">bronze</field>
</record>
<record model="gamification.goal.definition" id="definition_teacher">
<field name="name">Teacher</field>
<field name="description">Received at least 3 upvote for an answer for the first time</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '!=', False), ('vote_count', '>=', 3)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_teacher">
<field name="name">Teacher</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_a_1')" />
<field name="autojoin_group_id" eval="ref('base.group_user')"/>
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_teacher">
<field name="definition_id" eval="ref('definition_teacher')"/>
<field name="challenge_id" eval="ref('challenge_teacher')"/>
<field name="target_goal">1</field>
</record> -->
<!-- Nice: at least 4 upvotes -->
<!-- <record id="badge_a_2" model="gamification.badge">
<field name="name">Nice Answer</field>
<field name="description">Answer voted up 4 times</field>
<field name="level">bronze</field>
</record>
<record model="gamification.goal.definition" id="definition_nice_answer">
<field name="name">Nice Answer</field>
<field name="description">Answer voted up 4 times</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '!=', False), ('vote_count', '>=', 4)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_nice_answer">
<field name="name">Nice Answer</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_a_2')" />
<field name="autojoin_group_id" eval="ref('base.group_user')"/>
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_nice_answer">
<field name="definition_id" eval="ref('definition_nice_answer')"/>
<field name="challenge_id" eval="ref('challenge_nice_answer')"/>
<field name="target_goal">1</field>
</record> -->
<!-- Good: at least 6 upvotes -->
<!-- <record id="badge_a_3" model="gamification.badge">
<field name="name">Good Answer</field>
<field name="description">Answer voted up 6 times</field>
<field name="level">silver</field>
</record>
<record model="gamification.goal.definition" id="definition_good_answer">
<field name="name">Good Answer</field>
<field name="description">Answer voted up 6 times</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '!=', False), ('vote_count', '>=', 6)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_good_answer">
<field name="name">Good Answer</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_a_3')" />
<field name="autojoin_group_id" eval="ref('base.group_user')"/>
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_good_answer">
<field name="definition_id" eval="ref('definition_good_answer')"/>
<field name="challenge_id" eval="ref('challenge_good_answer')"/>
<field name="target_goal">1</field>
</record> -->
<!-- Great: at least 15 upvotes -->
<!-- <record id="badge_a_4" model="gamification.badge">
<field name="name">Great Answer</field>
<field name="description">Answer voted up 15 times</field>
<field name="level">gold</field>
</record>
<record model="gamification.goal.definition" id="definition_great_answer">
<field name="name">Great Answer</field>
<field name="description">Answer voted up 15 times</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '!=', False), ('vote_count', '>=', 15)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_great_answer">
<field name="name">Great Answer</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_a_4')" />
<field name="autojoin_group_id" eval="ref('base.group_user')"/>
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_great_answer">
<field name="definition_id" eval="ref('definition_great_answer')"/>
<field name="challenge_id" eval="ref('challenge_great_answer')"/>
<field name="target_goal">1</field>
</record> -->
<!-- ACCEPTANCE -->
<!-- Enlightened: at least 3 upvotes for an accepted answer -->
<!-- <record id="badge_a_5" model="gamification.badge">
<field name="name">Enlightened</field>
<field name="description">Answer was accepted with 3 or more votes</field>
<field name="level">silver</field>
</record>
<record model="gamification.goal.definition" id="definition_enlightened">
<field name="name">Enlightened</field>
<field name="description">Answer was accepted with 3 or more votes</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')"/>
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '!=', False), ('vote_count', '>=', 3), ('is_correct', '=', True)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_enlightened">
<field name="name">Enlightened</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_a_5')" />
<field name="autojoin_group_id" eval="ref('base.group_user')"/>
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_enlightened">
<field name="definition_id" eval="ref('definition_enlightened')"/>
<field name="challenge_id" eval="ref('challenge_enlightened')"/>
<field name="target_goal">1</field>
</record> -->
<!-- Guru: at least 15 upvotes for an accepted answer -->
<!-- <record id="badge_a_6" model="gamification.badge">
<field name="name">Guru</field>
<field name="description">Answer accepted with 15 or more votes</field>
<field name="level">silver</field>
</record>
<record model="gamification.goal.definition" id="definition_guru">
<field name="name">Guru</field>
<field name="description">Answer accepted with 15 or more votes</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '!=', False), ('vote_count', '>=', 15), ('is_correct', '=', True)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_guru">
<field name="name">Great Answer</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_a_6')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_guru">
<field name="definition_id" eval="ref('definition_guru')" />
<field name="target_goal">1</field>
<field name="challenge_id" eval="ref('challenge_guru')" />
</record> -->
<!-- Necromancer: 30 days old question -->
<!-- <record id="badge_a_7" model="gamification.badge">
<field name="name">Necromancer</field>
<field name="description">Answered a question more than 30 days later with at least 2 votes</field>
<field name="level">silver</field>
</record>
<record model="gamification.goal.definition" id="definition_necromancer">
<field name="name">Necromancer</field>
<field name="description">Answered a question more than 30 days later with at least 2 votes</field>
<field name="computation_mode">python</field>
<field name="compute_code">def get_posts(cr, uid, context=None):
res = 1
Post = self.pool['website.forum.post']
user_posts = Post.search(cr, uid, [('create_uid','=',object.user_id.id), ('parent_id', '!=', False), ('vote_count', '>=', 2)], context=context)
for post in Post.browse(cr, uid, user_posts, context=context):
print post.parent_id.create_date
question_date = datetime.strptime(post.parent_id.create_date, "%Y-%m-%d %H:%M:%S")
answer_date = datetime.strptime(post.create_date, "%Y-%m-%d %H:%M:%S")
if ((question_date - answer_date).days) >= 30:
res += 1
return res
result = get_posts(cr, uid, context=context)
</field>
<field name="display_mode">boolean</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_necromancer">
<field name="name">Necromancer</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_18')" />
<field name="autojoin_group_id" eval="ref('base.group_user')"/>
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_necromancer">
<field name="definition_id" eval="ref('definition_necromancer')"/>
<field name="challenge_id" eval="ref('challenge_necromancer')"/>
<field name="target_goal">2</field>
</record> -->
<!-- Sealf Leaner: own question, 3+ upvotes -->
<!-- <record id="badge_a_8" model="gamification.badge">
<field name="name">Self-Learner</field>
<field name="description">Answered own question with at least 4 up votes</field>
<field name="level">gold</field>
</record>
<record model="gamification.goal.definition" id="definition_self_learner">
<field name="name">Self-Learner</field>
<field name="description">Answere own question with at least 4 up votes</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '!=', False), ('parent_id.create_uid', '=', user.id), ('vote_count', '>=', 3)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_self_learner">
<field name="name">Self-Learner</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_a_8')" />
<field name="autojoin_group_id" eval="ref('base.group_user')"/>
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_self_learner">
<field name="definition_id" eval="ref('definition_self_learner')"/>
<field name="target_goal">1</field>
<field name="challenge_id" eval="ref('challenge_self_learner')"/>
</record> -->
</data>
</openerp>

View File

@ -0,0 +1,303 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Cleanup: answer or question edition -->
<!-- <record id="badge_3" model="gamification.badge">
<field name="name">Cleanup</field>
<field name="description">First rollback</field>
<field name="level">gold</field>
</record>
<record model="gamification.goal.definition" id="definition_cleanup">
<field name="name">Cleanup</field>
<field name="description">Edit answer or question</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('mail.model_mail_message')"/>
<field name="domain" eval="[('author_id', '=', user.partner_id.id), ('model', '=', 'forum.post'), ('subtype_id', 'in', [ref('website_forum.mt_answer_edit'), ref('website_forum.mt_question_edit')])]"/>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_cleanup">
<field name="name">Cleanup</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_3')"/>
<field name="autojoin_group_id" eval="ref('base.group_user')"/>
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_cleanup">
<field name="definition_id" eval="ref('definition_cleanup')"/>
<field name="challenge_id" eval="ref('challenge_cleanup')"/>
<field name="target_goal">1</field>
</record> -->
<!-- Critic: downvote based -->
<!-- <record id="badge_5" model="gamification.badge">
<field name="name">Critic</field>
<field name="description">First downvote</field>
<field name="level">bronze</field>
</record>
<record model="gamification.goal.definition" id="definition_critic">
<field name="name">Critic</field>
<field name="description">First downvote</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post_vote')"/>
<field name="domain">[('create_uid', '=', user.id), ('vote', '=', '-1')]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_critic">
<field name="name">Critic</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_5')" />
<field name="autojoin_group_id" eval="ref('base.group_user')"/>
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_critic">
<field name="definition_id" eval="ref('definition_critic')"/>
<field name="challenge_id" eval="ref('challenge_critic')"/>
<field name="target_goal">1</field>
</record> -->
<!-- Disciplined: delete own post with >=3 upvotes -->
<!-- <record id="badge_6" model="gamification.badge">
<field name="name">Disciplined</field>
<field name="description">Deleted own post with 3 or more upvotes</field>
<field name="level">bronze</field>
</record>
<record model="gamification.goal.definition" id="definition_disciplined">
<field name="name">Disciplined</field>
<field name="description">Delete own post with 3 or more upvotes</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('vote_count', '>=', 3), ('active', '=', False)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_disciplined">
<field name="name">Disciplined</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_6')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_disciplined">
<field name="definition_id" eval="ref('definition_disciplined')"/>
<field name="challenge_id" eval="ref('challenge_disciplined')"/>
<field name="target_goal">1</field>
</record> -->
<!-- Editor: first edit -->
<!-- <record id="badge_7" model="gamification.badge">
<field name="name">Editor</field>
<field name="description">First edit</field>
<field name="level">gold</field>
</record>
<record model="gamification.goal.definition" id="definition_editor">
<field name="name">Editor</field>
<field name="description">First edit of answer or question</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('mail.model_mail_message')" />
<field name="domain">[('create_uid','=',user.id), '|', ('name','!=',False), ('content','!=',False)]</field>
<field name="domain" eval="[('author_id', '=', user.partner_id.id), ('model', '=', 'forum.post'), ('subtype_id', 'in', [ref('website_forum.mt_answer_edit'), ref('website_forum.mt_question_edit')])]"/>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_editor">
<field name="name">Editor</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_7')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_editor">
<field name="definition_id" eval="ref('definition_editor')"/>
<field name="challenge_id" eval="ref('challenge_editor')"/>
<field name="target_goal">1</field>
</record> -->
<!-- <record id="badge_22" model="gamification.badge">
<field name="name">Organizer</field>
<field name="description">First retag</field>
<field name="level">bronze</field>
</record> -->
<!-- <record model="gamification.goal.definition" id="definition_notable_question">
<field name="name">Organizer</field>
<field name="description">Your First retag</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_website_forum_post_history')" />
<field name="domain">[('create_uid','=',user.id), ('tags','!=',False)]</field>
<field name="condition">higher</field>
</record> -->
<!-- <record model="gamification.challenge" id="challenge_notable_question">
<field name="name">Organizer</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_22')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record> -->
<!-- <record model="gamification.challenge.line" id="line_notable_question">
<field name="definition_id" eval="ref('definition_notable_question')" />
<field name="target_goal">1</field>
<field name="challenge_id" eval="ref('challenge_notable_question')" />
</record> -->
<!-- <record id="badge_29" model="gamification.badge">
<field name="name">Associate Editor</field>
<field name="description">Edited 30 entries</field>
<field name="level">silver</field>
</record> -->
<!-- <record model="gamification.goal.definition" id="definition_associate_editor">
<field name="name">Associate Editor</field>
<field name="description">Edit 30 answer or question</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_website_forum_post_history')" />
<field name="domain">[('create_uid','=',user.id), '|', ('name','!=',False), ('content','!=',False)]</field>
<field name="condition">higher</field>
</record> -->
<!-- <record model="gamification.challenge" id="challenge_associate_editor">
<field name="name">Associate Editor</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_29')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record> -->
<!-- <record model="gamification.challenge.line" id="line_associate_editor">
<field name="definition_id" eval="ref('definition_associate_editor')" />
<field name="target_goal">30</field>
<field name="challenge_id" eval="ref('challenge_associate_editor')" />
</record> -->
<!-- Enthusiast: vote for 15 days in a row -->
<!-- <record id="badge_9" model="gamification.badge">
<field name="name">Enthusiast</field>
<field name="description">Voted on questions/answers for 15 days in a row</field>
<field name="level">silver</field>
</record>
<record model="gamification.goal.definition" id="definition_enthusiast">
<field name="name">Enthusiast</field>
<field name="description">Vote on questions/answers for 15 days in a row</field>
<field name="computation_mode">python</field>
<field name="compute_code">start_date = date.today() - timedelta(days=16)
end_date = date.today() - timedelta(days=1)
cr.execute('SELECT COUNT(id), create_date from forum_post_vote where create_date &gt;= %s and create_date &lt;= %s and user_id = %s GROUP BY create_date',(start_date,end_date, object.user_id.id,))
data = cr.dictfetchall()
result = int(len(data) >= 15)</field>
<field name="display_mode">boolean</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_enthusiast">
<field name="name">Enthusiast</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_9')" />
<field name="autojoin_group_id" eval="ref('base.group_user')"/>
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_enthusiast">
<field name="definition_id" eval="ref('definition_enthusiast')"/>
<field name="challenge_id" eval="ref('challenge_enthusiast')"/>
<field name="target_goal">1</field>
</record>
<record id="badge_31" model="gamification.badge">
<field name="name">Supporter</field>
<field name="description">First upvote</field>
<field name="level">gold</field>
</record> -->
<!-- <record model="gamification.goal.definition" id="definition_supporter">
<field name="name">Supporter</field>
<field name="description">First upwnvote</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post_vote')" />
<field name="domain">[('user_id','=',user.id), ('vote', '=', '1')]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_supporter">
<field name="name">Supporter</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_31')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_supporter">
<field name="definition_id" eval="ref('definition_supporter')" />
<field name="target_goal">1</field>
<field name="challenge_id" eval="ref('challenge_supporter')" />
</record> -->
<!-- <record id="badge_23" model="gamification.badge">
<field name="name">Peer Pressure</field>
<field name="description">Deleted own post with 3 or more downvotes</field>
<field name="level">gold</field>
</record>
<record model="gamification.goal.definition" id="definition_peer_pressure">
<field name="name">Peer Pressure</field>
<field name="description">Delete own post with 3 or more down votes</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid','=',user.id), ('vote_count', '&lt;=', -3), ('active', '=', False)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_peer_pressure">
<field name="name">Peer Pressure</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_23')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_peer_pressure">
<field name="definition_id" eval="ref('definition_peer_pressure')" />
<field name="target_goal">1</field>
<field name="challenge_id" eval="ref('challenge_peer_pressure')" />
</record> -->
</data>
</openerp>

View File

@ -0,0 +1,208 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Biography: complet your profile -->
<!-- <record id="badge_p_1" model="gamification.badge">
<field name="name">Autobiographer</field>
<field name="description">Completed own biography</field>
<field name="level">bronze</field>
</record>
<record model="gamification.goal.definition" id="definition_configure_profile">
<field name="name">Completed own biography</field>
<field name="description">Write some information about your self</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('base.model_res_users')" />
<field name="domain">[('id','=',user.id),
('partner_id.country_id', '!=', False),
('partner_id.city', '!=', False),
('partner_id.email', '!=', False)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_configure_profile">
<field name="name">Complete own biography</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_p_1')"/>
<field name="autojoin_group_id" eval="ref('base.group_user')"/>
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_configure_profile">
<field name="definition_id" eval="ref('definition_configure_profile')"/>
<field name="challenge_id" eval="ref('challenge_configure_profile')"/>
<field name="target_goal">1</field>
</record> -->
<!-- Commentator: at least 10 comments posted on posts -->
<!-- <record id="badge_p_2" model="gamification.badge">
<field name="name">Commentator</field>
<field name="description">Posted 10 comments</field>
<field name="level">bronze</field>
</record>
<record model="gamification.goal.definition" id="definition_commentator">
<field name="name">Commentator</field>
<field name="description">Comment an answer or a question</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('mail.model_mail_message')"/>
<field name="domain" eval="[('author_id', '=', user.partner_id.id), ('type', '=', 'comment'), ('subtype_id', '=', ref('mail.mt_comment')), ('model', '=', 'forum post')]"/>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_commentator">
<field name="name">Commentator</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_p_2')"/>
<field name="autojoin_group_id" eval="ref('base.group_user')"/>
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_commentator">
<field name="definition_id" eval="ref('definition_commentator')"/>
<field name="challenge_id" eval="ref('challenge_commentator')"/>
<field name="target_goal">10</field>
</record> -->
<!-- Pundit: 10 comments with at least score of 10 -->
<!-- <record id="badge_25" model="gamification.badge">
<field name="name">Pundit</field>
<field name="description">Left 10 comments with score of 10 or more</field>
<field name="level">silver</field>
</record>
<record model="gamification.goal.definition" id="definition_pundit">
<field name="name">Pundit</field>
<field name="description">Post 10 comments with score of 10 or more</field>
<field name="computation_mode">python</field>
<field name="compute_code">def get_count(cr, uid, context=None):
res = 1
Message = self.pool['mail.message']
Post = self.pool['website.forum.post']
user_message = Message.read_group(cr, uid,[('create_uid','=',object.user_id.id), ('type', '=', 'comment'), ('model', '=', 'website.forum.post')], ['res_id'], groupby=['res_id'], context=context)
for rec in user_message:
if rec.get('res_id_count') >= 10:
post = Post.browse(cr, uid, rec.get('res_id'), context=context)
if post.vote_count >= 10:
res += 1
return res
result = get_count(cr, uid, context=context)
</field>
<field name="display_mode">boolean</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_pundit">
<field name="name">Pundit</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_25')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_pundit">
<field name="definition_id" eval="ref('definition_pundit')" />
<field name="target_goal">2</field>
<field name="challenge_id" eval="ref('challenge_pundit')" />
</record> -->
<!-- Chief Commentator: 100 comments -->
<!-- <record id="badge_p_4" model="gamification.badge">
<field name="name">Chief Commentator</field>
<field name="description">Posted 100 comments</field>
<field name="level">silver</field>
</record>
<record model="gamification.challenge" id="challenge_chief_commentator">
<field name="name">Commentator</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_p_4')"/>
<field name="autojoin_group_id" eval="ref('base.group_user')"/>
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_chief_commentator">
<field name="definition_id" eval="ref('definition_commentator')"/>
<field name="challenge_id" eval="ref('challenge_chief_commentator')"/>
<field name="target_goal">100</field>
</record> -->
<!-- Expert: tag-based activity -->
<!-- <record id="badge_10" model="gamification.badge">
<field name="name">Expert</field>
<field name="description">Posted more than 10 questions or answers in one tag</field>
<field name="level">silver</field>
</record>
<record model="gamification.goal.definition" id="definition_expert">
<field name="name">Expert</field>
<field name="description">Post more than 10 questions in one tag</field>
<field name="computation_mode">python</field>
<field name="compute_code">def get_counter(cr, uid, context=None):
res = 1
Post = pool['forum.post']
Tag = pool['forum.tag']
for tag_id in Tag.search(cr, uid, [], context=context):
post_count = Post.search_count(cr, uid , [('tag_ids', 'in', tag_id), ('user_id', '=', object.user_id.id)], context=context)
if post_count >= 10:
res += 1
return res
result = get_counter(cr, uid, context=context)
</field>
<field name="display_mode">boolean</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_expert">
<field name="name">Expert</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_10')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_expert">
<field name="definition_id" eval="ref('definition_expert')" />
<field name="target_goal">2</field>
<field name="challenge_id" eval="ref('challenge_expert')" />
</record> -->
<!-- <record id="badge_32" model="gamification.badge">
<field name="name">Taxonomist</field>
<field name="description">Created a tag used by 15 questions</field>
<field name="level">silver</field>
</record>
<record model="gamification.goal.definition" id="definition_taxonomist">
<field name="name">Taxonomist</field>
<field name="description">Create a tag which can used in minimum 15 questions</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_website_forum_tag')" />
<field name="domain">[('create_uid','=',user.id), ('posts_count', '>=', 15)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_taxonomist">
<field name="name">Taxonomist</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_32')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_taxonomist">
<field name="definition_id" eval="ref('definition_taxonomist')" />
<field name="target_goal">1</field>
<field name="challenge_id" eval="ref('challenge_taxonomist')" />
</record> -->
</data>
</openerp>

View File

@ -0,0 +1,343 @@
<!-- <?xml version="1.0" encoding="utf-8"?> -->
<openerp>
<data>
<!-- POPULARITY (VIEWS) -->
<!-- Popular: 150 views -->
<!-- <record id="badge_q_1" model="gamification.badge">
<field name="name">Popular Question</field>
<field name="description">Asked a question with at least 150 views</field>
<field name="level">bronze</field>
</record>
<record model="gamification.goal.definition" id="definition_popular_question">
<field name="name">Popular Question</field>
<field name="description">Asked a question with at least 150 views</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '=', False), ('views', '>=', 150)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_popular_question">
<field name="name">Popular Question</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_q_1')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_popular_question">
<field name="definition_id" eval="ref('definition_popular_question')"/>
<field name="challenge_id" eval="ref('challenge_popular_question')"/>
<field name="target_goal">1</field>
</record> -->
<!-- Notable: 250 views -->
<!-- <record id="badge_q_2" model="gamification.badge">
<field name="name">Notable Question</field>
<field name="description">Asked a question with at least 250 views</field>
<field name="level">silver</field>
</record>
<record model="gamification.goal.definition" id="definition_notable_question">
<field name="name">Notable Question</field>
<field name="description">Asked a question with at least 250 views</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '=', False), ('views', '>=', 250)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_notable_question">
<field name="name">Notable Question</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_q_2')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_notable_question">
<field name="definition_id" eval="ref('definition_notable_question')"/>
<field name="challenge_id" eval="ref('challenge_notable_question')"/>
<field name="target_goal">1</field>
</record> -->
<!-- Famous: 500 views -->
<!-- <record id="badge_q_3" model="gamification.badge">
<field name="name">Famous Question</field>
<field name="description">Asked a question with at least 500 views</field>
<field name="level">gold</field>
</record>
<record model="gamification.goal.definition" id="definition_famous_question">
<field name="name">Famous Question</field>
<field name="description">Asked a question with at least 500 views</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '=', False), ('views', '>=', 500)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_famous_question">
<field name="name">Famous Question</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_q_3')" />
<field name="autojoin_group_id" eval="ref('base.group_user')"/>
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_famous_question">
<field name="definition_id" eval="ref('definition_famous_question')"/>
<field name="challenge_id" eval="ref('challenge_famous_question')"/>
<field name="target_goal">1</field>
</record> -->
<!-- FAVORITE -->
<!-- Credible: at least 1 user have it in favorite -->
<!-- <record id="badge_q_4" model="gamification.badge">
<field name="name">Credible Question</field>
<field name="description">Question set as favorite by 1 user</field>
<field name="level">bronze</field>
</record>
<record model="gamification.goal.definition" id="definition_favorite_question">
<field name="name">Credible Question</field>
<field name="description">Question set as favorite by 1 user</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '=', False), ('favourite_count', '>=', 1)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_favorite_question">
<field name="name">Credible Question</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_q_4')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_favorite_question">
<field name="definition_id" eval="ref('definition_favorite_question')"/>
<field name="challenge_id" eval="ref('challenge_favorite_question')"/>
<field name="target_goal">1</field>
</record> -->
<!-- Favorite: at least 5 users have it in favorite -->
<!-- <record id="badge_q_5" model="gamification.badge">
<field name="name">Favorite Question</field>
<field name="description">Question set as favorite by 5 users</field>
<field name="level">silver</field>
</record>
<record model="gamification.goal.definition" id="definition_favorite_question">
<field name="name">Favorite Question</field>
<field name="description">Question set as favorite by 5 users</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '=', False), ('favourite_count', '>=', 5)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_favorite_question">
<field name="name">Favorite Question</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_q_5')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_favorite_question">
<field name="definition_id" eval="ref('definition_favorite_question')"/>
<field name="challenge_id" eval="ref('challenge_favorite_question')"/>
<field name="target_goal">1</field>
</record> -->
<!-- Stellar: at least 25 users have it in favorite -->
<!-- <record id="badge_q_6" model="gamification.badge">
<field name="name">Stellar Question</field>
<field name="description">Question set as favorite by 5 users</field>
<field name="level">bronze</field>
</record>
<record model="gamification.goal.definition" id="definition_stellar_question">
<field name="name">Stellar Question</field>
<field name="description">Question set as favorite by 5 users</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '=', False), ('favourite_count', '>=', 25)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_stellar_question">
<field name="name">Stellar Question</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_q_6')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_stellar_question">
<field name="definition_id" eval="ref('definition_stellar_question')"/>
<field name="challenge_id" eval="ref('challenge_stellar_question')"/>
<field name="target_goal">1</field>
</record> -->
<!-- QUALITY (VOTES) -->
<!-- Student: at least 1 upvote -->
<!-- <record id="badge_q_7" model="gamification.badge">
<field name="name">Student</field>
<field name="description">Asked first question with at least one up vote</field>
<field name="level">gold</field>
</record>
<record model="gamification.goal.definition" id="definition_student">
<field name="name">Student</field>
<field name="description">Asked first question with at least one up vote</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '=', False), ('vote_count', '>=', 1)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_student">
<field name="name">Student</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_q_7')"/>
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_student">
<field name="definition_id" eval="ref('definition_student')"/>
<field name="challenge_id" eval="ref('challenge_student')"/>
<field name="target_goal">1</field>
</record> -->
<!-- Nice: at least 4 upvotes -->
<!-- <record id="badge_q_8" model="gamification.badge">
<field name="name">Nice Quesiotn</field>
<field name="description">Question voted up 4 times</field>
<field name="level">bronze</field>
</record>
<record model="gamification.goal.definition" id="definition_nice_question">
<field name="name">Nice Question</field>
<field name="description">Question voted up 4 times</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')"/>
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '=', False), ('vote_count', '>=', 4)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_nice_question">
<field name="name">Nice Question</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_q_8')" />
<field name="autojoin_group_id" eval="ref('base.group_user')"/>
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_nice_question">
<field name="definition_id" eval="ref('definition_nice_question')"/>
<field name="challenge_id" eval="ref('challenge_nice_question')"/>
<field name="target_goal">1</field>
</record> -->
<!-- Good: at least 6 upvotes -->
<!-- <record id="badge_q_9" model="gamification.badge">
<field name="name">Good Question</field>
<field name="description">Question voted up 6 times</field>
<field name="level">silver</field>
</record>
<record model="gamification.goal.definition" id="definition_good_question">
<field name="name">Good Question</field>
<field name="description">Question voted up 6 times</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '=', False), ('vote_count', '>=', 6)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_good_question">
<field name="name">Good Question</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_q_9')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_good_question">
<field name="definition_id" eval="ref('definition_good_question')"/>
<field name="challenge_id" eval="ref('challenge_good_question')"/>
<field name="target_goal">1</field>
</record> -->
<!-- Great: at least 15 upvotes -->
<!-- <record id="badge_q_10" model="gamification.badge">
<field name="name">Great Question</field>
<field name="description">Question voted up 15 times</field>
<field name="level">gold</field>
</record>
<record model="gamification.goal.definition" id="definition_great_question">
<field name="name">Great Question</field>
<field name="description">Question voted up 15 times</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '=', False), ('vote_count', '>=', 15)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_great_question">
<field name="name">Great Question</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_q_10')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_great_question">
<field name="definition_id" eval="ref('definition_great_question')" />
<field name="target_goal">1</field>
<field name="challenge_id" eval="ref('challenge_great_question')" />
</record> -->
<!-- Question + Answer -->
<!-- <record id="badge_26" model="gamification.badge">
<field name="name">Scholar</field>
<field name="description">Asked a question and accepted an answer</field>
<field name="level">gold</field>
</record>
<record model="gamification.goal.definition" id="definition_scholar">
<field name="name">Scholar</field>
<field name="description">Ask a question and accept an answer</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('website_forum.model_forum_post')" />
<field name="domain">[('create_uid', '=', user.id), ('parent_id', '=', False), ('is_correct', '=', True)]</field>
<field name="condition">higher</field>
</record>
<record model="gamification.challenge" id="challenge_scholar">
<field name="name">Scholar</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="reward_id" eval="ref('badge_26')" />
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">forum</field>
</record>
<record model="gamification.challenge.line" id="line_scholar">
<field name="definition_id" eval="ref('definition_scholar')" />
<field name="target_goal">1</field>
<field name="challenge_id" eval="ref('challenge_scholar')" />
</record> -->
</data>
</openerp>

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="forum_help" model="forum.forum">
<field name="name">Help</field>
</record>
<record id="menu_questions" model="website.menu">
<field name="name">Forum</field>
<field name="url" eval="'/forum/'+str(ref('website_forum.forum_help'))"/>
<field name="parent_id" ref="website.main_menu"/>
<field name="sequence" type="int">35</field>
</record>
<record id="default_allow_auth_signup" model="ir.config_parameter">
<field name="key">auth_signup.allow_uninvited</field>
<field name="value" eval="True"/>
</record>
<!-- JUMP TO FORUM AT INSTALL -->
<record id="action_open_forum" model="ir.actions.act_url">
<field name="name">Forum</field>
<field name="target">self</field>
<field name="url" eval="'/forum/'+str(ref('website_forum.forum_help'))+'/#tutorial.forum=true'"/>
</record>
<record id="base.open_menu" model="ir.actions.todo">
<field name="action_id" ref="action_open_forum"/>
<field name="state">open</field>
</record>
<!-- Answers subtypes -->
<record id="mt_answer_new" model="mail.message.subtype">
<field name="name">New Answer</field>
<field name="res_model">forum.post</field>
<field name="default" eval="True"/>
<field name="hidden" eval="False"/>
<field name="description">New Answer</field>
</record>
<record id="mt_answer_edit" model="mail.message.subtype">
<field name="name">Answer Edited</field>
<field name="res_model">forum.post</field>
<field name="default" eval="False"/>
<field name="description">Answer Edited</field>
</record>
<!-- Questions subtypes -->
<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="description">New Question</field>
</record>
<record id="mt_question_edit" model="mail.message.subtype">
<field name="name">Question Edited</field>
<field name="res_model">forum.post</field>
<field name="default" eval="False"/>
<field name="description">Question Edited</field>
</record>
</data>
<data noupdate="1">
<!-- Reasons for closing Post -->
<record id="reason_1" model="forum.post.reason">
<field name="name">duplicate question</field>
</record>
<record id="reason_2" model="forum.post.reason">
<field name="name">off-topic or not relevant</field>
</record>
<record id="reason_3" model="forum.post.reason">
<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>
</record>
<record id="reason_5" model="forum.post.reason">
<field name="name">already answered and an answer was accepted</field>
</record>
<record id="reason_6" model="forum.post.reason">
<field name="name">not relevant or out dated</field>
</record>
<record id="reason_7" model="forum.post.reason">
<field name="name">contains offensive or malicious remarks</field>
</record>
<record id="reason_8" model="forum.post.reason">
<field name="name">spam or advertising</field>
</record>
<record id="reason_9" model="forum.post.reason">
<field name="name">too localized</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1,147 @@
<h1>Guidelines</h1>
<h2><a class="faq-question">What kinds of questions can I ask here?</a></h2>
<p>
This community is for professional and enthusiast users,
partners and programmers. You can ask questions about:
</p>
<ul>
<li>how to install OpenERP on a specific infrastructure,</li>
<li>how to configure or customize OpenERP to specific business needs,</li>
<li>what's the best way to use OpenERP for a specific business need,</li>
<li>how to develop modules for your own need,</li>
<li>specific questions about OpenERP service offers, etc.</li>
</ul>
<p>
<b>Before you ask - please make sure to search for a similar question.</b> You can
search questions by their title or tags. Its also OK to
answer your own question.
</p><p>
<b>Please avoid asking questions that are too subjective
and argumentative</b> or not relevant to this community.
</p>
<h2><a class="faq-question">What should I avoid in my questions?</a></h2>
<p>
You should only ask practical, answerable questions based
on actual problems that you face. Chatty, open-ended
questions diminish the usefulness of this site and push
other questions off the front page.
</p><p>
To prevent your question from being flagged and possibly removed, avoid asking
subjective questions where …
</p>
<ul>
<li>every answer is equally valid: “Whats your favorite ______?”</li>
<li>your answer is provided along with the question, and you expect more answers: “I use ______ for ______, what do you use?”</li>
<li>there is no actual problem to be solved: “Im curious if other people feel like I do.”</li>
<li>we are being asked an open-ended, hypothetical question: “What if ______ happened?”</li>
<li>it is a rant disguised as a question: “______ sucks, am I right?”</li>
</ul>
<p>
If you fit in one of these example or if your motivation for asking the
question is “I would like to participate in a discussion about ______”, then
you should not be asking here but on our mailing lists.
However, if your motivation is “I would like others to explain ______ to me”,
then you are probably OK.
</p><p>
(The above section was adapted from Stackoverflows FAQ.)
</p><p>
More over:
</p>
<ul>
<li><b>Answers should not add or expand questions</b>. Instead either edit the question edit or add a question comment.</li>
<li><b>Answers should not comment other answers</b>. Instead add a comment on the other answers.</li>
<li><b>Answers shouldn't just point to other Questions</b>. Instead add a question comment indication "Possible duplicate of...". However, it's ok to include links to other questions or answers providing relevant additional information.</li>
<li><b>Answers shouldn't just provide a link a solution</b>. Instead provide the solution description text in your answer, even if it's just a copy/paste. Links are welcome, but should complementary to answer, referring sources or additional reading.</li>
</ul>
<h2><a class="faq-question">What should I avoid in my answers?</a></h2>
<p>
<b>Answers should not add or expand questions</b>. Instead
either edit the question or add a comment.
</p><p>
<b>Answers should not comment other answers</b>. Instead
add a comment on the other answers.
</p><p>
<b>Answers shouldn't just point to other questions</b>.
Instead add a comment indicating <i>"Possible duplicate
of..."</i>. However, it's fine to include links to other
questions or answers providing relevant additional
information. </p> <p> <b>Answers shouldn't just provide a
link a solution</b>. Instead provide the solution
description text in your answer, even if it's just a
copy/paste. Links are welcome, but should complementary to
answer, referring sources or additional reading.
</p><p>
<b>Answers should not start debates</b>
This community Q&amp;A is not a discussion group. Please avoid holding debates in
your answers as they tend to dilute the essence of questions and answers. For
brief discussions please use commenting facility.
</p> <p>
When a question or answer is upvoted, the user who posted them will gain some
points, which are called "karma points". These points serve as a rough
measure of the community trust to him/her. Various moderation tasks are
gradually assigned to the users based on those points.
</p> <p>
For example, if you ask an interesting question or give a helpful answer, your
input will be upvoted. On the other hand if the answer is misleading - it will
be downvoted. Each vote in favor will generate 10 points, each vote against
will subtract 10 points. There is a limit of 200 points that can be accumulated
for a question or answer per day. The table below explains reputation point
requirements for each type of moderation task.
</p>
<table class="table table-striped">
<tbody>
<tr>
<td class="faq-rep-item"><strong>1</strong></td>
<td>upvote, add comments</td>
</tr><tr>
<td class="faq-rep-item"><strong>10</strong></td>
<td>downvote</td>
</tr><tr>
<td class="faq-rep-item"><strong>30</strong></td>
<td>insert text link, upload files</td>
</tr><tr>
<td class="faq-rep-item"><strong>50</strong></td>
<td>insert clickable link, answer own question immediately</td>
</tr><tr>
<td class="faq-rep-item"><strong>75</strong></td>
<td>retag, edit wiki questions and answers</td>
</tr><tr>
<td class="faq-rep-item"><strong>100</strong></td>
<td>flag offensive, close own questions</td>
</tr><tr>
<td class="faq-rep-item"><strong>200</strong></td>
<td>answer/comment by email</td>
</tr><tr>
<td class="faq-rep-item"><strong>300</strong></td>
<td>edit any post, view offensive flags</td>
</tr><tr>
<td class="faq-rep-item"><strong>500</strong></td>
<td>accept any answer (after 1 week)</td>
</tr><tr>
<td class="faq-rep-item"><strong>750</strong></td>
<td>delete any comment</td>
</tr><tr>
<td class="faq-rep-item"><strong>900</strong></td>
<td>lock posts</td>
</tr><tr>
<td class="faq-rep-item"><strong>1000</strong></td>
<td>delete any question or answer</td>
</tr>
</tbody>
</table>
<h2><a class="faq-question">Why can other people edit my questions/answers?</a></h2>
<p>
The goal of this site is create a relevant knowledge base that would answer
questions related to OpenERP.
</p><p>
Therefore questions and answers can be edited like wiki pages by experienced users of
this site in order to improve the overall quality of the knowledge base content.
Such privileges are granted based on user karma level: you will be able to do the same
once your karma gets high enough.
</p><p>
If this approach is not for you, please respect the community and use Google+
communities instead.
</p>

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Tag -->
<record id="tags_0" model="forum.tag">
<field name="name">Contract</field>
<field name="forum_id" ref="website_forum.forum_help"/>
</record>
<record id="tags_1" model="forum.tag">
<field name="name">Action</field>
<field name="forum_id" ref="website_forum.forum_help"/>
</record>
<record id="tags_2" model="forum.tag">
<field name="name">ecommerce</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="views">3</field>
<field name="tag_ids" eval="[(4,ref('website_forum.tags_0')), (4,ref('website_forum.tags_1'))]"/>
</record>
<record id="question_1" model="forum.post">
<field name="name">CMS replacement for ERP and eCommerce</field>
<field name="views">8</field>
<field name="forum_id" ref="website_forum.forum_help"/>
<field name="content"><![CDATA[<p>I use Wordpress as a CMS and eCommerce platform. The developing in Wordpress is quite easy and solid but it missing ERP feature (there is single plugin to integrate with Frontaccounting) so I wonder:
Can I use OpenERP as a replacement CMS of Wordpress + eCommerce plugin?
In simple words does OpenERP became CMS+ERP platform?</p>]]></field>
<field name="tag_ids" eval="[(4,ref('website_forum.tags_2'))]"/>
</record>
<!-- Answer -->
<record id="answer_0" model="forum.post">
<field name="forum_id" ref="website_forum.forum_help"/>
<field name="content"><![CDATA[<p>Just for posterity so other can see. Here are the steps to set automatic alerts on any contract.. i.e. HR Employee, or Fleet for example. I will use fleet as an example.</p>
<ul>
<li>Step 1. As a user who has access rights to Technical Features, go to Settings --> Automated Actions. Create A new Automated Action. For the Related Document Model choose.. Contract information on a vehicle (you can also type in the actual model name.. fleet.vehicle.log.contract ) . Set the trigger date to ... Contract Expiration Date. The Next Field (Delay After Trigger Date) is a bit ridiculous. Who wants to be reminded of a contract expiration AFTER the fact? The field should say Days Before Date to Fire Action and the number should be converted to a negative. IMHO. Any way... to get a workable solution you must enter in the number in the negative. So for instance like me if you want to be warned 35 days BEFORE the expiration... put in Delay After Trigger Date.. the number -35 But the sake of testing, right now just put in -1 for 1 day before. Save the Action.
<li>Step 2. Go to Server Actions and create new Action. Call it Fleet Contract Expiration Warning. The Object will be the same as above .. Contract information on a vehicle. The Action Type is Email. For email address I just put my email. Under subject put in... [[object.name]]. This will tell you the name of the car. Message you can put any text message you like. Now save the Server Action.</li>
<li>Step 3. Now go back to the Automated Action you created and go to the Action tab next to the conditions tab. Click Add and add the server action you created . In this case Fleet Contract Expiration Warning. Then Save.</li>
<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" />
</record>
<record id="answer_1" model="forum.post">
<field name="forum_id" ref="website_forum.forum_help"/>
<field name="content">OpenERP v8 (next release) provides a web module and an e-commerce module: www.openerp.com/website_cms
The CMS editor in OpernERP web is nice but I prefer drupal for customization and there is a drupal module for OpenERP. I think WP is better than OpenERP web too.
</field>
<field name="parent_id" ref="question_1"/>
</record>
<!-- Post Vote -->
<record id="post_vote_0" model="forum.post.vote">
<field name="post_id" ref="question_0"/>
<field name="user_id" ref="base.user_demo"/>
<field name="vote">1</field>
</record>
<record id="post_vote_1" model="forum.post.vote">
<field name="post_id" ref="answer_0"/>
<field name="user_id" ref="base.user_demo"/>
<field name="vote">1</field>
</record>
<!-- Run Scheduler -->
<function model="gamification.challenge" name="_cron_update"/>
</data>
</openerp>

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
import gamification
import res_users
import forum

View File

@ -0,0 +1,286 @@
# -*- coding: utf-8 -*-
import openerp
from openerp import SUPERUSER_ID
from openerp.addons.website.models.website import slug
from openerp.osv import osv, fields
from openerp.tools.translate import _
class Forum(osv.Model):
_name = 'forum.forum'
_description = 'Forums'
_inherit = ['website.seo.metadata']
_columns = {
'name': fields.char('Name', required=True, translate=True),
'faq': fields.html('Guidelines'),
'description': fields.html('Description'),
}
def _get_default_faq(self, cr, uid, context=None):
fname = openerp.modules.get_module_resource('website_forum', 'data', 'forum_default_faq.html')
with open(fname, 'r') as f:
return f.read()
return False
_defaults = {
'description': 'This community is for professionals and enthusiasts of our products and services.',
'faq': _get_default_faq,
}
def create(self, cr, uid, values, context=None):
if context is None:
context = {}
create_context = dict(context, mail_create_nolog=True)
return super(Forum, self).create(cr, uid, values, context=create_context)
class Post(osv.Model):
_name = 'forum.post'
_description = 'Forum Post'
_inherit = ['mail.thread', 'website.seo.metadata']
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)
for vote in self.pool['forum.post.vote'].browse(cr, uid, vote_ids, context=context):
res[vote.post_id.id] = vote.vote
return res
def _get_vote_count(self, cr, uid, ids, field_name, arg, context):
res = dict.fromkeys(ids, 0)
for post in self.browse(cr, uid, ids, context=context):
for vote in post.vote_ids:
res[post.id] += int(vote.vote)
return res
def _get_post_from_vote(self, cr, uid, ids, context=None):
result = {}
for vote in self.pool['forum.post.vote'].browse(cr, uid, ids, context=context):
result[vote.post_id.id] = True
return result.keys()
def _get_user_favourite(self, cr, uid, ids, field_name, arg, context):
res = dict.fromkeys(ids, False)
for post in self.browse(cr, uid, ids, context=context):
if uid in [f.id for f in post.favourite_ids]:
res[post.id] = True
return res
def _get_favorite_count(self, cr, uid, ids, field_name, arg, context):
res = dict.fromkeys(ids, 0)
for post in self.browse(cr, uid, ids, context=context):
res[post.id] += len(post.favourite_ids)
return res
def _get_post_from_hierarchy(self, cr, uid, ids, context=None):
post_ids = set(ids)
for post in self.browse(cr, SUPERUSER_ID, ids, context=context):
if post.parent_id:
post_ids.add(post.parent_id.id)
return list(post_ids)
def _get_child_count(self, cr, uid, ids, field_name=False, arg={}, context=None):
res = dict.fromkeys(ids, 0)
for post in self.browse(cr, uid, ids, context=context):
if post.parent_id:
res[post.parent_id.id] = len(post.parent_id.child_ids)
else:
res[post.id] = len(post.child_ids)
return res
def _get_uid_answered(self, cr, uid, ids, field_name, arg, context=None):
res = dict.fromkeys(ids, False)
for post in self.browse(cr, uid, ids, context=context):
res[post.id] = any(answer.create_uid.id == uid for answer in post.child_ids)
return res
_columns = {
'name': fields.char('Title', size=128),
'forum_id': fields.many2one('forum.forum', 'Forum', required=True),
'content': fields.html('Content'),
'tag_ids': fields.many2many('forum.tag', 'forum_tag_rel', 'forum_id', 'forum_tag_id', 'Tags'),
'state': fields.selection([('active', 'Active'), ('close', 'Close'), ('offensive', 'Offensive')], 'Status'),
'views': fields.integer('Number of Views'),
'active': fields.boolean('Active'),
'is_correct': fields.boolean('Valid Answer', help='Correct Answer/ Answer on this question accepted.'),
'website_message_ids': fields.one2many(
'mail.message', 'res_id',
domain=lambda self: [
'&', ('model', '=', self._name), ('type', '=', 'comment')
],
string='Post Messages', help="Comments on forum post",
),
# history
'create_date': fields.datetime('Asked on', select=True, readonly=True),
'create_uid': fields.many2one('res.users', 'Created by', select=True, readonly=True),
'write_date': fields.datetime('Update on', select=True, readonly=True),
'write_uid': fields.many2one('res.users', 'Updated by', select=True, readonly=True),
# vote fields
'vote_ids': fields.one2many('forum.post.vote', 'post_id', 'Votes'),
'user_vote': fields.function(_get_user_vote, string='My Vote', type='integer'),
'vote_count': fields.function(
_get_vote_count, string="Votes", type='integer',
store={
'forum.post': (lambda self, cr, uid, ids, c={}: ids, ['vote_ids'], 10),
'forum.post.vote': (_get_post_from_vote, [], 10),
}),
# favorite fields
'favourite_ids': fields.many2many('res.users', string='Favourite'),
'user_favourite': fields.function(_get_user_favourite, string="My Favourite", type='boolean'),
'favourite_count': fields.function(
_get_favorite_count, string='Favorite Count', type='integer',
store={
'forum.post': (lambda self, cr, uid, ids, c={}: ids, ['favourite_ids'], 10),
}),
# hierarchy
'parent_id': fields.many2one('forum.post', 'Question', ondelete='cascade'),
'child_ids': fields.one2many('forum.post', 'parent_id', 'Answers'),
'child_count': fields.function(
_get_child_count, string="Answers", type='integer',
store={
'forum.post': (_get_post_from_hierarchy, ['parent_id', 'child_ids'], 10),
}),
'uid_has_answered': fields.function(
_get_uid_answered, string='Has Answered', type='boolean',
),
# closing
'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),
}
_defaults = {
'state': 'active',
'views': 0,
'active': True,
'vote_ids': list(),
'favourite_ids': list(),
'child_ids': list(),
}
def create(self, cr, uid, vals, context=None):
if context is None:
context = {}
create_context = dict(context, mail_create_nolog=True)
post_id = super(Post, self).create(cr, uid, vals, context=create_context)
post = self.browse(cr, uid, post_id, context=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)
else:
self.message_post(cr, uid, post.id, subject=post.name, body=_('New Question Created'), subtype='website_forum.mt_question_new', context=context)
self.pool['res.users'].write(cr, SUPERUSER_ID, [post.create_uid.id], {'karma': 2}, context=context)
return post_id
def write(self, cr, uid, ids, vals, context=None):
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):
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)
# update karma of related user when any answer accepted
if 'correct' in vals:
for post in self.browse(cr, uid, ids, context=context):
karma_value = 15 if vals.get('correct') else -15
self.pool['res.users'].write(cr, SUPERUSER_ID, [post.create_uid.id], {'karma': karma_value}, context=context)
return res
def vote(self, cr, uid, ids, upvote=True, context=None):
Vote = self.pool['forum.post.vote']
vote_ids = Vote.search(cr, uid, [('post_id', 'in', ids), ('user_id', '=', uid)], context=context)
if vote_ids:
for vote in Vote.browse(cr, uid, vote_ids, context=context):
if upvote:
new_vote = '0' if vote.vote == '-1' else '1'
else:
new_vote = '0' if vote.vote == '1' else '-1'
Vote.write(cr, uid, vote_ids, {'vote': new_vote}, context=context)
else:
for post_id in ids:
new_vote = '1' if upvote else '-1'
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 set_viewed(self, cr, uid, ids, context=None):
for post in self.browse(cr, uid, ids, context=context):
self.write(cr, uid, [post.id], {'views': post.views + 1}, context=context)
return True
class PostReason(osv.Model):
_name = "forum.post.reason"
_description = "Post Closing Reason"
_columns = {
'name': fields.char('Post Reason', required=True),
}
class Vote(osv.Model):
_name = 'forum.post.vote'
_description = 'Vote'
_columns = {
'post_id': fields.many2one('forum.post', 'Post', ondelete='cascade', required=True),
'user_id': fields.many2one('res.users', 'User'),
'vote': fields.selection([('1', '1'), ('-1', '-1'), ('0', '0')], 'Vote', required=True),
'create_date': fields.datetime('Create Date', select=True, readonly=True),
}
_defaults = {
'user_id': lambda self, cr, uid, ctx: uid,
'vote': lambda *args: '1',
}
def update_karma(self, cr, uid, ids, new_vote='0', old_vote='0', context=None):
karma_value = (int(new_vote) - int(old_vote)) * 10
if karma_value:
for vote in self.browse(cr, uid, ids, context=context):
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [vote.post_id.create_uid.id], karma_value, context=context)
return True
def create(self, cr, uid, vals, context=None):
vote_id = super(Vote, self).create(cr, uid, vals, context=context)
self.update_karma(cr, uid, [vote_id], new_vote=vals.get('vote', '1'), context=context)
return vote_id
def write(self, cr, uid, ids, values, context=None):
res = super(Vote, self).write(cr, uid, ids, values, context=context)
if 'vote' in values:
for vote in self.browse(cr, uid, ids, context=context):
self.update_karma(cr, uid, ids, new_vote=values['vote'], old_vote=vote.vote, context=context)
return res
class Tags(osv.Model):
_name = "forum.tag"
_description = "Tag"
_inherit = ['website.seo.metadata']
def _get_posts_count(self, cr, uid, ids, field_name, arg, context=None):
return dict((tag_id, self.pool['forum.post'].search_count(cr, uid, [('tag_ids', 'in', tag_id)], context=context)) for tag_id in ids)
def _get_tag_from_post(self, cr, uid, ids, context=None):
return list(set(
[tag.id for post in self.pool['forum.post'].browse(cr, SUPERUSER_ID, ids, context=context) for tag in post.tag_ids]
))
_columns = {
'name': fields.char('Name', required=True),
'forum_id': fields.many2one('forum.forum', 'Forum', required=True),
'post_ids': fields.many2many('forum.post', 'forum_tag_rel', 'tag_id', 'post_id', 'Posts'),
'posts_count': fields.function(
_get_posts_count, type='integer', string="Number of Posts",
store={
'forum.post': (_get_tag_from_post, ['tag_ids'], 10),
}
),
}

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from openerp.osv import osv, fields
class gamification_challenge(osv.Model):
_inherit = 'gamification.challenge'
def _get_categories(self, cr, uid, context=None):
res = super(gamification_challenge, self)._get_categories(cr, uid, context=context)
res.append(('forum', 'Website / Forum'))
return res
class Badge(osv.Model):
_inherit = 'gamification.badge'
_columns = {
'level': fields.selection([('bronze', 'bronze'), ('silver', 'silver'), ('gold', 'gold')], 'Forum Badge Level'),
}

View File

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
from openerp.osv import osv, fields
class Users(osv.Model):
_inherit = 'res.users'
def _get_user_badge_level(self, cr, uid, ids, name, args, context=None):
"""Return total badge per level of users"""
result = dict.fromkeys(ids, False)
badge_user_obj = self.pool['gamification.badge.user']
for id in ids:
result[id] = {
'gold_badge': badge_user_obj.search(cr, uid, [('badge_id.level', '=', 'gold'), ('user_id', '=', id)], context=context, count=True),
'silver_badge': badge_user_obj.search(cr, uid, [('badge_id.level', '=', 'silver'), ('user_id', '=', id)], context=context, count=True),
'bronze_badge': badge_user_obj.search(cr, uid, [('badge_id.level', '=', 'bronze'), ('user_id', '=', id)], context=context, count=True),
}
return result
_columns = {
'create_date': fields.datetime('Create Date', select=True, readonly=True),
'karma': fields.integer('Karma'),
'badge_ids': fields.one2many('gamification.badge.user', 'user_id', 'Badges'),
'gold_badge': fields.function(_get_user_badge_level, string="Number of gold badges", type='integer', multi='badge_level'),
'silver_badge': fields.function(_get_user_badge_level, string="Number of silver badges", type='integer', multi='badge_level'),
'bronze_badge': fields.function(_get_user_badge_level, string="Number of bronze badges", type='integer', multi='badge_level'),
}
_defaults = {
'karma': 0,
}
def add_karma(self, cr, uid, ids, karma, context=None):
for user in self.browse(cr, uid, ids, context=context):
self.write(cr, uid, [user.id], {'karma': user.karma + karma}, context=context)
return True

View File

@ -0,0 +1,19 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_forum_forum,forum.forum,model_forum_forum,,1,0,0,0
access_forum_forum_manager,forum.forum.maanger,model_forum_forum,base.group_erp_manager,1,1,1,1
access_forum_post_public,forum.post.public,model_forum_post,base.group_public,1,0,0,0
access_forum_post_portal,forum.post.portal,model_forum_post,base.group_portal,1,1,1,0
access_forum_post_user,forum.post.user,model_forum_post,base.group_user,1,1,1,1
access_forum_post_vote_public,forum.post.vote.public,model_forum_post_vote,base.group_public,1,0,0,0
access_forum_post_vote_portal,orum.post.vote.portal,model_forum_post_vote,base.group_portal,1,1,1,0
access_forum_post_vote_user,forum.post.vote.user,model_forum_post_vote,base.group_user,1,1,1,1
access_forum_post_reason_public,forum.post.reason.public,model_forum_post_reason,base.group_public,1,0,0,0
access_forum_post_reason_portal,forum.post.reason.portal,model_forum_post_reason,base.group_portal,1,0,0,0
access_forum_post_reason_user,forum.post.reason.user,model_forum_post_reason,base.group_user,1,1,1,1
access_forum_tag_public,forum.tag.public,model_forum_tag,base.group_public,1,0,1,0
access_forum_tag_portal,forum.tag.portal,model_forum_tag,base.group_portal,1,0,1,0
access_forum_tag_user,forum.tag.user,model_forum_tag,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_forum_forum forum.forum model_forum_forum 1 0 0 0
3 access_forum_forum_manager forum.forum.maanger model_forum_forum base.group_erp_manager 1 1 1 1
4 access_forum_post_public forum.post.public model_forum_post base.group_public 1 0 0 0
5 access_forum_post_portal forum.post.portal model_forum_post base.group_portal 1 1 1 0
6 access_forum_post_user forum.post.user model_forum_post base.group_user 1 1 1 1
7 access_forum_post_vote_public forum.post.vote.public model_forum_post_vote base.group_public 1 0 0 0
8 access_forum_post_vote_portal orum.post.vote.portal model_forum_post_vote base.group_portal 1 1 1 0
9 access_forum_post_vote_user forum.post.vote.user model_forum_post_vote base.group_user 1 1 1 1
10 access_forum_post_reason_public forum.post.reason.public model_forum_post_reason base.group_public 1 0 0 0
11 access_forum_post_reason_portal forum.post.reason.portal model_forum_post_reason base.group_portal 1 0 0 0
12 access_forum_post_reason_user forum.post.reason.user model_forum_post_reason base.group_user 1 1 1 1
13 access_forum_tag_public forum.tag.public model_forum_tag base.group_public 1 0 1 0
14 access_forum_tag_portal forum.tag.portal model_forum_tag base.group_portal 1 0 1 0
15 access_forum_tag_user forum.tag.user model_forum_tag base.group_user 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -0,0 +1,5 @@
all: website_forum.css
%.css: %.sass
sass -t expanded --compass --unix-newlines $< $@
watch:
sass -t expanded --compass --unix-newlines --watch .:.

View File

@ -0,0 +1,82 @@
.box {
padding-left: 8px;
padding-right: 8px;
margin-left: 4px;
margin-right: 4px;
border-radius: 4px;
min-width: 80px;
}
.box span {
font-size: 200%;
font-weight: bold;
}
.question .question-name {
font-size: 150%;
}
.oe_grey {
background-color: #eeeeee;
}
.img-avatar {
max-width: 50px;
margin-right: 10px;
}
.badge-gold {
color: #ffcc00;
}
.badge-silver {
color: #cccccc;
}
.badge-bronze {
color: #eea91e;
}
.oe_answer_true {
color: #428bca;
}
.oe_answer_false {
color: #999999;
}
.forum_favourite_question {
color: #ffcc00 !important;
}
.load_tags {
width: 845px !important;
}
a.no-decoration {
cursor: pointer;
text-decoration: none !important;
}
.faq-question:hover {
text-decoration: none !important;
color: #428bca;
}
.oe_comment_grey {
background-color: whitesmoke;
padding: 4px;
}
.country_flag {
max-height: 16px;
display: inline-block;
margin-left: 2px;
}
.tag_text .text-core .text-wrap textarea, .tag_text .text-core .text-wrap input, .tag_text .text-core .text-wrap .text-dropdown, .tag_text .text-core .text-wrap .text-prompt {
font: 1.2em "Helvetica Neue", Helvetica, Arial, sans-serif !important;
}
.tag_text .text-core .text-wrap .text-tags .text-tag .text-button {
font: 1.2em "Helvetica Neue", Helvetica, Arial, sans-serif !important;
height: 1.2em !important;
}

View File

@ -0,0 +1,66 @@
.box
padding-left: 8px
padding-right: 8px
margin-left: 4px
margin-right: 4px
border-radius: 4px
min-width: 80px
span
font-size: 200%
font-weight: bold
.question
.question-name
font-size: 150%
.oe_grey
background-color: #eeeeee
.img-avatar
max-width: 50px
margin-right: 10px
.badge-gold
color: #ffcc00
.badge-silver
color: #cccccc
.badge-bronze
color: #eea91e
.oe_answer_true
color: #428bca
.oe_answer_false
color: #999999
.forum_favourite_question
color: #ffcc00 !important
.load_tags
width: 845px !important
a.no-decoration
cursor: pointer
text-decoration: none !important
.faq-question:hover
text-decoration: none !important
color: #428bca
.oe_comment_grey
background-color: #f5f5f5
padding: 4px
.country_flag
max-height: 16px
display: inline-block
margin-left: 2px
.tag_text .text-core .text-wrap
textarea, input, .text-dropdown, .text-prompt
font: 1.2em "Helvetica Neue", Helvetica, Arial, sans-serif !important
.text-tags .text-tag .text-button
font: 1.2em "Helvetica Neue", Helvetica, Arial, sans-serif !important
height: 1.2em !important

View File

@ -0,0 +1,31 @@
(function () {
'use strict';
var website = openerp.website;
var _t = openerp._t;
// website.EditorBar.include({
// start: function () {
// this.registerTour(new website.Tour.Forum(this));
// return this._super();
// },
// });
// website.Tour.Forum = website.Tour.extend({
// id: 'question',
// name: "Create a question",
// testPath: '/forum(/[0-9]+/register)?',
// init: function (editor) {
// var self = this;
// self.steps = [
// {
// title: _t("Create a question"),
// content: _t("Let's go through the first steps to create a new question."),
// popover: { next: _("Start Tutorial"), end: _("Skip It") },
// },
// ];
// return this._super();
// }
// });
}());

View File

@ -0,0 +1,31 @@
(function() {
"use strict";
var website = openerp.website;
var _t = openerp._t;
website.add_template_file('/website_forum/static/src/xml/website_forum.xml');
website.is_editable = true;
website.EditorBar.include({
start: function() {
website.is_editable_button = website.is_editable_button || !!$("#wrap").size();
var res = this._super();
this.$(".dropdown:has(.oe_content_menu)").removeClass("hidden");
return res;
},
events: _.extend({}, website.EditorBar.prototype.events, {
'click a[data-action=new_forum]': function (ev) {
ev.preventDefault();
website.prompt({
id: "editor_new_forum",
window_title: _t("New Forum"),
input: "Forum Name",
}).then(function (forum_name) {
website.form('/forum/new', 'POST', {
forum_name: forum_name
});
});
}
}),
});
})();

View File

@ -0,0 +1,156 @@
$(document).ready(function () {
$('.vote_up ,.vote_down').on('click', function (ev) {
ev.preventDefault();
var $link = $(ev.currentTarget);
openerp.jsonRpc($link.attr('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;">'+
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">&times;</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;">'+
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">&times;</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="position:absolute; margin-top: -30px; margin-left: 90px;">'+
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">&times;</button>'+
'Sorry, at least ' + data['karma'] + ' karma is required to vote'+
'</div>');
}
vote_alert = $link.parent().find("#vote_alert");
if (vote_alert.length == 0) {
$link.parent().append($warning);
}
} else {
$link.parent().find("#vote_count").html(data['vote_count']);
if (data['vote_count'] == 0) {
$link.parent().find(".text-success").removeClass("text-success");
$link.parent().find(".text-warning").removeClass("text-warning");
} else {
if (data['vote_count'] == 1) {
$link.addClass("text-success");
} else {
$link.addClass("text-warning");
}
}
}
});
return true;
});
$('.accept_answer').on('click', function (ev) {
ev.preventDefault();
var $link = $(ev.currentTarget);
openerp.jsonRpc($link.attr('href'), 'call', {}).then(function (data) {
if (data['error']) {
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">&times;</button>'+
'Sorry, anonymous users cannot choose correct answer.'+
'</div>');
} else if (data['error'] == 'own_post'){
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">&times;</button>'+
'Sorry, the user who asked this question can only accept the answer as correct.'+
'</div>');
}
correct_answer_alert = $link.parent().find("#correct_answer_alert");
if (correct_answer_alert.length == 0) {
$link.parent().append($warning);
}
} else {
$link.parents().find(".oe_answer_true").removeClass("oe_answer_true alert alert-info").addClass('oe_answer_false');
$link.parents().find(".answer_correct").removeClass("answer_correct alert alert-info")
if (data) {
$link.removeClass("oe_answer_false").addClass('oe_answer_true');
$link.parents('.forum_answer').first().addClass("answer_correct alert alert-info");
}
}
});
return true;
});
$('.favourite_question').on('click', function (ev) {
ev.preventDefault();
var $link = $(ev.currentTarget);
openerp.jsonRpc($link.attr('href'), 'call', {}).then(function (data) {
if (data) {
$link.addClass("forum_favourite_question")
} else {
$link.removeClass("forum_favourite_question")
}
});
return true;
});
$('.comment_delete').on('click', function (ev) {
ev.preventDefault();
var $link = $(ev.currentTarget);
openerp.jsonRpc($link.attr('href'), 'call', {}).then(function (data) {
$link.parents('.comment').first().remove();
});
return true;
});
$('.notification_close').on('click', function (ev) {
ev.preventDefault();
var $link = $(ev.currentTarget);
openerp.jsonRpc("/forum/notification_read", 'call', {
'notification_id': $link.attr("id")})
return true;
});
if($('input.load_tags').length){
var tags = $("input.load_tags").val();
$("input.load_tags").val("");
set_tags(tags);
};
function set_tags(tags) {
$("input.load_tags").textext({
plugins: 'tags focus autocomplete ajax',
tagsItems: tags.split(","),
//Note: The following list of keyboard keys is added. All entries are default except {32 : 'whitespace!'}.
keys: {8: 'backspace', 9: 'tab', 13: 'enter!', 27: 'escape!', 37: 'left', 38: 'up!', 39: 'right',
40: 'down!', 46: 'delete', 108: 'numpadEnter', 32: 'whitespace!'},
ajax: {
url: '/forum/get_tags',
dataType: 'json',
cacheResults: true
}
});
// Note: Adding event handler of whitespaceKeyDown event.
$("input.load_tags").bind("whitespaceKeyDown",function () {
$(this).textext()[0].tags().addTags([ $(this).val() ]);
$(this).val("");
});
}
if ($('textarea.load_editor').length) {
var editor = CKEDITOR.instances['content'];
editor.on('instanceReady', CKEDITORLoadComplete);
}
});
function IsKarmaValid(eventNumber,minKarma){
"use strict";
if(parseInt($("#karma").val()) >= minKarma){
CKEDITOR.tools.callFunction(eventNumber,this);
return false;
} else {
alert("Sorry you need more than 30 Karma.");
}
}
function CKEDITORLoadComplete(){
"use strict";
$('.cke_button__link').attr('onclick','IsKarmaValid(33,30)');
$('.cke_button__unlink').attr('onclick','IsKarmaValid(37,30)');
$('.cke_button__image').attr('onclick','IsKarmaValid(41,30)');
}

View File

@ -0,0 +1,7 @@
<templates id="template" xml:space="preserve">
<t t-extend="website.editorbar">
<t t-jquery="ul.oe_content_menu" t-operation="append">
<li><a href="#" data-action="new_forum">New Forum</a></li>
</t>
</t>
</templates>

View File

@ -0,0 +1,113 @@
<?xml version="1.0"?>
<openerp>
<data>
<!-- MAIN FORUM MENU -->
<menuitem name="Forum" id="menu_website_forum"
parent="mail.mail_feeds_main" sequence="50"/>
<!-- FORUM VIEWS -->
<record id="view_forum_forum_list" model="ir.ui.view">
<field name="name">forum.forum.list</field>
<field name="model">forum.forum</field>
<field name="arch" type="xml">
<tree string="Forums">
<field name="name"/>
</tree>
</field>
</record>
<record id="view_forum_forum_form" model="ir.ui.view">
<field name="name">forum.forum.form</field>
<field name="model">forum.forum</field>
<field name="arch" type="xml">
<form string="Forum" version="7.0">
<sheet>
<group>
<field name="name"/>
<field name="description"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_forum_forum" model="ir.actions.act_window">
<field name="name">Forums</field>
<field name="res_model">forum.forum</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_forum" parent="menu_website_forum" name="Forums" action="action_forum_forum" sequence="10"/>
<!-- POST VIEWS -->
<record id="view_forum_post_list" model="ir.ui.view">
<field name="name">forum.post.list</field>
<field name="model">forum.post</field>
<field name="arch" type="xml">
<tree string="Forum Posts">
<field name="name"/>
<field name="forum_id"/>
</tree>
</field>
</record>
<record id="view_forum_post_form" model="ir.ui.view">
<field name="name">forum.post.form</field>
<field name="model">forum.post</field>
<field name="arch" type="xml">
<form string="Forum Post" version="7.0">
<sheet>
<h1><field name="name" placeholder="Name"/></h1>
<group>
<field name="tag_ids" widget="many2many_tags"/>
<field name="forum_id"/>
<field name="parent_id"/>
<field name="content" placeholder="e.g. Once upon a time..." widget="html"/>
<group>
<field name="create_date"/>
<field name="create_uid"/>
</group>
<group>
<field name="write_uid"/>
<field name="write_date"/>
</group>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
<field name="message_ids" widget="mail_thread" options='{"thread_level": 1}' placeholder="Send a message to the group"/>
</div>
</form>
</field>
</record>
<record id="view_forum_post_search" model="ir.ui.view">
<field name="name">forum.post.search</field>
<field name="model">forum.post</field>
<field name="arch" type="xml">
<search string="Search in Post">
<field name="name" string="Content" filter_domain="['|', ('name', 'ilike', self), ('content', 'ilike', self)]"/>
<field name="create_uid"/>
<field name="forum_id"/>
<group expand="0" string="Group By...">
<filter string="Forum" domain="[]" context="{'group_by': 'forum_id'}"/>
<filter string="Author" domain="[]" context="{'group_by': 'create_uid'}"/>
</group>
</search>
</field>
</record>
<record id="action_forum_post" model="ir.actions.act_window">
<field name="name">Forum Posts</field>
<field name="res_model">forum.post</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_forum_post_list"/>
<field name="search_view_id" ref="view_forum_post_search"/>
</record>
<menuitem id="menu_forum_posts" parent="menu_website_forum" name="Posts" action="action_forum_post" sequence="20"/>
</data>
</openerp>

View File

@ -0,0 +1,24 @@
<openerp>
<data>
<template id="contact" inherit_id="base.contact" name="Forum Contact Widget">
<xpath expr="//div[@itemprop='address']" position="after">
<div>
<div t-if="'karma' in fields" class='css_editable_mode_hidden'>
<b><t t-esc="object.karma"/></b>
<div t-if="options.get('badges')" style="display: inline-block">
<t t-raw="separator"/>
<b>|</b>
<span class="fa fa-circle badge-gold"/>
<t t-esc="object.gold_badge"/>
<span class="fa fa-circle badge-silver"/>
<t t-esc="object.silver_badge"/>
<span class="fa fa-circle badge-bronze"/>
<t t-esc="object.bronze_badge"/>
</div>
<t t-raw="0"/>
</div>
</div>
</xpath>
</template>
</data>
</openerp>

View File

@ -0,0 +1,18 @@
<?xml version="1.0"?>
<openerp>
<data>
<!-- Update user form !-->
<record id="view_users_form_forum" model="ir.ui.view">
<field name="name">res.users.form.forum</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml">
<field name="signature" position="after">
<field name="karma" string="Forum Karma"/>
</field>
</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1,906 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Editor custo -->
<template id="editor_head" inherit_id="website.editor_head"
name="Event Editor">
<xpath expr="//script[@id='website_tour_js']" position="after">
<script type="text/javascript" src="/website_forum/static/src/js/website.tour.forum.js"/>
<script type="text/javascript" src="/website_forum/static/src/js/website_forum.editor.js"/>
</xpath>
</template>
<!-- Layout add nav and footer -->
<template id="header_footer_custom" inherit_id="website.layout"
name="Footer Questions Link">
<xpath expr="//footer//ul[@name='products']" position="inside">
<li><a t-attf-href="/forum/%(website_forum.forum_help)d">Q&amp;A</a></li>
<li><a href="/forum">Forums</a></li>
</xpath>
</template>
<!-- Page Index -->
<template id="header" name="Forum Index">
<t t-call="website.layout">
<t t-set="head">
<link rel='stylesheet' href="/web/static/lib/jquery.textext/jquery.textext.css"/>
<link rel='stylesheet' href='/website_forum/static/src/css/website_forum.css'/>
<!--
FP Note: Why do we need this ? Can we remove this code?
The problem is that you add your script for every page, not only for the forum
-->
<script type="text/javascript" src="/website_forum/static/src/js/website_forum.js"/>
<script type="text/javascript" src="/web/static/lib/jquery.textext/jquery.textext.js"/>
<script type="text/javascript" src="/web/static/lib/ckeditor/ckeditor.js"/>
<script type="text/javascript">
CKEDITOR.config.toolbar = [['Bold','Italic','Underline','Strike'],['NumberedList','BulletedList', 'Blockquote']
,['Outdent','Indent','Link','Unlink','Image'],] ;
</script>
</t>
<div class="container mt16">
<div class="navbar navbar-default">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#oe-help-navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<!-- <span class="icon-bar"></span> -->
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" t-attf-href="/forum/#{slug(forum)}">
<span t-field="forum.name"/>
</a>
</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>
<li t-att-class="searches.get('users') and 'active' or '' ">
<a t-attf-href="/forum/#{ slug(forum) }/users">People</a>
</li>
<li t-att-class="searches.get('tags') and 'active' or '' ">
<a t-attf-href="/forum/#{ slug(forum) }/tag">Tags</a>
</li>
<li t-att-class="searches.get('badges') and 'active' or '' ">
<a t-attf-href="/forum/#{ slug(forum) }/badge">Badges</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>
</form>
</div>
</div>
</div>
<div id="wrap" class="container">
<div class="row">
<div class="col-sm-9">
<div t-foreach="notifications or []" t-as="notification" class="alert alert-success alert-dismissable">
<button type="button" class="close notification_close" t-att-id="notification.id" data-dismiss="alert" aria-hidden="true">&amp;times;</button>
<div t-field="notification.body"/>
<a t-attf-href="/forum/#{ slug(forum) }/user/#{ slug(user) }#badges" class="fa fa-arrow-right">View Your Badges</a>
</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 class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">About This Forum</h3>
</div>
<div class="panel-body">
<t t-raw="forum.description"/><br/>
<a t-attf-href="/forum/#{slug(forum)}/faq" class="fa fa-arrow-right"> Read Guidelines</a>
</div>
</div>
<div t-if="header.get('question_data')">
<div class="panel panel-default">
<div class="panel-heading text-center">
<h3 class="panel-title">Question tools</h3>
</div>
<div class="panel-body text-center">
<t t-call="website_mail.follow"><t t-set="object" t-value="question"/></t>
<div class="mt8">
<strong><t t-raw="len(question.message_follower_ids)"/></strong> follower(s)
</div>
</div>
<div class="panel-heading text-center">
<h3 class="panel-title ">Stats</h3>
</div>
<div class="panel-body">
<table class="table">
<thead><tr><td> Asked: <strong><span t-field="question.create_date" t-field-options='{"format":"short"}'/></strong></td></tr></thead>
<tr><td> Seen: <strong><t t-raw="question.views"/></strong>
<span t-if="question.views&gt;1">times</span>
<span t-if="question.views&lt;=1">time</span>
</td></tr>
<tr><td> Last updated: <strong><span t-field="question.write_date" t-field-options='{"format":"short"}'/></strong></td></tr>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="oe_structure"/>
</t>
</template>
<!-- Display a post -->
<template id="display_post">
<div class="question clearfix">
<div class="pull-left text-center">
<div t-attf-class="box #{question.child_count and 'oe_green' or 'oe_grey'}">
<span t-esc="question.child_count"/>
<span t-if="question.is_correct" class="fa fa-2x fa-check-circle"/>
<div t-if="question.child_count&gt;1">Answers</div>
<div t-if="question.child_count&lt;=1">Answer</div>
</div>
<div class="text-muted text-center">
<span t-field="question.views"/> Views
</div>
</div>
<div class="pull-right text-center">
<div class="box oe_grey">
<span t-esc="question.vote_count or 0"/>
<div t-if="question.vote_count&gt;1">Votes</div>
<div t-if="question.vote_count&lt;=1">Vote</div>
</div>
</div>
<div style="margin-left: 95px;">
<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>
</div>
<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"}'/>
</div>
<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"/>
</t>
</div>
</div>
</template>
<!-- Display a post as an answer -->
<template id="display_post_answer">
<div class="clearfix">
<div t-attf-class="pull-left text-center mb16 box #{len(answer.vote_ids) and 'oe_green' or 'oe_grey'}">
<div t-esc="len(answer.vote_ids)"/>
</div>
<div class="question-name" style="margin-left: 32px;">
<a style="font-size: 15px;" t-attf-href="/forum/#{ slug(forum) }/question/#{ answer.parent_id.id }/#answer-#{ answer.id }" t-esc="answer.parent_id.name"/>
<t t-if="len(answer.website_message_ids)&gt;0">
(<t t-esc="len(answer.website_message_ids)"/>
<t t-if="len(answer.website_message_ids)&gt;1">Comments</t>
<t t-if="len(answer.website_message_ids)&lt;=1">Comment</t>)
</t>
</div>
</div>
</template>
<!-- FAQ Layout -->
<template id="faq">
<t t-call="website_forum.header">
<div t-field="forum.faq"/>
</t>
</template>
<!-- All Forums Layout -->
<template id="forum_all">
<t t-call="website.layout">
<div class="container">
<h1 class="mb32">Our forums</h1>
<div class="row">
<div t-foreach="forums" t-as="forum" class="col-sm-3 text-center mb32">
<a t-attf-href="/forum/#{ slug(forum) }">
<div class="fa fa-5x fa-comment mb16"/>
<div t-field="forum.name"/>
</a>
</div>
</div>
</div>
</t>
</template>
<!-- Specific Forum Layout -->
<template id="forum_index" name="Forum">
<t t-call="website_forum.header">
<h1 class="page-header mt0">
<t t-esc="len(question_ids)"/> <span>Questions</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="filters == 'tag'">Tag</t>
<t t-if="sorting == 'date'"> by activity date</t>
<t t-if="sorting == 'answered'"> by most answered</t>
<t t-if="sorting == 'vote'"> by most voted</t>
<b class="caret"/>
</a>
<ul class="dropdown-menu">
<li class="dropdown-header">Filter on</li>
<li t-att-class="filters == 'all' and 'active' or '' ">
<a t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', filters='all')">All</a>
</li>
<li t-att-class="filters == 'unanswered' and 'active' or '' ">
<a t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', filters='unanswered')">Unanswered</a>
</li>
<li t-if="uid" t-att-class="filters == 'followed' and 'active' or '' ">
<a t-att-href="url_for('') + '?' + keep_query( 'search', 'sorting', filters='followed')">Followed</a>
</li>
<li class="dropdown-header">Tags</li>
<li t-if="tag" t-att-class="tag and 'active' or '' ">
<a href=""><t t-esc="tag.name"/></a>
</li>
<li class="dropdown-header">Sort by</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 t-att-class="sorting == 'answered' and 'active' or '' ">
<a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='answered')">Most answered</a>
</li>
<li t-att-class="sorting == 'vote' and 'active' or '' ">
<a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='vote')">Most voted</a>
</li>
</ul>
</small>
</h1>
<div t-foreach="question_ids" t-as="question" class="mb16">
<t t-call="website_forum.display_post"/>
</div>
<t t-call="website.pager"/>
</t>
</template>
<template id="404">
<t t-call="website_forum.header">
<div class="oe_structure oe_empty"/>
<h1 class="mt32">Question not found!</h1>
<p>Sorry, this question is not available anymore.</p>
<p>
<a t-attf-href="/forum">Return to the question list.</a>
</p>
</t>
</template>
<!-- Edition: ask your question -->
<template id="ask_question">
<t t-call="website_forum.header">
<h1 class="mt0">Ask your Question</h1>
<ul>
<li> please, try to make your question interesting to others </li>
<li> provide enough details and, if possible, give an example </li>
<li> be clear and concise, avoid unnecessary introductions (Hi, ... Thanks...) </li>
</ul>
<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}"
class="form-control" placeholder="Enter your Question"/>
<h5 class="mt20">Please enter a descriptive question (should finish by a '?')</h5>
<input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
<textarea name="content" required="True" 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"/>
<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>
<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>
</div>
<input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
<textarea name="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}"/>
<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">
<t t-call="website_forum.header">
<h3 class=""><b>Close question</b></h3><br/>
<form t-attf-action="/forum/#{ slug(forum) }/question/#{slug(question)}/close" method="post" role="form">
<input name="post_id" t-att-value="post.id" type="hidden"/>
<span class="pull-left">Close the question:</span>
<a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(post) }" t-field="post.name"/>
<div class="mt16">
<label class="col-md-2 control-label mb16" for="reason">Reasons:</label>
<div class="col-md-9 mb16">
<select class="form-control" name="reason">
<t t-foreach="reasons or []" t-as="reason">
<option t-att-value="reason.id" t-att-selected="reason.id == post.closed_reason_id.id"><t t-esc="reason.name"/></option>
</t>
</select>
</div>
</div>
<div>
<button class="btn btn-primary btn-lg">Close</button>
</div>
</form>
</t>
</template>
<!-- Edition: post an answer -->
<template id="post_answer">
<h3 class="mt10">Your answer</h3>
<p>
<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">
<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" id="btn_ask_your_question">Post Your Answer</button>
</form>
<script type="text/javascript">
CKEDITOR.replace("content");
</script>
</template>
<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 ''}"
t-attf-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 ''}"
t-attf-href="/forum/#{slug(post.forum_id)}/post/#{slug(post)}/downvote"/>
<div>
votes
</div>
</div>
</template>
<!-- Specific Post Layout -->
<template id="post_description_full" name="Question Navigation">
<t t-call="website_forum.header">
<div t-attf-class="question #{not question.active and 'alert alert-danger' or ''}">
<div class="text-center pull-left">
<t t-call="website_forum.vote">
<t t-set="post" t-value="question"/>
</t>
<div class="text-muted">
<span t-esc="question.child_count"/>
<span t-if="question.child_count&gt;1">Answers</span>
<span t-if="question.child_count&lt;=1">Answer</span>
</div>
<div>
<a t-attf-href="/forum/#{slug(question.forum_id)}/question/#{slug(question)}/toggle_favourite"
t-attf-class="favourite_question no-decoration fa fa-2x fa-star #{question.user_favourite and 'forum_favourite_question' or ''}"/>
</div>
</div>
<div style="margin-left: 95px;">
<h1 class="mt0">
<span t-field="question.name"/>
<span t-if="not question.active"><b> [Deleted]</b></span>
<span t-if="question.state == 'close'"><b> [Closed]</b></span>
</h1>
<t t-raw="question.content"/>
<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"/>
</t>
</div>
<ul class="list-inline">
<li t-if="user.id == question.create_uid.id or user.karma&gt;=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) }">
comment
</a>
</li>
<li t-if="question.state != 'close' and (user.id == question.create_uid.id or user.karma&gt;=100)">
<a class="text-muted fa fa-times" t-attf-href="/forum/#{ slug(forum) }/question/#{slug(question)}/ask_for_close">close</a>
</li>
<li t-if="question.state == 'close' and user.karma&gt;=500">
<a class="text-muted fa fa-undo" t-attf-href="/forum/#{ slug(forum) }/question/#{slug(question)/reopen">reopen</a>
</li>
<li t-if="user.id == question.create_uid.id or user.karma&gt;=300">
<a class="text-muted fa fa-edit" t-attf-href="/forum/#{ slug(forum) }/post/#{slug(question)}/edit">edit</a>
</li>
<li t-if="question.active and user.id == question.create_uid.id or user.karma&gt;=1000">
<a class="text-muted fa fa-trash-o" t-attf-href="/forum/#{ slug(forum) }/question/#{slug(question)}/delete">delete</a>
</li>
<li t-if="uid == question.create_uid.id and not question.active">
<a class="text-muted fa fa-trash-o" t-attf-href="/forum/#{ slug(forum) }/question/#{slug(question)}/undelete">undelete</a>
</li>
<li><a class="text-muted fa fa-share" t-attf-href="/forum/#{slug(forum)}/question/#{slug(question)}">share</a></li>
</ul>
</div>
<div>
<span t-field="question.create_uid.image" t-field-options='{"widget": "image", "class":"pull-left img img-circle img-avatar"}'/>
<div>
<a t-attf-href="/forum/#{ slug(forum) }/user/#{ user.id }"
t-field="question.create_uid"
t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
style="display: inline-block;"/>
<div t-field="question.create_uid" t-field-options='{"widget": "contact", "badges": true, "fields": ["karma"]}'/>
</div>
</div>
<div class="alert alert-info" t-if="question.state == 'close'">
<p class="mt32 mb32 text-center">
<b>The question has been closed for the following reason "<span t-field="question.closed_reason_id.name"/>"
<t t-if="question.closed_uid">
<i>by <a t-attf-href="/forum/#{ slug(forum) }/user/#{ slug(question.closed_uid) }" t-field="question.closed_uid.name"/> </i>
</t>
<br/>close date <span t-field="question.closed_date"/></b>
</p>
</div>
</div>
<t t-call="website_forum.post_comment">
<t t-set="object" t-value="question"/>
</t>
</div>
</div>
<hr/>
<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 #{answer.is_correct and 'alert alert-info answer_correct' or ''}" t-attf-id="answer_#{answer.id}" >
<div class="text-center pull-left">
<t t-call="website_forum.vote">
<t t-set="post" t-value="answer"/>
</t>
<div class="text-muted">
<a t-attf-class="accept_answer fa fa-2x fa-check-circle no-decoration oe_answer_true #{answer.is_correct and 'oe_answer_true' or 'oe_answer_false'}"
t-attf-href="/forum/#{slug(question.forum_id)}/post/#{slug(answer)}/toggle_correct"/>
</div>
</div>
<div style="margin-left: 95px;" class="clearfix">
<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&gt;=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
</a>
</li>
<li t-if="user.id == answer.create_uid.id or user.karma&gt;=300">
<a class="text-muted fa fa-edit" t-attf-href="/forum/#{slug(forum)}/post/#{slug(answer)}/edit">edit</a>
</li>
<li t-if="user.id == answer.create_uid.id or user.karma&gt;=1000">
<a class="text-muted fa fa-trash-o" t-attf-href="/forum/#{slug(forum)}/post/#{slug(answer)}/delete">delete</a>
</li>
<li t-if="user.id == answer.create_uid.id">
<a class="text-muted fa fa-magic" t-attf-href="/forum/#{slug(forum)}/post/#{slug(answer)}/convert_to_comment">Convert as a comment</a>
</li>
<li><a class="text-muted fa fa-share" t-attf-href="/forum/#{slug(forum)}/question/#{slug(question)}/#answer_#{answer.id}">share</a></li>
</ul>
<span t-field="answer.create_uid.image" t-field-options='{"widget": "image", "class":"pull-left img img-circle img-avatar"}'/>
<div>
<a t-attf-href="/forum/#{ slug(forum) }/user/#{ user.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>
<t t-call="website_forum.post_comment">
<t t-set="object" t-value="answer"/>
</t>
</div>
</div>
</div>
<div t-if="not question.uid_has_answered">
<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>
</template>
<!-- Utility template: Post a Comment -->
<template id="post_comment">
<div class="row clearfix">
<div class="col-sm-10 col-sm-offset-2">
<div t-foreach="reversed(object.website_message_ids)" t-as="message" class="comment oe_comment_grey mb8">
<small class="text-muted">
<button type="button" t-if="user.partner_id.id == message.author_id.id and user.karma&gt;=750"
t-attf-href="/forum/#{slug(forum)}/post/#{slug(object)}/comment/#{slug(message)}/delete"
class="close comment_delete">&amp;times;</button>
<span t-field="message.body"/>
<a t-attf-href="/forum/#{slug(forum)}/user/#{message.id}"
t-field="message.author_id" t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
style="display: inline-block;"/>
on <span t-field="message.date" t-field-options='{"format":"short"}'/>
<a class="fa fa-magic text-muted pull-right"
t-attf-href="/forum/#{slug(forum)}/post/#{slug(object)}/comment/#{slug(message)}/convert_to_answer">Convert as an answer</a>
</small>
</div>
<div class="css_editable_mode_hidden">
<form t-attf-id="comment#{ object._name.replace('.','') + '-' + str(object.id) }" class="collapse"
t-attf-action="/forum/#{slug(forum)}/post/#{slug(object)}/comment" method="POST">
<input name="post_id" t-att-value="object.id" type="hidden"/>
<textarea name="comment" class="form-control" placeholder="Comment this post..."/>
<button type="submit" class="btn btn-primary mt8">Post</button>
</form>
</div>
</div>
</div>
</template>
<template id="tag">
<t t-call="website_forum.header">
<h1 class="mt0">
Tags
</h1>
<p class="text-muted">
A tag is a label that categorizes your question with other,
similar questions. Using the right tags makes it easier for
others to find and answer your question.
</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">
<span t-field="tag.name"/>
</a>
<span>
X <t t-esc="tag.posts_count"/>
</span>
</div>
</div>
</t>
</template>
<template id="badge">
<t t-call="website_forum.header">
<h1 class="mt0">
Badges
</h1>
<p>
Besides gaining reputation with your questions and answers,
you receive badges for being especially helpful. Badges
appear on your profile page, and your posts.
</p>
<table class="table mt32 mb64">
<tr t-foreach="badges" t-as="badge">
<td>
<a t-attf-href="/forum/#{ slug(forum) }/badge/#{ slug(badge) }" class="badge pull-left">
<span t-if="badge.level == 'gold'" class="fa fa-circle badge-gold"/>
<span t-if="badge.level == 'silver'" class="fa fa-circle badge-silver"/>
<span t-if="badge.level == 'bronze'" class="fa fa-circle badge-bronze"/>
<span t-field="badge.name"/>
</a>
</td><td>
<b t-esc="badge.stat_count_distinct"/>
<i class="text-muted">awarded users</i>
</td><td>
<span t-field="badge.description"/>
</td>
</tr>
</table>
</t>
</template>
<template id="badge_user">
<t t-call="website_forum.header">
<h3 class="mt32 mb32">
<b>Badge "<span t-field="badge.name"/>"</b>
</h3>
<div>
<div class="pull-left badge">
<span t-if="badge.level == 'gold'" class="fa fa-circle badge-gold"/>
<span t-if="badge.level == 'silver'" class="fa fa-circle badge-silver"/>
<span t-if="badge.level == 'bronze'" class="fa fa-circle badge-bronze"/>
<span t-field="badge.name"/>
</div>
<span t-field="badge.description" style="margin-left:20px"/>
</div>
<h4 class="mt32">
<t class="pull-left" t-esc="badge.stat_count_distinct"/>
<span t-if="badge.stat_count_distinct&gt;1">users</span>
<span t-if="badge.stat_count_distinct&lt;=1">user</span>
received this badge:
</h4>
<div class="row">
<div class="col-sm-3 mt16" t-foreach="users" t-as="user">
<span t-field="user.image" t-field-options='{"widget": "image", "class":"pull-left img img-circle img-avatar"}'/>
<div>
<a t-attf-href="/forum/#{slug(forum)}/user/#{user.id}" t-field="user.name"/>
</div>
</div>
</div>
</t>
</template>
<template id="users">
<t t-call="website_forum.header">
<div class="row">
<div t-foreach="users" t-as="user" class="col-sm-4">
<span t-field="user.image" t-field-options='{"widget": "image", "class":"pull-left img img-circle img-avatar"}'/>
<div>
<a t-attf-href="/forum/#{slug(forum)}/user/#{user.id}" t-field="user.name"/>
<t t-if="user.country_id">
<span t-field="user.country_id.image" t-field-options='{"widget": "image", "class": "country_flag"}'/>
</t>
<b><t t-esc="user.karma"/></b>
<t t-raw="separator"/>
<div>
<b> badges:</b>
<span class="fa fa-circle badge-gold"/>
<t t-esc="user.gold_badge"/>
<span class="fa fa-circle badge-silver"/>
<t t-esc="user.silver_badge"/>
<span class="fa fa-circle badge-bronze"/>
<t t-esc="user.bronze_badge"/>
</div>
<t t-raw="0"/>
</div>
</div>
</div>
<div class="pull-left">
<t t-call="website.pager"/>
</div>
</t>
</template>
<template id="edit_profile">
<t t-call="website_forum.header">
<h3>Edit Profile </h3>
<div class="col-md-2">
<span t-field="user.image" t-field-options='{"widget": "image", "class": "img img-responsive img-circle"}'/>
</div>
<form t-attf-action="/forum/#{slug(forum)}/user/#{slug(user)}/save" method="post" role="form" class="form-horizontal">
<input name="user_id" t-att-value="user.id" type="hidden"/>
<label class="col-md-2 control-label mb16" for="user.name">Real name</label>
<div class="col-md-7 mb16">
<input type="text" class="col-md-7 mb16 form-control" name="name" required="True" t-attf-value="#{user.name}"/>
</div>
<label class="col-md-2 control-label mb16" for="user.partner_id.website">Website</label>
<div class="col-md-7 mb16">
<input type="text" class="form-control" name="website" t-attf-value="#{user.partner_id.website or ''}"/>
</div>
<label class="col-md-4 control-label mb16" for="user.partner_id.email">Email</label>
<div class="col-md-7 mb16">
<input type="text" class="form-control" name="email" required="True" t-attf-value="#{user.partner_id.email}"/>
</div>
<label class="col-md-4 control-label mb16" for="user.partner_id.city">City</label>
<div class="col-md-7 mb16">
<input type="text" class="form-control" name="city" t-attf-value="#{user.partner_id.city or ''}"/>
</div>
<label class="col-md-4 control-label mb16" for="contact_name">Country</label>
<div class="col-md-7 mb16">
<select class="form-control" name="country">
<option value="">Country...</option>
<t t-foreach="countries or []" t-as="country">
<option t-att-value="country.id" t-att-selected="country.id == user.partner_id.country.id"><t t-esc="country.name"/></option>
</t>
</select>
</div>
<!--Note: using website_description fiels instead of using commnt firld of partner-->
<label class="col-md-4 control-label mb16" for="user.partner_id.website_description">Biography</label>
<div class="col-md-7 mb16">
<textarea name="description" style="min-height: 120px" required="True"
class="form-control"><t t-esc="user.partner_id.website_description"/></textarea>
</div>
<div class="col-sm-offset-4 col-md-4 mb16">
<button class="btn btn-primary btn-lg">Update</button>
</div>
</form>
</t>
</template>
<template id="user_detail_full">
<t t-call="website_forum.header">
<h1 class="mt0 page-header">
<span t-field="user.name"/>
<small>profile</small>
</h1>
<div class="row">
<div class="col-sm-2">
<span t-field="user.image"
t-field-options='{"widget": "image", "class": "img img-responsive img-circle"}'/>
</div>
<div class="col-sm-10">
<table class="table table-condensed">
<tr>
<td rowspan="2" valign="top"><span class="text-muted">contributions</span></td>
<td>member since</td>
<td><span t-field="user.create_date" t-field-options='{"format": "short"}'/></td>
</tr><tr>
<td>last connection</td>
<td><span t-field="user.login_date" t-field-options='{"format": "short"}'/></td>
</tr>
<tr>
<td rowspan="2" valign="top"><span class="text-muted">bio</span></td>
<td>website</td>
<td>
<a t-att-href="user.website" t-if="user.website">
<span t-field="user.website"/>
</a>
</td>
</tr><tr>
<td>location</td>
<td>
<span t-field="user.city"/>
<span t-if="user.city and user.country_id">, </span>
<span t-field="user.country_id"/>
<t t-if="user.country_id"> <span t-field="user.country_id.image" t-field-options='{"widget": "image", "class": "country_flag"}'/></t>
</td>
</tr>
<tr>
<td rowspan="2" valign="top"><span class="text-muted">stats</span></td>
<td>karma</td>
<td><span t-field="user.karma"/></td>
</tr><tr>
<td>votes</td>
<td>
<span class="fa fa-thumbs-up"/>
<span t-esc="up_votes"/>
<span class="fa fa-thumbs-down"/>
<span t-esc="down_votes"/>
</td>
</tr>
</table>
<div class="well well-sm">
<span t-field="user.partner_id.website_description"/>
<t t-if="uid == user.id">
<a class="fa fa-arrow-right" t-attf-href="/forum/#{slug(forum)}/user/#{slug(user)}/edit"> Edit Your Bio</a>
</t>
</div>
</div>
</div>
<ul class="nav nav-tabs">
<li class="active">
<a href="#questions" data-toggle="tab"><t t-esc="len(questions)"/> Questions</a>
</li>
<li>
<a href="#answers" data-toggle="tab"><t t-esc="len(answers)"/> Answers</a>
</li>
<li t-if="uid == user.id">
<a href="#favourite_question" data-toggle="tab"><t t-esc="len(favourite)"/> Favourite Questions</a>
</li>
<li t-if="uid == user.id">
<a href="#followed_question" data-toggle="tab"><t t-esc="len(followed)"/> Followed Questions</a>
</li>
<li t-if="uid == user.id">
<a href="#activity" data-toggle="tab">Activity</a>
</li>
<li>
<a href="#badges" data-toggle="tab">Badges</a>
</li>
<li t-if="uid == user.id">
<a href="#votes" data-toggle="tab">Votes</a>
</li>
</ul>
<div class="tab-content mt16">
<div class="tab-pane active" id="questions">
<div class="mb16" t-foreach="questions" t-as="question">
<t t-call="website_forum.display_post"/>
</div>
</div><div class="tab-pane" id="answers">
<div t-foreach="answers" t-as="answer">
<t t-call="website_forum.display_post_answer"/>
</div>
</div>
<div class="tab-pane" id="karma">
<h1>Karma</h1>
</div>
<div class="tab-pane" id="badges">
<t t-call="website_forum.user_badges"/>
</div>
<div class="tab-pane" id="favourite_question">
<div t-foreach="favourite" t-as="question">
<t t-call="website_forum.display_post"/>
</div>
</div>
<div class="tab-pane" id="followed_question">
<div t-foreach="followed" t-as="question">
<t t-call="website_forum.display_post"/>
</div>
</div>
<div class="tab-pane" id="votes">
<t t-call="website_forum.user_votes"/>
</div>
<div class="tab-pane" id="activity">
<ul class="list-unstyled">
<li t-foreach="activities" t-as="activity">
<span t-field="activity.date" t-field-options='{"format": "short"}'/>
<span t-esc="activity.subtype_id.name" class="label label-info"/>
<t t-set="post" t-value="posts[activity.res_id]"/>
<span t-if="post[1]">
<a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(post[0]) }#answer-#{ str(post[1].id) }">
<span t-esc="post[0].name"/>
</a>
</span>
<span t-if="not post[1]">
<a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(post[0]) }">
<span t-esc="post[0].name"/>
</a>
</span>
</li>
</ul>
</div>
</div>
</t>
</template>
<template id="user_badges">
<table class="table mt32 mb64">
<tr t-foreach="user.badge_ids" t-as="badge">
<td>
<a t-attf-href="/forum/#{ slug(forum) }/badge/#{ slug(badge.badge_id) }" class="badge pull-left">
<span t-if="badge.badge_id.level == 'gold'" class="fa fa-circle badge-gold"/>
<span t-if="badge.badge_id.level == 'silver'" class="fa fa-circle badge-silver"/>
<span t-if="badge.badge_id.level == 'bronze'" class="fa fa-circle badge-bronze"/>
<span t-field="badge.badge_id.name"/>
</a>
</td><td>
<b t-esc="badge.badge_id.stat_count_distinct"/>
<i class="text-muted">awarded users</i>
</td><td>
<span t-field="badge.badge_id.description"/>
</td>
</tr>
</table>
<div class="mb16" t-if="not user.badge_ids">
<b>No badge yet!</b><br/>
<a t-attf-href="/forum/#{ slug(forum) }/badge" class="fa fa-arrow-right"> Check available badges</a>
</div>
</template>
<template id="user_votes">
<div t-foreach="vote_post" t-as="vote">
<t t-esc="vote.post_id.create_date"/>
<span t-if="vote.vote == '1'" class="fa fa-thumbs-up text-success" style="margin-left:30px"/>
<span t-if="vote.vote == '-1'" class="fa fa-thumbs-down text-warning" style="margin-left:30px"/>
<t t-if="vote.post_id.parent_id">
<a t-attf-href="/forum/#{ slug(forum) }/question/#{ vote.post_id.parent_id.id }/#answer-#{ vote.post_id.id }" t-esc="vote.post_id.parent_id.name" style="margin-left:10px"/>
</t>
<t t-if="not vote.post_id.parent_id">
<a t-attf-href="/forum/#{ slug(forum) }/question/#{ vote.post_id.id }" style=" color:black;margin-left:10px" t-esc="vote.post_id.name"/>
</t>
</div>
<div class="mb16" t-if="not vote_post">
<b>No vote given by you yet!</b>
</div>
</template>
</data>
</openerp>