diff --git a/addons/gamification/models/goal.py b/addons/gamification/models/goal.py index 6ab4259cca2..af9a763236d 100644 --- a/addons/gamification/models/goal.py +++ b/addons/gamification/models/goal.py @@ -287,30 +287,33 @@ 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 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)) - - user_values = obj.read_group(cr, uid, subquery_domain, fields=[field_name], groupby=[field_name], context=context) + 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] 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/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.

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/data/badges_answer.xml b/addons/website_forum/data/badges_answer.xml index 8b56a5ac02e..9aed157df21 100644 --- a/addons/website_forum/data/badges_answer.xml +++ b/addons/website_forum/data/badges_answer.xml @@ -4,7 +4,7 @@ - + - + - + - + - + - + - + \ No newline at end of file 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 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/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 diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py index 74f4d9e5393..031ae4b33e1 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', @@ -166,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): @@ -193,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): @@ -231,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), } @@ -240,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 @@ -283,4 +288,5 @@ class Tags(osv.Model): 'forum.post': (_get_tag_from_post, ['tag_ids'], 10), } ), + 'create_uid': fields.many2one('res.users', 'Created by', readonly=True), } diff --git a/addons/website_forum/models/res_users.py b/addons/website_forum/models/res_users.py index 89a23cc2901..58d43a58191 100644 --- a/addons/website_forum/models/res_users.py +++ b/addons/website_forum/models/res_users.py @@ -32,6 +32,16 @@ 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 + + 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