[MERGE][IMP] survey: clarify live session links flow
Specifications - Handle the situation in which the quick access link is used but the live session is not launched yet, by showing an appropriate error message and by allowing a user with sufficient rights to launch the live session directly from the quick access page. - Make the live session's "go to" url in the presentation mode non-clickable so that the presenter can not join the session as an attendee as it messes up, and change the copy icon next to the url to a copy button, which is more explicit. Task-2816685 closes odoo/odoo#88434 Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
@@ -19,21 +19,18 @@ class UserInputSession(http.Controller):
|
||||
return request.env['survey.survey'].search([('access_token', '=', survey_token)])
|
||||
|
||||
def _fetch_from_session_code(self, session_code):
|
||||
""" Matches a survey against a passed session_code.
|
||||
We don't limit the session_state to be reachable (ready / in_progress) here because
|
||||
in some cases, we want closed session as well (where session_state = False).
|
||||
Instead, when necessary, the reachability is forced in routes calling this method to
|
||||
avoid people using those routes to access other (private) surveys.
|
||||
We limit to sessions opened within the last 7 days to avoid potential abuses. """
|
||||
if session_code:
|
||||
matching_survey = request.env['survey.survey'].sudo().search([
|
||||
('session_start_time', '>', fields.Datetime.now() - relativedelta(days=7)),
|
||||
('session_code', '=', session_code),
|
||||
], limit=1)
|
||||
if matching_survey:
|
||||
return matching_survey
|
||||
|
||||
return False
|
||||
""" Matches a survey against a passed session_code, and checks if it is valid.
|
||||
If it is valid, returns the start url. Else, the error type."""
|
||||
if not session_code:
|
||||
return None, {'error': 'survey_wrong'}
|
||||
survey = request.env['survey.survey'].sudo().search([('session_code', '=', session_code)], limit=1)
|
||||
if not survey or survey.certification:
|
||||
return None, {'error': 'survey_wrong'}
|
||||
if survey.session_state in ['ready', 'in_progress']:
|
||||
return survey, None
|
||||
if request.env.user.has_group("survey.group_survey_user"):
|
||||
return None, {'error': 'survey_session_not_launched', 'survey_id': survey.id}
|
||||
return None, {'error': 'survey_session_not_launched'}
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# SURVEY SESSION MANAGEMENT
|
||||
@@ -176,28 +173,24 @@ class UserInputSession(http.Controller):
|
||||
@http.route('/s/<string:session_code>', type='http', auth='public', website=True)
|
||||
def survey_start_short(self, session_code):
|
||||
"""" Redirects to 'survey_start' route using a shortened link & token.
|
||||
We match the session_code for open surveys.
|
||||
Shows an error message if the survey is not valid.
|
||||
This route is used in survey sessions where we need short links for people to type. """
|
||||
survey, survey_error = self._fetch_from_session_code(session_code)
|
||||
|
||||
survey = self._fetch_from_session_code(session_code)
|
||||
if survey and survey.session_state in ['ready', 'in_progress']:
|
||||
return request.redirect("/survey/start/%s" % survey.access_token)
|
||||
|
||||
return request.redirect("/s")
|
||||
if survey_error:
|
||||
return request.render('survey.survey_session_code',
|
||||
dict(**survey_error, session_code=session_code))
|
||||
return request.redirect(survey.get_start_url())
|
||||
|
||||
@http.route('/survey/check_session_code/<string:session_code>', type='json', auth='public', website=True)
|
||||
def survey_check_session_code(self, session_code):
|
||||
""" Checks if the given code is matching a survey session_code.
|
||||
If yes, redirect to /s/code route.
|
||||
If not, return error. The user is invited to type again the code. """
|
||||
survey = self._fetch_from_session_code(session_code)
|
||||
if survey:
|
||||
if survey.session_state in ['ready', 'in_progress']:
|
||||
return {"survey_url": "/survey/start/%s" % survey.access_token}
|
||||
else:
|
||||
return {"error": "survey_session_closed"}
|
||||
|
||||
return {"error": "survey_wrong"}
|
||||
If not, return error. The user is invited to type again the code."""
|
||||
survey, survey_error = self._fetch_from_session_code(session_code)
|
||||
if survey_error:
|
||||
return survey_error
|
||||
return {'survey_url': survey.get_start_url()}
|
||||
|
||||
def _prepare_manage_session_values(self, survey):
|
||||
is_first_question, is_last_question = False, False
|
||||
|
||||
@@ -8,9 +8,10 @@ publicWidget.registry.SurveyQuickAccessWidget = publicWidget.Widget.extend({
|
||||
events: {
|
||||
'click button[type="submit"]': '_onSubmit',
|
||||
'input #session_code': '_onSessionCodeInput',
|
||||
'click .o_survey_launch_session': '_onLaunchSessionClick',
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------------
|
||||
// Widget
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
@@ -23,9 +24,7 @@ publicWidget.registry.SurveyQuickAccessWidget = publicWidget.Widget.extend({
|
||||
// Init event listener
|
||||
if (!self.readonly) {
|
||||
$(document).on('keypress', self._onKeyPress.bind(self));
|
||||
}
|
||||
|
||||
self.$('input').focus();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -36,8 +35,19 @@ publicWidget.registry.SurveyQuickAccessWidget = publicWidget.Widget.extend({
|
||||
// Handlers
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
_onLaunchSessionClick: async function () {
|
||||
const sessionResult = await this._rpc({
|
||||
'model': 'survey.survey',
|
||||
'method': 'action_start_session',
|
||||
'args': [[this.$('.o_survey_launch_session').data('surveyId')]],
|
||||
});
|
||||
window.location = sessionResult.url;
|
||||
},
|
||||
|
||||
_onSessionCodeInput: function () {
|
||||
this.el.querySelectorAll('.o_survey_error > span').forEach((elem) => elem.classList.add('d-none'));
|
||||
this.$('.o_survey_launch_session').addClass('d-none');
|
||||
this.$('button[type="submit"]').removeClass('d-none');
|
||||
},
|
||||
|
||||
_onKeyPress: function (event) {
|
||||
@@ -54,10 +64,10 @@ publicWidget.registry.SurveyQuickAccessWidget = publicWidget.Widget.extend({
|
||||
|
||||
_submitCode: function () {
|
||||
var self = this;
|
||||
this.$('.o_survey_error > span').addClass("d-none");
|
||||
this.$('.o_survey_error > span').addClass('d-none');
|
||||
const sessionCodeInputVal = this.$('input#session_code').val().trim();
|
||||
if (!sessionCodeInputVal) {
|
||||
self.$('.o_survey_session_error_invalid_code').removeClass("d-none");
|
||||
self.$('.o_survey_session_error_invalid_code').removeClass('d-none');
|
||||
return;
|
||||
}
|
||||
this._rpc({
|
||||
@@ -66,10 +76,15 @@ publicWidget.registry.SurveyQuickAccessWidget = publicWidget.Widget.extend({
|
||||
if (response.survey_url) {
|
||||
window.location = response.survey_url;
|
||||
} else {
|
||||
if (response.error && response.error === 'survey_session_closed') {
|
||||
self.$('.o_survey_session_error_closed').removeClass("d-none");
|
||||
if (response.error && response.error === 'survey_session_not_launched') {
|
||||
self.$('.o_survey_session_error_not_launched').removeClass('d-none');
|
||||
if ("survey_id" in response) {
|
||||
self.$('button[type="submit"]').addClass('d-none');
|
||||
self.$('.o_survey_launch_session').removeClass('d-none');
|
||||
self.$('.o_survey_launch_session').data('surveyId', response.survey_id);
|
||||
}
|
||||
} else {
|
||||
self.$('.o_survey_session_error_invalid_code').removeClass("d-none");
|
||||
self.$('.o_survey_session_error_invalid_code').removeClass('d-none');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -51,6 +51,8 @@ publicWidget.registry.SurveySessionManage = publicWidget.Widget.extend(SurveyPre
|
||||
self.stopNextQuestion = false;
|
||||
// Background Management
|
||||
self.refreshBackground = self.$el.data('refreshBackground');
|
||||
// Copy link tooltip
|
||||
self.$('.o_survey_session_copy').tooltip({delay: 0, title: 'Click to copy link', placement: 'right'});
|
||||
|
||||
var isRpcCall = self.$el.data('isRpcCall');
|
||||
if (!isRpcCall) {
|
||||
|
||||
@@ -367,11 +367,6 @@ _::-webkit-full-page-media, _:future, :root .o_survey_wrap {
|
||||
|
||||
.o_survey_session_copy {
|
||||
cursor: pointer;
|
||||
opacity: .75;
|
||||
transition: opacity .3s ease;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -118,16 +118,20 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-4 offset-md-4 text-center">
|
||||
<input id="session_code" type="text" placeholder="e.g. 4812" autocomplete="off"
|
||||
class="form-control o_survey_question_text_box font-weight-bold bg-transparent text-primary text-center rounded-0 p-2 w-100"/>
|
||||
<input id="session_code"
|
||||
type="text" placeholder="e.g. 4812"
|
||||
autocomplete="off"
|
||||
t-attf-value="{{session_code if session_code else ''}}"
|
||||
class="form-control o_survey_question_text_box font-weight-bold bg-transparent text-primary text-center rounded-0 p-2 w-100"/>
|
||||
</div>
|
||||
<div class="col-12 col-md-4 offset-md-4 text-center o_survey_error text-danger pt-2" role="alert">
|
||||
<span class="o_survey_session_error_invalid_code d-none">Code is incorrect.</span>
|
||||
<span class="o_survey_session_error_closed d-none">Session is finished.</span>
|
||||
<div class="col-12 col-md-4 offset-md-4 text-center o_survey_error text-danger h4 pt-2 px-0" role="alert">
|
||||
<span t-attf-class="o_survey_session_error_invalid_code {{'d-none' if error != 'survey_wrong' else ''}}">Oops! No survey matches this code.</span>
|
||||
<span t-attf-class="o_survey_session_error_not_launched {{'d-none' if error != 'survey_session_not_launched' else ''}}">The session did not start yet.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center mt32 p-2">
|
||||
<button type="submit" class="btn btn-primary">Join Session</button>
|
||||
<button groups="survey.group_survey_user" type="button" t-attf-class="o_survey_launch_session btn btn-primary {{'d-none' if error != 'survey_session_not_launched' else ''}}" t-att-data-survey-id="survey_id">Launch Session</button>
|
||||
<button type="submit" t-attf-class="btn btn-primary {{'d-none' if error == 'survey_session_not_launched' and request.env.user.has_group('survey.group_survey_user') else ''}}">Join Session</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -38,8 +38,7 @@
|
||||
<div class="text-center">
|
||||
<h1 class="mb-4" t-field="survey.title" />
|
||||
<h2 class="mb-5 font-weight-normal">
|
||||
<span class="text-break">Go to <a t-att-href="survey.session_link" t-esc="survey.session_link" target="_blank" /></span>
|
||||
<i class="fa fa-link font-weight-normal ml-3 o_survey_session_copy" />
|
||||
<span class="text-break">To join: <span class="text-info o_survey_session_copy" t-esc="survey.session_link"/></span>
|
||||
<input class="o_survey_session_copy_url d-none" type="text" t-att-value="survey.session_link" />
|
||||
</h2>
|
||||
<h2 class="font-weight-normal"><span>Waiting for attendees...</span>
|
||||
@@ -87,8 +86,7 @@
|
||||
t-att-data-is-session-closed="is_session_closed">
|
||||
<div t-if="not is_session_closed" class="o_survey_question_header flex-wrap px-3 w-100 d-flex justify-content-between align-items-center position-absolute">
|
||||
<h3>
|
||||
<span>Go to <a t-att-href="survey.session_link" t-esc="survey.session_link" target="_blank" /></span>
|
||||
<i class="fa fa-copy font-weight-normal ml-3 mr-1 o_survey_session_copy" />
|
||||
<span>To join: <span class="text-info o_survey_session_copy" t-esc="survey.session_link"/></span>
|
||||
<input class="o_survey_session_copy_url d-none" type="text" t-att-value="survey.session_link" />
|
||||
</h3>
|
||||
<h1 t-if="question.is_time_limited" class="o_survey_timer_container">
|
||||
|
||||
Reference in New Issue
Block a user