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); }