requireLogin();
$app->sslOn();
require_once 'codebase/lib/PageNumbers.inc.php';
require_once 'codebase/lib/Cache.inc.php';
require_once 'codebase/lib/SortOrder.inc.php';
require_once 'codebase/lib/HTML.inc.php';
require_once 'models/Question.inc.php';
/********************************************************************
* CONFIG
********************************************************************/
// Titles and navigation header.
if (getFormData('filter_survey_id')) {
$s = Survey::get(array('survey_id' => getFormData('filter_survey_id')));
$nav->add(sprintf(_("Questions in %s"), $s['survey_name']), null);
} else {
$nav->add(_("Questions"), null);
}
// Instantiate a sorting object with the default sort and order. Add SQL for each column.
$so = new SortOrder('question_tbl.rank', 'ASC');
$so->asc_widget = '';
$so->desc_widget = '';
$so->setColumn('question_tbl.question_id', 'question_tbl.question_id ASC', 'question_tbl.question_id DESC');
$so->setColumn('question_tbl.rank', 'question_tbl.rank ASC, question_tbl.question_id ASC', 'question_tbl.rank DESC, question_tbl.question_id DESC');
$so->setColumn('question_tbl.question_text', 'question_tbl.question_text ASC', 'question_tbl.question_text DESC');
$so->setColumn('question_tbl.auto_continue', 'question_tbl.auto_continue ASC', 'question_tbl.auto_continue DESC');
$so->setColumn('question_tbl.added_datetime', 'question_tbl.added_datetime ASC', 'question_tbl.added_datetime DESC');
$so->setColumn('question_tbl.added_by_user_id', 'question_tbl.added_by_user_id ASC', 'question_tbl.added_by_user_id DESC');
$so->setColumn('question_tbl.modified_datetime', 'question_tbl.modified_datetime ASC', 'question_tbl.modified_datetime DESC');
$so->setColumn('question_tbl.modified_by_user_id', 'question_tbl.modified_by_user_id ASC', 'question_tbl.modified_by_user_id DESC');
// Instantiate page numbers. Total items are set and calculation is done in the getList method.
$page = new PageNumbers();
$page->setPerPage(getFormData('per_page'), 100);
$page->setPageNumber(getFormData('page_number'));
// Query parameters to retain always.
$app->carryQuery(array(
'filter_survey_id',
));
// Query parameters to retain only locally.
$locally_carried_queries = array(
'q',
'filter_survey_id',
'survey_id',
);
/********************************************************************
* MAIN
********************************************************************/
// We may want to use the add/edit interface from another script, so this
// allows us to remember which page we came from so we can go back there.
if (getFormData('boomerang', false) && isset($_SERVER['HTTP_REFERER'])) {
$app->setBoomerangURL($_SERVER['HTTP_REFERER'], 'question');
}
if (getFormData('break_list_cache', false)) {
// Remove any stale cached list data.
$cache->delete('question list');
}
// What action to take.
switch (getFormData('op')) {
case 'add' :
// Bounce the user if they don't have permission to create a record.
Question::requireAllow('create');
// Initialize variables for the form template.
$frm = getAddFields(getFormData('survey_id', getFormData('filter_survey_id')));
$nav->add(_("Add new question"));
$main_template = 'question_form.inc.html';
break;
case 'edit' :
// Bounce the user if they don't have permission to update a record.
Question::requireAllow('update');
// Initialize variables for the form template.
$frm = getEditFields(getFormData('question_id'));
if ('' != $frm['sent_datetime']) {
// Forbid editing if this question has been sent to anyone.
$app->raiseMsg(sprintf(_("That question was sent on %s. To ensure the question matches the responses, editing is disabled for sent messages."), date($app->getParam('date_format'), strtotime($frm['sent_datetime']))), MSG_NOTICE, __FILE__, __LINE__);
$app->dieBoomerangURL('question', $locally_carried_queries);
}
$nav->add(sprintf(_("Edit Question %s"), $frm['rank']));
$main_template = 'question_form.inc.html';
break;
case 'del' :
$app->requireValidCSRFToken();
// Bounce the user if they don't have permission to delete the specified record.
Question::requireAllow('delete', Question::get(array('question_id' => getFormData('question_id')), 1));
if ($del_row = Question::get(array('question_id' => getFormData('question_id')), 1)) {
Question::delete(getFormData('question_id'));
$app->raiseMsg(sprintf(_("The question %s has been deleted."), $del_row['question_text']), MSG_SUCCESS, __FILE__, __LINE__);
}
if ($app->validBoomerangURL('question')) {
// Display boomerang page.
$app->dieBoomerangURL('question', $locally_carried_queries);
}
// Display default page.
$app->dieURL($_SERVER['PHP_SELF'], $locally_carried_queries);
break;
case 'insert' :
$app->requireValidCSRFToken();
if (getFormData('account_id')) {
// Bounce the user if they don't have permission to create a record under the specified account_id.
Question::requireAllow('create', array(array('account_id' => getFormData('account_id'))));
} else {
// Bounce the user if they don't have permission to create a record at all.
Question::requireAllow('create');
}
if (getFormdata('btn_cancel', false)) {
if ($app->validBoomerangURL('question')) {
// Display boomerang page.
$app->dieBoomerangURL('question', $locally_carried_queries);
}
// Display default page.
$app->dieURL($_SERVER['PHP_SELF'], $locally_carried_queries);
}
$fv = validateInput($fv);
if ($fv->anyErrors()) {
$frm = getAddFields(getFormData('survey_id', getFormData('filter_survey_id')));
$frm = array_merge($frm, getFormData());
$nav->add(_("Add new question"));
$main_template = 'question_form.inc.html';
} else {
$question_id = Question::insert(getFormData());
$app->raiseMsg(sprintf(_("The question %s has been added."), getFormData('question_text')), MSG_SUCCESS, __FILE__, __LINE__);
if (getFormdata('btn_repeat', false)) {
// Display function again.
$app->dieURL($_SERVER['PHP_SELF'] . '?op=add', $locally_carried_queries);
} else if ($app->validBoomerangURL('question')) {
// Display boomerang page.
$app->dieBoomerangURL('question', $locally_carried_queries);
}
// Display default page.
$app->dieURL($_SERVER['PHP_SELF'], $locally_carried_queries);
}
break;
case 'update' :
$app->requireValidCSRFToken();
if (getFormData('account_id')) {
// Bounce the user if they don't have permission to update the specified record or don't have permission to assign this record to the specified account_id.
$check_rows = array_merge(Question::get(array('question_id' => getFormData('question_id')), 1), array(array('account_id' => getFormData('account_id'))));
Question::requireAllow('update', $check_rows);
} else {
// Bounce the user if they don't have permission to update the specified record.
Question::requireAllow('update', Question::get(array('question_id' => getFormData('question_id')), 1));
}
if (getFormdata('btn_reset', false)) {
$app->raiseMsg(_("Saved values have been reloaded."), MSG_NOTICE, __FILE__, __LINE__);
$app->dieURL($_SERVER['PHP_SELF'] . '?op=edit&question_id=' . getFormData('question_id'), $locally_carried_queries);
}
if (getFormdata('btn_cancel', false)) {
// Remove lock
$lock->select('question_tbl', 'question_id', getFormData('question_id'));
$lock->remove();
if ($app->validBoomerangURL('question')) {
// Display boomerang page.
$app->dieBoomerangURL('question', $locally_carried_queries);
}
// Display default page.
$app->dieURL($_SERVER['PHP_SELF'], $locally_carried_queries);
}
$fv = validateInput($fv);
if ($fv->anyErrors()) {
$frm = getEditFields(getFormData('question_id'));
$frm = array_merge($frm, getFormData());
$nav->add(sprintf(_("Edit Question %s"), $frm['rank']));
$main_template = 'question_form.inc.html';
} else {
Question::update(getFormData());
$app->raiseMsg(sprintf(_("The question %s has been updated."), getFormData('question_text')), MSG_SUCCESS, __FILE__, __LINE__);
if (getFormdata('btn_repeat', false)) {
// Display edit function with next available ID.
$qid = $db->query("SELECT question_id FROM question_tbl WHERE question_id > '" . $db->escapeString(getFormData('question_id')) . "' ORDER BY question_id ASC LIMIT 1");
if (list($next_id) = mysql_fetch_row($qid)) {
$app->dieURL($_SERVER['PHP_SELF'] . '?op=edit&question_id=' . $next_id, $locally_carried_queries);
} else {
$app->raiseMsg(_("Cannot edit next, the end of the list was reached"), MSG_NOTICE, __FILE__, __LINE__);
}
} else if ($app->validBoomerangURL('question')) {
// Display boomerang page.
$app->dieBoomerangURL('question', $locally_carried_queries);
}
// Display default page.
$app->dieURL($_SERVER['PHP_SELF'], $locally_carried_queries);
}
break;
default :
// Bounce the user if they don't have permission to list records.
Question::requireAllow('read');
// If the user does not have access to 'any' record, limit by their account_id.
$where_clause = '';
if (!$acl->check('user_id:' . $auth->get('user_id'), 'question:read', 'any')) {
$where_clause = "WHERE question_tbl.account_id = '" . $db->escapeString($auth->get('account_id')) . "'";
}
$list = Question::getPaginatedList($where_clause);
$main_template = 'question_list.inc.html';
break;
}
/********************************************************************
* OUTPUT
********************************************************************/
include 'header.inc.html';
$app->carryQuery($locally_carried_queries);
include $main_template;
include 'footer.inc.html';
/********************************************************************
* FUNCTIONS
********************************************************************/
/*
*
*
* @access public
* @param
* @return
* @author Quinn Comendant
* @version 1.0
* @since 16 Nov 2014 17:45:40
*/
function validateInput($fv)
{
$fv->numericRange('question_id', 0, 16777215, sprintf(_("%s must be a number between %d and %d."), _("Question ID"), 0, 16777215));
$fv->isInteger('question_id', sprintf(_("%s must be an integer."), _("Question ID")));
$fv->notEmpty('survey_id', sprintf(_("%s cannot be blank."), _("Survey")));
$fv->numericRange('survey_id', 0, 16777215, sprintf(_("%s must be a number between %d and %d."), _("Survey"), 0, 16777215));
$fv->isInteger('survey_id', sprintf(_("%s must be an integer."), _("Survey")));
$fv->notEmpty('question_text', sprintf(_("%s cannot be blank."), _("Question text")));
$fv->stringLength('question_text', 0, 160, sprintf(_("%s must be %d-to-%d characters in length."), _("Question text"), 0, 160));
$q_parsed = $fv->checkQuestion();
if ('statement' == $q_parsed['type']) {
$fv->notEmpty('auto_continue', sprintf(_("Please confirm you intend this to be a statement rather than a question."), null));
}
return $fv;
}
/*
*
*
* @access public
* @param
* @return
* @author Quinn Comendant
* @version 1.0
* @since 16 Nov 2014 17:45:40
*/
function getAddFields($survey_id)
{
global $db;
// Get the last used rank, to increment for this question.
$qid = $db->query("
SELECT question_tbl.rank
FROM question_tbl
WHERE question_tbl.survey_id = '" . $db->escapeString($survey_id) . "'
ORDER BY question_tbl.rank DESC
LIMIT 1
");
if (mysql_num_rows($qid) == 0) {
$last_rank = 0;
} else {
list($last_rank) = mysql_fetch_row($qid);
}
// Set default values for the reset of the fields.
return Question::merge(array(
'new_op' => 'insert',
'survey_id' => getFormData('survey_id', getFormData('filter_survey_id')),
'rank' => $last_rank + 1,
'submit_buttons' => array(
array('name' => 'btn_submit', 'value' => _("Add new question"), 'class' => 'small button', 'accesskey' => 's'),
array('name' => 'btn_repeat', 'value' => _("Add & repeat"), 'class' => 'small button secondary', 'accesskey' => 'r'),
array('name' => 'btn_cancel', 'value' => _("Cancel"), 'class' => 'small button secondary', 'accesskey' => 'c'),
),
));
}
/*
*
*
* @access public
* @param
* @return
* @author Quinn Comendant
* @version 1.0
* @since 16 Nov 2014 17:45:40
*/
function getEditFields($id)
{
global $lock, $locally_carried_queries;
$db =& DB::getInstance();
$app =& App::getInstance();
$lock->select('question_tbl', 'question_id', $id);
if ($lock->isLocked() && !$lock->isMine()) {
$lock->dieErrorPage();
}
// Get the information for the form.
$db->query("SET SESSION group_concat_max_len = 32000");
$qid = $db->query("
SELECT
question_tbl.*,
GROUP_CONCAT(question_action_tbl.question_option ORDER BY question_action_tbl.question_option ASC SEPARATOR '|') AS options_concat,
GROUP_CONCAT(question_action_tbl.question_action ORDER BY question_action_tbl.question_option ASC SEPARATOR '|') AS actions_concat,
GROUP_CONCAT(question_action_tbl.target_question_id ORDER BY question_action_tbl.question_option ASC SEPARATOR '|') AS targets_concat,
participant_question_tbl.sent_datetime
FROM question_tbl
LEFT JOIN question_action_tbl ON (question_tbl.question_id = question_action_tbl.question_id)
LEFT JOIN participant_question_tbl ON (question_tbl.question_id = participant_question_tbl.question_id)
WHERE question_tbl.question_id = '" . $db->escapeString($id) . "'
GROUP BY question_tbl.question_id
");
if (!$frm = mysql_fetch_assoc($qid)) {
$app->logMsg('Could not find record with question_id: ' . $id, LOG_WARNING, __FILE__, __LINE__);
$app->raiseMsg(sprintf(_("The requested record %s could not be found."), $id), MSG_ERR, __FILE__, __LINE__);
$app->dieBoomerangURL('question', $locally_carried_queries);
}
// Process preselected options.
$options = array();
$actions = explode('|', $frm['actions_concat']);
$targets = explode('|', $frm['targets_concat']);
foreach (explode('|', $frm['options_concat']) as $i => $o) {
$options[$o] = array(
'action' => isset($actions[$i]) ? $actions[$i] : '',
'target' => isset($targets[$i]) ? $targets[$i] : '',
);
}
// Lock this record.
$lock->set('question_tbl', 'question_id', $id, $frm['question_text']);
// Set misc values for the form.
return Question::merge(array(
'new_op' => 'update',
'submit_buttons' => array(
array('name' => 'btn_submit', 'value' => _("Save changes"), 'class' => 'small button', 'accesskey' => 's'),
array('name' => 'btn_repeat', 'value' => _("Save & edit next"), 'class' => 'small button secondary', 'accesskey' => 'e'),
array('name' => 'btn_reset', 'value' => _("Reset"), 'class' => 'small button secondary', 'accesskey' => 'r'),
array('name' => 'btn_cancel', 'value' => _("Cancel"), 'class' => 'small button secondary', 'accesskey' => 'c'),
),
), $frm);
}