From 87a1b547178db9531df7f81bd89516f1d08f6320 Mon Sep 17 00:00:00 2001
From: "Okan SUMER (osu)"
Date: Wed, 18 Mar 2020 15:28:12 +0000
Subject: [PATCH 1/5] [IMP] gamification: improve tree and form view
This commit improve the tree and form view of gamification.karma.rank
and correct a bug on auto generated email when a user pass to the
next rank.
- Add a stat button in form view and column in tree view to know
how many users have the current rank
- Split Description and Motivational in 2 pages
- Hide the line that mention the next rank the user can get when
there is no more rank to get in email templates
- Add a menu to access badges tree view
Part of https://github.com/odoo/odoo/pull/46634
task-2201708
---
.../models/gamification_karma_rank.py | 12 ++++++-
.../views/gamification_karma_rank_views.xml | 33 +++++++++++++++----
addons/website_forum/views/forum.xml | 1 +
3 files changed, 39 insertions(+), 7 deletions(-)
diff --git a/addons/gamification/models/gamification_karma_rank.py b/addons/gamification/models/gamification_karma_rank.py
index a324b323773..8e987076bfe 100644
--- a/addons/gamification/models/gamification_karma_rank.py
+++ b/addons/gamification/models/gamification_karma_rank.py
@@ -3,6 +3,7 @@
from odoo import api, fields, models
from odoo.tools.translate import html_translate
+
class KarmaRank(models.Model):
_name = 'gamification.karma.rank'
_description = 'Rank based on karma'
@@ -14,14 +15,23 @@ class KarmaRank(models.Model):
description_motivational = fields.Html(
string='Motivational', translate=html_translate, sanitize_attributes=False,
help="Motivational phrase to reach this rank")
- karma_min = fields.Integer(string='Required Karma', required=True, default=1,
+ karma_min = fields.Integer(
+ string='Required Karma', required=True, default=1,
help='Minimum karma needed to reach this rank')
user_ids = fields.One2many('res.users', 'rank_id', string='Users', help="Users having this rank")
+ rank_users_count = fields.Integer("# Users", compute="_compute_rank_users_count")
_sql_constraints = [
('karma_min_check', "CHECK( karma_min > 0 )", 'The required karma has to be above 0.')
]
+ @api.depends('user_ids')
+ def _compute_rank_users_count(self):
+ requests_data = self.env['res.users'].read_group([('rank_id', '!=', False)], ['rank_id'], ['rank_id'])
+ requests_mapped_data = dict((data['rank_id'][0], data['rank_id_count']) for data in requests_data)
+ for rank in self:
+ rank.rank_users_count = requests_mapped_data.get(rank.id, 0)
+
@api.model_create_multi
def create(self, values_list):
res = super(KarmaRank, self).create(values_list)
diff --git a/addons/gamification/views/gamification_karma_rank_views.xml b/addons/gamification/views/gamification_karma_rank_views.xml
index fc0205794b5..bee0f28f40e 100644
--- a/addons/gamification/views/gamification_karma_rank_views.xml
+++ b/addons/gamification/views/gamification_karma_rank_views.xml
@@ -1,6 +1,14 @@
+
+
+ Users
+ res.users
+ tree,form
+ [('rank_id', '=', active_id)]
+
+
Ranks
@@ -36,6 +44,7 @@
+
@@ -46,7 +55,16 @@
diff --git a/addons/website_forum/views/forum.xml b/addons/website_forum/views/forum.xml
index c01640354c9..45c592fc831 100644
--- a/addons/website_forum/views/forum.xml
+++ b/addons/website_forum/views/forum.xml
@@ -311,5 +311,6 @@
+
From bfb70b6b9c0afceaa145d5053ea68e1d1e08d21e Mon Sep 17 00:00:00 2001
From: "Okan SUMER (osu)"
Date: Wed, 18 Mar 2020 15:55:18 +0000
Subject: [PATCH 2/5] [IMP] website_forum: rename fields, labels, texts,...
This commit rename every "Question" references by "Post"
to make it appropriate for both forum's type (Question and Discussion)
It renames some other fields/labels to be shorter or with a
capital letter at the start.
Update demo data to add a title to answers
Part of https://github.com/odoo/odoo/pull/46634
task-2201708
---
addons/website_forum/data/forum_data.xml | 26 +++++++-------
addons/website_forum/data/forum_demo.xml | 2 ++
addons/website_forum/models/forum.py | 28 +++++++--------
.../static/src/js/tours/website_forum.js | 6 ++--
.../tests/tours/website_forum_question.js | 2 +-
addons/website_forum/views/forum.xml | 6 ++--
addons/website_forum/views/website_forum.xml | 36 +++++++++----------
.../views/website_slides_templates.xml | 2 +-
8 files changed, 55 insertions(+), 53 deletions(-)
diff --git a/addons/website_forum/data/forum_data.xml b/addons/website_forum/data/forum_data.xml
index bda7eb83e21..3000a08e72e 100644
--- a/addons/website_forum/data/forum_data.xml
+++ b/addons/website_forum/data/forum_data.xml
@@ -77,55 +77,55 @@
- duplicate post
+ Duplicate postbasic
- off-topic or not relevant
+ Off-topic or not relevantbasic
- too subjective and argumentative
+ Too subjective and argumentativebasic
- not a real post
+ Not a real postbasic
- not relevant or out dated
+ Not relevant or out datedbasic
- contains offensive or malicious remarks
+ Contains offensive or malicious remarksbasic
- spam or advertising
+ Spam or advertisingbasic
- too localized
+ Too localizedbasic
- insulting and offensive language
+ Insulting and offensive languageoffensive
- violent language
+ Violent languageoffensive
- inappropriate and unacceptable statements
+ Inappropriate and unacceptable statementsoffensive
- threatening language
+ Threatening languageoffensive
- racist and hate speech
+ Racist and hate speechoffensive
diff --git a/addons/website_forum/data/forum_demo.xml b/addons/website_forum/data/forum_demo.xml
index 2884cab5c76..041ef4c8831 100644
--- a/addons/website_forum/data/forum_demo.xml
+++ b/addons/website_forum/data/forum_demo.xml
@@ -48,6 +48,7 @@ In simple words does Odoo became CMS+ERP platform?
]]>
+ Re: How to configure alerts for employee contract expirationJust 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.
Step 1. As a user who has access rights to Technical Features, go to Settings --> Automated Actions. Create A new Automated Action. For the Related Document Model choose.. Contract information on a vehicle (you can also type in the actual model name.. fleet.vehicle.log.contract ) . Set the trigger date to ... Contract Expiration Date. The Next Field (Delay After Trigger Date) is a bit ridiculous. Who wants to be reminded of a contract expiration AFTER the fact? The field should say Days Before Date to Fire Action and the number should be converted to a negative. IMHO. Any way... to get a workable solution you must enter in the number in the negative. So for instance like me if you want to be warned 35 days BEFORE the expiration... put in Delay After Trigger Date.. the number -35 But the sake of testing, right now just put in -1 for 1 day before. Save the Action.
@@ -59,6 +60,7 @@ In simple words does Odoo became CMS+ERP platform?]]>
+ Re: CMS replacement for ERP and eCommerceOdoo v8 provides a web module and an e-commerce module: www.odoo.com/page/website-builder
The CMS editor in Odoo web is nice but I prefer Drupal for customization and there is a Drupal module for Odoo. I think WP is better than Odoo web too.
diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py
index 55137df5148..4632fa1a897 100644
--- a/addons/website_forum/models/forum.py
+++ b/addons/website_forum/models/forum.py
@@ -30,9 +30,9 @@ class Forum(models.Model):
name = fields.Char('Forum Name', required=True, translate=True)
sequence = fields.Integer('Sequence', default=1)
mode = fields.Selection([
- ('questions', 'Questions'),
- ('discussions', 'Discussions')],
- string='Forum Mode', required=True, default='questions',
+ ('questions', 'Questions (1 answer)'),
+ ('discussions', 'Discussions (multiple answers)')],
+ string='Mode', required=True, default='questions',
help='Questions mode: only one answer allowed\n Discussions mode: multiple answers allowed')
privacy = fields.Selection([
('public', 'Public'),
@@ -84,10 +84,10 @@ class Forum(models.Model):
'of the forum content.')
# posts statistics
post_ids = fields.One2many('forum.post', 'forum_id', string='Posts')
- total_posts = fields.Integer('Post Count', compute='_compute_forum_statistics')
- total_views = fields.Integer('Views Count', compute='_compute_forum_statistics')
- total_answers = fields.Integer('Answers Count', compute='_compute_forum_statistics')
- total_favorites = fields.Integer('Favorites Count', compute='_compute_forum_statistics')
+ total_posts = fields.Integer('Posts', compute='_compute_forum_statistics')
+ total_views = fields.Integer('Views', compute='_compute_forum_statistics')
+ total_answers = fields.Integer('Answers', compute='_compute_forum_statistics')
+ total_favorites = fields.Integer('Favorites', compute='_compute_forum_statistics')
count_posts_waiting_validation = fields.Integer(string="Number of posts waiting for validation", compute='_compute_count_posts_waiting_validation')
count_flagged_posts = fields.Integer(string='Number of flagged posts', compute='_compute_count_flagged_posts')
# karma generation
@@ -220,8 +220,8 @@ class Post(models.Model):
content = fields.Html('Content', strip_style=True)
plain_content = fields.Text('Plain Content', compute='_get_plain_content', store=True)
tag_ids = fields.Many2many('forum.tag', 'forum_tag_rel', 'forum_id', 'forum_tag_id', string='Tags')
- state = fields.Selection([('active', 'Active'), ('pending', 'Waiting Validation'), ('close', 'Close'), ('offensive', 'Offensive'), ('flagged', 'Flagged')], string='Status', default='active')
- views = fields.Integer('Number of Views', default=0)
+ state = fields.Selection([('active', 'Active'), ('pending', 'Waiting Validation'), ('close', 'Closed'), ('offensive', 'Offensive'), ('flagged', 'Flagged')], string='Status', default='active')
+ views = fields.Integer('Views', default=0, readonly=True)
active = fields.Boolean('Active', default=True)
website_message_ids = fields.One2many(domain=lambda self: [('model', '=', self._name), ('message_type', 'in', ['email', 'comment'])])
website_id = fields.Many2one(related='forum_id.website_id', readonly=True)
@@ -229,7 +229,7 @@ class Post(models.Model):
# history
create_date = fields.Datetime('Asked on', index=True, readonly=True)
create_uid = fields.Many2one('res.users', string='Created by', index=True, readonly=True)
- write_date = fields.Datetime('Update on', index=True, readonly=True)
+ write_date = fields.Datetime('Updated on', index=True, readonly=True)
bump_date = fields.Datetime('Bumped on', readonly=True,
help="Technical field allowing to bump a question. Writing on this field will trigger "
"a write on write_date and therefore bump the post. Directly writing on write_date "
@@ -245,14 +245,14 @@ class Post(models.Model):
# favorite
favourite_ids = fields.Many2many('res.users', string='Favourite')
user_favourite = fields.Boolean('Is Favourite', compute='_get_user_favourite')
- favourite_count = fields.Integer('Favorite Count', compute='_get_favorite_count', store=True)
+ favourite_count = fields.Integer('Favorite', compute='_get_favorite_count', store=True)
# hierarchy
is_correct = fields.Boolean('Correct', help='Correct answer or answer accepted')
- parent_id = fields.Many2one('forum.post', string='Question', ondelete='cascade')
+ parent_id = fields.Many2one('forum.post', string='Question', ondelete='cascade', readonly=True)
self_reply = fields.Boolean('Reply to own question', compute='_is_self_reply', store=True)
child_ids = fields.One2many('forum.post', 'parent_id', string='Answers')
- child_count = fields.Integer('Number of answers', compute='_get_child_count', store=True)
+ child_count = fields.Integer('Answers', compute='_get_child_count', store=True)
uid_has_answered = fields.Boolean('Has Answered', compute='_get_uid_has_answered')
has_validated_answer = fields.Boolean('Is answered', compute='_get_has_validated_answer', store=True)
@@ -262,7 +262,7 @@ class Post(models.Model):
# closing
closed_reason_id = fields.Many2one('forum.post.reason', string='Reason')
- closed_uid = fields.Many2one('res.users', string='Closed by', index=True)
+ closed_uid = fields.Many2one('res.users', string='Closed by', index=True, readonly=True)
closed_date = fields.Datetime('Closed on', readonly=True)
# karma calculation and access
diff --git a/addons/website_forum/static/src/js/tours/website_forum.js b/addons/website_forum/static/src/js/tours/website_forum.js
index d3d182701d2..b8bd5c67a11 100644
--- a/addons/website_forum/static/src/js/tours/website_forum.js
+++ b/addons/website_forum/static/src/js/tours/website_forum.js
@@ -11,11 +11,11 @@ odoo.define("website_forum.tour_forum", function (require) {
}, [{
trigger: ".o_forum_ask_btn",
position: "left",
- content: _t("Ask the question in this forum by clicking on the button."),
+ content: _t("Create a new post in this forum by clicking on the button."),
}, {
trigger: "input[name=post_name]",
position: "top",
- content: _t("Give your question title."),
+ content: _t("Give your post title."),
}, {
trigger: ".note-editable p",
extra_trigger: "input[name=post_name]:not(:propValue(\"\"))",
@@ -31,7 +31,7 @@ odoo.define("website_forum.tour_forum", function (require) {
actions.auto("input[id=s2id_autogen2]");
},
}, {
- trigger: "button:contains(\"Post Your Question\")",
+ trigger: "button:contains(\"Post\")",
extra_trigger: "input[id=s2id_autogen2]:not(:propValue(\"Tags\"))",
content: _t("Click to post your question."),
position: "bottom",
diff --git a/addons/website_forum/static/tests/tours/website_forum_question.js b/addons/website_forum/static/tests/tours/website_forum_question.js
index 8457d58640f..b2f549aed83 100644
--- a/addons/website_forum/static/tests/tours/website_forum_question.js
+++ b/addons/website_forum/static/tests/tours/website_forum_question.js
@@ -26,7 +26,7 @@ odoo.define('website_forum.tour_forum_question', function (require) {
}, {
content: "Click to post your question.",
extra_trigger: "#wrap:not(:has(input[id=s2id_autogen2]:propValue('')))",
- trigger: 'button:contains("Post Your Question")',
+ trigger: 'button:contains("Post")',
}, {
content: "This page contain new created question.",
trigger: '#wrap:has(".fa-star")',
diff --git a/addons/website_forum/views/forum.xml b/addons/website_forum/views/forum.xml
index 45c592fc831..aba1aa64c47 100644
--- a/addons/website_forum/views/forum.xml
+++ b/addons/website_forum/views/forum.xml
@@ -225,10 +225,10 @@
-
+
-
+
@@ -257,7 +257,7 @@
tree,form,graph
- {'search_default_questions':1}
+ {'search_default_posts':1}
Create a new forum post
diff --git a/addons/website_forum/views/website_forum.xml b/addons/website_forum/views/website_forum.xml
index 7b142b0cd06..7bf8a313732 100644
--- a/addons/website_forum/views/website_forum.xml
+++ b/addons/website_forum/views/website_forum.xml
@@ -89,8 +89,8 @@
The goal of this site is create a relevant knowledge base that would answer questions related to Odoo.
Therefore questions and answers can be edited like wiki pages by experienced users of this site in order to improve the overall quality of the knowledge base content. Such privileges are granted based on user karma level: you will be able to do the same once your karma gets high enough.
-
If this approach is not for you, please respect the community and use Google+ communities instead.
+
If this approach is not for you, please respect the community.
@@ -503,13 +503,13 @@
-
+
- My Questions
+ My Posts
×
- My Questions
+ My Posts
@@ -581,7 +581,7 @@
My Favourites I'm Following
- My Questions
+ My PostsTags I Follow×
@@ -597,9 +597,9 @@
@@ -700,7 +700,7 @@
in your favouritesin your followed list
- in your questions
+ in your postsmatching "" and
@@ -721,7 +721,7 @@
No favourite questions in this forum (yet). Browse All
-
You have no questions in this forum (yet).
+
You have no posts in this forum (yet).
Amazing! There are no unanswered questions left!
@@ -770,7 +770,7 @@
+ class="form-control form-control-lg" placeholder="A clear, explicit and concise title" title="Title must not be empty"/>
- Good morning to all! Please, can someone help solve solve my tax computation problem in Canada? Thanks!
+ Good morning to all! Please, can someone help solve my tax computation problem in Canada? Thanks!
@@ -830,12 +830,12 @@
-
Use a clear, explicit and concise question title
+
Use a clear, explicit and concise title
How to configure TPS and TVQ's canadian taxes?
- Good morning to all! Please, can someone help solve solve my tax computation problem in Canada? Thanks!
+ Good morning to all! Please, can someone help solve my tax computation problem in Canada? Thanks!
diff --git a/addons/website_slides_forum/views/website_slides_templates.xml b/addons/website_slides_forum/views/website_slides_templates.xml
index ea17a3b88b2..09971c6fe55 100644
--- a/addons/website_slides_forum/views/website_slides_templates.xml
+++ b/addons/website_slides_forum/views/website_slides_templates.xml
@@ -20,7 +20,7 @@
- Ask a question
+ New Post
From b86902040169c612544cd710c6b0025c8b43ddbe Mon Sep 17 00:00:00 2001
From: "Okan SUMER (osu)"
Date: Wed, 18 Mar 2020 16:36:18 +0000
Subject: [PATCH 3/5] [IMP] website_forum: improve tree and form view
This commit add a lot of features and information about forum.forum,
forum.post, forum.tag.
- Correct the forum and post tree view to correctly render the number
of posts, answers, views and favorites
- Add a Status column to post tree view
- Add stat buttons to redirect to the frontend
- Add stat buttons to highlight datas in forum.forum and forum.post
- Make the tree view of forum.tag editable
- Add buttons to change the state of a forum.post in the form view
- Add post close reason menu and views
Part of https://github.com/odoo/odoo/pull/46634
task-2201708
---
addons/website_forum/models/forum.py | 47 ++++++++++++-----
addons/website_forum/views/forum.xml | 79 +++++++++++++++++++++++++---
2 files changed, 106 insertions(+), 20 deletions(-)
diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py
index 4632fa1a897..7468411efeb 100644
--- a/addons/website_forum/models/forum.py
+++ b/addons/website_forum/models/forum.py
@@ -11,6 +11,7 @@ from odoo import api, fields, models, tools, SUPERUSER_ID, _
from odoo.exceptions import UserError, ValidationError, AccessError
from odoo.tools import misc
from odoo.tools.translate import html_translate
+from odoo.addons.http_routing.models.ir_http import slug
_logger = logging.getLogger(__name__)
@@ -132,7 +133,7 @@ class Forum(models.Model):
def _compute_forum_statistics(self):
result = dict((cid, dict(total_posts=0, total_views=0, total_answers=0, total_favorites=0)) for cid in self.ids)
read_group_res = self.env['forum.post'].read_group(
- [('forum_id', 'in', self.ids), ('state', 'in', ('active', 'close'))],
+ [('forum_id', 'in', self.ids), ('state', 'in', ('active', 'close')), ('parent_id', '=', False)],
['forum_id', 'views', 'child_count', 'favourite_count'],
groupby=['forum_id'],
lazy=False)
@@ -141,7 +142,7 @@ class Forum(models.Model):
result[cid]['total_posts'] += res_group.get('__count', 0)
result[cid]['total_views'] += res_group.get('views', 0)
result[cid]['total_answers'] += res_group.get('child_count', 0)
- result[cid]['total_favorites'] += res_group.get('favourite_count', 0)
+ result[cid]['total_favorites'] += 1 if res_group.get('favourite_count', 0) else 0
for record in self:
record.update(result[record.id])
@@ -202,11 +203,21 @@ class Forum(models.Model):
post_tags.insert(0, [6, 0, existing_keep])
return post_tags
+ def _compute_website_url(self):
+ return '/forum/%s' % (slug(self))
+
def get_tags_first_char(self):
""" get set of first letter of forum tags """
tags = self.env['forum.tag'].search([('forum_id', '=', self.id), ('posts_count', '>', 0)])
return sorted(set([tag.name[0].upper() for tag in tags if len(tag.name)]))
+ def go_to_website(self):
+ self.ensure_one()
+ return {
+ 'type': 'ir.actions.act_url',
+ 'target': 'self',
+ 'url': self._compute_website_url(),
+ }
class Post(models.Model):
@@ -249,9 +260,9 @@ class Post(models.Model):
# hierarchy
is_correct = fields.Boolean('Correct', help='Correct answer or answer accepted')
- parent_id = fields.Many2one('forum.post', string='Question', ondelete='cascade', readonly=True)
+ parent_id = fields.Many2one('forum.post', string='Question', ondelete='cascade', readonly=True, index=True)
self_reply = fields.Boolean('Reply to own question', compute='_is_self_reply', store=True)
- child_ids = fields.One2many('forum.post', 'parent_id', string='Answers')
+ child_ids = fields.One2many('forum.post', 'parent_id', string='Post Answers')
child_count = fields.Integer('Answers', compute='_get_child_count', store=True)
uid_has_answered = fields.Boolean('Has Answered', compute='_get_uid_has_answered')
has_validated_answer = fields.Boolean('Is answered', compute='_get_has_validated_answer', store=True)
@@ -364,17 +375,10 @@ class Post(models.Model):
for post in self:
post.self_reply = post.parent_id.create_uid.id == post._uid
- @api.depends('child_ids.create_uid', 'website_message_ids')
+ @api.depends('child_ids')
def _get_child_count(self):
for post in self:
- children = self.search([('id', 'child_of', post.id)])
- children_count = len(children)
- message_count = self.env['mail.message'].search_count([
- ('model', '=', post._name),
- ('message_type', 'in', ['email', 'comment']),
- ('res_id', 'in', children.ids + [post.id]),
- ])
- post.child_count = children_count + message_count
+ post.child_count = len(post.child_ids)
def _get_uid_has_answered(self):
for post in self:
@@ -869,6 +873,21 @@ class Post(models.Model):
return
return super(Post, self)._notify_record_by_inbox(message, recipients_data, msg_vals=msg_vals, **kwargs)
+ def _compute_website_url(self):
+ return '/forum/{forum}/question/{post}{anchor}'.format(
+ forum=slug(self.forum_id),
+ post=slug(self),
+ anchor=self.parent_id and '#answer_%d' % self.id or ''
+ )
+
+ def go_to_website(self):
+ self.ensure_one()
+ return {
+ 'type': 'ir.actions.act_url',
+ 'target': 'self',
+ 'url': self._compute_website_url(),
+ }
+
class PostReason(models.Model):
_name = "forum.post.reason"
@@ -876,7 +895,7 @@ class PostReason(models.Model):
_order = 'name'
name = fields.Char(string='Closing Reason', required=True, translate=True)
- reason_type = fields.Char(string='Reason Type')
+ reason_type = fields.Selection([('basic', 'Basic'), ('offensive', 'Offensive')], string='Reason Type', default='basic')
class Vote(models.Model):
diff --git a/addons/website_forum/views/forum.xml b/addons/website_forum/views/forum.xml
index aba1aa64c47..138c24e9e27 100644
--- a/addons/website_forum/views/forum.xml
+++ b/addons/website_forum/views/forum.xml
@@ -1,6 +1,21 @@
+
+
+ Users favorite posts
+ forum.post
+ tree,form
+ [('forum_id', '=', active_id), ('favourite_count', '>', 0), ('state', 'in', ('active', 'close'))]
+
+
+
+ Posts
+ forum.post
+ tree,form
+ [('forum_id', '=', active_id), ('parent_id', '=', False), ('state', 'in', ('active', 'close'))]
+
+
@@ -32,6 +47,29 @@
@@ -163,6 +202,13 @@