helpdesk_rating_five_stars/controllers/rating.py
2025-11-26 10:39:26 +07:00

292 lines
10 KiB
Python

# -*- coding: utf-8 -*-
from odoo import http
from odoo.http import request
from odoo.exceptions import ValidationError
import logging
_logger = logging.getLogger(__name__)
class RatingController(http.Controller):
"""Controller for handling 5-star rating submissions from web and email"""
@http.route('/rating/<string:token>',
type='http', auth='public', website=True, methods=['GET'])
def rating_form(self, token, **kwargs):
"""
Display the web rating form for a given token
Args:
token: Unique rating token
**kwargs: Additional parameters
Returns:
Rendered rating form page or error page
"""
try:
# Find the rating record by token
rating = request.env['rating.rating'].sudo().search([
('access_token', '=', token)
], limit=1)
if not rating:
_logger.warning('Rating not found for token: %s', token)
return self._render_error_page(
'Invalid Link',
'This rating link is invalid or has expired. '
'Please contact support if you need assistance.'
)
# Get ticket information if available
ticket_name = ''
if rating.res_model == 'helpdesk.ticket' and rating.res_id:
ticket = request.env['helpdesk.ticket'].sudo().browse(rating.res_id)
if ticket.exists():
ticket_name = ticket.name or f'Ticket #{ticket.id}'
values = {
'token': token,
'rating': rating,
'ticket_name': ticket_name,
'page_title': 'Rate Your Experience',
}
return request.render(
'helpdesk_rating_five_stars.rating_form_page',
values
)
except Exception as e:
_logger.exception('Error displaying rating form')
return self._render_error_page(
'System Error',
'An unexpected error occurred. Please try again later.'
)
@http.route('/rating/<string:token>/submit',
type='http', auth='public', website=True, methods=['POST'], csrf=True)
def submit_rating_form(self, token, rating_value, feedback=None, **kwargs):
"""
Handle rating submission from the web form
Args:
token: Unique rating token
rating_value: Star rating (1-5)
feedback: Optional feedback text
**kwargs: Additional parameters
Returns:
Rendered thank you page or error page
"""
try:
# Convert rating_value to int
try:
rating_value = int(rating_value)
except (ValueError, TypeError):
_logger.warning('Invalid rating value format: %s', rating_value)
return self._render_error_page(
'Invalid Rating',
'Invalid rating value. Please try again.'
)
# Validate rating value range
if rating_value < 1 or rating_value > 5:
_logger.warning(
'Invalid rating value received: %s for token: %s',
rating_value, token
)
return self._render_error_page(
'Invalid Rating',
'Rating must be between 1 and 5 stars. Please try again.'
)
# Find the rating record by token
rating = request.env['rating.rating'].sudo().search([
('access_token', '=', token)
], limit=1)
if not rating:
_logger.warning('Rating not found for token: %s', token)
return self._render_error_page(
'Invalid Link',
'This rating link is invalid or has expired. '
'Please contact support if you need assistance.'
)
# Detect duplicate rating attempt (Requirement 7.2)
is_update = rating.consumed and rating.rating > 0
# Update the rating value and feedback
try:
write_vals = {
'rating': float(rating_value),
'consumed': True,
}
if feedback:
write_vals['feedback'] = feedback
rating.write(write_vals)
if is_update:
_logger.info(
'Rating updated (duplicate): token=%s, old_value=%s, new_value=%s, resource=%s',
token, rating.rating, rating_value, rating.res_model
)
else:
_logger.info(
'Rating created: token=%s, value=%s, resource=%s',
token, rating_value, rating.res_model
)
except ValidationError as e:
_logger.error(
'Validation error while saving rating: %s',
str(e)
)
return self._render_error_page(
'Validation Error',
str(e)
)
# Redirect to confirmation page with update flag
return self._render_confirmation_page(rating, rating_value, is_update=is_update)
except Exception as e:
_logger.exception('Unexpected error during rating submission')
return self._render_error_page(
'System Error',
'An unexpected error occurred. Please try again later.'
)
@http.route('/rating/<string:token>/<int:rating_value>',
type='http', auth='public', website=True, methods=['GET', 'POST'])
def submit_rating(self, token, rating_value, **kwargs):
"""
Handle rating submission from email links or web form
Args:
token: Unique rating token
rating_value: Star rating (1-5)
**kwargs: Additional parameters
Returns:
Rendered thank you page or error page
"""
try:
# Validate rating value range
if rating_value < 1 or rating_value > 5:
_logger.warning(
'Invalid rating value received: %s for token: %s',
rating_value, token
)
return self._render_error_page(
'Invalid Rating',
'Rating must be between 1 and 5 stars. Please try again.'
)
# Find the rating record by token
rating = request.env['rating.rating'].sudo().search([
('access_token', '=', token)
], limit=1)
if not rating:
_logger.warning('Rating not found for token: %s', token)
return self._render_error_page(
'Invalid Link',
'This rating link is invalid or has expired. '
'Please contact support if you need assistance.'
)
# Detect duplicate rating attempt (Requirement 7.2)
# Check if rating is already consumed and has a value
is_update = rating.consumed and rating.rating > 0
# Update the rating value
try:
rating.write({
'rating': float(rating_value),
'consumed': True,
})
if is_update:
_logger.info(
'Rating updated (duplicate): token=%s, old_value=%s, new_value=%s, resource=%s',
token, rating.rating, rating_value, rating.res_model
)
else:
_logger.info(
'Rating created: token=%s, value=%s, resource=%s',
token, rating_value, rating.res_model
)
except ValidationError as e:
_logger.error(
'Validation error while saving rating: %s',
str(e)
)
return self._render_error_page(
'Validation Error',
str(e)
)
# Redirect to confirmation page with update flag
return self._render_confirmation_page(rating, rating_value, is_update=is_update)
except Exception as e:
_logger.exception('Unexpected error during rating submission')
return self._render_error_page(
'System Error',
'An unexpected error occurred. Please try again later.'
)
def _render_confirmation_page(self, rating, rating_value, is_update=False):
"""
Render the confirmation page after successful rating submission
Args:
rating: The rating record
rating_value: The submitted rating value
is_update: Whether this is an update to an existing rating
Returns:
Rendered confirmation page
"""
# Generate star HTML for display
filled_star = ''
empty_star = ''
stars_html = (filled_star * rating_value) + (empty_star * (5 - rating_value))
values = {
'rating': rating,
'rating_value': rating_value,
'stars_html': stars_html,
'is_update': is_update,
'page_title': 'Thank You for Your Feedback',
}
return request.render(
'helpdesk_rating_five_stars.rating_confirmation_page',
values
)
def _render_error_page(self, error_title, error_message):
"""
Render an error page with the given title and message
Args:
error_title: Title of the error
error_message: Detailed error message
Returns:
Rendered error page
"""
values = {
'error_title': error_title,
'error_message': error_message,
'page_title': 'Rating Error',
}
return request.render(
'helpdesk_rating_five_stars.rating_error_page',
values
)