diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py index f31b59e430f..ed2cb30df2e 100644 --- a/addons/website_forum/controllers/main.py +++ b/addons/website_forum/controllers/main.py @@ -3,6 +3,7 @@ import json import lxml import requests +import logging import werkzeug.exceptions import werkzeug.urls import werkzeug.wrappers @@ -15,6 +16,8 @@ from odoo.addons.website.models.ir_http import sitemap_qs2dom from odoo.addons.website_profile.controllers.main import WebsiteProfile from odoo.http import request +_logger = logging.getLogger(__name__) + class WebsiteForum(WebsiteProfile): _post_per_page = 10 @@ -26,8 +29,6 @@ class WebsiteForum(WebsiteProfile): values.update({ 'header': kwargs.get('header', dict()), 'searches': kwargs.get('searches', dict()), - 'validation_email_sent': request.session.get('validation_email_sent', False), - 'validation_email_done': request.session.get('validation_email_done', False), }) if kwargs.get('forum'): values['forum'] = kwargs.get('forum') @@ -37,32 +38,21 @@ class WebsiteForum(WebsiteProfile): # User and validation # -------------------------------------------------- - + # TODO DBE : Those 3 are deprecated. To remove in v13. @http.route('/forum/send_validation_email', type='json', auth='user', website=True) - def send_validation_email(self, forum_id=None, **kwargs): - if request.env.uid != request.website.user_id.id: - request.env.user._send_forum_validation_email(forum_id=forum_id) - request.session['validation_email_sent'] = True - return True + def send_forum_validation_email(self, forum_id=None, **kwargs): + _logger.warning("The method send_forum_validation_email() is deprecated and should be removed in v13.") + return self.send_forum_validation_email(forum_id=forum_id, **kwargs) @http.route('/forum/validate_email', type='http', auth='public', website=True, sitemap=False) - def validate_email(self, token, id, email, forum_id=None, **kwargs): - if forum_id: - try: - forum_id = int(forum_id) - except ValueError: - forum_id = None - done = request.env['res.users'].sudo().browse(int(id)).process_forum_validation_token(token, email, forum_id=forum_id)[0] - if done: - request.session['validation_email_done'] = True - if forum_id: - return request.redirect("/forum/%s" % int(forum_id)) - return request.redirect('/forum') + def forum_validate_email(self, token, user_id, email, forum_id=None, **kwargs): + _logger.warning("The method forum_validate_email() is deprecated and should be removed in v13.") + return self.forum_validate_email(token=token, user_id=user_id, email=email, forum_id=forum_id, **kwargs) @http.route('/forum/validate_email/close', type='json', auth='public', website=True) - def validate_email_done(self): - request.session['validation_email_done'] = False - return True + def forum_validate_email_done(self, **kwargs): + _logger.warning("The method forum_validate_email_done() is deprecated and should be removed in v13.") + return self.validate_email_done(**kwargs) # Forum # -------------------------------------------------- @@ -550,6 +540,7 @@ class WebsiteForum(WebsiteProfile): # Profile # ----------------------------------- + @http.route(['/forum//user/'], type='http', auth="public", website=True) def view_user_forum_profile(self, forum, user_id, **post): return werkzeug.utils.redirect('/profile/user/' + str(user_id) + '?forum_id=' + str(forum.id)) diff --git a/addons/website_forum/data/forum_data.xml b/addons/website_forum/data/forum_data.xml index fe5fb2b8ea2..4196804495a 100644 --- a/addons/website_forum/data/forum_data.xml +++ b/addons/website_forum/data/forum_data.xml @@ -129,107 +129,5 @@ offensive - - - Forum: Email Verification - - ${object.company_id.name} Forums validation - ${('<%s>' % (object.env.user.company_id.email or user.email)) | safe} - ${object.email|safe} - - - - -
- - - - - - - - - - - - - - - -
- - - - - - - - -
- Your Forum
- - ${object.company_id.name} Forum validation - -
- ${user.company_id.name} -
-
-
-
- - - - - - - -
-

- Hello ${object.name},

- You have been invited to validate your email in order to get access to "${object.company_id.name}" Q/A Forums. - To validate your email, please click on the following link: -

- Thanks for your participation! -

-
-
-
-
- - - - - -
- ${user.company_id.name} - - ${user.company_id.phone} - % if user.company_id.email: - | - ${user.company_id.email} - - % endif - % if user.company_id.website: - | - ${user.company_id.website} - - % endif -
-
-
- - -
- Powered by Odoo -
-
-
-
- diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py index 68d48b8534f..4dc172a90a0 100644 --- a/addons/website_forum/models/forum.py +++ b/addons/website_forum/models/forum.py @@ -4,7 +4,6 @@ import logging import math import re -import uuid from datetime import datetime from odoo.addons.gamification.models.gamification_karma_rank import KarmaError @@ -21,15 +20,6 @@ class Forum(models.Model): _description = 'Forum' _inherit = ['mail.thread', 'website.seo.metadata', 'website.multi.mixin'] - @api.model_cr - def init(self): - """ Add forum uuid for user email validation. - - TDE TODO: move me somewhere else, auto_init ? """ - forum_uuids = self.env['ir.config_parameter'].search([('key', '=', 'website_forum.uuid')]) - if not forum_uuids: - forum_uuids.set_param('website_forum.uuid', str(uuid.uuid4())) - @api.model def _get_default_faq(self): with misc.file_open('website_forum/data/forum_default_faq.html', 'r') as f: diff --git a/addons/website_forum/models/res_users.py b/addons/website_forum/models/res_users.py index 43791f3538c..67326175ac9 100644 --- a/addons/website_forum/models/res_users.py +++ b/addons/website_forum/models/res_users.py @@ -32,57 +32,6 @@ class Users(models.Model): domain = [('parent_id', '=', False), ('state', '=', 'pending'), ('create_uid', '=', user.id)] user.forum_waiting_posts_count = Post.search_count(domain) - @api.model - def _generate_forum_token(self, user_id, email): - """Return a token for email validation. This token is valid for the day - and is a hash based on a (secret) uuid generated by the forum module, - the user_id, the email and currently the day (to be updated if necessary). """ - forum_uuid = self.env['ir.config_parameter'].sudo().get_param('website_forum.uuid') - return hashlib.sha256((u'%s-%s-%s-%s' % ( - datetime.now().replace(hour=0, minute=0, second=0, microsecond=0), - forum_uuid, - user_id, - email - )).encode('utf-8')).hexdigest() - - @api.one - def _send_forum_validation_email(self, forum_id=None): - if not self.email: - return False - token = self._generate_forum_token(self.id, self.email) - activation_template = self.env.ref('website_forum.validation_email') - if activation_template: - params = { - 'token': token, - 'id': self.id, - 'email': self.email} - if forum_id: - params['forum_id'] = forum_id - base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') - token_url = base_url + '/forum/validate_email?%s' % urls.url_encode(params) - with self._cr.savepoint(): - activation_template.sudo().with_context(token_url=token_url).send_mail( - self.id, force_send=True, raise_exception=True) - return True - - @api.one - def process_forum_validation_token(self, token, email, forum_id=None, context=None): - validation_token = self._generate_forum_token(self.id, email) - if token == validation_token and self.karma == 0: - karma = 3 - forum = None - if forum_id: - forum = self.env['forum.forum'].browse(forum_id) - else: - forum_ids = self.env['forum.forum'].search([], limit=1) - if forum_ids: - forum = forum_ids[0] - if forum: - # karma gained: karma to ask a question and have 2 downvotes - karma = forum.karma_ask + (-2 * forum.karma_gen_question_downvote) - return self.write({'karma': karma}) - return False - # Wrapper for call_kw with inherits @api.multi def open_website_url(self): diff --git a/addons/website_forum/static/src/js/website_forum.js b/addons/website_forum/static/src/js/website_forum.js index 613163a045a..cfca0be8454 100644 --- a/addons/website_forum/static/src/js/website_forum.js +++ b/addons/website_forum/static/src/js/website_forum.js @@ -6,6 +6,7 @@ var Wysiwyg = require('web_editor.wysiwyg.root'); var sAnimations = require('website.content.snippets.animation'); var session = require('web.session'); var qweb = core.qweb; +var WebsiteProfile = require('website_profile.website_profile'); var _t = core._t; @@ -29,8 +30,6 @@ sAnimations.registry.websiteForum = sAnimations.Class.extend({ 'click .favourite_question': '_onFavoriteQuestionClick', 'click .comment_delete': '_onDeleteCommentClick', 'click .notification_close': '_onCloseNotificationClick', - 'click .send_validation_email': '_onSendValidationEmailClick', - 'click .validated_email_close': '_onCloseValidatedEmailClick', 'click .js_close_intro': '_onCloseIntroClick', }, @@ -465,32 +464,6 @@ sAnimations.registry.websiteForum = sAnimations.Class.extend({ }); } }, - /** - * @private - * @param {Event} ev - */ - _onSendValidationEmailClick: function (ev) { - ev.preventDefault(); - var $link = $(ev.currentTarget); - this._rpc({ - route: '/forum/send_validation_email', - params: { - forum_id: $link.attr('forum-id'), - }, - }).then(function (data) { - if (data) { - $('button.validation_email_close').click(); - } - }); - }, - /** - * @private - */ - _onCloseValidatedEmailClick: function () { - this._rpc({ - route: '/forum/validate_email/close', - }); - }, /** * @private * @param {Event} ev @@ -579,4 +552,5 @@ sAnimations.registry.websiteForumSpam = sAnimations.Class.extend({ }); }, }); + }); diff --git a/addons/website_forum/views/website_forum.xml b/addons/website_forum/views/website_forum.xml index 482a7d9541b..1c4755f7092 100644 --- a/addons/website_forum/views/website_forum.xml +++ b/addons/website_forum/views/website_forum.xml @@ -52,22 +52,12 @@
-
- -
- -
-

Congratulations! Your email has just been validated. You may now participate to our forums.

-
-
+
+ + + + +
diff --git a/addons/website_profile/__manifest__.py b/addons/website_profile/__manifest__.py index 1214d3f03e8..fbb57d126fd 100644 --- a/addons/website_profile/__manifest__.py +++ b/addons/website_profile/__manifest__.py @@ -12,6 +12,7 @@ 'gamification' ], 'data': [ + 'data/profile_data.xml', 'views/gamification_badge_views.xml', 'views/website_profile.xml', 'security/ir.model.access.csv', diff --git a/addons/website_profile/controllers/main.py b/addons/website_profile/controllers/main.py index 4d0e58efbe8..b29ba2077fb 100644 --- a/addons/website_profile/controllers/main.py +++ b/addons/website_profile/controllers/main.py @@ -57,6 +57,8 @@ class WebsiteProfile(http.Controller): 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 @@ -111,8 +113,9 @@ class WebsiteProfile(http.Controller): 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 = self._prepare_user_profile_values(user, **params) + values.update(self._prepare_user_profile_values(user, **params)) return request.render("website_profile.user_profile_main", values) # Edit Profile @@ -234,3 +237,26 @@ class WebsiteProfile(http.Controller): 'pager': pager } return request.render("website_profile.users_page_main", values) + + # 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 diff --git a/addons/website_profile/data/profile_data.xml b/addons/website_profile/data/profile_data.xml new file mode 100644 index 00000000000..5331fa23e8e --- /dev/null +++ b/addons/website_profile/data/profile_data.xml @@ -0,0 +1,106 @@ + + + + + + + Profile: Email Verification + + ${object.company_id.name} Profile validation + ${('<%s>' % (object.env.user.company_id.email or user.email)) | safe} + ${object.email|safe} + + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + +
+ + ${object.company_id.name} Profile validation + + + ${user.company_id.name} +
+
+
+
+ + + + + + + +
+

+ Hello ${object.name},

+ You have been invited to validate your email in order to get access to "${object.company_id.name}" website. + To validate your email, please click on the following link: +

+ Thanks for your participation! +

+
+
+
+
+ + + + + +
+ ${user.company_id.name} + + ${user.company_id.phone} + % if user.company_id.email: + | + ${user.company_id.email} + + % endif + % if user.company_id.website: + | + ${user.company_id.website} + + % endif +
+
+
+ + +
+ Powered by Odoo +
+
+
+
+
+
diff --git a/addons/website_profile/models/__init__.py b/addons/website_profile/models/__init__.py index c26e78d1255..e5d082ad113 100644 --- a/addons/website_profile/models/__init__.py +++ b/addons/website_profile/models/__init__.py @@ -3,3 +3,4 @@ from . import gamification_badge from . import website +from . import res_users diff --git a/addons/website_profile/models/res_users.py b/addons/website_profile/models/res_users.py new file mode 100644 index 00000000000..5bf49be0a78 --- /dev/null +++ b/addons/website_profile/models/res_users.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import hashlib +import uuid + +from datetime import datetime +from werkzeug import urls +from odoo import api, models + +VALIDATION_KARMA_GAIN = 3 + + +class Users(models.Model): + _inherit = 'res.users' + + @api.model + def _generate_profile_token(self, user_id, email): + """Return a token for email validation. This token is valid for the day + and is a hash based on a (secret) uuid generated by the forum module, + the user_id, the email and currently the day (to be updated if necessary). """ + profile_uuid = self.env['ir.config_parameter'].sudo().get_param('website_profile.uuid') + if not profile_uuid: + profile_uuid = str(uuid.uuid4()) + self.env['ir.config_parameter'].sudo().set_param('website_profile.uuid', profile_uuid) + return hashlib.sha256((u'%s-%s-%s-%s' % ( + datetime.now().replace(hour=0, minute=0, second=0, microsecond=0), + profile_uuid, + user_id, + email + )).encode('utf-8')).hexdigest() + + def _send_profile_validation_email(self, **kwargs): + if not self.email: + return False + token = self._generate_profile_token(self.id, self.email) + activation_template = self.env.ref('website_profile.validation_email') + if activation_template: + params = { + 'token': token, + 'user_id': self.id, + 'email': self.email + } + params.update(kwargs) + base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + token_url = base_url + '/profile/validate_email?%s' % urls.url_encode(params) + with self._cr.savepoint(): + activation_template.sudo().with_context(token_url=token_url).send_mail( + self.id, force_send=True, raise_exception=True) + return True + + @api.multi + def _process_profile_validation_token(self, token, email): + self.ensure_one() + validation_token = self._generate_profile_token(self.id, email) + if token == validation_token and self.karma == 0: + return self.write({'karma': VALIDATION_KARMA_GAIN}) + return False diff --git a/addons/website_profile/static/src/js/website_profile.js b/addons/website_profile/static/src/js/website_profile.js new file mode 100644 index 00000000000..a3cc18f53f5 --- /dev/null +++ b/addons/website_profile/static/src/js/website_profile.js @@ -0,0 +1,47 @@ +odoo.define('website_profile.website_profile', function (require) { +'use strict'; + +var sAnimations = require('website.content.snippets.animation'); + +//TODO DBE : to change into publicWidget = require('web.public.widget'); after forward port in master +sAnimations.registry.websiteProfile = sAnimations.Class.extend({ + selector: '.o_wprofile_email_validation_container', + read_events: { + 'click .send_validation_email': '_onSendValidationEmailClick', + 'click .validated_email_close': '_onCloseValidatedEmailClick', + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + /** + * @private + * @param {Event} ev + */ + _onSendValidationEmailClick: function (ev) { + ev.preventDefault(); + var self = this; + var $element = $(ev.currentTarget); + this._rpc({ + route: '/profile/send_validation_email', + params: {'redirect_url': $element.data('redirect_url')}, + }).then(function (data) { + if (data) { + self.$('button.validation_email_close').click(); + } + }); + }, + + /** + * @private + */ + _onCloseValidatedEmailClick: function () { + this._rpc({ + route: '/profile/validate_email/close', + }); + }, +}); + +return sAnimations.registry.websiteProfile; + +}); diff --git a/addons/website_profile/views/website_profile.xml b/addons/website_profile/views/website_profile.xml index 2a108ef8906..fc9e6aae113 100644 --- a/addons/website_profile/views/website_profile.xml +++ b/addons/website_profile/views/website_profile.xml @@ -4,6 +4,9 @@ + +