diff --git a/addons/gamification/data/goal_base.xml b/addons/gamification/data/goal_base.xml
index 48dd770bbcc..5da7b86679d 100644
--- a/addons/gamification/data/goal_base.xml
+++ b/addons/gamification/data/goal_base.xml
@@ -61,7 +61,7 @@
Mail Group FollowingFollow mail groups to receive newspython
- self.number_following(cr, uid, 'mail.group')
+ result = pool.get('mail.followers').search(cr, uid, [('res_model', '=', 'mail.group'), ('partner_id', '=', object.user_id.partner_id.id)], count=True, context=context)
diff --git a/addons/gamification/data/goal_definition.py b/addons/gamification/data/goal_definition.py
index 937168fc0a2..e16f2c7b11f 100644
--- a/addons/gamification/data/goal_definition.py
+++ b/addons/gamification/data/goal_definition.py
@@ -30,12 +30,3 @@ class gamification_goal_definition_data(osv.Model):
of a user's goal. The return definition must be a float or integer.
"""
_inherit = 'gamification.goal.definition'
-
- def number_following(self, cr, uid, xml_id="mail.thread", context=None):
- """Return the number of 'xml_id' objects the user is following
-
- The model specified in 'xml_id' must inherit from mail.thread
- """
- ref_obj = self.pool.get(xml_id)
- user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
- return ref_obj.search(cr, uid, [('message_follower_ids', '=', user.partner_id.id)], count=True, context=context)
diff --git a/addons/gamification/models/goal.py b/addons/gamification/models/goal.py
index 698d20d0159..8792e219d71 100644
--- a/addons/gamification/models/goal.py
+++ b/addons/gamification/models/goal.py
@@ -25,9 +25,9 @@ from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DF
from openerp.tools.safe_eval import safe_eval
from openerp.tools.translate import _
-from datetime import date, datetime, timedelta
-
import logging
+import time
+from datetime import date, datetime, timedelta
_logger = logging.getLogger(__name__)
@@ -75,7 +75,6 @@ class gamification_goal_definition(osv.Model):
required=True),
'display_mode': fields.selection([
('progress', 'Progressive (using numerical values)'),
- ('checkbox', 'Checkbox (done or not-done)'),
('boolean', 'Exclusive (done or not-done)'),
],
string="Displayed as", required=True),
@@ -91,8 +90,8 @@ class gamification_goal_definition(osv.Model):
'domain': fields.char("Filter Domain",
help="Domain for filtering records. The rule can contain reference to 'user' that is a browse record of the current user, e.g. [('user_id', '=', user.id)].",
required=True),
- 'compute_code': fields.char('Compute Code',
- help="The name of the python method that will be executed to compute the current value. See the file gamification/goal_definition_data.py for examples."),
+ 'compute_code': fields.text('Python Code',
+ help="Python code to be executed for each user. 'result' should contains the new current value. Evaluated user can be access through object.user_id."),
'condition': fields.selection([
('higher', 'The higher the better'),
('lower', 'The lower the better')
@@ -114,6 +113,15 @@ class gamification_goal_definition(osv.Model):
'display_mode': 'progress',
}
+ def number_following(self, cr, uid, model_name="mail.thread", context=None):
+ """Return the number of 'model_name' objects the user is following
+
+ The model specified in 'model_name' must inherit from mail.thread
+ """
+ user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
+ return self.pool.get('mail.followers').search(cr, uid, [('res_model', '=', model_name), ('partner_id', '=', user.partner_id.id)], count=True, context=context)
+
+
class gamification_goal(osv.Model):
"""Goal instance for a user
@@ -221,6 +229,8 @@ class gamification_goal(osv.Model):
If a goal reaches the target value, the status is set to reached
If the end date is passed (at least +1 day, time not considered) without
the target value being reached, the goal is set as failed."""
+ if context is None:
+ context = {}
for goal in self.browse(cr, uid, ids, context=context):
towrite = {}
@@ -233,14 +243,25 @@ class gamification_goal(osv.Model):
elif goal.definition_id.computation_mode == 'python':
# execute the chosen method
- values = {'cr': cr, 'uid': goal.user_id.id, 'context': context, 'self': self.pool.get('gamification.goal.definition')}
- result = safe_eval(goal.definition_id.compute_code, values, {})
-
- if type(result) in (float, int, long) and result != goal.current:
- towrite['current'] = result
+ cxt = {
+ 'self': self.pool.get('gamification.goal'),
+ 'object': goal,
+ 'pool': self.pool,
+ 'cr': cr,
+ 'context': dict(context), # copy context to prevent side-effects of eval
+ 'uid': uid,
+ 'result': False,
+ 'date': date, 'datetime': datetime, 'timedelta': timedelta, 'time': time
+ }
+ code = goal.definition_id.compute_code.strip()
+ safe_eval(code, cxt, mode="exec", nocopy=True)
+ # the result of the evaluated codeis put in the 'result' local variable, propagated to the context
+ result = cxt.get('result', False)
+ if result and type(result) in (float, int, long):
+ if result != goal.current:
+ towrite['current'] = result
else:
- _logger.exception(_('Unvalid return content from the evaluation of %s' % str(goal.definition_id.compute_code)))
- # raise osv.except_osv(_('Error!'), _('Unvalid return content from the evaluation of %s' % str(goal.definition_id.compute_code)))
+ _logger.exception(_('Invalid return content from the evaluation of %s' % code))
else: # count or sum
obj = self.pool.get(goal.definition_id.model_id.model)
@@ -249,7 +270,7 @@ class gamification_goal(osv.Model):
# eval the domain with user replaced by goal user object
domain = safe_eval(goal.definition_id.domain, {'user': goal.user_id})
- #add temporal clause(s) to the domain if fields are filled on the goal
+ # add temporal clause(s) to the domain if fields are filled on the goal
if goal.start_date and field_date_name:
domain.append((field_date_name, '>=', goal.start_date))
if goal.end_date and field_date_name:
@@ -263,7 +284,7 @@ class gamification_goal(osv.Model):
else: # computation mode = count
new_value = obj.search(cr, uid, domain, context=context, count=True)
- #avoid useless write if the new value is the same as the old one
+ # avoid useless write if the new value is the same as the old one
if new_value != goal.current:
towrite['current'] = new_value
diff --git a/addons/gamification/static/src/js/gamification.js b/addons/gamification/static/src/js/gamification.js
index 22cfd5f3ab5..2a8db5f369d 100644
--- a/addons/gamification/static/src/js/gamification.js
+++ b/addons/gamification/static/src/js/gamification.js
@@ -7,9 +7,9 @@ openerp.gamification = function(instance) {
var self = this;
this._super(parent, action);
this.deferred = $.Deferred();
- // this.res_user = new instance.web.DataSetSearch(this, 'res.users');
this.goals_info = {};
this.challenge_suggestions = {};
+ $(document).off('keydown.klistener');
},
events: {
// update a challenge and related goals
@@ -49,6 +49,21 @@ openerp.gamification = function(instance) {
self.get_goal_todo_info();
});
});
+ },
+ 'click .oe_goal h4': function(event) {
+ var self = this;
+ this.kkeys = [];
+ $(document).on('keydown.klistener', function(event) {
+ if ("37,38,39,40,65,66".indexOf(event.keyCode) < 0) {
+ $(document).off('keydown.klistener');
+ } else {
+ self.kkeys.push(event.keyCode);
+ if (self.kkeys.toString().indexOf("38,38,40,40,37,39,37,39,66,65") >= 0) {
+ new instance.web.Model('gamification.badge').call('check_progress', []);
+ $(document).off('keydown.klistener');
+ }
+ }
+ });
}
},
start: function() {
@@ -63,6 +78,7 @@ openerp.gamification = function(instance) {
if (result.length === 0) {
self.$el.find(".oe_gamification_challenge_list").hide();
} else {
+ self.$el.find(".oe_gamification_challenge_list").empty();
_.each(result, function(item){
var $item = $(QWeb.render("gamification.ChallengeSummary", {challenge: item}));
self.render_money_fields($item);
@@ -115,34 +131,7 @@ openerp.gamification = function(instance) {
this._super();
var sidebar = new instance.gamification.Sidebar(this);
sidebar.appendTo($('.oe_mail_wall_aside'));
- }
- });
-
- instance.web_kanban.KanbanView.include({
- start: function() {
- this._super();
- $(document).off('keydown.klistener');
},
- events: {
- 'click': function(event) {
- var self = this;
- if (this.ViewManager.dataset.model === 'gamification.badge') {
- this.kkeys = [];
- $(document).off('keydown.klistener');
- $(document).on('keydown.klistener', function(event) {
- if ("37,38,39,40,65,66".indexOf(event.keyCode) < 0) {
- $(document).off('keydown.klistener');
- } else {
- self.kkeys.push(event.keyCode);
- if (self.kkeys.toString().indexOf("38,38,40,40,37,39,37,39,66,65") >= 0) {
- new instance.web.Model('gamification.badge').call('check_progress', []);
- $(document).off('keydown.klistener');
- }
- }
- });
- }
- }
- }
});
instance.web_kanban.KanbanRecord.include({
diff --git a/addons/gamification/views/challenge.xml b/addons/gamification/views/challenge.xml
index 973194738cd..3aa4410aaf2 100644
--- a/addons/gamification/views/challenge.xml
+++ b/addons/gamification/views/challenge.xml
@@ -101,9 +101,9 @@
-
-
Depending on the Diasplay mode, reports will be individual or shared.
-
+
+
Depending on the Display mode, reports will be individual or shared.