From a52e13bd86aa55662235095f27b327a0a74d04e3 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Mon, 14 Apr 2014 15:17:20 +0200 Subject: [PATCH 1/9] [FIX] remove wrong required and readonly fields bzr revid: mat@openerp.com-20140414131720-bzqd1sv0j2t5wywd --- addons/gamification/views/challenge.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/gamification/views/challenge.xml b/addons/gamification/views/challenge.xml index b37ef0eb0d8..f177a55ac5d 100644 --- a/addons/gamification/views/challenge.xml +++ b/addons/gamification/views/challenge.xml @@ -81,12 +81,12 @@ - + - +

Badges are granted when a challenge is finished. This is either at the end of a running period (eg: end of the month for a monthly challenge), at the end date of a challenge (if no periodicity is set) or when the challenge is manually closed.

From 0c8539846aaf3c55f1f42f7dd48dc2643667bd18 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Mon, 14 Apr 2014 15:51:15 +0200 Subject: [PATCH 2/9] [ADD] website_forum: quality badges bzr revid: mat@openerp.com-20140414135115-onmywwurr03g21dw --- addons/gamification/models/goal.py | 4 +-- addons/website_forum/data/badges_answer.xml | 37 ++++++++++++++------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/addons/gamification/models/goal.py b/addons/gamification/models/goal.py index 6ab4259cca2..a24df6e5c2d 100644 --- a/addons/gamification/models/goal.py +++ b/addons/gamification/models/goal.py @@ -287,11 +287,9 @@ class gamification_goal(osv.Model): field_date_name = definition.field_date_id and definition.field_date_id.name or False if definition.computation_mode == 'count' and definition.batch_mode: - + # batch mode, trying to do as much as possible in one request general_domain = safe_eval(definition.domain) - # goal_distinct_values = {goal.id: safe_eval(definition.batch_user_expression, {'user': goal.user_id}) for goal in goals} field_name = definition.batch_distinctive_field.name - # general_domain.append((field_name, 'in', list(set(goal_distinct_values.keys())))) subqueries = {} for goal in goals: start_date = field_date_name and goal.start_date or False diff --git a/addons/website_forum/data/badges_answer.xml b/addons/website_forum/data/badges_answer.xml index 8b56a5ac02e..b88ac0945d1 100644 --- a/addons/website_forum/data/badges_answer.xml +++ b/addons/website_forum/data/badges_answer.xml @@ -4,7 +4,7 @@ - + - + - + - + From c40318a46a1fa8ebc5f8e66fc4d5e3cd094c40b4 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Mon, 14 Apr 2014 16:54:15 +0200 Subject: [PATCH 3/9] [ADD] website_forum: self_reply field and some badges bzr revid: mat@openerp.com-20140414145415-8g9jtp95d173183i --- addons/gamification/models/goal.py | 2 +- addons/website_forum/data/badges_answer.xml | 56 +++++++++++++-------- addons/website_forum/models/forum.py | 10 ++++ 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/addons/gamification/models/goal.py b/addons/gamification/models/goal.py index a24df6e5c2d..268f27e3fe7 100644 --- a/addons/gamification/models/goal.py +++ b/addons/gamification/models/goal.py @@ -304,7 +304,7 @@ class gamification_goal(osv.Model): if end_date: subquery_domain.append((field_date_name, '>=', end_date)) - user_values = obj.read_group(cr, uid, subquery_domain, fields=[field_name], groupby=[field_name], context=context) + user_values = obj.read_group(cr, uid, subquery_domain, fields=[field_name], groupby=[field_name], context=context) for goal in [g for g in goals if g.id in query_goals.keys()]: for user_value in user_values: diff --git a/addons/website_forum/data/badges_answer.xml b/addons/website_forum/data/badges_answer.xml index b88ac0945d1..fa367e70ce8 100644 --- a/addons/website_forum/data/badges_answer.xml +++ b/addons/website_forum/data/badges_answer.xml @@ -61,6 +61,7 @@ personal never + True inprogress forum @@ -94,6 +95,7 @@ personal never + True inprogress forum @@ -127,6 +129,7 @@ personal never + True inprogress forum @@ -139,7 +142,7 @@ - + - + - + \ No newline at end of file diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py index 74f4d9e5393..cd22992f6b3 100644 --- a/addons/website_forum/models/forum.py +++ b/addons/website_forum/models/forum.py @@ -97,6 +97,12 @@ class Post(osv.Model): res[post.id] = any(answer.create_uid.id == uid for answer in post.child_ids) 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): + res[post.id] = post.parent_id and post.parent_id.create_uid == post.create_uid or False + return res + _columns = { 'name': fields.char('Title', size=128), 'forum_id': fields.many2one('forum.forum', 'Forum', required=True), @@ -137,6 +143,10 @@ 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', + store={ + 'forum.post': (lambda self, cr, uid, ids, c={}: ids, ['parent_id', 'create_uid'], 10), + }), 'child_ids': fields.one2many('forum.post', 'parent_id', 'Answers'), 'child_count': fields.function( _get_child_count, string="Answers", type='integer', From 9f3a2f84e03862c57e80337103d35e12b19d539d Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Mon, 14 Apr 2014 17:53:44 +0200 Subject: [PATCH 4/9] [ADD] website_forum: more badges bzr revid: mat@openerp.com-20140414155344-v580tpy5l12z9v95 --- addons/website_forum/data/badges_answer.xml | 10 +- .../website_forum/data/badges_moderation.xml | 133 ++++++++---------- 2 files changed, 66 insertions(+), 77 deletions(-) diff --git a/addons/website_forum/data/badges_answer.xml b/addons/website_forum/data/badges_answer.xml index fa367e70ce8..9aed157df21 100644 --- a/addons/website_forum/data/badges_answer.xml +++ b/addons/website_forum/data/badges_answer.xml @@ -44,7 +44,7 @@ bronze - Nice Answer + Nice Answer (4) Answer voted up 4 times count boolean @@ -78,7 +78,7 @@ silver - Good Answer + Good Answer (6) Answer voted up 6 times count boolean @@ -112,7 +112,7 @@ gold - Great Answer + Great Answer (15) Answer voted up 15 times count boolean @@ -182,7 +182,7 @@ silver - Guru + Guru (15) Answer accepted with 15 or more votes count boolean @@ -194,7 +194,7 @@ user.id - Great Answer + Guru once personal never diff --git a/addons/website_forum/data/badges_moderation.xml b/addons/website_forum/data/badges_moderation.xml index c169e5bc668..0a6f2d9925d 100644 --- a/addons/website_forum/data/badges_moderation.xml +++ b/addons/website_forum/data/badges_moderation.xml @@ -3,38 +3,15 @@ + - + - + - + - - - - - - - - - - - - - - Supporter First upvote gold - --> - - + - - + \ No newline at end of file From 14ff39f96ee23d07b1de0ea7848f28a5464dbe26 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 15 Apr 2014 12:18:42 +0200 Subject: [PATCH 5/9] [FIX] website_forum: mooooore baaaaaadges bzr revid: mat@openerp.com-20140415101842-yf6vndw7h62q0b42 --- addons/gamification/models/goal.py | 6 +- .../data/badges_participation.xml | 77 ++++++++++--------- addons/website_forum/models/forum.py | 1 + 3 files changed, 46 insertions(+), 38 deletions(-) diff --git a/addons/gamification/models/goal.py b/addons/gamification/models/goal.py index 268f27e3fe7..e39427c6bdb 100644 --- a/addons/gamification/models/goal.py +++ b/addons/gamification/models/goal.py @@ -304,7 +304,11 @@ class gamification_goal(osv.Model): if end_date: subquery_domain.append((field_date_name, '>=', end_date)) - user_values = obj.read_group(cr, uid, subquery_domain, fields=[field_name], groupby=[field_name], context=context) + if field_name == 'id': + user_ids = obj.search(cr, uid, subquery_domain, context=context) + user_values = [{'id': user_id, 'id_count': 1} for user_id in user_ids] + else: + user_values = obj.read_group(cr, uid, subquery_domain, fields=[field_name], groupby=[field_name], context=context) for goal in [g for g in goals if g.id in query_goals.keys()]: for user_value in user_values: diff --git a/addons/website_forum/data/badges_participation.xml b/addons/website_forum/data/badges_participation.xml index 9d0c2139abe..04c2ab7e4d9 100644 --- a/addons/website_forum/data/badges_participation.xml +++ b/addons/website_forum/data/badges_participation.xml @@ -3,7 +3,7 @@ - + - + - + - + - + 1 + \ No newline at end of file diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py index cd22992f6b3..4a368c361a4 100644 --- a/addons/website_forum/models/forum.py +++ b/addons/website_forum/models/forum.py @@ -293,4 +293,5 @@ class Tags(osv.Model): 'forum.post': (_get_tag_from_post, ['tag_ids'], 10), } ), + 'create_uid': fields.many2one('res.users', 'Created by', readonly=True), } From 15306066d0e0196001ab4afdb76901267b59553a Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 15 Apr 2014 13:35:45 +0200 Subject: [PATCH 6/9] I love the smell of napalm in the morning. bzr revid: mat@openerp.com-20140415113545-31efpjddjwqr4ajl --- addons/website_forum/data/badges_question.xml | 177 +++++++++++------- 1 file changed, 111 insertions(+), 66 deletions(-) diff --git a/addons/website_forum/data/badges_question.xml b/addons/website_forum/data/badges_question.xml index 02e9a9f306e..fd9c56636ff 100644 --- a/addons/website_forum/data/badges_question.xml +++ b/addons/website_forum/data/badges_question.xml @@ -4,19 +4,22 @@ - + + - + - + - + - + - + - + - + - + - + - + \ No newline at end of file From bc0738e47e37be2e5c1c5d9f235adb62265bdc9e Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 15 Apr 2014 15:19:29 +0200 Subject: [PATCH 7/9] One morning I shot an elephant in my pajamas. How he got in my pajamas, I don't know. bzr revid: mat@openerp.com-20140415131929-6pktlodmlgr2fuwz --- addons/website_forum/controllers/main.py | 2 +- addons/website_forum/models/forum.py | 25 ++++++++++-------------- addons/website_forum/models/res_users.py | 2 ++ 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py index 90cbf0ba722..354aa52c8b3 100644 --- a/addons/website_forum/controllers/main.py +++ b/addons/website_forum/controllers/main.py @@ -348,7 +348,7 @@ class WebsiteForum(http.Controller): 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 {'error': 'not_enough_karma', 'karma': 1} return request.registry['forum.post'].vote(request.cr, request.uid, [post.id], upvote=True, context=request.context) @http.route('/forum//post//downvote', type='json', auth="public", multilang=True, website=True) diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py index 4a368c361a4..031ae4b33e1 100644 --- a/addons/website_forum/models/forum.py +++ b/addons/website_forum/models/forum.py @@ -176,15 +176,14 @@ class Post(osv.Model): context = {} create_context = dict(context, mail_create_nolog=True) post_id = super(Post, self).create(cr, uid, vals, context=create_context) - post = 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 = _('

New Answer Posted

' % (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) + 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) return post_id def write(self, cr, uid, ids, vals, context=None): @@ -203,7 +202,7 @@ class Post(osv.Model): 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) + 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): @@ -241,7 +240,7 @@ class Vote(osv.Model): _description = 'Vote' _columns = { 'post_id': fields.many2one('forum.post', 'Post', ondelete='cascade', required=True), - 'user_id': fields.many2one('res.users', 'User'), + 'user_id': fields.many2one('res.users', 'User', required=True), 'vote': fields.selection([('1', '1'), ('-1', '-1'), ('0', '0')], 'Vote', required=True), 'create_date': fields.datetime('Create Date', select=True, readonly=True), } @@ -250,23 +249,19 @@ class Vote(osv.Model): '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) + 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) 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) + 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) + 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 89a23cc2901..3170fedf50a 100644 --- a/addons/website_forum/models/res_users.py +++ b/addons/website_forum/models/res_users.py @@ -32,6 +32,8 @@ 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 From 35c7f4814d08baa8772f0971051148398dab1e45 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 15 Apr 2014 15:48:09 +0200 Subject: [PATCH 8/9] Allow overwrite of the serialising method to exclude some categories in the challenge search bzr revid: mat@openerp.com-20140415134809-uconkvnp0z32jxjs --- addons/gamification/models/res_users.py | 15 ++++++++------- addons/website_forum/models/gamification.py | 1 + addons/website_forum/models/res_users.py | 8 ++++++++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/addons/gamification/models/res_users.py b/addons/gamification/models/res_users.py index 85cc18636f0..faca484dfb3 100644 --- a/addons/gamification/models/res_users.py +++ b/addons/gamification/models/res_users.py @@ -61,13 +61,12 @@ class res_users_gamification_group(osv.Model): challenge_obj.generate_goals_from_challenge(cr, SUPERUSER_ID, challenge_ids, context=context) return write_res - # def get_goals_todo_info(self, cr, uid, context=None): + def get_serialised_gamification_summary(self, cr, uid, excluded_categories=None, context=None): + return self._serialised_goals_summary(cr, uid, user_id=uid, excluded_categories=excluded_categories, context=context) - def get_serialised_gamification_summary(self, cr, uid, context=None): - return self._serialised_goals_summary(cr, uid, user_id=uid, context=context) - - def _serialised_goals_summary(self, cr, uid, user_id, context=None): + def _serialised_goals_summary(self, cr, uid, user_id, excluded_categories=None, context=None): """Return a serialised list of goals assigned to the user, grouped by challenge + :excluded_categories: list of challenge categories to exclude in search [ { @@ -81,9 +80,11 @@ class res_users_gamification_group(osv.Model): """ all_goals_info = [] challenge_obj = self.pool.get('gamification.challenge') - + domain = [('user_ids', 'in', uid), ('state', '=', 'inprogress')] + if excluded_categories and isinstance(excluded_categories, list): + domain.append(('category', 'not in', excluded_categories)) user = self.browse(cr, uid, uid, context=context) - challenge_ids = challenge_obj.search(cr, uid, [('user_ids', 'in', uid), ('state', '=', 'inprogress')], context=context) + challenge_ids = challenge_obj.search(cr, uid, domain, context=context) for challenge in challenge_obj.browse(cr, uid, challenge_ids, context=context): # serialize goals info to be able to use it in javascript lines = challenge_obj._get_serialized_challenge_lines(cr, uid, challenge, user_id, restrict_top=MAX_VISIBILITY_RANKING, context=context) diff --git a/addons/website_forum/models/gamification.py b/addons/website_forum/models/gamification.py index cffe52c4848..20eaca9851e 100644 --- a/addons/website_forum/models/gamification.py +++ b/addons/website_forum/models/gamification.py @@ -12,6 +12,7 @@ class gamification_challenge(osv.Model): return res + class Badge(osv.Model): _inherit = 'gamification.badge' _columns = { diff --git a/addons/website_forum/models/res_users.py b/addons/website_forum/models/res_users.py index 3170fedf50a..58d43a58191 100644 --- a/addons/website_forum/models/res_users.py +++ b/addons/website_forum/models/res_users.py @@ -37,3 +37,11 @@ class Users(osv.Model): for user in self.browse(cr, uid, ids, context=context): self.write(cr, uid, [user.id], {'karma': user.karma + karma}, context=context) return True + + def get_serialised_gamification_summary(self, cr, uid, excluded_categories=None, context=None): + if isinstance(excluded_categories, list): + if 'forum' not in excluded_categories: + 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 From 04436809528cba1f790262e103c5dd51e9282025 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 15 Apr 2014 18:15:38 +0200 Subject: [PATCH 9/9] [FIX] gamification: the subquery domain should use less than for ending dates bzr revid: mat@openerp.com-20140415161538-mdfadjjih90wuj3d --- addons/gamification/models/goal.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/addons/gamification/models/goal.py b/addons/gamification/models/goal.py index e39427c6bdb..af9a763236d 100644 --- a/addons/gamification/models/goal.py +++ b/addons/gamification/models/goal.py @@ -296,23 +296,24 @@ class gamification_goal(osv.Model): end_date = field_date_name and goal.end_date or False subqueries.setdefault((start_date, end_date), {}).update({goal.id:safe_eval(definition.batch_user_expression, {'user': goal.user_id})}) + # the global query should be split by time periods (especially for recurrent goals) for (start_date, end_date), query_goals in subqueries.items(): subquery_domain = list(general_domain) subquery_domain.append((field_name, 'in', list(set(query_goals.values())))) if start_date: subquery_domain.append((field_date_name, '>=', start_date)) if end_date: - subquery_domain.append((field_date_name, '>=', end_date)) + subquery_domain.append((field_date_name, '<=', end_date)) if field_name == 'id': + # grouping on id does not work and is similar to search anyway user_ids = obj.search(cr, uid, subquery_domain, context=context) user_values = [{'id': user_id, 'id_count': 1} for user_id in user_ids] else: user_values = obj.read_group(cr, uid, subquery_domain, fields=[field_name], groupby=[field_name], context=context) - + # user_values has format of read_group: [{'partner_id': 42, 'partner_id_count': 3},...] for goal in [g for g in goals if g.id in query_goals.keys()]: for user_value in user_values: - # return format of read_group: [{'partner_id': 42, 'partner_id_count': 3},...] queried_value = field_name in user_value and user_value[field_name] or False if isinstance(queried_value, tuple) and len(queried_value) == 2 and isinstance(queried_value[0], (int, long)): queried_value = queried_value[0]