From fb289e0b5d7efdf3c74fa9080da7b6f29dc3ff8e Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Sat, 2 Jul 2016 06:23:25 +0200 Subject: [PATCH] [SEC] rating: escape feedback, text2html to avoid js injection [IMP] rating: website rating page: reviewed design, rate on click, update on submit [IMP] rating_project: rating_status: 'no' instead of False [IMP] rating_project/issue: smileys insteaf of thumbs for consistency in kanban [IMP] rating: allow to update an existing rating (feedback + rate) [IMP] rating: consistency on rating names (statisfied, not satisfied, higly dissatisfed) [IMP] rating: avoid deadend after rating, button to go to Odoo [IMP] rating: res_config better sentence --- addons/project/models/res_config.py | 2 +- addons/rating/controllers/main.py | 36 +++++++++------ addons/rating/models/rating.py | 14 +++--- addons/rating/views/rating_template.xml | 44 ++++++++++--------- addons/rating_project/data/project_data.xml | 11 ++--- addons/rating_project/models/project.py | 6 +-- .../views/project_dashboard.xml | 8 ++-- addons/rating_project/views/project_view.xml | 22 ++++++---- .../views/project_issue_view.xml | 8 ++-- .../controllers/main.py | 4 +- .../views/project_project_view.xml | 2 +- 11 files changed, 88 insertions(+), 69 deletions(-) diff --git a/addons/project/models/res_config.py b/addons/project/models/res_config.py index 930ce8773d4..41fccf6143f 100644 --- a/addons/project/models/res_config.py +++ b/addons/project/models/res_config.py @@ -17,7 +17,7 @@ class ProjectConfiguration(models.TransientModel): '-This installs the module pad.') module_rating_project = fields.Selection([ (0, "No customer rating"), - (1, 'Allow activating customer rating on projects, at issue completion') + (1, 'Allow customer ratings on tasks or issues') ], string="Rating", help="This allows customers to give rating on provided services") generate_project_alias = fields.Selection([ diff --git a/addons/rating/controllers/main.py b/addons/rating/controllers/main.py index ed05f8d372c..5833b4633a8 100644 --- a/addons/rating/controllers/main.py +++ b/addons/rating/controllers/main.py @@ -4,28 +4,36 @@ import werkzeug from openerp import http from openerp.http import request +from openerp.tools.translate import _ class Rating(http.Controller): @http.route('/rating//', type='http', auth="public") def open_rating(self, token, rate, **kwargs): + assert rate in (1, 5, 10), "Incorrect rating" rating = request.env['rating.rating'].sudo().search([('access_token', '=', token)]) - if not rating.consumed: - return request.render('rating.rating_external_page_submit', {'rating': rate, 'token': token}) - else: - return request.render('rating.rating_external_page_view', {'is_rated': True}) + if not rating: + return request.not_found() + rate_names={ + 5: _("not satisfied"), + 1: _("highly dissatisfied"), + 10: _("satisfied") + } + rating.sudo().write({'rating': rate, 'consumed': True}) + return request.render('rating.rating_external_page_submit', { + 'rating': rating, 'token': token, + 'rate_name': rate_names[rate], 'rate': rate + }) return request.not_found() @http.route(['/rating///submit_feedback'], type="http", auth="public", method=['post']) def submit_rating(self, token, rate, **kwargs): rating = request.env['rating.rating'].sudo().search([('access_token', '=', token)]) - if not rating.consumed: - record_sudo = request.env[rating.res_model].sudo().browse(rating.res_id) - record_sudo.rating_apply(rate, token=token, feedback=kwargs.get('feedback')) - # redirect to the form view if logged person - if request.session.uid: - return werkzeug.utils.redirect('/web#model=%s&id=%s&view_type=form' % (record_sudo._name, record_sudo.id)) - return request.render('rating.rating_external_page_view', {'is_public': True}) - else: - return request.render('rating.rating_external_page_view', {'is_rated': True}) - return request.not_found() + if not rating: + return request.not_found() + record_sudo = request.env[rating.res_model].sudo().browse(rating.res_id) + record_sudo.rating_apply(rate, token=token, feedback=kwargs.get('feedback')) + # redirect to the form view if logged person + if request.session.uid: + return werkzeug.utils.redirect('/web#model=%s&id=%s&view_type=form' % (record_sudo._name, record_sudo.id)) + return request.render('rating.rating_external_page_view') diff --git a/addons/rating/models/rating.py b/addons/rating/models/rating.py index a723d2514e5..9c87139d380 100644 --- a/addons/rating/models/rating.py +++ b/addons/rating/models/rating.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- + import uuid from odoo import api, fields, models +from openerp import tools + class Rating(models.Model): @@ -105,22 +108,23 @@ class RatingMixin(models.AbstractModel): """ Rating, rating = self.env['rating.rating'], None if token: - rating = self.env['rating.rating'].search([('access_token', '=', token), ('consumed', '=', False)], limit=1) + rating = self.env['rating.rating'].search([('access_token', '=', token)], limit=1) else: - rating = Rating.search([('res_model', '=', self._name), ('res_id', '=', self.ids[0]), ('consumed', '=', False)], limit=1) + rating = Rating.search([('res_model', '=', self._name), ('res_id', '=', self.ids[0])], limit=1) if rating: rating.write({'rating': rate, 'feedback': feedback, 'consumed': True}) if hasattr(self, 'message_post'): + feedback = tools.plaintext2html(feedback or '') self.message_post( - body="%s" - % (rate, '
' + feedback if feedback else ''), + body="%s" + % (rate, feedback), subtype=subtype or "mail.mt_comment", author_id=rating.partner_id and rating.partner_id.id or None # None will set the default author in mail_thread.py ) if hasattr(self, 'stage_id') and self.stage_id and hasattr(self.stage_id, 'auto_validation_kanban_state') and self.stage_id.auto_validation_kanban_state: if rating.rating > 5: self.write({'kanban_state': 'done'}) - else: + if rating.rating < 5: self.write({'kanban_state': 'blocked'}) return rating diff --git a/addons/rating/views/rating_template.xml b/addons/rating/views/rating_template.xml index a3f6a4424b9..77c1bf6cb51 100644 --- a/addons/rating/views/rating_template.xml +++ b/addons/rating/views/rating_template.xml @@ -101,13 +101,12 @@
-
-

-

Sorry you have already voted!

+
+
-
-

-

Thank you for submitting your feedback!

+

We appreciate your feedback!

+
@@ -119,21 +118,24 @@
-

Please submit your rating

-

You selected

-
-
-
-
Do you want to give additional explanation? (Optional)
- - -
-
-
-
- -
-
+

Thanks! We appreciate your feedback.

+

Your rating has been submitted.

+
+ +
+
+ you are
+ on our services on ""
+ by . +
+
+

+ Would be great if you can provide more informaion: +

+ + + +
diff --git a/addons/rating_project/data/project_data.xml b/addons/rating_project/data/project_data.xml index 1332a726e39..864fbd334c3 100644 --- a/addons/rating_project/data/project_data.xml +++ b/addons/rating_project/data/project_data.xml @@ -57,8 +57,9 @@

- Tell us how you feel about our service + Tell us how you feel about our service:

+
(click on one of these smileys)
@@ -67,17 +68,17 @@ - Great + Satisfied - Okay + Not satisfied - Bad + Highly Dissatisfied @@ -96,7 +97,7 @@

This customer survey has been sent because your task has been moved to the stage ${object.stage_id.name}

% endif % if object.project_id.rating_status == 'periodic': -

This customer survey has been sent ${object.project_id.rating_status_period} as long as the task is in the ${object.stage_id.name} stage. +

This customer survey is send ${object.project_id.rating_status_period} as long as the task is in the ${object.stage_id.name} stage. % endif

Email automatically sent by Odoo Project for ${object.project_id.company_id.name}

diff --git a/addons/rating_project/models/project.py b/addons/rating_project/models/project.py index 67b5eb02764..56bf9637ef7 100644 --- a/addons/rating_project/models/project.py +++ b/addons/rating_project/models/project.py @@ -78,10 +78,10 @@ class Project(models.Model): percentage_satisfaction_project = fields.Integer( compute="_compute_percentage_satisfaction_project", string="Happy % on Project", store=True, default=-1) rating_request_deadline = fields.Datetime(compute='_compute_rating_request_deadline', store=True) - rating_status = fields.Selection([('stage', 'Rating on Stage'), ('periodic', 'Periodical Rating')], 'Customer(s) Ratings', help="How to get the customer's feedbacks?\n" - "- Rating on stage: Email will be sent when a task/issue is pulled in another stage\n" + rating_status = fields.Selection([('stage', 'Rating when changing stage'), ('periodic', 'Periodical Rating'), ('no','No rating')], 'Customer(s) Ratings', help="How to get the customer's feedbacks?\n" + "- Rating when changing stage: Email will be sent when a task/issue is pulled in another stage\n" "- Periodical Rating: Email will be sent periodically\n\n" - "Don't forget to set up the mail templates on the stages for which you want to get the customer's feedbacks.") + "Don't forget to set up the mail templates on the stages for which you want to get the customer's feedbacks.", default="no", required=True) rating_status_period = fields.Selection([ ('daily', 'Daily'), ('weekly', 'Weekly'), ('bimonthly', 'Twice a Month'), ('monthly', 'Once a Month'), ('quarterly', 'Quarterly'), ('yearly', 'Yearly') diff --git a/addons/rating_project/views/project_dashboard.xml b/addons/rating_project/views/project_dashboard.xml index 1188ddd4560..50b1b516e92 100644 --- a/addons/rating_project/views/project_dashboard.xml +++ b/addons/rating_project/views/project_dashboard.xml @@ -10,11 +10,11 @@ -
+
- No rating + No rating yet % @@ -23,7 +23,7 @@
-
+
Customers Ratings @@ -32,4 +32,4 @@ - \ No newline at end of file + diff --git a/addons/rating_project/views/project_view.xml b/addons/rating_project/views/project_view.xml index 466581cbabb..d3cabb26513 100644 --- a/addons/rating_project/views/project_view.xml +++ b/addons/rating_project/views/project_view.xml @@ -21,6 +21,7 @@ @@ -39,9 +40,9 @@ - - - + + + @@ -56,7 +57,7 @@