diff --git a/addons/gamification/data/goal_base.xml b/addons/gamification/data/goal_base.xml
index 0437dee031c..c12763025f6 100644
--- a/addons/gamification/data/goal_base.xml
+++ b/addons/gamification/data/goal_base.xml
@@ -164,7 +164,7 @@
oncepersonalnever
- [('groups_id', 'in', ref('base.group_user'))]
+ inprogressother
@@ -174,7 +174,7 @@
oncepersonalnever
- [('groups_id', 'in', ref('base.user_root'))]
+ inprogressother
diff --git a/addons/gamification/models/challenge.py b/addons/gamification/models/challenge.py
index 295340a309b..a0c4b638ae3 100644
--- a/addons/gamification/models/challenge.py
+++ b/addons/gamification/models/challenge.py
@@ -21,14 +21,13 @@
from openerp import SUPERUSER_ID
from openerp.osv import fields, osv
-from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DF
+from openerp.tools import ustr, DEFAULT_SERVER_DATE_FORMAT as DF
from openerp.tools.safe_eval import safe_eval as eval
from openerp.tools.translate import _
from datetime import date, datetime, timedelta
import calendar
import logging
-import functools
_logger = logging.getLogger(__name__)
# display top 3 in ranking, could be db variable
@@ -117,12 +116,6 @@ class gamification_challenge(osv.Model):
except ValueError:
return False
- def _get_challenger_users(self, cr, uid, domain, context=None):
- ref = functools.partial(self.pool['ir.model.data'].xmlid_to_res_id, cr, uid)
- user_domain = eval(domain, {'ref': ref})
- return self.pool['res.users'].search(cr, uid, user_domain, context=context)
-
-
_order = 'end_date, start_date, name, id'
_columns = {
'name': fields.char('Challenge Name', required=True, translate=True),
@@ -218,7 +211,6 @@ class gamification_challenge(osv.Model):
def create(self, cr, uid, vals, context=None):
"""Overwrite the create method to add the user of groups"""
- # add users when change the group auto-subscription
if vals.get('user_domain'):
user_ids = self._get_challenger_users(cr, uid, vals.get('user_domain'), context=context)
@@ -240,14 +232,18 @@ class gamification_challenge(osv.Model):
if isinstance(ids, (int,long)):
ids = [ids]
- if vals.get('state') == 'inprogress':
- for challenge in self.browse(cr, uid, ids, context=context):
- user_ids = self._get_challenger_users(cr, uid, challenge.user_domain, context=context)
- write_op = [(4, user_id) for user_id in user_ids]
- self.write(cr, uid, [challenge.id], {'user_ids': write_op}, context=context)
- self.message_subscribe_users(cr, uid, [challenge.id], user_ids, context=context)
+ if vals.get('user_domain'):
+ user_ids = self._get_challenger_users(cr, uid, vals.get('user_domain'), context=context)
- self.generate_goals_from_challenge(cr, uid, ids, context=context)
+ if not vals.get('user_ids'):
+ vals['user_ids'] = []
+ vals['user_ids'] += [(4, user_id) for user_id in user_ids]
+
+ write_res = super(gamification_challenge, self).write(cr, uid, ids, vals, context=context)
+
+ if vals.get('state') == 'inprogress':
+ self._recompute_challenge_users(cr, uid, ids, context=context)
+ self._generate_goals_from_challenge(cr, uid, ids, context=context)
elif vals.get('state') == 'done':
self.check_challenge_reward(cr, uid, ids, force=True, context=context)
@@ -256,9 +252,6 @@ class gamification_challenge(osv.Model):
# resetting progress
if self.pool.get('gamification.goal').search(cr, uid, [('challenge_id', 'in', ids), ('state', '=', 'inprogress')], context=context):
raise osv.except_osv("Error", "You can not reset a challenge with unfinished goals.")
-
- write_res = super(gamification_challenge, self).write(cr, uid, ids, vals, context=context)
-
return write_res
@@ -314,18 +307,10 @@ class gamification_challenge(osv.Model):
# update every running goal already generated linked to selected challenges
goal_obj.update(cr, uid, goal_ids, context=context)
+ self._recompute_challenge_users(cr, uid, ids, context=context)
+ self._generate_goals_from_challenge(cr, uid, ids, context=context)
+
for challenge in self.browse(cr, uid, ids, context=context):
- # in case of new users matching the domain
- old_user_ids = [user.id for user in challenge.user_ids]
- new_user_ids = self._get_challenger_users(cr, uid, challenge.user_domain, context=context)
- to_remove_ids = list(set(old_user_ids) - set(new_user_ids))
- to_add_ids = list(set(new_user_ids) - set(old_user_ids))
-
- write_op = [(3, user_id) for user_id in to_remove_ids]
- write_op += [(4, user_id) for user_id in to_add_ids]
- self.write(cr, uid, [challenge.id], {'user_ids': write_op}, context=context)
-
- self.generate_goals_from_challenge(cr, uid, [challenge.id], context=context)
# goals closed but still opened at the last report date
closed_goals_to_report = goal_obj.search(cr, uid, [
@@ -345,11 +330,37 @@ class gamification_challenge(osv.Model):
return True
def quick_update(self, cr, uid, challenge_id, context=None):
- """Update all the goals of a challenge, no generation of new goals"""
+ """Update all the goals of a specific challenge, no generation of new goals"""
goal_ids = self.pool.get('gamification.goal').search(cr, uid, [('challenge_id', '=', challenge_id)], context=context)
self.pool.get('gamification.goal').update(cr, uid, goal_ids, context=context)
return True
+ def _get_challenger_users(self, cr, uid, domain, context=None):
+ user_domain = eval(ustr(domain))
+ return self.pool['res.users'].search(cr, uid, user_domain, context=context)
+
+ def _recompute_challenge_users(self, cr, uid, challenge_ids, context=None):
+ """Recompute the domain to add new users and remove the one no longer matching the domain"""
+ for challenge in self.browse(cr, uid, challenge_ids, context=context):
+ if challenge.user_domain:
+
+ old_user_ids = [user.id for user in challenge.user_ids]
+ new_user_ids = self._get_challenger_users(cr, uid, challenge.user_domain, context=context)
+ to_remove_ids = list(set(old_user_ids) - set(new_user_ids))
+ to_add_ids = list(set(new_user_ids) - set(old_user_ids))
+
+ write_op = [(3, user_id) for user_id in to_remove_ids]
+ write_op += [(4, user_id) for user_id in to_add_ids]
+ if write_op:
+ self.write(cr, uid, [challenge.id], {'user_ids': write_op}, context=context)
+
+ if to_remove_ids:
+ self.message_unsubscribe_users(cr, uid, [challenge.id], to_remove_ids, context=None)
+ if to_add_ids:
+ self.message_subscribe_users(cr, uid, [challenge.id], to_add_ids, context=context)
+
+ return True
+
def action_check(self, cr, uid, ids, context=None):
"""Check a challenge
@@ -370,12 +381,17 @@ class gamification_challenge(osv.Model):
##### Automatic actions #####
def generate_goals_from_challenge(self, cr, uid, ids, context=None):
+ _logger.warning("Deprecated, use private method _generate_goals_from_challenge(...) instead.")
+ return self._generate_goals_from_challenge(cr, uid, ids, context=context)
+
+ def _generate_goals_from_challenge(self, cr, uid, ids, context=None):
"""Generate the goals for each line and user.
If goals already exist for this line and user, the line is skipped. This
can be called after each change in the list of users or lines.
:param list(int) ids: the list of challenge concerned"""
+ goal_obj = self.pool.get('gamification.goal')
to_update = []
for challenge in self.browse(cr, uid, ids, context=context):
(start_date, end_date) = start_end_date_for_period(challenge.period)
@@ -387,45 +403,49 @@ class gamification_challenge(osv.Model):
end_date = challenge.end_date
for line in challenge.line_ids:
- # FIXME: allow to restrict to a subset of users
- for user in challenge.user_ids:
- goal_obj = self.pool.get('gamification.goal')
- domain = [('line_id', '=', line.id), ('user_id', '=', user.id)]
- if start_date:
- domain.append(('start_date', '=', start_date))
+ # there is potentially a lot of users
+ # detect the ones with no goal linked to this line
+ date_clause = ""
+ query_params = [line.id]
+ if start_date:
+ date_clause += "AND g.start_date = %s"
+ query_params.append(start_date)
+ if end_date:
+ date_clause += "AND g.end_date = %s"
+ query_params.append(end_date)
+
+ query = """SELECT u.id AS user_id
+ FROM res_users u
+ LEFT JOIN gamification_goal g
+ ON (u.id = g.user_id)
+ WHERE line_id = %s
+ {date_clause}
+ """.format(date_clause=date_clause)
- # goal already existing for this line ?
- if len(goal_obj.search(cr, uid, domain, context=context)) > 0:
+ cr.execute(query, query_params)
+ user_with_goal_ids = cr.dictfetchall()
+ user_without_goal_ids = list(set([user.id for user in challenge.user_ids]) - set([user['user_id'] for user in user_with_goal_ids]))
- # resume canceled goals
- domain.append(('state', '=', 'canceled'))
- canceled_goal_ids = goal_obj.search(cr, uid, domain, context=context)
- if canceled_goal_ids:
- goal_obj.write(cr, uid, canceled_goal_ids, {'state': 'inprogress'}, context=context)
- to_update.extend(canceled_goal_ids)
+ values = {
+ 'definition_id': line.definition_id.id,
+ 'line_id': line.id,
+ 'target_goal': line.target_goal,
+ 'state': 'inprogress',
+ }
- # skip to next user
- continue
+ if start_date:
+ values['start_date'] = start_date
+ if end_date:
+ values['end_date'] = end_date
- values = {
- 'definition_id': line.definition_id.id,
- 'line_id': line.id,
- 'user_id': user.id,
- 'target_goal': line.target_goal,
- 'state': 'inprogress',
- }
+ if challenge.remind_update_delay:
+ values['remind_update_delay'] = challenge.remind_update_delay
- if start_date:
- values['start_date'] = start_date
- if end_date:
- values['end_date'] = end_date
-
- if challenge.remind_update_delay:
- values['remind_update_delay'] = challenge.remind_update_delay
-
- new_goal_id = goal_obj.create(cr, uid, values, context=context)
- to_update.append(new_goal_id)
+ for user_id in user_without_goal_ids:
+ values.update({'user_id': user_id})
+ goal_id = goal_obj.create(cr, uid, values, context=context)
+ to_update.append(goal_id)
goal_obj.update(cr, uid, to_update, context=context)
@@ -638,7 +658,7 @@ class gamification_challenge(osv.Model):
message = "%s has joined the challenge" % user.name
self.message_post(cr, SUPERUSER_ID, challenge_ids, body=message, context=context)
self.write(cr, SUPERUSER_ID, challenge_ids, {'invited_user_ids': [(3, user_id)], 'user_ids': [(4, user_id)]}, context=context)
- return self.generate_goals_from_challenge(cr, SUPERUSER_ID, challenge_ids, context=context)
+ return self._generate_goals_from_challenge(cr, SUPERUSER_ID, challenge_ids, context=context)
# TODO in trunk, remove unused parameter user_id
def discard_challenge(self, cr, uid, challenge_ids, context=None, user_id=None):
diff --git a/addons/gamification/models/res_users.py b/addons/gamification/models/res_users.py
index 330311ba05e..67020520467 100644
--- a/addons/gamification/models/res_users.py
+++ b/addons/gamification/models/res_users.py
@@ -19,7 +19,6 @@
#
##############################################################################
-from openerp import SUPERUSER_ID
from openerp.osv import osv
from challenge import MAX_VISIBILITY_RANKING
diff --git a/addons/gamification/views/challenge.xml b/addons/gamification/views/challenge.xml
index 75dcd4a7959..87dea680222 100644
--- a/addons/gamification/views/challenge.xml
+++ b/addons/gamification/views/challenge.xml
@@ -48,6 +48,7 @@
+
diff --git a/addons/gamification_sale_crm/sale_crm_goals.xml b/addons/gamification_sale_crm/sale_crm_goals.xml
index fbc1c952bb8..ffb3a24318a 100644
--- a/addons/gamification_sale_crm/sale_crm_goals.xml
+++ b/addons/gamification_sale_crm/sale_crm_goals.xml
@@ -130,7 +130,7 @@
Monthly Sales Targetsmonthlyranking
- [('groups_id', 'in', ref('base.group_sale_salesman'))]
+ weekly
@@ -138,7 +138,7 @@
Lead Acquisitionmonthlyranking
- [('groups_id', 'in', ref('base.group_sale_salesman'))]
+ weekly
diff --git a/addons/mass_mailing/wizard/test_mailing.py b/addons/mass_mailing/wizard/test_mailing.py
index 39883d941ae..bd1124a8cdc 100644
--- a/addons/mass_mailing/wizard/test_mailing.py
+++ b/addons/mass_mailing/wizard/test_mailing.py
@@ -25,16 +25,14 @@ class TestMassMailing(osv.TransientModel):
test_emails = tools.email_split(wizard.email_to)
mail_ids = []
for test_mail in test_emails:
- body = mailing.body_html
- unsubscribe_url = self.pool['mail.mass_mailing'].get_unsubscribe_url(cr, uid, mailing.id, 0, email=test_mail, context=context)
- body = tools.append_content_to_html(body, unsubscribe_url, plaintext=False, container_tag='p')
mail_values = {
'email_from': mailing.email_from,
'reply_to': mailing.reply_to,
'email_to': test_mail,
'subject': mailing.name,
- 'body_html': body,
+ 'body_html': mailing.body_html,
'auto_delete': True,
+ 'mailing_id': wizard.mass_mailing_id.id,
}
mail_ids.append(Mail.create(cr, uid, mail_values, context=context))
Mail.send(cr, uid, mail_ids, context=context)
diff --git a/addons/report/tests/test_reports.py b/addons/report/tests/test_reports.py
index b1853489573..d3718df5e63 100644
--- a/addons/report/tests/test_reports.py
+++ b/addons/report/tests/test_reports.py
@@ -19,7 +19,9 @@
#
##############################################################################
import logging
+
import openerp
+import openerp.tests
_logger = logging.getLogger(__name__)
diff --git a/addons/survey/survey.py b/addons/survey/survey.py
index 0569c8ab0d5..590d7ae22c8 100644
--- a/addons/survey/survey.py
+++ b/addons/survey/survey.py
@@ -34,6 +34,27 @@ import uuid
_logger = logging.getLogger(__name__)
+class survey_stage(osv.Model):
+ """Stages for Kanban view of surveys"""
+
+ _name = 'survey.stage'
+ _description = 'Survey Stage'
+ _order = 'sequence asc'
+
+ _columns = {
+ 'name': fields.char(string="Name", required=True, translate=True),
+ 'sequence': fields.integer(string="Sequence"),
+ 'closed': fields.boolean(string="Closed", help="If closed, people won't be able to answer to surveys in this column."),
+ 'fold': fields.boolean(string="Folded in kanban view")
+ }
+ _defaults = {
+ 'sequence': 1,
+ 'closed': False
+ }
+ _sql_constraints = [
+ ('positive_sequence', 'CHECK(sequence >= 0)', 'Sequence number MUST be a natural')
+ ]
+
class survey_survey(osv.Model):
'''Settings for a multi-page/multi-question survey.
@@ -175,9 +196,15 @@ class survey_survey(osv.Model):
'quizz_mode': fields.boolean(string='Quizz mode')
}
+ def _default_stage(self, cr, uid, context=None):
+ ids = self.pool['survey.stage'].search(cr, uid, [], limit=1, context=context)
+ if ids:
+ return ids[0]
+ return False
+
_defaults = {
'color': 0,
- 'stage_id': lambda self, cr, uid, context: self.pool.get('survey.stage').search_read(cr, uid, fields=['id'], order='sequence asc', limit=1, context=context)[0]['id']
+ 'stage_id': lambda self, *a, **kw: self._default_stage(*a, **kw)
}
def _read_group_stage_ids(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None):
@@ -456,26 +483,6 @@ class survey_survey(osv.Model):
}
-class survey_stage(osv.Model):
- """Stages for Kanban view of surveys"""
-
- _name = 'survey.stage'
- _description = 'Survey Stage'
- _order = 'sequence asc'
-
- _columns = {
- 'name': fields.char(string="Name", required=True, translate=True),
- 'sequence': fields.integer(string="Sequence"),
- 'closed': fields.boolean(string="Closed", help="If closed, people won't be able to answer to surveys in this column."),
- 'fold': fields.boolean(string="Folded in kanban view")
- }
- _defaults = {
- 'sequence': 1,
- 'closed': False
- }
- _sql_constraints = [
- ('positive_sequence', 'CHECK(sequence >= 0)', 'Sequence number MUST be a natural')
- ]
class survey_page(osv.Model):
diff --git a/addons/website/static/src/js/website.snippets.editor.js b/addons/website/static/src/js/website.snippets.editor.js
index f59f2cf07ca..bae014029e1 100644
--- a/addons/website/static/src/js/website.snippets.editor.js
+++ b/addons/website/static/src/js/website.snippets.editor.js
@@ -161,6 +161,7 @@
return this._super.apply(this, arguments);
},
save: function () {
+ website.snippet.clean_for_save = true;
this.snippets.clean_for_save();
this._super();
},
@@ -1518,6 +1519,9 @@
});
},
onFocus : function () {
+ // don't open media editor before clean for save
+ if (website.snippet.clean_for_save) return;
+
var self = this;
if (this.$target.parent().data("oe-field") === "image") {
this.$overlay.addClass("hidden");
diff --git a/addons/website_blog/models/website_blog.py b/addons/website_blog/models/website_blog.py
index 031856fff10..ab96cc5b7f8 100644
--- a/addons/website_blog/models/website_blog.py
+++ b/addons/website_blog/models/website_blog.py
@@ -52,7 +52,7 @@ class BlogPost(osv.Model):
'name': fields.char('Title', required=True, translate=True),
'subtitle': fields.char('Sub Title', translate=True),
'author_id': fields.many2one('res.partner', 'Author'),
- 'background_image': fields.binary('Background Image'),
+ 'background_image': fields.binary('Background Image', oldname='content_image'),
'blog_id': fields.many2one(
'blog.blog', 'Blog',
required=True, ondelete='cascade',
diff --git a/addons/website_certification/__init__.py b/addons/website_certification/__init__.py
new file mode 100644
index 00000000000..2a6cb8bee84
--- /dev/null
+++ b/addons/website_certification/__init__.py
@@ -0,0 +1,23 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-TODAY OpenERP S.A.
+#
+# 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 .
+#
+##############################################################################
+
+import certification
+import controllers
diff --git a/addons/website_certification/__openerp__.py b/addons/website_certification/__openerp__.py
new file mode 100644
index 00000000000..041014646fe
--- /dev/null
+++ b/addons/website_certification/__openerp__.py
@@ -0,0 +1,38 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-TODAY OpenERP S.A.
+#
+# 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 .
+#
+##############################################################################
+
+{
+ 'name': 'Certified People',
+ 'category': 'Website',
+ 'summary': 'Display your network of certified people on your website',
+ 'version': '1.0',
+ 'author': 'OpenERP S.A.',
+ 'depends': ['marketing', 'website'],
+ 'description': """
+ Display your network of certified people on your website
+ """,
+ 'data': [
+ 'security/ir.model.access.csv',
+ 'views/website_certification_views.xml',
+ 'views/website_certification_templates.xml',
+ ],
+ 'installable': True,
+}
diff --git a/addons/website_certification/certification.py b/addons/website_certification/certification.py
new file mode 100644
index 00000000000..48636e027f7
--- /dev/null
+++ b/addons/website_certification/certification.py
@@ -0,0 +1,43 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-TODAY OpenERP S.A.
+#
+# 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 .
+#
+##############################################################################
+
+
+from openerp.osv import osv, fields
+
+
+class certification_type(osv.Model):
+ _name = 'certification.type'
+ _order = 'name ASC'
+ _columns = {
+ 'name': fields.char("Certification Type", required=True)
+ }
+
+
+class certification_certification(osv.Model):
+ _name = 'certification.certification'
+ _order = 'certification_date DESC'
+ _columns = {
+ 'partner_id': fields.many2one('res.partner', string="Partner", required=True),
+ 'type_id': fields.many2one('certification.type', string="Certification", required=True),
+ 'certification_date': fields.date("Certification Date", required=True),
+ 'certification_score': fields.char("Certification Score", required=True),
+ 'certification_hidden_score': fields.boolean("Hide score on website?")
+ }
diff --git a/addons/website_certification/controllers/__init__.py b/addons/website_certification/controllers/__init__.py
new file mode 100644
index 00000000000..672df6ec1f9
--- /dev/null
+++ b/addons/website_certification/controllers/__init__.py
@@ -0,0 +1,22 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-TODAY OpenERP S.A.
+#
+# 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 .
+#
+##############################################################################
+
+import main
diff --git a/addons/website_certification/controllers/main.py b/addons/website_certification/controllers/main.py
new file mode 100644
index 00000000000..ab955bc12dd
--- /dev/null
+++ b/addons/website_certification/controllers/main.py
@@ -0,0 +1,49 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-TODAY OpenERP S.A.
+#
+# 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 .
+#
+##############################################################################
+
+
+from openerp.addons.web import http
+from openerp.addons.web.http import request
+
+
+class WebsiteCertifiedPartners(http.Controller):
+
+ @http.route(['/certifications',
+ '/certifications/'], type='http', auth='public',
+ website=True, multilang=True)
+ def certified_partners(self, cert_type=None, **post):
+ cr, uid, context = request.cr, request.uid, request.context
+ certification_obj = request.registry['certification.certification']
+ cert_type_obj = request.registry['certification.type']
+
+ domain = []
+ if cert_type:
+ domain.append(('type_id', '=', cert_type.id))
+
+ certifications_ids = certification_obj.search(cr, uid, domain, context=context)
+ certifications = certification_obj.browse(cr, uid, certifications_ids, context=context)
+ types = cert_type_obj.browse(cr, uid, cert_type_obj.search(cr, uid, [], context=context), context=context)
+ data = {
+ 'certifications': certifications,
+ 'types': types
+ }
+
+ return request.website.render("website_certification.certified_partners", data)
diff --git a/addons/website_certification/security/ir.model.access.csv b/addons/website_certification/security/ir.model.access.csv
new file mode 100644
index 00000000000..a297b053d26
--- /dev/null
+++ b/addons/website_certification/security/ir.model.access.csv
@@ -0,0 +1,7 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_certifications_public,certification.certification public,model_certification_certification,base.group_public,1,0,0,0
+access_certifications_types_public,certification.type public,model_certification_type,base.group_public,1,0,0,0
+access_certifications_users,certification.certification users,model_certification_certification,base.group_user,1,0,0,0
+access_certifications_types_users,certification.type users,model_certification_type,base.group_user,1,0,0,0
+access_certifications_marketing,certification.certification marketing,model_certification_certification,marketing.group_marketing_user,1,1,1,1
+access_certifications_types_marketing,certification.type marketing,model_certification_type,marketing.group_marketing_user,1,1,1,1
diff --git a/addons/website_certification/views/website_certification_templates.xml b/addons/website_certification/views/website_certification_templates.xml
new file mode 100644
index 00000000000..13fe86a810c
--- /dev/null
+++ b/addons/website_certification/views/website_certification_templates.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/website_certification/views/website_certification_views.xml b/addons/website_certification/views/website_certification_views.xml
new file mode 100644
index 00000000000..2935c541a7b
--- /dev/null
+++ b/addons/website_certification/views/website_certification_views.xml
@@ -0,0 +1,58 @@
+
+
+
+
+ view.certification.certification.tree
+ certification.certification
+
+
+
+
+
+
+
+
+
+
+
+ view.certification.certification.form
+ certification.certification
+
+
+
+
+
+ view.certification.certification.search
+ certification.certification
+
+
+
+
+
+
+
+
+
+
+
+
+ Certifications
+ certification.certification
+ form
+ tree,form
+
+
+
+
+
+
diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py
index d6394b069cc..6f5ba3e213c 100644
--- a/addons/website_forum/controllers/main.py
+++ b/addons/website_forum/controllers/main.py
@@ -32,12 +32,21 @@ class WebsiteForum(http.Controller):
return msg
def _prepare_forum_values(self, forum=None, **kwargs):
+ Forum = request.registry['forum.forum']
user = request.registry['res.users'].browse(request.cr, request.uid, request.uid, context=request.context)
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())}
+ 'searches': kwargs.get('searches', dict()),
+ 'can_edit_own': True,
+ 'can_edit_all': user.karma > Forum._karma_modo_edit_all,
+ 'can_close_own': user.karma > Forum._karma_modo_close_own,
+ 'can_close_all': user.karma > Forum._karma_modo_close_all,
+ 'can_unlink_own': user.karma > Forum._karma_modo_unlink_own,
+ 'can_unlink_all': user.karma > Forum._karma_modo_unlink_all,
+ 'can_unlink_comment': user.karma > Forum._karma_modo_unlink_comment,
+ }
if forum:
values['forum'] = forum
elif kwargs.get('forum_id'):
@@ -45,6 +54,14 @@ class WebsiteForum(http.Controller):
values.update(kwargs)
return values
+ def _has_enough_karma(self, karma_name, uid=None):
+ Forum = request.registry['forum.forum']
+ karma = hasattr(Forum, karma_name) and getattr(Forum, karma_name) or 0
+ user = request.registry['res.users'].browse(request.cr, SUPERUSER_ID, uid or request.uid, context=request.context)
+ if user.karma < karma:
+ return False, {'error': 'not_enough_karma', 'karma': karma}
+ return True, {}
+
# Forum
# --------------------------------------------------
@@ -204,6 +221,10 @@ class WebsiteForum(http.Controller):
@http.route('/forum//question//ask_for_close', type='http', auth="user", multilang=True, website=True)
def question_ask_for_close(self, forum, question, **post):
+ check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_close_own' or '_karma_modo_close_all')
+ if not check_res[0]:
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
cr, uid, context = request.cr, request.uid, request.context
Reason = request.registry['forum.post.reason']
reason_ids = Reason.search(cr, uid, [], context=context)
@@ -211,7 +232,7 @@ class WebsiteForum(http.Controller):
values = self._prepare_forum_values(**post)
values.update({
- 'post': question,
+ 'question': question,
'question': question,
'forum': forum,
'reasons': reasons,
@@ -228,6 +249,10 @@ class WebsiteForum(http.Controller):
@http.route('/forum//question//close', type='http', auth="user", multilang=True, methods=['POST'], website=True)
def question_close(self, forum, question, **post):
+ check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_close_own' or '_karma_modo_close_all')
+ if not check_res[0]:
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {
'state': 'close',
'closed_uid': request.uid,
@@ -238,17 +263,28 @@ class WebsiteForum(http.Controller):
@http.route('/forum//question//reopen', type='http', auth="user", multilang=True, website=True)
def question_reopen(self, forum, question, **kwarg):
+ check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_close_own' or '_karma_modo_close_all')
+ if not check_res[0]:
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'state': 'active'}, context=request.context)
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
@http.route('/forum//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.
+ check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_unlink_own' or '_karma_modo_unlink_all')
+ if not check_res[0]:
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'active': False}, context=request.context)
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
@http.route('/forum//question//undelete', type='http', auth="user", multilang=True, website=True)
def question_undelete(self, forum, question, **kwarg):
+ check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_unlink_own' or '_karma_modo_unlink_all')
+ if not check_res[0]:
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'active': True}, context=request.context)
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
@@ -287,19 +323,27 @@ class WebsiteForum(http.Controller):
@http.route('/forum//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 post.parent_id is False:
+ return request.redirect('/')
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:
+ user = request.registry['res.users'].browse(request.cr, SUPERUSER_ID, request.uid, context=request.context)
+ if post.parent_id.create_uid.id != uid:
return {'error': 'own_post'}
+ if post.create_uid.id == user.id and user.karma < request.registry['forum.forum']._karma_answer_accept_own:
+ return {'error': 'not_enough_karma', 'karma': 20}
# 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)
+ request.registry['forum.post'].write(cr, uid, [post.id], {'is_correct': not post.is_correct}, context=context)
return not post.is_correct
@http.route('/forum//post//delete', type='http', auth="user", multilang=True, website=True)
def post_delete(self, forum, post, **kwargs):
+ check_res = self._has_enough_karma(post.create_uid.id == request.uid and '_karma_modo_unlink_own' or '_karma_modo_unlink_all')
+ if not check_res[0]:
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
question = post.parent_id
request.registry['forum.post'].unlink(request.cr, request.uid, [post.id], context=request.context)
if question:
@@ -308,6 +352,10 @@ class WebsiteForum(http.Controller):
@http.route('/forum//post//edit', type='http', auth="user", website=True, multilang=True)
def post_edit(self, forum, post, **kwargs):
+ check_res = self._has_enough_karma(post.create_uid.id == request.uid and '_karma_modo_edit_own' or '_karma_modo_edit_all')
+ if not check_res[0]:
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
tags = ""
for tag_name in post.tag_ids:
tags += tag_name.name + ","
@@ -345,15 +393,15 @@ class WebsiteForum(http.Controller):
@http.route('/forum//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': 1}
- return request.registry['forum.post'].vote(request.cr, request.uid, [post.id], upvote=True, context=request.context)
+ check_res = self._has_enough_karma('_karma_upvote')
+ if not check_res[0]:
+ return check_res[1]
+ upvote = True if not post.user_vote > 0 else False
+ return request.registry['forum.post'].vote(request.cr, request.uid, [post.id], upvote=upvote, context=request.context)
@http.route('/forum//post//downvote', type='json', auth="public", multilang=True, website=True)
def post_downvote(self, forum, post, **kwargs):
@@ -361,10 +409,11 @@ class WebsiteForum(http.Controller):
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)
+ check_res = self._has_enough_karma('_karma_downvote')
+ if not check_res[0]:
+ return check_res[1]
+ upvote = True if post.user_vote < 0 else False
+ return request.registry['forum.post'].vote(request.cr, request.uid, [post.id], upvote=upvote, context=request.context)
# User
# --------------------------------------------------
@@ -392,6 +441,16 @@ class WebsiteForum(http.Controller):
return request.website.render("website_forum.users", values)
+ @http.route(['/forum//partner/'], type='http', auth="public", website=True, multilang=True)
+ def open_partner(self, forum, partner_id=0, **post):
+ cr, uid, context = request.cr, request.uid, request.context
+ pids = request.registry['res.partner'].search(cr, SUPERUSER_ID, [('id', '=', partner_id)], context=context)
+ if pids:
+ partner = request.registry['res.partner'].browse(cr, SUPERUSER_ID, pids[0], context=context)
+ if partner.user_ids:
+ return werkzeug.utils.redirect("/forum/%s/user/%d" % (slug(forum), partner.user_ids[0].id))
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
@http.route(['/forum//user/'], 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
diff --git a/addons/website_forum/data/badges_answer.xml b/addons/website_forum/data/badges_answer.xml
index 4e92600663d..97f184d59f0 100644
--- a/addons/website_forum/data/badges_answer.xml
+++ b/addons/website_forum/data/badges_answer.xml
@@ -1,6 +1,6 @@
-
+
@@ -8,6 +8,7 @@
TeacherReceived at least 3 upvote for an answer for the first timebronze
+ nobodyTeacher
@@ -42,6 +43,7 @@
Nice AnswerAnswer voted up 4 timesbronze
+ nobodyNice Answer (4)
@@ -76,6 +78,7 @@
Good AnswerAnswer voted up 6 timessilver
+ nobodyGood Answer (6)
@@ -110,6 +113,7 @@
Great AnswerAnswer voted up 15 timesgold
+ nobodyGreat Answer (15)
@@ -146,6 +150,7 @@
EnlightenedAnswer was accepted with 3 or more votessilver
+ nobodyEnlightened
@@ -180,6 +185,7 @@
GuruAnswer accepted with 15 or more votessilver
+ nobodyGuru (15)
@@ -256,6 +262,7 @@ for post in Post.browse(cr, uid, user_posts, context=context):
Self-LearnerAnswered own question with at least 4 up votesgold
+ nobodySelf-Learner
diff --git a/addons/website_forum/data/badges_moderation.xml b/addons/website_forum/data/badges_moderation.xml
index d99508bba51..41f3eb7fe41 100644
--- a/addons/website_forum/data/badges_moderation.xml
+++ b/addons/website_forum/data/badges_moderation.xml
@@ -1,6 +1,6 @@
-
+
@@ -15,6 +15,7 @@
CriticFirst downvotebronze
+ nobodyCritic
@@ -50,6 +51,7 @@
DisciplinedDeleted own post with 3 or more upvotesbronze
+ nobodyDisciplined
@@ -85,6 +87,7 @@
EditorFirst editgold
+ nobodyEditor
@@ -223,6 +226,7 @@ result = int(len(data) >= 15)
SupporterFirst upvotegold
+ nobodySupporter
@@ -258,6 +262,7 @@ result = int(len(data) >= 15)
Peer PressureDeleted own post with 3 or more downvotesgold
+ nobodyPeer Pressure
diff --git a/addons/website_forum/data/badges_participation.xml b/addons/website_forum/data/badges_participation.xml
index cf1f79185e1..05c2540d77d 100644
--- a/addons/website_forum/data/badges_participation.xml
+++ b/addons/website_forum/data/badges_participation.xml
@@ -1,12 +1,13 @@
-
+
AutobiographerCompleted own biographybronze
+ nobodyCompleted own biography
@@ -46,6 +47,7 @@
CommentatorPosted 10 commentsbronze
+ nobodyCommentator
@@ -81,6 +83,7 @@
PunditLeft comments with score of 10 or moresilver
+ nobodyPundit
@@ -115,6 +118,7 @@
Chief CommentatorPosted 100 commentssilver
+ nobodyChief Commentator
@@ -177,6 +181,7 @@ result = get_counter(cr, uid, context=context)
TaxonomistCreated a tag used by 15 questionssilver
+ nobodyTaxonomist
diff --git a/addons/website_forum/data/badges_question.xml b/addons/website_forum/data/badges_question.xml
index ab05d8bcf7a..ff2d63c034d 100644
--- a/addons/website_forum/data/badges_question.xml
+++ b/addons/website_forum/data/badges_question.xml
@@ -1,6 +1,6 @@
-
+
@@ -8,6 +8,7 @@
Popular QuestionAsked a question with at least 150 viewsbronze
+ nobodyPopular Question (150)
@@ -43,6 +44,7 @@
Notable QuestionAsked a question with at least 250 viewssilver
+ nobodyPopular Question (250)
@@ -77,6 +79,7 @@
Famous QuestionAsked a question with at least 500 viewsgold
+ nobodyPopular Question (500)
@@ -113,6 +116,7 @@
Credible QuestionQuestion set as favorite by 1 userbronze
+ nobodyFavourite Question (1)
@@ -147,6 +151,7 @@
Favorite QuestionQuestion set as favorite by 5 userssilver
+ nobodyFavourite Question (5)
@@ -181,6 +186,7 @@
Stellar QuestionQuestion set as favorite by 25 usersbronze
+ nobodyFavourite Question (25)
@@ -217,6 +223,7 @@
StudentAsked first question with at least one up votegold
+ nobodyUpvoted question (1)
@@ -251,6 +258,7 @@
Nice QuesiotnQuestion voted up 4 timesbronze
+ nobodyUpvoted question (4)
@@ -285,6 +293,7 @@
Good QuestionQuestion voted up 6 timessilver
+ nobodyUpvoted question (6)
@@ -319,6 +328,7 @@
Great QuestionQuestion voted up 15 timesgold
+ nobodyUpvoted question (15)
@@ -354,6 +364,7 @@
ScholarAsked a question and accepted an answergold
+ nobodyScholar
diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py
index 166fdb809c7..7a8385d1a82 100644
--- a/addons/website_forum/models/forum.py
+++ b/addons/website_forum/models/forum.py
@@ -9,9 +9,38 @@ from openerp.tools.translate import _
class Forum(osv.Model):
+ """TDE TODO: set karma values for actions dynamic for a given forum"""
_name = 'forum.forum'
_description = 'Forums'
_inherit = ['website.seo.metadata']
+ # karma values
+ _karma_upvote = 5 # done
+ _karma_downvote = 50 # done
+ _karma_answer_accept_own = 20 # done
+ _karma_answer_accept_own_now = 50
+ _karma_answer_accept_all = 500
+ _karma_editor_link_files = 30 # done
+ _karma_editor_clickable_link = 50
+ _karma_comment = 1
+ _karma_modo_retag = 75
+ _karma_modo_flag = 100
+ _karma_modo_flag_see_all = 300
+ _karma_modo_unlink_comment = 750
+ _karma_modo_edit_own = 1 # done
+ _karma_modo_edit_all = 300 # done
+ _karma_modo_close_own = 100 # done
+ _karma_modo_close_all = 900 # done
+ _karma_modo_unlink_own = 500 # done
+ _karma_modo_unlink_all = 1000 # done
+ # karma generation
+ _karma_gen_quest_new = 2 # done
+ _karma_gen_upvote_quest = 5 # done
+ _karma_gen_downvote_quest = -2 # done
+ _karma_gen_upvote_ans = 10 # done
+ _karma_gen_downvote_ans = -2 # done
+ _karma_gen_ans_accept = 2 # done
+ _karma_gen_ans_accepted = 15 # done
+ _karma_gen_ans_flagged = -100
_columns = {
'name': fields.char('Name', required=True, translate=True),
@@ -97,6 +126,13 @@ class Post(osv.Model):
res[post.id] = any(answer.create_uid.id == uid for answer in post.child_ids)
return res
+ def _get_has_validated_answer(self, cr, uid, ids, field_name, arg, context=None):
+ res = dict.fromkeys(ids, False)
+ ans_ids = self.search(cr, uid, [('parent_id', 'in', ids), ('is_correct', '=', True)], context=context)
+ for answer in self.browse(cr, uid, ans_ids, context=context):
+ res[answer.parent_id.id] = True
+ return res
+
def _is_self_reply(self, cr, uid, ids, field_name, arg, context=None):
res = dict.fromkeys(ids, False)
for post in self.browse(cr, uid, ids, context=context):
@@ -143,7 +179,8 @@ class Post(osv.Model):
}),
# hierarchy
'parent_id': fields.many2one('forum.post', 'Question', ondelete='cascade'),
- 'self_reply': fields.function(_is_self_reply, 'Reply to own question', type='boolean',
+ 'self_reply': fields.function(
+ _is_self_reply, 'Reply to own question', type='boolean',
store={
'forum.post': (lambda self, cr, uid, ids, c={}: ids, ['parent_id', 'create_uid'], 10),
}),
@@ -156,6 +193,12 @@ class Post(osv.Model):
'uid_has_answered': fields.function(
_get_uid_answered, string='Has Answered', type='boolean',
),
+ 'has_validated_answer': fields.function(
+ _get_has_validated_answer, string='Has a Validated Answered', type='boolean',
+ store={
+ 'forum.post': (_get_post_from_hierarchy, ['parent_id', 'child_ids', 'is_correct'], 10),
+ }
+ ),
# closing
'closed_reason_id': fields.many2one('forum.post.reason', 'Reason'),
'closed_uid': fields.many2one('res.users', 'Closed by', select=1),
@@ -183,10 +226,18 @@ class Post(osv.Model):
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=vals.get('name', ''), body=_('New Question Created'), subtype='website_forum.mt_question_new', context=context)
- self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], 2, context=context)
+ self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], self.pool['forum.forum']._karma_gen_quest_new, context=context)
return post_id
def write(self, cr, uid, ids, vals, context=None):
+ Forum = self.pool['forum.forum']
+ # update karma when accepting/rejecting answers
+ if 'is_correct' in vals:
+ mult = 1 if vals['is_correct'] else -1
+ for post in self.browse(cr, uid, ids, context=context):
+ if vals['is_correct'] != post.is_correct:
+ self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [post.create_uid.id], Forum._karma_gen_ans_accepted * mult, context=context)
+ self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], Forum._karma_gen_ans_accept * mult, context=context)
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:
@@ -198,11 +249,6 @@ class Post(osv.Model):
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'].add_karma(cr, SUPERUSER_ID, [post.create_uid.id], {'karma': karma_value}, context=context)
return res
def vote(self, cr, uid, ids, upvote=True, context=None):
@@ -252,16 +298,30 @@ class Vote(osv.Model):
def create(self, cr, uid, vals, context=None):
vote_id = super(Vote, self).create(cr, uid, vals, context=context)
- karma_value = int(vals.get('vote', '1')) * 10
- post = self.pool['forum.post'].browse(cr, uid, vals.get('post_id'), context=context)
- self.pool['res.users'].add_karma(cr, SUPERUSER_ID, post.create_uid.id, karma_value, context=context)
+ if vals.get('vote', '1') == '1':
+ karma = self.pool['forum.forum']._karma_upvote
+ elif vals.get('vote', '1') == '-1':
+ karma = self.pool['forum.forum']._karma_downvote
+ post = self.pool['forum.post'].browse(cr, uid, vals['post_id'], context=context)
+ self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [post.create_uid.id], karma, context=context)
return vote_id
def write(self, cr, uid, ids, values, context=None):
+ def _get_karma_value(old_vote, new_vote, up_karma, down_karma):
+ _karma_upd = {
+ '-1': {'-1': 0, '0': -1 * down_karma, '1': -1 * down_karma + up_karma},
+ '0': {'-1': 1 * down_karma, '0': 0, '1': up_karma},
+ '1': {'-1': -1 * up_karma + down_karma, '0': -1 * up_karma, '1': 0}
+ }
+ return _karma_upd[old_vote][new_vote]
if 'vote' in values:
+ Forum = self.pool['forum.forum']
for vote in self.browse(cr, uid, ids, context=context):
- karma_value = (int(values.get('vote')) - int(vote.vote)) * 10
- self.pool['res.users'].add_karma(cr, SUPERUSER_ID, vote.post_id.create_uid.id, karma_value, context=context)
+ if vote.post_id.parent_id:
+ karma_value = _get_karma_value(vote.vote, values['vote'], Forum._karma_gen_upvote_ans, Forum._karma_gen_downvote_ans)
+ else:
+ karma_value = _get_karma_value(vote.vote, values['vote'], Forum._karma_gen_upvote_quest, Forum._karma_gen_downvote_quest)
+ self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [vote.post_id.create_uid.id], karma_value, context=context)
res = super(Vote, self).write(cr, uid, ids, values, context=context)
return res
diff --git a/addons/website_forum/models/res_users.py b/addons/website_forum/models/res_users.py
index 58d43a58191..a9f2dfe0e93 100644
--- a/addons/website_forum/models/res_users.py
+++ b/addons/website_forum/models/res_users.py
@@ -32,8 +32,6 @@ class Users(osv.Model):
}
def add_karma(self, cr, uid, ids, karma, context=None):
- if isinstance(ids, (int, long)):
- ids = [ids]
for user in self.browse(cr, uid, ids, context=context):
self.write(cr, uid, [user.id], {'karma': user.karma + karma}, context=context)
return True
@@ -44,4 +42,4 @@ class Users(osv.Model):
excluded_categories.append('forum')
else:
excluded_categories = ['forum']
- return super(Users, self).get_serialised_gamification_summary(cr, uid, excluded_categories=excluded_categories, context=context)
\ No newline at end of file
+ return super(Users, self).get_serialised_gamification_summary(cr, uid, excluded_categories=excluded_categories, context=context)
diff --git a/addons/website_forum/static/src/js/website_forum.js b/addons/website_forum/static/src/js/website_forum.js
index f483fb98855..9053c573efb 100644
--- a/addons/website_forum/static/src/js/website_forum.js
+++ b/addons/website_forum/static/src/js/website_forum.js
@@ -18,9 +18,9 @@ $(document).ready(function () {
'');
}
else if (data['error'] == 'not_enough_karma') {
- var $warning = $('
'+
+ var $warning = $('
'+
''+
- 'Sorry, at least ' + data['karma'] + ' karma is required to vote'+
+ 'Sorry, at least ' + data['karma'] + ' karma is required to vote. You can gain karma by answering questions and receiving votes.'+
'
'+
''+
- 'Sorry, the user who asked this question can only accept the answer as correct.'+
+ 'Sorry, only the user who asked this question can accept the answer as correct.'+
+ '
');
+ } else if (data['error'] == 'not_enough_karma') {
+ var $warning = $('
'+
+ ''+
+ 'Sorry, at least ' + data['karma'] + ' karma is required to accept your own answers. You can gain karma by answering questions and receiving votes.'+
'