diff --git a/addons/gamification/models/res_users.py b/addons/gamification/models/res_users.py index f556dcc514ad8a9b3ca6d98debad21a5adcadd13..6a188f2003ae081207d686e6532d3df35359dc68 100644 --- a/addons/gamification/models/res_users.py +++ b/addons/gamification/models/res_users.py @@ -8,6 +8,7 @@ class Users(models.Model): _inherit = 'res.users' karma = fields.Integer('Karma', default=0) + karma_position = fields.Integer('Karma position', compute="_compute_karma_position", store=False) badge_ids = fields.One2many('gamification.badge.user', 'user_id', string='Badges', copy=False) gold_badge = fields.Integer('Gold badges count', compute="_get_user_badge_level") silver_badge = fields.Integer('Silver badges count', compute="_get_user_badge_level") @@ -15,6 +16,29 @@ class Users(models.Model): rank_id = fields.Many2one('gamification.karma.rank', 'Rank', index=False) next_rank_id = fields.Many2one('gamification.karma.rank', 'Next Rank', index=False) + @api.depends('karma') + def _compute_karma_position(self): + where_query = self._where_calc([]) + self._apply_ir_rules(where_query, 'read') + from_clause, where_clause, where_clause_params = where_query.get_sql() + + query = """ + SELECT sub.id, sub.karma_position + FROM ( + SELECT id, row_number() OVER (ORDER BY res_users.karma DESC) AS karma_position + FROM {from_clause} + WHERE {where_clause} + ) sub + WHERE sub.id IN %s + """.format(from_clause=from_clause, where_clause=where_clause) + + self.env.cr.execute(query, where_clause_params + [tuple(self.ids)]) + + position_map = {item['id']: item['karma_position'] for item in self.env.cr.dictfetchall()} + + for user in self: + user.karma_position = position_map.get(user.id, 0) + @api.multi @api.depends('badge_ids') def _get_user_badge_level(self): diff --git a/addons/website_profile/controllers/main.py b/addons/website_profile/controllers/main.py index b29ba2077fbe92c41c4634368a86370794630042..de56318e7c6e9452a333bccb58305111eb9f147c 100644 --- a/addons/website_profile/controllers/main.py +++ b/addons/website_profile/controllers/main.py @@ -6,6 +6,7 @@ import werkzeug import werkzeug.exceptions import werkzeug.urls import werkzeug.wrappers +import math from odoo import http, modules, tools from odoo.http import request @@ -13,8 +14,9 @@ from odoo.osv import expression class WebsiteProfile(http.Controller): - PAGER_MAX_PAGE = 5 - + _users_per_page = 30 + _pager_max_pages = 5 + # Profile # --------------------------------------------------- @@ -198,11 +200,12 @@ class WebsiteProfile(http.Controller): # All Users Page # --------------------------------------------------- - def _prepare_all_users_values(self, user, position): + def _prepare_all_users_values(self, user): return { - 'position': position, + 'position': user.karma_position, 'id': user.id, 'name': user.name, + 'company_name': user.company_id.name, 'rank': user.rank_id.name, 'karma': user.karma, 'badge_count': len(user.badge_ids), @@ -214,26 +217,22 @@ class WebsiteProfile(http.Controller): User = request.env['res.users'] dom = [('karma', '>', 1), ('website_published', '=', True)] - # Get the Top 3 users - top3_users = User.sudo().search(dom, limit=3, order='karma DESC') - top3_user_values = [self._prepare_all_users_values(user, position+1) for position, user in enumerate(top3_users)] + # Searches + search_term = searches.get('search') + if search_term: + dom = expression.AND([['|', ('name', 'ilike', search_term), ('company_id.name', 'ilike', search_term)], dom]) - # Get the other users - if top3_users: - dom += [('id', 'not in', top3_users.ids)] - step = 30 user_count = User.sudo().search_count(dom) - pager = request.website.pager(url="/profile/users", total=user_count, page=page, step=step, scope=step) - - if searches.get('user'): - dom += [('name', 'ilike', searches.get('user'))] + page_count = math.ceil(user_count / self._users_per_page) + pager = request.website.pager(url="/profile/users", total=user_count, page=page, step=self._users_per_page, + scope=page_count if page_count < self._pager_max_pages else self._pager_max_pages) - users = User.sudo().search(dom, limit=step, offset=pager['offset'], order='karma DESC') + users = User.sudo().search(dom, limit=self._users_per_page, offset=pager['offset'], order='karma DESC') + user_values = [self._prepare_all_users_values(user) for user in users] - user_values = [self._prepare_all_users_values(user, position + 4 + ((page-1) * step)) for position, user in enumerate(users)] values = { - 'top3_users': top3_user_values, - 'users': user_values, + 'top3_users': user_values[:3] if not search_term and page == 1 else None, + 'users': user_values[3:] if not search_term and page == 1 else user_values, 'pager': pager } return request.render("website_profile.users_page_main", values) diff --git a/addons/website_profile/static/src/scss/website_profile.scss b/addons/website_profile/static/src/scss/website_profile.scss index 224b46b1c8494aaa3a590549b11c579807d7aa0b..a20b1ea2eef27a9d52da33d0ceadac1236fa76f3 100644 --- a/addons/website_profile/static/src/scss/website_profile.scss +++ b/addons/website_profile/static/src/scss/website_profile.scss @@ -118,11 +118,54 @@ $owprofile-tabs-height: 37px; } // All Users Page +.o_wprofile_all_users_nav { + margin: auto; + background: linear-gradient(90deg, #875A7B 20%, #62495B 80%) !important; + a { + color: #FFFFFF; + } + nav { + .breadcrumb-item::before { + font-weight: bold; + color: #FFFFFF; + opacity: 0.8; + } + .breadcrumb-item { + a { + font-weight: bold; + color: #FFFFFF; + opacity: 0.8; + transition: opacity linear .3s; + } + &.active { + a { + opacity: 1.0; + } + } + } + ol { + background-color: transparent; + } + } +} + .o_wprofile_all_users_header { @include media-breakpoint-up(sm) { min-height: 200px; margin-bottom: -60px; } + margin: auto; + background: linear-gradient(90deg, #875A7B 20%, #62495B 80%) !important; + > div:first-child { + margin: auto; + width: 100%; + max-width: 1140px; + padding: 32px 32px 0px 32px; + color: white; + top: 48px; + padding-top: 0px; + height: 250px; + } } .o_wprofile_top3_card_footer div { diff --git a/addons/website_profile/views/website_profile.xml b/addons/website_profile/views/website_profile.xml index fc9e6aae11371099157e6ef5e2a61c1cb96dbd1e..b115d553e8af22dc5c44b2723a4e355f4a26c845 100644 --- a/addons/website_profile/views/website_profile.xml +++ b/addons/website_profile/views/website_profile.xml @@ -392,6 +392,40 @@ </template> <template id="users_page_header" name="Users Page Header"> + <div class="o_wprofile_all_users_nav"> + <div class="container"> + <div class="row align-items-center justify-content-between"> + <!-- nav --> + <nav aria-label="breadcrumb" class="col-md-8 col-xs-12"> + <ol class="breadcrumb"> + <li class="breadcrumb-item"> + <a t-att-href="home_url or '/'">Home</a> + </li> + <li t-att-class="'breadcrumb-item active'"> + <a href="#">Users</a> + </li> + </ol> + </nav> + <div class="col-md-4 col-xs-12 d-flex flex-row align-items-center"> + <!-- karma / profile --> + <a t-if="not is_public_user" t-att-href="'/profile/user/%s' % user_id.id" class="font-weight-bold mr-3"> + <i class="fa fa-diamond" /> <t t-esc="user_id.karma"/> + </a> + <!-- search --> + <form t-attf-action="/profile/users" role="search" method="get"> + <div class="input-group"> + <input type="text" class="form-control" name="search" placeholder="Search in Users" t-att-value="search"/> + <span class="input-group-append"> + <button class="btn btn-primary" type="submit" aria-label="Search" title="Search"> + <i class="fa fa-search"></i> + </button> + </span> + </div> + </form> + </div> + </div> + </div> + </div> <div class="o_wprofile_all_users_header o_wprofile_gradient text-white"> <div class="container"> <h1 class="py-5">All Users</h1> diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py index 26533550f2d3fface8e2c4d1dda8fa0d7bd1e3a0..c876881497bbad7ad8a1f7dd4ab866fabec98459 100644 --- a/addons/website_slides/controllers/main.py +++ b/addons/website_slides/controllers/main.py @@ -20,9 +20,9 @@ _logger = logging.getLogger(__name__) class WebsiteSlides(WebsiteProfile): - SLIDES_PER_PAGE = 12 - SLIDES_PER_ASIDE = 20 - SLIDES_PER_CATEGORY = 4 + _slides_per_page = 12 + _slides_per_aside = 20 + _slides_per_category = 4 _channel_order_by_criterion = { 'vote': 'total_votes desc', 'view': 'total_views desc', @@ -73,8 +73,8 @@ class WebsiteSlides(WebsiteProfile): if slide.channel_id.channel_type == 'documentation': related_domain = expression.AND([base_domain, [('category_id', '=', slide.category_id.id)]]) - most_viewed_slides = request.env['slide.slide'].search(base_domain, limit=self.SLIDES_PER_ASIDE, order='total_views desc') - related_slides = request.env['slide.slide'].search(related_domain, limit=self.SLIDES_PER_ASIDE) + most_viewed_slides = request.env['slide.slide'].search(base_domain, limit=self._slides_per_aside, order='total_views desc') + related_slides = request.env['slide.slide'].search(related_domain, limit=self._slides_per_aside) category_data = [] uncategorized_slides = request.env['slide.slide'] else: @@ -348,10 +348,10 @@ class WebsiteSlides(WebsiteProfile): pager_args['sorting'] = actual_sorting slide_count = request.env['slide.slide'].sudo().search_count(domain) - page_count = math.ceil(slide_count / self.SLIDES_PER_PAGE) + page_count = math.ceil(slide_count / self._slides_per_page) pager = request.website.pager(url=pager_url, total=slide_count, page=page, - step=self.SLIDES_PER_PAGE, url_args=pager_args, - scope=page_count if page_count < self.PAGER_MAX_PAGE else self.PAGER_MAX_PAGE) + step=self._slides_per_page, url_args=pager_args, + scope=page_count if page_count < self._pager_max_pages else self._pager_max_pages) values = { 'channel': channel, @@ -397,7 +397,7 @@ class WebsiteSlides(WebsiteProfile): values['category_data'] = channel._get_categorized_slides( domain, order, force_void=True, - limit=self.SLIDES_PER_CATEGORY if channel.channel_type == 'documentation' else False, + limit=self._slides_per_category if channel.channel_type == 'documentation' else False, offset=pager['offset']) values['channel_progress'] = self._get_channel_progress(channel, include_quiz=True) diff --git a/addons/website_slides_survey/controllers/slides.py b/addons/website_slides_survey/controllers/slides.py index b65b3c3333b12723852361881961b53023056d16..9396de502b8da4e7348e07575734c2f48f2efa0b 100644 --- a/addons/website_slides_survey/controllers/slides.py +++ b/addons/website_slides_survey/controllers/slides.py @@ -60,8 +60,8 @@ class WebsiteSlides(WebsiteSlides): # All Users Page # --------------------------------------------------- - def _prepare_all_users_values(self, user, position): - result = super(WebsiteSlides, self)._prepare_all_users_values(user, position) + def _prepare_all_users_values(self, user): + result = super(WebsiteSlides, self)._prepare_all_users_values(user) result.update({ 'certification_count': len(self._get_user_certificates(user)) })