mod_survey
Adds survey resources: user-defined forms that can be created in the admin interface and filled in by site visitors. The module renders multi-page forms, validates and stores answers, supports quizzes, and reports or exports the collected results.
Survey question types
| Type | Description |
|---|---|
| likert | A five-point scale from completely disagree (1) to completely agree (5). |
| short answer | A single-line text field with optional validation such as email, date, or numeric. |
| long answer | A multi-line text field. |
| matching | Match each item to one of the supplied options. |
| thurstone | Translatable single or multiple choice, optionally submitting immediately after a choice. |
| multiple choice | Simple choices. Numeric choice values can also be totaled in printable and chart results. Use thurstone for translatable choices. |
| true or false | A boolean question with configurable option text. |
| yes or no | A boolean question with configurable option text. |
| narrative | Inline questions embedded in narrative text. |
| category | Select one resource from a category. |
| country | Select a country. |
| hidden | A hidden value, for example to record that a page was submitted. |
| upload | A file upload for the final page. The upload question has no stored result; a custom survey handler must process the file. |
| header | A subheading between questions. |
| prompt | An additional prompt block. |
| text block | Explanatory text between questions. |
Tests and quizzes
Thurstone and matching questions can be marked as test questions with
is_test. This selects their test rendering and makes the configured correct
answers available to the feedback templates. is_test_direct shows feedback
while filling in the question.
Scoring is currently implemented for thurstone questions. Each choice can have
an is_correct flag and points_int; the default is one point. A single-choice
question awards the selected correct answer. A multiple-choice question can
award correct selections and correctly omitted wrong selections. With
is_test_neg, wrong selections and omitted correct answers subtract their
configured points. The score for an individual question never goes below zero.
Matching test questions support direct correctness feedback but currently add
no points to the stored total.
survey_test_results stores the calculated total in the answer's points
field and annotates the stored answers with their points. Set the survey
property survey_test_percentage to the percentage needed to pass. The
survey_show_results setting controls whether the final page shows only the
thank-you text, the respondent's result, the respondent's result only after a
pass, or aggregated results.
Templates can use survey_test_max_points to retrieve the maximum score and
the survey_any_correct_answer and survey_any_wrong_answer filters when
rendering answer feedback.
Editing submitted answers
The survey_multiple resource property controls repeat submissions and edits:
0means one final submission; it cannot be edited by the respondent.1allows multiple submissions, each stored as a new answer.2allows one submission and lets a logged-in respondent edit their own stored answer.
People who can edit the survey resource can edit any of its saved answers by
answer id. A participant can update only their own answer, and only in mode 2.
Anonymous respondents cannot edit a final submission in this mode. These checks
are made server-side with the update_result ACL action; hiding an edit button
is not the access control.
m_survey:replace_survey_submission/4 recalculates the test score and updates
the answer's modified and modifier_id fields. The submitted date is set
when a new answer is stored. On an edit it is refreshed only when the current
user owns the saved answer; an editor changing somebody else's answer leaves
the original submitted date intact.
Saving intermediate progress is separate from editing a submitted answer. Also
note that edit-after-submit and submission-count limits depend on the selected
survey handler storing results in survey_answers.
Editor-only questions
Set is_editor_only on a question block when only people with edit permission
on the survey should supply that answer. Editors see the normal input and can
change it. A non-editor sees the question in read-only form, including its
prompt and explanation, and also sees the stored answer when one is present.
This restriction is enforced in both the form flow and the storage layer. Submitted values for editor-only questions are discarded for non-editors, including the expanded input names used by narrative and matching questions. When a non-editor updates an answer, any existing editor-only values are copied from the stored answer instead of being overwritten. An editor-only question marked required is not considered missing for a non-editor. When an editor uses Save & Email, editor-only answers are included in the respondent email even if the survey's normal confirmation settings omit open or all answers.
Answer status
Every saved answer has optional workflow metadata, separate from the answer audit fields:
status- a non-negative numeric status index, orundefinedfor no status. The bundled interface presents status values 0 through 5 as color swatches.status_date- UTC date and time of the last status change.status_note- an optional internal note. It is trimmed and limited to 65,536 Unicode characters; longer input is truncated safely.status_modifier_id- the user who last changed the status.
Use m_survey:set_answer_status/5 to replace all four status fields together.
The answer id must belong to the supplied survey, and the current user must be
allowed to edit that survey. Changing status does not update modified or
modifier_id, because those fields describe changes to the submitted answers.
Status is internal editor information. m_survey:single_result/3 and
single_result/4 remove all status fields when the current user cannot edit the
survey. The read-only _survey_answer_status.tpl and the editable
_survey_answer_status_edit.tpl apply the same editor check. The latter is
included by _dialog_survey_answer_status.tpl, which handles saving through
the survey_answer_status submit event.
_dialog_survey_result_view.tpl shows an entire saved result without paging.
For editors it combines the status fields with editable editor-only questions;
all respondent answers are read-only and unanswered respondent questions are
omitted. Its survey_result_view_save event accepts only status and
editor-only values. Both this view and the final page of the full paged editor
offer Save & Email; the extra mail is sent only after the same server-side
answer-edit permission check as a normal save. Post-submit content such as the
reserved survey_feedback block, and resultless survey flow-control blocks,
are omitted from the saved-answer view.
Both status templates accept an optional status_labels list for values 0
through 5. Without labels they show only the color swatches. For example:
{% include "_survey_answer_status.tpl"
id=id
answer_id=answer_id
status_labels=[_"New", _"Accepted", _"Rejected"]
%}
Intercepting survey submissions
When a survey is submitted, the module sends a first #survey_submit{}
notification with these fields:
id- id of the submitted survey.handler- selected handler name, described below.answers- normalized answers.missing- names of required answers that were missing.answers_raw- unprocessed submitted values.
An observer can handle a submission by returning ok:
observe_survey_submit(#survey_submit{id = SurveyId}, Context) ->
?DEBUG(SurveyId),
ok.
Creating a custom survey handler
The survey edit page has a dropdown of survey handlers. A handler is a survey
resource property that selects how a submission is processed. Handlers are
collected with the #survey_get_handlers{} fold notification:
observe_survey_get_handlers(#survey_get_handlers{}, All, Context) ->
[
{<<"email_me">>,
?__(<<"E-mail me when the survey is submitted">>, Context)}
| All
].
The selected value is passed in the handler field of #survey_submit{}. An
observer should match its handler and return undefined for the others:
observe_survey_submit(
#survey_submit{handler = <<"email_me">>, id = SurveyId},
Context) ->
%% Handle and, if desired, store this submission.
ok;
observe_survey_submit(#survey_submit{}, _Context) ->
undefined.
Configuration keys
The result editor can link an answer to a newly created person. Its category and content group are configured with:
mod_survey.person_category, defaultperson.mod_survey.person_content_group, defaultdefault_content_group. If empty, the active ACL module selects the default content group.
Accepted events
This module handles the following notifier callbacks:
observe_acl_is_allowed/2checks view, update, delete, and MQTT access for survey answers.observe_admin_edit_blocks/3adds the survey question blocks to the editor.observe_admin_rscform/3normalizes page jumps into page-break blocks.observe_export_resource_filename/2,observe_export_resource_header/2, andobserve_export_resource_data/2provide the survey results download.observe_rsc_merge/2moves answers from a merged resource to the winner.observe_survey_get_handlers/3adds built-in survey handlers.observe_survey_is_submit/2checks whether a block submits the survey.observe_survey_submit/2processes submissions for built-in handlers.observe_tick_24h/2removes expired intermediate survey results.
Delegate callbacks handled by event/2 include the survey_start,
survey_back, survey_remove_result, and survey_remove_result_confirm
postbacks, and the survey_next, survey_answer_status, and
survey_result_view_save submit events.