Skip to content

Commit

Permalink
[IMP] website_forum:enable searching across all forums
Browse files Browse the repository at this point in the history
Purpose
=======
Make it possible for users to have an overview and search in all forums.
This includes searching for posts of other users, much like /slides/all.

Specifications
=============
- add routes for `/forum/all`
- change templates in `website_forum` to show posts even if `forum` is
not specified to shows results and search in all forums

Task-2676848
Based on odoo#79372

Co-authored by: Fabio Barbero <[email protected]>

Part-of: odoo#129123
  • Loading branch information
lm4649 committed Sep 11, 2023
1 parent 0e992e3 commit 4bb00c2
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 86 deletions.
47 changes: 33 additions & 14 deletions addons/website_forum/controllers/website_forum.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,53 +73,67 @@ def sitemap_forum(env, rule, qs):
if not qs or qs.lower() in loc:
yield {'loc': loc}

def _get_forum_port_search_options(self, forum=None, tag=None, filters=None, my=None, **post):
def _get_forum_post_search_options(self, forum=None, tag=None, filters=None, my=None, create_uid=False, include_answers=False, **post):
return {
'allowFuzzy': not post.get('noFuzzy'),
'create_uid': create_uid,
'displayDescription': False,
'displayDetail': False,
'displayExtraDetail': False,
'displayExtraLink': False,
'displayImage': False,
'allowFuzzy': not post.get('noFuzzy'),
'forum': str(forum.id) if forum else None,
'tag': str(tag.id) if tag else None,
'filters': filters,
'forum': str(forum.id) if forum else None,
'include_answers': include_answers,
'my': my,
'tag': str(tag.id) if tag else None,
}

@http.route(['/forum/<model("forum.forum"):forum>',
@http.route(['/forum/all',
'/forum/all/page/<int:page>',
'/forum/<model("forum.forum"):forum>',
'/forum/<model("forum.forum"):forum>/page/<int:page>',
'''/forum/<model("forum.forum"):forum>/tag/<model("forum.tag"):tag>/questions''',
'''/forum/<model("forum.forum"):forum>/tag/<model("forum.tag"):tag>/questions/page/<int:page>''',
], type='http', auth="public", website=True, sitemap=sitemap_forum)
def questions(self, forum, tag=None, page=1, filters='all', my=None, sorting=None, search='', **post):
def questions(self, forum=None, tag=None, page=1, filters='all', my=None, sorting=None, search='', create_uid=False, include_answers=False, **post):
Post = request.env['forum.post']

author = request.env['res.users'].browse(int(create_uid))

if author == request.env.user:
my = 'mine'
if sorting:
# check that sorting is valid
# retro-compatibily for V8 and google links
# retro-compatibility for V8 and google links
try:
sorting = werkzeug.urls.url_unquote_plus(sorting)
Post._generate_order_by(sorting, None)
except (UserError, ValueError):
sorting = False

if not sorting:
sorting = forum.default_order
sorting = forum.default_order if forum else 'last_activity_date desc'

options = self._get_forum_port_search_options(
options = self._get_forum_post_search_options(
forum=forum,
tag=tag,
filters=filters,
my=my,
create_uid=author.id,
include_answers=include_answers,
**post
)
question_count, details, fuzzy_search_term = request.website._search_with_fuzzy(
"forum_posts_only", search, limit=page * self._post_per_page, order=sorting, options=options)
question_ids = details[0].get('results', Post)
question_ids = question_ids[(page - 1) * self._post_per_page:page * self._post_per_page]

url = f"/forum/{slug(forum)}{f'/tag/{slug(tag)}/questions' if tag else ''}"
if not forum:
url = '/forum/all'
else:
url = f"/forum/{slug(forum)}{f'/tag/{slug(tag)}/questions' if tag else ''}"

url_args = {'sorting': sorting}

for name, value in zip(['filters', 'search', 'my'], [filters, search, my]):
Expand All @@ -132,7 +146,7 @@ def questions(self, forum, tag=None, page=1, filters='all', my=None, sorting=Non

values = self._prepare_user_values(forum=forum, searches=post)
values.update({
'main_object': tag or forum,
'author': author,
'edit_in_backend': True,
'question_ids': question_ids,
'question_count': question_count,
Expand All @@ -145,6 +159,10 @@ def questions(self, forum, tag=None, page=1, filters='all', my=None, sorting=Non
'search': fuzzy_search_term or search,
'original_search': fuzzy_search_term and search,
})

if forum or tag:
values['main_object'] = tag or forum

return request.render("website_forum.forum_index", values)

@http.route(['''/forum/<model("forum.forum"):forum>/faq'''], type='http', auth="public", website=True, sitemap=True)
Expand Down Expand Up @@ -602,9 +620,10 @@ def open_partner(self, forum, partner_id=0, **post):
# Profile
# -----------------------------------

@http.route(['/forum/<model("forum.forum"):forum>/user/<int:user_id>'], type='http', auth="public", website=True)
def view_user_forum_profile(self, forum, user_id, forum_origin='/forum', **post):
return request.redirect(f'/profile/user/{user_id}?forum_id={forum.id}&forum_origin={forum_origin}')
@http.route(['/forum/user/<int:user_id>'], type='http', auth="public", website=True)
def view_user_forum_profile(self, user_id, forum_id='', forum_origin='/forum', **post):
forum_origin_query = f'?forum_origin={forum_origin}&forum_id={forum_id}' if forum_id else ''
return request.redirect(f'/profile/user/{user_id}{forum_origin_query}')

def _prepare_user_profile_values(self, user, **post):
values = super(WebsiteForum, self)._prepare_user_profile_values(user, **post)
Expand Down
31 changes: 19 additions & 12 deletions addons/website_forum/models/forum_post.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from odoo import api, fields, models, tools, _
from odoo.addons.http_routing.models.ir_http import slug, unslug
from odoo.exceptions import UserError, ValidationError, AccessError
from odoo.osv import expression
from odoo.tools import sql

_logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -804,30 +805,36 @@ def _search_get_detail(self, website, order, options):
}

domain = website.website_domain()
domain += [('parent_id', '=', False), ('state', '=', 'active'), ('can_view', '=', True)]
domain = expression.AND([domain, [('state', '=', 'active'), ('can_view', '=', True)]])
include_answers = options.get('include_answers', False)
if not include_answers:
domain = expression.AND([domain, [('parent_id', '=', False)]])
forum = options.get('forum')
if forum:
domain += [('forum_id', '=', unslug(forum)[1])]
domain = expression.AND([domain, [('forum_id', '=', unslug(forum)[1])]])
tags = options.get('tag')
if tags:
domain += [('tag_ids', 'in', [unslug(tag)[1] for tag in tags.split(',')])]
domain = expression.AND([domain, [('tag_ids', 'in', [unslug(tag)[1] for tag in tags.split(',')])]])
filters = options.get('filters')
if filters == 'unanswered':
domain += [('child_ids', '=', False)]
domain = expression.AND([domain, [('child_ids', '=', False)]])
elif filters == 'solved':
domain += [('has_validated_answer', '=', True)]
domain = expression.AND([domain, [('has_validated_answer', '=', True)]])
elif filters == 'unsolved':
domain += [('has_validated_answer', '=', False)]
domain = expression.AND([domain, [('has_validated_answer', '=', False)]])
user = self.env.user
my = options.get('my')
if my == 'mine':
domain += [('create_uid', '=', user.id)]
elif my == 'followed':
domain += [('message_partner_ids', '=', user.partner_id.id)]
create_uid = user.id if my == 'mine' else options.get('create_uid')
if create_uid:
domain = expression.AND([domain, [('create_uid', '=', create_uid)]])
if my == 'followed':
domain = expression.AND([domain, [('message_partner_ids', '=', user.partner_id.id)]])
elif my == 'tagged':
domain += [('tag_ids.message_partner_ids', '=', user.partner_id.id)]
domain = expression.AND([domain, [('tag_ids.message_partner_ids', '=', user.partner_id.id)]])
elif my == 'favourites':
domain += [('favourite_ids', '=', user.id)]
domain = expression.AND([domain, [('favourite_ids', '=', user.id)]])
elif my == 'upvoted':
domain = expression.AND([domain, [('vote_ids.user_id', '=', user.id)]])

# 'sorting' from the form's "Order by" overrides order during auto-completion
order = options.get('sorting', order)
Expand Down
13 changes: 7 additions & 6 deletions addons/website_forum/views/forum_forum_templates.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,17 @@
<th class="o_wforum_table_title"></th>
<th class="o_wforum_table_posters"></th>
<th class="o_wforum_table_replies small fw-normal text-center">
<a class="text-muted" t-attf-href="?#{ keep_query('search', 'filters', sorting='child_count asc' if sorting == 'child_count desc' else 'child_count desc') }">
Replies <i t-attf-class="fa fa-caret-#{ 'down' if sorting == 'child_count desc' else 'up' } #{ 'd-none ' if not sorting.startswith('child_count') else '' }"></i>
<a class="text-muted" t-attf-href="?#{ keep_query('search', 'filters', 'my', 'create_uid', sorting='child_count asc' if sorting == 'child_count desc' else 'child_count desc') }">
Replies <i t-attf-class="fa fa-caret-#{ 'down' if sorting == 'child_count desc' else 'up' } #{ not sorting.startswith('child_count') and 'd-none ' }"></i>
</a>
</th>
<th class="o_wforum_table_views small fw-normal text-center">
<a class="text-muted" t-attf-href="?#{ keep_query('search', 'filters', sorting='views asc' if sorting == 'views desc' else 'views desc') }">
Views <i t-attf-class="fa fa-caret-#{'down' if sorting == 'views desc' else 'up'} #{ 'd-none ' if not sorting.startswith('views') else '' }"></i>
<a class="text-muted" t-attf-href="?#{ keep_query('search', 'filters', 'my', 'create_uid', sorting='views asc' if sorting == 'views desc' else 'views desc') }">
Views <i t-attf-class="fa fa-caret-#{'down' if sorting == 'views desc' else 'up'} #{ not sorting.startswith('views') and 'd-none ' }"></i>
</a>
</th>
<th class="o_wforum_table_activity small fw-normal text-center">
<a class="text-muted" t-attf-href="?#{ keep_query('search', 'filters', sorting='last_activity_date asc' if sorting == 'last_activity_date desc' else 'last_activity_date desc') }">
<a class="text-muted" t-attf-href="?#{ keep_query('search', 'filters', 'my', 'create_uid', sorting='last_activity_date asc' if sorting == 'last_activity_date desc' else 'last_activity_date desc') }">
Activity <i t-attf-class="fa fa-caret-#{ 'down' if sorting == 'last_activity_date desc' else 'up'} #{ 'd-none ' if not sorting.startswith('last_activity') else '' }"></i>
</a>
</th>
Expand All @@ -45,7 +45,8 @@
</table>
<t t-if="question_count == 0 or original_search" t-call="website_forum.no_results_message">
<t t-set="record_name_plural">posts</t>
<t t-set="go_back_url" t-valuef="/forum/#{ slug(forum) }/"/>
<t t-set="_forum_slug" t-value="slug(forum) if forum else 'all'"/>
<t t-set="go_back_url" t-valuef="/forum/#{_forum_slug}/"/>
</t>
<t t-call="website.pager"/>
</t>
Expand Down
Loading

0 comments on commit 4bb00c2

Please sign in to comment.