diff options
Diffstat (limited to 'addons/website_profile/controllers/main.py')
| -rw-r--r-- | addons/website_profile/controllers/main.py | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/addons/website_profile/controllers/main.py b/addons/website_profile/controllers/main.py new file mode 100644 index 00000000..6ad68d1b --- /dev/null +++ b/addons/website_profile/controllers/main.py @@ -0,0 +1,324 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import base64 +import werkzeug +import werkzeug.exceptions +import werkzeug.urls +import werkzeug.wrappers +import math + +from dateutil.relativedelta import relativedelta +from operator import itemgetter + +from odoo import fields, http, modules, tools +from odoo.http import request +from odoo.osv import expression + + +class WebsiteProfile(http.Controller): + _users_per_page = 30 + _pager_max_pages = 5 + + # Profile + # --------------------------------------------------- + + def _check_avatar_access(self, user_id, **post): + """ Base condition to see user avatar independently form access rights + is to see published users having karma, meaning they participated to + frontend applications like forum or elearning. """ + try: + user = request.env['res.users'].sudo().browse(user_id).exists() + except: + return False + if user: + return user.website_published and user.karma > 0 + return False + + def _get_default_avatar(self): + img_path = modules.get_module_resource('web', 'static/src/img', 'placeholder.png') + with open(img_path, 'rb') as f: + return base64.b64encode(f.read()) + + def _check_user_profile_access(self, user_id): + user_sudo = request.env['res.users'].sudo().browse(user_id) + # User can access - no matter what - his own profile + if user_sudo.id == request.env.user.id: + return user_sudo + if user_sudo.karma == 0 or not user_sudo.website_published or \ + (user_sudo.id != request.session.uid and request.env.user.karma < request.website.karma_profile_min): + return False + return user_sudo + + def _prepare_user_values(self, **kwargs): + kwargs.pop('edit_translations', None) # avoid nuking edit_translations + values = { + 'user': request.env.user, + 'is_public_user': request.website.is_public_user(), + 'validation_email_sent': request.session.get('validation_email_sent', False), + 'validation_email_done': request.session.get('validation_email_done', False), + } + values.update(kwargs) + return values + + def _prepare_user_profile_parameters(self, **post): + return post + + def _prepare_user_profile_values(self, user, **post): + return { + 'uid': request.env.user.id, + 'user': user, + 'main_object': user, + 'is_profile_page': True, + 'edit_button_url_param': '', + } + + @http.route([ + '/profile/avatar/<int:user_id>', + ], type='http', auth="public", website=True, sitemap=False) + def get_user_profile_avatar(self, user_id, field='image_256', width=0, height=0, crop=False, **post): + if field not in ('image_128', 'image_256'): + return werkzeug.exceptions.Forbidden() + + can_sudo = self._check_avatar_access(user_id, **post) + if can_sudo: + status, headers, image_base64 = request.env['ir.http'].sudo().binary_content( + model='res.users', id=user_id, field=field, + default_mimetype='image/png') + else: + status, headers, image_base64 = request.env['ir.http'].binary_content( + model='res.users', id=user_id, field=field, + default_mimetype='image/png') + if status == 301: + return request.env['ir.http']._response_by_status(status, headers, image_base64) + if status == 304: + return werkzeug.wrappers.Response(status=304) + + if not image_base64: + image_base64 = self._get_default_avatar() + if not (width or height): + width, height = tools.image_guess_size_from_field_name(field) + + image_base64 = tools.image_process(image_base64, size=(int(width), int(height)), crop=crop) + + content = base64.b64decode(image_base64) + headers = http.set_safe_image_headers(headers, content) + response = request.make_response(content, headers) + response.status_code = status + return response + + @http.route(['/profile/user/<int:user_id>'], type='http', auth="public", website=True) + def view_user_profile(self, user_id, **post): + user = self._check_user_profile_access(user_id) + if not user: + return request.render("website_profile.private_profile") + values = self._prepare_user_values(**post) + params = self._prepare_user_profile_parameters(**post) + values.update(self._prepare_user_profile_values(user, **params)) + return request.render("website_profile.user_profile_main", values) + + # Edit Profile + # --------------------------------------------------- + @http.route('/profile/edit', type='http', auth="user", website=True) + def view_user_profile_edition(self, **kwargs): + user_id = int(kwargs.get('user_id', 0)) + countries = request.env['res.country'].search([]) + if user_id and request.env.user.id != user_id and request.env.user._is_admin(): + user = request.env['res.users'].browse(user_id) + values = self._prepare_user_values(searches=kwargs, user=user, is_public_user=False) + else: + values = self._prepare_user_values(searches=kwargs) + values.update({ + 'email_required': kwargs.get('email_required'), + 'countries': countries, + 'url_param': kwargs.get('url_param'), + }) + return request.render("website_profile.user_profile_edit_main", values) + + def _profile_edition_preprocess_values(self, user, **kwargs): + values = { + 'name': kwargs.get('name'), + 'website': kwargs.get('website'), + 'email': kwargs.get('email'), + 'city': kwargs.get('city'), + 'country_id': int(kwargs.get('country')) if kwargs.get('country') else False, + 'website_description': kwargs.get('description'), + } + + if 'clear_image' in kwargs: + values['image_1920'] = False + elif kwargs.get('ufile'): + image = kwargs.get('ufile').read() + values['image_1920'] = base64.b64encode(image) + + if request.uid == user.id: # the controller allows to edit only its own privacy settings; use partner management for other cases + values['website_published'] = kwargs.get('website_published') == 'True' + return values + + @http.route('/profile/user/save', type='http', auth="user", methods=['POST'], website=True) + def save_edited_profile(self, **kwargs): + user_id = int(kwargs.get('user_id', 0)) + if user_id and request.env.user.id != user_id and request.env.user._is_admin(): + user = request.env['res.users'].browse(user_id) + else: + user = request.env.user + values = self._profile_edition_preprocess_values(user, **kwargs) + whitelisted_values = {key: values[key] for key in type(user).SELF_WRITEABLE_FIELDS if key in values} + user.write(whitelisted_values) + if kwargs.get('url_param'): + return werkzeug.utils.redirect("/profile/user/%d?%s" % (user.id, kwargs['url_param'])) + else: + return werkzeug.utils.redirect("/profile/user/%d" % user.id) + + # Ranks and Badges + # --------------------------------------------------- + def _prepare_badges_domain(self, **kwargs): + """ + Hook for other modules to restrict the badges showed on profile page, depending of the context + """ + domain = [('website_published', '=', True)] + if 'badge_category' in kwargs: + domain = expression.AND([[('challenge_ids.challenge_category', '=', kwargs.get('badge_category'))], domain]) + return domain + + def _prepare_ranks_badges_values(self, **kwargs): + ranks = [] + if 'badge_category' not in kwargs: + Rank = request.env['gamification.karma.rank'] + ranks = Rank.sudo().search([], order='karma_min DESC') + + Badge = request.env['gamification.badge'] + badges = Badge.sudo().search(self._prepare_badges_domain(**kwargs)) + badges = badges.sorted("granted_users_count", reverse=True) + values = self._prepare_user_values(searches={'badges': True}) + + values.update({ + 'ranks': ranks, + 'badges': badges, + 'user': request.env.user, + }) + return values + + @http.route('/profile/ranks_badges', type='http', auth="public", website=True, sitemap=True) + def view_ranks_badges(self, **kwargs): + values = self._prepare_ranks_badges_values(**kwargs) + return request.render("website_profile.rank_badge_main", values) + + # All Users Page + # --------------------------------------------------- + def _prepare_all_users_values(self, users): + user_values = [] + for user in users: + user_values.append({ + '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), + 'website_published': user.website_published + }) + return user_values + + @http.route(['/profile/users', + '/profile/users/page/<int:page>'], type='http', auth="public", website=True, sitemap=True) + def view_all_users_page(self, page=1, **kwargs): + User = request.env['res.users'] + dom = [('karma', '>', 1), ('website_published', '=', True)] + + # Searches + search_term = kwargs.get('search') + group_by = kwargs.get('group_by', False) + render_values = { + 'search': search_term, + 'group_by': group_by or 'all', + } + if search_term: + dom = expression.AND([['|', ('name', 'ilike', search_term), ('partner_id.commercial_company_name', 'ilike', search_term)], dom]) + + user_count = User.sudo().search_count(dom) + my_user = request.env.user + current_user_values = False + if user_count: + 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=self._users_per_page, offset=pager['offset'], order='karma DESC') + user_values = self._prepare_all_users_values(users) + + # Get karma position for users (only website_published) + position_domain = [('karma', '>', 1), ('website_published', '=', True)] + position_map = self._get_position_map(position_domain, users, group_by) + + max_position = max([user_data['karma_position'] for user_data in position_map.values()], default=1) + for user in user_values: + user_data = position_map.get(user['id'], dict()) + user['position'] = user_data.get('karma_position', max_position + 1) + user['karma_gain'] = user_data.get('karma_gain_total', 0) + user_values.sort(key=itemgetter('position')) + + if my_user.website_published and my_user.karma and my_user.id not in users.ids: + # Need to keep the dom to search only for users that appear in the ranking page + current_user = User.sudo().search(expression.AND([[('id', '=', my_user.id)], dom])) + if current_user: + current_user_values = self._prepare_all_users_values(current_user)[0] + + user_data = self._get_position_map(position_domain, current_user, group_by).get(current_user.id, {}) + current_user_values['position'] = user_data.get('karma_position', 0) + current_user_values['karma_gain'] = user_data.get('karma_gain_total', 0) + + else: + user_values = [] + pager = {'page_count': 0} + render_values.update({ + 'top3_users': user_values[:3] if not search_term and page == 1 else [], + 'users': user_values, + 'my_user': current_user_values, + 'pager': pager, + }) + return request.render("website_profile.users_page_main", render_values) + + def _get_position_map(self, position_domain, users, group_by): + if group_by: + position_map = self._get_user_tracking_karma_gain_position(position_domain, users.ids, group_by) + else: + position_results = users._get_karma_position(position_domain) + position_map = dict((user_data['user_id'], dict(user_data)) for user_data in position_results) + return position_map + + def _get_user_tracking_karma_gain_position(self, domain, user_ids, group_by): + """ Helper method computing boundaries to give to _get_tracking_karma_gain_position. + See that method for more details. """ + to_date = fields.Date.today() + if group_by == 'week': + from_date = to_date - relativedelta(weeks=1) + elif group_by == 'month': + from_date = to_date - relativedelta(months=1) + else: + from_date = None + results = request.env['res.users'].browse(user_ids)._get_tracking_karma_gain_position(domain, from_date=from_date, to_date=to_date) + return dict((item['user_id'], dict(item)) for item in results) + + # User and validation + # -------------------------------------------------- + + @http.route('/profile/send_validation_email', type='json', auth='user', website=True) + def send_validation_email(self, **kwargs): + if request.env.uid != request.website.user_id.id: + request.env.user._send_profile_validation_email(**kwargs) + request.session['validation_email_sent'] = True + return True + + @http.route('/profile/validate_email', type='http', auth='public', website=True, sitemap=False) + def validate_email(self, token, user_id, email, **kwargs): + done = request.env['res.users'].sudo().browse(int(user_id))._process_profile_validation_token(token, email) + if done: + request.session['validation_email_done'] = True + url = kwargs.get('redirect_url', '/') + return request.redirect(url) + + @http.route('/profile/validate_email/close', type='json', auth='public', website=True) + def validate_email_done(self, **kwargs): + request.session['validation_email_done'] = False + return True |
