From 4d41e36a9193cb1c14b8cfcd32105f98bba04057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 9 Apr 2014 18:50:59 +0200 Subject: [PATCH] [IMP] website_forum: cleaning before merging - cleaned models, removing unnecessary fields + removed history feature of posts + removed unnecessary override of mail.message and ir_http + renamed some fields (like badges -> badge_ids to be more coherent with openerp naming) - updated views accordingly - cleaned demo data to lessen the diff bzr revid: tde@openerp.com-20140409165059-36zc06f0to3q4qfu --- addons/website_forum/__openerp__.py | 1 - addons/website_forum/controllers/main.py | 80 ++-- .../website_forum/data/forum_badges_data.xml | 42 +- addons/website_forum/data/forum_data.xml | 50 +-- addons/website_forum/data/forum_demo.xml | 368 +----------------- .../data/question_improvement.yml | 16 - addons/website_forum/models/__init__.py | 20 - addons/website_forum/models/forum.py | 348 ++++++----------- addons/website_forum/models/gamification.py | 22 +- addons/website_forum/models/ir_http.py | 18 - .../security/ir.model.access.csv | 3 - .../static/src/js/website_forum.editor.js | 2 +- addons/website_forum/views/website_forum.xml | 28 +- 13 files changed, 224 insertions(+), 774 deletions(-) delete mode 100644 addons/website_forum/data/question_improvement.yml delete mode 100644 addons/website_forum/models/ir_http.py diff --git a/addons/website_forum/__openerp__.py b/addons/website_forum/__openerp__.py index 8b33c11995b..6085e850c60 100644 --- a/addons/website_forum/__openerp__.py +++ b/addons/website_forum/__openerp__.py @@ -46,7 +46,6 @@ Ask questions, get answers, no distractions ], 'demo': [ 'data/forum_demo.xml', - 'data/question_improvement.yml', ], 'css': ['static/src/css/website_forum.css'], 'installable': True, diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py index 403d54dc6d1..cb502fc2e3e 100644 --- a/addons/website_forum/controllers/main.py +++ b/addons/website_forum/controllers/main.py @@ -1,23 +1,4 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2013-Today OpenERP SA (). -# -# 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 werkzeug.urls import simplejson @@ -38,7 +19,8 @@ from openerp.addons.web.controllers.main import login_redirect controllers = controllers() -class website_forum(http.Controller): + +class WebsiteForum(http.Controller): @http.route(['/forum'], type='http', auth="public", website=True, multilang=True) def forum(self, **searches): @@ -46,38 +28,35 @@ class website_forum(http.Controller): Forum = request.registry['website.forum'] obj_ids = Forum.search(cr, uid, [], context=context) forums = Forum.browse(cr, uid, obj_ids, context=context) - return request.website.render("website_forum.forum_index", { 'forums': forums }) + return request.website.render("website_forum.forum_index", {'forums': forums}) - @http.route('/forum/add_forum', type='http', auth="user", multilang=True, website=True) - def add_forum(self, forum_name="New Forum", **kwargs): + @http.route('/forum/new', type='http', auth="user", multilang=True, website=True) + def forum_create(self, forum_name="New Forum", **kwargs): forum_id = request.registry['website.forum'].create(request.cr, request.uid, { 'name': forum_name, }, context=request.context) - return request.redirect("/forum/%s" % forum_id) + return request.redirect("/forum/%s" % slug(forum_id)) - @http.route(['/forum/', + @http.route(['/forum/', '/forum//page/', '/forum//tag//questions' - ], type='http', auth="public", website=True, multilang=True) - + ], type='http', auth="public", website=True, multilang=True) def questions(self, forum, tag='', page=1, filters='', sorting='', **searches): cr, uid, context = request.cr, request.uid, request.context Forum = request.registry['website.forum.post'] user = request.registry['res.users'].browse(cr, uid, uid, context=context) - domain = [('forum_id', '=', forum.id), ('parent_id', '=', False)] + order = "id desc" - search = searches.get('search',False) - if search: - domain += ['|', - ('name', 'ilike', search), - ('content', 'ilike', search)] + domain = [('forum_id', '=', forum.id), ('parent_id', '=', False)] + if searches.get('search'): + domain += ['|', ('name', 'ilike', searches['search']), ('content', 'ilike', searches['search'])] #filter questions for tag. if tag: if not filters: filters = 'tag' - domain += [ ('tags', '=', tag.id) ] + domain += [('tag_ids', 'in', tag.id)] if not filters: filters = 'all' @@ -147,17 +126,17 @@ class website_forum(http.Controller): cr, uid, context = request.cr, request.uid, request.context #maintain total views on post. - Statistics = request.registry['website.forum.post.statistics'] - post_obj = request.registry['website.forum.post'] - if request.session.uid: - view_ids = Statistics.search(cr, uid, [('user_id', '=', request.session.uid), ('post_id', '=', question.id)], context=context) - if not view_ids: - Statistics.create(cr, SUPERUSER_ID, {'user_id': request.session.uid, 'post_id': question.id }, context=context) - else: - request.session[request.session_id] = request.session.get(request.session_id, []) - if not (question.id in request.session[request.session_id]): - request.session[request.session_id].append(question.id) - post_obj._set_view_count(cr, SUPERUSER_ID, [question.id], 'views', 1, {}, context=context) + # Statistics = request.registry['website.forum.post.statistics'] + # post_obj = request.registry['website.forum.post'] + # if request.session.uid: + # view_ids = Statistics.search(cr, uid, [('user_id', '=', request.session.uid), ('post_id', '=', question.id)], context=context) + # if not view_ids: + # Statistics.create(cr, SUPERUSER_ID, {'user_id': request.session.uid, 'post_id': question.id }, context=context) + # else: + # request.session[request.session_id] = request.session.get(request.session_id, []) + # if not (question.id in request.session[request.session_id]): + # request.session[request.session_id].append(question.id) + # post_obj._set_view_count(cr, SUPERUSER_ID, [question.id], 'views', 1, {}, context=context) #Check that user have answered question or not. answer_done = False @@ -324,7 +303,7 @@ class website_forum(http.Controller): 'forum_id': forum.id, 'name': question.get('question_name'), 'content': question.get('content'), - 'tags' : question_tags, + 'tag_idss' : question_tags, 'state': 'active', 'active': True, }, context=create_context) @@ -408,7 +387,7 @@ class website_forum(http.Controller): else: new_tag = Tag.create(cr, uid, {'name' : tag,'forum_id' : forum.id}, context=context) question_tags.append(new_tag) - vals.update({'tags': [(6, 0, question_tags)], 'name': post.get('question_name')}) + vals.update({'tag_ids': [(6, 0, question_tags)], 'name': post.get('question_name')}) post_id = post.get('answer_id') if post.get('answer_id') else post.get('question_id') new_question_id = request.registry['website.forum.post'].write( cr, uid, [int(post_id)], vals, context=context) @@ -462,10 +441,10 @@ class website_forum(http.Controller): User = request.registry['res.users'] step = 30 - tag_count = User.search(cr, uid, [('forum','=',True)], count=True, context=context) + tag_count = User.search(cr, uid, [('karma', '>', 1)], count=True, context=context) pager = request.website.pager(url="/forum/users", total=tag_count, page=page, step=step, scope=30) - obj_ids = User.search(cr, uid, [('forum','=',True)], limit=step, offset=pager['offset'], context=context) + obj_ids = User.search(cr, uid, [('karma', '>', 1)], limit=step, offset=pager['offset'], context=context) users = User.browse(cr, uid, obj_ids, context=context) searches['users'] = 'True' @@ -484,8 +463,7 @@ class website_forum(http.Controller): if not request.session.uid: return {'error': 'anonymous_user'} cr, uid, context, post_id = request.cr, request.uid, request.context, int(post.get('post_id')) - Vote = request.registry['website.forum.post.vote'] - return Vote.vote(cr, uid, post_id, post.get('vote'), context) + return request.registry['website.forum.post'].vote(cr, uid, [post_id], post.get('vote'), context) @http.route('/forum/post_delete', type='json', auth="user", multilang=True, methods=['POST'], website=True) def delete_answer(self, **kwarg): diff --git a/addons/website_forum/data/forum_badges_data.xml b/addons/website_forum/data/forum_badges_data.xml index a595fd8ec3f..5882fb21af6 100644 --- a/addons/website_forum/data/forum_badges_data.xml +++ b/addons/website_forum/data/forum_badges_data.xml @@ -46,7 +46,7 @@ gold - + Cleanup @@ -67,11 +67,11 @@ forum - + Commentator @@ -178,7 +178,7 @@ gold - + Editor @@ -199,11 +199,11 @@ forum - + Enlightened @@ -217,7 +217,7 @@ count boolean - [('user_id','=',user.id), ('vote_count', '>=', 3), ('correct', '=', True)] + [('user_id','=',user.id), ('vote_count', '>=', 3), ('is_correct', '=', True)] higher @@ -294,8 +294,8 @@ result = get_counter(cr, uid, context=context) res = 1 Post = self.pool['website.forum.post'] Tag = self.pool['website.forum.tag'] - for tag in Tag.search(cr, uid, [], context=context): - post_count = Post.search_count(cr, uid , [('tags', '=', tag), ('user_id', '=', object.user_id.id)], context=context) + for tag_id in Tag.search(cr, uid, [], context=context): + post_count = Post.search_count(cr, uid , [('tag_ids', 'in', tag_id), ('user_id', '=', object.user_id.id)], context=context) if post_count >= 10: res += 1 return res @@ -540,7 +540,7 @@ result = count_favorites(cr, uid, context=context) count boolean - [('user_id','=',user.id), ('parent_id', '!=', False), ('vote_count', '>=', 15), ('correct', '=', True)] + [('user_id','=',user.id), ('parent_id', '!=', False), ('vote_count', '>=', 15), ('is_correct', '=', True)] higher @@ -710,7 +710,7 @@ result = get_posts(cr, uid, context=context) bronze - + Organizer @@ -731,11 +731,11 @@ result = get_posts(cr, uid, context=context) forum - + Peer Pressure @@ -860,7 +860,7 @@ result = get_count(cr, uid, context=context) count boolean - [('user_id','=',user.id), ('parent_id', '=', False), ('correct', '=', True)] + [('user_id','=',user.id), ('parent_id', '=', False), ('is_correct', '=', True)] higher @@ -965,7 +965,7 @@ result = count_favorites(cr, uid, context=context) silver - + Associate Editor @@ -986,11 +986,11 @@ result = count_favorites(cr, uid, context=context) forum - + Student diff --git a/addons/website_forum/data/forum_data.xml b/addons/website_forum/data/forum_data.xml index 0e765e0eec5..af9a8738b20 100644 --- a/addons/website_forum/data/forum_data.xml +++ b/addons/website_forum/data/forum_data.xml @@ -28,33 +28,39 @@ - - - Asked a question + + + New Answer website.forum.post - - Asked a question + + New Answer - - - Answered a question - website.forum.post - - Answered a question - - - - Question edited - website.forum.post - - Question edited - - - Answer edited + Answer Edited + website.forum.post + + Answer Edited + + + + New Question + website.forum.post + + New Answer + + + Question Edited + website.forum.post + + Answer Edited + + + + New Answer website.forum.post - Answer edited + + parent_id diff --git a/addons/website_forum/data/forum_demo.xml b/addons/website_forum/data/forum_demo.xml index 7431b26c6fa..98c871e9bc5 100644 --- a/addons/website_forum/data/forum_demo.xml +++ b/addons/website_forum/data/forum_demo.xml @@ -2,218 +2,53 @@ - + Contract - - e-mail - - - - - Csv - - - - Action - - + Alert - - - POS - - - - - Menu - - - - - one2many - - - - - offline - - - - + ecommerce - - xmlRPC - + - - Stock - - - - - update - - - - - + - How to configure alerts for employee contract expiration. + How to configure alerts for employee contract expiration 5 - + - - How to get translated state through browse ? - - Hello everybody, - -I use a XML-RPC to access to invoices, I want to get the states of invoices, but always I get paid instead of PayƩ (French) - 4 - - - - - - Restrain the user from confirming the Purchase requisition - - 122 - Can anybody tell me how to restrict the user from confirming the purchase requisition? In my case when a user is creating a purchase requisition than the user after saving it is able to send it to the supplier rather I want the user to just generate the purchase requisition and let the manager do the remaining works like sending the purchase requisition to the supplier and than receiving the goods. Please help me out. Thanks in advance. - - - - - - Offline installing for add-ons - 32 - - How can I install web based addons without Internet connections (I'm using OpenERP over LAN)? - -P.S. - -AFAIK current version (7.x) supports web interface while the desktop clients became deprecated. -BTW, I left OpenERP since ver. 6.x to use PostBooks instead but I recently decided to use OpenERP once again after recent new features. - - - - - CMS replacement for ERP and eCommerce 23 - I use Wordpress as a CMS and eCommerce platform. The developing in Wordpress is too easy and solid but it missing ERP feature (there is single plugin to integrate with Frontaccounting) so I wonder: + I use Wordpress as a CMS and eCommerce platform. The developing in Wordpress is quite easy and solid but it missing ERP feature (there is single plugin to integrate with Frontaccounting) so I wonder: Can I use OpenERP as a replacement CMS of Wordpress + eCommerce plugin? In simple words does OpenERP became CMS+ERP platform? - + - - - Register payment using XMLRPC - 15 - - Hi there, - -I have been trying to register an invoice payment through OpenERP. I have been able to manually create and approve the invoice, the voucher and its line - -I'm currently creating the voucher using this information: - - - - - - Create one field on two modules - 12 - - Hello, - -I shall like creating a field "x" on an order form ( stock.picking.form ) and to reveal it also on the delivery slip ( stock.picking.form ). - -Thank you in advance - - - - - - access rights to one2many field - 1 - Now i create new group , assign user and access right as READ & CREATE to object stock.picking.ads but nothing is reflected , iam able to delete and write which should not happen. Very Strange!!! - - - - - - - how to import csv into customer database - - 5 - hi, how to import csv into customer database? Thanks - - - - - - send mails not receiving properly - 4 - Hi, The options for sending mails have been enabled in openerp. - There are options to send the invoice,sales order, - quotations etc by the email.But the issue is even after the button 'Send By Email' is clicked, - the email is not received to the recipients .Those emails are stored in the Archives under the Messaging window.How to configure incoming and outgoing mails in openerp - - - - - - - How to refresh weight of stock move lines after product weight update? - 56 - - - - - - - Update new module v7.0 Ubuntu 12.04 - 87 - - - - - - - Can view top menu In openerp 7.0. (black taskbar at top of window???) - 45 - - - - - - - - - - - - Just for posterity so other can see. Here are the steps to set automatic alerts on any contract.. i.e. HR Employee, or Fleet for example. I will use fleet as an example. @@ -227,200 +62,27 @@ Thank you in advance - - - Hello everybody, - I use a XML-RPC to access to invoices, I want to get the states of invoices, but always I get paid instead of PayƩ (French) - I use administrator to connect to the databse, he has as lang = 'fr_FR' - def _get_invoice_states(self, cr, uid, ids, field_name, args, context=None): - if not context : - context = {} - user = self.pool.get('res.users').read(cr, uid, uid, ['lang','tz']) - context.update({'lang' : str(user.get('lang',u'fr_FR'))}) - context.update({'tz' : str(user.get('tz',u'GMT'))}) - context.update({'uid' : uid}) - result = {} - for invoice in self.browse(cr, uid, ids, context=context): - res = _('Name : ') + (invoice.number or '') - res += _('Etat : ') + (invoice.state or '') - - - - True - - - - - - Yes you could download the module from internet on another - computer and unzip the file on the ERP server. - Then you have to activate the module, see the tutorial on acespritechblog.wordpress.com (sorry I cannot post the full link) - - - - - - OpenERP v8 (next release) provides a web module and an e-commerce module: www.openerp.com/website_cms The CMS editor in OpernERP web is nice but I prefer drupal for customization and there is a drupal module for OpenERP. I think WP is better than OpenERP web too. - - - - - - - - no need to inherit account.voucher. after creating the account.voucher record, you just add this in your XMLRPC script. - - self.sock.execute(self.dbname, self.uid, self.pwd, 'account.voucher', - 'button_proforma_voucher', voucher_id, {}) - - voucher_id should be the ID of the created voucher. - - - True - - - - - - - I had the same issue and in my case I needed to remove the field "move_id" from account.voucher and adding the field "move_line_id" to account.voucher.line, have you tried that? - - move_line_id should match the ID of the account.move.line whose "move_id" field matches the "move_id" field of the invoice you created - - I also set 'type'='cr' for account.voucher.line - - After that, executing workflow('account.voucher', 'proforma_voucher', voucher_id) worked ok, - - Hope this helps! - - - - - - - - - Step 1: First make sure the CRM module is installed. If it isnt then you can click on the CRM module in the applications view. - - Step 2: Go to Settings -> Configuration -> General Settings and check the "Allow users to import data from CSV files" checkbox - - Step 3: Go to Sales -> Customers then switch to the List view by clicking the List view button in the upper right corner - - Step 4: Click on the "Import" link next to the red Create button - - Step 5: Click the "Choose File" button and find your csv file to import - - Step 6: Match the fields from the csv file to the fields in the drop down menus. - - Step 7: Click the "Validate" button to see if any errors occurred. Correct any errors on the csv file, save it, then refresh the file by clicking the refresh button next to the "Choose File" button - - Step 8: Click "Validate" again. If there are still errors, then repeat step 7, otherwise click the "Import" button. Then youre done - - - - - - - - - - Hello, - Email outgoing server can be configured in: Settings >> General Settings >> Email >> Outgoing mail server. - SMTP Server: Your SMTP server address - Connection Security: SSL or none - Username: Your E-Mail user name - Password: Your E-Mail password - - - - - - - - - also settings-> update moduel list? can find this anywhere?? - - - - - - - - - Give your admin user the technical features right and you will be able to see more options in the settings menu. (use a refresh) - - - True + - - + 1 - - - - - -1 - - - - - - -1 - - - - - - 1 - - - - - - 1 - - 1 - - - - 1 - - - - - - -1 - - - - - - 1 - - - - - - 1 - - diff --git a/addons/website_forum/data/question_improvement.yml b/addons/website_forum/data/question_improvement.yml deleted file mode 100644 index 95ce436737a..00000000000 --- a/addons/website_forum/data/question_improvement.yml +++ /dev/null @@ -1,16 +0,0 @@ -- - Admin User Edit a Question asked by demo user to improve typo -- - !python {model: website.forum.post}: | - self.write(cr, ref('base.user_root'), [ref('website_forum.question_5')],{ - 'name': 'CMS Replacement For ERP and ECommerce ?', - }) -- - Make mail notifications as read for assigned badges. -- - !python {model: mail.message}: | - notificaton_obj = self.pool.get('mail.notification') - bedge_user_ids = self.pool.get("gamification.badge.user").search(cr, uid, [('user_id','in', [ref('base.user_demo'),ref('base.user_root')]),('badge_id', 'in', [ref('badge_5')])], context=context) - message_ids = self.search(cr, uid, [('res_id', 'not in', bedge_user_ids),('model', '=', 'gamification.badge.user')], context=context) - notify_ids = notificaton_obj.search(cr, uid, [('message_id', 'in', message_ids)], context=context) - notificaton_obj.write(cr, uid, notify_ids ,{ 'read': True }) diff --git a/addons/website_forum/models/__init__.py b/addons/website_forum/models/__init__.py index 1a9084cd096..a3a421abac8 100644 --- a/addons/website_forum/models/__init__.py +++ b/addons/website_forum/models/__init__.py @@ -1,24 +1,4 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2013-Today OpenERP SA (). -# -# 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 gamification import forum -import ir_http diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py index 9d8cd2db5f7..73663298bd5 100644 --- a/addons/website_forum/models/forum.py +++ b/addons/website_forum/models/forum.py @@ -1,71 +1,35 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2013-Today OpenERP SA (). -# -# 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 re import openerp -from openerp import tools + from openerp import SUPERUSER_ID from openerp.osv import osv, fields from openerp.tools.translate import _ -from datetime import date, datetime -from openerp.addons.website.models.website import slug -#TODO: Do we need a forum object like blog object ? Need to check with BE team class Forum(osv.Model): _name = 'website.forum' _description = 'Forums' _inherit = ['mail.thread', 'website.seo.metadata'] - def _get_right_column(self, cr, uid, ids, field_name, arg, context): - res = {} - for forum in self.browse(cr, uid, ids, context=context): - res[forum.id] = """
-
-

About This Forum

-
-
- This community is for professionals and enthusiasts of our - products and services.
- Read Guidelines -
-
""" % slug(forum) - return res - _columns = { 'name': fields.char('Name', required=True, translate=True), 'faq': fields.html('Guidelines'), - 'right_column':fields.function(_get_right_column, string="Right Column", type='html', store=True), + 'description': fields.text('Description'), } - def _get_default_faq(self, cr, uid, context={}): + + def _get_default_faq(self, cr, uid, context=None): fname = openerp.modules.get_module_resource('website_forum', 'data', 'forum_default_faq.html') with open(fname, 'r') as f: return f.read() return False _defaults = { + 'description': 'This community is for professionals and enthusiasts of our products and services.', 'faq': _get_default_faq, } + class Post(osv.Model): _name = 'website.forum.post' _description = "Question" @@ -94,40 +58,11 @@ class Post(osv.Model): res[post.id] = len(post.child_ids) return res - def _get_view_count(self, cr, uid, ids, field_name=False, arg={}, context=None): - res = dict.fromkeys(ids, 0) - for post in self.browse(cr, uid, ids, context=context): - res[post.id] = post.views + 1 - return res - - def _set_view_count(self, cr, uid, ids, name, value, arg, context=None): - if isinstance(ids, (int, long)): - ids = [ids] - for rec in self.browse(cr, uid, ids, context=context): - views = rec.views + value - cr.execute('UPDATE website_forum_post SET views=%s WHERE id=%s;',(views, rec.id)) - return True - - def _get_views(self, cr, uid, ids, context=None): - result = {} - for statistic in self.pool['website.forum.post.statistics'].browse(cr, uid, ids, context=context): - result[statistic.post_id.id] = True - return result.keys() - def _get_user_vote(self, cr, uid, ids, field_name, arg, context): res = dict.fromkeys(ids, 0) - # Note: read_group is not returning all fields which we passed in list.when it will work uncomment this code and remove remaining code - #Vote = self.pool['website.forum.post.vote'] - #data = Vote.read_group(cr, uid, [('post_id','in', ids), ('user_id', '=', uid)], [ "post_id", "vote"], groupby=["post_id"], context=context) - #for rec in data: - # res[rec[post_id][0]] = rec['vote'] - for post in self.browse(cr, uid, ids, context=context): - for vote in post.vote_ids: - if vote.user_id.id == uid: - if vote.vote == '1': - res[post.id] = 1 - elif vote.vote == '-1': - res[post.id] = -1 + vote_ids = self.pool['website.forum.post.vote'].search(cr, uid, [('post_id', 'in', ids), ('user_id', '=', uid)], context=context) + for vote in self.pool['website.forum.post.vote'].browse(cr, uid, vote_ids, context=context): + res[vote.post_id.id] = vote.vote return res def _get_user_favourite(self, cr, uid, ids, field_name, arg, context): @@ -143,37 +78,25 @@ class Post(osv.Model): 'forum_id': fields.many2one('website.forum', 'Forum', required=True), 'content': fields.text('Content'), 'create_date': fields.datetime('Asked on', select=True, readonly=True), - 'user_id': fields.many2one('res.users', 'Asked by', select=True, readonly=True ), - 'write_date': fields.datetime('Update on', select=True, readonly=True ), + 'user_id': fields.many2one('res.users', 'Asked by', select=True, readonly=True), + 'write_date': fields.datetime('Update on', select=True, readonly=True), 'write_uid': fields.many2one('res.users', 'Update by', select=True, readonly=True), - - 'tags': fields.many2many('website.forum.tag', 'forum_tag_rel', 'forum_id', 'forum_tag_id', 'Tag'), - 'vote_ids':fields.one2many('website.forum.post.vote', 'post_id', 'Votes'), - 'user_vote':fields.function(_get_user_vote, string="My Vote", type='integer'), - + 'tag_ids': fields.many2many('website.forum.tag', 'forum_tag_rel', 'forum_id', 'forum_tag_id', 'Tag'), + 'vote_ids': fields.one2many('website.forum.post.vote', 'post_id', 'Votes'), + 'user_vote': fields.function(_get_user_vote, string="My Vote", type='integer'), 'favourite_ids': fields.many2many('res.users', 'forum_favourite_rel', 'forum_id', 'user_id', 'Favourite'), - 'user_favourite':fields.function(_get_user_favourite, string="My Favourite", type='boolean'), - - 'state': fields.selection([('active', 'Active'), ('close', 'Close'),('offensive', 'Offensive')], 'Status'), + 'user_favourite': fields.function(_get_user_favourite, string="My Favourite", type='boolean'), + 'state': fields.selection([('active', 'Active'), ('close', 'Close'), ('offensive', 'Offensive')], 'Status'), 'active': fields.boolean('Active'), - - 'views_ids': fields.one2many('website.forum.post.statistics', 'post_id', 'Views'), - 'views':fields.function(_get_view_count, string="Views", type='integer', - store={ - 'website.forum.post.statistics': (_get_views, [], 10), - } - ), - + 'views': fields.integer('Number of Views'), 'parent_id': fields.many2one('website.forum.post', 'Question', ondelete='cascade'), 'child_ids': fields.one2many('website.forum.post', 'parent_id', 'Answers'), - 'child_count':fields.function(_get_child_count, string="Answers", type='integer', + 'child_count': fields.function( + _get_child_count, string="Answers", type='integer', store={ - 'website.forum.post': (lambda self, cr, uid, ids, c={}: ids, [], 10), + 'website.forum.post': (lambda self, cr, uid, ids, c={}: ids, ['parent_id', 'child_ids'], 10), } ), - - 'history_ids': fields.one2many('blog.post.history', 'post_id', 'History', help='Last post modifications'), - # TODO FIXME: when website_mail/mail_thread.py inheritance work -> this field won't be necessary 'website_message_ids': fields.one2many( 'mail.message', 'res_id', domain=lambda self: [ @@ -182,86 +105,86 @@ class Post(osv.Model): string='Post Messages', help="Comments on forum post", ), - - 'vote_count':fields.function(_get_vote_count, string="Votes", type='integer', + 'vote_count': fields.function( + _get_vote_count, string="Votes", type='integer', store={ 'website.forum.post': (lambda self, cr, uid, ids, c={}: ids, ['vote_ids'], 10), 'website.forum.post.vote': (_get_vote, [], 10), } ), - - 'correct': fields.boolean('Correct Answer/ Answer on this question accepted.'), - 'reason_id': fields.many2one('website.forum.post.reason', 'Reason'), + 'is_correct': fields.boolean('Valid Answer', help='Correct Answer/ Answer on this question accepted.'), + 'closed_reason_id': fields.many2one('website.forum.post.reason', 'Reason'), 'closed_by': fields.many2one('res.users', 'Closed by'), 'closed_date': fields.datetime('Closed on', readonly=True), } + _defaults = { 'state': 'active', 'vote_count': 0, 'active': True, } - def create_history(self, cr, uid, ids, context=None): - hist_obj = self.pool['website.forum.post.history'] - for post in self.browse(cr, uid, ids, context=context): - history_count = hist_obj.search(cr, uid, [('post_id','=', post.id)], count=True, context=context) - date = datetime.today().strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT) - name = "No.%s Revision" %(history_count+1) if history_count else "initial version" - hist_obj.create(cr, uid, { - 'post_id': post.id, - 'content': post.content, - 'name': '%s - (%s) %s' % (history_count+1, date, name), - 'post_name': post.name, - 'tags': [(6,0, [x.id for x in post.tags])], - 'user_id': post.write_uid and post.write_uid.id or post.user_id.id, - }, context=context) - def create(self, cr, uid, vals, context=None): if context is None: context = {} create_context = dict(context, mail_create_nolog=True) - body, subtype = "Asked a question", "website_forum.mt_question_create" + post_id = super(Post, self).create(cr, uid, vals, context=create_context) + # post message + subtype depending on parent_id if vals.get("parent_id"): - body, subtype = "Answered a question", "website_forum.mt_answer_create" - #Note: because of no name it gives error on slug so set name of question in answer - question = self.browse(cr, uid, vals.get("parent_id"), context=context) - vals['name'] = question.name + name, body, subtype = vals.get('name'), 'New Answer', 'website_forum.mt_answer_new' + else: + name, body, subtype = vals.get('name'), 'Post Created', 'website_forum.mt_question_new' #add 2 karma to user when asks question. self.pool['res.users'].write(cr, SUPERUSER_ID, [vals.get('user_id')], {'karma': 2}, context=context) - post_id = super(Post, self).create(cr, uid, vals, context=create_context) - self.create_history(cr, uid, [post_id], context=context) self.message_post(cr, uid, [post_id], body=_(body), subtype=subtype, context=context) return post_id def write(self, cr, uid, ids, vals, context=None): - super(Post, self).write(cr, uid, ids, vals, context=context) - #NOTE: to avoid message post on write of last comment time - if not vals.get('message_last_post'): - user = self.pool['res.users'].browse(cr, uid ,uid, context=context) - self.create_history(cr, uid, ids, 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: for post in self.browse(cr, uid, ids, context=context): - body, subtype = "Edited question", "website_forum.mt_question_edit" if post.parent_id: - body, subtype = "Edited answer", "website_forum.mt_answer_edit" + body, subtype = 'Answer Edited', 'website_forum.mt_answer_edit' + else: + body, subtype = 'Question Edited', 'website_forum.mt_question_edit' self.message_post(cr, uid, [post.id], body=_(body), subtype=subtype, context=context) - - #update karma of related user when any answer accepted. - value = 0 + # update karma of related user when any answer accepted + if vals.get('correct'): + for post in self.browse(cr, uid, ids, context=context): + value = -15 if vals.get('correct'): value = 15 - elif vals.get('correct') == False: - value = -15 self.pool['res.users'].write(cr, SUPERUSER_ID, [post.user_id.id], {'karma': value}, context=context) - return True + return res + + def vote(self, cr, uid, ids, vote, context=None): + print ids, vote + return True + # try: + # vote = int(vote) + # except: + # return {'error': 'Wrong Vote Value'} + + # if not vote in [-1, 0, 1]: + # return {'error': 'Wrong Vote Value'} + # user = self.pool['res.users'].browse(cr, uid, uid, context=context) + # # must have at least 10 karma to vote + # if (vote == '-1') and (user.karma <= 10): + # return {'error': 'lessthen_10_karma'} + # # user can not vote on own post + # posts = self.pool['website.forum.post'].browse(cr, uid, ids, context=context) + # if any(post.user_id.id == uid for post in posts): + # return {'error': 'own_post'} + + # vote_ids = self.pool['website.forum.post.vote'].search(cr, uid, [('post_id', 'in', post_ids), ('user_id', '=', uid)], context=context) + # if vote_ids: + # self.pool['website.forum.post.vote'].write(cr, uid, vote_ids, {'vote': new_vote}, context=context) + # else: + # self.popol['website.forum.post.vote'].create(cr, uid, {'post_id': post_id, 'vote': vote}, context=context) + # post.refresh() + # return {'vote_count': post.vote_count} -class PostStatistics(osv.Model): - _name = "website.forum.post.statistics" - _description = "Post Statistics" - _columns = { - 'name': fields.char('Post Reason'), - 'post_id': fields.many2one('website.forum.post', 'Post', ondelete='cascade'), - 'user_id': fields.many2one('res.users', 'Created by'), - } class PostReason(osv.Model): _name = "website.forum.post.reason" @@ -270,6 +193,7 @@ class PostReason(osv.Model): 'name': fields.char('Post Reason'), } + class Users(osv.Model): _inherit = 'res.users' @@ -285,47 +209,26 @@ class Users(osv.Model): } return result - def _set_user_karma(self, cr, uid, ids, name, value, arg, context=None): - if isinstance(ids, (int, long)): - ids = [ids] - for rec in self.browse(cr, uid, ids, context=context): - karma = rec.karma + value - cr.execute('UPDATE res_users SET karma=%s WHERE id=%s;',(karma, rec.id)) - return True - - def _get_user_karma(self, cr, uid, ids, field_name, arg, context=None): - result = {} - for user in self.browse(cr, uid, ids, context=context): - result[user.id] = user.karma - return result - _columns = { 'create_date': fields.datetime('Create Date', select=True, readonly=True), - 'forum': fields.boolean('Is Forum Member'), - 'karma': fields.function(_get_user_karma, fnct_inv=_set_user_karma, type='integer', string="Karma", store=True), - - 'badges': fields.one2many('gamification.badge.user', 'user_id', 'Badges'), - 'gold_badge':fields.function(_get_user_badge_level, string="Number of gold badges", type='integer', multi='badge_level'), - 'silver_badge':fields.function(_get_user_badge_level, string="Number of silver badges", type='integer', multi='badge_level'), - 'bronze_badge':fields.function(_get_user_badge_level, string="Number of bronze badges", type='integer', multi='badge_level'), + # 'is_forum': fields.boolean('Is Forum Member'), + 'karma': fields.integer('Karma'), + 'badge_ids': fields.one2many('gamification.badge.user', 'user_id', 'Badges'), + 'gold_badge': fields.function(_get_user_badge_level, string="Number of gold badges", type='integer', multi='badge_level'), + 'silver_badge': fields.function(_get_user_badge_level, string="Number of silver badges", type='integer', multi='badge_level'), + 'bronze_badge': fields.function(_get_user_badge_level, string="Number of bronze badges", type='integer', multi='badge_level'), } + _defaults = { - 'forum': False, - 'karma': 1, + # 'is_forum': False, + 'karma': 0, } -class PostHistory(osv.Model): - _name = 'website.forum.post.history' - _description = 'Post History' - _inherit = ['website.seo.metadata'] - _columns = { - 'name': fields.char('History Title'), - 'post_id': fields.many2one('website.forum.post', 'Post', ondelete='cascade'), - 'post_name': fields.char('Post Name'), - 'content': fields.text('Content'), - 'user_id': fields.many2one('res.users', 'Created by', select=True, readonly=True), - 'tags': fields.many2many('website.forum.tag', 'post_tag_rel', 'post_id', 'post_tag_id', 'Tag'), - } + def add_karma(self, cr, uid, ids, karma, context=None): + for user in self.browse(cr, uid, ids, context=context): + self.write(cr, uid, [user.id], {'karma': user.karma + karma}, context=context) + return True + class Vote(osv.Model): _name = 'website.forum.post.vote' @@ -333,61 +236,35 @@ class Vote(osv.Model): _columns = { 'post_id': fields.many2one('website.forum.post', 'Post', ondelete='cascade', required=True), 'user_id': fields.many2one('res.users', 'User'), - 'vote': fields.selection([('1', '1'),('-1', '-1'),('0','0')], 'Vote'), + 'vote': fields.selection([('1', '1'), ('-1', '-1'), ('0', '0')], 'Vote', required=True), 'create_date': fields.datetime('Create Date', select=True, readonly=True), } _defaults = { 'user_id': lambda self, cr, uid, ctx: uid, - 'vote': lambda *args: 1 + '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.user_id.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) - Post = self.pool["website.forum.post"] - record = Post.browse(cr, uid, vals.get('post_id'), context=context) - #Add 10 karma when user get up vote and subtract 10 karma when gets down vote. - value = 10 if vals.get('vote') == '1' else -10 - self.pool['res.users'].write(cr, SUPERUSER_ID, [record.user_id.id], {'karma': value}, context=context) - body = "voted %s %s" % ('answer' if record.parent_id else 'question','up' if vals.get('vote')==1 else 'down') - Post.message_post(cr, uid, [record.id], body=_(body), context=context) + self.update_karma(cr, uid, [vote_id], new_vote=vals.get('vote', '1'), context=context) + # body = "voted %s %s" % ('answer' if record.parent_id else 'question','up' if vals.get('vote')==1 else 'down') + # Post.message_post(cr, uid, [record.id], body=_(body), context=context) return vote_id - def vote(self, cr, uid, post_id, vote, context=None): - assert int(vote) in (1, -1, 0), "vote can be -1 or 1, nothing else" - #user can not vote on own post. - post = self.pool['website.forum.post'].browse(cr, uid, post_id, context=context) - if post.user_id.id == uid: - return {'error': 'own_post'} - user = self.pool['res.users'].browse(cr, uid, uid, context=None) - if (vote == '-1') and (user.karma <= 10): - return {'error': 'lessthen_10_karma'} - vote_ids = self.search(cr, uid, [('post_id', '=', post_id), ('user_id','=',uid)], context=context) - if vote_ids: - #when user will click again on vote it should set it 0. - record = self.browse(cr,uid, vote_ids[0], context=context) - new_vote = '0' if record.vote in ['1','-1'] else vote - #update karma when user changed vote. - if record.vote == '1' or new_vote == '-1': - value = -10 - elif record.vote == '-1' or new_vote == '1': - value = 10 - self.pool['res.users'].write(cr, SUPERUSER_ID, [record.post_id.user_id.id], {'karma': value}, context=context) - self.write(cr, uid, vote_ids, { - 'vote': new_vote - }, context=context) - else: - self.create(cr, uid, { - 'post_id': post_id, - 'vote': vote, - }, context=context) - post.refresh() - return {'vote_count': post.vote_count} + def write(self, cr, uid, ids, values, context=None): + res = super(Vote, self).write(cr, uid, ids, values, context=context) + if 'vote' in values: + for vote in self.browse(cr, uid, ids, context=context): + self.update_karma(cr, uid, ids, new_vote=values['vote'], old_vote=vote.vote, context=context) + return res -class MailMessage(osv.Model): - _inherit = 'mail.message' - _columns = { - 'create_uid': fields.many2one('res.users', 'Created by', readonly=True ), - } class Tags(osv.Model): _name = "website.forum.tag" @@ -395,25 +272,20 @@ class Tags(osv.Model): _inherit = ['website.seo.metadata'] def _get_posts_count(self, cr, uid, ids, field_name, arg, context=None): - result = {} - Post = self.pool['website.forum.post'] - for tag in ids: - result[tag] = Post.search_count(cr, uid , [('tags', '=', tag)], context=context) - return result + return dict((tag_id, self.pool['website.forum.post'].search_count(cr, uid, [('tag_ids', 'in', tag_id)], context=context)) for tag_id in ids) - def _get_post(self, cr, uid, ids, context=None): - result = {} - for post in self.pool['website.forum.post'].browse(cr, uid, ids, context=context): - for tag in post.tags: - result[tag.id] = True - return result.keys() + def _get_tag_from_post(self, cr, uid, ids, context=None): + return list(set( + [tag.id for post in self.pool['website.forum.post'].browse(cr, SUPERUSER_ID, ids, context=context) for tag in post.tag_ids] + )) _columns = { 'name': fields.char('Name', size=64, required=True), 'forum_id': fields.many2one('website.forum', 'Forum', required=True), - 'posts_count': fields.function(_get_posts_count, type='integer', string="# of Posts", + 'posts_count': fields.function( + _get_posts_count, type='integer', string="# of Posts", store={ - 'website.forum.post': (_get_post, ['tags'], 10), + 'website.forum.post': (_get_tag_from_post, ['tag_ids'], 10), } ), - } + } diff --git a/addons/website_forum/models/gamification.py b/addons/website_forum/models/gamification.py index ecf281bb75a..c7474022f08 100644 --- a/addons/website_forum/models/gamification.py +++ b/addons/website_forum/models/gamification.py @@ -1,29 +1,11 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2013-Today OpenERP SA (). -# -# 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 copy -import openerp + from openerp.osv import osv, fields from openerp.tools.translate import _ + class gamification_challenge(osv.Model): _inherit = 'gamification.challenge' diff --git a/addons/website_forum/models/ir_http.py b/addons/website_forum/models/ir_http.py deleted file mode 100644 index 76974e01c4f..00000000000 --- a/addons/website_forum/models/ir_http.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- -import traceback -import werkzeug -import openerp -from openerp.http import request -from openerp.osv import orm - -class ir_http(orm.AbstractModel): - _inherit = 'ir.http' - - def _handle_exception(self, exception=None, code=500): - #At this time it gives error when user's email address is not configured instead of raise exception so redirect user to update profile. - #when website will handle exception then remove this code. - if code == 500 and isinstance(exception, openerp.osv.orm.except_orm): - if exception[1] == "Unable to send email, please configure the sender's email address or alias.": - forum = request.httprequest.path.strip('/forum').split('/') - return werkzeug.utils.redirect("/forum/%s/edit/profile/%s" % (forum[0],request.uid)) - return super(ir_http, self)._handle_exception(exception, code=code) diff --git a/addons/website_forum/security/ir.model.access.csv b/addons/website_forum/security/ir.model.access.csv index 398c58f12d0..0482778ad15 100644 --- a/addons/website_forum/security/ir.model.access.csv +++ b/addons/website_forum/security/ir.model.access.csv @@ -1,11 +1,8 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink - access_website_forum,website.forum,model_website_forum,,1,0,0,0 access_website_forum_post,website.forum.post,model_website_forum_post,,1,1,1,0 -access_website_forum_post_history,website.forum.post.history,model_website_forum_post_history,,1,0,1,0 access_website_forum_post_vote,website.forum.post.vote,model_website_forum_post_vote,,1,1,1,0 access_website_forum_post_reason,website.forum.post.reason,model_website_forum_post_reason,,1,0,0,0 -access_website_forum_post_statistics,website.forum.post.statistics,model_website_forum_post_statistics,,1,0,0,0 access_website_forum_tag,website.forum.tag,model_website_forum_tag,,1,0,1,0 access_gamification_badge_user,gamification.badge.user,gamification.model_gamification_badge_user,,1,0,0,0 access_gamification_badge,gamification_badge,gamification.model_gamification_badge,,1,0,0,0 diff --git a/addons/website_forum/static/src/js/website_forum.editor.js b/addons/website_forum/static/src/js/website_forum.editor.js index 4c4887f6b38..5ccf971761a 100644 --- a/addons/website_forum/static/src/js/website_forum.editor.js +++ b/addons/website_forum/static/src/js/website_forum.editor.js @@ -21,7 +21,7 @@ window_title: _t("New Forum"), input: "Forum Name", }).then(function (forum_name) { - website.form('/forum/add_forum', 'POST', { + website.form('/forum/new', 'POST', { forum_name: forum_name }); }); diff --git a/addons/website_forum/views/website_forum.xml b/addons/website_forum/views/website_forum.xml index ce0bd921ca4..d7ba9acfb21 100644 --- a/addons/website_forum/views/website_forum.xml +++ b/addons/website_forum/views/website_forum.xml @@ -28,7 +28,7 @@
- +
Answers
Answer
@@ -52,7 +52,7 @@ with votes
- + @@ -83,7 +83,7 @@ @@ -129,7 +129,15 @@