diff --git a/application/controllers/admin/export.php b/application/controllers/admin/export.php index fe324d0e67b..11a56d6f6fa 100644 --- a/application/controllers/admin/export.php +++ b/application/controllers/admin/export.php @@ -186,7 +186,7 @@ public function exportresults() $data['excesscols'] = $aFieldMap; //get max number of datasets - $iMaximum = Yii::app()->db->createCommand("SELECT count(id) FROM {{survey_".intval($iSurveyID)."}}")->queryScalar(); + $iMaximum = SurveyDynamic::model($iSurveyID)->getMaxId(); $data['max_datasets'] = $iMaximum; $data['surveyid'] = $iSurveyID; diff --git a/application/controllers/admin/remotecontrol.php b/application/controllers/admin/remotecontrol.php index a7c81949919..bba4c7f4422 100644 --- a/application/controllers/admin/remotecontrol.php +++ b/application/controllers/admin/remotecontrol.php @@ -28,6 +28,7 @@ class remotecontrol extends Survey_Common_Action */ public function run() { + Yii::import('application.helpers.remotecontrol.*'); $oHandler=new remotecontrol_handle($this->controller); $RPCType=Yii::app()->getConfig("RPCInterface"); if (Yii::app()->getRequest()->isPostRequest) { @@ -159,2346 +160,4 @@ public function test() } -} -/** -* This class handles all methods of the RPCs -*/ -class remotecontrol_handle -{ - /** - * @var AdminController - */ - protected $controller; - - /** - * Constructor, stores the action instance into this handle class - * - * @access public - * @param AdminController $controller - * @return void - */ - public function __construct(AdminController $controller) - { - $this->controller = $controller; - } - - - /** - * RPC routine to create a session key. - * - * @access public - * @param string $username - * @param string $password - * @return string - */ - public function get_session_key($username, $password) - { - if ($this->_doLogin($username, $password)) - { - $this->_jumpStartSession($username); - $sSessionKey = randomChars(32); - - $session = new Session; - $session->id = $sSessionKey; - $session->expire = time() + Yii::app()->getConfig('iSessionExpirationTime'); - $session->data = $username; - $session->save(); - - return $sSessionKey; - } - else - return array('status' => 'Invalid user name or password'); - } - - /** - * Closes the RPC session - * - * @access public - * @param string $sSessionKey - * @return string - */ - public function release_session_key($sSessionKey) - { - Session::model()->deleteAllByAttributes(array('id' => $sSessionKey)); - $criteria = new CDbCriteria; - $criteria->condition = 'expire < ' . time(); - Session::model()->deleteAll($criteria); - return 'OK'; - } - - /** - * RPC Routine to get settings. - * - * @access public - * @param string $sSessionKey Auth Credentials - * @param string $sSetttingName Name of the setting to get - * @return string The requested value - */ - public function get_site_settings($sSessionKey,$sSetttingName) - { - if ($this->_checkSessionKey($sSessionKey)) - { - if(Permission::model()->hasGlobalPermission('superadmin','read')) - { - if (Yii::app()->getConfig($sSetttingName) !== false) - return Yii::app()->getConfig($sSetttingName); - else - return array('status' => 'Invalid setting'); - } - else - return array('status' => 'Invalid setting'); - } - else - return array('status' => 'Invalid session key'); - } - - - /* Survey specific functions */ - - /** - * RPC Routine to add an empty survey with minimum details. - * Used as a placeholder for importing groups and/or questions. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID The wish id of the Survey to add - * @param string $sSurveyTitle Title of the new Survey - * @param string $sSurveyLanguage Default language of the Survey - * @param string $sformat Question appearance format - * @return array|string|int - */ - public function add_survey($sSessionKey, $iSurveyID, $sSurveyTitle, $sSurveyLanguage, $sformat = 'G') - { - Yii::app()->loadHelper("surveytranslator"); - if ($this->_checkSessionKey($sSessionKey)) - { - if (Permission::model()->hasGlobalPermission('surveys','create')) - { - if( $sSurveyTitle=='' || $sSurveyLanguage=='' || !array_key_exists($sSurveyLanguage,getLanguageDataRestricted()) || !in_array($sformat, array('A','G','S'))) - return array('status' => 'Faulty parameters'); - - $aInsertData = array('template' => 'default', - 'owner_id' => Yii::app()->session['loginID'], - 'active' => 'N', - 'language'=>$sSurveyLanguage, - 'format' => $sformat - ); - - if (!is_null($iSurveyID)) - $aInsertData['wishSID'] = $iSurveyID; - - try - { - $iNewSurveyid = Survey::model()->insertNewSurvey($aInsertData); - if (!$iNewSurveyid) - return array('status' => 'Creation Failed'); - - $sTitle = html_entity_decode($sSurveyTitle, ENT_QUOTES, "UTF-8"); - - // Load default email templates for the chosen language - $oLanguage = new Limesurvey_lang($sSurveyLanguage); - $aDefaultTexts = templateDefaultTexts($oLanguage, 'unescaped'); - unset($oLanguage); - - $bIsHTMLEmail = false; - - $aInsertData = array( - 'surveyls_survey_id' => $iNewSurveyid, - 'surveyls_title' => $sTitle, - 'surveyls_language' => $sSurveyLanguage, - ); - - $langsettings = new SurveyLanguageSetting; - $langsettings->insertNewSurvey($aInsertData); - Permission::model()->giveAllSurveyPermissions(Yii::app()->session['loginID'], $iNewSurveyid); - - return (int)$iNewSurveyid; - } - catch(Exception $e) - { - return array('status' => $e->getmessage()); - } - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid session key'); - } - - /** - * RPC Routine to delete a survey. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID The id of the Survey to be deleted - * @return array Returns Status - */ - public function delete_survey($sSessionKey, $iSurveyID) - { - if ($this->_checkSessionKey($sSessionKey)) - { - if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'delete')) - { - Survey::model()->deleteSurvey($iSurveyID,true); - return array('status' => 'OK'); - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid session key'); - } - - /** - * RPC Routine to import a survey - imports lss,csv,xls or survey zip archive. - * - * @access public - * @param string $sSessionKey Auth Credentials - * @param string $sImportData String containing the BASE 64 encoded data of a lss,csv,xls or survey zip archive - * @param string $sImportDataType lss,csv,xls or zip - * @param string $sNewSurveyName The optional new name of the survey - * @param integer $DestSurveyID This is the new ID of the survey - if already used a random one will be taken instead - * @return array|integer iSurveyID - ID of the new survey - */ - public function import_survey($sSessionKey, $sImportData, $sImportDataType, $sNewSurveyName=NULL, $DestSurveyID=NULL) - { - if ($this->_checkSessionKey($sSessionKey)) - { - if (Permission::model()->hasGlobalPermission('surveys','create')) - { - if (!in_array($sImportDataType,array('zip','csv','xls','lss'))) return array('status' => 'Invalid extension'); - Yii::app()->loadHelper('admin/import'); - // First save the data to a temporary file - $sFullFilePath = Yii::app()->getConfig('tempdir') . DIRECTORY_SEPARATOR . randomChars(40).'.'.$sImportDataType; - file_put_contents($sFullFilePath,base64_decode(chunk_split($sImportData))); - $aImportResults = importSurveyFile($sFullFilePath, true, $sNewSurveyName, $DestSurveyID); - unlink($sFullFilePath); - if (isset($aImportResults['error'])) return array('status' => 'Error: '.$aImportResults['error']); - else - { - return (int)$aImportResults['newsid']; - } - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid session key'); - } - - /** - * RPC Routine to get survey properties. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID The id of the Survey to be checked - * @param array $aSurveySettings The properties to get - * @return array - */ - public function get_survey_properties($sSessionKey,$iSurveyID, $aSurveySettings) - { - Yii::app()->loadHelper("surveytranslator"); - if ($this->_checkSessionKey($sSessionKey)) - { - $oSurvey = Survey::model()->findByPk($iSurveyID); - if (!isset($oSurvey)) - { - return array('status' => 'Error: Invalid survey ID'); - } - if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'read')) - { - $aBasicDestinationFields=Survey::model()->tableSchema->columnNames; - $aSurveySettings=array_intersect($aSurveySettings,$aBasicDestinationFields); - - if (empty($aSurveySettings)) - return array('status' => 'No valid Data'); - $aResult = array(); - foreach($aSurveySettings as $sPropertyName) - { - $aResult[$sPropertyName]=$oSurvey->$sPropertyName; - } - return $aResult; - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid Session key'); - } - - /** - * RPC Routine to set survey properties. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param integer $iSurveyID - ID of the survey - * @param array|struct $aSurveyData - An array with the particular fieldnames as keys and their values to set on that particular survey - * @return array Of succeeded and failed nodifications according to internal validation. - */ - public function set_survey_properties($sSessionKey, $iSurveyID, $aSurveyData) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $oSurvey=Survey::model()->findByPk($iSurveyID); - if (is_null($oSurvey)) - { - return array('status' => 'Error: Invalid survey ID'); - } - if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'update')) - { - // Remove fields that may not be modified - unset($aSurveyData['sid']); - unset($aSurveyData['owner_id']); - unset($aSurveyData['active']); - unset($aSurveyData['language']); - unset($aSurveyData['additional_languages']); - // Remove invalid fields - $aDestinationFields=array_flip(Survey::model()->tableSchema->columnNames); - $aSurveyData=array_intersect_key($aSurveyData,$aDestinationFields); - $oSurvey=Survey::model()->findByPk($iSurveyID); - $aBasicAttributes = $oSurvey->getAttributes(); - $aResult = array(); - - if ($oSurvey->active=='Y') - { - // remove all fields that may not be changed when a survey is active - unset($aSurveyData['anonymized']); - unset($aSurveyData['datestamp']); - unset($aSurveyData['savetimings']); - unset($aSurveyData['ipaddr']); - unset($aSurveyData['refurl']); - } - - if (empty($aSurveyData)) - return array('status' => 'No valid Data'); - - foreach($aSurveyData as $sFieldName=>$sValue) - { - $oSurvey->$sFieldName=$sValue; - try - { - $bSaveResult=$oSurvey->save(); // save the change to database - //unset the value if it fails, so as to prevent future fails - $aResult[$sFieldName]=$bSaveResult; - if (!$bSaveResult) - $oSurvey->$sFieldName=$aBasicAttributes[$sFieldName]; - } - catch(Exception $e) - { - //unset the value that caused the exception - $oSurvey->$sFieldName=$aBasicAttributes[$sFieldName]; - } - } - return $aResult; - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid Session key'); - } - - /** - * RPC Routine to list the ids and info of surveys belonging to a user. - * Returns array of ids and info. - * If user is admin he can get surveys of every user (parameter sUser) or all surveys (sUser=null) - * Else only the syrveys belonging to the user requesting will be shown. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param string $sUser Optional username to get list of surveys - * @return array The list of surveys - */ - public function list_surveys($sSessionKey, $sUser=NULL) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $sCurrentUser = Yii::app()->session['user']; - - if( Permission::model()->hasGlobalPermission('superadmin','read') ) - { - if ($sUser == null) - $aUserSurveys = Survey::model()->findAll(); //list all surveys - else - { - $aUserData = User::model()->findByAttributes(array('users_name' => $sUser)); - if (!isset($aUserData)) - return array('status' => 'Invalid user'); - else - $aUserSurveys = Survey::model()->findAllByAttributes(array("owner_id"=>$aUserData->attributes['uid'])); - } - } - else - { - if (($sCurrentUser == $sUser) || ($sUser == null) ) - { - $sUid = User::model()->findByAttributes(array('users_name' => $sCurrentUser))->uid; - $aUserSurveys = Survey::model()->findAllByAttributes(array("owner_id"=>$sUid)); - } - else - return array('status' => 'No permission'); - } - - if(count($aUserSurveys)==0) - return array('status' => 'No surveys found'); - - foreach ($aUserSurveys as $oSurvey) - { - $oSurveyLanguageSettings = SurveyLanguageSetting::model()->findByAttributes(array('surveyls_survey_id' => $oSurvey->primaryKey, 'surveyls_language' => $oSurvey->language)); - if (!isset($oSurveyLanguageSettings)) - $aSurveyTitle = ''; - else - $aSurveyTitle = $oSurveyLanguageSettings->attributes['surveyls_title']; - $aData[]= array('sid'=>$oSurvey->primaryKey,'surveyls_title'=>$aSurveyTitle,'startdate'=>$oSurvey->attributes['startdate'],'expires'=>$oSurvey->attributes['expires'],'active'=>$oSurvey->attributes['active']); - } - return $aData; - } - else - return array('status' => 'Invalid session key'); - } - - - - /** - * RPC Routine that launches a newly created survey. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID The id of the survey to be activated - * @return array The result of the activation - */ - public function activate_survey($sSessionKey, $iSurveyID) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $oSurvey=Survey::model()->findByPk($iSurveyID); - if (is_null($oSurvey)) - return array('status' => 'Error: Invalid survey ID'); - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveyactivation', 'update')) - { - Yii::app()->loadHelper('admin/activate'); - $aActivateResults = activateSurvey($iSurveyID); - - if (isset($aActivateResults['error'])) return array('status' => 'Error: '.$aActivateResults['error']); - else - { - return $aActivateResults; - } - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid session key'); - } - - /** - * RPC routine to export statistics of a survey to a user. - * Returns string - base64 encoding of the statistics. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Id of the Survey - * @param string $docType Type of documents the exported statistics should be - * @param string $sLanguage Optional language of the survey to use - * @param string $graph Create graph option - * @param int|array $groupIDs An OPTIONAL array (ot a single int) containing the groups we choose to generate statistics from - * @return string Base64 encoded string with the statistics file - */ - public function export_statistics($sSessionKey, $iSurveyID, $docType='pdf', $sLanguage=null, $graph='0', $groupIDs=null) - { - Yii::app()->loadHelper('admin/statistics'); - - $tempdir = Yii::app()->getConfig("tempdir"); - if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key'); - - $oSurvey = Survey::model()->findByPk($iSurveyID); - if (!isset($oSurvey)) - return array('status' => 'Error: Invalid survey ID');; - - if(Survey::model()->findByPk($iSurveyID)->owner_id != $_SESSION['loginID']) - return array('status' => 'Error: No Permission'); - $aAdditionalLanguages = array_filter(explode(" ", $oSurvey->additional_languages)); - - if (is_null($sLanguage)|| !in_array($sLanguage,$aAdditionalLanguages)) - $sLanguage = $oSurvey->language; - - $oAllQuestions =Question::model()->getQuestionList($iSurveyID, $sLanguage); - if (!isset($oAllQuestions)) - return array('status' => 'No available data'); - - if($groupIDs!=null) - { - if(is_int($groupIDs)) - $groupIDs = array($groupIDs); - - if(is_array($groupIDs)) - { - //check that every value of the array belongs to the survey defined - $aGroups = QuestionGroup::model()->findAllByAttributes(array('sid' => $iSurveyID)); - - foreach( $aGroups as $group) - $validGroups[] = $group['gid']; - - $groupIDs=array_intersect($groupIDs,$validGroups); - - if (empty($groupIDs)) - return array('status' => 'Error: Invalid group ID'); - - foreach($oAllQuestions as $key => $aQuestion) - { - if(!in_array($aQuestion['gid'],$groupIDs)) - unset($oAllQuestions[$key]); - } - } - else - return array('status' => 'Error: Invalid group ID'); - } - - if (!isset($oAllQuestions)) - return array('status' => 'No available data'); - - usort($oAllQuestions, 'groupOrderThenQuestionOrder'); - - $aSummary = createCompleteSGQA($iSurveyID,$oAllQuestions,$sLanguage); - - $helper = new statistics_helper(); - switch ($docType) - { - case 'pdf': - $sTempFile = $helper->generate_statistics($iSurveyID,$aSummary,$aSummary,$graph,$docType,'F',$sLanguage); - $sResult = file_get_contents($sTempFile); - unlink($sTempFile); - break; - case 'xls': - $sTempFile = $helper->generate_statistics($iSurveyID,$aSummary,$aSummary,'0',$docType, 'F',$sLanguage); - $sResult = file_get_contents($sTempFile); - unlink($sTempFile); - break; - case 'html': - $sResult = $helper->generate_statistics($iSurveyID,$aSummary,$aSummary,'0',$docType, 'DD',$sLanguage); - break; - } - - return base64_encode($sResult); - - } - -/** - * RPC Routine to export submission timeline. - * Returns an array of values (count and period) - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Id of the Survey - * @param string $sType (day|hour) - * @param string $dStart - * @param string $dEnd - * @return array On success: The timeline. On failure array with error information - * */ - public function export_timeline($sSessionKey, $iSurveyID, $sType, $dStart, $dEnd) - { - if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key'); - if (!in_array($sType, array('day','hour'))) return array('status' => 'Invalid Period'); - if (!hasSurveyPermission($iSurveyID, 'responses', 'read')) return array('status' => 'No permission'); - $oSurvey=Survey::model()->findByPk($iSurveyID); - if (is_null($oSurvey)) return array('status' => 'Error: Invalid survey ID'); - if (!tableExists('{{survey_' . $iSurveyID . '}}')) return array('status' => 'No available data'); - - $oResponses = SurveyDynamic::model($iSurveyID)->timeline($sType, $dStart, $dEnd); - if (empty($oResponses)) return array('status' => 'No valid Data'); - - return $oResponses; - - } - - /** - * RPC routine to get survey summary, regarding token usage and survey participation. - * Returns the requested value as string. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Id of the Survey to get summary - * @param string $sStatName Name of the sumamry option - * @return string The requested value - */ - public function get_summary($sSessionKey,$iSurveyID, $sStatName) - { - $aPermittedStats = array(); - if ($this->_checkSessionKey($sSessionKey)) - { - $aPermittedTokenStats = array('token_count', - 'token_invalid', - 'token_sent', - 'token_opted_out', - 'token_completed' - ); - $aPermittedSurveyStats = array('completed_responses', - 'incomplete_responses', - 'full_responses' - ); - $aPermittedStats = array_merge($aPermittedSurveyStats, $aPermittedTokenStats); - $oSurvey = Survey::model()->findByPk($iSurveyID); - if (!isset($oSurvey)) - return array('status' => 'Invalid surveyid'); - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'read')) - { - if(in_array($sStatName, $aPermittedTokenStats)) - { - if (tableExists('{{tokens_' . $iSurveyID . '}}')) - $summary = TokenDynamic::model($iSurveyID)->summary(); - else - return array('status' => 'No available data'); - } - - if(in_array($sStatName, $aPermittedSurveyStats) && !tableExists('{{survey_' . $iSurveyID . '}}')) - return array('status' => 'No available data'); - - if (!in_array($sStatName, $aPermittedStats)) - return array('status' => 'No such property'); - - - switch($sStatName) - { - case 'token_count': - if (isset($summary)) - return $summary['tkcount']; - break; - case 'token_invalid': - if (isset($summary)) - return $summary['tkinvalid']; - break; - case 'token_sent': - if (isset($summary)) - return $summary['tksent']; - break; - case 'token_opted_out': - if (isset($summary)) - return $summary['tkoptout']; - break; - case 'token_completed'; - if (isset($summary)) - return $summary['tkcompleted']; - break; - case 'completed_responses': - return SurveyDynamic::model($iSurveyID)->count('submitdate IS NOT NULL'); - break; - case 'incomplete_responses': - return SurveyDynamic::model($iSurveyID)->countByAttributes(array('submitdate' => null)); - break; - case 'full_responses'; - return SurveyDynamic::model($iSurveyID)->count(); - break; - default: - return array('status' => 'Data is not available'); - } - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid session key'); - } - - /*Survey language specific functions */ - - /** - * RPC Routine to add a survey language. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param integer $iSurveyID ID of the survey where a token table will be created for - * @param string $sLanguage A valid language shortcut to add to the current survey. If the language already exists no error will be given. - * @return array Status=>OK when successfull, otherwise the error description - */ - public function add_language($sSessionKey, $iSurveyID, $sLanguage) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $oSurvey=Survey::model()->findByPk($iSurveyID); - if (is_null($oSurvey)) - { - return array('status' => 'Error: Invalid survey ID'); - } - if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'update')) - { - Yii::app()->loadHelper('surveytranslator'); - $aLanguages=getLanguageData(); - - if(!isset($aLanguages[$sLanguage])) - { - return array('status' => 'Invalid language'); - } - $oSurvey=Survey::model()->findByPk($iSurveyID); - if ($sLanguage==$oSurvey->language) - { - return array('status' => 'OK'); - } - $aLanguages=$oSurvey->getAdditionalLanguages(); - $aLanguages[]=$sLanguage; - $aLanguages=array_unique($aLanguages); - $oSurvey->additional_languages=implode(' ',$aLanguages); - try - { - $oSurvey->save(); // save the change to database - $languagedetails=getLanguageDetails($sLanguage); - - $insertdata = array( - 'surveyls_survey_id' => $iSurveyID, - 'surveyls_language' => $sLanguage, - 'surveyls_title' => '', - 'surveyls_dateformat' => $languagedetails['dateformat'] - ); - $setting= new SurveyLanguageSetting; - foreach ($insertdata as $k => $v) - $setting->$k = $v; - $setting->save(); - fixLanguageConsistency($iSurveyID,$sLanguage); - return array('status' => 'OK'); - } - catch(Exception $e) - { - return array('status' => 'Error'); - } - - } - else - return array('status' => 'No permission'); - } - } - - /** - * RPC Routine to delete a survey language. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param integer $iSurveyID ID of the survey where a token table will be created for - * @param string $sLanguage A valid language shortcut to delete from the current survey. If the language does not exist in that survey no error will be given. - * @return array Status=>OK when successfull, otherwise the error description - */ - public function delete_language($sSessionKey, $iSurveyID, $sLanguage) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $oSurvey=Survey::model()->findByPk($iSurveyID); - if (is_null($oSurvey)) - { - return array('status' => 'Error: Invalid survey ID'); - } - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'update')) - { - - Yii::app()->loadHelper('surveytranslator'); - $aLanguages=getLanguageData(); - - if(!isset($aLanguages[$sLanguage])) - { - return array('status' => 'Invalid language'); - } - $oSurvey=Survey::model()->findByPk($iSurveyID); - if ($sLanguage==$oSurvey->language) - { - return array('status' => 'Cannot remove base language'); - } - $aLanguages=$oSurvey->getAdditionalLanguages(); - unset($aLanguages[$sLanguage]); - $oSurvey->additional_languages=implode(' ',$aLanguages); - try - { - $oSurvey->save(); // save the change to database - SurveyLanguageSetting::model()->deleteByPk(array('surveyls_survey_id' => $iSurveyID, 'surveyls_language' => $sLanguage)); - cleanLanguagesFromSurvey($iSurveyID,$oSurvey->additional_languages); - return array('status' => 'OK'); - } - catch(Exception $e) - { - return array('status' => 'Error'); - } - - } - else - return array('status' => 'No permission'); - } - } - - - /** - * RPC Routine to get survey language properties. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Dd of the Survey - * @param array $aSurveyLocaleSettings Properties to get - * @param string $sLang Language to use - * @return array The requested values - */ - public function get_language_properties($sSessionKey,$iSurveyID, $aSurveyLocaleSettings, $sLang=NULL) - { - Yii::app()->loadHelper("surveytranslator"); - if ($this->_checkSessionKey($sSessionKey)) - { - $oSurvey = Survey::model()->findByPk($iSurveyID); - if (!isset($oSurvey)) - { - return array('status' => 'Error: Invalid survey ID'); - } - if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'read')) - { - $aBasicDestinationFields=SurveyLanguageSetting::model()->tableSchema->columnNames; - $aSurveyLocaleSettings=array_intersect($aSurveyLocaleSettings,$aBasicDestinationFields); - - if ($sLang == NULL || !array_key_exists($sLang,getLanguageDataRestricted())) - $sLang = $oSurvey->language; - - - $oSurveyLocale=SurveyLanguageSetting::model()->findByAttributes(array('surveyls_survey_id' => $iSurveyID, 'surveyls_language' => $sLang)); - $aResult = array(); - - if (empty($aSurveyLocaleSettings)) - return array('status' => 'No valid Data'); - - foreach($aSurveyLocaleSettings as $sPropertyName) - { - $aResult[$sPropertyName]=$oSurveyLocale->$sPropertyName; - //$aResult[$sPropertyName]=$aLangAttributes[$sPropertyName]; - } - return $aResult; - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid Session key'); - } - - /** - * RPC Routine to set survey language properties. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param integer $iSurveyID - ID of the survey - * @param array|struct $aSurveyLocaleData - An array with the particular fieldnames as keys and their values to set on that particular survey - * @param string $sLanguage - Optional - Language to update - if not give the base language of the particular survey is used - * @return array Status=>OK, when save successful otherwise error text. - */ - public function set_language_properties($sSessionKey, $iSurveyID, $aSurveyLocaleData, $sLanguage=NULL) - { - Yii::app()->loadHelper("surveytranslator"); - if ($this->_checkSessionKey($sSessionKey)) - { - $oSurvey=Survey::model()->findByPk($iSurveyID); - if (is_null($oSurvey)) - { - return array('status' => 'Error: Invalid survey ID'); - } - - if (is_null($sLanguage)) - { - $sLanguage=$oSurvey->language; - } - - if (!array_key_exists($sLanguage,getLanguageDataRestricted())) - return array('status' => 'Error: Invalid language'); - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveylocale', 'update')) - { - // Remove fields that may not be modified - unset($aSurveyLocaleData['surveyls_language']); - unset($aSurveyLocaleData['surveyls_survey_id']); - - // Remove invalid fields - $aDestinationFields=array_flip(SurveyLanguageSetting::model()->tableSchema->columnNames); - - $aSurveyLocaleData=array_intersect_key($aSurveyLocaleData,$aDestinationFields); - $oSurveyLocale = SurveyLanguageSetting::model()->findByPk(array('surveyls_survey_id' => $iSurveyID, 'surveyls_language' => $sLanguage)); - - $aLangAttributes = $oSurveyLocale->getAttributes(); - $aResult = array(); - - if (empty($aSurveyLocaleData)) - return array('status' => 'No valid Data'); - - foreach($aSurveyLocaleData as $sFieldName=>$sValue) - { - $oSurveyLocale->$sFieldName=$sValue; - try - { - // save the change to database - Every single change alone - to allow for validation to work - $bSaveResult=$oSurveyLocale->save(); - $aResult[$sFieldName]=$bSaveResult; - //unset failed values - if (!$bSaveResult) - $oSurveyLocale->$sFieldName=$aLangAttributes[$sFieldName]; - } - catch(Exception $e) - { - $oSurveyLocale->$sFieldName=$aLangAttributes[$sFieldName]; - } - } - $aResult['status'] = 'OK'; - return $aResult; - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid Session key'); - } - - /* Group specific functions */ - - /** - * RPC Routine to add an empty group with minimum details. - * Used as a placeholder for importing questions. - * Returns the groupid of the created group. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Dd of the Survey to add the group - * @param string $sGroupTitle Name of the group - * @param string $sGroupDescription Optional description of the group - * @return array|int The id of the new group - Or status - */ - public function add_group($sSessionKey, $iSurveyID, $sGroupTitle, $sGroupDescription='') - { - if ($this->_checkSessionKey($sSessionKey)) - { - if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'update')) - { - $oSurvey = Survey::model()->findByPk($iSurveyID); - if (!isset($oSurvey)) - return array('status' => 'Error: Invalid survey ID'); - - if($oSurvey['active']=='Y') - return array('status' => 'Error:Survey is active and not editable'); - - $oGroup = new QuestionGroup; - $oGroup->sid = $iSurveyID; - $oGroup->group_name = $sGroupTitle; - $oGroup->description = $sGroupDescription; - $oGroup->group_order = getMaxGroupOrder($iSurveyID); - $oGroup->language = Survey::model()->findByPk($iSurveyID)->language; - if($oGroup->save()) - return (int)$oGroup->gid; - else - return array('status' => 'Creation Failed'); - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid Session Key'); - } - - /** - * RPC Routine to delete a group of a survey . - * Returns the id of the deleted group. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Id of the survey that the group belongs - * @param int $iGroupID Id of the group to delete - * @return array|int The id of the deleted group or status - */ - public function delete_group($sSessionKey, $iSurveyID, $iGroupID) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $iSurveyID = sanitize_int($iSurveyID); - $iGroupID = sanitize_int($iGroupID); - $oSurvey = Survey::model()->findByPk($iSurveyID); - if (!isset($oSurvey)) - return array('status' => 'Error: Invalid survey ID'); - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveycontent', 'delete')) - { - $oGroup = QuestionGroup::model()->findByAttributes(array('gid' => $iGroupID)); - if (!isset($oGroup)) - return array('status' => 'Error: Invalid group ID'); - - if($oSurvey['active']=='Y') - return array('status' => 'Error:Survey is active and not editable'); - - $depented_on = getGroupDepsForConditions($oGroup->sid,"all",$iGroupID,"by-targgid"); - if(isset($depented_on)) - return array('status' => 'Group with depencdencies - deletion not allowed'); - - $iGroupsDeleted = QuestionGroup::deleteWithDependency($iGroupID, $iSurveyID); - - if ($iGroupsDeleted === 1) - { - fixSortOrderGroups($iSurveyID); - return (int)$iGroupID; - } - else - return array('status' => 'Group deletion failed'); - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid Session Key'); - } - - /** - * RPC Routine to import a group - imports lsg,csv - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID The id of the survey that the group will belong - * @param string $sImportData String containing the BASE 64 encoded data of a lsg,csv - * @param string $sImportDataType lsg,csv - * @param string $sNewGroupName Optional new name for the group - * @param string $sNewGroupDescription Optional new description for the group - * @return array|integer iGroupID - ID of the new group or status - */ - public function import_group($sSessionKey, $iSurveyID, $sImportData, $sImportDataType, $sNewGroupName=NULL, $sNewGroupDescription=NULL) - { - - if ($this->_checkSessionKey($sSessionKey)) - { - $oSurvey = Survey::model()->findByPk($iSurveyID); - if (!isset($oSurvey)) - return array('status' => 'Error: Invalid survey ID'); - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'update')) - { - if($oSurvey->getAttribute('active') =='Y') - return array('status' => 'Error:Survey is active and not editable'); - - if (!in_array($sImportDataType,array('csv','lsg'))) return array('status' => 'Invalid extension'); - libxml_use_internal_errors(true); - Yii::app()->loadHelper('admin/import'); - // First save the data to a temporary file - $sFullFilePath = Yii::app()->getConfig('tempdir') . DIRECTORY_SEPARATOR . randomChars(40).'.'.$sImportDataType; - file_put_contents($sFullFilePath,base64_decode(chunk_split($sImportData))); - - if (strtolower($sImportDataType)=='csv') - { - $aImportResults = CSVImportGroup($sFullFilePath, $iSurveyID); - } - elseif ( strtolower($sImportDataType)=='lsg') - { - $xml = simplexml_load_file($sFullFilePath); - if(!$xml) - { - unlink($sFullFilePath); - return array('status' => 'Error: Invalid LimeSurvey group structure XML '); - } - $aImportResults = XMLImportGroup($sFullFilePath, $iSurveyID); - } - else - return array('status' => 'Invalid extension'); //just for symmetry! - - unlink($sFullFilePath); - - if (isset($aImportResults['fatalerror'])) return array('status' => 'Error: '.$aImportResults['fatalerror']); - else - { - $iNewgid = $aImportResults['newgid']; - - $oGroup = QuestionGroup::model()->findByAttributes(array('gid' => $iNewgid)); - $slang=$oGroup['language']; - if($sNewGroupName!='') - $oGroup->setAttribute('group_name',$sNewGroupName); - if($sNewGroupDescription!='') - $oGroup->setAttribute('description',$sNewGroupDescription); - try - { - $oGroup->save(); - } - catch(Exception $e) - { - // no need to throw exception - } - return (int)$aImportResults['newgid']; - } - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid session key'); - } - - /** - * RPC Routine to find response IDs given a survey ID and a token. - * @param string $sSessionKey - * @param int $iSurveyID - * @param string $sToken - */ - public function get_response_ids($sSessionKey, $iSurveyID, $sToken) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $responses = SurveyDynamic::model($iSurveyID)->findAllByAttributes(array('token' => $sToken)); - $result = array(); - foreach ($responses as $response) - { - $result[] = (int) $response->id; - } - return $result; - } - else - { - return array('status' => 'Invalid Session Key'); - } - - } - - /** - * RPC Routine to return properties of a group of a survey . - * Returns array of properties - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iGroupID Id of the group to get properties - * @param array $aGroupSettings The properties to get - * @return array The requested values - */ - public function get_group_properties($sSessionKey, $iGroupID, $aGroupSettings) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $oGroup = QuestionGroup::model()->findByAttributes(array('gid' => $iGroupID)); - if (!isset($oGroup)) - return array('status' => 'Error: Invalid group ID'); - - if (Permission::model()->hasSurveyPermission($oGroup->sid, 'survey', 'read')) - { - $aBasicDestinationFields=QuestionGroup::model()->tableSchema->columnNames; - $aGroupSettings=array_intersect($aGroupSettings,$aBasicDestinationFields); - - if (empty($aGroupSettings)) - return array('status' => 'No valid Data'); - - foreach($aGroupSettings as $sGroupSetting) - { - $aResult[$sGroupSetting] = $oGroup->$sGroupSetting; - } - return $aResult; - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid Session Key'); - } - - - /** - * RPC Routine to set group properties. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param integer $iGroupID - ID of the survey - * @param array|struct $aGroupData - An array with the particular fieldnames as keys and their values to set on that particular survey - * @return array Of succeeded and failed modifications according to internal validation. - */ - public function set_group_properties($sSessionKey, $iGroupID, $aGroupData) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $oGroup=QuestionGroup::model()->findByAttributes(array('gid' => $iGroupID)); - if (is_null($oGroup)) - { - return array('status' => 'Error: Invalid group ID'); - } - if (Permission::model()->hasSurveyPermission($oGroup->sid, 'survey', 'update')) - { - $aResult = array(); - // Remove fields that may not be modified - unset($aGroupData['sid']); - unset($aGroupData['gid']); - // Remove invalid fields - $aDestinationFields=array_flip(QuestionGroup::model()->tableSchema->columnNames); - $aGroupData=array_intersect_key($aGroupData,$aDestinationFields); - $aGroupAttributes = $oGroup->getAttributes(); - if (empty($aGroupData)) - return array('status' => 'No valid Data'); - - foreach($aGroupData as $sFieldName=>$sValue) - { - //all dependencies this group has - $has_dependencies=getGroupDepsForConditions($oGroup->sid,$iGroupID); - //all dependencies on this group - $depented_on = getGroupDepsForConditions($oGroup->sid,"all",$iGroupID,"by-targgid"); - //We do not allow groups with dependencies to change order - that would lead to broken dependencies - - if((isset($has_dependencies) || isset($depented_on)) && $sFieldName == 'group_order') - $aFailed[$sFieldName]='Group with dependencies - Order cannot be changed'; - else - { - $oGroup->setAttribute($sFieldName,$sValue); - } - try - { - // save the change to database - one by one to allow for validation to work - $bSaveResult=$oGroup->save(); - fixSortOrderGroups($oGroup->sid); - $aResult[$sFieldName] = $bSaveResult; - //unset failed values - if (!$bSaveResult) - $oGroup->$sFieldName=$aGroupAttributes[$sFieldName]; - } - catch(Exception $e) - { - //unset values that cause exception - $oGroup->$sFieldName=$aGroupAttributes[$sFieldName]; - } - } - return $aResult; - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid Session key'); - } - - /** - * RPC Routine to return the ids and info of groups belonging to survey . - * Returns array of ids and info. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Id of the Survey containing the groups - * @return array The list of groups - */ - public function list_groups($sSessionKey, $iSurveyID) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $oSurvey = Survey::model()->findByPk($iSurveyID); - if (!isset($oSurvey)) - return array('status' => 'Error: Invalid survey ID'); - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'read')) - { - $oGroupList = QuestionGroup::model()->findAllByAttributes(array("sid"=>$iSurveyID)); - if(count($oGroupList)==0) - return array('status' => 'No groups found'); - - foreach ($oGroupList as $oGroup) - { - $aData[]= array('id'=>$oGroup->primaryKey,'group_name'=>$oGroup->attributes['group_name']); - } - return $aData; - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid Session Key'); - } - - - /* Question specific functions */ - - - /** - * RPC Routine to delete a question of a survey . - * Returns the id of the deleted question. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int iQuestionID Id of the question to delete - * @return array|int Id of the deleted Question or status - */ - public function delete_question($sSessionKey, $iQuestionID) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $oQuestion = Question::model()->findByAttributes(array('qid' => $iQuestionID)); - if (!isset($oQuestion)) - return array('status' => 'Error: Invalid question ID'); - - $iSurveyID = $oQuestion['sid']; - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveycontent', 'delete')) - { - $oSurvey = Survey::model()->findByPk($iSurveyID); - - if($oSurvey['active']=='Y') - return array('status' => 'Survey is active and not editable'); - $iGroupID=$oQuestion['gid']; - - $oCondition = Condition::model()->findAllByAttributes(array('cqid' => $iQuestionID)); - if(count($oCondition)>0) - return array('status' => 'Cannot delete Question. Others rely on this question'); - - LimeExpressionManager::RevertUpgradeConditionsToRelevance(NULL,$iQuestionID); - - try - { - Condition::model()->deleteAllByAttributes(array('qid' => $iQuestionID)); - QuestionAttribute::model()->deleteAllByAttributes(array('qid' => $iQuestionID)); - Answer::model()->deleteAllByAttributes(array('qid' => $iQuestionID)); - - $sCriteria = new CDbCriteria; - $sCriteria->addCondition('qid = :qid or parent_qid = :qid'); - $sCriteria->params[':qid'] = $iQuestionID; - Question::model()->deleteAll($sCriteria); - - DefaultValue::model()->deleteAllByAttributes(array('qid' => $iQuestionID)); - QuotaMember::model()->deleteAllByAttributes(array('qid' => $iQuestionID)); - Question::updateSortOrder($iGroupID, $iSurveyID); - - return (int)$iQuestionID; - } - catch(Exception $e) - { - return array('status' => 'Error'); - } - - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid session key'); - } - - - /** - * RPC Routine to import a question - imports lsq,csv. - * - * @access public - * @param string $sSessionKey - * @param int $iSurveyID The id of the survey that the question will belong - * @param int $iGroupID The id of the group that the question will belong - * @param string $sImportData String containing the BASE 64 encoded data of a lsg,csv - * @param string $sImportDataType lsq,csv - * @param string $sMandatory Optional Mandatory question option (default to No) - * @param string $sNewQuestionTitle Optional new title for the question - * @param string $sNewqQuestion An optional new question - * @param string $sNewQuestionHelp An optional new question help text - * @return array|integer iQuestionID - ID of the new question - Or status - */ - public function import_question($sSessionKey, $iSurveyID,$iGroupID, $sImportData, $sImportDataType, $sMandatory='N', $sNewQuestionTitle=NULL, $sNewqQuestion=NULL, $sNewQuestionHelp=NULL) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $oSurvey = Survey::model()->findByPk($iSurveyID); - if (!isset($oSurvey)) - return array('status' => 'Error: Invalid survey ID'); - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'update')) - { - if($oSurvey->getAttribute('active') =='Y') - return array('status' => 'Error:Survey is Active and not editable'); - - $oGroup = QuestionGroup::model()->findByAttributes(array('gid' => $iGroupID)); - if (!isset($oGroup)) - return array('status' => 'Error: Invalid group ID'); - - $sGroupSurveyID = $oGroup['sid']; - if($sGroupSurveyID != $iSurveyID) - return array('status' => 'Error: Missmatch in surveyid and groupid'); - - if (!in_array($sImportDataType,array('csv','lsq'))) return array('status' => 'Invalid extension'); - libxml_use_internal_errors(true); - Yii::app()->loadHelper('admin/import'); - // First save the data to a temporary file - $sFullFilePath = Yii::app()->getConfig('tempdir') . DIRECTORY_SEPARATOR . randomChars(40).'.'.$sImportDataType; - file_put_contents($sFullFilePath,base64_decode(chunk_split($sImportData))); - - if (strtolower($sImportDataType)=='csv') - { - $aImportResults = CSVImportQuestion($sFullFilePath, $iSurveyID, $iGroupID); - } - elseif ( strtolower($sImportDataType)=='lsq') - { - - $xml = simplexml_load_file($sFullFilePath); - if(!$xml) - { - unlink($sFullFilePath); - return array('status' => 'Error: Invalid LimeSurvey question structure XML '); - } - $aImportResults = XMLImportQuestion($sFullFilePath, $iSurveyID, $iGroupID); - } - else - return array('status' => 'Really Invalid extension'); //just for symmetry! - - unlink($sFullFilePath); - - if (isset($aImportResults['fatalerror'])) return array('status' => 'Error: '.$aImportResults['fatalerror']); - else - { - fixLanguageConsistency($iSurveyID); - $iNewqid = $aImportResults['newqid']; - - $oQuestion = Question::model()->findByAttributes(array('sid' => $iSurveyID, 'gid' => $iGroupID, 'qid' => $iNewqid)); - if($sNewQuestionTitle!=NULL) - $oQuestion->setAttribute('title',$sNewQuestionTitle); - if($sNewqQuestion!='') - $oQuestion->setAttribute('question',$sNewqQuestion); - if($sNewQuestionHelp!='') - $oQuestion->setAttribute('help',$sNewQuestionHelp); - if(in_array($sMandatory, array('Y','N'))) - $oQuestion->setAttribute('mandatory',$sMandatory); - else - $oQuestion->setAttribute('mandatory','N'); - - try - { - $oQuestion->save(); - } - catch(Exception $e) - { - // no need to throw exception - } - return (int)$aImportResults['newqid']; - } - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid session key'); - } - - - /** - * RPC Routine to return properties of a question of a survey. - * Returns string - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iQuestionID Id of the question to get properties - * @param array $aQuestionSettings The properties to get - * @param string $sLanguage Optional parameter language for multilingual questions - * @return array The requested values - */ - public function get_question_properties($sSessionKey, $iQuestionID, $aQuestionSettings, $sLanguage=NULL) - { - if ($this->_checkSessionKey($sSessionKey)) - { - Yii::app()->loadHelper("surveytranslator"); - $oQuestion = Question::model()->findByAttributes(array('qid' => $iQuestionID)); - if (!isset($oQuestion)) - return array('status' => 'Error: Invalid questionid'); - - $iSurveyID = $oQuestion->sid; - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'read')) - { - if (is_null($sLanguage)) - $sLanguage=Survey::model()->findByPk($iSurveyID)->language; - - if (!array_key_exists($sLanguage,getLanguageDataRestricted())) - return array('status' => 'Error: Invalid language'); - - $oQuestion = Question::model()->findByAttributes(array('qid' => $iQuestionID, 'language'=>$sLanguage)); - if (!isset($oQuestion)) - return array('status' => 'Error: Invalid questionid'); - - $aBasicDestinationFields=Question::model()->tableSchema->columnNames; - array_push($aBasicDestinationFields,'available_answers') ; - array_push($aBasicDestinationFields,'subquestions') ; - array_push($aBasicDestinationFields,'attributes') ; - array_push($aBasicDestinationFields,'attributes_lang') ; - array_push($aBasicDestinationFields,'answeroptions') ; - $aQuestionSettings=array_intersect($aQuestionSettings,$aBasicDestinationFields); - - if (empty($aQuestionSettings)) - return array('status' => 'No valid Data'); - - $aResult=array(); - foreach ($aQuestionSettings as $sPropertyName ) - { - if ($sPropertyName == 'available_answers' || $sPropertyName == 'subquestions') - { - $oSubQuestions = Question::model()->findAllByAttributes(array('parent_qid' => $iQuestionID,'language'=>$sLanguage ),array('order'=>'title') ); - if (count($oSubQuestions)>0) - { - $aData = array(); - foreach($oSubQuestions as $oSubQuestion) - { - if($sPropertyName == 'available_answers') - $aData[$oSubQuestion['title']]= $oSubQuestion['question']; - else - { - $aData[$oSubQuestion['qid']]['title']= $oSubQuestion['title']; - $aData[$oSubQuestion['qid']]['question']= $oSubQuestion['question']; - $aData[$oSubQuestion['qid']]['scale_id']= $oSubQuestion['scale_id']; - } - - } - - $aResult[$sPropertyName]=$aData; - } - else - $aResult[$sPropertyName]='No available answers'; - } - else if ($sPropertyName == 'attributes') - { - $oAttributes = QuestionAttribute::model()->findAllByAttributes(array('qid' => $iQuestionID, 'language'=> null ),array('order'=>'attribute') ); - if (count($oAttributes)>0) - { - $aData = array(); - foreach($oAttributes as $oAttribute) - $aData[$oAttribute['attribute']]= $oAttribute['value']; - - $aResult['attributes']=$aData; - } - else - $aResult['attributes']='No available attributes'; - } - else if ($sPropertyName == 'attributes_lang') - { - $oAttributes = QuestionAttribute::model()->findAllByAttributes(array('qid' => $iQuestionID, 'language'=> $sLanguage ),array('order'=>'attribute') ); - if (count($oAttributes)>0) - { - $aData = array(); - foreach($oAttributes as $oAttribute) - $aData[$oAttribute['attribute']]= $oAttribute['value']; - - $aResult['attributes_lang']=$aData; - } - else - $aResult['attributes_lang']='No available attributes'; - } - else if ($sPropertyName == 'answeroptions') - { - $oAttributes = Answer::model()->findAllByAttributes(array('qid' => $iQuestionID, 'language'=> $sLanguage ),array('order'=>'sortorder') ); - if (count($oAttributes)>0) - { - $aData = array(); - foreach($oAttributes as $oAttribute) { - $aData[$oAttribute['code']]['answer']=$oAttribute['answer']; - $aData[$oAttribute['code']]['assessment_value']=$oAttribute['assessment_value']; - $aData[$oAttribute['code']]['scale_id']=$oAttribute['scale_id']; - } - $aResult['answeroptions']=$aData; - } - else - $aResult['answeroptions']='No available answer options'; - } - else - { - $aResult[$sPropertyName]=$oQuestion->$sPropertyName; - } - } - return $aResult; - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid session key'); - } - - /** - * RPC Routine to set question properties. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param integer $iQuestionID - ID of the question - * @param array|struct $aQuestionData - An array with the particular fieldnames as keys and their values to set on that particular question - * @param string $sLanguage Optional parameter language for multilingual questions - * @return array Of succeeded and failed modifications according to internal validation. - */ - public function set_question_properties($sSessionKey, $iQuestionID, $aQuestionData,$sLanguage=NULL) - { - if ($this->_checkSessionKey($sSessionKey)) - { - Yii::app()->loadHelper("surveytranslator"); - $oQuestion=Question::model()->findByAttributes(array('qid' => $iQuestionID)); - if (is_null($oQuestion)) - return array('status' => 'Error: Invalid group ID'); - - $iSurveyID = $oQuestion->sid; - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'update')) - { - if (is_null($sLanguage)) - $sLanguage=Survey::model()->findByPk($iSurveyID)->language; - - if (!array_key_exists($sLanguage,getLanguageDataRestricted())) - return array('status' => 'Error: Invalid language'); - - $oQuestion = Question::model()->findByAttributes(array('qid' => $iQuestionID, 'language'=>$sLanguage)); - if (!isset($oQuestion)) - return array('status' => 'Error: Invalid questionid'); - - // Remove fields that may not be modified - unset($aQuestionData['qid']); - unset($aQuestionData['gid']); - unset($aQuestionData['sid']); - unset($aQuestionData['parent_qid']); - unset($aQuestionData['language']); - unset($aQuestionData['type']); - // Remove invalid fields - $aDestinationFields=array_flip(Question::model()->tableSchema->columnNames); - $aQuestionData=array_intersect_key($aQuestionData,$aDestinationFields); - $aQuestionAttributes = $oQuestion->getAttributes(); - - if (empty($aQuestionData)) - return array('status' => 'No valid Data'); - - foreach($aQuestionData as $sFieldName=>$sValue) - { - //all the dependencies that this question has to other questions - $dependencies=getQuestDepsForConditions($oQuestion->sid,$oQuestion->gid,$iQuestionID); - //all dependencies by other questions to this question - $is_criteria_question=getQuestDepsForConditions($oQuestion->sid,$oQuestion->gid,"all",$iQuestionID,"by-targqid"); - //We do not allow questions with dependencies in the same group to change order - that would lead to broken dependencies - - if((isset($dependencies) || isset($is_criteria_question)) && $sFieldName == 'question_order') - $aFailed[$sFieldName]='Questions with dependencies - Order cannot be changed'; - else - { - $oQuestion->setAttribute($sFieldName,$sValue); - } - - try - { - $bSaveResult=$oQuestion->save(); // save the change to database - Question::model()->updateQuestionOrder($oQuestion->gid, $oQuestion->sid); - $aResult[$sFieldName]=$bSaveResult; - //unset fields that failed - if (!$bSaveResult) - $oQuestion->$sFieldName=$aQuestionAttributes[$sFieldName]; - } - catch(Exception $e) - { - //unset fields that caused exception - $oQuestion->$sFieldName=$aQuestionAttributes[$sFieldName]; - } - } - return $aResult; - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid Session key'); - } - - - /** - * RPC Routine to return the ids and info of questions of a survey/group. - * Returns array of ids and info. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Id of the survey to list questions - * @param int $iGroupID Optional id of the group to list questions - * @param string $sLanguage Optional parameter language for multilingual questions - * @return array The list of questions - */ - public function list_questions($sSessionKey, $iSurveyID, $iGroupID=NULL, $sLanguage=NULL) - { - if ($this->_checkSessionKey($sSessionKey)) - { - Yii::app()->loadHelper("surveytranslator"); - $oSurvey = Survey::model()->findByPk($iSurveyID); - if (!isset($oSurvey)) - return array('status' => 'Error: Invalid survey ID'); - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'read')) - { - if (is_null($sLanguage)) - $sLanguage=$oSurvey->language; - - if (!array_key_exists($sLanguage,getLanguageDataRestricted())) - return array('status' => 'Error: Invalid language'); - - if($iGroupID!=NULL) - { - $oGroup = QuestionGroup::model()->findByAttributes(array('gid' => $iGroupID)); - $sGroupSurveyID = $oGroup['sid']; - - if($sGroupSurveyID != $iSurveyID) - return array('status' => 'Error: IMissmatch in surveyid and groupid'); - else - $aQuestionList = Question::model()->findAllByAttributes(array("sid"=>$iSurveyID, "gid"=>$iGroupID,"parent_qid"=>"0","language"=>$sLanguage)); - } - else - $aQuestionList = Question::model()->findAllByAttributes(array("sid"=>$iSurveyID,"parent_qid"=>"0", "language"=>$sLanguage)); - - if(count($aQuestionList)==0) - return array('status' => 'No questions found'); - - foreach ($aQuestionList as $oQuestion) - { - $aData[]= array('id'=>$oQuestion->primaryKey,'title'=>$oQuestion->attributes['title'],'type'=>$oQuestion->attributes['type'], 'question'=>$oQuestion->attributes['question']); - } - return $aData; - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid session key'); - } - - /* Participant-Token specific functions */ - - - - /** - * RPC Routine to add participants to the tokens collection of the survey. - * Returns the inserted data including additional new information like the Token entry ID and the token string. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Id of the Survey - * @param struct $aParticipantData Data of the participants to be added - * @param bool Optional - Defaults to true and determins if the access token automatically created - * @return array The values added - */ - public function add_participants($sSessionKey, $iSurveyID, $aParticipantData, $bCreateToken=true) - { - if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key'); - $oSurvey=Survey::model()->findByPk($iSurveyID); - if (is_null($oSurvey)) - { - return array('status' => 'Error: Invalid survey ID'); - } - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'create')) - { - if (!Yii::app()->db->schema->getTable('{{tokens_' . $iSurveyID . '}}')) - return array('status' => 'No token table'); - - $aDestinationFields = Yii::app()->db->schema->getTable('{{tokens_' . $iSurveyID . '}}')->getColumnNames(); - $aDestinationFields = array_flip($aDestinationFields); - - foreach ($aParticipantData as &$aParticipant) - { - $aParticipant=array_intersect_key($aParticipant,$aDestinationFields); - TokenDynamic::sid($iSurveyID); - $token = new TokenDynamic; - - if ($new_token_id=$token->insertParticipant($aParticipant)) - { - if ($bCreateToken) - $token_string = TokenDynamic::model()->createToken($new_token_id); - else - $token_string = ''; - - $aParticipant = array_merge($aParticipant, array( - 'tid' => $new_token_id, - 'token' => $token_string, - )); - } - else - { - $aParticipant=false; - } - } - return $aParticipantData; - } - else - return array('status' => 'No permission'); - } - - /** - * RPC Routine to delete multiple participants of a Survey. - * Returns the id of the deleted token - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Id of the Survey that the participants belong to - * @param array $aTokenIDs Id of the tokens/participants to delete - * @return array Result of deletion - */ - public function delete_participants($sSessionKey, $iSurveyID, $aTokenIDs) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $iSurveyID = sanitize_int($iSurveyID); - - $oSurvey = Survey::model()->findByPk($iSurveyID); - if (!isset($oSurvey)) - return array('status' => 'Error: Invalid survey ID'); - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'delete')) - { - if(!tableExists("{{tokens_$iSurveyID}}")) - return array('status' => 'Error: No token table'); - - $aResult=array(); - foreach($aTokenIDs as $iTokenID) - { - $tokenidExists = TokenDynamic::model($iSurveyID)->findByPk($iTokenID); - if (!isset($tokenidExists)) - $aResult[$iTokenID]='Invalid token ID'; - else - { - SurveyLink::deleteTokenLink(array($iTokenID), $iSurveyID); - if(TokenDynamic::model($iSurveyID)->deleteRecords(array($iTokenID))) - $aResult[$iTokenID]='Deleted'; - else - $aResult[$iTokenID]='Deletion went wrong'; - } - } - return $aResult; - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid Session Key'); - } - - - /** - * RPC Routine to return settings of a token/participant of a survey . - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Id of the Survey to get token properties - * @param int $iTokenID Id of the participant to check - * @param array $aTokenProperties The properties to get - * @return array The requested values - */ - public function get_participant_properties($sSessionKey, $iSurveyID, $iTokenID, $aTokenProperties) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $surveyidExists = Survey::model()->findByPk($iSurveyID); - if (!isset($surveyidExists)) - return array('status' => 'Error: Invalid survey ID'); - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'read')) - { - if(!tableExists("{{tokens_$iSurveyID}}")) - return array('status' => 'Error: No token table'); - - $oToken = TokenDynamic::model($iSurveyID)->findByPk($iTokenID); - if (!isset($oToken)) - return array('status' => 'Error: Invalid tokenid'); - - $aResult=array(); - $aBasicDestinationFields=TokenDynamic::model()->tableSchema->columnNames; - $aTokenProperties=array_intersect($aTokenProperties,$aBasicDestinationFields); - - if (empty($aTokenProperties)) - return array('status' => 'No valid Data'); - - foreach($aTokenProperties as $sPropertyName ) - { - $aResult[$sPropertyName]=$oToken->$sPropertyName; - } - return $aResult; - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid Session Key'); - } - - /** - * RPC Routine to set properties of a survey participant/token. - * Returns array - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Id of the survey that participants belong - * @param int $iTokenID Id of the participant to alter - * @param array|struct $aTokenData Data to change - * @return array Result of the change action - */ - public function set_participant_properties($sSessionKey, $iSurveyID, $iTokenID, $aTokenData) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $oSurvey = Survey::model()->findByPk($iSurveyID); - if (!isset($oSurvey)) - return array('status' => 'Error: Invalid survey ID'); - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'update')) - { - if(!tableExists("{{tokens_$iSurveyID}}")) - return array('status' => 'Error: No token table'); - - $oToken = TokenDynamic::model($iSurveyID)->findByPk($iTokenID); - if (!isset($oToken)) - return array('status' => 'Error: Invalid tokenid'); - - $aResult = array(); - // Remove fields that may not be modified - unset($aTokenData['tid']); - - $aBasicDestinationFields=array_flip(TokenDynamic::model()->tableSchema->columnNames); - $aTokenData=array_intersect_key($aTokenData,$aBasicDestinationFields); - $aTokenAttributes = $oToken->getAttributes(); - - if (empty($aTokenData)) - return array('status' => 'No valid Data'); - - foreach($aTokenData as $sFieldName=>$sValue) - { - $oToken->$sFieldName=$sValue; - try - { - $bSaveResult=$oToken->save(); - $aResult[$sFieldName]=$bSaveResult; - //unset fields that failed - if (!$bSaveResult) - $oToken->$sFieldName=$aTokenAttributes[$sFieldName]; - } - catch(Exception $e) - { - $oToken->$sFieldName=$aTokenAttributes[$sFieldName]; - } - } - return $aResult; - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid Session Key'); - } - - - - /** - * RPC Routine to return the ids and info of token/participants of a survey. - * if $bUnused is true, user will get the list of not completed tokens (token_return functionality). - * Parameters iStart and ilimit are used to limit the number of results of this call. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Id of the survey to list participants - * @param int $iStart Start id of the token list - * @param int $iLimit Number of participants to return - * @param bool $bUnused If you want unused tokensm, set true - * @return array The list of tokens - */ - public function list_participants($sSessionKey, $iSurveyID, $iStart=0, $iLimit=10, $bUnused=false) - { - if ($this->_checkSessionKey($sSessionKey)) - { - $oSurvey = Survey::model()->findByPk($iSurveyID); - if (!isset($oSurvey)) - return array('status' => 'Error: Invalid survey ID'); - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'read')) - { - if(!tableExists("{{tokens_$iSurveyID}}")) - return array('status' => 'Error: No token table'); - - if($bUnused) - $oTokens = TokenDynamic::model($iSurveyID)->findAll(array('condition'=>"completed = 'N'", 'limit' => $iLimit, 'offset' => $iStart)); - else - $oTokens = TokenDynamic::model($iSurveyID)->findAll(array('limit' => $iLimit, 'offset' => $iStart)); - - if(count($oTokens)==0) - return array('status' => 'No Tokens found'); - - foreach ($oTokens as $token) - { - $aData[] = array( - 'tid'=>$token->primarykey, - 'token'=>$token->attributes['token'], - 'participant_info'=>array( - 'firstname'=>$token->attributes['firstname'], - 'lastname'=>$token->attributes['lastname'], - 'email'=>$token->attributes['email'], - )); - } - return $aData; - } - else - return array('status' => 'No permission'); - } - else - return array('status' => 'Invalid Session Key'); - } - - /** - * RPC routine to to initialise the survey's collection of tokens where new participant tokens may be later added. - * - * @access public - * @param string $sSessionKey Auth credentials - * @param integer $iSurveyID ID of the survey where a token table will be created for - * @param array $aAttributeFields An array of integer describing any additional attribute fields - * @return array Status=>OK when successfull, otherwise the error description - */ - public function activate_tokens($sSessionKey, $iSurveyID, $aAttributeFields=array()) - { - if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key'); - if (Permission::model()->hasGlobalPermission('surveys','create')) - { - $oSurvey=Survey::model()->findByPk($iSurveyID); - if (is_null($oSurvey)) - { - return array('status' => 'Error: Invalid survey ID'); - } - if (is_array($aAttributeFields) && count($aAttributeFields)>0) - { - foreach ($aAttributeFields as &$sField) - { - $sField= intval($sField); - $sField='attribute_'.$sField; - } - $aAttributeFields=array_unique($aAttributeFields); - } - Yii::app()->loadHelper('admin/token'); - if (createTokenTable($iSurveyID, $aAttributeFields)) - { - return array('status' => 'OK'); - } - else - { - return array('status' => 'Token table could not be created'); - } - } - else - return array('status' => 'No permission'); - } - - /** - * RPC Routine to invite participants in a survey - * Returns array of results of sending - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID ID of the survey that participants belong - * @return array Result of the action - */ - public function invite_participants($sSessionKey, $iSurveyID ) - { - Yii::app()->loadHelper('admin/token'); - if (!$this->_checkSessionKey($sSessionKey)) - return array('status' => 'Invalid session key'); - - $oSurvey = Survey::model()->findByPk($iSurveyID); - if (!isset($oSurvey)) - return array('status' => 'Error: Invalid survey ID'); - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'update')) - { - - if(!tableExists("{{tokens_$iSurveyID}}")) - return array('status' => 'Error: No token table'); - - $iMaxEmails = (int)Yii::app()->getConfig("maxemails"); - $SQLemailstatuscondition = "emailstatus = 'OK'"; - - $oTokens = TokenDynamic::model($iSurveyID); - $aResultTokens = $oTokens->findUninvited(false, $iMaxEmails, true, $SQLemailstatuscondition); - $aAllTokens = $oTokens->findUninvitedIDs(false, 0, true, $SQLemailstatuscondition); - $iAllTokensCount=count($aAllTokens); - unset($aAllTokens); - if (empty($aResultTokens)) - return array('status' => 'Error: No candidate tokens'); - - foreach($aResultTokens as $key=>$oToken) - { - //pattern taken from php_filter_validate_email PHP_5_4/ext/filter/logical_filters.c - $pattern = '/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD'; - - //if(!filter_var($emailaddress, FILTER_VALIDATE_EMAIL)) - if (preg_match($pattern, $oToken['email']) !== 1) - unset($aResultTokens[$key]); - } - - if (empty($aResultTokens)) - return array('status' => 'Error: No candidate tokens'); - $aResult = emailTokens($iSurveyID,$aResultTokens,'invite'); - $iLeft = $iAllTokensCount - count($aResultTokens); - $aResult['status'] =$iLeft. " left to send"; - - return $aResult; - } - else - return array('status' => 'No permission'); - } - - - /** - * RPC Routine to send reminder for participants in a survey - * Returns array of results of sending - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID ID of the survey that participants belong - * @param int $iMinDaysBetween Optional parameter days from last reminder - * @param int $iMaxReminders Optional parameter Maximum reminders count - * @return array Result of the action - */ - public function remind_participants($sSessionKey, $iSurveyID, $iMinDaysBetween=null, $iMaxReminders=null ) - { - Yii::app()->loadHelper('admin/token'); - if (!$this->_checkSessionKey($sSessionKey)) - return array('status' => 'Invalid session key'); - - $oSurvey = Survey::model()->findByPk($iSurveyID); - if (!isset($oSurvey)) - return array('status' => 'Error: Invalid survey ID'); - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'update')) - { - $timeadjust = Yii::app()->getConfig("timeadjust"); - - if(!tableExists("{{tokens_$iSurveyID}}")) - return array('status' => 'Error: No token table'); - - if (getEmailFormat($iSurveyID) == 'html') - $bHtml = true; - else - $bHtml = false; - - $SQLemailstatuscondition = "emailstatus = 'OK'"; - $SQLremindercountcondition = ''; - $SQLreminderdelaycondition = ''; - $iMaxEmails = (int)Yii::app()->getConfig("maxemails"); - - if(!is_null($iMinDaysBetween)) - { - $compareddate = dateShift(date("Y-m-d H:i:s", time() - 86400 * $iMinDaysBetween), "Y-m-d H:i", $timeadjust); - $SQLreminderdelaycondition = " ((remindersent = 'N' AND sent < '" . $compareddate . "') OR (remindersent < '" . $compareddate . "'))"; - } - - if(!is_null($iMaxReminders)) - $SQLremindercountcondition = "remindercount < " . $iMaxReminders; - - $oTokens = TokenDynamic::model($iSurveyID); - $aAllTokens = $oTokens->findUninvitedIDs(false, 0, false, $SQLemailstatuscondition, $SQLremindercountcondition, $SQLreminderdelaycondition); - $iAllTokensCount=count($aAllTokens); - unset($aAllTokens); // save some memory before the next query - - $aResultTokens = $oTokens->findUninvited(false, $iMaxEmails, false, $SQLemailstatuscondition, $SQLremindercountcondition, $SQLreminderdelaycondition); - - if (empty($aResultTokens)) - return array('status' => 'Error: No candidate tokens'); - - $aResult = emailTokens($iSurveyID, $aResultTokens, 'remind'); - - $iLeft = $iAllTokensCount - count($aResultTokens); - $aResult['status'] =$iLeft. " left to send"; - return $aResult; - } - else - return array('status' => 'No permission'); - - } - - - /* Response specific functions */ - - - /** - * RPC Routine to add a response to the survey responses collection. - * Returns the id of the inserted survey response - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Id of the Survey to insert responses - * @param struct $aResponseData The actual response - * @return int The response ID - */ - public function add_response($sSessionKey, $iSurveyID, $aResponseData) - { - if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key'); - $oSurvey=Survey::model()->findByPk($iSurveyID); - if (is_null($oSurvey)) - { - return array('status' => 'Error: Invalid survey ID'); - } - - if (Permission::model()->hasSurveyPermission($iSurveyID, 'responses', 'create')) - { - if (!Yii::app()->db->schema->getTable('{{survey_' . $iSurveyID . '}}')) - return array('status' => 'No survey response table'); - - //set required values if not set - - // @todo: Some of this is part of the validation and should be done in the model instead - if (!isset($aResponseData['submitdate'])) - $aResponseData['submitdate'] = date("Y-m-d H:i:s"); - if (!isset($aResponseData['startlanguage'])) - $aResponseData['startlanguage'] = getBaseLanguageFromSurveyID($iSurveyID); - - if ($oSurvey->datestamp=='Y') - { - if (!isset($aResponseData['datestamp'])) - $aResponseData['datestamp'] = date("Y-m-d H:i:s"); - if (!isset($aResponseData['startdate'])) - $aResponseData['startdate'] = date("Y-m-d H:i:s"); - } - - SurveyDynamic::sid($iSurveyID); - $survey_dynamic = new SurveyDynamic; - $aBasicDestinationFields=$survey_dynamic->tableSchema->columnNames; - $aResponseData=array_intersect_key($aResponseData, array_flip($aBasicDestinationFields)); - $result_id = $survey_dynamic->insertRecords($aResponseData); - - if ($result_id) - return $result_id; - else - return array('status' => 'Unable to add response'); - } - else - return array('status' => 'No permission'); - - } - - /** - * RPC Routine to export responses. - * Returns the requested file as base64 encoded string - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Id of the Survey - * @param string $sDocumentType pdf,csv,xls,doc - * @param string $sLanguageCode The language to be used - * @param string $sCompletionStatus Optional 'complete','incomplete' or 'all' - defaults to 'all' - * @param string $sHeadingType 'code','full' or 'abbreviated' Optional defaults to 'code' - * @param string $sResponseType 'short' or 'long' Optional defaults to 'short' - * @param integer $iFromResponseID Optional - * @param integer $iToResponseID Optional - * @param array $aFields Optional Selected fields - * @return array|string On success: Requested file as base 64-encoded string. On failure array with error information - * */ - public function export_responses($sSessionKey, $iSurveyID, $sDocumentType, $sLanguageCode=null, $sCompletionStatus='all', $sHeadingType='full', $sResponseType='short', $iFromResponseID=null, $iToResponseID=null, $aFields=null) - { - if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key'); - Yii::app()->loadHelper('admin/exportresults'); - if (!tableExists('{{survey_' . $iSurveyID . '}}')) return array('status' => 'No Data'); - if(!$count = SurveyDynamic::model($iSurveyID)->count()) return array('status' => 'No Data'); - - if (!Permission::model()->hasSurveyPermission($iSurveyID, 'responses', 'export')) return array('status' => 'No permission'); - if (is_null($sLanguageCode)) $sLanguageCode=getBaseLanguageFromSurveyID($iSurveyID); - if (is_null($aFields)) $aFields=array_keys(createFieldMap($iSurveyID,'full',true,false,$sLanguageCode)); - if($sDocumentType=='xls'){ - // Cut down to the first 255 fields - $aFields=array_slice($aFields,0,255); - } - $oFomattingOptions=new FormattingOptions(); - - if($iFromResponseID !=null) - $oFomattingOptions->responseMinRecord=$iFromResponseID; - else - $oFomattingOptions->responseMinRecord=1; - - if($iToResponseID !=null) - $oFomattingOptions->responseMaxRecord=$iToResponseID; - else - $oFomattingOptions->responseMaxRecord = $count; - - $oFomattingOptions->selectedColumns=$aFields; - $oFomattingOptions->responseCompletionState=$sCompletionStatus; - $oFomattingOptions->headingFormat=$sHeadingType; - $oFomattingOptions->answerFormat=$sResponseType; - $oFomattingOptions->output='file'; - - $oExport=new ExportSurveyResultsService(); - $sTempFile=$oExport->exportSurvey($iSurveyID,$sLanguageCode, $sDocumentType,$oFomattingOptions, ''); - return new BigFile($sTempFile, true, 'base64'); - } - - /** - * RPC Routine to export token response in a survey. - * Returns the requested file as base64 encoded string - * - * @access public - * @param string $sSessionKey Auth credentials - * @param int $iSurveyID Id of the Survey - * @param string $sDocumentType pdf,csv,xls,doc - * @param string $sToken The token for which responses needed - * @param string $sLanguageCode The language to be used - * @param string $sCompletionStatus Optional 'complete','incomplete' or 'all' - defaults to 'all' - * @param string $sHeadingType 'code','full' or 'abbreviated' Optional defaults to 'code' - * @param string $sResponseType 'short' or 'long' Optional defaults to 'short' - * @param array $aFields Optional Selected fields - * @return array|string On success: Requested file as base 64-encoded string. On failure array with error information - * - */ - public function export_responses_by_token($sSessionKey, $iSurveyID, $sDocumentType, $sToken, $sLanguageCode=null, $sCompletionStatus='all', $sHeadingType='full', $sResponseType='short', $aFields=null) - { - if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key'); - if (!Permission::model()->hasSurveyPermission($iSurveyID, 'responses', 'export')) return array('status' => 'No permission'); - if (!tableExists('{{survey_' . $iSurveyID . '}}')) return array('status' => 'No Data'); - if(!$oResult = SurveyDynamic::model($iSurveyID)->findByAttributes(array('token' => $sToken))) return array('status' => 'No Response found for Token'); - if ($oResult['id']) - { - return $this->export_responses($sSessionKey, $iSurveyID, $sDocumentType, $sLanguageCode, $sCompletionStatus, $sHeadingType, $sResponseType, $oResult['id'], $oResult['id'], $aFields); - } - } - - - /** - * Tries to login with username and password - * - * @access protected - * @param string $sUsername The username - * @param mixed $sPassword The Password - * @return bool - */ - protected function _doLogin($sUsername, $sPassword) - { - $identity = new UserIdentity(sanitize_user($sUsername), $sPassword); - - if (!$identity->authenticate()) - { - return false; - } - else - return true; - } - - /** - * Fills the session with necessary user info on the fly - * - * @access protected - * @param string $username The username - * @return bool - */ - protected function _jumpStartSession($username) - { - $aUserData = User::model()->findByAttributes(array('users_name' => $username))->attributes; - - $session = array( - 'loginID' => intval($aUserData['uid']), - 'user' => $aUserData['users_name'], - 'full_name' => $aUserData['full_name'], - 'htmleditormode' => $aUserData['htmleditormode'], - 'templateeditormode' => $aUserData['templateeditormode'], - 'questionselectormode' => $aUserData['questionselectormode'], - 'dateformat' => $aUserData['dateformat'], - 'adminlang' => 'en' - ); - foreach ($session as $k => $v) - Yii::app()->session[$k] = $v; - Yii::app()->user->setId($aUserData['uid']); - - $this->controller->_GetSessionUserRights($aUserData['uid']); - return true; - } - - /** - * This function checks if the XML-RPC session key is valid. If yes returns true, otherwise false and sends an error message with error code 1 - * - * @access protected - * @param string $sSessionKey Auth credentials - * @return bool - */ - protected function _checkSessionKey($sSessionKey) - { - $criteria = new CDbCriteria; - $criteria->condition = 'expire < ' . time(); - Session::model()->deleteAll($criteria); - $oResult = Session::model()->findByPk($sSessionKey); - - if (is_null($oResult)) - return false; - else - { - $this->_jumpStartSession($oResult->data); - return true; - } - } -} +} \ No newline at end of file diff --git a/application/controllers/admin/templates.php b/application/controllers/admin/templates.php index 1f10ecdc01a..f818ac55de1 100644 --- a/application/controllers/admin/templates.php +++ b/application/controllers/admin/templates.php @@ -244,7 +244,7 @@ public function uploadfile() { $uploadresult = $clang->gT("This filename is not allowed to be uploaded."); } - elseif(!in_array(substr(strrchr($filename, '.'),1),explode ( "," , $allowedtemplateuploads ))) + elseif(!in_array(strtolower(substr(strrchr($filename, '.'),1)),explode ( "," , $allowedtemplateuploads ))) { $uploadresult = $clang->gT("This file type is not allowed to be uploaded."); diff --git a/application/helpers/admin/activate_helper.php b/application/helpers/admin/activate_helper.php index 5bc2e6897d9..f080b724beb 100644 --- a/application/helpers/admin/activate_helper.php +++ b/application/helpers/admin/activate_helper.php @@ -14,7 +14,9 @@ /** * fixes the numbering of questions -* @param $fixnumbering +* This can happen if question 1 have subquestion code 1 and have question 11 in same survey and group (then same SGQA) +* @param int $fixnumbering +* @todo can call this function (no $_GET, but getParam) AND do it with Yii */ function fixNumbering($fixnumbering, $iSurveyID) { @@ -23,11 +25,11 @@ function fixNumbering($fixnumbering, $iSurveyID) LimeExpressionManager::RevertUpgradeConditionsToRelevance($iSurveyID); //Fix a question id - requires renumbering a question - $oldqid = $fixnumbering; - $query = "SELECT qid FROM {{questions}} ORDER BY qid DESC"; - $result = dbSelectLimitAssoc($query, 1); - foreach ($result->readAll() as $row) {$lastqid=$row['qid'];} + $oldqid = (int) $fixnumbering; + $lastqid=Questions::model()->getMaxId('qid', true); // Always refresh as we insert new qid's $newqid=$lastqid+1; + + // Not sure we can do this in MSSQL ? $query = "UPDATE {{questions}} SET qid=$newqid WHERE qid=$oldqid"; $result = db_execute_assosc($query); // Update subquestions @@ -181,7 +183,8 @@ function checkQuestions($postsid, $iSurveyID, $qtypes) $conquery= "SELECT {{conditions}}.qid, cqid, {{questions}}.question, " . "{{questions}}.gid " . "FROM {{conditions}}, {{questions}}, {{groups}} " - . "WHERE {{conditions}}.qid={{questions}}.qid " + . "WHERE {{questions}}.sid={$iSurveyID} " + . "AND {{conditions}}.qid={{questions}}.qid " . "AND {{questions}}.gid={{groups}}.gid ORDER BY {{conditions}}.qid"; $conresult=Yii::app()->db->createCommand($conquery)->query()->readAll(); //2: Check each conditions cqid that it occurs later than the cqid diff --git a/application/helpers/admin/export/SurveyDao.php b/application/helpers/admin/export/SurveyDao.php index 3b80cd565d4..52716be8fa0 100644 --- a/application/helpers/admin/export/SurveyDao.php +++ b/application/helpers/admin/export/SurveyDao.php @@ -17,17 +17,17 @@ public function loadSurveyById($id, $lang = null) { $survey = new SurveyObj(); $clang = Yii::app()->lang; - + $intId = sanitize_int($id); $survey->id = $intId; - $survey->info = getSurveyInfo($survey->id); + $survey->info = getSurveyInfo($survey->id); $availableLanguages = Survey::model()->findByPk($intId)->getAllLanguages(); - + if (is_null($lang) || in_array($lang, $availableLanguages) === false) { // use base language when requested language is not found or no specific language is requested $lang = Survey::model()->findByPk($intId)->language; } - + $clang = new limesurvey_lang($lang); $survey->fieldMap = createFieldMap($intId,'full',true,false,$lang); // Check to see if timings are present and add to fieldmap if needed @@ -40,7 +40,7 @@ public function loadSurveyById($id, $lang = null) //The id given to us is not an integer, croak. safeDie("An invalid survey ID was encountered: $sid"); } - + //Load groups $sQuery = 'SELECT g.* FROM {{groups}} AS g '. 'WHERE g.sid = '.$intId.' AND g.language = \'' . $lang . '\' ' . @@ -54,7 +54,7 @@ public function loadSurveyById($id, $lang = null) 'WHERE q.sid = '.$intId.' AND q.language = \''.$lang.'\' '. 'ORDER BY g.group_order, q.question_order;'; $survey->questions = Yii::app()->db->createCommand($sQuery)->query()->readAll(); - + //Load answers $sQuery = 'SELECT DISTINCT a.* FROM {{answers}} AS a '. 'JOIN {{questions}} AS q ON a.qid = q.qid '. @@ -72,7 +72,7 @@ public function loadSurveyById($id, $lang = null) $sQuery = 'SELECT * FROM {{surveys_languagesettings}} WHERE surveyls_survey_id = '.$intId.' AND surveyls_language = \'' . $lang . '\';'; $recordSet = Yii::app()->db->createCommand($sQuery)->query(); $survey->languageSettings = $recordSet->read(); - $recordSet->close(); + $recordSet->close(); return $survey; } @@ -84,15 +84,17 @@ public function loadSurveyById($id, $lang = null) * If none are then all responses are loaded. * * @param Survey $survey - * @param int $iMinimum - * @param int $iMaximum + * @param int $iMinimum + * @param int $iMaximum + * @param string $sFilter An optional filter for the results + * @param string $completionState all, complete or incomplete */ - public function loadSurveyResults(SurveyObj $survey, $iMinimum, $iMaximum, $sFilter='' ) + public function loadSurveyResults(SurveyObj $survey, $iMinimum, $iMaximum, $sFilter='', $completionState = 'all' ) { // Get info about the survey $aSelectFields=Yii::app()->db->schema->getTable('{{survey_' . $survey->id . '}}')->getColumnNames(); - + $oRecordSet = Yii::app()->db->createCommand()->from('{{survey_' . $survey->id . '}}'); if (tableExists('tokens_'.$survey->id) && array_key_exists ('token',SurveyDynamic::model($survey->id)->attributes) && Permission::model()->hasSurveyPermission($survey->id,'tokens','read')) { @@ -110,10 +112,31 @@ public function loadSurveyResults(SurveyObj $survey, $iMinimum, $iMaximum, $sFil $aSelectFields[]='{{survey_' . $survey->id . '}}.id'; } - if ($sFilter!='') - $oRecordSet->where($sFilter); - - $iOffset = $iMinimum - 1; - $survey->responses=$oRecordSet->select($aSelectFields)->order('{{survey_' . $survey->id . '}}.id')->limit($iMaximum - $iOffset, $iOffset)->query(); + $aParams = array( + 'min'=>$iMinimum, + 'max'=>$iMaximum + ); + $selection = 'id >= :min AND id <= :max'; + $oRecordSet->where($selection, $aParams); + + if ($sFilter!='') { + $oRecordSet->andWhere($sFilter); + } + + switch ($completionState) + { + case 'incomplete': + $oRecordSet->andWhere('submitdate IS NULL'); + break; + case 'complete': + $oRecordSet->andWhere('submitdate IS NOT NULL'); + break; + case 'all': + default: + // Do nothing, all responses + break; + } + + $survey->responses=$oRecordSet->select($aSelectFields)->query(); } } \ No newline at end of file diff --git a/application/helpers/admin/export/Writer.php b/application/helpers/admin/export/Writer.php index 77a2d9ed3da..d2209755fe8 100644 --- a/application/helpers/admin/export/Writer.php +++ b/application/helpers/admin/export/Writer.php @@ -36,33 +36,6 @@ public function init(SurveyObj $survey, $sLanguageCode, FormattingOptions $oOpti } } - - /** - * Returns true if, given the $oOptions, the response should be included in the - * output, and false if otherwise. - * - * @param mixed $response - * @param FormattingOptions $oOptions - * @return boolean - */ - protected function shouldOutputResponse(array $response, FormattingOptions $oOptions) - { - switch ($oOptions->responseCompletionState) - { - default: - case 'all': - return true; - break; - case 'incomplete': - return !isset($response['submitdate']); - break; - case 'complete': - return isset($response['submitdate']); - break; - - } - } - /** * Returns an abbreviated heading for the survey's question that matches * the $fieldName parameter (or false if a match is not found). @@ -428,12 +401,6 @@ final public function write(SurveyObj $survey, $sLanguageCode, FormattingOptions { $elementArray = array(); - //If we shouldn't be outputting this response then we should skip the rest - //of the loop and continue onto the next value. - if (!$this->shouldOutputResponse($response, $oOptions)) - { - continue; - } foreach ($oOptions->selectedColumns as $column) { $value = $response[$column]; diff --git a/application/helpers/admin/exportresults_helper.php b/application/helpers/admin/exportresults_helper.php index 3d3da6b1108..cd096f749d8 100644 --- a/application/helpers/admin/exportresults_helper.php +++ b/application/helpers/admin/exportresults_helper.php @@ -128,8 +128,8 @@ function exportSurvey($iSurveyId, $sLanguageCode, $sExportPlugin, FormattingOpti $surveyDao = new SurveyDao(); $survey = $surveyDao->loadSurveyById($iSurveyId, $sLanguageCode); $writer->init($survey, $sLanguageCode, $oOptions); - - $surveyDao->loadSurveyResults($survey, $oOptions->responseMinRecord, $oOptions->responseMaxRecord, $sFilter); + + $surveyDao->loadSurveyResults($survey, $oOptions->responseMinRecord, $oOptions->responseMaxRecord, $sFilter, $oOptions->responseCompletionState); $writer->write($survey, $sLanguageCode, $oOptions,true); $result = $writer->close(); diff --git a/application/helpers/frontend_helper.php b/application/helpers/frontend_helper.php index 7761ad77a69..00f16e26787 100644 --- a/application/helpers/frontend_helper.php +++ b/application/helpers/frontend_helper.php @@ -2271,13 +2271,13 @@ function doAssessment($surveyid, $returndataonly=false) if ($val >= $assessed['min'] && $val <= $assessed['max'] && $returndataonly===false) { $assessments .= "\t - +
-
".str_replace(array("{PERC}", "{TOTAL}"), array($val, $total), $assessed['name'])."
".str_replace(array("{PERC}", "{TOTAL}"), array($val, $total), $assessed['message'])." + ".str_replace(array("{PERC}", "{TOTAL}"), array($val, $total), $assessed['message'])."

\n"; @@ -2294,10 +2294,13 @@ function doAssessment($surveyid, $returndataonly=false) if ($total >= $assessed['min'] && $total <= $assessed['max'] && $returndataonly===false) { $assessments .= "\t\t\t - +
".str_replace(array("{PERC}", "{TOTAL}"), array($val, $total), stripslashes($assessed['name']))." -
- + + +
".str_replace(array("{PERC}", "{TOTAL}"), array($val, $total), stripslashes($assessed['message']))." + ".str_replace(array("{PERC}", "{TOTAL}"), array($val, $total), stripslashes($assessed['name']))." +
".str_replace(array("{PERC}", "{TOTAL}"), array($val, $total), stripslashes($assessed['message']))."
\n"; diff --git a/application/helpers/qanda_helper.php b/application/helpers/qanda_helper.php index a494edc2bc2..77c8f2cf433 100644 --- a/application/helpers/qanda_helper.php +++ b/application/helpers/qanda_helper.php @@ -3518,6 +3518,7 @@ function do_shortfreetext($ia) class=\"mapservice\" value = \"{$aQuestionAttributes['location_mapservice']}\" >
"; + header_includes("map.js"); if ($aQuestionAttributes['location_mapservice']==1 && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != "off") Yii::app()->getClientScript()->registerScriptFile("https://maps.googleapis.com/maps/api/js?sensor=false"); else if ($aQuestionAttributes['location_mapservice']==1) @@ -4490,14 +4491,15 @@ function do_array($ia) } $lresult= Answer::model()->findAll(array('order'=>'sortorder, code', 'condition'=>'qid=:qid AND language=:language AND scale_id=0', 'params'=>array(':qid'=>$ia[0],':language'=>$_SESSION['survey_'.Yii::app()->getConfig('surveyID')]['s_lang']))); + $labelans=array(); + $labelcode=array(); + foreach ($lresult as $lrow) + { + $labelans[]=$lrow->answer; + $labelcode[]=$lrow->code; + } if ($useDropdownLayout === false && count($lresult) > 0) { - foreach ($lresult as $lrow) - { - $labelans[]=$lrow->answer; - $labelcode[]=$lrow->code; - } - $sQuery = "SELECT count(qid) FROM {{questions}} WHERE parent_qid={$ia[0]} AND question like '%|%' "; $iCount = Yii::app()->db->createCommand($sQuery)->queryScalar(); @@ -4973,14 +4975,15 @@ function do_array_multitext($ia) $lquery = "SELECT * FROM {{questions}} WHERE parent_qid={$ia[0]} AND language='".$_SESSION['survey_'.Yii::app()->getConfig('surveyID')]['s_lang']."' and scale_id=1 ORDER BY question_order"; $lresult = Yii::app()->db->createCommand($lquery)->query(); - if (count($lresult)> 0) + $labelans=array(); + $labelcode=array(); + foreach($lresult->readAll() as $lrow) + { + $labelans[]=$lrow['question']; + $labelcode[]=$lrow['title']; + } + if ($numrows=count($labelans)) { - foreach($lresult->readAll() as $lrow) - { - $labelans[]=$lrow['question']; - $labelcode[]=$lrow['title']; - } - $numrows=count($labelans); if ($ia[6] != 'Y' && SHOW_NO_ANSWER == 1) {$numrows++;} if( ($show_grand == true && $show_totals == 'col' ) || $show_totals == 'row' || $show_totals == 'both' ) { @@ -5299,14 +5302,15 @@ function do_array_multiflexi($ia) $lquery = "SELECT * FROM {{questions}} WHERE parent_qid={$ia[0]} AND language='".$_SESSION['survey_'.Yii::app()->getConfig('surveyID')]['s_lang']."' and scale_id=1 ORDER BY question_order"; $lresult = dbExecuteAssoc($lquery); $aQuestions=$lresult->readAll(); - if (count($aQuestions) > 0) + $labelans=array(); + $labelcode=array(); + foreach ($aQuestions as $lrow) + { + $labelans[]=$lrow['question']; + $labelcode[]=$lrow['title']; + } + if ($numrows=count($labelans)) { - foreach ($aQuestions as $lrow) - { - $labelans[]=$lrow['question']; - $labelcode[]=$lrow['title']; - } - $numrows=count($labelans); if ($ia[6] != 'Y' && SHOW_NO_ANSWER == 1) {$numrows++;} $cellwidth=$columnswidth/$numrows; @@ -5557,14 +5561,17 @@ function do_arraycolumns($ia) $lquery = "SELECT * FROM {{answers}} WHERE qid=".$ia[0]." AND language='".$_SESSION['survey_'.Yii::app()->getConfig('surveyID')]['s_lang']."' and scale_id=0 ORDER BY sortorder, code"; $oAnswers = dbExecuteAssoc($lquery); $aAnswers = $oAnswers->readAll(); - if (count($aAnswers) > 0) + $labelans=array(); + $labelcode=array(); + $labels=array(); + foreach ($aAnswers as $lrow) + { + $labelans[]=$lrow['answer']; + $labelcode[]=$lrow['code']; + $labels[]=array("answer"=>$lrow['answer'], "code"=>$lrow['code']); + } + if (count($labelans) > 0) { - foreach ($aAnswers as $lrow) - { - $labelans[]=$lrow['answer']; - $labelcode[]=$lrow['code']; - $labels[]=array("answer"=>$lrow['answer'], "code"=>$lrow['code']); - } if ($ia[6] != 'Y' && SHOW_NO_ANSWER == 1) { $labelcode[]=''; diff --git a/application/helpers/remotecontrol/remotecontrol_handle.php b/application/helpers/remotecontrol/remotecontrol_handle.php new file mode 100644 index 00000000000..1dc45bd4c61 --- /dev/null +++ b/application/helpers/remotecontrol/remotecontrol_handle.php @@ -0,0 +1,2343 @@ +controller = $controller; + } + + + /** + * RPC routine to create a session key. + * + * @access public + * @param string $username + * @param string $password + * @return string + */ + public function get_session_key($username, $password) + { + if ($this->_doLogin($username, $password)) + { + $this->_jumpStartSession($username); + $sSessionKey = randomChars(32); + + $session = new Session; + $session->id = $sSessionKey; + $session->expire = time() + Yii::app()->getConfig('iSessionExpirationTime'); + $session->data = $username; + $session->save(); + + return $sSessionKey; + } + else + return array('status' => 'Invalid user name or password'); + } + + /** + * Closes the RPC session + * + * @access public + * @param string $sSessionKey + * @return string + */ + public function release_session_key($sSessionKey) + { + Session::model()->deleteAllByAttributes(array('id' => $sSessionKey)); + $criteria = new CDbCriteria; + $criteria->condition = 'expire < ' . time(); + Session::model()->deleteAll($criteria); + return 'OK'; + } + + /** + * RPC Routine to get settings. + * + * @access public + * @param string $sSessionKey Auth Credentials + * @param string $sSetttingName Name of the setting to get + * @return string The requested value + */ + public function get_site_settings($sSessionKey,$sSetttingName) + { + if ($this->_checkSessionKey($sSessionKey)) + { + if(Permission::model()->hasGlobalPermission('superadmin','read')) + { + if (Yii::app()->getConfig($sSetttingName) !== false) + return Yii::app()->getConfig($sSetttingName); + else + return array('status' => 'Invalid setting'); + } + else + return array('status' => 'Invalid setting'); + } + else + return array('status' => 'Invalid session key'); + } + + + /* Survey specific functions */ + + /** + * RPC Routine to add an empty survey with minimum details. + * Used as a placeholder for importing groups and/or questions. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID The wish id of the Survey to add + * @param string $sSurveyTitle Title of the new Survey + * @param string $sSurveyLanguage Default language of the Survey + * @param string $sformat Question appearance format + * @return array|string|int + */ + public function add_survey($sSessionKey, $iSurveyID, $sSurveyTitle, $sSurveyLanguage, $sformat = 'G') + { + Yii::app()->loadHelper("surveytranslator"); + if ($this->_checkSessionKey($sSessionKey)) + { + if (Permission::model()->hasGlobalPermission('surveys','create')) + { + if( $sSurveyTitle=='' || $sSurveyLanguage=='' || !array_key_exists($sSurveyLanguage,getLanguageDataRestricted()) || !in_array($sformat, array('A','G','S'))) + return array('status' => 'Faulty parameters'); + + $aInsertData = array('template' => 'default', + 'owner_id' => Yii::app()->session['loginID'], + 'active' => 'N', + 'language'=>$sSurveyLanguage, + 'format' => $sformat + ); + + if (!is_null($iSurveyID)) + $aInsertData['wishSID'] = $iSurveyID; + + try + { + $iNewSurveyid = Survey::model()->insertNewSurvey($aInsertData); + if (!$iNewSurveyid) + return array('status' => 'Creation Failed'); + + $sTitle = html_entity_decode($sSurveyTitle, ENT_QUOTES, "UTF-8"); + + // Load default email templates for the chosen language + $oLanguage = new Limesurvey_lang($sSurveyLanguage); + $aDefaultTexts = templateDefaultTexts($oLanguage, 'unescaped'); + unset($oLanguage); + + $bIsHTMLEmail = false; + + $aInsertData = array( + 'surveyls_survey_id' => $iNewSurveyid, + 'surveyls_title' => $sTitle, + 'surveyls_language' => $sSurveyLanguage, + ); + + $langsettings = new SurveyLanguageSetting; + $langsettings->insertNewSurvey($aInsertData); + Permission::model()->giveAllSurveyPermissions(Yii::app()->session['loginID'], $iNewSurveyid); + + return (int)$iNewSurveyid; + } + catch(Exception $e) + { + return array('status' => $e->getmessage()); + } + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid session key'); + } + + /** + * RPC Routine to delete a survey. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID The id of the Survey to be deleted + * @return array Returns Status + */ + public function delete_survey($sSessionKey, $iSurveyID) + { + if ($this->_checkSessionKey($sSessionKey)) + { + if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'delete')) + { + Survey::model()->deleteSurvey($iSurveyID,true); + return array('status' => 'OK'); + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid session key'); + } + + /** + * RPC Routine to import a survey - imports lss,csv,xls or survey zip archive. + * + * @access public + * @param string $sSessionKey Auth Credentials + * @param string $sImportData String containing the BASE 64 encoded data of a lss,csv,xls or survey zip archive + * @param string $sImportDataType lss,csv,xls or zip + * @param string $sNewSurveyName The optional new name of the survey + * @param integer $DestSurveyID This is the new ID of the survey - if already used a random one will be taken instead + * @return array|integer iSurveyID - ID of the new survey + */ + public function import_survey($sSessionKey, $sImportData, $sImportDataType, $sNewSurveyName=NULL, $DestSurveyID=NULL) + { + if ($this->_checkSessionKey($sSessionKey)) + { + if (Permission::model()->hasGlobalPermission('surveys','create')) + { + if (!in_array($sImportDataType,array('zip','csv','xls','lss'))) return array('status' => 'Invalid extension'); + Yii::app()->loadHelper('admin/import'); + // First save the data to a temporary file + $sFullFilePath = Yii::app()->getConfig('tempdir') . DIRECTORY_SEPARATOR . randomChars(40).'.'.$sImportDataType; + file_put_contents($sFullFilePath,base64_decode(chunk_split($sImportData))); + $aImportResults = importSurveyFile($sFullFilePath, true, $sNewSurveyName, $DestSurveyID); + unlink($sFullFilePath); + if (isset($aImportResults['error'])) return array('status' => 'Error: '.$aImportResults['error']); + else + { + return (int)$aImportResults['newsid']; + } + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid session key'); + } + + /** + * RPC Routine to get survey properties. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID The id of the Survey to be checked + * @param array $aSurveySettings The properties to get + * @return array + */ + public function get_survey_properties($sSessionKey,$iSurveyID, $aSurveySettings) + { + Yii::app()->loadHelper("surveytranslator"); + if ($this->_checkSessionKey($sSessionKey)) + { + $oSurvey = Survey::model()->findByPk($iSurveyID); + if (!isset($oSurvey)) + { + return array('status' => 'Error: Invalid survey ID'); + } + if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'read')) + { + $aBasicDestinationFields=Survey::model()->tableSchema->columnNames; + $aSurveySettings=array_intersect($aSurveySettings,$aBasicDestinationFields); + + if (empty($aSurveySettings)) + return array('status' => 'No valid Data'); + $aResult = array(); + foreach($aSurveySettings as $sPropertyName) + { + $aResult[$sPropertyName]=$oSurvey->$sPropertyName; + } + return $aResult; + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid Session key'); + } + + /** + * RPC Routine to set survey properties. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param integer $iSurveyID - ID of the survey + * @param array|struct $aSurveyData - An array with the particular fieldnames as keys and their values to set on that particular survey + * @return array Of succeeded and failed nodifications according to internal validation. + */ + public function set_survey_properties($sSessionKey, $iSurveyID, $aSurveyData) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $oSurvey=Survey::model()->findByPk($iSurveyID); + if (is_null($oSurvey)) + { + return array('status' => 'Error: Invalid survey ID'); + } + if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'update')) + { + // Remove fields that may not be modified + unset($aSurveyData['sid']); + unset($aSurveyData['owner_id']); + unset($aSurveyData['active']); + unset($aSurveyData['language']); + unset($aSurveyData['additional_languages']); + // Remove invalid fields + $aDestinationFields=array_flip(Survey::model()->tableSchema->columnNames); + $aSurveyData=array_intersect_key($aSurveyData,$aDestinationFields); + $oSurvey=Survey::model()->findByPk($iSurveyID); + $aBasicAttributes = $oSurvey->getAttributes(); + $aResult = array(); + + if ($oSurvey->active=='Y') + { + // remove all fields that may not be changed when a survey is active + unset($aSurveyData['anonymized']); + unset($aSurveyData['datestamp']); + unset($aSurveyData['savetimings']); + unset($aSurveyData['ipaddr']); + unset($aSurveyData['refurl']); + } + + if (empty($aSurveyData)) + return array('status' => 'No valid Data'); + + foreach($aSurveyData as $sFieldName=>$sValue) + { + $oSurvey->$sFieldName=$sValue; + try + { + $bSaveResult=$oSurvey->save(); // save the change to database + //unset the value if it fails, so as to prevent future fails + $aResult[$sFieldName]=$bSaveResult; + if (!$bSaveResult) + $oSurvey->$sFieldName=$aBasicAttributes[$sFieldName]; + } + catch(Exception $e) + { + //unset the value that caused the exception + $oSurvey->$sFieldName=$aBasicAttributes[$sFieldName]; + } + } + return $aResult; + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid Session key'); + } + + /** + * RPC Routine to list the ids and info of surveys belonging to a user. + * Returns array of ids and info. + * If user is admin he can get surveys of every user (parameter sUser) or all surveys (sUser=null) + * Else only the syrveys belonging to the user requesting will be shown. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param string $sUser Optional username to get list of surveys + * @return array The list of surveys + */ + public function list_surveys($sSessionKey, $sUser=NULL) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $sCurrentUser = Yii::app()->session['user']; + + if( Permission::model()->hasGlobalPermission('superadmin','read') ) + { + if ($sUser == null) + $aUserSurveys = Survey::model()->findAll(); //list all surveys + else + { + $aUserData = User::model()->findByAttributes(array('users_name' => $sUser)); + if (!isset($aUserData)) + return array('status' => 'Invalid user'); + else + $aUserSurveys = Survey::model()->findAllByAttributes(array("owner_id"=>$aUserData->attributes['uid'])); + } + } + else + { + if (($sCurrentUser == $sUser) || ($sUser == null) ) + { + $sUid = User::model()->findByAttributes(array('users_name' => $sCurrentUser))->uid; + $aUserSurveys = Survey::model()->findAllByAttributes(array("owner_id"=>$sUid)); + } + else + return array('status' => 'No permission'); + } + + if(count($aUserSurveys)==0) + return array('status' => 'No surveys found'); + + foreach ($aUserSurveys as $oSurvey) + { + $oSurveyLanguageSettings = SurveyLanguageSetting::model()->findByAttributes(array('surveyls_survey_id' => $oSurvey->primaryKey, 'surveyls_language' => $oSurvey->language)); + if (!isset($oSurveyLanguageSettings)) + $aSurveyTitle = ''; + else + $aSurveyTitle = $oSurveyLanguageSettings->attributes['surveyls_title']; + $aData[]= array('sid'=>$oSurvey->primaryKey,'surveyls_title'=>$aSurveyTitle,'startdate'=>$oSurvey->attributes['startdate'],'expires'=>$oSurvey->attributes['expires'],'active'=>$oSurvey->attributes['active']); + } + return $aData; + } + else + return array('status' => 'Invalid session key'); + } + + + + /** + * RPC Routine that launches a newly created survey. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID The id of the survey to be activated + * @return array The result of the activation + */ + public function activate_survey($sSessionKey, $iSurveyID) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $oSurvey=Survey::model()->findByPk($iSurveyID); + if (is_null($oSurvey)) + return array('status' => 'Error: Invalid survey ID'); + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveyactivation', 'update')) + { + Yii::app()->loadHelper('admin/activate'); + $aActivateResults = activateSurvey($iSurveyID); + + if (isset($aActivateResults['error'])) return array('status' => 'Error: '.$aActivateResults['error']); + else + { + return $aActivateResults; + } + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid session key'); + } + + /** + * RPC routine to export statistics of a survey to a user. + * Returns string - base64 encoding of the statistics. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Id of the Survey + * @param string $docType Type of documents the exported statistics should be + * @param string $sLanguage Optional language of the survey to use + * @param string $graph Create graph option + * @param int|array $groupIDs An OPTIONAL array (ot a single int) containing the groups we choose to generate statistics from + * @return string Base64 encoded string with the statistics file + */ + public function export_statistics($sSessionKey, $iSurveyID, $docType='pdf', $sLanguage=null, $graph='0', $groupIDs=null) + { + Yii::app()->loadHelper('admin/statistics'); + + $tempdir = Yii::app()->getConfig("tempdir"); + if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key'); + + $oSurvey = Survey::model()->findByPk($iSurveyID); + if (!isset($oSurvey)) + return array('status' => 'Error: Invalid survey ID');; + + if(Survey::model()->findByPk($iSurveyID)->owner_id != $_SESSION['loginID']) + return array('status' => 'Error: No Permission'); + $aAdditionalLanguages = array_filter(explode(" ", $oSurvey->additional_languages)); + + if (is_null($sLanguage)|| !in_array($sLanguage,$aAdditionalLanguages)) + $sLanguage = $oSurvey->language; + + $oAllQuestions =Question::model()->getQuestionList($iSurveyID, $sLanguage); + if (!isset($oAllQuestions)) + return array('status' => 'No available data'); + + if($groupIDs!=null) + { + if(is_int($groupIDs)) + $groupIDs = array($groupIDs); + + if(is_array($groupIDs)) + { + //check that every value of the array belongs to the survey defined + $aGroups = QuestionGroup::model()->findAllByAttributes(array('sid' => $iSurveyID)); + + foreach( $aGroups as $group) + $validGroups[] = $group['gid']; + + $groupIDs=array_intersect($groupIDs,$validGroups); + + if (empty($groupIDs)) + return array('status' => 'Error: Invalid group ID'); + + foreach($oAllQuestions as $key => $aQuestion) + { + if(!in_array($aQuestion['gid'],$groupIDs)) + unset($oAllQuestions[$key]); + } + } + else + return array('status' => 'Error: Invalid group ID'); + } + + if (!isset($oAllQuestions)) + return array('status' => 'No available data'); + + usort($oAllQuestions, 'groupOrderThenQuestionOrder'); + + $aSummary = createCompleteSGQA($iSurveyID,$oAllQuestions,$sLanguage); + + $helper = new statistics_helper(); + switch ($docType) + { + case 'pdf': + $sTempFile = $helper->generate_statistics($iSurveyID,$aSummary,$aSummary,$graph,$docType,'F',$sLanguage); + $sResult = file_get_contents($sTempFile); + unlink($sTempFile); + break; + case 'xls': + $sTempFile = $helper->generate_statistics($iSurveyID,$aSummary,$aSummary,'0',$docType, 'F',$sLanguage); + $sResult = file_get_contents($sTempFile); + unlink($sTempFile); + break; + case 'html': + $sResult = $helper->generate_statistics($iSurveyID,$aSummary,$aSummary,'0',$docType, 'DD',$sLanguage); + break; + } + + return base64_encode($sResult); + + } + +/** + * RPC Routine to export submission timeline. + * Returns an array of values (count and period) + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Id of the Survey + * @param string $sType (day|hour) + * @param string $dStart + * @param string $dEnd + * @return array On success: The timeline. On failure array with error information + * */ + public function export_timeline($sSessionKey, $iSurveyID, $sType, $dStart, $dEnd) + { + if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key'); + if (!in_array($sType, array('day','hour'))) return array('status' => 'Invalid Period'); + if (!hasSurveyPermission($iSurveyID, 'responses', 'read')) return array('status' => 'No permission'); + $oSurvey=Survey::model()->findByPk($iSurveyID); + if (is_null($oSurvey)) return array('status' => 'Error: Invalid survey ID'); + if (!tableExists('{{survey_' . $iSurveyID . '}}')) return array('status' => 'No available data'); + + $oResponses = SurveyDynamic::model($iSurveyID)->timeline($sType, $dStart, $dEnd); + if (empty($oResponses)) return array('status' => 'No valid Data'); + + return $oResponses; + + } + + /** + * RPC routine to get survey summary, regarding token usage and survey participation. + * Returns the requested value as string. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Id of the Survey to get summary + * @param string $sStatName Name of the sumamry option + * @return string The requested value + */ + public function get_summary($sSessionKey,$iSurveyID, $sStatName) + { + $aPermittedStats = array(); + if ($this->_checkSessionKey($sSessionKey)) + { + $aPermittedTokenStats = array('token_count', + 'token_invalid', + 'token_sent', + 'token_opted_out', + 'token_completed' + ); + $aPermittedSurveyStats = array('completed_responses', + 'incomplete_responses', + 'full_responses' + ); + $aPermittedStats = array_merge($aPermittedSurveyStats, $aPermittedTokenStats); + $oSurvey = Survey::model()->findByPk($iSurveyID); + if (!isset($oSurvey)) + return array('status' => 'Invalid surveyid'); + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'read')) + { + if(in_array($sStatName, $aPermittedTokenStats)) + { + if (tableExists('{{tokens_' . $iSurveyID . '}}')) + $summary = TokenDynamic::model($iSurveyID)->summary(); + else + return array('status' => 'No available data'); + } + + if(in_array($sStatName, $aPermittedSurveyStats) && !tableExists('{{survey_' . $iSurveyID . '}}')) + return array('status' => 'No available data'); + + if (!in_array($sStatName, $aPermittedStats)) + return array('status' => 'No such property'); + + + switch($sStatName) + { + case 'token_count': + if (isset($summary)) + return $summary['tkcount']; + break; + case 'token_invalid': + if (isset($summary)) + return $summary['tkinvalid']; + break; + case 'token_sent': + if (isset($summary)) + return $summary['tksent']; + break; + case 'token_opted_out': + if (isset($summary)) + return $summary['tkoptout']; + break; + case 'token_completed'; + if (isset($summary)) + return $summary['tkcompleted']; + break; + case 'completed_responses': + return SurveyDynamic::model($iSurveyID)->count('submitdate IS NOT NULL'); + break; + case 'incomplete_responses': + return SurveyDynamic::model($iSurveyID)->countByAttributes(array('submitdate' => null)); + break; + case 'full_responses'; + return SurveyDynamic::model($iSurveyID)->count(); + break; + default: + return array('status' => 'Data is not available'); + } + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid session key'); + } + + /*Survey language specific functions */ + + /** + * RPC Routine to add a survey language. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param integer $iSurveyID ID of the survey where a token table will be created for + * @param string $sLanguage A valid language shortcut to add to the current survey. If the language already exists no error will be given. + * @return array Status=>OK when successfull, otherwise the error description + */ + public function add_language($sSessionKey, $iSurveyID, $sLanguage) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $oSurvey=Survey::model()->findByPk($iSurveyID); + if (is_null($oSurvey)) + { + return array('status' => 'Error: Invalid survey ID'); + } + if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'update')) + { + Yii::app()->loadHelper('surveytranslator'); + $aLanguages=getLanguageData(); + + if(!isset($aLanguages[$sLanguage])) + { + return array('status' => 'Invalid language'); + } + $oSurvey=Survey::model()->findByPk($iSurveyID); + if ($sLanguage==$oSurvey->language) + { + return array('status' => 'OK'); + } + $aLanguages=$oSurvey->getAdditionalLanguages(); + $aLanguages[]=$sLanguage; + $aLanguages=array_unique($aLanguages); + $oSurvey->additional_languages=implode(' ',$aLanguages); + try + { + $oSurvey->save(); // save the change to database + $languagedetails=getLanguageDetails($sLanguage); + + $insertdata = array( + 'surveyls_survey_id' => $iSurveyID, + 'surveyls_language' => $sLanguage, + 'surveyls_title' => '', + 'surveyls_dateformat' => $languagedetails['dateformat'] + ); + $setting= new SurveyLanguageSetting; + foreach ($insertdata as $k => $v) + $setting->$k = $v; + $setting->save(); + fixLanguageConsistency($iSurveyID,$sLanguage); + return array('status' => 'OK'); + } + catch(Exception $e) + { + return array('status' => 'Error'); + } + + } + else + return array('status' => 'No permission'); + } + } + + /** + * RPC Routine to delete a survey language. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param integer $iSurveyID ID of the survey where a token table will be created for + * @param string $sLanguage A valid language shortcut to delete from the current survey. If the language does not exist in that survey no error will be given. + * @return array Status=>OK when successfull, otherwise the error description + */ + public function delete_language($sSessionKey, $iSurveyID, $sLanguage) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $oSurvey=Survey::model()->findByPk($iSurveyID); + if (is_null($oSurvey)) + { + return array('status' => 'Error: Invalid survey ID'); + } + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'update')) + { + + Yii::app()->loadHelper('surveytranslator'); + $aLanguages=getLanguageData(); + + if(!isset($aLanguages[$sLanguage])) + { + return array('status' => 'Invalid language'); + } + $oSurvey=Survey::model()->findByPk($iSurveyID); + if ($sLanguage==$oSurvey->language) + { + return array('status' => 'Cannot remove base language'); + } + $aLanguages=$oSurvey->getAdditionalLanguages(); + unset($aLanguages[$sLanguage]); + $oSurvey->additional_languages=implode(' ',$aLanguages); + try + { + $oSurvey->save(); // save the change to database + SurveyLanguageSetting::model()->deleteByPk(array('surveyls_survey_id' => $iSurveyID, 'surveyls_language' => $sLanguage)); + cleanLanguagesFromSurvey($iSurveyID,$oSurvey->additional_languages); + return array('status' => 'OK'); + } + catch(Exception $e) + { + return array('status' => 'Error'); + } + + } + else + return array('status' => 'No permission'); + } + } + + + /** + * RPC Routine to get survey language properties. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Dd of the Survey + * @param array $aSurveyLocaleSettings Properties to get + * @param string $sLang Language to use + * @return array The requested values + */ + public function get_language_properties($sSessionKey,$iSurveyID, $aSurveyLocaleSettings, $sLang=NULL) + { + Yii::app()->loadHelper("surveytranslator"); + if ($this->_checkSessionKey($sSessionKey)) + { + $oSurvey = Survey::model()->findByPk($iSurveyID); + if (!isset($oSurvey)) + { + return array('status' => 'Error: Invalid survey ID'); + } + if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'read')) + { + $aBasicDestinationFields=SurveyLanguageSetting::model()->tableSchema->columnNames; + $aSurveyLocaleSettings=array_intersect($aSurveyLocaleSettings,$aBasicDestinationFields); + + if ($sLang == NULL || !array_key_exists($sLang,getLanguageDataRestricted())) + $sLang = $oSurvey->language; + + + $oSurveyLocale=SurveyLanguageSetting::model()->findByAttributes(array('surveyls_survey_id' => $iSurveyID, 'surveyls_language' => $sLang)); + $aResult = array(); + + if (empty($aSurveyLocaleSettings)) + return array('status' => 'No valid Data'); + + foreach($aSurveyLocaleSettings as $sPropertyName) + { + $aResult[$sPropertyName]=$oSurveyLocale->$sPropertyName; + //$aResult[$sPropertyName]=$aLangAttributes[$sPropertyName]; + } + return $aResult; + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid Session key'); + } + + /** + * RPC Routine to set survey language properties. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param integer $iSurveyID - ID of the survey + * @param array|struct $aSurveyLocaleData - An array with the particular fieldnames as keys and their values to set on that particular survey + * @param string $sLanguage - Optional - Language to update - if not give the base language of the particular survey is used + * @return array Status=>OK, when save successful otherwise error text. + */ + public function set_language_properties($sSessionKey, $iSurveyID, $aSurveyLocaleData, $sLanguage=NULL) + { + Yii::app()->loadHelper("surveytranslator"); + if ($this->_checkSessionKey($sSessionKey)) + { + $oSurvey=Survey::model()->findByPk($iSurveyID); + if (is_null($oSurvey)) + { + return array('status' => 'Error: Invalid survey ID'); + } + + if (is_null($sLanguage)) + { + $sLanguage=$oSurvey->language; + } + + if (!array_key_exists($sLanguage,getLanguageDataRestricted())) + return array('status' => 'Error: Invalid language'); + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveylocale', 'update')) + { + // Remove fields that may not be modified + unset($aSurveyLocaleData['surveyls_language']); + unset($aSurveyLocaleData['surveyls_survey_id']); + + // Remove invalid fields + $aDestinationFields=array_flip(SurveyLanguageSetting::model()->tableSchema->columnNames); + + $aSurveyLocaleData=array_intersect_key($aSurveyLocaleData,$aDestinationFields); + $oSurveyLocale = SurveyLanguageSetting::model()->findByPk(array('surveyls_survey_id' => $iSurveyID, 'surveyls_language' => $sLanguage)); + + $aLangAttributes = $oSurveyLocale->getAttributes(); + $aResult = array(); + + if (empty($aSurveyLocaleData)) + return array('status' => 'No valid Data'); + + foreach($aSurveyLocaleData as $sFieldName=>$sValue) + { + $oSurveyLocale->$sFieldName=$sValue; + try + { + // save the change to database - Every single change alone - to allow for validation to work + $bSaveResult=$oSurveyLocale->save(); + $aResult[$sFieldName]=$bSaveResult; + //unset failed values + if (!$bSaveResult) + $oSurveyLocale->$sFieldName=$aLangAttributes[$sFieldName]; + } + catch(Exception $e) + { + $oSurveyLocale->$sFieldName=$aLangAttributes[$sFieldName]; + } + } + $aResult['status'] = 'OK'; + return $aResult; + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid Session key'); + } + + /* Group specific functions */ + + /** + * RPC Routine to add an empty group with minimum details. + * Used as a placeholder for importing questions. + * Returns the groupid of the created group. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Dd of the Survey to add the group + * @param string $sGroupTitle Name of the group + * @param string $sGroupDescription Optional description of the group + * @return array|int The id of the new group - Or status + */ + public function add_group($sSessionKey, $iSurveyID, $sGroupTitle, $sGroupDescription='') + { + if ($this->_checkSessionKey($sSessionKey)) + { + if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'update')) + { + $oSurvey = Survey::model()->findByPk($iSurveyID); + if (!isset($oSurvey)) + return array('status' => 'Error: Invalid survey ID'); + + if($oSurvey['active']=='Y') + return array('status' => 'Error:Survey is active and not editable'); + + $oGroup = new QuestionGroup; + $oGroup->sid = $iSurveyID; + $oGroup->group_name = $sGroupTitle; + $oGroup->description = $sGroupDescription; + $oGroup->group_order = getMaxGroupOrder($iSurveyID); + $oGroup->language = Survey::model()->findByPk($iSurveyID)->language; + if($oGroup->save()) + return (int)$oGroup->gid; + else + return array('status' => 'Creation Failed'); + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid Session Key'); + } + + /** + * RPC Routine to delete a group of a survey . + * Returns the id of the deleted group. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Id of the survey that the group belongs + * @param int $iGroupID Id of the group to delete + * @return array|int The id of the deleted group or status + */ + public function delete_group($sSessionKey, $iSurveyID, $iGroupID) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $iSurveyID = sanitize_int($iSurveyID); + $iGroupID = sanitize_int($iGroupID); + $oSurvey = Survey::model()->findByPk($iSurveyID); + if (!isset($oSurvey)) + return array('status' => 'Error: Invalid survey ID'); + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveycontent', 'delete')) + { + $oGroup = QuestionGroup::model()->findByAttributes(array('gid' => $iGroupID)); + if (!isset($oGroup)) + return array('status' => 'Error: Invalid group ID'); + + if($oSurvey['active']=='Y') + return array('status' => 'Error:Survey is active and not editable'); + + $depented_on = getGroupDepsForConditions($oGroup->sid,"all",$iGroupID,"by-targgid"); + if(isset($depented_on)) + return array('status' => 'Group with depencdencies - deletion not allowed'); + + $iGroupsDeleted = QuestionGroup::deleteWithDependency($iGroupID, $iSurveyID); + + if ($iGroupsDeleted === 1) + { + fixSortOrderGroups($iSurveyID); + return (int)$iGroupID; + } + else + return array('status' => 'Group deletion failed'); + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid Session Key'); + } + + /** + * RPC Routine to import a group - imports lsg,csv + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID The id of the survey that the group will belong + * @param string $sImportData String containing the BASE 64 encoded data of a lsg,csv + * @param string $sImportDataType lsg,csv + * @param string $sNewGroupName Optional new name for the group + * @param string $sNewGroupDescription Optional new description for the group + * @return array|integer iGroupID - ID of the new group or status + */ + public function import_group($sSessionKey, $iSurveyID, $sImportData, $sImportDataType, $sNewGroupName=NULL, $sNewGroupDescription=NULL) + { + + if ($this->_checkSessionKey($sSessionKey)) + { + $oSurvey = Survey::model()->findByPk($iSurveyID); + if (!isset($oSurvey)) + return array('status' => 'Error: Invalid survey ID'); + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'update')) + { + if($oSurvey->getAttribute('active') =='Y') + return array('status' => 'Error:Survey is active and not editable'); + + if (!in_array($sImportDataType,array('csv','lsg'))) return array('status' => 'Invalid extension'); + libxml_use_internal_errors(true); + Yii::app()->loadHelper('admin/import'); + // First save the data to a temporary file + $sFullFilePath = Yii::app()->getConfig('tempdir') . DIRECTORY_SEPARATOR . randomChars(40).'.'.$sImportDataType; + file_put_contents($sFullFilePath,base64_decode(chunk_split($sImportData))); + + if (strtolower($sImportDataType)=='csv') + { + $aImportResults = CSVImportGroup($sFullFilePath, $iSurveyID); + } + elseif ( strtolower($sImportDataType)=='lsg') + { + $xml = simplexml_load_file($sFullFilePath); + if(!$xml) + { + unlink($sFullFilePath); + return array('status' => 'Error: Invalid LimeSurvey group structure XML '); + } + $aImportResults = XMLImportGroup($sFullFilePath, $iSurveyID); + } + else + return array('status' => 'Invalid extension'); //just for symmetry! + + unlink($sFullFilePath); + + if (isset($aImportResults['fatalerror'])) return array('status' => 'Error: '.$aImportResults['fatalerror']); + else + { + $iNewgid = $aImportResults['newgid']; + + $oGroup = QuestionGroup::model()->findByAttributes(array('gid' => $iNewgid)); + $slang=$oGroup['language']; + if($sNewGroupName!='') + $oGroup->setAttribute('group_name',$sNewGroupName); + if($sNewGroupDescription!='') + $oGroup->setAttribute('description',$sNewGroupDescription); + try + { + $oGroup->save(); + } + catch(Exception $e) + { + // no need to throw exception + } + return (int)$aImportResults['newgid']; + } + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid session key'); + } + + /** + * RPC Routine to find response IDs given a survey ID and a token. + * @param string $sSessionKey + * @param int $iSurveyID + * @param string $sToken + */ + public function get_response_ids($sSessionKey, $iSurveyID, $sToken) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $responses = SurveyDynamic::model($iSurveyID)->findAllByAttributes(array('token' => $sToken)); + $result = array(); + foreach ($responses as $response) + { + $result[] = (int) $response->id; + } + return $result; + } + else + { + return array('status' => 'Invalid Session Key'); + } + + } + + /** + * RPC Routine to return properties of a group of a survey . + * Returns array of properties + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iGroupID Id of the group to get properties + * @param array $aGroupSettings The properties to get + * @return array The requested values + */ + public function get_group_properties($sSessionKey, $iGroupID, $aGroupSettings) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $oGroup = QuestionGroup::model()->findByAttributes(array('gid' => $iGroupID)); + if (!isset($oGroup)) + return array('status' => 'Error: Invalid group ID'); + + if (Permission::model()->hasSurveyPermission($oGroup->sid, 'survey', 'read')) + { + $aBasicDestinationFields=QuestionGroup::model()->tableSchema->columnNames; + $aGroupSettings=array_intersect($aGroupSettings,$aBasicDestinationFields); + + if (empty($aGroupSettings)) + return array('status' => 'No valid Data'); + + foreach($aGroupSettings as $sGroupSetting) + { + $aResult[$sGroupSetting] = $oGroup->$sGroupSetting; + } + return $aResult; + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid Session Key'); + } + + + /** + * RPC Routine to set group properties. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param integer $iGroupID - ID of the survey + * @param array|struct $aGroupData - An array with the particular fieldnames as keys and their values to set on that particular survey + * @return array Of succeeded and failed modifications according to internal validation. + */ + public function set_group_properties($sSessionKey, $iGroupID, $aGroupData) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $oGroup=QuestionGroup::model()->findByAttributes(array('gid' => $iGroupID)); + if (is_null($oGroup)) + { + return array('status' => 'Error: Invalid group ID'); + } + if (Permission::model()->hasSurveyPermission($oGroup->sid, 'survey', 'update')) + { + $aResult = array(); + // Remove fields that may not be modified + unset($aGroupData['sid']); + unset($aGroupData['gid']); + // Remove invalid fields + $aDestinationFields=array_flip(QuestionGroup::model()->tableSchema->columnNames); + $aGroupData=array_intersect_key($aGroupData,$aDestinationFields); + $aGroupAttributes = $oGroup->getAttributes(); + if (empty($aGroupData)) + return array('status' => 'No valid Data'); + + foreach($aGroupData as $sFieldName=>$sValue) + { + //all dependencies this group has + $has_dependencies=getGroupDepsForConditions($oGroup->sid,$iGroupID); + //all dependencies on this group + $depented_on = getGroupDepsForConditions($oGroup->sid,"all",$iGroupID,"by-targgid"); + //We do not allow groups with dependencies to change order - that would lead to broken dependencies + + if((isset($has_dependencies) || isset($depented_on)) && $sFieldName == 'group_order') + $aFailed[$sFieldName]='Group with dependencies - Order cannot be changed'; + else + { + $oGroup->setAttribute($sFieldName,$sValue); + } + try + { + // save the change to database - one by one to allow for validation to work + $bSaveResult=$oGroup->save(); + fixSortOrderGroups($oGroup->sid); + $aResult[$sFieldName] = $bSaveResult; + //unset failed values + if (!$bSaveResult) + $oGroup->$sFieldName=$aGroupAttributes[$sFieldName]; + } + catch(Exception $e) + { + //unset values that cause exception + $oGroup->$sFieldName=$aGroupAttributes[$sFieldName]; + } + } + return $aResult; + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid Session key'); + } + + /** + * RPC Routine to return the ids and info of groups belonging to survey . + * Returns array of ids and info. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Id of the Survey containing the groups + * @return array The list of groups + */ + public function list_groups($sSessionKey, $iSurveyID) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $oSurvey = Survey::model()->findByPk($iSurveyID); + if (!isset($oSurvey)) + return array('status' => 'Error: Invalid survey ID'); + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'read')) + { + $oGroupList = QuestionGroup::model()->findAllByAttributes(array("sid"=>$iSurveyID)); + if(count($oGroupList)==0) + return array('status' => 'No groups found'); + + foreach ($oGroupList as $oGroup) + { + $aData[]= array('id'=>$oGroup->primaryKey,'group_name'=>$oGroup->attributes['group_name']); + } + return $aData; + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid Session Key'); + } + + + /* Question specific functions */ + + + /** + * RPC Routine to delete a question of a survey . + * Returns the id of the deleted question. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int iQuestionID Id of the question to delete + * @return array|int Id of the deleted Question or status + */ + public function delete_question($sSessionKey, $iQuestionID) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $oQuestion = Question::model()->findByAttributes(array('qid' => $iQuestionID)); + if (!isset($oQuestion)) + return array('status' => 'Error: Invalid question ID'); + + $iSurveyID = $oQuestion['sid']; + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveycontent', 'delete')) + { + $oSurvey = Survey::model()->findByPk($iSurveyID); + + if($oSurvey['active']=='Y') + return array('status' => 'Survey is active and not editable'); + $iGroupID=$oQuestion['gid']; + + $oCondition = Condition::model()->findAllByAttributes(array('cqid' => $iQuestionID)); + if(count($oCondition)>0) + return array('status' => 'Cannot delete Question. Others rely on this question'); + + LimeExpressionManager::RevertUpgradeConditionsToRelevance(NULL,$iQuestionID); + + try + { + Condition::model()->deleteAllByAttributes(array('qid' => $iQuestionID)); + QuestionAttribute::model()->deleteAllByAttributes(array('qid' => $iQuestionID)); + Answer::model()->deleteAllByAttributes(array('qid' => $iQuestionID)); + + $sCriteria = new CDbCriteria; + $sCriteria->addCondition('qid = :qid or parent_qid = :qid'); + $sCriteria->params[':qid'] = $iQuestionID; + Question::model()->deleteAll($sCriteria); + + DefaultValue::model()->deleteAllByAttributes(array('qid' => $iQuestionID)); + QuotaMember::model()->deleteAllByAttributes(array('qid' => $iQuestionID)); + Question::updateSortOrder($iGroupID, $iSurveyID); + + return (int)$iQuestionID; + } + catch(Exception $e) + { + return array('status' => 'Error'); + } + + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid session key'); + } + + + /** + * RPC Routine to import a question - imports lsq,csv. + * + * @access public + * @param string $sSessionKey + * @param int $iSurveyID The id of the survey that the question will belong + * @param int $iGroupID The id of the group that the question will belong + * @param string $sImportData String containing the BASE 64 encoded data of a lsg,csv + * @param string $sImportDataType lsq,csv + * @param string $sMandatory Optional Mandatory question option (default to No) + * @param string $sNewQuestionTitle Optional new title for the question + * @param string $sNewqQuestion An optional new question + * @param string $sNewQuestionHelp An optional new question help text + * @return array|integer iQuestionID - ID of the new question - Or status + */ + public function import_question($sSessionKey, $iSurveyID,$iGroupID, $sImportData, $sImportDataType, $sMandatory='N', $sNewQuestionTitle=NULL, $sNewqQuestion=NULL, $sNewQuestionHelp=NULL) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $oSurvey = Survey::model()->findByPk($iSurveyID); + if (!isset($oSurvey)) + return array('status' => 'Error: Invalid survey ID'); + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'update')) + { + if($oSurvey->getAttribute('active') =='Y') + return array('status' => 'Error:Survey is Active and not editable'); + + $oGroup = QuestionGroup::model()->findByAttributes(array('gid' => $iGroupID)); + if (!isset($oGroup)) + return array('status' => 'Error: Invalid group ID'); + + $sGroupSurveyID = $oGroup['sid']; + if($sGroupSurveyID != $iSurveyID) + return array('status' => 'Error: Missmatch in surveyid and groupid'); + + if (!in_array($sImportDataType,array('csv','lsq'))) return array('status' => 'Invalid extension'); + libxml_use_internal_errors(true); + Yii::app()->loadHelper('admin/import'); + // First save the data to a temporary file + $sFullFilePath = Yii::app()->getConfig('tempdir') . DIRECTORY_SEPARATOR . randomChars(40).'.'.$sImportDataType; + file_put_contents($sFullFilePath,base64_decode(chunk_split($sImportData))); + + if (strtolower($sImportDataType)=='csv') + { + $aImportResults = CSVImportQuestion($sFullFilePath, $iSurveyID, $iGroupID); + } + elseif ( strtolower($sImportDataType)=='lsq') + { + + $xml = simplexml_load_file($sFullFilePath); + if(!$xml) + { + unlink($sFullFilePath); + return array('status' => 'Error: Invalid LimeSurvey question structure XML '); + } + $aImportResults = XMLImportQuestion($sFullFilePath, $iSurveyID, $iGroupID); + } + else + return array('status' => 'Really Invalid extension'); //just for symmetry! + + unlink($sFullFilePath); + + if (isset($aImportResults['fatalerror'])) return array('status' => 'Error: '.$aImportResults['fatalerror']); + else + { + fixLanguageConsistency($iSurveyID); + $iNewqid = $aImportResults['newqid']; + + $oQuestion = Question::model()->findByAttributes(array('sid' => $iSurveyID, 'gid' => $iGroupID, 'qid' => $iNewqid)); + if($sNewQuestionTitle!=NULL) + $oQuestion->setAttribute('title',$sNewQuestionTitle); + if($sNewqQuestion!='') + $oQuestion->setAttribute('question',$sNewqQuestion); + if($sNewQuestionHelp!='') + $oQuestion->setAttribute('help',$sNewQuestionHelp); + if(in_array($sMandatory, array('Y','N'))) + $oQuestion->setAttribute('mandatory',$sMandatory); + else + $oQuestion->setAttribute('mandatory','N'); + + try + { + $oQuestion->save(); + } + catch(Exception $e) + { + // no need to throw exception + } + return (int)$aImportResults['newqid']; + } + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid session key'); + } + + + /** + * RPC Routine to return properties of a question of a survey. + * Returns string + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iQuestionID Id of the question to get properties + * @param array $aQuestionSettings The properties to get + * @param string $sLanguage Optional parameter language for multilingual questions + * @return array The requested values + */ + public function get_question_properties($sSessionKey, $iQuestionID, $aQuestionSettings, $sLanguage=NULL) + { + if ($this->_checkSessionKey($sSessionKey)) + { + Yii::app()->loadHelper("surveytranslator"); + $oQuestion = Question::model()->findByAttributes(array('qid' => $iQuestionID)); + if (!isset($oQuestion)) + return array('status' => 'Error: Invalid questionid'); + + $iSurveyID = $oQuestion->sid; + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'read')) + { + if (is_null($sLanguage)) + $sLanguage=Survey::model()->findByPk($iSurveyID)->language; + + if (!array_key_exists($sLanguage,getLanguageDataRestricted())) + return array('status' => 'Error: Invalid language'); + + $oQuestion = Question::model()->findByAttributes(array('qid' => $iQuestionID, 'language'=>$sLanguage)); + if (!isset($oQuestion)) + return array('status' => 'Error: Invalid questionid'); + + $aBasicDestinationFields=Question::model()->tableSchema->columnNames; + array_push($aBasicDestinationFields,'available_answers') ; + array_push($aBasicDestinationFields,'subquestions') ; + array_push($aBasicDestinationFields,'attributes') ; + array_push($aBasicDestinationFields,'attributes_lang') ; + array_push($aBasicDestinationFields,'answeroptions') ; + $aQuestionSettings=array_intersect($aQuestionSettings,$aBasicDestinationFields); + + if (empty($aQuestionSettings)) + return array('status' => 'No valid Data'); + + $aResult=array(); + foreach ($aQuestionSettings as $sPropertyName ) + { + if ($sPropertyName == 'available_answers' || $sPropertyName == 'subquestions') + { + $oSubQuestions = Question::model()->findAllByAttributes(array('parent_qid' => $iQuestionID,'language'=>$sLanguage ),array('order'=>'title') ); + if (count($oSubQuestions)>0) + { + $aData = array(); + foreach($oSubQuestions as $oSubQuestion) + { + if($sPropertyName == 'available_answers') + $aData[$oSubQuestion['title']]= $oSubQuestion['question']; + else + { + $aData[$oSubQuestion['qid']]['title']= $oSubQuestion['title']; + $aData[$oSubQuestion['qid']]['question']= $oSubQuestion['question']; + $aData[$oSubQuestion['qid']]['scale_id']= $oSubQuestion['scale_id']; + } + + } + + $aResult[$sPropertyName]=$aData; + } + else + $aResult[$sPropertyName]='No available answers'; + } + else if ($sPropertyName == 'attributes') + { + $oAttributes = QuestionAttribute::model()->findAllByAttributes(array('qid' => $iQuestionID, 'language'=> null ),array('order'=>'attribute') ); + if (count($oAttributes)>0) + { + $aData = array(); + foreach($oAttributes as $oAttribute) + $aData[$oAttribute['attribute']]= $oAttribute['value']; + + $aResult['attributes']=$aData; + } + else + $aResult['attributes']='No available attributes'; + } + else if ($sPropertyName == 'attributes_lang') + { + $oAttributes = QuestionAttribute::model()->findAllByAttributes(array('qid' => $iQuestionID, 'language'=> $sLanguage ),array('order'=>'attribute') ); + if (count($oAttributes)>0) + { + $aData = array(); + foreach($oAttributes as $oAttribute) + $aData[$oAttribute['attribute']]= $oAttribute['value']; + + $aResult['attributes_lang']=$aData; + } + else + $aResult['attributes_lang']='No available attributes'; + } + else if ($sPropertyName == 'answeroptions') + { + $oAttributes = Answer::model()->findAllByAttributes(array('qid' => $iQuestionID, 'language'=> $sLanguage ),array('order'=>'sortorder') ); + if (count($oAttributes)>0) + { + $aData = array(); + foreach($oAttributes as $oAttribute) { + $aData[$oAttribute['code']]['answer']=$oAttribute['answer']; + $aData[$oAttribute['code']]['assessment_value']=$oAttribute['assessment_value']; + $aData[$oAttribute['code']]['scale_id']=$oAttribute['scale_id']; + } + $aResult['answeroptions']=$aData; + } + else + $aResult['answeroptions']='No available answer options'; + } + else + { + $aResult[$sPropertyName]=$oQuestion->$sPropertyName; + } + } + return $aResult; + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid session key'); + } + + /** + * RPC Routine to set question properties. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param integer $iQuestionID - ID of the question + * @param array|struct $aQuestionData - An array with the particular fieldnames as keys and their values to set on that particular question + * @param string $sLanguage Optional parameter language for multilingual questions + * @return array Of succeeded and failed modifications according to internal validation. + */ + public function set_question_properties($sSessionKey, $iQuestionID, $aQuestionData,$sLanguage=NULL) + { + if ($this->_checkSessionKey($sSessionKey)) + { + Yii::app()->loadHelper("surveytranslator"); + $oQuestion=Question::model()->findByAttributes(array('qid' => $iQuestionID)); + if (is_null($oQuestion)) + return array('status' => 'Error: Invalid group ID'); + + $iSurveyID = $oQuestion->sid; + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'update')) + { + if (is_null($sLanguage)) + $sLanguage=Survey::model()->findByPk($iSurveyID)->language; + + if (!array_key_exists($sLanguage,getLanguageDataRestricted())) + return array('status' => 'Error: Invalid language'); + + $oQuestion = Question::model()->findByAttributes(array('qid' => $iQuestionID, 'language'=>$sLanguage)); + if (!isset($oQuestion)) + return array('status' => 'Error: Invalid questionid'); + + // Remove fields that may not be modified + unset($aQuestionData['qid']); + unset($aQuestionData['gid']); + unset($aQuestionData['sid']); + unset($aQuestionData['parent_qid']); + unset($aQuestionData['language']); + unset($aQuestionData['type']); + // Remove invalid fields + $aDestinationFields=array_flip(Question::model()->tableSchema->columnNames); + $aQuestionData=array_intersect_key($aQuestionData,$aDestinationFields); + $aQuestionAttributes = $oQuestion->getAttributes(); + + if (empty($aQuestionData)) + return array('status' => 'No valid Data'); + + foreach($aQuestionData as $sFieldName=>$sValue) + { + //all the dependencies that this question has to other questions + $dependencies=getQuestDepsForConditions($oQuestion->sid,$oQuestion->gid,$iQuestionID); + //all dependencies by other questions to this question + $is_criteria_question=getQuestDepsForConditions($oQuestion->sid,$oQuestion->gid,"all",$iQuestionID,"by-targqid"); + //We do not allow questions with dependencies in the same group to change order - that would lead to broken dependencies + + if((isset($dependencies) || isset($is_criteria_question)) && $sFieldName == 'question_order') + $aFailed[$sFieldName]='Questions with dependencies - Order cannot be changed'; + else + { + $oQuestion->setAttribute($sFieldName,$sValue); + } + + try + { + $bSaveResult=$oQuestion->save(); // save the change to database + Question::model()->updateQuestionOrder($oQuestion->gid, $oQuestion->sid); + $aResult[$sFieldName]=$bSaveResult; + //unset fields that failed + if (!$bSaveResult) + $oQuestion->$sFieldName=$aQuestionAttributes[$sFieldName]; + } + catch(Exception $e) + { + //unset fields that caused exception + $oQuestion->$sFieldName=$aQuestionAttributes[$sFieldName]; + } + } + return $aResult; + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid Session key'); + } + + + /** + * RPC Routine to return the ids and info of questions of a survey/group. + * Returns array of ids and info. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Id of the survey to list questions + * @param int $iGroupID Optional id of the group to list questions + * @param string $sLanguage Optional parameter language for multilingual questions + * @return array The list of questions + */ + public function list_questions($sSessionKey, $iSurveyID, $iGroupID=NULL, $sLanguage=NULL) + { + if ($this->_checkSessionKey($sSessionKey)) + { + Yii::app()->loadHelper("surveytranslator"); + $oSurvey = Survey::model()->findByPk($iSurveyID); + if (!isset($oSurvey)) + return array('status' => 'Error: Invalid survey ID'); + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'read')) + { + if (is_null($sLanguage)) + $sLanguage=$oSurvey->language; + + if (!array_key_exists($sLanguage,getLanguageDataRestricted())) + return array('status' => 'Error: Invalid language'); + + if($iGroupID!=NULL) + { + $oGroup = QuestionGroup::model()->findByAttributes(array('gid' => $iGroupID)); + $sGroupSurveyID = $oGroup['sid']; + + if($sGroupSurveyID != $iSurveyID) + return array('status' => 'Error: IMissmatch in surveyid and groupid'); + else + $aQuestionList = Question::model()->findAllByAttributes(array("sid"=>$iSurveyID, "gid"=>$iGroupID,"parent_qid"=>"0","language"=>$sLanguage)); + } + else + $aQuestionList = Question::model()->findAllByAttributes(array("sid"=>$iSurveyID,"parent_qid"=>"0", "language"=>$sLanguage)); + + if(count($aQuestionList)==0) + return array('status' => 'No questions found'); + + foreach ($aQuestionList as $oQuestion) + { + $aData[]= array('id'=>$oQuestion->primaryKey,'title'=>$oQuestion->attributes['title'],'type'=>$oQuestion->attributes['type'], 'question'=>$oQuestion->attributes['question']); + } + return $aData; + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid session key'); + } + + /* Participant-Token specific functions */ + + + + /** + * RPC Routine to add participants to the tokens collection of the survey. + * Returns the inserted data including additional new information like the Token entry ID and the token string. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Id of the Survey + * @param struct $aParticipantData Data of the participants to be added + * @param bool Optional - Defaults to true and determins if the access token automatically created + * @return array The values added + */ + public function add_participants($sSessionKey, $iSurveyID, $aParticipantData, $bCreateToken=true) + { + if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key'); + $oSurvey=Survey::model()->findByPk($iSurveyID); + if (is_null($oSurvey)) + { + return array('status' => 'Error: Invalid survey ID'); + } + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'create')) + { + if (!Yii::app()->db->schema->getTable('{{tokens_' . $iSurveyID . '}}')) + return array('status' => 'No token table'); + + $aDestinationFields = Yii::app()->db->schema->getTable('{{tokens_' . $iSurveyID . '}}')->getColumnNames(); + $aDestinationFields = array_flip($aDestinationFields); + + foreach ($aParticipantData as &$aParticipant) + { + $aParticipant=array_intersect_key($aParticipant,$aDestinationFields); + TokenDynamic::sid($iSurveyID); + $token = new TokenDynamic; + + if ($new_token_id=$token->insertParticipant($aParticipant)) + { + if ($bCreateToken) + $token_string = TokenDynamic::model()->createToken($new_token_id); + else + $token_string = ''; + + $aParticipant = array_merge($aParticipant, array( + 'tid' => $new_token_id, + 'token' => $token_string, + )); + } + else + { + $aParticipant=false; + } + } + return $aParticipantData; + } + else + return array('status' => 'No permission'); + } + + /** + * RPC Routine to delete multiple participants of a Survey. + * Returns the id of the deleted token + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Id of the Survey that the participants belong to + * @param array $aTokenIDs Id of the tokens/participants to delete + * @return array Result of deletion + */ + public function delete_participants($sSessionKey, $iSurveyID, $aTokenIDs) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $iSurveyID = sanitize_int($iSurveyID); + + $oSurvey = Survey::model()->findByPk($iSurveyID); + if (!isset($oSurvey)) + return array('status' => 'Error: Invalid survey ID'); + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'delete')) + { + if(!tableExists("{{tokens_$iSurveyID}}")) + return array('status' => 'Error: No token table'); + + $aResult=array(); + foreach($aTokenIDs as $iTokenID) + { + $tokenidExists = TokenDynamic::model($iSurveyID)->findByPk($iTokenID); + if (!isset($tokenidExists)) + $aResult[$iTokenID]='Invalid token ID'; + else + { + SurveyLink::deleteTokenLink(array($iTokenID), $iSurveyID); + if(TokenDynamic::model($iSurveyID)->deleteRecords(array($iTokenID))) + $aResult[$iTokenID]='Deleted'; + else + $aResult[$iTokenID]='Deletion went wrong'; + } + } + return $aResult; + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid Session Key'); + } + + + /** + * RPC Routine to return settings of a token/participant of a survey . + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Id of the Survey to get token properties + * @param int $iTokenID Id of the participant to check + * @param array $aTokenProperties The properties to get + * @return array The requested values + */ + public function get_participant_properties($sSessionKey, $iSurveyID, $iTokenID, $aTokenProperties) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $surveyidExists = Survey::model()->findByPk($iSurveyID); + if (!isset($surveyidExists)) + return array('status' => 'Error: Invalid survey ID'); + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'read')) + { + if(!tableExists("{{tokens_$iSurveyID}}")) + return array('status' => 'Error: No token table'); + + $oToken = TokenDynamic::model($iSurveyID)->findByPk($iTokenID); + if (!isset($oToken)) + return array('status' => 'Error: Invalid tokenid'); + + $aResult=array(); + $aBasicDestinationFields=TokenDynamic::model()->tableSchema->columnNames; + $aTokenProperties=array_intersect($aTokenProperties,$aBasicDestinationFields); + + if (empty($aTokenProperties)) + return array('status' => 'No valid Data'); + + foreach($aTokenProperties as $sPropertyName ) + { + $aResult[$sPropertyName]=$oToken->$sPropertyName; + } + return $aResult; + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid Session Key'); + } + + /** + * RPC Routine to set properties of a survey participant/token. + * Returns array + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Id of the survey that participants belong + * @param int $iTokenID Id of the participant to alter + * @param array|struct $aTokenData Data to change + * @return array Result of the change action + */ + public function set_participant_properties($sSessionKey, $iSurveyID, $iTokenID, $aTokenData) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $oSurvey = Survey::model()->findByPk($iSurveyID); + if (!isset($oSurvey)) + return array('status' => 'Error: Invalid survey ID'); + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'update')) + { + if(!tableExists("{{tokens_$iSurveyID}}")) + return array('status' => 'Error: No token table'); + + $oToken = TokenDynamic::model($iSurveyID)->findByPk($iTokenID); + if (!isset($oToken)) + return array('status' => 'Error: Invalid tokenid'); + + $aResult = array(); + // Remove fields that may not be modified + unset($aTokenData['tid']); + + $aBasicDestinationFields=array_flip(TokenDynamic::model()->tableSchema->columnNames); + $aTokenData=array_intersect_key($aTokenData,$aBasicDestinationFields); + $aTokenAttributes = $oToken->getAttributes(); + + if (empty($aTokenData)) + return array('status' => 'No valid Data'); + + foreach($aTokenData as $sFieldName=>$sValue) + { + $oToken->$sFieldName=$sValue; + try + { + $bSaveResult=$oToken->save(); + $aResult[$sFieldName]=$bSaveResult; + //unset fields that failed + if (!$bSaveResult) + $oToken->$sFieldName=$aTokenAttributes[$sFieldName]; + } + catch(Exception $e) + { + $oToken->$sFieldName=$aTokenAttributes[$sFieldName]; + } + } + return $aResult; + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid Session Key'); + } + + + + /** + * RPC Routine to return the ids and info of token/participants of a survey. + * if $bUnused is true, user will get the list of not completed tokens (token_return functionality). + * Parameters iStart and ilimit are used to limit the number of results of this call. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Id of the survey to list participants + * @param int $iStart Start id of the token list + * @param int $iLimit Number of participants to return + * @param bool $bUnused If you want unused tokensm, set true + * @return array The list of tokens + */ + public function list_participants($sSessionKey, $iSurveyID, $iStart=0, $iLimit=10, $bUnused=false) + { + if ($this->_checkSessionKey($sSessionKey)) + { + $oSurvey = Survey::model()->findByPk($iSurveyID); + if (!isset($oSurvey)) + return array('status' => 'Error: Invalid survey ID'); + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'read')) + { + if(!tableExists("{{tokens_$iSurveyID}}")) + return array('status' => 'Error: No token table'); + + if($bUnused) + $oTokens = TokenDynamic::model($iSurveyID)->findAll(array('condition'=>"completed = 'N'", 'limit' => $iLimit, 'offset' => $iStart)); + else + $oTokens = TokenDynamic::model($iSurveyID)->findAll(array('limit' => $iLimit, 'offset' => $iStart)); + + if(count($oTokens)==0) + return array('status' => 'No Tokens found'); + + foreach ($oTokens as $token) + { + $aData[] = array( + 'tid'=>$token->primarykey, + 'token'=>$token->attributes['token'], + 'participant_info'=>array( + 'firstname'=>$token->attributes['firstname'], + 'lastname'=>$token->attributes['lastname'], + 'email'=>$token->attributes['email'], + )); + } + return $aData; + } + else + return array('status' => 'No permission'); + } + else + return array('status' => 'Invalid Session Key'); + } + + /** + * RPC routine to to initialise the survey's collection of tokens where new participant tokens may be later added. + * + * @access public + * @param string $sSessionKey Auth credentials + * @param integer $iSurveyID ID of the survey where a token table will be created for + * @param array $aAttributeFields An array of integer describing any additional attribute fields + * @return array Status=>OK when successfull, otherwise the error description + */ + public function activate_tokens($sSessionKey, $iSurveyID, $aAttributeFields=array()) + { + if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key'); + if (Permission::model()->hasGlobalPermission('surveys','create')) + { + $oSurvey=Survey::model()->findByPk($iSurveyID); + if (is_null($oSurvey)) + { + return array('status' => 'Error: Invalid survey ID'); + } + if (is_array($aAttributeFields) && count($aAttributeFields)>0) + { + foreach ($aAttributeFields as &$sField) + { + $sField= intval($sField); + $sField='attribute_'.$sField; + } + $aAttributeFields=array_unique($aAttributeFields); + } + Yii::app()->loadHelper('admin/token'); + if (createTokenTable($iSurveyID, $aAttributeFields)) + { + return array('status' => 'OK'); + } + else + { + return array('status' => 'Token table could not be created'); + } + } + else + return array('status' => 'No permission'); + } + + /** + * RPC Routine to invite participants in a survey + * Returns array of results of sending + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID ID of the survey that participants belong + * @return array Result of the action + */ + public function invite_participants($sSessionKey, $iSurveyID ) + { + Yii::app()->loadHelper('admin/token'); + if (!$this->_checkSessionKey($sSessionKey)) + return array('status' => 'Invalid session key'); + + $oSurvey = Survey::model()->findByPk($iSurveyID); + if (!isset($oSurvey)) + return array('status' => 'Error: Invalid survey ID'); + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'update')) + { + + if(!tableExists("{{tokens_$iSurveyID}}")) + return array('status' => 'Error: No token table'); + + $iMaxEmails = (int)Yii::app()->getConfig("maxemails"); + $SQLemailstatuscondition = "emailstatus = 'OK'"; + + $oTokens = TokenDynamic::model($iSurveyID); + $aResultTokens = $oTokens->findUninvited(false, $iMaxEmails, true, $SQLemailstatuscondition); + $aAllTokens = $oTokens->findUninvitedIDs(false, 0, true, $SQLemailstatuscondition); + $iAllTokensCount=count($aAllTokens); + unset($aAllTokens); + if (empty($aResultTokens)) + return array('status' => 'Error: No candidate tokens'); + + foreach($aResultTokens as $key=>$oToken) + { + //pattern taken from php_filter_validate_email PHP_5_4/ext/filter/logical_filters.c + $pattern = '/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD'; + + //if(!filter_var($emailaddress, FILTER_VALIDATE_EMAIL)) + if (preg_match($pattern, $oToken['email']) !== 1) + unset($aResultTokens[$key]); + } + + if (empty($aResultTokens)) + return array('status' => 'Error: No candidate tokens'); + $aResult = emailTokens($iSurveyID,$aResultTokens,'invite'); + $iLeft = $iAllTokensCount - count($aResultTokens); + $aResult['status'] =$iLeft. " left to send"; + + return $aResult; + } + else + return array('status' => 'No permission'); + } + + + /** + * RPC Routine to send reminder for participants in a survey + * Returns array of results of sending + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID ID of the survey that participants belong + * @param int $iMinDaysBetween Optional parameter days from last reminder + * @param int $iMaxReminders Optional parameter Maximum reminders count + * @return array Result of the action + */ + public function remind_participants($sSessionKey, $iSurveyID, $iMinDaysBetween=null, $iMaxReminders=null ) + { + Yii::app()->loadHelper('admin/token'); + if (!$this->_checkSessionKey($sSessionKey)) + return array('status' => 'Invalid session key'); + + $oSurvey = Survey::model()->findByPk($iSurveyID); + if (!isset($oSurvey)) + return array('status' => 'Error: Invalid survey ID'); + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'tokens', 'update')) + { + $timeadjust = Yii::app()->getConfig("timeadjust"); + + if(!tableExists("{{tokens_$iSurveyID}}")) + return array('status' => 'Error: No token table'); + + if (getEmailFormat($iSurveyID) == 'html') + $bHtml = true; + else + $bHtml = false; + + $SQLemailstatuscondition = "emailstatus = 'OK'"; + $SQLremindercountcondition = ''; + $SQLreminderdelaycondition = ''; + $iMaxEmails = (int)Yii::app()->getConfig("maxemails"); + + if(!is_null($iMinDaysBetween)) + { + $compareddate = dateShift(date("Y-m-d H:i:s", time() - 86400 * $iMinDaysBetween), "Y-m-d H:i", $timeadjust); + $SQLreminderdelaycondition = " ((remindersent = 'N' AND sent < '" . $compareddate . "') OR (remindersent < '" . $compareddate . "'))"; + } + + if(!is_null($iMaxReminders)) + $SQLremindercountcondition = "remindercount < " . $iMaxReminders; + + $oTokens = TokenDynamic::model($iSurveyID); + $aAllTokens = $oTokens->findUninvitedIDs(false, 0, false, $SQLemailstatuscondition, $SQLremindercountcondition, $SQLreminderdelaycondition); + $iAllTokensCount=count($aAllTokens); + unset($aAllTokens); // save some memory before the next query + + $aResultTokens = $oTokens->findUninvited(false, $iMaxEmails, false, $SQLemailstatuscondition, $SQLremindercountcondition, $SQLreminderdelaycondition); + + if (empty($aResultTokens)) + return array('status' => 'Error: No candidate tokens'); + + $aResult = emailTokens($iSurveyID, $aResultTokens, 'remind'); + + $iLeft = $iAllTokensCount - count($aResultTokens); + $aResult['status'] =$iLeft. " left to send"; + return $aResult; + } + else + return array('status' => 'No permission'); + + } + + + /* Response specific functions */ + + + /** + * RPC Routine to add a response to the survey responses collection. + * Returns the id of the inserted survey response + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Id of the Survey to insert responses + * @param struct $aResponseData The actual response + * @return int The response ID + */ + public function add_response($sSessionKey, $iSurveyID, $aResponseData) + { + if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key'); + $oSurvey=Survey::model()->findByPk($iSurveyID); + if (is_null($oSurvey)) + { + return array('status' => 'Error: Invalid survey ID'); + } + + if (Permission::model()->hasSurveyPermission($iSurveyID, 'responses', 'create')) + { + if (!Yii::app()->db->schema->getTable('{{survey_' . $iSurveyID . '}}')) + return array('status' => 'No survey response table'); + + //set required values if not set + + // @todo: Some of this is part of the validation and should be done in the model instead + if (!isset($aResponseData['submitdate'])) + $aResponseData['submitdate'] = date("Y-m-d H:i:s"); + if (!isset($aResponseData['startlanguage'])) + $aResponseData['startlanguage'] = getBaseLanguageFromSurveyID($iSurveyID); + + if ($oSurvey->datestamp=='Y') + { + if (!isset($aResponseData['datestamp'])) + $aResponseData['datestamp'] = date("Y-m-d H:i:s"); + if (!isset($aResponseData['startdate'])) + $aResponseData['startdate'] = date("Y-m-d H:i:s"); + } + + SurveyDynamic::sid($iSurveyID); + $survey_dynamic = new SurveyDynamic; + $aBasicDestinationFields=$survey_dynamic->tableSchema->columnNames; + $aResponseData=array_intersect_key($aResponseData, array_flip($aBasicDestinationFields)); + $result_id = $survey_dynamic->insertRecords($aResponseData); + + if ($result_id) + return $result_id; + else + return array('status' => 'Unable to add response'); + } + else + return array('status' => 'No permission'); + + } + + /** + * RPC Routine to export responses. + * Returns the requested file as base64 encoded string + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Id of the Survey + * @param string $sDocumentType pdf,csv,xls,doc + * @param string $sLanguageCode The language to be used + * @param string $sCompletionStatus Optional 'complete','incomplete' or 'all' - defaults to 'all' + * @param string $sHeadingType 'code','full' or 'abbreviated' Optional defaults to 'code' + * @param string $sResponseType 'short' or 'long' Optional defaults to 'short' + * @param integer $iFromResponseID Optional + * @param integer $iToResponseID Optional + * @param array $aFields Optional Selected fields + * @return array|string On success: Requested file as base 64-encoded string. On failure array with error information + * */ + public function export_responses($sSessionKey, $iSurveyID, $sDocumentType, $sLanguageCode=null, $sCompletionStatus='all', $sHeadingType='full', $sResponseType='short', $iFromResponseID=null, $iToResponseID=null, $aFields=null) + { + if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key'); + Yii::app()->loadHelper('admin/exportresults'); + if (!tableExists('{{survey_' . $iSurveyID . '}}')) return array('status' => 'No Data'); + if(!$maxId = SurveyDynamic::model($iSurveyID)->getMaxId()) return array('status' => 'No Data'); + + if (!Permission::model()->hasSurveyPermission($iSurveyID, 'responses', 'export')) return array('status' => 'No permission'); + if (is_null($sLanguageCode)) $sLanguageCode=getBaseLanguageFromSurveyID($iSurveyID); + if (is_null($aFields)) $aFields=array_keys(createFieldMap($iSurveyID,'full',true,false,$sLanguageCode)); + if($sDocumentType=='xls'){ + // Cut down to the first 255 fields + $aFields=array_slice($aFields,0,255); + } + $oFomattingOptions=new FormattingOptions(); + + if($iFromResponseID !=null) + $oFomattingOptions->responseMinRecord=$iFromResponseID; + else + $oFomattingOptions->responseMinRecord=1; + + if($iToResponseID !=null) + $oFomattingOptions->responseMaxRecord=$iToResponseID; + else + $oFomattingOptions->responseMaxRecord = $maxId; + + $oFomattingOptions->selectedColumns=$aFields; + $oFomattingOptions->responseCompletionState=$sCompletionStatus; + $oFomattingOptions->headingFormat=$sHeadingType; + $oFomattingOptions->answerFormat=$sResponseType; + $oFomattingOptions->output='file'; + + $oExport=new ExportSurveyResultsService(); + $sTempFile=$oExport->exportSurvey($iSurveyID,$sLanguageCode, $sDocumentType,$oFomattingOptions, ''); + return new BigFile($sTempFile, true, 'base64'); + } + + /** + * RPC Routine to export token response in a survey. + * Returns the requested file as base64 encoded string + * + * @access public + * @param string $sSessionKey Auth credentials + * @param int $iSurveyID Id of the Survey + * @param string $sDocumentType pdf,csv,xls,doc + * @param string $sToken The token for which responses needed + * @param string $sLanguageCode The language to be used + * @param string $sCompletionStatus Optional 'complete','incomplete' or 'all' - defaults to 'all' + * @param string $sHeadingType 'code','full' or 'abbreviated' Optional defaults to 'code' + * @param string $sResponseType 'short' or 'long' Optional defaults to 'short' + * @param array $aFields Optional Selected fields + * @return array|string On success: Requested file as base 64-encoded string. On failure array with error information + * + */ + public function export_responses_by_token($sSessionKey, $iSurveyID, $sDocumentType, $sToken, $sLanguageCode=null, $sCompletionStatus='all', $sHeadingType='full', $sResponseType='short', $aFields=null) + { + if (!$this->_checkSessionKey($sSessionKey)) return array('status' => 'Invalid session key'); + if (!Permission::model()->hasSurveyPermission($iSurveyID, 'responses', 'export')) return array('status' => 'No permission'); + if (!tableExists('{{survey_' . $iSurveyID . '}}')) return array('status' => 'No Data'); + if(!$oResult = SurveyDynamic::model($iSurveyID)->findByAttributes(array('token' => $sToken))) return array('status' => 'No Response found for Token'); + if ($oResult['id']) + { + return $this->export_responses($sSessionKey, $iSurveyID, $sDocumentType, $sLanguageCode, $sCompletionStatus, $sHeadingType, $sResponseType, $oResult['id'], $oResult['id'], $aFields); + } + } + + + /** + * Tries to login with username and password + * + * @access protected + * @param string $sUsername The username + * @param mixed $sPassword The Password + * @return bool + */ + protected function _doLogin($sUsername, $sPassword) + { + $identity = new UserIdentity(sanitize_user($sUsername), $sPassword); + + if (!$identity->authenticate()) + { + return false; + } + else + return true; + } + + /** + * Fills the session with necessary user info on the fly + * + * @access protected + * @param string $username The username + * @return bool + */ + protected function _jumpStartSession($username) + { + $aUserData = User::model()->findByAttributes(array('users_name' => $username))->attributes; + + $session = array( + 'loginID' => intval($aUserData['uid']), + 'user' => $aUserData['users_name'], + 'full_name' => $aUserData['full_name'], + 'htmleditormode' => $aUserData['htmleditormode'], + 'templateeditormode' => $aUserData['templateeditormode'], + 'questionselectormode' => $aUserData['questionselectormode'], + 'dateformat' => $aUserData['dateformat'], + 'adminlang' => 'en' + ); + foreach ($session as $k => $v) + Yii::app()->session[$k] = $v; + Yii::app()->user->setId($aUserData['uid']); + + $this->controller->_GetSessionUserRights($aUserData['uid']); + return true; + } + + /** + * This function checks if the XML-RPC session key is valid. If yes returns true, otherwise false and sends an error message with error code 1 + * + * @access protected + * @param string $sSessionKey Auth credentials + * @return bool + */ + protected function _checkSessionKey($sSessionKey) + { + $criteria = new CDbCriteria; + $criteria->condition = 'expire < ' . time(); + Session::model()->deleteAll($criteria); + $oResult = Session::model()->findByPk($sSessionKey); + + if (is_null($oResult)) + return false; + else + { + $this->_jumpStartSession($oResult->data); + return true; + } + } +} \ No newline at end of file diff --git a/application/models/ExpressionError.php b/application/models/ExpressionError.php index b340d5bba1c..a865e2f9a1c 100644 --- a/application/models/ExpressionError.php +++ b/application/models/ExpressionError.php @@ -47,7 +47,7 @@ public function tableName() */ public function primaryKey() { - return array('scid'); + return 'scid'; } function getAllRecords($condition=FALSE) diff --git a/application/models/LSActiveRecord.php b/application/models/LSActiveRecord.php index c5dfdf08abd..68389a53998 100644 --- a/application/models/LSActiveRecord.php +++ b/application/models/LSActiveRecord.php @@ -103,6 +103,42 @@ public function beforeDelete() { $result = App()->getPluginManager()->dispatchEvent(new PluginEvent('before'.get_class($this).'Delete', $this)); return parent::beforeDelete(); - } + } + + /** + * Return the max value for a field + * + * This is a convenience method, that uses the primary key of the model to + * retrieve the highest value. + * + * @param string $field The field that contains the Id, when null primary key is used if it is a single field + * @param boolean $forceRefresh Don't use value from static cache but always requery the database + * @return false|int + */ + public function getMaxId($field = null, $forceRefresh = false) { + static $maxIds = array(); + + if (is_null($field)) { + $primaryKey = $this->getPrimaryKey(); + if (is_string($primaryKey)) { + $field = $primaryKey; + } else { + // Composite key, throw a warning to the programmer + throw new Exception(sprintf('Table %s has a composite primary key, please explicitly state what field you need the max value for.', $this->tableName())); + } + } + + if ($forceRefresh || !array_key_exists($field, $maxIds)) { + $maxId = $this->dbConnection->createCommand() + ->select('MAX(' . $this->dbConnection->quoteColumnName($field) . ')') + ->from($this->tableName()) + ->queryScalar(); + + // Save so we can reuse in the same request + $maxIds[$field] = $maxId; + } + + return $maxIds[$field]; + } } \ No newline at end of file diff --git a/application/models/Label.php b/application/models/Label.php index a51a1a47cc0..fcd9610949d 100644 --- a/application/models/Label.php +++ b/application/models/Label.php @@ -40,7 +40,7 @@ public function tableName() */ public function primaryKey() { - return 'lid,language'; + return array('lid', 'language'); } /** * Returns the static model of Settings table diff --git a/application/models/Question.php b/application/models/Question.php index 18aff44ae93..0681a00daa0 100644 --- a/application/models/Question.php +++ b/application/models/Question.php @@ -51,7 +51,7 @@ public function tableName() */ public function primaryKey() { - return 'qid,language'; + return array('qid', 'language'); } /** @@ -96,7 +96,6 @@ public function rules() ); } - /** * Rewrites sort order for questions in a group * diff --git a/application/models/QuestionGroup.php b/application/models/QuestionGroup.php index 9b47757c640..405ff1f6cde 100644 --- a/application/models/QuestionGroup.php +++ b/application/models/QuestionGroup.php @@ -47,7 +47,7 @@ public function tableName() */ public function primaryKey() { - return 'gid,language'; + return array('gid', 'language'); } diff --git a/application/models/SurveyDynamic.php b/application/models/SurveyDynamic.php index e31a0565450..ca532a1dbc0 100644 --- a/application/models/SurveyDynamic.php +++ b/application/models/SurveyDynamic.php @@ -260,7 +260,7 @@ public function exist($srid) } return $exist; } - + /** * Return next id if next response exist in database * diff --git a/scripts/map.js b/scripts/map.js new file mode 100644 index 00000000000..a7218974498 --- /dev/null +++ b/scripts/map.js @@ -0,0 +1,168 @@ +/* + * @license This file is part of LimeSurvey + * See COPYRIGHT.php for copyright notices and details. + * + */ + +$(document).ready(function() +{ + $(".location").each(function(index,element){ + var question = $(element).attr('name'); + var coordinates = $(element).val(); + var latLng = coordinates.split(" "); + var question_id = question.substr(0,question.length-2); + if ($("#mapservice_"+question_id).val()==1){ + // Google Maps + if (gmaps[''+question] == undefined) { + GMapsInitialize(question,latLng[0],latLng[1]); + } + } + else if ($("#mapservice_"+question_id).val()==2){ + // Open Street Map + if (osmaps[''+question]==undefined) { + osmaps[''+question] = OSMapInitialize(question,latLng[0],latLng[1]); + } + } + }); + $(document).on('focusout', ".location",function(event){ + var question = $(event.target).attr('name'); + var name = question.substr(0,question.length - 2); + var coordinates = $(event.target).attr('value'); + var xy = coordinates.split(" "); + var currentMap = gmaps[question]; + var marker = gmaps['marker__'+question]; + var markerLatLng = new google.maps.LatLng(xy[0],xy[1]); + geocodeAddress(name, markerLatLng); + marker.setPosition(markerLatLng); + currentMap.panTo(markerLatLng); + }); +}); + +gmaps = new Object; +osmaps = new Object; +zoom = []; + +// OSMap functions +function OSMapInitialize(question,lat,lng){ + + map = new OpenLayers.Map("gmap_canvas_" + question); + map.addLayer(new OpenLayers.Layer.OSM()); + var lonLat = new OpenLayers.LonLat(lat,lng) + .transform( + new OpenLayers.Projection("EPSG:4326"), // transform from WGS 1984 + map.getProjectionObject() // to Spherical Mercator Projection + ); + var zoom=11; + var markers = new OpenLayers.Layer.Markers( "Markers" ); + map.addLayer(markers); + markers.addMarker(new OpenLayers.Marker(lonLat)); + map.setCenter (lonLat, zoom); + return map; + +} +//// Google Maps Functions (for API V3) //// + +// Initialize map +function GMapsInitialize(question,lat,lng) { + + var name = question.substr(0,question.length - 2); + var latlng = new google.maps.LatLng(lat, lng); + + var mapOptions = { + zoom: zoom[name], + center: latlng, + mapTypeId: google.maps.MapTypeId.ROADMAP + }; + + var map = new google.maps.Map(document.getElementById("gmap_canvas_" + question), mapOptions); + gmaps[''+question] = map; + + var marker = new google.maps.Marker({ + position: latlng, + draggable:true, + map: map, + id: 'marker__'+question + }); + gmaps['marker__'+question] = marker; + + google.maps.event.addListener(map, 'rightclick', function(event) { + marker.setPosition(event.latLng); + map.panTo(event.latLng); + geocodeAddress(name, event.latLng); + $("#answer"+question).val(Math.round(event.latLng.lat()*10000)/10000 + " " + Math.round(event.latLng.lng()*10000)/10000); + }); + + google.maps.event.addListener(marker, 'dragend', function(event) { + //map.panTo(event.latLng); + geocodeAddress(name, event.latLng); + $("#answer"+question).val(Math.round(event.latLng.lat()*10000)/10000 + " " + Math.round(event.latLng.lng()*10000)/10000); + }); +} + +// Reset map when shown by conditions +function resetMap(qID) { + var question = $('#question'+qID+' input.location').attr('name'); + var name = question.substr(0,question.length - 2); + var coordinates = $('#question'+qID+' input.location').attr('value'); + var xy = coordinates.split(" "); + if(gmaps[question]) { + var currentMap = gmaps[question]; + var marker = gmaps['marker__'+question]; + var markerLatLng = new google.maps.LatLng(xy[0],xy[1]); + marker.setPosition(markerLatLng); + google.maps.event.trigger(currentMap, 'resize') + currentMap.setCenter(markerLatLng); + } +} + +// Reverse geocoder +function geocodeAddress(name, pos) { + var geocoder = new google.maps.Geocoder(); + + var city = ''; + var state = ''; + var country = ''; + var postal = ''; + + geocoder.geocode({ + latLng: pos + }, function(results, status) { + if (status == google.maps.GeocoderStatus.OK && results[0]) { + $(results[0].address_components).each(function(i, val) { + if($.inArray('locality', val.types) > -1) { + city = val.short_name; + } + else if($.inArray('administrative_area_level_1', val.types) > -1) { + state = val.short_name; + } + else if($.inArray('country', val.types) > -1) { + country = val.short_name; + } + else if($.inArray('postal_code', val.types) > -1) { + postal = val.short_name; + } + }); + + var location = (results[0].geometry.location); + } + getInfoToStore(name, pos.lat(), pos.lng(), city, state, country, postal); + }); +} + +// Store address info +function getInfoToStore(name, lat, lng, city, state, country, postal){ + + var boycott = $("#boycott_"+name).val(); + // 2 - city; 3 - state; 4 - country; 5 - postal + if (boycott.indexOf("2")!=-1) + city = ''; + if (boycott.indexOf("3")!=-1) + state = ''; + if (boycott.indexOf("4")!=-1) + country = ''; + if (boycott.indexOf("5")!=-1) + postal = ''; + + $("#answer"+name).val(lat + ';' + lng + ';' + city + ';' + state + ';' + country + ';' + postal); +} + diff --git a/scripts/survey_runtime.js b/scripts/survey_runtime.js index c75e8c92f7e..90a569dbdb7 100644 --- a/scripts/survey_runtime.js +++ b/scripts/survey_runtime.js @@ -12,14 +12,11 @@ * See COPYRIGHT.php for copyright notices and details. */ -var DOM1; $(document).ready(function() { - // Jquery-ui navigation buttons navbuttonsJqueryUi(); addClassEmpty(); - DOM1 = (typeof document.getElementsByTagName!='undefined'); if (typeof LEMsetTabIndexes === 'function') { LEMsetTabIndexes(); } if (typeof checkconditions!='undefined') checkconditions(); if (typeof template_onload!='undefined') template_onload(); @@ -68,38 +65,6 @@ $(document).ready(function() // Maxlength for textareas TODO limit to not CSS3 compatible browser maxlengthtextarea(); - // Maps - $(".location").each(function(index,element){ - var question = $(element).attr('name'); - var coordinates = $(element).val(); - var latLng = coordinates.split(" "); - var question_id = question.substr(0,question.length-2); - if ($("#mapservice_"+question_id).val()==1){ - // Google Maps - if (gmaps[''+question] == undefined) { - GMapsInitialize(question,latLng[0],latLng[1]); - } - } - else if ($("#mapservice_"+question_id).val()==2){ - // Open Street Map - if (osmaps[''+question]==undefined) { - osmaps[''+question] = OSMapInitialize(question,latLng[0],latLng[1]); - } - } - }); - $(document).on('focusout', ".location",function(event){ - var question = $(event.target).attr('name'); - var name = question.substr(0,question.length - 2); - var coordinates = $(event.target).attr('value'); - var xy = coordinates.split(" "); - var currentMap = gmaps[question]; - var marker = gmaps['marker__'+question]; - var markerLatLng = new google.maps.LatLng(xy[0],xy[1]); - geocodeAddress(name, markerLatLng); - marker.setPosition(markerLatLng); - currentMap.panTo(markerLatLng); - }); - // #index if ($("#index").size() && $("#index .row.current").size()){ var idx = $("#index"); @@ -178,136 +143,6 @@ function tableCellAdapters() }); } -// This part need to be moved in another external file -gmaps = new Object; -osmaps = new Object; -zoom = []; - -// OSMap functions -function OSMapInitialize(question,lat,lng){ - - map = new OpenLayers.Map("gmap_canvas_" + question); - map.addLayer(new OpenLayers.Layer.OSM()); - var lonLat = new OpenLayers.LonLat(lat,lng) - .transform( - new OpenLayers.Projection("EPSG:4326"), // transform from WGS 1984 - map.getProjectionObject() // to Spherical Mercator Projection - ); - var zoom=11; - var markers = new OpenLayers.Layer.Markers( "Markers" ); - map.addLayer(markers); - markers.addMarker(new OpenLayers.Marker(lonLat)); - map.setCenter (lonLat, zoom); - return map; - -} - -//// Google Maps Functions (for API V3) //// - -// Initialize map -function GMapsInitialize(question,lat,lng) { - - var name = question.substr(0,question.length - 2); - var latlng = new google.maps.LatLng(lat, lng); - - var mapOptions = { - zoom: zoom[name], - center: latlng, - mapTypeId: google.maps.MapTypeId.ROADMAP - }; - - var map = new google.maps.Map(document.getElementById("gmap_canvas_" + question), mapOptions); - gmaps[''+question] = map; - - var marker = new google.maps.Marker({ - position: latlng, - draggable:true, - map: map, - id: 'marker__'+question - }); - gmaps['marker__'+question] = marker; - - google.maps.event.addListener(map, 'rightclick', function(event) { - marker.setPosition(event.latLng); - map.panTo(event.latLng); - geocodeAddress(name, event.latLng); - $("#answer"+question).val(Math.round(event.latLng.lat()*10000)/10000 + " " + Math.round(event.latLng.lng()*10000)/10000); - }); - - google.maps.event.addListener(marker, 'dragend', function(event) { - //map.panTo(event.latLng); - geocodeAddress(name, event.latLng); - $("#answer"+question).val(Math.round(event.latLng.lat()*10000)/10000 + " " + Math.round(event.latLng.lng()*10000)/10000); - }); -} - -// Reset map when shown by conditions -function resetMap(qID) { - var question = $('#question'+qID+' input.location').attr('name'); - var name = question.substr(0,question.length - 2); - var coordinates = $('#question'+qID+' input.location').attr('value'); - var xy = coordinates.split(" "); - if(gmaps[question]) { - var currentMap = gmaps[question]; - var marker = gmaps['marker__'+question]; - var markerLatLng = new google.maps.LatLng(xy[0],xy[1]); - marker.setPosition(markerLatLng); - google.maps.event.trigger(currentMap, 'resize') - currentMap.setCenter(markerLatLng); - } -} - -// Reverse geocoder -function geocodeAddress(name, pos) { - var geocoder = new google.maps.Geocoder(); - - var city = ''; - var state = ''; - var country = ''; - var postal = ''; - - geocoder.geocode({ - latLng: pos - }, function(results, status) { - if (status == google.maps.GeocoderStatus.OK && results[0]) { - $(results[0].address_components).each(function(i, val) { - if($.inArray('locality', val.types) > -1) { - city = val.short_name; - } - else if($.inArray('administrative_area_level_1', val.types) > -1) { - state = val.short_name; - } - else if($.inArray('country', val.types) > -1) { - country = val.short_name; - } - else if($.inArray('postal_code', val.types) > -1) { - postal = val.short_name; - } - }); - - var location = (results[0].geometry.location); - } - getInfoToStore(name, pos.lat(), pos.lng(), city, state, country, postal); - }); -} - -// Store address info -function getInfoToStore(name, lat, lng, city, state, country, postal){ - - var boycott = $("#boycott_"+name).val(); - // 2 - city; 3 - state; 4 - country; 5 - postal - if (boycott.indexOf("2")!=-1) - city = ''; - if (boycott.indexOf("3")!=-1) - state = ''; - if (boycott.indexOf("4")!=-1) - country = ''; - if (boycott.indexOf("5")!=-1) - postal = ''; - - $("#answer"+name).val(lat + ';' + lng + ';' + city + ';' + state + ';' + country + ';' + postal); -} - Array.prototype.push = function() { var n = this.length >>> 0; diff --git a/templates/basic/template.css b/templates/basic/template.css index 9559f6d1f43..5ae49ebd8d4 100644 --- a/templates/basic/template.css +++ b/templates/basic/template.css @@ -316,7 +316,9 @@ table.question tr.array1:hover,table.question tr.array2:hover { .assessments-container { } - +.assessments td{ + text-align: center; +} .clearall-result { font-size: small; font-family:Arial, Helvetica, sans-serif; diff --git a/templates/bluengrey/template.css b/templates/bluengrey/template.css index 4fe35e08f15..15dadd93672 100644 --- a/templates/bluengrey/template.css +++ b/templates/bluengrey/template.css @@ -535,7 +535,9 @@ td.answertext { .assessments-container { background-color: #FFFFFF; } - +.assessments td{ + text-align: center; +} td.clearall-result { text-align: center; } diff --git a/templates/clear_logo/template.css b/templates/clear_logo/template.css index befaed58cca..cdba81ad748 100644 --- a/templates/clear_logo/template.css +++ b/templates/clear_logo/template.css @@ -413,7 +413,9 @@ table.question tr.array1:hover,table.question tr.array2:hover { .assessments-container { } - +.assessments td{ + text-align: center; +} .completed-table { margin: 0 auto; width: 75%; diff --git a/templates/default/template.css b/templates/default/template.css index d5c7ec6b21d..0ec614b4bc4 100644 --- a/templates/default/template.css +++ b/templates/default/template.css @@ -596,7 +596,9 @@ table.group { .assessments-container { } - +.assessments td{ + text-align: center; +} .completed-table { margin: 0 auto; width: 90%; diff --git a/templates/eirenicon/template.css b/templates/eirenicon/template.css index b342ee042bd..a4a24bd82de 100644 --- a/templates/eirenicon/template.css +++ b/templates/eirenicon/template.css @@ -472,7 +472,9 @@ table.group { .assessments-container { } - +.assessments td{ + text-align: center; +} .completed-table { margin: 0 auto; width: 75%; diff --git a/templates/limespired/template.css b/templates/limespired/template.css index 2bfadd87134..e224ba68e81 100644 --- a/templates/limespired/template.css +++ b/templates/limespired/template.css @@ -646,7 +646,9 @@ table.question tr.array2:hover { .survey-assessment { font-weight: bold; } - +.assessments td{ + text-align: center; +} A:link,A:visited,A:active { text-decoration: none; color: #00677d; diff --git a/templates/mint_idea/template.css b/templates/mint_idea/template.css index f9ac914fb54..7d19203271c 100644 --- a/templates/mint_idea/template.css +++ b/templates/mint_idea/template.css @@ -356,7 +356,9 @@ div.clear-all { div.assessment-heading { font-weight: bold; } - +.assessments td{ + text-align: center; +} /* paragraphs -------------------------------------------------------------------- */ p { margin: 15px 0; diff --git a/templates/sherpa/template.css b/templates/sherpa/template.css index 91c202387b4..e68c12668ee 100644 --- a/templates/sherpa/template.css +++ b/templates/sherpa/template.css @@ -229,7 +229,9 @@ select.select { div.assessment-heading { font-weight: bold; } - +.assessments td{ + text-align: center; +} .assessment-heading, .survey-completed { text-align: center; diff --git a/templates/vallendar/template.css b/templates/vallendar/template.css index 3526eedf476..0c1f8c25bb2 100644 --- a/templates/vallendar/template.css +++ b/templates/vallendar/template.css @@ -297,7 +297,9 @@ table.assessment-table { .assessments td { border: 0 none; } - +.assessments td{ + text-align: center; +} .completed-table { margin: 0 auto; width: 75%;