diff --git a/.gitignore b/.gitignore index ada34299db8..6dd858a4ba3 100644 --- a/.gitignore +++ b/.gitignore @@ -54,5 +54,12 @@ Thumbs.db .buildpath *.un~ launch.json +# ignore plugins directory by default except LS plugin +# if you want to add a new distributed plugin : add the directory here +/plugins/* +!/plugins/index.html +!/plugins/Demo/ +!/plugins/AuditLog/ +enabletests diff --git a/application/config/internal.php b/application/config/internal.php index 927ddcf6a13..c9756a89fe8 100644 --- a/application/config/internal.php +++ b/application/config/internal.php @@ -43,6 +43,7 @@ // Third party path 'third_party' => realpath(__DIR__ . '/../../third_party'), 'core' => realpath(__DIR__ . '/../../assets/packages'), + 'fonts' => realpath(__DIR__ . '/../../fonts'), // yiistrap configuration 'bootstrap' => realpath(__DIR__ . '/../extensions/bootstrap'), @@ -58,6 +59,8 @@ // This line just point application.vendor.Twig to application/third_party/Twig // @see: ETwigViewRenderer::$twigPathAlias 'application.vendor.Twig'=>'application.third_party.Twig', + // 'CaptchaExtendedAction' => realpath(__DIR__ . '/../extensions/captchaExtended/CaptchaExtendedAction.php'), + // 'CaptchaExtendedValidator' => realpath(__DIR__ . '/../extensions/captchaExtended/CaptchaExtendedValidator.php') ), 'modules'=>array( @@ -84,12 +87,13 @@ 'application.models.*', 'application.controllers.*', 'application.modules.*', - 'bootstrap.helpers.*', 'bootstrap.widgets.*', 'bootstrap.behaviors.*', 'yiiwheels.widgets.select2.WhSelect2', - 'third_party.Twig.*' + 'third_party.Twig.*', + 'ext.captchaExtended.CaptchaExtendedAction', + 'ext.captchaExtended.CaptchaExtendedValidator' ), 'preload' => array ('log'), @@ -214,6 +218,8 @@ 'registerGeneralScript' => 'LS_Twig_Extension::registerGeneralScript', 'registerTemplateScript' => 'LS_Twig_Extension::registerTemplateScript', 'registerScript' => 'LS_Twig_Extension::registerScript', + 'unregisterPackage' => 'LS_Twig_Extension::unregisterPackage', + 'listCoreScripts' => 'LS_Twig_Extension::listCoreScripts', 'getAllQuestionClasses' => 'LS_Twig_Extension::getAllQuestionClasses', 'intval' => 'intval', 'empty' => 'empty', @@ -237,7 +243,7 @@ ), 'sandboxConfig' => array( - 'tags' => array('if', 'for', 'set', 'autoescape'), + 'tags' => array('if', 'for', 'set', 'autoescape', 'block'), 'filters' => array('escape', 'raw', 't', 'merge', 'length', 'gT', 'keys'), 'methods' => array( 'ETwigViewRendererStaticClassProxy' => array("encode", "textfield", "form", "link", "emailField", "beginForm", "endForm", "dropDownList", "htmlButton", "passwordfield" ), @@ -248,7 +254,7 @@ 'ETwigViewRendererYiiCoreStaticClassesProxy' => array("Html"), 'LSYii_Application' => array("request"), ), - 'functions' => array('include', 'dump', 'flatEllipsizeText', 'getLanguageData', 'array_flip', 'array_intersect_key', 'registerPublicCssFile', 'registerTemplateCssFile', 'registerGeneralScript', 'registerTemplateScript', 'registerScript', 'getAllQuestionClasses','intval', 'count', 'empty', 'reset', 'renderCaptcha', 'getPost','getParam', 'getQuery', 'isset', 'str_replace', 'assetPublish', 'image', 'sprintf', 'gT' ), + 'functions' => array('include', 'dump', 'flatEllipsizeText', 'getLanguageData', 'array_flip', 'array_intersect_key', 'registerPublicCssFile', 'registerTemplateCssFile', 'registerGeneralScript', 'registerTemplateScript', 'registerScript', 'unregisterPackage', 'listCoreScripts', 'getAllQuestionClasses','intval', 'count', 'empty', 'reset', 'renderCaptcha', 'getPost','getParam', 'getQuery', 'isset', 'str_replace', 'assetPublish', 'image', 'sprintf', 'gT' ), ), ), diff --git a/application/config/packages.php b/application/config/packages.php index 2a7f19a0ee9..c69ed44bc92 100644 --- a/application/config/packages.php +++ b/application/config/packages.php @@ -65,8 +65,8 @@ ), 'bootstrap-rtl'=>array( /* Adding boostrap rtl package */ - 'devBaseUrl' => 'assets/packages/bootstrap-rtl/', - 'basePath' => 'core.bootstrap-rtl', + 'devBaseUrl' => 'assets/packages/bootstrap/', + 'basePath' => 'core.bootstrap', 'css'=> array( 'bootstrap-rtl.css', ), diff --git a/application/config/third_party.php b/application/config/third_party.php index ab4f27bc678..ded633a106e 100755 --- a/application/config/third_party.php +++ b/application/config/third_party.php @@ -8,7 +8,7 @@ /* This allow us to use minified version according to debug */ $debug = isset($userConfig['config']['debug']) ? $userConfig['config']['debug'] : 0; /* To add more easily min version : config > 2 , seems really an core dev issue to fix bootstrap.js ;) */ -$minVersion = ($debug>2) ? "":".min"; +$minVersion = ($debug>0) ? "":".min"; /* Please : comment the reason, mantis bug link: ajax don't need any package if i don't make error */ /* Ajax must renderPartial (better : always return json) and never render and don't registerScript (IMHO) / Shnoulle on 2016-11-16 */ if(isset($_GET['isAjax'])){ @@ -19,6 +19,7 @@ // jQuery 'jquery' => array( + 'devBaseUrl' => 'third_party/jquery', 'basePath' => 'third_party.jquery', 'js' => array( 'jquery-3.1.1'.$minVersion.'.js', @@ -27,16 +28,17 @@ ), // Bootstrap // This package replace the Yiistrap register() function - // Then instead of using the composer dependency system for templates (will be used for LS3) + // Then instead of using the composer dependency system for templates // We can use the package dependency system (easier for now) 'bootstrap' => array( - 'basePath' => 'bootstrap', + 'devBaseUrl' => 'assets/packages/bootstrap/', + 'basePath' => 'core.bootstrap', 'css'=> array( - 'css/bootstrap.css',/* Admin need it, not public */ - 'css/yiistrap.css', + 'bootstrap'.$minVersion.'.css',/* Admin need it, not public */ + 'yiistrap'.$minVersion.'.css', ), 'js'=>array( - 'js/bootstrap'.$minVersion.'.js' + 'bootstrap'.$minVersion.'.js' ), 'depends' => array( 'jquery', @@ -59,14 +61,16 @@ 'fontawesome' => array( //'basePath' => 'third_party.bootstrap', // Need fix third_party alias - 'basePath' => 'third_party.fontawesome', + 'devBaseUrl' => 'fonts/fontawesome/', + 'basePath' => 'fonts.fontawesome', 'css'=> array( - 'css/font-awesome.min.css', + 'css/font-awesome'.$minVersion.'.css', ), ), // jQuery UI 'jqueryui' => array( + 'devBaseUrl' => 'third_party/jquery-ui', 'basePath' => 'third_party.jquery-ui', 'js' => array( 'jquery-ui'.$minVersion.'.js', @@ -188,6 +192,7 @@ // Ace 'ace' => array( + 'devBaseUrl' => 'third_party/ace', 'basePath' => 'third_party.ace', 'js' => array( 'ace.js' @@ -199,6 +204,7 @@ // jQuery Ace 'jquery-ace' => array( + 'devBaseUrl' => 'third_party/jquery-ace', 'basePath' => 'third_party.jquery-ace', 'js' => array( 'jquery.ace.js', @@ -232,6 +238,7 @@ // Decimal.js calculate in js 'decimal' => array( + 'devBaseUrl' => 'third_party/decimal', 'basePath' => 'third_party.decimal', 'js' => array( 'decimal.js' @@ -370,5 +377,14 @@ 'jquery.autocomplete'.$minVersion.'.js' ), ), - + 'jszip' => array( + 'basePath' => 'third_party.jszip', + 'js' => array( + 'jszip.js', + 'fileSaver.js', + ), + 'depends' => array( + 'jquery', + ) + ) ); diff --git a/application/config/version.php b/application/config/version.php index 8cd3decb376..378ba348441 100644 --- a/application/config/version.php +++ b/application/config/version.php @@ -13,8 +13,8 @@ $config['versionnumber'] = '3.0.0-alpha'; //The current version of this branch $config['masterversion'] = '2.62.2'; //The current masters version merged into this branch -$config['dbversionnumber'] = 263; +$config['dbversionnumber'] = 292; $config['buildnumber'] = ''; $config['updatable'] = true; -$config['assetsversionnumber'] = '2647'; +$config['assetsversionnumber'] = '2671'; return $config; diff --git a/application/controllers/InstallerController.php b/application/controllers/InstallerController.php index cc4951eb780..40e86a72dde 100644 --- a/application/controllers/InstallerController.php +++ b/application/controllers/InstallerController.php @@ -885,6 +885,11 @@ function check_DirectoryWriteable($directory, &$data, $base, $keyError, $bRecurs if (!check_PHPFunction('mb_convert_encoding', $aData['mbstringPresent'])) $bProceed = false; + // zlib library check + if (!check_PHPFunction('zlib_get_coding_type', $aData['zlibPresent'])) { + $bProceed = false; + } + // JSON library check if (!check_PHPFunction('json_encode', $aData['bJSONPresent'])) $bProceed = false; diff --git a/application/controllers/OptoutController.php b/application/controllers/OptoutController.php old mode 100644 new mode 100755 index 5248cabe6f0..9036d6090b8 --- a/application/controllers/OptoutController.php +++ b/application/controllers/OptoutController.php @@ -24,11 +24,55 @@ class OptoutController extends LSYii_Controller { public $layout = 'bare'; public $defaultAction = 'tokens'; + + function actiontokens() + { + + + $iSurveyID = Yii::app()->request->getQuery('surveyid'); + $sLanguageCode = Yii::app()->request->getQuery('langcode'); + $sToken = Token::sanitizeToken(Yii::app()->request->getQuery('token')); + + Yii::app()->loadHelper('database'); + Yii::app()->loadHelper('sanitize'); + + //IF there is no survey id, redirect back to the default public page + if (!$iSurveyID){ + $this->redirect(array('/')); + } + + $iSurveyID = (int)$iSurveyID; //Make sure it's an integer (protect from SQL injects) + //Check that there is a SID + // Get passed language from form, so that we dont lose this! + if (!isset($sLanguageCode) || $sLanguageCode == "" || !$sLanguageCode) + { + $sBaseLanguage = Survey::model()->findByPk($iSurveyID)->language; + } + else + { + $sBaseLanguage = sanitize_languagecode($sLanguageCode); + } + + Yii::app()->setLanguage($sBaseLanguage); + + $aSurveyInfo=getSurveyInfo($iSurveyID,$sBaseLanguage); + + if ($aSurveyInfo==false || !tableExists("{{tokens_{$iSurveyID}}}")){ + throw new CHttpException(404, "The survey in which you are trying to participate does not seem to exist. It may have been deleted or the link you were given is outdated or incorrect."); + }else{ + $sMessage = "

".gT('Please confirm that you want to opt out of this survey by clicking the button below.').'
'. gT("After confirmation you won't receive any invitations or reminders for this survey anymore.")."

"; + $sMessage .= '

'.gT("I confirm").'

'; + $this->_renderHtml($sMessage, $aSurveyInfo, $iSurveyID); + } + + + } + /** * This function is run when opting out of an individual token table. The other function /optout/participants * opts the user out of ALL survey invitations from the system */ - function actiontokens() + function actionremovetokens() { $iSurveyID=Yii::app()->request->getQuery('surveyid'); $sLanguageCode=Yii::app()->request->getQuery('langcode'); diff --git a/application/controllers/RegisterController.php b/application/controllers/RegisterController.php index 563ffe5f544..08e63d323d5 100644 --- a/application/controllers/RegisterController.php +++ b/application/controllers/RegisterController.php @@ -48,8 +48,8 @@ public function actions() { return array( 'captcha' => array( - 'class' => 'CCaptchaAction', - 'backColor'=>0xf6f6f6 + 'class' => 'CaptchaExtendedAction', + 'mode'=>CaptchaExtendedAction::MODE_MATH ) ); } @@ -471,7 +471,7 @@ private function display($iSurveyId) $oTemplate = Template::model()->getInstance('', $iSurveyId); Yii::app()->clientScript->registerPackage( 'survey-template' ); - $this->sTemplate=$oTemplate->name; + $this->sTemplate=$oTemplate->sTemplateName; if(!$this->sMessage){ $this->aGlobalData['languagechanger']=makeLanguageChangerSurvey($sLanguage); // Only show language changer shown the form is shown, not after submission $this->aReplacementData['content']=self::getRegisterForm($iSurveyId); diff --git a/application/controllers/SurveyController.php b/application/controllers/SurveyController.php index 628cecaa914..8e97a96f642 100644 --- a/application/controllers/SurveyController.php +++ b/application/controllers/SurveyController.php @@ -80,8 +80,9 @@ public function actions() 'uploader' => 'application.controllers.uploader', 'verification' => 'application.controllers.verification', 'captcha' => array( - 'class' => 'CCaptchaAction', - 'backColor'=>0xf6f6f6 + 'class'=>'CaptchaExtendedAction', + // if needed, modify settings + 'mode'=>CaptchaExtendedAction::MODE_MATH, ) ); } diff --git a/application/controllers/SurveysController.php b/application/controllers/SurveysController.php index 45bf9e47875..3ac104ad9db 100644 --- a/application/controllers/SurveysController.php +++ b/application/controllers/SurveysController.php @@ -31,7 +31,7 @@ public function actionPublicList($lang = null) //$oTemplate->registerAssets(); - $this->sTemplate = $oTemplate->name; + $this->sTemplate = $oTemplate->sTemplateName; //Yii::app()->clientScript->registerPackage( 'survey-template' ); //Yii::app()->clientScript->registerPackage( 'survey-template-'.$oTemplate->sTemplateName ); //var_dump('survey-template-'.$oTemplate->sTemplateName); @@ -70,7 +70,7 @@ public function actionError() { $oTemplate = Template::model()->getInstance(Yii::app()->getConfig("defaulttemplate")); - $this->sTemplate = $oTemplate->name; + $this->sTemplate = $oTemplate->sTemplateName; $error = Yii::app()->errorHandler->error; if ($error){ @@ -81,5 +81,4 @@ public function actionError() } } - } -?> + } \ No newline at end of file diff --git a/application/controllers/admin/NotificationController.php b/application/controllers/admin/NotificationController.php index f1346869611..0173dc035aa 100644 --- a/application/controllers/admin/NotificationController.php +++ b/application/controllers/admin/NotificationController.php @@ -28,17 +28,15 @@ public function index() public function getNotificationAsJSON($notId) { $this->checkPermission(); - - $not = Notification::model()->findByPk($notId); - - if ($not) - { - echo json_encode(array('result' => $not->getAttributes())); + if ((string) (int) $notId !== (string) $notId) { + } - else - { - echo json_encode(array('error' => 'Found no notification with id ' . $notId)); + $not = Notification::model()->findByPk($notId); + if(!$not) { + throw new CHttpException(404,sprintf(gT("Notification %s not found"),$notId)); } + header('Content-type: application/json'); + echo json_encode(array('result' => $not->getAttributes())); } /** @@ -51,17 +49,16 @@ public function notificationRead($notId) { $this->checkPermission(); - try - { - $not = Notification::model()->findByPk($notId); - $result = $not->markAsRead(); - echo json_encode(array('result' => $result)); + if ((string) (int) $notId !== (string) $notId) { + throw new CHttpException(403,gT("Invalid notification id")); } - catch (Exception $ex) - { - echo json_encode(array('error' => $ex->getMessage())); + $not = Notification::model()->findByPk($notId); + if(!$not) { + throw new CHttpException(404,sprintf(gT("Notification %s not found"),$notId)); } - + $result = $not->markAsRead(); + header('Content-type: application/json'); + echo json_encode(array('result' => $result)); } /** @@ -73,7 +70,6 @@ public function notificationRead($notId) public function actionGetMenuWidget($surveyId = null, $showLoader = false) { $this->checkPermission(); - echo self::getMenuWidget($surveyId, $showLoader); } @@ -85,14 +81,14 @@ public function actionGetMenuWidget($surveyId = null, $showLoader = false) public function clearAllNotifications($surveyId = null) { Notification::model()->deleteAll( - 'entity = \'user\' AND entity_id = ' . Yii::app()->user->id + 'entity = :entity AND entity_id = :entity_id', + array(":entity"=>'user',":entity_id"=>Yii::app()->user->id) ); - if (!is_null($surveyId)) - { - $surveyId = intval($surveyId); + if (is_int($surveyId)) { Notification::model()->deleteAll( - 'entity = \'survey\' AND entity_id = ' . $surveyId + 'entity = :entity AND entity_id = :entity_id', + array(":entity"=>'survey',":entity_id"=>$surveyId) ); } } @@ -104,9 +100,8 @@ public function clearAllNotifications($surveyId = null) protected function checkPermission() { // Abort if user is not logged in - if(Yii::app()->user->isGuest) - { - die('No permission'); + if (Yii::app()->user->isGuest) { + throw new CHttpException(401); } } @@ -129,10 +124,13 @@ public static function getMenuWidget($surveyId = null, $showLoader = false) $data = array(); $data['surveyId'] = $surveyId; $data['showLoader'] = $showLoader; - $data['clearAllNotificationsUrl'] = Yii::app()->createUrl('admin/notification', array( + $params=array( 'sa' => 'clearAllNotifications', - 'surveyId' => $surveyId - )); + ); + if ($surveyId) { + $params['surveyId'] = $surveyId; + } + $data['clearAllNotificationsUrl'] = Yii::app()->createUrl('admin/notification', $params); $data['updateUrl'] = Notification::getUpdateUrl($surveyId); $data['nrOfNewNotifications'] = Notification::countNewNotifications($surveyId); $data['nrOfNotifications'] = Notification::countNotifications($surveyId); diff --git a/application/controllers/admin/database.php b/application/controllers/admin/database.php index 03a72507f9e..899d6eee7d4 100644 --- a/application/controllers/admin/database.php +++ b/application/controllers/admin/database.php @@ -1317,6 +1317,30 @@ private function actionInsertCopyQuestion($iSurveyID) $validAttributes = Question::getQuestionTemplateAttributes($validAttributes, $aAttributeValues, $cqr ); $aLanguages=array_merge(array(Survey::model()->findByPk($iSurveyID)->language),Survey::model()->findByPk($iSurveyID)->additionalLanguages); + /* Start to fix some param before save (TODO : use models directly ?) */ + /* Date management */ + Yii::app()->loadHelper('surveytranslator'); + $formatdata=getDateFormatData(Yii::app()->session['dateformat']); + $startdate = App()->request->getPost('startdate'); + if (trim($startdate)=="") + { + $startdate=null; + } + else + { + $datetimeobj = DateTime::createFromFormat($formatdata['phpdate'].' H:i', $startdate ); + $startdate=$datetimeobj->format("Y-m-d H:i:s"); + } + $expires = App()->request->getPost('expires'); + if (trim($expires)=="") + { + $expires=null; + } + else + { + $datetimeobj = DateTime::createFromFormat($formatdata['phpdate'].' H:i', $expires); + $expires=$datetimeobj->format("Y-m-d H:i:s"); + } foreach ($validAttributes as $validAttribute) { diff --git a/application/controllers/admin/dataentry.php b/application/controllers/admin/dataentry.php index c6d5bc323ab..dea95551584 100644 --- a/application/controllers/admin/dataentry.php +++ b/application/controllers/admin/dataentry.php @@ -710,8 +710,8 @@ public function editdata($subaction, $id, $surveyid, $language='') ; if ($idrow[$fname['fieldname']]!='') { - $datetimeobj = new Date_Time_Converter($idrow[$fname['fieldname']], "Y-m-d H:i:s"); - $thisdate = $datetimeobj->convert($dateformatdetails['phpdate']); + $datetimeobj = DateTime::createFromFormat("!Y-m-d H:i:s", $idrow[$fname['fieldname']]); + $thisdate = $datetimeobj->format($dateformatdetails['phpdate']); } else { @@ -1503,12 +1503,10 @@ public function update() $qidattributes = getQuestionAttributeValues($irow['qid']); $dateformatdetails = getDateFormatDataForQID($qidattributes, $thissurvey); - $this->getController()->loadLibrary('Date_Time_Converter'); - $datetimeobj = new date_time_converter($thisvalue,$dateformatdetails['phpdate']) ; + $datetimeobj = DateTime::createFromFormat('!' . $dateformatdetails['phpdate'], $thisvalue); //need to check if library get initialized with new value of constructor or not. - //$datetimeobj = new Date_Time_Converter($thisvalue,$dateformatdetails['phpdate']); - $updateqr .= dbQuoteID($fieldname)." = '{$datetimeobj->convert("Y-m-d H:i:s")}', \n"; + $updateqr .= dbQuoteID($fieldname)." = '{$datetimeobj->format("Y-m-d H:i:s")}', \n"; } } elseif (($irow['type'] == 'N' || $irow['type'] == 'K') && $thisvalue == "") @@ -1766,11 +1764,10 @@ public function insert() } elseif ($irow['type'] == 'D') { - Yii::app()->loadLibrary('Date_Time_Converter'); $qidattributes = getQuestionAttributeValues($irow['qid']); $dateformatdetails = getDateFormatDataForQID($qidattributes, $thissurvey); - $datetimeobj = new Date_Time_Converter($_POST[$fieldname],$dateformatdetails['phpdate']); - $insert_data[$fieldname] = $datetimeobj->convert("Y-m-d H:i:s"); + $datetimeobj = DateTime::createFromFormat('!' . $dateformatdetails['phpdate'], $_POST[$fieldname]); + $insert_data[$fieldname] = $datetimeobj->format("Y-m-d H:i:s"); } else { @@ -2466,23 +2463,21 @@ private function _array_filter_help($qidattributes, $surveyprintlang, $surveyid) if(!empty($qidattributes['array_filter'])) { - $newquestiontext = Question::model()->findByAttributes(array('title' => $qidattributes['array_filter'], 'language' => $surveyprintlang, 'sid' => $surveyid)); - if(is_object($newquestiontext)) - { - $newquestiontext->getAttribute('question'); + /** @var Question $question */ + $question = Question::model()->findByAttributes(array('title' => $qidattributes['array_filte'], 'language' => $surveyprintlang, 'sid' => $surveyid)); + if($question) { $output .= "\n

- ".sprintf(gT("Only answer this question for the items you selected in question %s ('%s')"),$qidattributes['array_filter'], flattenText(breakToNewline($newquestiontext)))." + ".sprintf(gT("Only answer this question for the items you selected in question %s ('%s')"),$qidattributes['array_filter'], flattenText(breakToNewline($question->question)))."

\n"; } } if(!empty($qidattributes['array_filter_exclude'])) { - $newquestiontext = Question::model()->findByAttributes(array('title' => $qidattributes['array_filter_exclude'], 'language' => $surveyprintlang, 'sid' => $surveyid)); - if(is_object($newquestiontext)) - { - $newquestiontext->getAttribute('question'); + /** @var Question $question */ + $question = Question::model()->findByAttributes(array('title' => $qidattributes['array_filter_exclude'], 'language' => $surveyprintlang, 'sid' => $surveyid)); + if($question) { $output .= "\n

- ".sprintf(gT("Only answer this question for the items you did not select in question %s ('%s')"),$qidattributes['array_filter_exclude'], breakToNewline($newquestiontext))." + ".sprintf(gT("Only answer this question for the items you did not select in question %s ('%s')"),$qidattributes['array_filter_exclude'], breakToNewline($question->question))."

\n"; } } diff --git a/application/controllers/admin/export.php b/application/controllers/admin/export.php index cdf8d73d5fd..45b96b88cd4 100644 --- a/application/controllers/admin/export.php +++ b/application/controllers/admin/export.php @@ -1370,7 +1370,7 @@ public function quexml($iSurveyID) */ private function _exportPrintableHtmls($iSurveyID,$readFile = true){ $oSurvey = Survey::model()->findByPk($iSurveyID); - $assetsDir = Template::getTemplateURL($oSurvey->template); + $assetsDir = substr(Template::getTemplateURL($oSurvey->template),1); $fullAssetsDir = Template::getTemplatePath($oSurvey->template); $aLanguages = $oSurvey->getAllLanguages(); diff --git a/application/controllers/admin/homepagesettings.php b/application/controllers/admin/homepagesettings.php index 442d86bc434..da2bd1494d1 100644 --- a/application/controllers/admin/homepagesettings.php +++ b/application/controllers/admin/homepagesettings.php @@ -56,6 +56,11 @@ public function create() $model=new Boxes; if(isset($_POST['Boxes'])) { + if (Yii::app()->getConfig('demoMode')) + { + Yii::app()->setFlashMessage(gT('This setting cannot be changed because demo mode is active.'),'error'); + $this->getController()->redirect(Yii::app()->getController()->createUrl("/admin/homepagesettings")); + } $model->attributes=$_POST['Boxes']; if($model->save()) { diff --git a/application/controllers/admin/htmleditor_pop.php b/application/controllers/admin/htmleditor_pop.php index 586f017c05f..b5627c82ab5 100644 --- a/application/controllers/admin/htmleditor_pop.php +++ b/application/controllers/admin/htmleditor_pop.php @@ -39,8 +39,7 @@ function index() $aData['sControlIdDis'] = $aData['sFieldName'] . '_popupctrldis'; $aData['toolbarname'] = 'popup'; $aData['htmlformatoption'] = ''; - - if (in_array($aData['sFieldType'], array('email-inv', 'email-reg', 'email-conf', 'email-rem'))) + if (in_array($aData['sFieldType'], array('email-invitation', 'email-registration', 'email-confirmation', 'email-reminder'))) { $aData['htmlformatoption'] = ',fullPage:true'; } diff --git a/application/controllers/admin/limereplacementfields.php b/application/controllers/admin/limereplacementfields.php index e604c65d78a..d9db2fde955 100644 --- a/application/controllers/admin/limereplacementfields.php +++ b/application/controllers/admin/limereplacementfields.php @@ -26,7 +26,6 @@ public function index() throw new CHttpException(401); } list($replacementFields, $isInsertAnswerEnabled) = $this->_getReplacementFields($fieldtype, $surveyid); - if ($isInsertAnswerEnabled === true) { //2: Get all other questions that occur before this question that are pre-determined answer types @@ -42,6 +41,7 @@ public function index() } $data['countfields'] = count($replacementFields); + asort($replacementFields); $data['replFields'] = $replacementFields; if (isset($childQuestions)) { $data['cquestions'] = $childQuestions; @@ -208,99 +208,103 @@ private function _getReplacementFields($fieldtype, $surveyid) case 'editdescription': // for translation case 'editwelcome': // for translation case 'editend': // for translation - $replFields[] = array('TOKEN:FIRSTNAME', gT("First name from token")); - $replFields[] = array('TOKEN:LASTNAME', gT("Last name from token")); - $replFields[] = array('TOKEN:EMAIL', gT("Email from the token")); + $replFields['TOKEN:FIRSTNAME']= gT("First name from token"); + $replFields['TOKEN:LASTNAME']= gT("Last name from token"); + $replFields['TOKEN:EMAIL']= gT("Email from the token"); $attributes = getTokenFieldsAndNames($surveyid, true); foreach ($attributes as $attributefield => $attributedescription) { - $replFields[] = array('TOKEN:' . strtoupper($attributefield), sprintf(gT("Token attribute: %s"), $attributedescription['description'])); + $replFields['TOKEN:' . strtoupper($attributefield)]= sprintf(gT("Token attribute: %s"), $attributedescription['description']); } - $replFields[] = array('EXPIRY', gT("Survey expiration date")); - $replFields[] = array('ADMINNAME', gT("Name of the survey administrator")); - $replFields[] = array('ADMINEMAIL', gT("Email address of the survey administrator")); + $replFields['EXPIRY']= gT("Survey expiration date"); + $replFields['ADMINNAME']= gT("Name of the survey administrator"); + $replFields['ADMINEMAIL']= gT("Email address of the survey administrator"); return array($replFields, false); case 'email-admin_notification': case 'email-admin_detailed_notification': - $replFields[] = array('RELOADURL', gT("Reload URL")); - $replFields[] = array('VIEWRESPONSEURL', gT("View response URL")); - $replFields[] = array('EDITRESPONSEURL', gT("Edit response URL")); - $replFields[] = array('STATISTICSURL', gT("Statistics URL")); - $replFields[] = array('TOKEN', gT("Token code for this participant")); - $replFields[] = array('TOKEN:FIRSTNAME', gT("First name from token")); - $replFields[] = array('TOKEN:LASTNAME', gT("Last name from token")); - $replFields[] = array('SURVEYNAME', gT("Name of the survey")); - $replFields[] = array('SURVEYDESCRIPTION', gT("Description of the survey")); + $replFields['RELOADURL']= gT("Reload URL"); + $replFields['VIEWRESPONSEURL']= gT("View response URL"); + $replFields['EDITRESPONSEURL']= gT("Edit response URL"); + $replFields['STATISTICSURL']= gT("Statistics URL"); + $replFields['TOKEN']= gT("Token code for this participant"); + $replFields['TOKEN:FIRSTNAME']= gT("First name from token"); + $replFields['TOKEN:LASTNAME']= gT("Last name from token"); + $replFields['SURVEYNAME']= gT("Survey title"); + $replFields['SID']= gT("Survey ID"); + $replFields['SURVEYDESCRIPTION']= gT("Survey description"); $attributes = getTokenFieldsAndNames($surveyid, true); - foreach ($attributes as $attributefield => $attributedescription) - { - $replFields[] = array(strtoupper($attributefield), sprintf(gT("Token attribute: %s"), $attributedescription['description'])); + foreach ($attributes as $attributefield => $attributedescription) { + $replFields[strtoupper($attributefield)] = sprintf(gT("Token attribute: %s"), $attributedescription['description']); } - $replFields[] = array('ADMINNAME', gT("Name of the survey administrator")); - $replFields[] = array('ADMINEMAIL', gT("Email address of the survey administrator")); + $replFields['ADMINNAME']= gT("Name of the survey administrator"); + $replFields['ADMINEMAIL']= gT("Email address of the survey administrator"); return array($replFields, false); case 'email-admin-resp': - $replFields[] = array('RELOADURL', gT("Reload URL")); - $replFields[] = array('VIEWRESPONSEURL', gT("View response URL")); - $replFields[] = array('EDITRESPONSEURL', gT("Edit response URL")); - $replFields[] = array('STATISTICSURL', gT("Statistics URL")); - $replFields[] = array('ANSWERTABLE', gT("Answers from this response")); - $replFields[] = array('TOKEN', gT("Token code for this participant")); - $replFields[] = array('TOKEN:FIRSTNAME', gT("First name from token")); - $replFields[] = array('TOKEN:LASTNAME', gT("Last name from token")); - $replFields[] = array('SURVEYNAME', gT("Name of the survey")); - $replFields[] = array('SURVEYDESCRIPTION', gT("Description of the survey")); + $replFields['RELOADURL']= gT("Reload URL"); + $replFields['VIEWRESPONSEURL']= gT("View response URL"); + $replFields['EDITRESPONSEURL']= gT("Edit response URL"); + $replFields['STATISTICSURL']= gT("Statistics URL"); + $replFields['ANSWERTABLE']= gT("Answers from this response"); + $replFields['TOKEN']= gT("Token code for this participant"); + $replFields['TOKEN:FIRSTNAME']= gT("First name from token"); + $replFields['TOKEN:LASTNAME']= gT("Last name from token"); + $replFields['SURVEYNAME']= gT("Survey title"); + $replFields['SID']= gT("Survey ID"); + $replFields['SURVEYDESCRIPTION']= gT("Survey description"); $attributes = getTokenFieldsAndNames($surveyid, true); foreach ($attributes as $attributefield => $attributedescription) { - $replFields[] = array(strtoupper($attributefield), sprintf(gT("Token attribute: %s"), $attributedescription['description'])); + $replFields[strtoupper($attributefield)] = sprintf(gT("Token attribute: %s"), $attributedescription['description']); } - $replFields[] = array('ADMINNAME', gT("Name of the survey administrator")); - $replFields[] = array('ADMINEMAIL', gT("Email address of the survey administrator")); + $replFields['ADMINNAME']= gT("Name of the survey administrator"); + $replFields['ADMINEMAIL']= gT("Email address of the survey administrator"); return array($replFields, false); case 'email-invitation': case 'email-reminder': // these 2 fields are supported by email-inv and email-rem // but not email-reg for the moment - $replFields[] = array('EMAIL', gT("Email from the token")); - $replFields[] = array('TOKEN', gT("Token code for this participant")); - $replFields[] = array('OPTOUTURL', gT("URL for a respondent to opt-out of this survey")); - $replFields[] = array('OPTINURL', gT("URL for a respondent to opt-in to this survey")); + $replFields['EMAIL']= gT("Email from the token"); + $replFields['TOKEN']= gT("Token code for this participant"); + $replFields['OPTOUTURL']= gT("URL for a respondent to opt-out of this survey"); + $replFields['OPTINURL']= gT("URL for a respondent to opt-in to this survey"); + // $replFields['SID']= gT("Survey ID"); case 'email-registration': - $replFields[] = array('FIRSTNAME', gT("First name from token")); - $replFields[] = array('LASTNAME', gT("Last name from token")); - $replFields[] = array('SURVEYNAME', gT("Name of the survey")); - $replFields[] = array('SURVEYDESCRIPTION', gT("Description of the survey")); + $replFields['FIRSTNAME']= gT("First name from token"); + $replFields['LASTNAME']= gT("Last name from token"); + $replFields['SURVEYNAME']= gT("Survey title"); + $replFields['SID']= gT("Survey ID"); + $replFields['SURVEYDESCRIPTION']= gT("Survey description"); $attributes = getTokenFieldsAndNames($surveyid, true); foreach ($attributes as $attributefield => $attributedescription) { - $replFields[] = array(strtoupper($attributefield), sprintf(gT("Token attribute: %s"), $attributedescription['description'])); + $replFields[strtoupper($attributefield)] = sprintf(gT("Token attribute: %s"), $attributedescription['description']); } - $replFields[] = array('ADMINNAME', gT("Name of the survey administrator")); - $replFields[] = array('ADMINEMAIL', gT("Email address of the survey administrator")); - $replFields[] = array('SURVEYURL', gT("URL of the survey")); - $replFields[] = array('EXPIRY', gT("Survey expiration date")); + $replFields['ADMINNAME']= gT("Name of the survey administrator"); + $replFields['ADMINEMAIL']= gT("Email address of the survey administrator"); + $replFields['SURVEYURL']= gT("URL of the survey"); + $replFields['EXPIRY']= gT("Survey expiration date"); return array($replFields, false); case 'email-confirmation': - $replFields[] = array('TOKEN', gT("Token code for this participant")); - $replFields[] = array('FIRSTNAME', gT("First name from token")); - $replFields[] = array('LASTNAME', gT("Last name from token")); - $replFields[] = array('EMAIL', gT("Email from token")); - $replFields[] = array('SURVEYNAME', gT("Name of the survey")); - $replFields[] = array('SURVEYDESCRIPTION', gT("Description of the survey")); + $replFields['TOKEN']= gT("Token code for this participant"); + $replFields['FIRSTNAME']= gT("First name from token"); + $replFields['LASTNAME']= gT("Last name from token"); + $replFields['EMAIL']= gT("Email from token"); + $replFields['SURVEYNAME']= gT("Survey title"); + $replFields['SID']= gT("Survey ID"); + $replFields['SURVEYDESCRIPTION']= gT("Survey description"); $attributes = getTokenFieldsAndNames($surveyid, true); foreach ($attributes as $attributefield => $attributedescription) { - $replFields[] = array(strtoupper($attributefield), sprintf(gT("Token attribute: %s"), $attributedescription['description'])); + $replFields[strtoupper($attributefield)]= sprintf(gT("Token attribute: %s"), $attributedescription['description']); } - $replFields[] = array('ADMINNAME', gT("Name of the survey administrator")); - $replFields[] = array('ADMINEMAIL', gT("Email address of the survey administrator")); - $replFields[] = array('SURVEYURL', gT("URL of the survey")); - $replFields[] = array('EXPIRY', gT("Survey expiration date")); + $replFields['ADMINNAME']= gT("Name of the survey administrator"); + $replFields['ADMINEMAIL']= gT("Email address of the survey administrator"); + $replFields['SURVEYURL']= gT("URL of the survey"); + $replFields['EXPIRY']= gT("Survey expiration date"); // email-conf can accept insertans fields for non anonymous surveys if (isset($surveyid)) { @@ -318,25 +322,25 @@ private function _getReplacementFields($fieldtype, $surveyid) case 'editgroup_desc': // for translation case 'editquestion': // for translation case 'editquestion_help': // for translation - $replFields[] = array('TOKEN:FIRSTNAME', gT("First name from token")); - $replFields[] = array('TOKEN:LASTNAME', gT("Last name from token")); - $replFields[] = array('TOKEN:EMAIL', gT("Email from the token")); - $replFields[] = array('SID', gT("This question's survey ID number")); - $replFields[] = array('GID', gT("This question's group ID number")); - $replFields[] = array('QID', gT("This question's question ID number")); - $replFields[] = array('SGQ', gT("This question's SGQA code")); + $replFields['TOKEN:FIRSTNAME']= gT("First name from token"); + $replFields['TOKEN:LASTNAME']= gT("Last name from token"); + $replFields['TOKEN:EMAIL']= gT("Email from the token"); + $replFields['SID']= gT("This question's survey ID number"); + $replFields['GID']= gT("This question's group ID number"); + $replFields['QID']= gT("This question's question ID number"); + $replFields['SGQ']= gT("This question's SGQA code"); $attributes = getTokenFieldsAndNames($surveyid, true); foreach ($attributes as $attributefield => $attributedescription) { - $replFields[] = array('TOKEN:' . strtoupper($attributefield), sprintf(gT("Token attribute: %s"), $attributedescription['description'])); + $replFields['TOKEN:' . strtoupper($attributefield)]= sprintf(gT("Token attribute: %s"), $attributedescription['description']); } - $replFields[] = array('EXPIRY', gT("Survey expiration date")); + $replFields['EXPIRY']= gT("Survey expiration date"); case 'editanswer': return array($replFields, true); case 'assessment-text': - $replFields[] = array('TOTAL', gT("Overall assessment score")); - $replFields[] = array('PERC', gT("Assessment group score")); + $replFields['TOTAL']= gT("Overall assessment score"); + $replFields['PERC']= gT("Assessment group score"); return array($replFields, false); } } diff --git a/application/controllers/admin/questiongroups.php b/application/controllers/admin/questiongroups.php index c8efc21268f..50c74af9d24 100644 --- a/application/controllers/admin/questiongroups.php +++ b/application/controllers/admin/questiongroups.php @@ -209,6 +209,7 @@ public function insert($surveyid) $oGroup=new QuestionGroup; $oGroup->sid=$surveyid; if(isset($newGroupID)){ + switchMSSQLIdentityInsert('groups',true); $oGroup->gid=$newGroupID; } $oGroup->group_name = Yii::app()->request->getPost('group_name_' . $sLanguage,""); @@ -224,6 +225,10 @@ public function insert($surveyid) if(!isset($newGroupID)){ $newGroupID=$oGroup->gid; } + else + { + switchMSSQLIdentityInsert('groups',true); + } }else{ Yii::app()->setFlashMessage(CHtml::errorSummary($oGroup),'error'); } diff --git a/application/controllers/admin/questions.php b/application/controllers/admin/questions.php index 6ee5c384aa5..4caae9a93f5 100644 --- a/application/controllers/admin/questions.php +++ b/application/controllers/admin/questions.php @@ -897,8 +897,9 @@ public function getSubquestionRowForAllLanguages($surveyid, $gid, $qid, $codes, /** * AJAX Method to QuickAdd multiple Rows AJAX-based */ - public function getSubquestionRowQuickAdd( $surveyid, $gid, $qid, $codes, $language, $first, $scale_id, $type, $position, $assessmentvisible='' ) + public function getSubquestionRowQuickAdd( $surveyid, $gid, $qid, $codes, $language, $first, $scale_id, $type, $position=null, $assessmentvisible='' ) { + $qid = '{{quid_placeholder}}'; echo $this->getSubquestionRow( $surveyid, $gid, $qid, $codes, $language, $first, $scale_id, $type, $position, $assessmentvisible ); } /** @@ -1418,12 +1419,13 @@ public function deleteMultiple() if (is_object($oQuestion)) { - $aResults[$iQid]['question'] = viewHelper::flatEllipsizeText($oQuestion->question,true,0); - $aResults[$iQid]['result'] = $this->delete($oQuestion->sid, $oQuestion->gid, $iQid, true ); + $aResults[$iQid]['title'] = viewHelper::flatEllipsizeText($oQuestion->question,true,0); + $result = $this->delete($oQuestion->sid, $oQuestion->gid, $iQid, true ); + $aResults[$iQid]['result'] = $result['status']; } } - Yii::app()->getController()->renderPartial('/admin/survey/Question/massive_actions/_action_results', array('aResults'=>$aResults,'successLabel'=>gT('Deleted'))); + Yii::app()->getController()->renderPartial('ext.admin.survey.ListSurveysWidget.views.massive_actions._action_results', array('aResults'=>$aResults,'successLabel'=>gT('Deleted'))); } /** diff --git a/application/controllers/admin/remotecontrol.php b/application/controllers/admin/remotecontrol.php index eddd0e0a4c7..4afa2cc1305 100644 --- a/application/controllers/admin/remotecontrol.php +++ b/application/controllers/admin/remotecontrol.php @@ -66,10 +66,9 @@ public function run() } LSjsonRPCServer::handle($oHandler); } - foreach (App()->log->routes as $route) - { - $route->enabled = $route->enabled && !($route instanceOf CWebLogRoute); - } + foreach (App()->log->routes as $route) { + $route->enabled = $route->enabled && !($route instanceOf CWebLogRoute); + } exit; } else { @@ -80,15 +79,14 @@ public function run() /* @var $method ReflectionMethod */ if (substr($method->getName(),0,1) !== '_') { $list[$method->getName()] = array( - 'description' => str_replace(array("\r", "\r\n", "\n"), "
", $method->getDocComment()), - 'parameters' => $method->getParameters() + 'description' => $method->getDocComment(), + 'parameters' => $method->getParameters(), ); } } ksort($list); $aData['method'] = $RPCType; $aData['list'] = $list; - $aData['display']['menu_bars'] = false; // Hide normal menu bar $this->_renderWrappedTemplate('remotecontrol', array('index_view'), $aData); } } diff --git a/application/controllers/admin/statistics.php b/application/controllers/admin/statistics.php index 3ea2b99eeb1..a4a11bae545 100644 --- a/application/controllers/admin/statistics.php +++ b/application/controllers/admin/statistics.php @@ -114,6 +114,7 @@ public function run($surveyid = 0, $subaction = null) App()->getClientScript()->registerScriptFile( App()->getConfig('adminscripts') . 'statistics.js'); App()->getClientScript()->registerScriptFile( App()->getConfig('adminscripts') . 'json-js/json2.min.js'); + yii::app()->clientScript->registerPackage('jszip'); $aData['display']['menu_bars']['browse'] = gT("Quick statistics"); //Select public language file @@ -470,7 +471,7 @@ public function run($surveyid = 0, $subaction = null) $showtextinline = (int)Yii::app()->request->getPost('showtextinline',0); $aData['showtextinline'] = $showtextinline; $aData['usegraph'] = $usegraph; - + //Show Summary results if (isset($summary) && $summary) { @@ -492,7 +493,7 @@ public function run($surveyid = 0, $subaction = null) } } //end if -> show summary results - + $aData['sStatisticsLanguage']=$statlang; $aData['output'] = $statisticsoutput; $aData['summary'] = $summary; @@ -801,6 +802,7 @@ public function simpleStatistics($surveyid) App()->getClientScript()->registerScriptFile( App()->getConfig('adminscripts') . 'statistics.js'); App()->getClientScript()->registerScriptFile( App()->getConfig('adminscripts') . 'json-js/json2.min.js'); yii::app()->clientScript->registerPackage('jspdf'); + yii::app()->clientScript->registerPackage('jszip'); echo $this->_renderWrappedTemplate('export', 'statistics_user_view', $aData); } @@ -810,7 +812,7 @@ public function setIncompleteanswers() $sIncompleteAnswers = Yii::app()->request->getPost('state'); if (in_array($sIncompleteAnswers,array('all', 'complete', 'incomplete'))) { - Yii::app()->session['incompleteanswers']= $sIncompleteAnswers; + Yii::app()->session['incompleteanswers']= $sIncompleteAnswers; } } diff --git a/application/controllers/admin/surveypermission.php b/application/controllers/admin/surveypermission.php index ee1eeee693d..9b07dfede74 100644 --- a/application/controllers/admin/surveypermission.php +++ b/application/controllers/admin/surveypermission.php @@ -107,7 +107,7 @@ public function index($iSurveyID) foreach ($result4 as $resul4row) { - $group_names[] = $resul4row->name; + $group_names[] = \CHtml::encode($resul4row->name); } if(count($group_names) > 0) $group_names_query = implode(", ", $group_names); @@ -122,11 +122,11 @@ public function index($iSurveyID) if($PermissionRow['uid']!=Yii::app()->user->getId() || Permission::model()->hasGlobalPermission('superadmin','read')) // Can not update own security { $surveysecurity .= CHtml::form(array("admin/surveypermission/sa/set/surveyid/{$iSurveyID}"), 'post', array('style'=>"display:inline;")) - ."" - ."" - ."" - ."" - ."\n"; + .""; + $surveysecurity .= \CHtml::hiddenField('action','setsurveysecurity'); + $surveysecurity .= \CHtml::hiddenField('user',$PermissionRow['users_name']); + $surveysecurity .= \CHtml::hiddenField('uid',$PermissionRow['uid']); + $surveysecurity .= "\n"; } } if(Permission::model()->hasSurveyPermission($iSurveyID,'surveysecurity','delete')) @@ -143,7 +143,7 @@ public function index($iSurveyID) } $surveysecurity .= "\n"; - $surveysecurity .= "{$PermissionRow['users_name']}\n" + $surveysecurity .= "".\CHtml::encode($PermissionRow['users_name'])."\n" . ""; if(isset($group_names) > 0) @@ -157,7 +157,7 @@ public function index($iSurveyID) unset($group_names); $surveysecurity .= "\n" - . "\n{$PermissionRow['full_name']}\n"; + . "\n".\CHtml::encode($PermissionRow['full_name'])."\n"; //Now show the permissions foreach ($aBaseSurveyPermissions as $sPKey=>$aPDetails) { @@ -492,13 +492,13 @@ function set($surveyid) $query = "select users_name from {{users}} where uid=:uid"; $resrow = Yii::app()->db->createCommand($query)->bindParam(":uid", $postuserid, PDO::PARAM_INT)->queryRow(); $sUsername=$resrow['users_name']; - $usersummary .= "

".sprintf(gT("Edit survey permissions for user %s"),"".$sUsername."")."

"; + $usersummary .= "

".sprintf(gT("Edit survey permissions for user %s"),"".\CHtml::encode($sUsername)."")."

"; } else { $resrow = UserGroup::model()->find('ugid = :ugid',array(':ugid' => $postusergroupid)); $sUsergroupName=$resrow['name']; - $usersummary .= "

".sprintf(gT("Edit survey permissions for group %s"),"".$sUsergroupName."")."

"; + $usersummary .= "

".sprintf(gT("Edit survey permissions for group %s"),"".\CHtml::encode($sUsergroupName)."")."

"; } $usersummary .= '
'; $usersummary .= "
" diff --git a/application/controllers/admin/templates.php b/application/controllers/admin/templates.php index bdd882ed198..a84867aeddc 100644 --- a/application/controllers/admin/templates.php +++ b/application/controllers/admin/templates.php @@ -26,10 +26,10 @@ class templates extends Survey_Common_Action public function runWithParams($params) { - if (!Permission::model()->hasGlobalPermission('templates','read')) - { + if (!Permission::model()->hasGlobalPermission('templates','read')){ die('No permission'); } + parent::runWithParams($params); } @@ -231,7 +231,7 @@ public function uploadfile() $oEditedTemplate = Template::model()->getTemplateConfiguration($templatename); $templatedir = $oEditedTemplate->viewPath; $screenname = returnGlobal('screenname'); - $cssfiles = $this->_initcssfiles($oEditedTemplate); + $cssfiles = $oEditedTemplate->getValidScreenFiles("css"); $basedestdir = Yii::app()->getConfig('usertemplaterootdir'); $tempdir = Yii::app()->getConfig('tempdir'); $allowedtemplateuploads=Yii::app()->getConfig('allowedtemplateuploads'); @@ -333,20 +333,23 @@ protected function _strip_ext($name) * @param string $templatename * @return void */ - public function index($editfile = 'startpage.pstpl', $screenname = 'welcome', $templatename = '') + public function index($editfile = '', $screenname = 'welcome', $templatename = '') { + + if ($templatename=='') { $templatename = Yii::app()->getConfig("defaulttemplate"); } + // This can happen if the global default template is deleted - if (!Template::checkIfTemplateExists($templatename)) - { + if (!Template::checkIfTemplateExists($templatename)){ // Redirect to the default template Yii::app()->setFlashMessage(sprintf(gT('Template %s does not exist.'),htmlspecialchars($templatename,ENT_QUOTES)),'error'); $this->getController()->redirect(array('admin/templates/sa/view/','templatename'=>'default')); } + /* Keep Bootstrap Package clean after loading template : because template can update boostrap */ - $aBootstrapPackage=Yii::app()->clientScript->packages['bootstrap']; + $aBootstrapPackage = Yii::app()->clientScript->packages['bootstrap']; $aViewUrls = $this->_initialise($templatename, $screenname, $editfile, true, true); @@ -455,7 +458,7 @@ public function templaterename() * @access public * @return void */ - public function templatecopy() + public function atemplatecopy() { if (!Permission::model()->hasGlobalPermission('templates','create')) { @@ -494,6 +497,56 @@ public function templatecopy() } } + + /** + * Function responsible to copy a template. + * + * @access public + * @return void + */ + public function templatecopy() + { + if (!Permission::model()->hasGlobalPermission('templates','create')){ + die('No permission'); + } + + $newname = sanitize_dirname(Yii::app()->request->getPost("newname")); + $copydir = sanitize_dirname(Yii::app()->request->getPost("copydir")); + $action = Yii::app()->request->getPost("action"); + + if ($newname && $copydir) { + // Copies all the files from one template directory to a new one + Yii::app()->loadHelper('admin/template'); + $newdirname = Yii::app()->getConfig('usertemplaterootdir') . "/" . $newname; + $copydirname = getTemplatePath($copydir); + $oFileHelper = new CFileHelper; + $mkdirresult = mkdir_p($newdirname); + + if ($mkdirresult == 1) { + // We just copy the while directory structure, but only the xml file + $oFileHelper->copyDirectory($copydirname,$newdirname, array('fileTypes' => array('xml'))); + $templatename = $newname; + //TemplateConfiguration::removeAllNodes($newdirname); + TemplateConfiguration::extendsConfig($copydir, $newname ); + $this->getController()->redirect(array("admin/templates/sa/view",'templatename'=>$newname)); + } + + elseif ($mkdirresult == 2) + { + Yii::app()->setFlashMessage(sprintf(gT("Directory with the name `%s` already exists - choose another name"), $newname),'error'); + $this->getController()->redirect(array("admin/templates/sa/view",'templatename'=>$copydir)); + } + else + { + Yii::app()->setFlashMessage(sprintf(gT("Unable to create directory `%s`."), $newname),'error'); + Yii::app()->setFlashMessage(gT("Please check the directory permissions.")); + $this->getController()->redirect(array("admin/templates/sa/view")); + } + }else{ + $this->getController()->redirect(array("admin/templates/sa/view")); + } + } + /** * Function responsible to delete a template. * @@ -551,10 +604,10 @@ public function delete($templatename) public function templatesavechanges() { - if (!Permission::model()->hasGlobalPermission('templates','update')) - { + if (!Permission::model()->hasGlobalPermission('templates','update')){ die('No permission'); } + if (returnGlobal('changes')) { $changedtext = returnGlobal('changes'); $changedtext = str_replace('request->getPost('templatename')); - $screenname = returnGlobal('screenname'); - $oEditedTemplate = Template::model()->getTemplateConfiguration($sTemplateName); - $aScreenFiles = $this->getValidScreenFiles($sTemplateName); - $cssfiles = $this->_initcssfiles($oEditedTemplate); - $jsfiles = $this->_getEditableJsFiles($oEditedTemplate); + $action = returnGlobal('action'); + $editfile = returnGlobal('editfile'); + $relativePathEditfile = returnGlobal('relativePathEditfile'); + $sTemplateName = Template::templateNameFilter(App()->request->getPost('templatename')); + $screenname = returnGlobal('screenname'); + $oEditedTemplate = Template::model()->getTemplateConfiguration($sTemplateName); + $aScreenFiles = $oEditedTemplate->getValidScreenFiles("view"); + $cssfiles = $oEditedTemplate->getValidScreenFiles("css"); + $jsfiles = $oEditedTemplate->getValidScreenFiles("js"); - if ($action == "templatesavechanges" && $changedtext) - { + + if ($action == "templatesavechanges" && $changedtext){ Yii::app()->loadHelper('admin/template'); $changedtext = str_replace("\r\n", "\n", $changedtext); - if ($editfile) - { + + if ($relativePathEditfile){ // Check if someone tries to submit a file other than one of the allowed filenames if ( - in_array($editfile,$aScreenFiles)===false && - in_array($editfile,$cssfiles)===false && - in_array($editfile,$jsfiles)===false - ) - { + in_array($relativePathEditfile,$aScreenFiles)===false && + in_array($relativePathEditfile,$cssfiles)===false && + in_array($relativePathEditfile,$jsfiles)===false + ){ Yii::app()->user->setFlash('error',gT('Invalid template name')); $this->getController()->redirect(array("admin/templates/sa/upload")); } - $savefilename = gettemplatefilename($sTemplateName, $editfile); - if (is_writable($savefilename)) - { - if (!$handle = fopen($savefilename, 'w')) - { + //$savefilename = $oEditedTemplate + if( !file_exists($oEditedTemplate->path.'/'.$relativePathEditfile) && !file_exists($oEditedTemplate->viewPath.$relativePathEditfile) ){ + $oEditedTemplate->extendsFile($relativePathEditfile); + } + + $savefilename = $oEditedTemplate->extendsFile($relativePathEditfile); + + if (is_writable($savefilename)){ + + if (!$handle = fopen($savefilename, 'w')){ Yii::app()->user->setFlash('error',gT('Could not open file '). $savefilename); $this->getController()->redirect(array("admin/templates/sa/upload")); } - if (!fwrite($handle, $changedtext)) - { + if (!fwrite($handle, $changedtext)){ Yii::app()->user->setFlash('error',gT('Could not write file '). $savefilename); $this->getController()->redirect(array("admin/templates/sa/upload")); } @@ -617,16 +673,15 @@ public function templatesavechanges() $oEditedTemplate->actualizeLastUpdate(); fclose($handle); - } - else - { + }else{ Yii::app()->user->setFlash('error',"The file $savefilename is not writable"); $this->getController()->redirect(array("admin/templates/sa/upload")); } } } - $this->getController()->redirect(array('admin/templates/','sa'=>'view','editfile'=>$editfile,'screenname'=>$screenname,'templatename'=>$sTemplateName)); + + $this->getController()->redirect(array('admin/templates/','sa'=>'view','editfile'=>$relativePathEditfile,'screenname'=>$screenname,'templatename'=>$sTemplateName)); } /** @@ -668,7 +723,7 @@ protected function _templatebar($screenname, $editfile, $screens, $tempdir, $tem * @param array $myoutput * @return void */ - protected function _templatesummary($templatename, $screenname, $editfile, $templates, $files, $cssfiles, $jsfiles, $otherfiles, $myoutput) + protected function _templatesummary($templatename, $screenname, $editfile, $relativePathEditfile, $templates, $files, $cssfiles, $jsfiles, $otherfiles, $myoutput) { $tempdir = Yii::app()->getConfig("tempdir"); $tempurl = Yii::app()->getConfig("tempurl"); @@ -697,20 +752,9 @@ protected function _templatesummary($templatename, $screenname, $editfile, $temp App()->getClientScript()->reset(); @fwrite($fnew, getHeader()); - - //~ foreach ($cssfiles as $cssfile) - //~ { - //~ $myoutput = str_replace($cssfile, $cssfile . "?t=$time", $myoutput); - //~ } - - - $myoutput = implode("\n", $myoutput); - - - App()->getClientScript()->registerScriptFile( App()->getConfig('generalscripts') . 'survey_runtime.js'); /* register template package : PS : use asset :) */ - Yii::app()->clientScript->registerPackage( 'survey-template' ); + Yii::app()->clientScript->registerPackage( 'survey-template-'.$templatename ); /* some needed utils script from limesurvey-public package */ App()->getClientScript()->registerScript("activateActionLink","activateActionLink();",CClientScript::POS_END);/* show the button if needed */ @@ -725,9 +769,11 @@ protected function _templatesummary($templatename, $screenname, $editfile, $temp if (Yii::app()->session['templateeditormode'] !== 'default') { $sTemplateEditorMode = Yii::app()->session['templateeditormode']; } else { - $sTemplateEditorMode = getGlobalSetting('templateeditormode', 'full'); + $sTemplateEditorMode = getGlobalSetting('templateeditormode'); } $sExtension=substr(strrchr($editfile, '.'), 1); + + // Select ACE editor mode switch ($sExtension) { case 'css':$sEditorFileType='css'; @@ -736,14 +782,18 @@ protected function _templatesummary($templatename, $screenname, $editfile, $temp break; case 'js':$sEditorFileType='javascript'; break; + case 'twig':$sEditorFileType='twig'; + break; default: $sEditorFileType='html'; break; } - $editableCssFiles = $this->_initcssfiles($oEditedTemplate, true); + $editableCssFiles = $oEditedTemplate->getValidScreenFiles("css"); $filesdir = $oEditedTemplate->filesPath; + $aData['oEditedTemplate'] = $oEditedTemplate; $aData['screenname'] = $screenname; $aData['editfile'] = $editfile; + $aData['relativePathEditfile'] = $relativePathEditfile; $aData['tempdir'] = $tempdir; $aData['templatename'] = $templatename; $aData['templates'] = $templates; @@ -762,82 +812,6 @@ protected function _templatesummary($templatename, $screenname, $editfile, $temp return $aViewUrls; } - /** - * Function that initialises file data. - * - * @access protected - * @param string $templatename - * @return string[] - */ - protected function getValidScreenFiles($templatename) - { - $aScreenFiles = array('assessment.pstpl', - 'clearall.pstpl', - 'completed.pstpl', - 'endgroup.pstpl', - 'endpage.pstpl', - 'groupdescription.pstpl', - 'load.pstpl', - 'navigator.pstpl', - 'printanswers.pstpl', - 'privacy.pstpl', - 'question.pstpl', - 'register.pstpl', - 'save.pstpl', - 'surveylist.pstpl', - 'startgroup.pstpl', - 'startpage.pstpl', - 'survey.pstpl', - 'welcome.pstpl', - 'print_survey.pstpl', - 'print_group.pstpl', - 'print_question.pstpl'); - - /// TODO : use config.xml - if (is_file(Yii::app()->getConfig('usertemplaterootdir') . '/' . $templatename . '/question_start.pstpl')) - $aScreenFiles[] = 'question_start.pstpl'; - - return $aScreenFiles; - } - - /** - * Function that initialises cssfile data. - * - * @access protected - * @param TemplateConfiguration $oEditedTemplate - * @param boolean $editable - * @return array - */ - protected function _initcssfiles(TemplateConfiguration $oEditedTemplate, $editable=false) - { - // If editable CSS files are required, and if they are defined in the template config file - if($editable && is_object($oEditedTemplate->config->files_editable->css)) - { - $aCssFiles = (array) $oEditedTemplate->config->files_editable->css->filename; - } - // Else we get all the CSS files - else - { - $aCssFiles = (array) $oEditedTemplate->config->files->css->filename; - } - return $aCssFiles; - } - - protected function _getEditableJsFiles($oEditedTemplate) - { - // If editable JS files are defined in the template config file - if(is_object($oEditedTemplate->config->files_editable->js)) - { - $aJsFiles = (array) $oEditedTemplate->config->files_editable->js->filename; - } - // Else we get all the JS files - else - { - $aJsFiles = (array) $oEditedTemplate->config->files->js->filename; - } - return $aJsFiles; - } - /** * Function that initialises all data and call other functions to load default view. * @@ -870,8 +844,8 @@ protected function _initialise($templatename, $screenname, $editfile, $showsumma //App()->getClientScript()->reset(); Yii::app()->loadHelper('surveytranslator'); Yii::app()->loadHelper('admin/template'); - $files = $this->getValidScreenFiles($templatename); - $cssfiles = $this->_initcssfiles($oEditedTemplate); + $files = $oEditedTemplate->getValidScreenFiles("view"); + $cssfiles = $oEditedTemplate->getValidScreenFiles("css"); // Standard Support Files @@ -882,115 +856,37 @@ protected function _initialise($templatename, $screenname, $editfile, $showsumma // Standard screens // Only these may be viewed $screens=array(); - $screens['surveylist'] = gT('Survey List Page','unescaped'); - $screens['welcome'] = gT('Welcome Page','unescaped'); - $screens['question'] = gT('Question Page','unescaped'); - $screens['completed'] = gT('Completed Page','unescaped'); - $screens['clearall'] = gT('Clear All Page','unescaped'); - $screens['register'] = gT('Register Page','unescaped'); - $screens['load'] = gT('Load Page','unescaped'); - $screens['save'] = gT('Save Page','unescaped'); - $screens['printanswers'] = gT('Print answers page','unescaped'); - $screens['printablesurvey'] = gT('Printable survey page','unescaped'); - - /* pstpl file list */ - /* used for call AND for pstl editable files list */ - $SurveyList = array('startpage.pstpl', - 'surveylist.pstpl', - 'endpage.pstpl' - ); - $Welcome = array('startpage.pstpl', - 'welcome.pstpl', - 'privacy.pstpl', - 'navigator.pstpl', - 'endpage.pstpl' - ); - /* Not used : data updated during rendering */ - $Question = array('startpage.pstpl', - 'survey.pstpl', - 'startgroup.pstpl', - 'groupdescription.pstpl', - 'question.pstpl', - 'endgroup.pstpl', - 'navigator.pstpl', - 'endpage.pstpl' - ); - $CompletedTemplate = array( - 'startpage.pstpl', - 'assessment.pstpl', - 'completed.pstpl', - 'endpage.pstpl' - ); - /* Not used */ - $Clearall = array('startpage.pstpl', - 'clearall.pstpl', - 'endpage.pstpl' - ); - /* Not used */ - $Register = array('startpage.pstpl', - 'survey.pstpl', - 'register.pstpl', - 'endpage.pstpl' - ); - /* Not used */ - $Save = array('startpage.pstpl', - 'save.pstpl', - 'endpage.pstpl' - ); - /* Not used */ - $Load = array('startpage.pstpl', - 'load.pstpl', - 'endpage.pstpl' - ); - /* Not used */ - $printtemplate = array('startpage.pstpl', - 'printanswers.pstpl', - 'endpage.pstpl' - ); - /* Not used */ - $printablesurveytemplate = array('print_survey.pstpl', - 'print_group.pstpl', - 'print_question.pstpl' - ); + + + $screens['welcome'] = gT('Welcome Page','unescaped'); // first page* + $screens['question'] = gT('Question Page','unescaped'); // main + $screens['completed'] = gT('Completed Page','unescaped'); // submit? + $screens['clearall'] = gT('Clear All Page','unescaped'); + $screens['load'] = gT('Load Page','unescaped'); + $screens['save'] = gT('Save Page','unescaped'); + $screens['surveylist'] = gT('Survey List Page','unescaped'); + $screens['error'] = gT('Error','unescaped'); + $screens['assessments'] = gT('Assessments','unescaped'); + $file_version = "LimeSurvey template editor " . Yii::app()->getConfig('versionnumber'); + Yii::app()->session['s_lang'] = Yii::app()->session['adminlang']; + $templatename = sanitize_dirname($templatename); + // Checks if screen name is in the list of allowed screen names if (!isset($screens[$screenname])) { Yii::app()->user->setFlash('error',gT('Invalid screen name')); $this->getController()->redirect(array("admin/templates/sa/upload")); } - if (is_file(Yii::app()->getConfig('usertemplaterootdir') . DIRECTORY_SEPARATOR . $templatename . DIRECTORY_SEPARATOR.'question_start.pstpl')) { - $files[] = 'question_start.pstpl'; - $Question[] = 'question_start.pstpl'; - } /* See if we found the file to be edited inside template */ /* @todo must control if is updatable : in updatable file OR is a view */ /* Actually allow to update any file exemple css/template-core.css */ + $oEditedTemplate = Template::model()->getTemplateConfiguration($templatename); - if (file_exists(Yii::app()->getConfig('usertemplaterootdir') . DIRECTORY_SEPARATOR . $templatename. DIRECTORY_SEPARATOR.$editfile)){ - /* the file seems a simple file */ - $sEditFile=realpath(Yii::app()->getConfig('usertemplaterootdir') . DIRECTORY_SEPARATOR . $templatename. DIRECTORY_SEPARATOR.$editfile); - }elseif (file_exists($oEditedTemplate->viewPath. DIRECTORY_SEPARATOR.$editfile)){ - /* the file seems a view file */ - $sEditFile=realpath($oEditedTemplate->viewPath. DIRECTORY_SEPARATOR.$editfile); - }else{ - /* the file seems to be invalid */ - $sEditFile=''; - } - // Make sure file is within the template path - if (strpos($sEditFile,realpath(Yii::app()->getConfig('usertemplaterootdir') . DIRECTORY_SEPARATOR . $templatename))===false) - { - $editfile='startpage.pstpl'; - } - $extension = substr(strrchr($editfile, "."), 1); - $highlighter = 'html'; - if ($extension == 'css' || $extension == 'js') - { - $highlighter = $extension; - } + // @TODO: Proper language code conversion $sLanguageCode = 'en'; $availableeditorlanguages = array('bg', 'cs', 'de', 'dk', 'en', 'eo', 'es', 'fi', 'fr', 'hr', 'it', 'ja', 'mk', 'nl', 'pl', 'pt', 'ru', 'sk', 'zh'); @@ -1027,10 +923,14 @@ protected function _initialise($templatename, $screenname, $editfile, $showsumma $thissurvey['tokenanswerspersistence'] = "Y"; $thissurvey['templatedir'] = $templatename; $thissurvey['format'] = "G"; - $thissurvey['surveyls_url'] = "http://www.limesurvey.org/"; + $thissurvey['surveyls_url'] = "https://www.limesurvey.org/"; $thissurvey['surveyls_urldescription'] = gT("Some URL description"); $thissurvey['usecaptcha'] = "A"; - $percentcomplete = makegraph(6, 10); + $thissurvey['showprogress'] = true; + $thissurvey['aNavigator']['show'] = true; + $thissurvey['aNavigator']['aMoveNext']['show'] = true; + $thissurvey['aNavigator']['aMovePrev']['show'] = true; + $percentcomplete = 0; //makegraph(6, 10); $groupname = gT("Group 1: The first lot of questions"); $groupdescription = gT("This group description is fairly vacuous, but quite important."); @@ -1056,88 +956,18 @@ protected function _initialise($templatename, $screenname, $editfile, $showsumma $templateurl = getTemplateURL($templatename); // Save these variables in an array - $aData['thissurvey'] = $thissurvey; - $aData['percentcomplete'] = $percentcomplete; - $aData['groupname'] = $groupname; - $aData['groupdescription'] = $groupdescription; - $aData['navigator'] = $navigator; - $aData['help'] = gT("This is some help text."); - $aData['surveyformat'] = $surveyformat; - $aData['totalquestions'] = $totalquestions; - $aData['completed'] = $completed; - $aData['notanswered'] = $notanswered; - $aData['privacy'] = $privacy; - $aData['surveyid'] = $surveyid; - $aData['sid'] = $surveyid; - $aData['token'] = $token; - $aData['assessments'] = $assessments; - $aData['printoutput'] = $printoutput; - $aData['templatedir'] = $templatedir; - $aData['templateurl'] = $templateurl; - $aData['templatename'] = $templatename; - $aData['screenname'] = $screenname; - $aData['editfile'] = $editfile; - /* always here, even if hidden or in navigator , for button : if nopt in navigator : must be hidden by default */ - $aGlobalReplacements = array( - 'SAVE_LINKS' => $this->getController()->renderPartial("/survey/system/actionLink/saveSave",array( - 'submit'=>'', // Don't do the action, just for display - 'class'=>'ls-link-action ls-link-saveall' - ),true), - 'CLEARALL_LINKS' => $this->getController()->renderPartial("/survey/system/actionLink/clearAll",array( - 'class'=>'ls-link-action ls-link-clearall', - 'submit'=>'', - 'confirm'=>'', - ),true), - 'SAVE' => $this->getController()->renderPartial("/survey/system/actionButton/saveSave",array( - 'value'=>'saveall', - 'name'=>'saveall', - 'class'=>'ls-saveaction ls-saveall' - ),true), - 'CLEARALL' => $this->getController()->renderPartial("/survey/system/actionButton/clearAll",array( - 'value'=>'clearall', - 'name'=>'clearall', - 'class'=>'ls-clearaction ls-clearall', - 'confirmedby'=>'confirm-clearall', - 'confirmvalue'=>'confirm', - ),true), - ); - $myoutput[] = ""; + $aData['thissurvey'] = $thissurvey; + + $aGlobalReplacements = array(); + $myoutput[] = ""; + + $files = $oEditedTemplate->getValidScreenFiles("view", $screenname); + $sLayoutFile = $oEditedTemplate->getLayoutForScreen($screenname); switch ($screenname) { - case 'surveylist': - $aSurveyList = array( - 'publicSurveys' => Survey::model()->active()->open()->public()->with('languagesettings')->findAll(), - 'futureSurveys' => Survey::model()->active()->registration()->public()->with('languagesettings')->findAll(), - ); - $aReplacementSurveyList = array( - "SURVEYCONTACT" => sprintf(gT("Please contact %s ( %s ) for further assistance."), Yii::app()->getConfig("siteadminname"), Yii::app()->getConfig("siteadminemail")), - "SURVEYLISTHEADING" => gT("The following surveys are available:"), - "SURVEYLIST" => $this->getController()->renderPartial('/admin/templates/templateeditor_surveylist_view', $aSurveyList, true), - ); - //$aData['surveylist'] = $aSurveyListTexts; - $aData['aReplacements'] = array_merge($aGlobalReplacements,$aReplacementSurveyList); - $myoutput[] = ""; - $files=$SurveyList; - foreach ($files as $qs) - { - $myoutput = array_merge($myoutput, doreplacement($oEditedTemplate->viewPath . "/$qs", $aData, $oEditedTemplate)); - } - break; case 'question': - $files=$Question; - $myoutput[] = $this->getController()->renderPartial('/admin/templates/templateeditor_question_meta_view', array(), true); - - $myoutput = array_merge($myoutput, doreplacement($oEditedTemplate->viewPath . "/startpage.pstpl", $aData, $oEditedTemplate)); - $myoutput = array_merge($myoutput, doreplacement($oEditedTemplate->viewPath . "/survey.pstpl", $aData, $oEditedTemplate)); - - // Normally output by survey_runtime - $myoutput = array_merge($myoutput, array('
')); - - $myoutput = array_merge($myoutput, doreplacement($oEditedTemplate->viewPath . "/startgroup.pstpl", $aData, $oEditedTemplate)); - $myoutput = array_merge($myoutput, doreplacement($oEditedTemplate->viewPath . "/groupdescription.pstpl", $aData, $oEditedTemplate)); - $aReplacements = array( 'QUESTION_TEXT' => gT("How many roads must a man walk down?"), 'QUESTION_CODE' => 'Q1 ', @@ -1153,58 +983,42 @@ protected function _initialise($templatename, $screenname, $editfile, $showsumma 'vtip'=>gT('Hint when response is valid') ), true), ); - $aReplacements['ANSWER'] = $this->getController()->renderPartial('/admin/templates/templateeditor_question_answer_view', array(), true); - $aData['aReplacements'] = array_merge($aGlobalReplacements,$aReplacements); - $myoutput = array_merge($myoutput, doreplacement($oEditedTemplate->viewPath . "/question.pstpl", $aData, $oEditedTemplate)); - $aReplacements = array( - 'QUESTION_TEXT' => gT('Please explain something in detail:'), - 'QUESTION_CODE' => 'Q2 ', - 'QUESTIONHELP' => '', - 'QUESTION_ESSENTIALS' => 'id="question2"', - 'QUESTION_CLASS' => 'text-long input-error', - 'QUESTION_NUMBER' => '2', - 'QUESTION_VALID_MESSAGE'=>$this->getController()->renderPartial('//survey/questions/question_help/em-tip',array( - 'coreId'=>"vmsg_4496_num_answers", - 'coreClass'=>"em-tip text-danger",// Unsure for this one, text-danger is set in JS only - 'vtip'=>gT('Hint when response is not valid') - ), true), - ); - $aReplacements['ANSWER'] = $this->getController()->renderPartial('/admin/templates/templateeditor_question_answer_view', array('alt' => true), true); + $aReplacements['ANSWER'] = $this->getController()->renderPartial('/admin/templates/templateeditor_question_answer_view', array(), true); $aData['aReplacements'] = array_merge($aGlobalReplacements,$aReplacements); - $myoutput = array_merge($myoutput, doreplacement($oEditedTemplate->viewPath . "/question.pstpl", $aData, $oEditedTemplate)); - - $myoutput = array_merge($myoutput, doreplacement($oEditedTemplate->viewPath . "/endgroup.pstpl", $aData, $oEditedTemplate)); - // Normally output by survey_runtime - $myoutput = array_merge($myoutput, array('
')); - $sMovePrev = App()->getController()->renderPartial("/survey/system/actionButton/movePrevious",array('value'=>"moveprev",'class'=>"ls-move-btn ls-move-previous-btn"),true); - $sMoveNext = App()->getController()->renderPartial("/survey/system/actionButton/moveNext",array('value'=>"movenext",'class'=>"ls-move-btn ls-move-next-btn"),true); - - $aData['aReplacements'] = array_merge($aGlobalReplacements,array( - 'MOVEPREVBUTTON' => $sMovePrev, - 'MOVENEXTBUTTON' => $sMoveNext, - 'NAVIGATOR' => "$sMovePrev $sMoveNext", - )); - $myoutput = array_merge($myoutput, doreplacement($oEditedTemplate->viewPath . "/navigator.pstpl", $aData, $oEditedTemplate)); - $myoutput = array_merge($myoutput, doreplacement($oEditedTemplate->viewPath . "/endpage.pstpl", $aData, $oEditedTemplate)); - break; - - case 'welcome': - $sMoveNext = App()->getController()->renderPartial("/survey/system/actionButton/moveNext",array('value'=>"movenext",'class'=>"ls-move-btn ls-move-next-btn"),true); - $aData['aReplacements'] = array_merge($aGlobalReplacements,array( - 'MOVEPREVBUTTON' => '', - 'MOVENEXTBUTTON' => $sMoveNext, - 'NAVIGATOR' => "$sMoveNext", - )); - $files=$Welcome ; - foreach ($files as $qs) { - $myoutput = array_merge($myoutput, doreplacement($oEditedTemplate->viewPath . "/$qs", $aData, $oEditedTemplate)); - } + // Group Datas + $thissurvey['aGroups'][1]["name"] = $groupname; + $thissurvey['aGroups'][1]["showdescription"] = true; + $thissurvey['aGroups'][1]["description"] = $groupdescription; + + // Question 1 Datas + $thissurvey['aGroups'][1]["aQuestions"][1]["qid"] = "1"; + $thissurvey['aGroups'][1]["aQuestions"][1]["code"] = 'Q1 '; + $thissurvey['aGroups'][1]["aQuestions"][1]["text"] = gT("How many roads must a man walk down?"); + $thissurvey['aGroups'][1]["aQuestions"][1]["mandatory"] = true; + $thissurvey['aGroups'][1]["aQuestions"][1]["valid_message"] = '
Choose one of the following answers
'; + $thissurvey['aGroups'][1]["aQuestions"][1]["answer"] = $this->getController()->renderPartial('/admin/templates/templateeditor_question_answer_view', array(), true); + $thissurvey['aGroups'][1]["aQuestions"][1]["help"]["show"] = true; + $thissurvey['aGroups'][1]["aQuestions"][1]["help"]["text"] = "This is some helpful text."; + + // Question 2 Datas + $thissurvey['aGroups'][1]["aQuestions"][2]["qid"] = "1"; + $thissurvey['aGroups'][1]["aQuestions"][2]["code"] = 'Q2 '; + $thissurvey['aGroups'][1]["aQuestions"][2]["text"] = gT("Please explain something in detail:"); + $thissurvey['aGroups'][1]["aQuestions"][2]["mandatory"] = false; + $thissurvey['aGroups'][1]["aQuestions"][2]["valid_message"] = '
Hint when response is not valid
'; + $thissurvey['aGroups'][1]["aQuestions"][2]["answer"] = $this->getController()->renderPartial('/admin/templates/templateeditor_question_answer_view', array('alt' => true), true); + $thissurvey['aGroups'][1]["aQuestions"][2]["help"]["show"] = true; + $thissurvey['aGroups'][1]["aQuestions"][2]["help"]["text"] = "This is some helpful text."; + + // This is just to prevent getAllClasses to retreive .ls-hidden CSS class + $thissurvey['aGroups'][1]["aQuestions"][1]['templateeditor'] = true; + $thissurvey['aGroups'][1]["aQuestions"][2]['templateeditor'] = true; break; case 'register': - $files=$Register; + $sLayoutFile = ""; // TODO $myoutput[] = templatereplace(file_get_contents("$templatedir/startpage.pstpl"), array(), $aData, 'Unspecified', false, NULL, array(), false, $oEditedTemplate); $aData = array( @@ -1226,61 +1040,27 @@ protected function _initialise($templatename, $screenname, $editfile, $showsumma $myoutput[] = "\n"; break; - case 'save': - $files=$Save; - $aData['aReplacements'] = $aGlobalReplacements; - $myoutput[] = templatereplace(file_get_contents("$templatedir/startpage.pstpl"), array(), $aData, 'Unspecified', false, NULL, array(), false, $oEditedTemplate); - $aData['aReplacements']['SAVEHEADING'] = App()->getController()->renderPartial("/survey/frontpage/saveForm/heading",array(),true); - $aData['aReplacements']['SAVEMESSAGE'] = App()->getController()->renderPartial("/survey/frontpage/saveForm/message",array(),true); - $aData['aReplacements']['SAVEALERT'] = App()->getController()->renderPartial("/survey/frontpage/saveForm/anonymized",array(),true); - $aData['aReplacements']['SAVEERROR'] = ""; - $saveForm = CHtml::beginForm(array("/survey/index","sid"=>$surveyid), 'post',array('id'=>'form-save')); - $saveForm .= App()->getController()->renderPartial("/survey/frontpage/saveForm/form",array('captcha'=>false),true); - $saveForm .= CHtml::endForm(); - $aData['aReplacements']['SAVEFORM'] = $saveForm; - $myoutput = array_merge($myoutput, doreplacement($oEditedTemplate->viewPath . "/save.pstpl", $aData, $oEditedTemplate)); - $myoutput[] = templatereplace(file_get_contents("$templatedir/endpage.pstpl"), array(), $aData, 'Unspecified', false, NULL, array(), false, $oEditedTemplate); - $myoutput[] = "\n"; + case 'completed': + $thissurvey['aCompleted']['showDefault'] = true; + $thissurvey['aCompleted']['aPrintAnswers']['show'] = true; + $thissurvey['aCompleted']['aPublicStatistics']['show'] = true; break; - case 'load': - $files=$Load; - $aData['aReplacements'] = $aGlobalReplacements; - $myoutput[] = templatereplace(file_get_contents("$templatedir/startpage.pstpl"), array(),$aData['aReplacements'], 'Unspecified', false, NULL, array(), false, $oEditedTemplate); - $aData['aReplacements']['LOADHEADING'] = App()->getController()->renderPartial("/survey/frontpage/loadForm/heading",array(),true); - $aData['aReplacements']['LOADMESSAGE'] = App()->getController()->renderPartial("/survey/frontpage/loadForm/message",array(),true); - $aData['aReplacements']['LOADERROR'] = ""; - $loadForm = CHtml::beginForm(array("/survey/index","sid"=>$surveyid), 'post',array('id'=>'form-load')); - $loadForm .= App()->getController()->renderPartial("/survey/frontpage/loadForm/form",array('captcha'=>false),true); - $loadForm .= CHtml::endForm(); - $aData['aReplacements']['LOADFORM'] = $loadForm; - $myoutput = array_merge($myoutput, doreplacement($oEditedTemplate->viewPath . "/load.pstpl", $aData, $oEditedTemplate)); - $myoutput[] = templatereplace(file_get_contents("$templatedir/endpage.pstpl"), $aData['aReplacements'], $aData['aReplacements'], 'Unspecified', false, NULL, array(), false, $oEditedTemplate); - - $myoutput[] = "\n"; - break; + case 'assessments': + $thissurvey['aAssessments']['show'] = true; - case 'clearall': - $files=$Clearall; - $aData['aReplacements'] = $aGlobalReplacements; - $myoutput[] = templatereplace(file_get_contents("$templatedir/startpage.pstpl"), array(), $aData, 'Unspecified', false, NULL, array(), false, $oEditedTemplate); - $myoutput[] = templatereplace(file_get_contents("$templatedir/clearall.pstpl"), array(), $aData, 'Unspecified', false, NULL, array(), false, $oEditedTemplate); - $myoutput[] = templatereplace(file_get_contents("$templatedir/endpage.pstpl"), array(), $aData, 'Unspecified', false, NULL, array(), false, $oEditedTemplate); - $myoutput[] = "\n"; + // Datas for assessments + $thissurvey['aAssessments']["datas"]["total"][0] = array("name" => gT("Welcome to the Assessment"), "min" => "0", "max" => "3", "message" => gT("You got {TOTAL} points out of 3 possible points.")); + $thissurvey['aAssessments']["datas"]["total"]["show"] = true; + $thissurvey['aAssessments']["datas"]["subtotal"]["show"] = true; + $thissurvey['aAssessments']["datas"]["subtotal"]["datas"][2] = 3; + $thissurvey['aAssessments']["datas"]["subtotal_score"][1] = 3; + $thissurvey['aAssessments']["datas"]["total_score"] = 3; break; - case 'completed': - $aData['aReplacements'] = $aGlobalReplacements; - $files=$CompletedTemplate; - $myoutput[] = ""; - foreach ($files as $qs) - { - $myoutput = array_merge($myoutput, doreplacement($oEditedTemplate->viewPath . "/$qs", $aData, $oEditedTemplate)); - } - break; case 'printablesurvey': + $sLayoutFile = "TODO"; $aData['aReplacements'] = $aGlobalReplacements; - $files=$printablesurveytemplate; $questionoutput = array(); foreach (file("$templatedir/print_question.pstpl") as $op) { @@ -1320,43 +1100,35 @@ protected function _initialise($templatename, $screenname, $editfile, $showsumma break; case 'printanswers': - $files=$printtemplate; + $sLayoutFile = "TODO"; $myoutput[] = templatereplace(file_get_contents("$templatedir/startpage.pstpl"), array(), $aData, 'Unspecified', false, NULL, array(), false, $oEditedTemplate); $myoutput[] = templatereplace(file_get_contents("$templatedir/printanswers.pstpl"), array('ANSWERTABLE' => $printoutput), $aData, 'Unspecified', false, NULL, array(), false, $oEditedTemplate); $myoutput[] = templatereplace(file_get_contents("$templatedir/endpage.pstpl"), array(), $aData, 'Unspecified', false, NULL, array(), false, $oEditedTemplate); $myoutput[] = "\n"; break; + + case 'error': + $thissurvey['aError']['title'] = gT("Error"); + $thissurvey['aError']['message'] = gT("This is an error message example"); + break; } - $myoutput[] = ""; - $jsfiles = $this->_getEditableJsFiles($oEditedTemplate); - $aCssAndJsfiles = array_merge($cssfiles,$jsfiles ) ; + $myoutput = Yii::app()->twigRenderer->renderTemplateForTemplateEditor( $sLayoutFile,array('aSurveyInfo'=>$thissurvey), $oEditedTemplate); - if (is_array($files)) - { - $match = 0; - if (in_array($editfile,$files) || in_array($editfile,$aCssAndJsfiles)) - { - $match=1; - } + $jsfiles = $oEditedTemplate->getValidScreenFiles("js"); + $aCssAndJsfiles = array_merge($cssfiles,$jsfiles ) ; - if ($match == 0) - { - if (count($files) > 0) - { - $editfile = $files[0]; - } - else - { - $editfile = ""; - } - } + // XML Behaviour: if only one file, then $files is just a string + if (!is_array($files) && is_string($files)){ + $files = array(0=>$files); } + // Get list of 'otherfiles' // We can't use $oTemplate->otherFiles, because of retrocompatibility with 2.06 template and the big mess of it mixing files $filesdir = ($oEditedTemplate->filesPath!='')?$oEditedTemplate->filesPath:$templatedir . '../files'; + $otherfiles = array(); if ( file_exists($filesdir) && $handle = opendir($filesdir)) { @@ -1372,6 +1144,14 @@ protected function _initialise($templatename, $screenname, $editfile, $showsumma closedir($handle); } + $editfile = (empty($editfile))?$sLayoutFile:$editfile; + $sEditfile = $oEditedTemplate->getFilePathForEdition($editfile, array_merge($files, $aCssAndJsfiles)); + + $extension = substr(strrchr($sEditfile, "."), 1); + $highlighter = 'html'; + if ($extension == 'css' || $extension == 'js'){ + $highlighter = $extension; + } $aData['codelanguage'] = $sLanguageCode; $aData['highlighter'] = $highlighter; @@ -1379,7 +1159,7 @@ protected function _initialise($templatename, $screenname, $editfile, $showsumma $aData['templatename'] = $templatename; $aData['templateapiversion'] = $oEditedTemplate->getApiVersion(); $aData['templates'] = $aAllTemplates; - $aData['editfile'] = $editfile; + $aData['editfile'] = $sEditfile; $aData['screenname'] = $screenname; $aData['tempdir'] = Yii::app()->getConfig('tempdir'); $aData['usertemplaterootdir'] = Yii::app()->getConfig('usertemplaterootdir'); @@ -1388,8 +1168,9 @@ protected function _initialise($templatename, $screenname, $editfile, $showsumma if ($showsummary) { //$aCssfileseditable = (array) $oEditedTemplate->config->files_editable->css->filename; - $aViewUrls = array_merge($aViewUrls, $this->_templatesummary($templatename, $screenname, $editfile, $aAllTemplates, $files, $cssfiles, $jsfiles, $otherfiles, $myoutput)); + $aViewUrls = array_merge($aViewUrls, $this->_templatesummary($templatename, $screenname, $sEditfile, $editfile, $aAllTemplates, $files, $cssfiles, $jsfiles, $otherfiles, $myoutput)); } + App()->getClientScript()->registerScriptFile( App()->getConfig('adminscripts') . 'admin_core.js'); return $aViewUrls; } @@ -1403,6 +1184,7 @@ protected function _initialise($templatename, $screenname, $editfile, $showsumma */ protected function _renderWrappedTemplate($sAction = 'templates', $aViewUrls = array(), $aData = array()) { + //var_dump($aViewUrls); //$aData['display']['menu_bars'] = false; parent::_renderWrappedTemplate($sAction, $aViewUrls, $aData); } diff --git a/application/controllers/admin/tokens.php b/application/controllers/admin/tokens.php index 2408baa62a2..b2af0d96d8c 100644 --- a/application/controllers/admin/tokens.php +++ b/application/controllers/admin/tokens.php @@ -116,7 +116,7 @@ public function bounceprocessing($iSurveyId) $hostencryption = strtoupper($thissurvey['bounceaccountencryption']); } - list($hostname, $port) = explode(':', $hostname); // deprecated: split(':', $hostname); + @list($hostname, $port) = explode(':', $hostname); if (empty($port)) { @@ -1509,12 +1509,12 @@ public function email($iSurveyId, $tokenids = null) } } $tokenoutput .= htmlspecialchars(ReplaceFields("{$emrow['tid']}: {FIRSTNAME} {LASTNAME} ({EMAIL})", $fieldsarray)). "
\n"; - if (Yii::app()->getConfig("emailsmtpdebug") == 2) + if (Yii::app()->getConfig("emailsmtpdebug") > 1) { $tokenoutput .= $maildebug; } } else { - $tokenoutput .= htmlspecialchars(ReplaceFields(gT("Email to {FIRSTNAME} {LASTNAME} ({EMAIL}) failed. Error message:",'unescaped') . " " . $maildebug , $fieldsarray)). "
"; + $tokenoutput .= sprintf(htmlspecialchars(ReplaceFields("{$emrow['tid']}: {FIRSTNAME} {LASTNAME} ({EMAIL}). Error message: %s", $fieldsarray)),$maildebug) . "
\n"; $bSendError=true; } } diff --git a/application/controllers/admin/translate.php b/application/controllers/admin/translate.php index 337a2abb37f..eaf157dc81f 100644 --- a/application/controllers/admin/translate.php +++ b/application/controllers/admin/translate.php @@ -138,105 +138,97 @@ private function _translateSave($iSurveyID, $tolang, $baselang, $tab_names) */ private function _displayUntranslatedFields($iSurveyID, $tolang, $baselang, $tab_names, $baselangdesc, $tolangdesc) { + // Define aData $aData['surveyid'] = $iSurveyID; $aData['tab_names'] = $tab_names; $aData['tolang'] = $tolang; $aData['baselang'] = $baselang; + $aData['baselangdesc'] = $baselangdesc; + $aData['tolangdesc'] = $tolangdesc; - foreach( $tab_names as $type ) - { - $aData['amTypeOptions'][] = $this->setupTranslateFields($type); - } - + //This is for the tab navbar + $aData['amTypeOptions'] = array_map(array($this,'setupTranslateFields'),$tab_names); $aViewUrls['translateformheader_view'][] = $aData; + + //Set the output as empty $aViewUrls['output'] = ''; // Define content of each tab - $count = 0; - foreach( $tab_names as $type ) + + //iterate through all tabs + $allTabNames = count($tab_names); + for($i=0;$i<$allTabNames;$i++ ) { + $type= $tab_names[$i]; $amTypeOptions = $this->setupTranslateFields($type); - $type2 = $amTypeOptions["associated"]; + // Setup form + $evenRow = FALSE; //deprecated => using css + $all_fields_empty = TRUE; + + $resultbase = $this->query($type, "querybase", $iSurveyID, $tolang, $baselang); + $resultto = $this->query($type, "queryto", $iSurveyID, $tolang, $baselang); + + $type2 = $amTypeOptions["associated"]; $associated = FALSE; if ( ! empty($type2) ) { $associated = TRUE; + //get type otions again again $amTypeOptions2 = $this->setupTranslateFields($type2); $resultbase2 = $this->query($type, "querybase", $iSurveyID, $tolang, $baselang); $resultto2 = $this->query($type, "queryto", $iSurveyID, $tolang, $baselang); } - // Setup form - // start a counter in order to number the input fields for each record - $i = 0; - $evenRow = FALSE; - $all_fields_empty = TRUE; - $resultbase = $this->query($type, "querybase", $iSurveyID, $tolang, $baselang); - $resultto = $this->query($type, "queryto", $iSurveyID, $tolang, $baselang); - $aData['baselangdesc'] = $baselangdesc; - $aData['tolangdesc'] = $tolangdesc; $aData['type'] = $type; - - if($count<1) - { - $aData['activeTab']=true; - $count++; - } - else - { - $aData['activeTab']=false; - } - + $aData['activeTab']=($i<1); $aData['translateTabs'] = $this->displayTranslateFieldsHeader($baselangdesc, $tolangdesc, $type); $aViewUrls['output'] .= $this->getController()->renderPartial("/admin/translate/translatetabs_view", $aData, true); - foreach ( $resultbase as $rowfrom ) + + for($j=0;$j 0 ) - { - $all_fields_empty = FALSE; - } - $aData['textfrom'] = $textfrom; - $aData['textfrom2'] = $textfrom2; - $aData['textto'] = $textto; - $aData['textto2'] = $textto2; - $aData['rowfrom'] = $rowfrom; - $aData['rowfrom2'] = $resultbase2; - $aData['evenRow'] = $evenRow; - $aData['gid'] = $gid; - $aData['qid'] = $qid; - $aData['amTypeOptions'] = $amTypeOptions; - $aData['amTypeOptions2'] = $amTypeOptions2; - $aData['i'] = $i; - $aData['type'] = $type; - $aData['type2'] = $type2; - $aData['associated'] = $associated; - - $evenRow = !($evenRow); + $all_fields_empty = !( $textform_length > 0 ); + + $aData = $aData + array( + 'textfrom' => $this->_cleanup($textfrom, array()), + 'textfrom2' => $this->_cleanup($textfrom2, array()), + 'textto' => $this->_cleanup($textto, array()), + 'textto2' => $this->_cleanup($textto2, array()), + 'rowfrom' => $rowfrom, + 'rowfrom2' => $resultbase2, + 'evenRow' => $evenRow, + 'gid' => $gid, + 'qid' => $qid, + 'amTypeOptions' => $amTypeOptions, + 'amTypeOptions2' => $amTypeOptions2, + 'i' => $j, + 'type' => $type, + 'type2' => $type2, + 'associated' => $associated, + ); $aData['translateFields'] = $this->displayTranslateFields($iSurveyID, $gid, $qid, $type, - $amTypeOptions, $baselangdesc, $tolangdesc, $textfrom, $textto, $i, $rowfrom, $evenRow); + $amTypeOptions, $baselangdesc, $tolangdesc, $textfrom, $textto, $j, $rowfrom, $evenRow); if ($associated && strlen(trim((string)$textfrom2)) > 0) { - $evenRow = !($evenRow); $aData['translateFields'] .= $this->displayTranslateFields($iSurveyID, $gid, $qid, $type2, - $amTypeOptions2, $baselangdesc, $tolangdesc, $textfrom2, $textto2, $i, $resultbase2[$i], $evenRow); + $amTypeOptions2, $baselangdesc, $tolangdesc, $textfrom2, $textto2, $j, $resultbase2[$j], $evenRow); } $aViewUrls['output'] .= $this->getController()->renderPartial("/admin/translate/translatefields_view", $aData, true); - - $i++; } // end while $aData['all_fields_empty'] = $all_fields_empty; @@ -244,10 +236,9 @@ private function _displayUntranslatedFields($iSurveyID, $tolang, $baselang, $tab $aData['bReadOnly']=!Permission::model()->hasSurveyPermission($iSurveyID, 'translations', 'update'); $aViewUrls['output'] .= $this->getController()->renderPartial("/admin/translate/translatefieldsfooter_view", $aData, true); } // end foreach - // Submit buttonrender $aViewUrls['translatefooter_view'][] = $aData; - + // var_dump($aViewUrls); return $aViewUrls; } @@ -372,11 +363,6 @@ private function _getLanguageList($iSurveyID, $tolang) 'onchange' => "window.open(this.options[this.selectedIndex].value,'_top')" ) ); - $language_list .= CHtml::closeTag('div'); - $language_list .= CHtml::closeTag('div'); - $language_list .= CHtml::closeTag('div'); - $language_list .= CHtml::closeTag('div'); - $language_list .= ''; if ( count(Survey::model()->findByPk($iSurveyID)->additionalLanguages) > 1 ) { $selected = ( ! isset($tolang) ) ? "selected" : ""; @@ -408,10 +394,19 @@ private function _getLanguageList($iSurveyID, $tolang) $language_list .= CHtml::closeTag('select'); $language_list .= CHtml::closeTag('div'); // End of menubar-right + $language_list .= CHtml::closeTag('div'); + $language_list .= CHtml::closeTag('div'); + $language_list .= CHtml::closeTag('div'); return $language_list; } + private function _cleanup($string, $options=array()){ + $oTidy = new tidy; + $cleansedString = $oTidy->repairString($string); + return $cleansedString; + } + /** * setupTranslateFields() creates a customised array with database query * information for use by survey translation @@ -829,21 +824,21 @@ private function displayTranslateFieldsHeader($baselangdesc, $tolangdesc, $type) { $translateoutput = ""; - $translateoutput .= CHtml::openTag('table', array('class'=>'translate')); - $translateoutput .= CHtml::openTag('tr'); - if ($type=='question' || $type=='subquestion' || $type=='question_help' || $type=='answer') - { - $translateoutput.=''; - } - $translateoutput .= ''; - $translateoutput .= ''; - if ($type=='question' || $type=='subquestion' || $type=='question_help' || $type=='answer') - { - $translateoutput .= CHtml::tag('th', array(), CHtml::tag('b', array(), gT('Question code / ID'))); - } - $translateoutput .= CHtml::tag('th', array(), CHtml::tag('b', array(), $baselangdesc)); - $translateoutput .= CHtml::tag('th', array(), CHtml::tag('b', array(), $tolangdesc)); - $translateoutput .= CHtml::closeTag("tr"); + $translateoutput .= CHtml::openTag('div', array('class'=>'container-fluid')); + // if ($type=='question' || $type=='subquestion' || $type=='question_help' || $type=='answer') + // { + // $translateoutput.=''; + // } + //$translateoutput .= ''; + //$translateoutput .= ''; + $translateoutput .= CHtml::openTag('div', array('class' => 'row')); + if ($type=='question' || $type=='subquestion' || $type=='question_help' || $type=='answer') + { + $translateoutput .= CHtml::tag('div', array('class'=>'col-md-2'), CHtml::tag('b', array(), gT('Question code / ID'))); + } + $translateoutput .= CHtml::tag('div', array('class'=>'col-sm-5'), CHtml::tag('b', array(), $baselangdesc)); + $translateoutput .= CHtml::tag('div', array('class'=>'col-sm-5'), CHtml::tag('b', array(), $tolangdesc)); + $translateoutput .= CHtml::closeTag("div"); return $translateoutput; } @@ -868,67 +863,64 @@ private function displayTranslateFields($iSurveyID, $gid, $qid, $type, $amTypeOp $baselangdesc, $tolangdesc, $textfrom, $textto, $i, $rowfrom, $evenRow) { $translateoutput = ""; - $translateoutput .= CHtml::openTag('tr', array('class' => ( $evenRow ) ? 'odd' : 'even')); - - $value1 = ( ! empty($amTypeOptions["id1"]) ) ? $rowfrom[$amTypeOptions["id1"]] : ""; - $value2 = ( ! empty($amTypeOptions["id2"]) ) ? $rowfrom[$amTypeOptions["id2"]] : ""; - $iScaleID = ( ! empty($amTypeOptions["scaleid"]) ) ? $rowfrom[$amTypeOptions["scaleid"]] : ""; - - // Display text in original language - // Display text in foreign language. Save a copy in type_oldvalue_i to identify changes before db update - if ($type=='answer') - { - //print_r($rowfrom->attributes);die(); - $translateoutput .= "".htmlspecialchars($rowfrom->questions->title)." ({$rowfrom->questions->qid})\n"; - } - if ($type=='question_help' || $type=='question') - { - //print_r($rowfrom->attributes);die(); - $translateoutput .= "".htmlspecialchars($rowfrom->title)." ({$rowfrom->qid})\n"; - } - else if ($type=='subquestion') - { - //print_r($rowfrom->attributes);die(); - $translateoutput .= "".htmlspecialchars($rowfrom->parents->title)." ({$rowfrom->parents->qid})\n"; - } - - $translateoutput .= CHtml::tag( - 'td', - array( - 'class' => '_from_', - 'id' => "${type}_from_${i}" - ), - showJavaScript($textfrom) - ); - $translateoutput .= CHtml::openTag('td', array('valign'=>'middle')); - $translateoutput .= CHtml::hiddenField("{$type}_id1_{$i}", $value1); - $translateoutput .= CHtml::hiddenField("{$type}_id2_{$i}", $value2); - if (is_numeric($iScaleID)) $translateoutput .= CHtml::hiddenField("{$type}_scaleid_{$i}", $iScaleID); - - $nrows = max($this->calc_nrows($textfrom), $this->calc_nrows($textto)); - - $translateoutput .= CHtml::hiddenField("{$type}_oldvalue_{$i}", $textto); - $translateoutput .= CHtml::textArea("{$type}_newvalue_{$i}", $textto, - array( - 'class' => 'col-sm-10', - 'cols' => '75', - 'rows' => $nrows, - ) - ); - - $htmleditor_data = array( - "edit" . $type , - $type . "_newvalue_" . $i, - htmlspecialchars($textto), - $iSurveyID, - $gid, - $qid, - "translate" . $amTypeOptions["HTMLeditorType"] - ); - $translateoutput .= $this->_loadEditor($amTypeOptions, $htmleditor_data); - - $translateoutput .= CHtml::closeTag("td"); - $translateoutput .= CHtml::closeTag("tr"); + $translateoutput .= CHtml::openTag('div', array('class'=>'row')); + $value1 = ( ! empty($amTypeOptions["id1"]) ) ? $rowfrom[$amTypeOptions["id1"]] : ""; + $value2 = ( ! empty($amTypeOptions["id2"]) ) ? $rowfrom[$amTypeOptions["id2"]] : ""; + $iScaleID = ( ! empty($amTypeOptions["scaleid"]) ) ? $rowfrom[$amTypeOptions["scaleid"]] : ""; + // Display text in original language + // Display text in foreign language. Save a copy in type_oldvalue_i to identify changes before db update + if ($type=='answer') + { + //print_r($rowfrom->attributes);die(); + $translateoutput .= CHtml::tag("div",array("class"=>'col-sm-2'), htmlspecialchars($rowfrom->questions->title)." (".$rowfrom->questions->qid.")"); + } + if ($type=='question_help' || $type=='question') + { + //print_r($rowfrom->attributes);die(); + $translateoutput .= CHtml::tag("div",array("class"=>'col-sm-2'),htmlspecialchars($rowfrom->title)." ({$rowfrom->qid})"); + } + else if ($type=='subquestion') + { + //print_r($rowfrom->attributes);die(); + $translateoutput .= CHtml::tag("div",array("class"=>'col-sm-2'),htmlspecialchars($rowfrom->parents->title)." ({$rowfrom->parents->qid})"); + } + + $translateoutput .= CHtml::tag( + 'div', + array( + 'class' => '_from_ col-sm-5', + 'id' => "${type}_from_${i}" + ), + showJavaScript($textfrom) + ); + + $translateoutput .= CHtml::openTag('div', array('class'=>'col-sm-5')); + + $translateoutput .= CHtml::hiddenField("{$type}_id1_{$i}", $value1); + $translateoutput .= CHtml::hiddenField("{$type}_id2_{$i}", $value2); + if (is_numeric($iScaleID)) $translateoutput .= CHtml::hiddenField("{$type}_scaleid_{$i}", $iScaleID); + $nrows = max($this->calc_nrows($textfrom), $this->calc_nrows($textto)); + $translateoutput .= CHtml::hiddenField("{$type}_oldvalue_{$i}", $textto); + $translateoutput .= CHtml::textArea("{$type}_newvalue_{$i}", $textto, + array( + 'class' => 'col-sm-10', + 'cols' => '75', + 'rows' => $nrows, + ) + ); + $htmleditor_data = array( + "edit" . $type , + $type . "_newvalue_" . $i, + htmlspecialchars($textto), + $iSurveyID, + $gid, + $qid, + "translate" . $amTypeOptions["HTMLeditorType"] + ); + $translateoutput .= $this->_loadEditor($amTypeOptions, $htmleditor_data); + + $translateoutput .= CHtml::closeTag("div"); + $translateoutput .= CHtml::closeTag("div"); return $translateoutput; } @@ -980,7 +972,9 @@ private function calc_nrows( $subject ) */ private function displayTranslateFieldsFooter() { - $translateoutput = CHtml::closeTag("table"); + $translateoutput = CHtml::closeTag("div"); + $translateoutput = CHtml::closeTag("div"); + $translateoutput = CHtml::closeTag("div"); return $translateoutput; } diff --git a/application/controllers/admin/update.php b/application/controllers/admin/update.php index 7663760cc30..1de52e94766 100755 --- a/application/controllers/admin/update.php +++ b/application/controllers/admin/update.php @@ -333,7 +333,7 @@ public function backup() if (Yii::app()->request->getPost('datasupdateinfo')) { - $updateinfos= json_decode( base64_decode( Yii::app()->request->getPost('datasupdateinfo') ),true); + $updateinfos= (array) json_decode( base64_decode( Yii::app()->request->getPost('datasupdateinfo') ),true); $updateModel = new UpdateForm(); $backupInfos = $updateModel->backupFiles($updateinfos); diff --git a/application/controllers/admin/useraction.php b/application/controllers/admin/useraction.php index 4ca6bb068e6..e4f6377fd74 100644 --- a/application/controllers/admin/useraction.php +++ b/application/controllers/admin/useraction.php @@ -41,6 +41,9 @@ private function _getPostOrParam($param){ $value = Yii::app()->request->getPost($param); if(!$value) { + /* This already return GET or POST : : http://www.yiiframework.com/doc/api/1.1/CHttpRequest#getParam-detail + * DB update need $_POST, then only Yii::app()->request->getPost or control Yii::app()->request->getIsPostRequest() + **/ $value = Yii::app()->request->getParam($param); } return $value; @@ -177,93 +180,91 @@ public function adduser() */ public function deluser() { + if(Yii::app()->request->getIsPostRequest()){ /* DB action : need post request */ + if (!Permission::model()->hasGlobalPermission('superadmin','read') && !Permission::model()->hasGlobalPermission('users','delete')) { + Yii::app()->setFlashMessage(gT("You do not have permission to access this page."),'error'); + $this->getController()->redirect(array("admin/user/sa/index")); + } - $csrfToken = Yii::app()->request->csrfToken; - $transferredToken = $this->_getPostOrParam(Yii::app()->request->csrfTokenName); - if( $csrfToken != $transferredToken){ - Yii::app()->setFlashMessage(gT("Security token mismatch."),'error'); - $this->getController()->redirect(array("admin/user/sa/index")); - } - if (!Permission::model()->hasGlobalPermission('superadmin','read') && !Permission::model()->hasGlobalPermission('users','delete')) { - Yii::app()->setFlashMessage(gT("You do not have permission to access this page."),'error'); - $this->getController()->redirect(array("admin/user/sa/index")); - } + $action = $this->_getPostOrParam("action"); - $action = $this->_getPostOrParam("action"); + $aViewUrls = array(); - $aViewUrls = array(); + // CAN'T DELETE ORIGINAL SUPERADMIN (with findByAttributes : found the first user without parent) + $oInitialAdmin = User::model()->findByAttributes(array('parent_id' => 0)); - // CAN'T DELETE ORIGINAL SUPERADMIN (with findByAttributes : found the first user without parent) - $oInitialAdmin = User::model()->findByAttributes(array('parent_id' => 0)); + $postuserid = $this->_getPostOrParam("uid"); + $postuser = flattenText($this->_getPostOrParam("user")); - $postuserid = $this->_getPostOrParam("uid"); - $postuser = flattenText($this->_getPostOrParam("user")); + if ($oInitialAdmin && $oInitialAdmin->uid == $postuserid) // it's the original superadmin !!! + { + Yii::app()->setFlashMessage(gT("Initial Superadmin cannot be deleted!"),'error'); + $this->getController()->redirect(array("admin/user/sa/index")); + return; + } - if ($oInitialAdmin && $oInitialAdmin->uid == $postuserid) // it's the original superadmin !!! - { - Yii::app()->setFlashMessage(gT("Initial Superadmin cannot be deleted!"),'error'); - $this->getController()->redirect(array("admin/user/sa/index")); - return; - } + //If there was no uid transferred + if (!$postuserid) + { + Yii::app()->setFlashMessage(gT("Could not delete user. User was not supplied."),'error'); + $this->getController()->redirect(array("admin/user/sa/index")); + return; + } - //If there was no uid transferred - if (!$postuserid) - { - Yii::app()->setFlashMessage(gT("Could not delete user. User was not supplied."),'error'); - $this->getController()->redirect(array("admin/user/sa/index")); - return; - } + $sresultcount = 0; // 1 if I am parent of $postuserid + if (!Permission::model()->hasGlobalPermission('superadmin','read')) + { + $sresult = User::model()->findAllByAttributes(array('parent_id' => $postuserid, 'parent_id' => Yii::app()->session['loginID'])); + $sresultcount = count($sresult); + } - $sresultcount = 0; // 1 if I am parent of $postuserid - if (!Permission::model()->hasGlobalPermission('superadmin','read')) - { - $sresult = User::model()->findAllByAttributes(array('parent_id' => $postuserid, 'parent_id' => Yii::app()->session['loginID'])); - $sresultcount = count($sresult); - } + if (Permission::model()->hasGlobalPermission('superadmin','read') || $sresultcount > 0 || $postuserid == Yii::app()->session['loginID']) + { + $transfer_surveys_to = 0; + $ownerUser = User::model()->findAll(); + $aData = array(); + $aData['users'] = $ownerUser; - if (Permission::model()->hasGlobalPermission('superadmin','read') || $sresultcount > 0 || $postuserid == Yii::app()->session['loginID']) - { - $transfer_surveys_to = 0; - $ownerUser = User::model()->findAll(); - $aData = array(); - $aData['users'] = $ownerUser; + $current_user = Yii::app()->session['loginID']; + if (count($ownerUser) == 2) { + $action = "finaldeluser"; + foreach ($ownerUser as &$user) + { + if ($postuserid != $user['uid']) + $transfer_surveys_to = $user['uid']; + } + } - $current_user = Yii::app()->session['loginID']; - if (count($ownerUser) == 2) { - $action = "finaldeluser"; - foreach ($ownerUser as &$user) - { - if ($postuserid != $user['uid']) - $transfer_surveys_to = $user['uid']; + $ownerUser = Survey::model()->findAllByAttributes(array('owner_id' => $postuserid)); + if (count($ownerUser) == 0) { + $action = "finaldeluser"; } - } - $ownerUser = Survey::model()->findAllByAttributes(array('owner_id' => $postuserid)); - if (count($ownerUser) == 0) { - $action = "finaldeluser"; - } + if ($action == "finaldeluser") + { + $this->deleteFinalUser($ownerUser, $transfer_surveys_to); + } + else + { + $aData['postuserid'] = $postuserid; + $aData['postuser'] = $postuser; + $aData['current_user'] = $current_user; - if ($action == "finaldeluser") - { - $this->deleteFinalUser($ownerUser, $transfer_surveys_to); + $aViewUrls['deluser'][] = $aData; + $this->_renderWrappedTemplate('user', $aViewUrls); + } } else { - $aData['postuserid'] = $postuserid; - $aData['postuser'] = $postuser; - $aData['current_user'] = $current_user; - - $aViewUrls['deluser'][] = $aData; - $this->_renderWrappedTemplate('user', $aViewUrls); + Yii::app()->setFlashMessage(gT("You do not have permission to access this page."),'error'); + $this->getController()->redirect(array("admin/user/sa/index")); } + + return $aViewUrls; } - else - { - Yii::app()->setFlashMessage(gT("You do not have permission to access this page."),'error'); - $this->getController()->redirect(array("admin/user/sa/index")); - } + /* No action done, come back to user/index */ + $this->getController()->redirect(array("admin/user/sa/index")); - return $aViewUrls; } /** @@ -590,25 +591,23 @@ public function setusertemplates() App()->getClientScript()->registerPackage('jquery-tablesorter'); App()->getClientScript()->registerScriptFile( App()->getConfig('adminscripts') . 'users.js'); $postuserid = (int) Yii::app()->request->getPost("uid"); - $aData['postuser'] = flattenText(Yii::app()->request->getPost("user")); - $aData['postemail'] = flattenText(Yii::app()->request->getPost("email")); - $aData['postuserid'] = $postuserid; - $aData['postfull_name'] = flattenText(Yii::app()->request->getPost("full_name")); + $oUser = User::model()->findByAttributes(array('uid' => $postuserid)); + if(!$oUser) { + // @todo : review to send a 403 + $this->getController()->redirect(array("admin/user/sa/index")); + } + $aData['oUser']=$oUser; $this->_refreshtemplates(); $templaterights=array(); - foreach (getUserList() as $usr) + + $trights = Permission::model()->findAllByAttributes(array('uid' => $oUser->uid,'entity'=>'template')); + foreach ($trights as $srow) { - if ($usr['uid'] == $postuserid) - { - $trights = Permission::model()->findAllByAttributes(array('uid' => $usr['uid'],'entity'=>'template')); - foreach ($trights as $srow) - { - $templaterights[$srow["permission"]] = array("use"=>$srow["read_p"]); - } - $templates = Template::model()->findAll(); - $aData['data'] = array('templaterights'=>$templaterights,'templates'=>$templates); - } + $templaterights[$srow["permission"]] = array("use"=>$srow["read_p"]); } + $templates = Template::model()->findAll(); + $aData['data'] = array('templaterights'=>$templaterights,'templates'=>$templates); + $aData['fullpagebar']['savebutton']['form'] = 'modtemplaterightsform'; $aData['fullpagebar']['closebutton']['url_keep'] = true; diff --git a/application/controllers/admin/usergroups.php b/application/controllers/admin/usergroups.php index 718fbeb89a9..f0b942e024e 100644 --- a/application/controllers/admin/usergroups.php +++ b/application/controllers/admin/usergroups.php @@ -52,9 +52,8 @@ public function mail($ugid) foreach ($eguresult as $egurow) { - $to[] = $egurow->users->users_name . ' <' . $egurow->users->email . '>'; + $to[] = \CHtml::encode($egurow->users->users_name) . ' <' . $egurow->users->email . '>'; } - $from_user_result = User::model()->findByPk(Yii::app()->session['loginID']); $from_user_row = $from_user_result; diff --git a/application/core/LSETwigViewRenderer.php b/application/core/LSETwigViewRenderer.php index 9bcaad23141..02ad1459e1f 100644 --- a/application/core/LSETwigViewRenderer.php +++ b/application/core/LSETwigViewRenderer.php @@ -67,7 +67,6 @@ public function render( $sView, $aData, $bReturn=true) $this->_twig = parent::getTwig(); // Twig object $loader = $this->_twig->getLoader(); // Twig Template loader - $oTemplate = Template::model()->getInstance($thissurvey['template']); // Template configuration $requiredView = Yii::getPathOfAlias('application.views').$sView; // By default, the required view is the core view $loader->setPaths(App()->getBasePath().'/views/'); // Core views path @@ -136,18 +135,27 @@ public function renderQuestion( $sView, $aData) } } - - public function renderTemplateFromFile($sView, $aDatas, $bReturn) + public function renderTemplateForTemplateEditor($sView, $aDatas, $oEditedTemplate) { - $oTemplate = $this->getTemplateForView($sView); + $oTemplate = $this->getTemplateForView($sView, $oEditedTemplate); $line = file_get_contents($oTemplate->viewPath.$sView); - $this->renderTemplateFromString( $line, $aDatas, $bReturn); + $result = $this->renderTemplateFromString( $line, $aDatas, $oTemplate, true); + return $result; } - private function getTemplateForView($sView) + public function renderTemplateFromFile($sView, $aDatas, $bReturn) { $oRTemplate = Template::model()->getInstance(); + $oTemplate = $this->getTemplateForView($sView, $oRTemplate); + $line = file_get_contents($oTemplate->viewPath.$sView); + $result = $this->renderTemplateFromString( $line, $aDatas, $oTemplate, $bReturn); + if ($bReturn){ + return $result; + } + } + private function getTemplateForView($sView, $oRTemplate) + { while (!file_exists($oRTemplate->viewPath.$sView)){ $oMotherTemplate = $oRTemplate->oMotherTemplate; @@ -168,20 +176,41 @@ private function getTemplateForView($sView) * @param array $aDatas Array containing the datas needed to render the view ($thissurvey) * @param boolean $bReturn Should the function echo the result, or just returns it? */ - public function renderTemplateFromString( $line, $aDatas, $bReturn) + public function renderTemplateFromString( $line, $aDatas, $oRTemplate, $bReturn=false) { $this->_twig = $twig = parent::getTwig(); $loader = $this->_twig->getLoader(); - $oRTemplate = Template::model()->getInstance(); $loader->addPath($oRTemplate->viewPath); Yii::app()->clientScript->registerPackage( $oRTemplate->sPackageName ); + // Set Langage // TODO remove one of the Yii::app()->session see bug #5901 + if (!empty($aDatas['aSurveyInfo']['sid'])){ + if (Yii::app()->session['survey_'.$aDatas['aSurveyInfo']['sid']]['s_lang'] ){ + $languagecode = Yii::app()->session['survey_'.$aDatas['aSurveyInfo']['sid']]['s_lang']; + }elseif ($aDatas['aSurveyInfo']['sid'] && Survey::model()->findByPk($aDatas['aSurveyInfo']['sid'])){ + $languagecode = Survey::model()->findByPk($aDatas['aSurveyInfo']['sid'])->language; + }else{ + $languagecode = Yii::app()->getConfig('defaultlang'); + } + + $aDatas["aSurveyInfo"]['languagecode'] = $languagecode; + $aDatas["aSurveyInfo"]['dir'] = (getLanguageRTL($languagecode))?"rtl":"ltr"; + } + // Add all mother templates path while($oRTemplate->oMotherTemplate instanceof TemplateConfiguration){ $oRTemplate = $oRTemplate->oMotherTemplate; $loader->addPath($oRTemplate->viewPath); } + // Add the template options + foreach($oRTemplate->oOptions as $oOption){ + foreach($oOption as $key => $value){ + $aDatas["aSurveyInfo"]["options"][$key] = (string) $value; + } + } + + // Plugin for blocks replacement // TODO: add blocks to template.... $event = new PluginEvent('beforeTwigRenderTemplate'); @@ -206,17 +235,21 @@ public function renderTemplateFromString( $line, $aDatas, $bReturn) $oTwigTemplate = $twig->createTemplate($line); $nvLine = $oTwigTemplate->render($aDatas, false); - ob_start(function($buffer, $phase) - { - App()->getClientScript()->render($buffer); - App()->getClientScript()->reset(); - return $buffer; - }); + if (!$bReturn){ + ob_start(function($buffer, $phase) + { + App()->getClientScript()->render($buffer); + App()->getClientScript()->reset(); + return $buffer; + }); - ob_implicit_flush(false); - echo $nvLine; - ob_flush(); + ob_implicit_flush(false); + echo $nvLine; + ob_flush(); - Yii::app()->end(); + Yii::app()->end(); + }else{ + return $nvLine; + } } } diff --git a/application/core/LSHttpRequest.php b/application/core/LSHttpRequest.php index 1bd5b57c4a7..f6d92ded6b5 100644 --- a/application/core/LSHttpRequest.php +++ b/application/core/LSHttpRequest.php @@ -88,15 +88,11 @@ public function getUrlReferrer($sAlternativeUrl=null) $baseRequestUri = str_replace(Yii::app()->getBaseUrl(), "", Yii::app()->request->requestUri); $referrer = ($baseReferrer != $baseRequestUri)?$referrer:null; //Use alternative url if the $referrer is still available in the checkLoopInNavigationStack - if( ($this->checkLoopInNavigationStack($referrer)) || (is_null($referrer)) ) - { + if( ($this->checkLoopInNavigationStack($referrer)) || (is_null($referrer)) ) { // Checks if the alternative url should be used - if(isset($sAlternativeUrl)) - { + if(isset($sAlternativeUrl)) { $referrer = $sAlternativeUrl; - } - else - { + } else { return App()->createUrl('admin/index'); } } @@ -132,17 +128,15 @@ public function updateNavigationStack() /** * Method to check if an url is part of the stack - * Returns true, when an url is saved in the stack - * @param $referrerURL The URL that is checked against the stack + * @return bool Returns true, when an url is saved in the stack + * @param string $referrerURL The URL that is checked against the stack */ protected function checkLoopInNavigationStack($referrerURL) { $navStack = App()->session['LSNAVSTACK']; - foreach($navStack as $url) - { + foreach($navStack as $url) { $refEqualsUrl = ($referrerURL == $url); - if ($refEqualsUrl) - { + if ($refEqualsUrl) { return true; } } diff --git a/application/core/LSYii_Application.php b/application/core/LSYii_Application.php index 8f4e6edeeb6..3ffff2eb0d0 100644 --- a/application/core/LSYii_Application.php +++ b/application/core/LSYii_Application.php @@ -193,7 +193,7 @@ public function loadConfig($file) * * @access public * @param string $name - * @param type $default Value to return when not found, default is false + * @param boolean|mixed $default Value to return when not found, default is false * @return mixed */ public function getConfig($name, $default = false) @@ -234,7 +234,9 @@ public function getApi() */ public function getPluginManager() { - return $this->getComponent('pluginManager'); + /** @var PluginManager $pluginManager */ + $pluginManager =$this->getComponent('pluginManager'); + return $pluginManager; } /** diff --git a/application/core/LSYii_ClientScript.php b/application/core/LSYii_ClientScript.php index af4e9e1c6ba..96030562a80 100644 --- a/application/core/LSYii_ClientScript.php +++ b/application/core/LSYii_ClientScript.php @@ -50,7 +50,7 @@ public function getCoreScripts() * Remove a package from coreScript. * It can be useful when mixing backend/frontend rendering (see: template editor) * - * @var $name of the package to remove + * @var string $sName of the package to remove */ public function unregisterPackage($sName) { @@ -108,28 +108,23 @@ public function registerCssFile($url,$media='') parent::registerCssFile($url,$media); // We publish the script } + /** + * The method will first check if a devbaseUrl parameter is provided, + * so when debug mode is on, it doens't use the asset manager + */ public function registerPackage($name) { if(!YII_DEBUG || Yii::app()->getConfig('use_asset_manager')){ parent::registerPackage( $name ); }else{ - $aDepends = $this->getRecursiveDependencies($name); - // CONVERT ALL PACKAGE IN $aDepend to BASE URL instead of PATH - foreach($aDepends as $package){ + // We first convert the current package to devBaseUrl + $this->convertDevBaseUrl($name); - $aOldPackageDefinition = Yii::app()->clientScript->packages[$package]; - - // This will overwrite the package definition using a base url instead of a base path - // The package must have a devBaseUrl, else it will remain unchanged (for core/external package) - if( array_key_exists('devBaseUrl', $aOldPackageDefinition ) ){ - Yii::app()->clientScript->addPackage( $package, array( - 'baseUrl' => $aOldPackageDefinition['devBaseUrl'], // Don't use asset manager - 'css' => array_key_exists('css', $aOldPackageDefinition)?$aOldPackageDefinition['css']:array(), - 'js' => array_key_exists('js', $aOldPackageDefinition)?$aOldPackageDefinition['js']:array(), - 'depends' => array_key_exists('depends', $aOldPackageDefinition)?$aOldPackageDefinition['depends']:array(), - ) ); - } + // Then we do the same for all its dependencies + $aDepends = $this->getRecursiveDependencies($name); + foreach($aDepends as $package){ + $this->convertDevBaseUrl($package); } parent::registerPackage( $name ); @@ -159,6 +154,26 @@ public function getRecursiveDependencies($sPackageName) return array(); } + + /** + * Convert one package to baseUrl + */ + private function convertDevBaseUrl($package) + { + $aOldPackageDefinition = Yii::app()->clientScript->packages[$package]; + + // This will overwrite the package definition using a base url instead of a base path + // The package must have a devBaseUrl, else it will remain unchanged (for core/external package) + if( array_key_exists('devBaseUrl', $aOldPackageDefinition ) ){ + Yii::app()->clientScript->addPackage( $package, array( + 'baseUrl' => $aOldPackageDefinition['devBaseUrl'], // Don't use asset manager + 'css' => array_key_exists('css', $aOldPackageDefinition)?$aOldPackageDefinition['css']:array(), + 'js' => array_key_exists('js', $aOldPackageDefinition)?$aOldPackageDefinition['js']:array(), + 'depends' => array_key_exists('depends', $aOldPackageDefinition)?$aOldPackageDefinition['depends']:array(), + ) ); + } + } + /** * This function will analyze the url of a file (css/js) to register * It will check if it can be published via the asset manager and if so will retreive its path diff --git a/application/core/LSYii_Validators.php b/application/core/LSYii_Validators.php index a12a2d5eeb8..ec6b24670fe 100644 --- a/application/core/LSYii_Validators.php +++ b/application/core/LSYii_Validators.php @@ -141,8 +141,7 @@ public function xssFilter($value) foreach($aValues as $key=>$aValue){ if($aValue[2]=="STRING") $sNewValue.=$bCountIsOk ? $aFilteredValues[$key][0]:$filter->purify($aValue[0]);// If EM is broken : can throw invalid $key - else - { + else { $sExpression=trim($aValue[0], '{}'); $sNewValue.="{"; $aParsedExpressions=$oExpressionManager->Tokenize($sExpression,true); diff --git a/application/core/LS_Twig_Extension.php b/application/core/LS_Twig_Extension.php index 69781ccda9a..d2e820b5c84 100644 --- a/application/core/LS_Twig_Extension.php +++ b/application/core/LS_Twig_Extension.php @@ -91,15 +91,14 @@ public static function registerGeneralScript($sGeneralScriptFileName, $position= /** * Publish a script file from template directory, using or not the asset manager (depending on configuration) * In any twig file, you can register a template script file doing: {{ registerTemplateScript($sTemplateScriptFileName) }} - * @param string $sGeneralScriptFileName name of the script file to publish in general script directory (it should contains the subdirectories) + * @param string $sTemplateScriptFileName name of the script file to publish in general script directory (it should contains the subdirectories) */ public static function registerTemplateScript($sTemplateScriptFileName, $position=null, array $htmlOptions=array()) { $oTemplate = self::getTemplateForRessource($sTemplateScriptFileName); - $position = self::getPosition($position); Yii::app()->getClientScript()->registerScriptFile( - $oRTemplate->sTemplateUrl . + $oTemplate->sTemplateUrl . $sTemplateScriptFileName, $position, $htmlOptions @@ -163,7 +162,7 @@ public static function getAllQuestionClasses($iQid) /* Add the relevance class */ if (!$lemQuestionInfo['relevant']){ - $aQuestionClass .= ' ls-unrelevant'; + $aQuestionClass .= ' ls-irrelevant'; $aQuestionClass .= ' ls-hidden'; } @@ -230,7 +229,7 @@ public static function image($sImagePath, $alt='', $htmlOptions=array ( ) ) public static function getTemplateForRessource($sRessource) { $oRTemplate = Template::model()->getInstance(); - + while (!file_exists($oRTemplate->path.'/'.$sRessource)){ $oMotherTemplate = $oRTemplate->oMotherTemplate; @@ -259,5 +258,22 @@ public static function getQuery($sName, $sDefaultValue=null) return Yii::app()->request->getQuery($sName, $sDefaultValue); } + public static function unregisterPackage($name) + { + return Yii::app()->getClientScript()->unregisterPackage($name); + } + + public static function listCoreScripts() + { + foreach(Yii::app()->getClientScript()->coreScripts as $key => $package){ + + echo "
"; + echo "$key:
"; + var_dump($package); + + } + + } + } diff --git a/application/core/Survey_Common_Action.php b/application/core/Survey_Common_Action.php index e231199526a..0f88606bc31 100644 --- a/application/core/Survey_Common_Action.php +++ b/application/core/Survey_Common_Action.php @@ -64,18 +64,8 @@ public function runWithParams($params) $params = $this->_addPseudoParams($params); if (!empty($params['iSurveyId'])) { - $oSurvey=Survey::model()->findByPk($params['iSurveyId']); - if(!$oSurvey) { - Yii::app()->setFlashMessage(gT("Invalid survey ID"),'error'); - $this->getController()->redirect(array("admin/index")); - } elseif (!Permission::model()->hasSurveyPermission($params['iSurveyId'], 'survey', 'read')) { - Yii::app()->setFlashMessage(gT("No permission"), 'error'); - $this->getController()->redirect(array("admin/index")); - } else { - LimeExpressionManager::SetSurveyId($params['iSurveyId']); // must be called early - it clears internal cache if a new survey is being used - } + LimeExpressionManager::SetSurveyId($params['iSurveyId']); // must be called early - it clears internal cache if a new survey is being used } - // Check if the method is public and of the action class, not its parents // ReflectionClass gets us the methods of the class and parent class // If the above method existence check passed, it might not be neceessary that it is of the action class @@ -110,8 +100,7 @@ public function runWithParams($params) private function _addPseudoParams($params) { // Return if params isn't an array - if (empty($params) || !is_array($params)) - { + if (empty($params) || !is_array($params)) { return $params; } @@ -143,7 +132,7 @@ private function _addPseudoParams($params) // with that key's value in the params // (only if that place is empty) foreach ($pseudos as $key => $pseudo) { - if (!empty($params[$key])) { + if (isset($params[$key])) { $pseudo = (array) $pseudo; foreach ($pseudo as $pseud) { if (empty($params[$pseud])) { @@ -153,29 +142,52 @@ private function _addPseudoParams($params) } } + /* Control sid,gid and qid params validity see #12434 */ // Fill param with according existing param, replace existing parameters. // iGroupId/gid can be found with qid/iQuestionId - if(isset($params['iQuestionId'])) - { - if((int) $params['iQuestionId'] >0 ) - { //Check if the transfered iQuestionId is numeric to prevent Errors with postgresql - $oQuestion=Question::model()->find("qid=:qid",array(":qid"=>$params['iQuestionId']));//Move this in model to use cache - if($oQuestion) - { - $params['iGroupId']=$params['gid']=$oQuestion->gid; - } + if(!empty($params['iQuestionId'])) { + if((string)(int)$params['iQuestionId']!==(string)$params['iQuestionId']) { // pgsql need filtering before find + throw new CHttpException(403,gT("Invalid question id")); + } + $oQuestion=Question::model()->find("qid=:qid",array(":qid"=>$params['iQuestionId']));//Move this in model to use cache + if(!$oQuestion) { + throw new CHttpException(404,gT("Question not found")); + } + if(!isset($params['iGroupId'])) { + $params['iGroupId']=$params['gid']=$oQuestion->gid; } } // iSurveyId/iSurveyID/sid can be found with gid/iGroupId - if(isset($params['iGroupId'])) - { + if(!empty($params['iGroupId'])) { + if((string)(int)$params['iGroupId']!==(string)$params['iGroupId']) { // pgsql need filtering before find + throw new CHttpException(403,gT("Invalid group id")); + } $oGroup=QuestionGroup::model()->find("gid=:gid",array(":gid"=>$params['iGroupId']));//Move this in model to use cache - if($oGroup) - { + if(!$oGroup) { + throw new CHttpException(404,gT("Group not found")); + } + if(!isset($params['iSurveyId'])) { $params['iSurveyId']=$params['iSurveyID']=$params['surveyid']=$params['sid']=$oGroup->sid; } } - + // Finally control validity of sid + if(!empty($params['iSurveyId'])) { + if((string)(int)$params['iSurveyId']!==(string)$params['iSurveyId']) { // pgsql need filtering before find + // 403 mean The request was valid, but the server is refusing action. + throw new CHttpException(403,gT("Invalid survey id")); + } + $oSurvey=Survey::model()->findByPk($params['iSurveyId']); + if(!$oSurvey) { + throw new CHttpException(404,gT("Survey not found")); + } + // Minimal permission needed, extra permission must be tested in each controller + if (!Permission::model()->hasSurveyPermission($params['iSurveyId'], 'survey', 'read')) { + // 403 mean (too) The user might not have the necessary permissions for a resource. + // 401 semantically means "unauthenticated" + throw new CHttpException(403); + } + $params['iSurveyId']=$params['iSurveyID']=$params['surveyid']=$params['sid']=$oSurvey->sid; + } // Finally return the populated array return $params; } @@ -374,46 +386,57 @@ protected function _renderWrappedTemplate($sAction = '', $aViewUrls = array(), $ /** * Display the update notification */ - function _updatenotification() + protected function _updatenotification() { - // Lower dbversionnumbers will not have the notifications table. - if (Yii::app()->getConfig('dbversionnumber') < 259) { + // Never use Notification model for database update. + // TODO: Real fix: No database queries while doing database update, meaning + // don't call _renderWrappedTemplate. + if (get_class($this) == 'databaseupdate') { return; } - if( !Yii::app()->user->isGuest && Yii::app()->getConfig('updatable')) - { + if (!Yii::app()->user->isGuest && Yii::app()->getConfig('updatable')) { $updateModel = new UpdateForm(); $updateNotification = $updateModel->updateNotification; $urlUpdate = Yii::app()->createUrl("admin/update"); - $urlUpdateNotificationState = Yii::app()->createUrl("admin/update/sa/notificationstate"); $currentVersion = Yii::app()->getConfig("buildnumber"); $superadmins = User::model()->getSuperAdmins(); - if($updateNotification->result) - { - if($updateNotification->security_update) - { - UniqueNotification::broadcast(array( - 'title' => gT('Security update!')." (".gT("Current version: ").$currentVersion.")", - 'message' => gT('A security update is available.')." ".gT('Click here to use ComfortUpdate.')."" - ), $superadmins); - } - else if(Yii::app()->session['unstable_update'] ) - { - UniqueNotification::broadcast(array( - 'title' => gT('New UNSTABLE update available')." (".gT("Current version: ").$currentVersion.")", - 'markAsNew' => false, - 'message' => gT('A security update is available.')."".gT('Click here to use ComfortUpdate.')."" - ), $superadmins); - } - else - { - UniqueNotification::broadcast(array( - 'title' => gT('New update available')." (".gT("Current version: ").$currentVersion.")", - 'markAsNew' => false, - 'message' => gT('A security update is available.')."".gT('Click here to use ComfortUpdate.')."" - ), $superadmins); + if ($updateNotification->result) { + if ($updateNotification->security_update) { + UniqueNotification::broadcast( + array( + 'title' => gT('Security update!')." (".gT("Current version: ") + . $currentVersion.")", + 'message' => gT('A security update is available.')." " + . gT('Click here to use ComfortUpdate.')."", + 'importance' => Notification::HIGH_IMPORTANCE + ), + $superadmins + ); + } elseif (Yii::app()->session['unstable_update']) { + UniqueNotification::broadcast( + array( + 'title' => gT('New UNSTABLE update available')." (" + . gT("Current version: ").$currentVersion.")", + 'markAsNew' => false, + 'message' => gT('A security update is available.')."" + . gT('Click here to use ComfortUpdate.')."", + 'importance' => Notification::HIGH_IMPORTANCE + ), + $superadmins + ); + } else { + UniqueNotification::broadcast( + array( + 'title' => gT('New update available')." (".gT("Current version: ").$currentVersion.")", + 'markAsNew' => false, + 'message' => gT('A security update is available.')."" + . gT('Click here to use ComfortUpdate.')."", + 'importance' => Notification::HIGH_IMPORTANCE + ), + $superadmins + ); } } } @@ -572,19 +595,15 @@ function _organizequestionbar($aData) /** * Shows admin menu for question * - * @param int Survey id - * @param int Group id - * @param int Question id - * @param string action + * @param array $aData */ - function _questionbar($aData) + public function _questionbar($aData) { - if(isset($aData['questionbar'])) - { - if (is_object($aData['oSurvey'])) - { + if(isset($aData['questionbar'])) { + if (is_object($aData['oSurvey'])) { $iSurveyID = $aData['surveyid']; + /** @var Survey $oSurvey */ $oSurvey = $aData['oSurvey']; $gid = $aData['gid']; $qid = $aData['qid']; @@ -1067,8 +1086,7 @@ private function _listquestions($aData) /** * Show survey summary - * @param int Survey id - * @param string Action to be performed + * @param array $aData */ public function _surveysummary($aData) { @@ -1190,52 +1208,37 @@ public function _surveysummary($aData) $aData['language'] = getLanguageNameFromCode($aSurveyInfo['language'], false); } - // get the rowspan of the Additionnal languages row - // is at least 1 even if no additionnal language is present - $additionnalLanguagesCount = count($aAdditionalLanguages); - $first = true; - if ($aSurveyInfo['surveyls_urldescription'] == "") - { + if ($aSurveyInfo['surveyls_urldescription'] == "") { $aSurveyInfo['surveyls_urldescription'] = htmlspecialchars($aSurveyInfo['surveyls_url']); } - if ($aSurveyInfo['surveyls_url'] != "") - { + if ($aSurveyInfo['surveyls_url'] != "") { $aData['endurl'] = " ".flattenText($aSurveyInfo['surveyls_urldescription']).""; - } - else - { + } else { $aData['endurl'] = "-"; } $aData['sumcount3'] = $sumcount3; $aData['sumcount2'] = $sumcount2; - if ($activated == "N") - { + if ($activated == "N") { $aData['activatedlang'] = gT("No"); - } - else - { + } else { $aData['activatedlang'] = gT("Yes"); } $aData['activated'] = $activated; - if ($activated == "Y") - { + if ($activated == "Y") { $aData['surveydb'] = Yii::app()->db->tablePrefix . "survey_" . $iSurveyID; } $aData['warnings'] = ""; - if ($activated == "N" && $sumcount3 == 0) - { + if ($activated == "N" && $sumcount3 == 0) { $aData['warnings'] = gT("Survey cannot be activated yet.") . "
\n"; - if ($sumcount2 == 0 && Permission::model()->hasSurveyPermission($iSurveyID, 'surveycontent', 'create')) - { + if ($sumcount2 == 0 && Permission::model()->hasSurveyPermission($iSurveyID, 'surveycontent', 'create')) { $aData['warnings'] .= "[" . gT("You need to add question groups") . "]
"; } - if ($sumcount3 == 0 && Permission::model()->hasSurveyPermission($iSurveyID, 'surveycontent', 'create')) - { + if ($sumcount3 == 0 && Permission::model()->hasSurveyPermission($iSurveyID, 'surveycontent', 'create')) { $aData['warnings'] .= "[" . gT("You need to add questions") . "]
"; } } @@ -1243,7 +1246,7 @@ public function _surveysummary($aData) //return (array('column'=>array($columns_used,$hard_limit) , 'size' => array($length, $size_limit) )); // $aData['tableusage'] = getDBTableUsage($iSurveyID); - // ToDo: Table usage is calculated on every menu display which is too slow with bug surveys. + // ToDo: Table usage is calculated on every menu display which is too slow with big surveys. // Needs to be moved to a database field and only updated if there are question/subquestions added/removed (it's currently also not functional due to the port) // diff --git a/application/core/plugins/AuthLDAP/AuthLDAP.php b/application/core/plugins/AuthLDAP/AuthLDAP.php index a9856892683..cc861a85ac9 100644 --- a/application/core/plugins/AuthLDAP/AuthLDAP.php +++ b/application/core/plugins/AuthLDAP/AuthLDAP.php @@ -127,7 +127,7 @@ public function init() { /** * Check availability of LDAP Apache Module * - * @return unknown_type + * @return null */ public function beforeActivate() { @@ -142,7 +142,7 @@ public function beforeActivate() /** * Create a LDAP user * - * @return unknown_type + * @return null */ public function createNewUser() { diff --git a/application/core/plugins/Authdb/Authdb.php b/application/core/plugins/Authdb/Authdb.php index c42fc2c06d7..740e501d040 100644 --- a/application/core/plugins/Authdb/Authdb.php +++ b/application/core/plugins/Authdb/Authdb.php @@ -28,20 +28,18 @@ public function init() /** * Create a DB user * - * @return unknown_type + * @return null */ public function createNewUser() { // Do nothing if the user to be added is not DB type - if (flattenText(Yii::app()->request->getPost('user_type')) != 'DB') - { + if (flattenText(Yii::app()->request->getPost('user_type')) != 'DB') { return; } $oEvent = $this->getEvent(); $new_user = flattenText(Yii::app()->request->getPost('new_user'), false, true); $new_email = flattenText(Yii::app()->request->getPost('new_email'), false, true); - if (!validateEmailAddress($new_email)) - { + if (!validateEmailAddress($new_email)) { $oEvent->set('errorCode',self::ERROR_INVALID_EMAIL); $oEvent->set('errorMessageTitle',gT("Failed to add user")); $oEvent->set('errorMessageBody',gT("The email address is not valid.")); @@ -50,8 +48,7 @@ public function createNewUser() $new_full_name = flattenText(Yii::app()->request->getPost('new_full_name'), false, true); $new_pass = createPassword(); $iNewUID = User::model()->insertUser($new_user, $new_pass, $new_full_name, Yii::app()->session['loginID'], $new_email); - if (!$iNewUID) - { + if (!$iNewUID) { $oEvent->set('errorCode',self::ERROR_ALREADY_EXISTING_USER); $oEvent->set('errorMessageTitle',''); $oEvent->set('errorMessageBody',gT("Failed to add user")); @@ -179,7 +176,7 @@ public function newUserSession() /** * Set the onetime password * - * @param type $onepass + * @param string $onepass * @return Authdb */ protected function setOnePass($onepass) diff --git a/application/core/plugins/ExportR/RDataWriter.php b/application/core/plugins/ExportR/RDataWriter.php index 0eb055c4f45..ec7e82567b0 100644 --- a/application/core/plugins/ExportR/RDataWriter.php +++ b/application/core/plugins/ExportR/RDataWriter.php @@ -28,8 +28,8 @@ public function init(\SurveyObj $survey, $sLanguageCode, \FormattingOptions $oOp /** * Perform response transformation, for example F/M for female/male will be mapped to 1/2 values * - * @param type $value - * @param type $fieldType + * @param string $value + * @param string $fieldType * @param FormattingOptions $oOptions * @return mixed */ diff --git a/application/core/plugins/ExportSTATAxml/ExportSTATAxml.php b/application/core/plugins/ExportSTATAxml/ExportSTATAxml.php index 9a6c7b03d1f..25416545bb9 100644 --- a/application/core/plugins/ExportSTATAxml/ExportSTATAxml.php +++ b/application/core/plugins/ExportSTATAxml/ExportSTATAxml.php @@ -72,7 +72,6 @@ public function listExportPlugins() public function newExport() { $event = $this->getEvent(); - $type = $event->get('type'); $pluginsettings=$this->getPluginSettings(true); $writer = new STATAxmlWriter($pluginsettings); diff --git a/application/core/plugins/QuickMenu/QuickMenu.php b/application/core/plugins/QuickMenu/QuickMenu.php index 4458d70c255..1f1f09a4a21 100644 --- a/application/core/plugins/QuickMenu/QuickMenu.php +++ b/application/core/plugins/QuickMenu/QuickMenu.php @@ -447,7 +447,7 @@ public function afterQuickMenuLoad() * Save order after drag-n-drop sorting * * @param LSHttpRequest $request - * @return void + * @return string */ public function saveOrder(LSHttpRequest $request) { @@ -455,13 +455,10 @@ public function saveOrder(LSHttpRequest $request) $userId = Yii::app()->user->getId(); - try - { + try { $this->deleteOldSortings($userId); $this->insertNewSortings($userId, $buttons); - } - catch(Exception $ex) - { + } catch(Exception $ex) { // Any error is sent as JSON to client return json_encode(array( 'result' => 'error', diff --git a/application/core/plugins/extendedStartPage/views/publicSurveyList_extended.php b/application/core/plugins/extendedStartPage/views/publicSurveyList_extended.php index 391fed64027..6469e4c67c5 100644 --- a/application/core/plugins/extendedStartPage/views/publicSurveyList_extended.php +++ b/application/core/plugins/extendedStartPage/views/publicSurveyList_extended.php @@ -3,7 +3,7 @@ $list = "
"; $list .= "
"; $divideToggle = true; - + /** @var Survey[] $publicSurveys */ foreach($publicSurveys as $survey) { $outputSurveys++; @@ -57,7 +57,7 @@ $content = $survey->localizedTitle; $content .= "" - ." " + ." " .""; $list .= CHtml::link( @@ -153,9 +153,9 @@ "SURVEYLISTHEADING"=> $listheading, "SURVEYLIST"=> $list, ); + // FIXME makeLanguageChanger() is not accessible from here?? $data['languagechanger'] = makeLanguageChanger(App()->language); /* must register script if template don't do it */ App()->clientScript->registerScript("ExtendedStartpageToolTip","$('.surveytitle,.view-stats').tooltip()",CClientScript::POS_READY); $oTemplate = Template::model()->getInstance("default"); echo templatereplace(file_get_contents($oTemplate->pstplPath."/surveylist.pstpl"),$aReplacementData,$data,'survey['.__LINE__.']'); -?> diff --git a/application/core/plugins/oldUrlCompat/oldUrlCompat.php b/application/core/plugins/oldUrlCompat/oldUrlCompat.php index 60acea09e01..69a23658a57 100644 --- a/application/core/plugins/oldUrlCompat/oldUrlCompat.php +++ b/application/core/plugins/oldUrlCompat/oldUrlCompat.php @@ -3,7 +3,7 @@ * Plugin to redirect old url system (index.php?sid=surveyid) to the new url * * @author Denis Chenu - * @copyright 2016 LimeSurvey team + * @copyright 2016 LimeSurvey team * @license GPL v3 * @version 0.0.1 * diff --git a/application/extensions/AdminFooter/views/footer.php b/application/extensions/AdminFooter/views/footer.php index 1ff5ea1e8ad..55a7d01e65e 100644 --- a/application/extensions/AdminFooter/views/footer.php +++ b/application/extensions/AdminFooter/views/footer.php @@ -5,5 +5,5 @@ - +
diff --git a/application/extensions/LimeScript/LimeScript.php b/application/extensions/LimeScript/LimeScript.php index aeba5a0c61f..fc08c116480 100644 --- a/application/extensions/LimeScript/LimeScript.php +++ b/application/extensions/LimeScript/LimeScript.php @@ -19,6 +19,7 @@ public function run() $data['replacementFields']['path'] = App()->createUrl("admin/limereplacementfields/sa/index/"); $json = json_encode($data, JSON_FORCE_OBJECT); $script = "LS.data = $json;\n" + . "LS.lang = {};\n" . "$.ajaxSetup({data: {YII_CSRF_TOKEN: LS.data.csrfToken}});"; App()->getClientScript()->registerScript('LimeScript', $script, CClientScript::POS_HEAD); } diff --git a/application/extensions/PanelBoxWidget/PanelBoxWidget.php b/application/extensions/PanelBoxWidget/PanelBoxWidget.php index 2221a390f69..93439f7659d 100644 --- a/application/extensions/PanelBoxWidget/PanelBoxWidget.php +++ b/application/extensions/PanelBoxWidget/PanelBoxWidget.php @@ -1,196 +1,168 @@ display=='singlebox') - { - if($this->fromDb) - { - $this->setValuesFromDb(); - } - - return $this->renderBox(); - } - elseif($this->display='allboxesinrows') - { - return $this->renderRows(); + if ($this->display == 'singlebox') { + if ($this->fromDb) { + $this->setValuesFromDb(); } - } - public function getBoxes() - { - $boxes = Boxes::model()->findAll(array('order' => 'position ASC')); - return $boxes; + return $this->renderBox(); + } elseif ($this->display = 'allboxesinrows') { + return $this->renderRows(); } + } - protected function setValuesFromDb() - { - $box = Boxes::model()->find(array('condition'=>'position=:positionId', 'params'=>array(':positionId'=>$this->dbPosition))); - if($box) - { - $this->position = $box->position; - if(!preg_match("/^(http|https)/", $box->url)) { - $this->url = Yii::app()->createUrl($box->url); - } - else { - $this->url = $box->url; - $this->external = true; - } - $this->title = $box->title; - $this->ico = $box->ico; - $this->description = $box->desc; - $this->usergroup = $box->usergroup; - } - else - { - $this->position = '1'; - $this->url = ''; - $this->title = gT('Error'); - $this->description = gT('Unknown box ID!'); - } - } + public function getBoxes() + { + $boxes = Boxes::model()->findAll(array('order' => 'position ASC')); + return $boxes; + } - /** - * Render a single box - */ - protected function renderBox() - { - if ( self::canSeeBox()) - { - $offset = ($this->offset != '') ? 'col-sm-offset-1 col-lg-offset-'.$this->offset : ''; - - $this->render('box', array( - 'position'=> $this->position, - 'offset' => $offset, - 'url'=> $this->url, - 'title'=> $this->title, - 'ico'=> $this->ico, - 'description'=> $this->description, - 'external' => $this->external, - )); + protected function setValuesFromDb() + { + $box = Boxes::model()->find(array( + 'condition' => 'position=:positionId', + 'params' => array(':positionId' => $this->dbPosition) + )); + if ($box) { + $this->position = $box->position; + if (!preg_match("/^(http|https)/", $box->url)) { + $this->url = Yii::app()->createUrl($box->url); + } else { + $this->url = $box->url; + $this->external = true; } + $this->title = $box->title; + $this->ico = $box->ico; + $this->description = $box->desc; + $this->usergroup = $box->usergroup; + } else { + $this->position = '1'; + $this->url = ''; + $this->title = gT('Error'); + $this->description = gT('Unknown box ID!'); } + } - /** - * Render all boxes in row - */ - protected function renderRows() - { - // We get all the boxes in the database - $boxes = self::getBoxes(); - $boxcount = 0; - $bIsRowOpened = false; - foreach($boxes as $box) - { - - $canSeeBox = self::canSeeBox($box); - if( $canSeeBox ) - { - $boxcount=$boxcount+1; - } + /** + * Render a single box + */ + protected function renderBox() + { + if (self::canSeeBox()) { + $offset = ($this->offset != '') ? 'col-sm-offset-1 col-lg-offset-' . $this->offset : ''; + + $this->render('box', array( + 'position' => $this->position, + 'offset' => $offset, + 'url' => $this->url, + 'title' => $this->title, + 'ico' => $this->ico, + 'description' => $this->description, + 'external' => $this->external, + )); + } + } - // It's the first box to show, we must display row header, and have an offset - if($boxcount == 1 && $canSeeBox) - { + /** + * Render all boxes in row + */ + protected function renderRows() + { + // We get all the boxes in the database + $boxes = self::getBoxes(); + $boxcount = 0; + $bIsRowOpened = false; + foreach ($boxes as $box) { + + $canSeeBox = self::canSeeBox($box); + if ($canSeeBox) { + $boxcount = $boxcount + 1; + } + // It's the first box to show, we must display row header, and have an offset + if ($boxcount == 1 && $canSeeBox) { - $this->render('row_header'); - $bIsRowOpened = true; - $this->controller->widget('ext.PanelBoxWidget.PanelBoxWidget', array( - 'display'=>'singlebox', - 'fromDb'=> true, - 'dbPosition'=>$box->position, - 'offset' =>$this->offset, - )); - } - elseif($canSeeBox) - { - $this->controller->widget('ext.PanelBoxWidget.PanelBoxWidget', array( - 'display'=>'singlebox', - 'fromDb'=> true, - 'dbPosition'=>$box->position, - 'offset' =>'', - )); - } - // If it is the last box, we should close the box - if($boxcount == $this->boxesbyrow) - { - $this->render('row_footer'); - $boxcount = 0; - $bIsRowOpened = false; - } + $this->render('row_header'); + $bIsRowOpened = true; + $this->controller->widget('ext.PanelBoxWidget.PanelBoxWidget', array( + 'display' => 'singlebox', + 'fromDb' => true, + 'dbPosition' => $box->position, + 'offset' => $this->offset, + )); + } elseif ($canSeeBox) { + $this->controller->widget('ext.PanelBoxWidget.PanelBoxWidget', array( + 'display' => 'singlebox', + 'fromDb' => true, + 'dbPosition' => $box->position, + 'offset' => '', + )); } - // If the last row has not been closed, we close it - if($bIsRowOpened == true) - { + // If it is the last box, we should close the box + if ($boxcount == $this->boxesbyrow) { $this->render('row_footer'); + $boxcount = 0; + $bIsRowOpened = false; } } - protected function canSeeBox( $box='') - { - $box=($box=='')?$this:$box; - if ( $box->usergroup=='-1' ) - { + // If the last row has not been closed, we close it + if ($bIsRowOpened == true) { + $this->render('row_footer'); + } + } + + protected function canSeeBox($box = '') + { + $box = ($box == '') ? $this : $box; + if ($box->usergroup == '-1') { + return true; + } // If the usergroup is not set, or set to -2, only admin can see the box + elseif (empty($box->usergroup) || $box->usergroup == '-2') { + if (Permission::model()->hasGlobalPermission('superadmin', 'read') ? 1 : 0) { return true; + } else { + return false; } - // If the usergroup is not set, or set to -2, only admin can see the box - elseif ( empty($box->usergroup) || $box->usergroup=='-2' ) - { - if(Permission::model()->hasGlobalPermission('superadmin','read') ? 1 : 0) - { + } // If usergroup is set to -3, nobody can see the box + elseif ($box->usergroup == '-3') { + return false; + } // If usegroup is set and exist, if the user belong to it, he can see the box + else { + $oUsergroup = UserGroup::model()->findByPk($box->usergroup); + + // The group doesn't exist anymore, so only admin can see it + if (!is_object($oUsergroup)) { + if (Permission::model()->hasGlobalPermission('superadmin', 'read') ? 1 : 0) { return true; - } - else - { + } else { return false; } } - // If usergroup is set to -3, nobody can see the box - elseif ( $box->usergroup=='-3' ) - { - return false; - } - // If usegroup is set and exist, if the user belong to it, he can see the box - else - { - $oUsergroup = UserGroup::model()->findByPk($box->usergroup); - - // The group doesn't exist anymore, so only admin can see it - if(!is_object($oUsergroup)) - { - if(Permission::model()->hasGlobalPermission('superadmin','read') ? 1 : 0) - { - return true; - } - else - { - return false; - } - } - if(Yii::app()->user->isInUserGroup($box->usergroup)) - { - return true; - } + if (Yii::app()->user->isInUserGroup($box->usergroup)) { + return true; } } - } + +} diff --git a/application/extensions/PanelBoxWidget/views/box.php b/application/extensions/PanelBoxWidget/views/box.php index a33cf605f44..08d304ed9a8 100644 --- a/application/extensions/PanelBoxWidget/views/box.php +++ b/application/extensions/PanelBoxWidget/views/box.php @@ -1,18 +1,27 @@ -
-
> -
-

-
-
-
- > - - - +
+ +
> +
+
- -
diff --git a/application/extensions/admin/survey/ListSurveysWidget/views/listSurveys.php b/application/extensions/admin/survey/ListSurveysWidget/views/listSurveys.php index 42a9c713d65..e1463106cfa 100644 --- a/application/extensions/admin/survey/ListSurveysWidget/views/listSurveys.php +++ b/application/extensions/admin/survey/ListSurveysWidget/views/listSurveys.php @@ -79,7 +79,7 @@ 'header' => gT('Owner'), 'name' => 'owner', 'type' => 'raw', - 'value'=>'CHtml::link($data->owner->users_name, Yii::app()->createUrl("admin/survey/sa/view/",array("surveyid"=>$data->sid)))', + 'value'=>'CHtml::link(CHtml::encode($data->owner->users_name), Yii::app()->createUrl("admin/survey/sa/view/",array("surveyid"=>$data->sid)))', 'headerHtmlOptions'=>array('class' => 'hidden-md hidden-sm hidden-xs'), 'htmlOptions' => array('class' => 'hidden-md hidden-sm hidden-xs has-link'), ), diff --git a/application/extensions/captchaExtended/CHANGELOG b/application/extensions/captchaExtended/CHANGELOG new file mode 100644 index 00000000000..2c401770255 --- /dev/null +++ b/application/extensions/captchaExtended/CHANGELOG @@ -0,0 +1,16 @@ +Captcha Extended Change Log +=========================== + +Version 1.0.2 Sept 19, 2013 +--------------------------- +- bugfix: skip captcha counter incrementation if clientajax validation is turned on. Otherwise captcha code would be silently invalidated after entering as many form fields as the number of allowed captcha attempts. + +Version 1.0.1 July 01, 2012 +--------------------------- +- fixed client-side validation that generated incorrect validation hash + +Version 1.0.0 August 29, 2011 +---------------------------- +Initial release + +Please report bugs to lubosdz AT hotmail DOT com. diff --git a/application/extensions/captchaExtended/CaptchaExtendedAction.php b/application/extensions/captchaExtended/CaptchaExtendedAction.php new file mode 100644 index 00000000000..bd2b011787f --- /dev/null +++ b/application/extensions/captchaExtended/CaptchaExtendedAction.php @@ -0,0 +1,552 @@ + Yii::getPathOfAlias('ext.captchaExtended').DIRECTORY_SEPARATOR.'CaptchaExtendedAction.php', +* 'CaptchaExtendedValidator' => Yii::getPathOfAlias('ext.captchaExtended').DIRECTORY_SEPARATOR.'CaptchaExtendedValidator.php' +* )); +* } +* +* 3) Define action in controller, e.g. SiteController: +* +* public function actions(){ +* return array( +* 'captcha'=>array( +* 'class'=>'CaptchaExtendedAction', +* ), +* ); +* } +* +* 4) Define client validation in model::rules(): +* +* public function rules(){ +* return array( +* array('verifyCode', 'CaptchaExtendedValidator', 'allowEmpty'=>!CCaptcha::checkRequirements()), +* ); +* } +* +* 5) If needed, collect localized strings via CLI command "yiic message messages/config.php" and translate captcha related strings. +* +* 6) If needed, you can tune captcha modes and visibility options: +* - In "words" mode, you can place your own file [words.txt] or [words.yourlanguage.txt] +* - If needed, set the dots density [0-100], the number of through lines [0-] or fillSections [0-], font and background colors +* +* 7) Test & enjoy! +*/ +class CaptchaExtendedAction extends CCaptchaAction{ + + const + MODE_MATH = 'math', + MODE_MATHVERBAL = 'mathverbal', + MODE_DEFAULT = 'default', + MODE_LOGICAL = 'logical', + MODE_WORDS = 'words'; + + /** + * @var integer padding around the text. Defaults to 2. + */ + public $offset = 2; + + /** + * Captcha mode, supported values are [logical, words, mathverbal, math, default]. + * Default value is [default], which uses native frameworks implementation. + * Captcha mode examples: + * - logical e.g. min(5, one, 9) or max (two, three, 3) + * - words e.g. [localized random words] (supports translated strings in UTF-8 including latin2 and cyrillic) + * - mathverbal e.g. How much is 12 plus 8 ? + * - math e.g. 93 - 3 = + * - default e.g. random latin1 characters + */ + public $mode = self::MODE_DEFAULT; + + /** + * Path to the file to be used for generating random words in "words" mode + */ + public $fileWords; + + /** + * Dots density around characters 0 - 100 [%], defaults 5. + */ + public $density = 5; // dots density 0 - 100% + + /** + * The number of lines drawn through the generated captcha picture, default 3. + */ + public $lines = 3; + + /** + * The number of sections to be filled with random flood color, default 10. + */ + public $fillSections = 10; + + /** + * Run action + */ + public function run(){ + + if(!extension_loaded('mbstring')){ + throw new CHttpException(500, Yii::t('main','Missing extension "{ext}"', array('{ext}' => 'mbstring'))); + } + + // set font file with all extended UTF-8 characters + // Duality supplied with the framework does not support some extended characters like Å¡Äťžôäě... + $this->fontFile = dirname(__FILE__).'/fonts/nimbus.ttf'; + + // set captcha mode + $this->mode = strtolower($this->mode); + + // set image size + switch ($this->mode){ + case self::MODE_LOGICAL: + case self::MODE_WORDS: + $this->width = 300; + $this->height = 50; + break; + case self::MODE_MATHVERBAL: + $this->width = 400; + $this->height = 50; + break; + case self::MODE_MATH: + case self::MODE_DEFAULT: + default: + $this->width = 120; + $this->height = 50; + } + + if($this->mode == self::MODE_DEFAULT){ + // default framework implementation + parent::run(); + }else{ + // we hash result value rather than the displayed code + if(isset($_GET[self::REFRESH_GET_VAR])){ + $result=$this->getVerifyResult(true); + echo CJSON::encode(array( + 'hash1'=>$this->generateValidationHash($result), + 'hash2'=>$this->generateValidationHashCI($result), + 'url'=>$this->getController()->createUrl($this->getId(),array('v' => uniqid())), + )); + }else{ + $this->renderImage($this->getVerifyCode()); + } + } + Yii::app()->end(); + } + + /** + * Return hash for case insensitive result (converted to lowercase) + * @param string $result + */ + protected function generateValidationHashCI($result){ + $result = preg_replace('/\s/', '', $result); + $result = mb_convert_case($result, MB_CASE_LOWER, 'utf-8'); + $result = urlencode($result); + return $this->generateValidationHash($result); + } + + /** + * Generates a new verification code. + * @return string the generated verification code + */ + protected function generateVerifyCode(){ + switch (strtolower($this->mode)){ + case self::MODE_MATH: + return $this->getCodeMath(); + case self::MODE_MATHVERBAL: + return $this->getCodeMathVerbal(); + case self::MODE_LOGICAL: + return $this->getCodeLogical(); + case self::MODE_WORDS: + return $this->getCodeWords(); + case self::MODE_DEFAULT: + default: + $code = parent::generateVerifyCode(); + return array('code' => $code, 'result' => $code); + } + } + + /** + * Return code for random words from text file. + * First we'll try to load file for current language, like [words.de.txt] + * If not found, we will try to load generic file like [words.txt] + */ + protected function getCodeWords(){ + if($this->fileWords === null){ + // guess words file upon current language like [words.de.txt], [words.ru.txt] + $this->fileWords = dirname(__FILE__).DIRECTORY_SEPARATOR.'words.'.Yii::app()->language.'.txt'; + if(!is_file($this->fileWords)){ + // take fallback file without language specification + $this->fileWords = dirname(__FILE__).DIRECTORY_SEPARATOR.'words.txt'; + } + } + if(!file_exists($this->fileWords)){ + throw new CHttpException(500, Yii::t('main','File not found in "{path}"', array('{path}' => $this->fileWords))); + } + $words = file_get_contents($this->fileWords); + $words = explode(' ', $words); + $found = array(); + for($i=0;$ipurifyWord($w[0]); + if(strlen($w)>3){ + // accept only word with at least 3 characters + $found[] = $w; + if(strlen(implode('', $found))>10){ + // words must have at least 10 characters together + break; + } + } + } + $code = implode('', $found); // without whitespaces + return array('code' => $code, 'result' => $code); + } + + /** + * Return captcha word without dirty characters like *,/,{,},.. Retain diacritics if unicode supported. + * @param string $w The word to be purified + */ + protected function purifyWord($w){ + if(@preg_match('/\pL/u', 'a')){ + // unicode supported, we remove everything except for accented characters + $w = preg_replace('/[^\p{L}]/u', '', (string) $w); + }else{ + // Unicode is not supported. Cannot validate utf-8 characters, we keep only latin1 + $w = preg_replace('/[^a-zA-Z0-9]/','',$w); + } + return $w; + } + + /** + * Return code for math mode like 9+1= or 95-5= + */ + protected function getCodeMath(){ + $n2 = mt_rand(1,9); + if(mt_rand(1,100) > 50){ + $n1 = mt_rand(1,9)*10+$n2; + $code = $n1.'-'.$n2.'='; + $r = $n1-$n2; + }else{ + $n1 = mt_rand(1,10)*10-$n2; + $code = $n1.'+'.$n2.'='; + $r = $n1+$n2; + } + return array('code' => $code, 'result' => $r); + } + + /** + * Return numbers 0..9 translated into word + */ + protected static function getNumbers(){ + return array( + '0' => Yii::t('main','zero'), + '1' => Yii::t('main','one'), + '2' => Yii::t('main','two'), + '3' => Yii::t('main','three'), + '4' => Yii::t('main','four'), + '5' => Yii::t('main','five'), + '6' => Yii::t('main','six'), + '7' => Yii::t('main','seven'), + '8' => Yii::t('main','eight'), + '9' => Yii::t('main','nine'), + ); + } + + /** + * Return verbal representation for supplied number, like 1 => one + * @param int $n The number to be translated + */ + protected static function getNumber($n){ + static $nums; + if(empty($nums)){ + $nums = self::getNumbers(); + } + return array_key_exists($n, $nums) ? $nums[$n] : ''; + } + + /** + * Return code for logical formula like min(one,7,four) + */ + protected function getCodeLogical(){ + $t = mt_rand(2,4); + $a = array(); + for($i=0;$i<$t;++$i){ + // we dont use zero + $a[] = mt_rand(1,9); + } + if(mt_rand(0,1)){ + $r = max($a); + $code = array(); + for($i=0;$i30 ? self::getNumber($a[$i]) : $a[$i]; + } + $code = Yii::t('main','max').' ( '.implode(', ',$code).' )'; + }else{ + $r = min($a); + $code = array(); + for($i=0;$i30 ? self::getNumber($a[$i]) : $a[$i]; + } + $code = Yii::t('main','min').' ( '.implode(', ',$code).' )'; + } + return array('code' => $code, 'result' => $r); + } + + /** + * Return code for verbal math mode like "How much is 1 plus 1 ?" + */ + protected function getCodeMathVerbal(){ + $n2 = mt_rand(1,9); + if(mt_rand(1,100) > 50){ + switch(mt_rand(0,2)){ + case 0: + $op = Yii::t('main','minus'); + break; + case 1: + $op = Yii::t('main','deducted by'); + break; + case 2: + $op = '-'; + break; + } + $n1 = mt_rand(1,9)*10+$n2; + $code = $n1.' '.$op.' '. ( mt_rand(1,10)>3 ? self::getNumber($n2) : $n2); + $r = $n1-$n2; + }else{ + switch(mt_rand(0,2)){ + case 0: + $op = Yii::t('main','plus'); + break; + case 1: + $op = Yii::t('main','and'); + break; + case 2: + $op = '+'; + break; + } + $n1 = mt_rand(1,10)*10-$n2; + $code = $n1.' '.$op.' '.( mt_rand(1,10)>3 ? self::getNumber($n2) : $n2); + $r = $n1+$n2; + } + switch (mt_rand(0,2)){ + case 0: + $question = Yii::t('main','How much is'); + break; + case 1: + $question = Yii::t('main','What\'s result for'); + break; + case 2: + $question = Yii::t('main','Give result for'); + break; + } + + switch (mt_rand(0,2)){ + case 0: + $equal = '?'; + break; + case 1: + $equal = '='; + break; + case 2: + $equal = str_repeat('.', mt_rand(2,5)); + break; + } + + $code = $question.' '.$code.' '.$equal; + return array('code' => $code, 'result' => $r); + } + + + /** + * Validates the input to see if it matches the generated code. + * @param string $input user input + * @param boolean $caseSensitive whether the comparison should be case-sensitive + * @return whether the input is valid + */ + public function validate($input,$caseSensitive){ + // open session, if necessary generate new code + $this->getVerifyCode(); + // read result + $session = Yii::app()->session; + $name = $this->getSessionKey(); + $result = $session[$name . 'result']; + // input always taken without whitespaces + $input = preg_replace('/\s/','',$input); + $valid = $caseSensitive ? strcmp($input, $result)===0 : strcasecmp($input, $result)===0; + // increase attempts counter, but not in case of ajax-client validation (that is always POST request having variable 'ajax') + // otherwise captcha would be silently invalidated after entering the number of fields equaling to testlimit number + if(empty($_POST['ajax'])){ + $name = $this->getSessionKey() . 'count'; + $session[$name] = $session[$name] + 1; + if($valid || $session[$name] > $this->testLimit && $this->testLimit > 0){ + // generate new code also each time correctly entered + $this->getVerifyCode(true); + } + } + return $valid; + } + + /** + * Gets the verification code. + * @param boolean $regenerate whether the verification code should be regenerated. + * @return string the verification code. + */ + public function getVerifyCode($regenerate=false){ + if($this->fixedVerifyCode !== null){ + return $this->fixedVerifyCode; + } + $session = Yii::app()->session; + $session->open(); + $name = $this->getSessionKey(); + if(empty($session[$name]) || $regenerate){ + $code = $this->generateVerifyCode(); + $session[$name] = $code['code']; + $session[$name . 'result'] = $code['result']; + $session[$name . 'count'] = 1; + } + return $session[$name]; + } + + /** + * Return verification result expected by user + * @param bool $regenerate + */ + public function getVerifyResult($regenerate=false){ + if($this->fixedVerifyCode !== null){ + return $this->fixedVerifyCode; + } + $session = Yii::app()->session; + $session->open(); + $name = $this->getSessionKey(); + if(empty($session[$name . 'result']) || $regenerate){ + $code = $this->generateVerifyCode(); + $session[$name] = $code['code']; + $session[$name . 'result'] = $code['result']; + $session[$name . 'count'] = 1; + } + return $session[$name . 'result']; + } + + /** + * Renders the CAPTCHA image based on the code. + * @param string $code the verification code + * @return string image content + */ + protected function renderImage($code){ + + $image = imagecreatetruecolor($this->width,$this->height); + + $backColor = imagecolorallocate($image, + (int)($this->backColor % 0x1000000 / 0x10000), + (int)($this->backColor % 0x10000 / 0x100), + $this->backColor % 0x100); + imagefilledrectangle($image,0,0,$this->width,$this->height,$backColor); + imagecolordeallocate($image,$backColor); + + if($this->transparent){ + imagecolortransparent($image,$backColor); + } + + if($this->fontFile === null){ + $this->fontFile = dirname(__FILE__) . '/Duality.ttf'; + } + + $length = strlen($code); + $box = imagettfbbox(25,0,$this->fontFile,$code); + $w = $box[4] - $box[0] + $this->offset * ($length - 1); + $h = $box[1] - $box[5]; + $scale = min(($this->width - $this->padding * 2) / $w,($this->height - $this->padding * 2) / $h); + $x = 10; + $y = round($this->height * 27 / 40); + + $r = (int)($this->foreColor % 0x1000000 / 0x10000); + $g = (int)($this->foreColor % 0x10000 / 0x100); + $b = $this->foreColor % 0x100; + $foreColor = imagecolorallocate($image, mt_rand($r-50,$r+50), mt_rand($g-50,$g+50),mt_rand($b-50,$b+50)); + + for($i = 0; $i < $length; ++$i){ + $fontSize = (int)(rand(26,32) * $scale * 0.8); + $angle = rand(-10,10); + $letter = $code[$i]; + + // UTF-8 characters above > 127 are stored in two bytes + if(ord($letter)>127){ + ++$i; + $letter .= $code[$i]; + } + + // randomize font color + if(mt_rand(0,10)>7){ + $foreColor = imagecolorallocate($image, mt_rand($r-50,$r+50), mt_rand($g-50,$g+50),mt_rand($b-50,$b+50)); + } + + $box = imagettftext($image,$fontSize,$angle,$x,$y,$foreColor,$this->fontFile,$letter); + $x = $box[2] + $this->offset; + } + + // add density dots + $this->density = intval($this->density); + if($this->density > 0){ + $length = intval($this->width*$this->height/100*$this->density); + $c = imagecolorallocate($image, mt_rand(0,255), mt_rand(0,255), mt_rand(0,255)); + for($i=0;$i<$length;++$i){ + $x = mt_rand(0,$this->width); + $y = mt_rand(0,$this->height); + imagesetpixel($image, $x, $y, $c); + } + } + + // add lines + $this->lines = intval($this->lines); + if($this->lines > 0){ + for($i=0; $i<$this->lines; ++$i){ + imagesetthickness($image, mt_rand(1,2)); + // gray lines only to save human eyes:-) + $c = imagecolorallocate($image, mt_rand(200,255), mt_rand(200,255), mt_rand(200,255)); + $x = mt_rand(0, $this->width); + $y = mt_rand(0, $this->width); + imageline($image, $x, 0, $y, $this->height, $c); + } + } + + // filled flood section + $this->fillSections = intval($this->fillSections); + if($this->fillSections > 0){ + for($i = 0; $i < $this->fillSections; ++$i){ + $c = imagecolorallocate($image, mt_rand(200,255), mt_rand(200,255), mt_rand(200,255)); + $x = mt_rand(0, $this->width); + $y = mt_rand(0, $this->width); + imagefill($image, $x, $y, $c); + } + } + + imagecolordeallocate($image,$foreColor); + + header('Pragma: public'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Content-Transfer-Encoding: binary'); + header("Content-type: image/png"); + imagepng($image); + imagedestroy($image); + } + +} \ No newline at end of file diff --git a/application/extensions/captchaExtended/CaptchaExtendedValidator.php b/application/extensions/captchaExtended/CaptchaExtendedValidator.php new file mode 100644 index 00000000000..49d122830fc --- /dev/null +++ b/application/extensions/captchaExtended/CaptchaExtendedValidator.php @@ -0,0 +1,65 @@ +getCaptchaAction(); + + if($captcha->mode == CaptchaExtendedAction::MODE_DEFAULT){ + // default framework implementation + return parent::clientValidateAttribute($object,$attribute); + } + + $message=$this->message!==null ? $this->message : Yii::t('main','The verification code "{attribute}" is incorrect.'); + $message=strtr($message, array( + '{attribute}'=>$object->getAttributeLabel($attribute), + )); + + $result=$captcha->getVerifyResult(); + // remove whitespaces + $result = preg_replace('/\s/', '', $result); + + if(!$this->caseSensitive){ + $result = mb_convert_case($result, MB_CASE_LOWER, 'utf-8'); + } + $result = urlencode($result); + $hash=$captcha->generateValidationHash($result); + + $js=" +var hash = $('body').data('{$this->captchaAction}.hash'); +if(hash == null){ + hash = $hash; +}else{ + hash = hash[".($this->caseSensitive ? 0 : 1)."]; +} +value = value.replace(/\\s/g,''); +".($this->caseSensitive ? '' : 'value = value.toLowerCase();')." +value = encodeURIComponent(value); +for(var i=value.length-1, h=0; i >= 0; --i){ + h+=value.charCodeAt(i); +} +if(h != hash) { + messages.push(".CJSON::encode($message)."); +} +"; + if($this->allowEmpty){ + $js=" +if(value!=''){ + $js +} +"; + } + return $js; + } + +} \ No newline at end of file diff --git a/application/extensions/captchaExtended/LICENSE b/application/extensions/captchaExtended/LICENSE new file mode 100644 index 00000000000..5d5e8b2aa8b --- /dev/null +++ b/application/extensions/captchaExtended/LICENSE @@ -0,0 +1,6 @@ +Captcha Extended is free software. +That means you can freely use it for private and/or commercial purposes, +modify the code or use it in third party application. +You are not obliged to retain any copyrights from original author. +---------------------------------- + diff --git a/application/extensions/captchaExtended/README b/application/extensions/captchaExtended/README new file mode 100644 index 00000000000..51691892505 --- /dev/null +++ b/application/extensions/captchaExtended/README @@ -0,0 +1,65 @@ +Captcha Extended +================ + +Captcha Extended is an extension written for Yii framework. +It enhances original captcha code delivered along with the framework. + +Features +======== +- supports modes: logical, words, mathverbal, math, default +- supports extended characters latin1, latin2 (utf-8) including middle- east- european and cyrillyc characters +- implements masking elements: dots density, through lines, fillSections, font color varying. + +INSTALLATION +============ + +1) Unzip CaptchaExtended.zip files into ../protected/extensions/captchaExtended/*.* + +2) Register class paths to [CaptchaExtendedAction] and [CaptchaExtendedValidator], e.g. in components/controller.php: + + public function init(){ + // register class paths for extension captcha extended + Yii::$classMap = array_merge( Yii::$classMap, array( + 'CaptchaExtendedAction' => Yii::getPathOfAlias('ext.captchaExtended').DIRECTORY_SEPARATOR.'CaptchaExtendedAction.php', + 'CaptchaExtendedValidator' => Yii::getPathOfAlias('ext.captchaExtended').DIRECTORY_SEPARATOR.'CaptchaExtendedValidator.php' + )); + } + +3) Define action in controller, e.g. SiteController: + + public function actions(){ + return array( + 'captcha'=>array( + 'class'=>'CaptchaExtendedAction', + ), + ); + } + +4) Define client validation in model::rules(): + + public function rules(){ + return array( + array('verifyCode', 'CaptchaExtendedValidator', 'allowEmpty'=>!CCaptcha::checkRequirements()), + ); + } + +5) If needed, collect localized strings via CLI command "yiic message messages/config.php" and translate captcha related strings. + +6) If needed, you can tune captcha modes and visibility options: + - In "words" mode, you can place your own file [words.txt] or [words.yourlanguage.txt] + - If needed, you can .. + -> set the dots density [0-100], + -> the number of through lines [0-] + -> the number of fillSections [0-], + -> font and background colors + +7) Test & enjoy! + +============================= + +Please report bug to lubosdz AT hotmail DOT com. + +Thanx +Lubos +29/08/2011 +Bratislava, Slovakia \ No newline at end of file diff --git a/application/extensions/captchaExtended/fonts/nimbus.ttf b/application/extensions/captchaExtended/fonts/nimbus.ttf new file mode 100644 index 00000000000..309c0a23364 Binary files /dev/null and b/application/extensions/captchaExtended/fonts/nimbus.ttf differ diff --git a/application/extensions/captchaExtended/fonts/readme.txt b/application/extensions/captchaExtended/fonts/readme.txt new file mode 100644 index 00000000000..b4f1e874319 --- /dev/null +++ b/application/extensions/captchaExtended/fonts/readme.txt @@ -0,0 +1,173 @@ +Fonts: + +******************************************************************************* +Nimbus Sans L regular +"nimbus.ttf" - An "arial"-look-alike font. If you want to use the real Arial +font you should upload the arial-normal ttf file from your Windows system +(fonts/arial.ttf). +******************************************************************************* + +License (t3lib/fonts/nimbus.ttf): + +nimbus.ttf was downloaded as n019003l.ttf from +. +nimbus.sfd.gz was downladed as NimbusSansL-Regu.sfd from + + + Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; + Cyrillic glyphs added by Valek Filippov (C) 2001-2002 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + 02110-1301, USA. + + + +******************************************************************************* +Bitstream Vera Sans +"vera.ttf" - A "verdana"-look-alike font. If you want to use the real Verdana +font you should upload the verdana-normal ttf file from your Windows system +(fonts/verdana.ttf). +******************************************************************************* + +This file was downloaded from . + +Copyright Holder: Bitstream, Inc. + +License (t3lib/fonts/vera.ttf): + +Bitstream Vera Fonts Copyright + +The fonts have a generous copyright, allowing derivative works (as +long as "Bitstream" or "Vera" are not in the names), and full +redistribution (so long as they are not *sold* by themselves). They +can be be bundled, redistributed and sold with any software. + +The fonts are distributed under the following copyright: + +Copyright +========= + +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream +Vera is a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the fonts accompanying this license ("Fonts") and associated +documentation files (the "Font Software"), to reproduce and distribute +the Font Software, including without limitation the rights to use, +copy, merge, publish, distribute, and/or sell copies of the Font +Software, and to permit persons to whom the Font Software is furnished +to do so, subject to the following conditions: + +The above copyright and trademark notices and this permission notice +shall be included in all copies of one or more of the Font Software +typefaces. + +The Font Software may be modified, altered, or added to, and in +particular the designs of glyphs or characters in the Fonts may be +modified and additional glyphs or characters may be added to the +Fonts, only if the fonts are renamed to names not containing either +the words "Bitstream" or the word "Vera". + +This License becomes null and void to the extent applicable to Fonts +or Font Software that has been modified and is distributed under the +"Bitstream Vera" names. + +The Font Software may be sold as part of a larger software package but +no copy of one or more of the Font Software typefaces may be sold by +itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL +BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, +OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT +SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome +Foundation, and Bitstream Inc., shall not be used in advertising or +otherwise to promote the sale, use or other dealings in this Font +Software without prior written authorization from the Gnome Foundation +or Bitstream Inc., respectively. For further information, contact: +fonts at gnome dot org. + +Copyright FAQ +============= + + 1. I don't understand the resale restriction... What gives? + + Bitstream is giving away these fonts, but wishes to ensure its + competitors can't just drop the fonts as is into a font sale system + and sell them as is. It seems fair that if Bitstream can't make money + from the Bitstream Vera fonts, their competitors should not be able to + do so either. You can sell the fonts as part of any software package, + however. + + 2. I want to package these fonts separately for distribution and + sale as part of a larger software package or system. Can I do so? + + Yes. A RPM or Debian package is a "larger software package" to begin + with, and you aren't selling them independently by themselves. + See 1. above. + + 3. Are derivative works allowed? + Yes! + + 4. Can I change or add to the font(s)? + Yes, but you must change the name(s) of the font(s). + + 5. Under what terms are derivative works allowed? + + You must change the name(s) of the fonts. This is to ensure the + quality of the fonts, both to protect Bitstream and Gnome. We want to + ensure that if an application has opened a font specifically of these + names, it gets what it expects (though of course, using fontconfig, + substitutions could still could have occurred during font + opening). You must include the Bitstream copyright. Additional + copyrights can be added, as per copyright law. Happy Font Hacking! + + 6. If I have improvements for Bitstream Vera, is it possible they might get + adopted in future versions? + + Yes. The contract between the Gnome Foundation and Bitstream has + provisions for working with Bitstream to ensure quality additions to + the Bitstream Vera font family. Please contact us if you have such + additions. Note, that in general, we will want such additions for the + entire family, not just a single font, and that you'll have to keep + both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add + glyphs to the font, they must be stylistically in keeping with Vera's + design. Vera cannot become a "ransom note" font. Jim Lyles will be + providing a document describing the design elements used in Vera, as a + guide and aid for people interested in contributing to Vera. + + 7. I want to sell a software package that uses these fonts: Can I do so? + + Sure. Bundle the fonts with your software and sell your software + with the fonts. That is the intent of the copyright. + + 8. If applications have built the names "Bitstream Vera" into them, + can I override this somehow to use fonts of my choosing? + + This depends on exact details of the software. Most open source + systems and software (e.g., Gnome, KDE, etc.) are now converting to + use fontconfig (see www.fontconfig.org) to handle font configuration, + selection and substitution; it has provisions for overriding font + names and subsituting alternatives. An example is provided by the + supplied local.conf file, which chooses the family Bitstream Vera for + "sans", "serif" and "monospace". Other software (e.g., the XFree86 + core server) has other mechanisms for font substitution. + diff --git a/application/extensions/captchaExtended/words.de.txt b/application/extensions/captchaExtended/words.de.txt new file mode 100644 index 00000000000..e351f8fcb77 --- /dev/null +++ b/application/extensions/captchaExtended/words.de.txt @@ -0,0 +1,5 @@ +Nachfolgend finden Sie eine Liste sämtlicher Zeitungen mit Aktivitäten im Internet. +Mit Hilfe der nebenstehenden Gliederung gelangen Sie von jeder Zeitungspage per Klick auf die von Ihnen gewählte Ãœbersicht. +Falls Sie auf unserer Liste ein Blatt vermissen oder überflüssig finden, können Sie uns dies gern in Form einer E-Mail mitteilen. +Sie können uns auch gern Ihre Erfahrungen bei diesbezüglichen "Reisen" im Netz mitteilen. +Sagen Sie uns bitte auch Ihre Meinung zu Online-Zeitungen. Wünschen und Kritik stehen wir aufgeschlossen gegenüber. \ No newline at end of file diff --git a/application/extensions/captchaExtended/words.en.txt b/application/extensions/captchaExtended/words.en.txt new file mode 100644 index 00000000000..bb80e1c1baa --- /dev/null +++ b/application/extensions/captchaExtended/words.en.txt @@ -0,0 +1,5 @@ +North Carolina and Virginia dealt with widespread power outages, flooding, deaths and damage Saturday as +Hurricane Irene continued its northward trek along the East Coast, with Norfolk, Virginia, and the Hampton Roads +area next in its sights. +Nearly 1 million power customers were without electricity in North Carolina and Virginia because of the storm +Saturday afternoon, according to state and utility reports. More than a million people had evacuated from New Jersey alone. \ No newline at end of file diff --git a/application/extensions/captchaExtended/words.ru.txt b/application/extensions/captchaExtended/words.ru.txt new file mode 100644 index 00000000000..ea2360d5b32 --- /dev/null +++ b/application/extensions/captchaExtended/words.ru.txt @@ -0,0 +1,4 @@ +Ðевыполнение РоÑÑией контракта на поÑтавку Ирану получило дальнейшее развитие. +ИÑламÑÐºÐ°Ñ Ð ÐµÑпублика решила обратитьÑÑ Ð² международный Ñуд. Ðекоторые ÑкÑперты обращают внимание и на то, +что Ñтали пробукÑовывать и выгодные проекты в нефтегазовой Ñфере. +Ситуацию Ð´Ð»Ñ "Правды.Ру" комментируют ÑкÑперты \ No newline at end of file diff --git a/application/extensions/captchaExtended/words.sk.txt b/application/extensions/captchaExtended/words.sk.txt new file mode 100644 index 00000000000..8e8302393c5 --- /dev/null +++ b/application/extensions/captchaExtended/words.sk.txt @@ -0,0 +1,7 @@ +Prichádza výťah, nastúpite, stlaÄíte trojku, kabína sa zatrasie a zastane. Neviete, Äi ste sa pohli, len si utierate pot z Äela. +Vysoké teploty dokážu ÄasÅ¥ výťahov vyradiÅ¥ z prevádzky. „Bolo tam minimálne Å¡tyridsaÅ¥ stupňov, ak nie viac. Za tri minúty som bol kompletne spotený, je to taká malá sauniÄka,“ hovorí BratislavÄan Martin. Vo výťahu bratislavského bizniscentra na Lazaretskej ulici strávil v pondelok desiatky minút, chcel sa odviesÅ¥ jedno poschodie. +„NaÅ¡Å¥astie som nebol na medziposchodí, Äo som ani netuÅ¡il a mohol som vystúpiÅ¥. Dvere sme vypáÄili násilím.“ Profesionálna záchranka priÅ¡la asi desaÅ¥ minút po jeho vyslobodení. +Dodávateľ výťahov limity priznáva. „Definujeme, že výťahová Å¡achta by mala pracovaÅ¥ v teplotnom rozmedzí od päť stupňov do Å¡tyridsaÅ¥,“ povedal Peter Ondrík zo spoloÄnosti Schindler. +Teplotu má zabezpeÄiÅ¥ správca budovy. „Ak sa to nestane, môžu nastaÅ¥ nejaké poruchy, za to je zodpovedná stavba,“ hovorí Ondrík. Výťah by sa v extrémnej teplote mal vypnúť, nie vždy sa to podarí. + + diff --git a/application/extensions/captchaExtended/words.txt b/application/extensions/captchaExtended/words.txt new file mode 100644 index 00000000000..403b8c9b407 --- /dev/null +++ b/application/extensions/captchaExtended/words.txt @@ -0,0 +1,6 @@ +We choose to do "Hello World" testing mainly to achieve our goal, i.e., to find out the minimal overhead of each framework. +Many people complain that the "Hello World" application is meaningless because a real world application often needs to deal +with more complex tasks, such as database queries. This is not very true. In reality, especially in a large scale Web 2.0 application, +we often encounter scenarios that are very close to "Hello World". For example, an application may need to respond to an AJAX request +that should return the current server timestamp; a page has a large portion of its content being cached and an application just needs to +fetch the cached content and display it. \ No newline at end of file diff --git a/application/favicon.ico b/application/favicon.ico index 5b07b8621d3..a3b07f24137 100644 Binary files a/application/favicon.ico and b/application/favicon.ico differ diff --git a/application/helpers/ClassFactory.php b/application/helpers/ClassFactory.php index 23dd3b98ccd..37b722345dd 100644 --- a/application/helpers/ClassFactory.php +++ b/application/helpers/ClassFactory.php @@ -43,4 +43,3 @@ public static function registerClass($prefix, $baseClass) } } } -?> \ No newline at end of file diff --git a/application/helpers/Hash.php b/application/helpers/Hash.php index caf29886aac..a718106ad56 100644 --- a/application/helpers/Hash.php +++ b/application/helpers/Hash.php @@ -100,6 +100,7 @@ public static function extract(array $data, $path) { if (strpos($path, '[') === false) { $tokens = explode('.', $path); } else { + // FIXME ! $tokens = String::tokenize($path, '.', '[', ']'); } @@ -386,7 +387,7 @@ public static function combine(array $data, $keyPath, $valuePath = null, $groupP * @param array $data Source array from which to extract the data * @param string $paths An array containing one or more Hash::extract()-style key paths * @param string $format Format string into which values will be inserted, see sprintf() - * @return array An array of strings extracted from `$path` and formatted with `$format` + * @return array|null An array of strings extracted from `$path` and formatted with `$format` * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::format * @see sprintf() * @see Hash::extract() @@ -396,7 +397,7 @@ public static function format(array $data, array $paths, $format) { $count = count($paths); if (!$count) { - return; + return null; } for ($i = 0; $i < $count; $i++) { diff --git a/application/helpers/SurveyRuntimeHelper.php b/application/helpers/SurveyRuntimeHelper.php index 81e53d705b1..447bb8262ab 100644 --- a/application/helpers/SurveyRuntimeHelper.php +++ b/application/helpers/SurveyRuntimeHelper.php @@ -87,11 +87,10 @@ public function run($surveyid,$args) { // Survey settings $this->setSurveySettings( $surveyid, $args); + // Start rendering $this->makeLanguageChanger(); // language changer can be used on any entry screen, so it must be set first - extract($args); - $this->param = $param; /////////////////////////////////////////////////////////// // 1: We check if token and/or captcha form shouls be shown @@ -165,7 +164,7 @@ public function run($surveyid,$args) //Get the answers/inputnames // TMSW - can content of retrieveAnswers() be provided by LEM? Review scope of what it provides. // TODO - retrieveAnswers is slow - queries database separately for each question. May be fixed in _CI or _YII ports, so ignore for now - list($plus_qanda, $plus_inputnames) = retrieveAnswers($ia, $this->iSurveyid); + list($plus_qanda, $plus_inputnames) = retrieveAnswers($ia); if ($plus_qanda){ $plus_qanda[] = $ia[4]; @@ -244,17 +243,6 @@ public function run($surveyid,$args) Yii::app()->loadHelper('surveytranslator'); - // Set Langage // TODO remove one of the Yii::app()->session see bug #5901 - if (Yii::app()->session['survey_'.$this->iSurveyid]['s_lang'] ){ - $languagecode = Yii::app()->session['survey_'.$this->iSurveyid]['s_lang']; - }elseif ($this->iSurveyid && Survey::model()->findByPk($this->iSurveyid)){ - $languagecode = Survey::model()->findByPk($this->iSurveyid)->language; - }else{ - $languagecode = Yii::app()->getConfig('defaultlang'); - } - - $this->aSurveyInfo['languagecode'] = $languagecode; - $this->aSurveyInfo['dir'] = (getLanguageRTL($languagecode))?"rtl":"ltr"; $this->aSurveyInfo['upload_file'] = $upload_file; $hiddenfieldnames = $this->aSurveyInfo['hiddenfieldnames'] = implode("|", $inputnames); @@ -565,7 +553,7 @@ private function setArgs() //THE FOLLOWING DEALS WITH SUBMITTING ANSWERS AND COMPLETING AN ACTIVE SURVEY //don't use cookies if tokens are being used - if ($this->aSurveyInfo['active'] == "Y"){ + if (!empty($this->aSurveyInfo['active']) && $this->aSurveyInfo['active'] == "Y"){ global $tokensexist; if ($this->aSurveyInfo['usecookie'] == "Y" && $tokensexist != 1) { setcookie("LS_" . $this->iSurveyid . "_STATUS", "COMPLETE", time() + 31536000); //Cookie will expire in 365 days @@ -786,8 +774,6 @@ private function setMoveResult() { // retrieve datas from local variable - $this->aMoveResult = false; - if (isset($_SESSION[$this->LEMsessid]['LEMtokenResume'])){ LimeExpressionManager::StartSurvey($this->aSurveyInfo['sid'], $this->sSurveyMode, $this->aSurveyOptions, false, $this->LEMdebugLevel); @@ -1023,7 +1009,7 @@ private function moveSubmitIfNeeded() //Check for assessments if ($this->aSurveyInfo['assessments'] == "Y"){ $this->aSurveyInfo['aAssessments']['show'] = true; - $this->aSurveyInfo['aAssessments'] = doAssessment($this->iSurveyid, true); + $this->aSurveyInfo['aAssessments'] = doAssessment($this->iSurveyid); } $redata = compact(array_keys(get_defined_vars())); @@ -1046,7 +1032,7 @@ private function moveSubmitIfNeeded() $this->aSurveyInfo['aAssessments']['show'] = false; if ($this->aSurveyInfo['assessments'] == "Y"){ $this->aSurveyInfo['aAssessments']['show'] = true; - $this->aSurveyInfo['aAssessments'] = doAssessment($this->iSurveyid, true); + $this->aSurveyInfo['aAssessments'] = doAssessment($this->iSurveyid); } // End text @@ -1148,6 +1134,7 @@ private function moveSubmitIfNeeded() private function setVarFromArgs($args) { extract($args); + $this->param = $param; // Todo: check which ones are really needed $this->LEMskipReprocessing = isset( $LEMskipReprocessing )?$LEMskipReprocessing :null ; @@ -1192,8 +1179,8 @@ public function setJavascriptVar($iSurveyId='') /** * Construction of replacement array, actually doing it with redata * - * @param $aQuestionQanda : array from qanda helper - * @return aray of replacement for question.psptl + * @param array $aQuestionQanda : array from qanda helper + * @return array of replacement for question.psptl **/ public static function getQuestionReplacement($aQuestionQanda) { @@ -1293,7 +1280,7 @@ public static function getQuestionReplacement($aQuestionQanda) /* Add the relevance class */ if (!$lemQuestionInfo['relevant']) { - $aQuestionClass[]='ls-unrelevant'; + $aQuestionClass[]='ls-irrelevant'; $aQuestionClass[]='ls-hidden'; } if ($lemQuestionInfo['hidden']){ /* Can use aQuestionAttributes too */ @@ -1648,7 +1635,7 @@ private function setSurveySettings( $surveyid, $args ) extract($args); $this->LEMsessid = 'survey_' . $this->iSurveyid; - $this->aSurveyInfo = (!$thissurvey)?getSurveyInfo($this->iSurveyid):$thissurvey; + $this->aSurveyInfo = getSurveyInfo($this->iSurveyid); $this->aSurveyInfo['surveyUrl'] = App()->createUrl("/survey/index",array("sid"=>$this->iSurveyid)); // TODO: check this: @@ -1673,6 +1660,7 @@ private function setPreview() } if ($this->sSurveyMode == 'group' && $this->previewgrp){ + // FIXME $param not defined $_gid = sanitize_int($param['gid']); LimeExpressionManager::StartSurvey($this->aSurveyInfo['sid'], 'group', $this->aSurveyOptions, false, $this->LEMdebugLevel); @@ -1697,11 +1685,15 @@ private function setPreview() $groupdescription = $this->groupdescription = $this->aStepInfo['gtext']; }elseif($this->sSurveyMode == 'question' && $this->previewquestion){ - $_qid = sanitize_int($param['qid']); - LimeExpressionManager::StartSurvey($this->iSurveyid, 'question', $this->aSurveyOptions, false, $this->LEMdebugLevel); - $qSec = LimeExpressionManager::GetQuestionSeq($_qid); - $this->aMoveResult= LimeExpressionManager::JumpTo($qSec+1,true,false,true); - $this->aStepInfo = LimeExpressionManager::GetStepIndexInfo($this->aMoveResult['seq']); + /** + FIXME $param not defined + */ + $_qid = sanitize_int($param['qid']); + + LimeExpressionManager::StartSurvey($this->iSurveyid, 'question', $this->aSurveyOptions, false, $this->LEMdebugLevel); + $qSec = LimeExpressionManager::GetQuestionSeq($_qid); + $this->aMoveResult= LimeExpressionManager::JumpTo($qSec+1,true,false,true); + $this->aStepInfo = LimeExpressionManager::GetStepIndexInfo($this->aMoveResult['seq']); } } diff --git a/application/helpers/Zend/Server/Definition.php b/application/helpers/Zend/Server/Definition.php index 7e278f34a77..0eb699be34f 100644 --- a/application/helpers/Zend/Server/Definition.php +++ b/application/helpers/Zend/Server/Definition.php @@ -146,7 +146,7 @@ public function hasMethod($method) * Get a given method definition * * @param string $method - * @return null|Zend_Server_Method_Definition + * @return bool|null|Zend_Server_Method_Definition */ public function getMethod($method) { diff --git a/application/helpers/Zend/XmlRpc/Generator/GeneratorAbstract.php b/application/helpers/Zend/XmlRpc/Generator/GeneratorAbstract.php index a3e196c244a..02e52196c23 100644 --- a/application/helpers/Zend/XmlRpc/Generator/GeneratorAbstract.php +++ b/application/helpers/Zend/XmlRpc/Generator/GeneratorAbstract.php @@ -50,7 +50,7 @@ public function __construct($encoding = 'UTF-8') * * @param string $name XML tag name * @param string $value Optional value of the XML tag - * @return Zend_XmlRpc_Generator_Abstract Fluent interface + * @return self Fluent interface */ public function openElement($name, $value = null) { @@ -68,7 +68,7 @@ public function openElement($name, $value = null) * Method marks the end of an XML element * * @param string $name XML tag name - * @return Zend_XmlRpc_Generator_Abstract Fluent interface + * @return self Fluent interface */ public function closeElement($name) { diff --git a/application/helpers/Zend/XmlRpc/Generator/XmlWriter.php b/application/helpers/Zend/XmlRpc/Generator/XmlWriter.php index b3c070b5bb6..e1a9b213e26 100644 --- a/application/helpers/Zend/XmlRpc/Generator/XmlWriter.php +++ b/application/helpers/Zend/XmlRpc/Generator/XmlWriter.php @@ -76,7 +76,7 @@ protected function _writeTextData($text) * Close an previously opened XML element * * @param string $name - * @return void + * @return self */ protected function _closeElement($name) { diff --git a/application/helpers/Zend/XmlRpc/Server.php b/application/helpers/Zend/XmlRpc/Server.php index d02f6b06bc8..f9accb02892 100644 --- a/application/helpers/Zend/XmlRpc/Server.php +++ b/application/helpers/Zend/XmlRpc/Server.php @@ -164,7 +164,6 @@ class Zend_XmlRpc_Server extends Zend_Server_Abstract 'dateTime.iso8601' => 'dateTime.iso8601', 'date' => 'dateTime.iso8601', 'time' => 'dateTime.iso8601', - 'time' => 'dateTime.iso8601', 'Zend_Date' => 'dateTime.iso8601', 'DateTime' => 'dateTime.iso8601', 'array' => 'array', diff --git a/application/helpers/Zend/XmlRpc/Value/Collection.php b/application/helpers/Zend/XmlRpc/Value/Collection.php index 61c20c99034..4fcaa815736 100644 --- a/application/helpers/Zend/XmlRpc/Value/Collection.php +++ b/application/helpers/Zend/XmlRpc/Value/Collection.php @@ -59,7 +59,7 @@ public function __construct($value) /** * Return the value of this object, convert the XML-RPC native collection values into a PHP array * - * @return arary + * @return array */ public function getValue() { diff --git a/application/helpers/admin/activate_helper.php b/application/helpers/admin/activate_helper.php index 544ef192d46..1bd8871ac92 100644 --- a/application/helpers/admin/activate_helper.php +++ b/application/helpers/admin/activate_helper.php @@ -107,7 +107,7 @@ function checkGroup($postsid) * checks questions in a survey for consistency * @param integer $postsid * @param integer $iSurveyID -* @return array $faildcheck +* @return array|bool $faildcheck */ function checkQuestions($postsid, $iSurveyID, $qtypes) { @@ -426,7 +426,7 @@ function activateSurvey($iSurveyID, $simulate = false) } if ($simulate){ - return array('dbengine'=>$CI->db->databasetabletype, 'dbtype'=>Yii::app()->db->driverName, 'fields'=>$arrSim); + return array('dbengine'=>Yii::app()->db->getDriverName(), 'dbtype'=>Yii::app()->db->driverName, 'fields'=>$arrSim); } // If last question is of type MCABCEFHP^QKJR let's get rid of the ending coma in createsurvey diff --git a/application/helpers/admin/ajax_helper.php b/application/helpers/admin/ajax_helper.php index 545a374f271..233e66ea109 100644 --- a/application/helpers/admin/ajax_helper.php +++ b/application/helpers/admin/ajax_helper.php @@ -14,7 +14,7 @@ class AjaxHelper { /** - * As createAbsoluteUrl, but appends param ajax = 1 to url + * As Yii createUrl, but appends param ajax = 1 to url * Use when creating Ajax action links, like button clicks that * will open modals or save data. * @param string $route @@ -24,7 +24,7 @@ class AjaxHelper public static function createUrl($route, array $params = array()) { $params['ajax'] = 1; - return App()->createAbsoluteUrl($route, $params); + return App()->createUrl($route, $params); } /** * Echoes json with result set as $msg @@ -83,8 +83,7 @@ public static function outputNotLoggedIn() /** * Echo $str with json header - * @param string str - * @param JsonOutput $str + * @param string $str * @return void */ private static function echoString($str) diff --git a/application/helpers/admin/export/FormattingOptions.php b/application/helpers/admin/export/FormattingOptions.php index 414dc8e207d..73bbe307424 100644 --- a/application/helpers/admin/export/FormattingOptions.php +++ b/application/helpers/admin/export/FormattingOptions.php @@ -49,14 +49,14 @@ class FormattingOptions /** * Indicates whether to use Expression Manager code * - * @var bolean + * @var boolean */ public $useEMCode; /** * What is the caracters to separate code and text * - * @var bolean + * @var boolean */ public $headCodeTextSeparator; diff --git a/application/helpers/admin/export/HtmlWriter.php b/application/helpers/admin/export/HtmlWriter.php index 0029a0a4bcc..9ddb09ab55c 100644 --- a/application/helpers/admin/export/HtmlWriter.php +++ b/application/helpers/admin/export/HtmlWriter.php @@ -47,7 +47,7 @@ protected function writeHeader() $this->openTag('head'); $this->tag('meta', array('charset' => 'utf-8')); $this->tag('style', 'td { border: 1px solid black }'); - $this->closeTag('head'); + $this->closeTag(); $this->openTag('body'); // Title of the survey. $this->tag('h1', array( @@ -111,20 +111,19 @@ protected function openTag($tag, $options = array()) } /** - * Renders a question and recurses into subquestions. - * @param type $question + * Renders a question and recurses into sub-questions. + * @param Question $question */ protected function renderQuestion($question, $value, $header) { - if (isset($value) && strlen($value) > 0) - { + if (isset($value) && strlen($value) > 0) { $this->openTag('tr', array( 'data-qid' => $question['qid'], 'class' => 'question' )); - $this->tag('td', $header); - $this->tag('td', $value); + $this->tag('td', $header); + $this->tag('td', $value); $this->closeTag(); } } @@ -167,5 +166,3 @@ public function close() fclose($this->handle); } } - -?> diff --git a/application/helpers/admin/export/IWriter.php b/application/helpers/admin/export/IWriter.php index 6eb9ec61923..487a6f9a5cb 100644 --- a/application/helpers/admin/export/IWriter.php +++ b/application/helpers/admin/export/IWriter.php @@ -8,7 +8,7 @@ interface IWriter * See Survey and SurveyDao objects for information on loading a survey * and results from the database. * - * @param Survey $survey + * @param SurveyObj $survey * @param string $sLanguageCode * @param FormattingOptions $oOptions */ diff --git a/application/helpers/admin/export/SurveyDao.php b/application/helpers/admin/export/SurveyDao.php index 9051ae6d84f..f640e054f4e 100644 --- a/application/helpers/admin/export/SurveyDao.php +++ b/application/helpers/admin/export/SurveyDao.php @@ -37,7 +37,7 @@ public function loadSurveyById($id, $lang = null) if (empty($intId)) { //The id given to us is not an integer, croak. - safeDie("An invalid survey ID was encountered: $sid"); + safeDie("An invalid survey ID was encountered"); } //Load groups diff --git a/application/helpers/admin/export/Writer.php b/application/helpers/admin/export/Writer.php index 1234d9d7444..3d1954292aa 100644 --- a/application/helpers/admin/export/Writer.php +++ b/application/helpers/admin/export/Writer.php @@ -9,6 +9,7 @@ abstract class Writer implements IWriter { protected $sLanguageCode; + /** @var Translator $translator */ protected $translator; public $filename; public $webfilename; diff --git a/application/helpers/admin/exportresults_helper.php b/application/helpers/admin/exportresults_helper.php index 2b75f4cd824..d1532950d36 100644 --- a/application/helpers/admin/exportresults_helper.php +++ b/application/helpers/admin/exportresults_helper.php @@ -48,16 +48,18 @@ class ExportSurveyResultsService * @var array */ protected $_exports; - + /** - * Root function for any export results action - * - * @param mixed $iSurveyId - * @param mixed $sLanguageCode - * @param csv|doc|pdf|xls $sExportPlugin Type of export - * @param FormattingOptions $oOptions - * @param string $sFilter - */ + * Root function for any export results action + * + * @param mixed $iSurveyId + * @param mixed $sLanguageCode + * @param string $sExportPlugin Type of export + * @param FormattingOptions $oOptions + * @param string $sFilter + * @return + * @throws Exception + */ function exportSurvey($iSurveyId, $sLanguageCode, $sExportPlugin, FormattingOptions $oOptions, $sFilter = '') { //Do some input validation. @@ -108,7 +110,7 @@ function exportSurvey($iSurveyId, $sLanguageCode, $sExportPlugin, FormattingOpti $surveyDao->loadSurveyResults($survey, $oOptions->responseMinRecord, $oOptions->responseMaxRecord, $sFilter, $oOptions->responseCompletionState); - $writer->write($survey, $sLanguageCode, $oOptions,true); + $writer->write($survey, $sLanguageCode, $oOptions); $result = $writer->close(); // Close resultset if needed diff --git a/application/helpers/admin/htmleditor_helper.php b/application/helpers/admin/htmleditor_helper.php index 75ed34eda07..ca649260311 100644 --- a/application/helpers/admin/htmleditor_helper.php +++ b/application/helpers/admin/htmleditor_helper.php @@ -261,7 +261,6 @@ function(){ var $oCKeditorVarName = CKEDITOR.replace('$fieldname', { ,LimeReplacementFieldsSID : \"".$surveyID."\" ,LimeReplacementFieldsGID : \"".$gID."\" ,LimeReplacementFieldsQID : \"".$qID."\" - ,LimeReplacementFieldsType : \"".$fieldtype."\" ,LimeReplacementFieldsAction : \"".$action."\" ,LimeReplacementFieldsPath : \"".Yii::app()->getController()->createUrl("admin/limereplacementfields/sa/index/")."\" ,language:'".sTranslateLangCode2CK(Yii::app()->session['adminlang'])."'" @@ -284,4 +283,3 @@ function(){ var $oCKeditorVarName = CKEDITOR.replace('$fieldname', { return $htmlcode; } -?> diff --git a/application/helpers/admin/import_helper.php b/application/helpers/admin/import_helper.php index 359bc9ee40f..e21dbc59322 100644 --- a/application/helpers/admin/import_helper.php +++ b/application/helpers/admin/import_helper.php @@ -1546,7 +1546,7 @@ function XMLImportSurvey($sFullFilePath,$sXMLdata=NULL,$sNewSurveyName=NULL,$iDe translateInsertansTags($iNewSID,$iOldSID,$aOldNewFieldmap); replaceExpressionCodes($iNewSID,$aQuestionCodeReplacements); if (count($aQuestionCodeReplacements)) { - array_unshift($results['importwarnings'] , "".gT('Attention: Several question codes were updated. Please check these carefully as the update may not be perfect with customized expressions.').''); + array_unshift($results['importwarnings'] , "".gT('Attention: Several question codes were updated. Please check these carefully as the update may not be perfect with customized expressions.').''); } LimeExpressionManager::RevertUpgradeConditionsToRelevance($iNewSID); LimeExpressionManager::UpgradeConditionsToRelevance($iNewSID); @@ -1764,6 +1764,7 @@ function CSVImportResponses($sFullFilePath,$iSurveyId,$aOptions=array()) $aRealFieldNames = Yii::app()->db->getSchema()->getTable(SurveyDynamic::model($iSurveyId)->tableName())->getColumnNames(); //$aCsvHeader=array_map("trim",explode($aOptions['sSeparator'], trim(array_shift($aFileResponses)))); $aCsvHeader=str_getcsv(array_shift($aFileResponses),$aOptions['sSeparator'],$aOptions['sQuoted']); + LimeExpressionManager::SetDirtyFlag($iSurveyId); // Be sure survey EM code are up to date $aLemFieldNames=LimeExpressionManager::getLEMqcode2sgqa($iSurveyId); $aKeyForFieldNames=array();// An array assicated each fieldname with corresponding responses key if(!$aCsvHeader){ @@ -2085,7 +2086,7 @@ function XSSFilterArray(&$array) * Import survey from an TSV file template that does not require or allow assigning of GID or QID values. * NOTE: This currently only supports import of one language * @param string $sFullFilePath -* @return type +* @return array * * @author TMSWhite */ @@ -2109,7 +2110,7 @@ function TSVImportSurvey($sFullFilePath) // UTF16 Byte Order Mark present $encoding = 'UTF-16'; } else { - $file_sample = fread($handle, 1000) + 'e'; //read first 1000 bytes + $file_sample = fread($handle, 1000) . 'e'; //read first 1000 bytes // + e is a workaround for mb_string bug rewind($handle); diff --git a/application/helpers/admin/statistics_helper.php b/application/helpers/admin/statistics_helper.php index 103d1172788..75d6b25b99e 100644 --- a/application/helpers/admin/statistics_helper.php +++ b/application/helpers/admin/statistics_helper.php @@ -337,9 +337,9 @@ function getQuestionMapData($sField, $qsid) /** Builds the list of addon SQL select statements * that builds the query result set * -* @param $allfields An array containing the names of the fields/answers we want to display in the statistics summary -* @param $fieldmap The fieldmap for the survey -* @param $language The language to use +* @param array $allfields An array containing the names of the fields/answers we want to display in the statistics summary +* @param integer $surveyid +* @param string $language The language to use * * @return array $selects array of individual select statements that can be added/appended to * the 'where' portion of a SQL statement to restrict the result set @@ -792,6 +792,9 @@ protected function buildOutputList($rt, $language, $surveyid, $outputType, $sql, list($qsid, $qgid, $qqid) = explode("X", substr($rt, 1, strlen($rt)), 3); //select details for this question + /** + FIXME $iQuestionIDlength not defined!! + */ $nresult = Question::model()->find('language=:language AND parent_qid=0 AND qid=:qid', array(':language'=>$language, ':qid'=>substr($qqid, 0, $iQuestionIDlength))); $qtitle=$nresult->title; $qtype=$nresult->type; @@ -1596,6 +1599,7 @@ protected function buildOutputList($rt, $language, $surveyid, $outputType, $sql, * @param string $outputType * @param integer $usegraph * @param boolean $browse + * @return array */ protected function displaySimpleResults($outputs, $results, $rt, $outputType, $surveyid, $sql, $usegraph, $browse, $sLanguage) { @@ -1604,6 +1608,7 @@ protected function displaySimpleResults($outputs, $results, $rt, $outputType, $s $statisticsoutput=""; $sDatabaseType = Yii::app()->db->getDriverName(); $astatdata=array(); + $sColumnName = null; //loop though the array which contains all answer data $ColumnName_RM=array(); @@ -2055,10 +2060,11 @@ protected function displaySimpleResults($outputs, $results, $rt, $outputType, $s } else { $percentage = 0; } + break; default: - $aggregatedPercentage = 'na'; - break; + $aggregatedPercentage = 'na'; + break; } @@ -2225,7 +2231,7 @@ protected function displaySimpleResults($outputs, $results, $rt, $outputType, $s //-------------------------- PCHART OUTPUT ---------------------------- list($qsid, $qgid, $qqid) = explode("X", $rt, 3); $qsid = $surveyid; - $aattr = getQuestionAttributeValues($outputs['parentqid'], substr($rt, 0, 1)); + $aattr = getQuestionAttributeValues($outputs['parentqid']); //PCHART has to be enabled and we need some data // @@ -2259,15 +2265,16 @@ protected function displaySimpleResults($outputs, $results, $rt, $outputType, $s $cachefilename = ''; if($outputType == 'xls' || $outputType == 'pdf') { + /** + * + //FIXME $MyCache is undefined $cachefilename = createChart($qqid, $qsid, $bShowPieChart, $lbl, $gdata, $grawdata, $MyCache, $sLanguage, $outputs['qtype']); + * + */ } } } - else - { - - } if(isset($aattr["statistics_graphtype"])) @@ -2386,6 +2393,8 @@ protected function displayResults($outputs, $results, $rt, $outputType, $surveyi $tempdir = Yii::app()->getConfig("tempdir"); $astatdata = array(); + $sColumnName = null; + if ($usegraph==1 && $outputType != 'html') { //for creating graphs we need some more scripts which are included here @@ -3187,10 +3196,11 @@ protected function displayResults($outputs, $results, $rt, $outputType, $surveyi } else { $percentage = 0; } + break; default: - $aggregatedPercentage = 'na'; - break; + $aggregatedPercentage = 'na'; + break; } @@ -3589,7 +3599,7 @@ protected function displayResults($outputs, $results, $rt, $outputType, $surveyi //-------------------------- PCHART OUTPUT ---------------------------- list($qsid, $qgid, $qqid) = explode("X", $rt, 3); $qsid = $surveyid; - $aattr = getQuestionAttributeValues($outputs['parentqid'], substr($rt, 0, 1)); + $aattr = getQuestionAttributeValues($outputs['parentqid']); //PCHART has to be enabled and we need some data // diff --git a/application/helpers/admin/template_helper.php b/application/helpers/admin/template_helper.php index 7f4464adb9d..0b589482f5b 100644 --- a/application/helpers/admin/template_helper.php +++ b/application/helpers/admin/template_helper.php @@ -166,6 +166,11 @@ function gettemplatefilename($template, $templatefile) { $oEditedTemplate = Template::model()->getTemplateConfiguration($template); switch (pathinfo($templatefile, PATHINFO_EXTENSION)) { + case 'twig': + // TODO: recursivity + $oEditedTemplate = Template::model()->getTemplateConfiguration($template); + return $oEditedTemplate->viewPath.$templatefile; + break; case 'pstpl': $oEditedTemplate = Template::model()->getTemplateConfiguration($template); return $oEditedTemplate->viewPath.$templatefile; diff --git a/application/helpers/adodb/adodb-time.inc_helper.php b/application/helpers/adodb/adodb-time.inc_helper.php index 9be084b2041..cd6802f3daa 100644 --- a/application/helpers/adodb/adodb-time.inc_helper.php +++ b/application/helpers/adodb/adodb-time.inc_helper.php @@ -1435,6 +1435,3 @@ function adodb_strftime($fmt, $ts=false,$is_gmt=false) $ret = adodb_date($fmtdate, $ts, $is_gmt); return $ret; } - - -?> \ No newline at end of file diff --git a/application/helpers/common_helper.php b/application/helpers/common_helper.php index 97ab7be6cd1..6a9010ac4df 100644 --- a/application/helpers/common_helper.php +++ b/application/helpers/common_helper.php @@ -109,7 +109,7 @@ function quoteText($sText, $sEscapeMode = 'html') * @param string $SelectedCode Value of the Question Type (defaults to "T") * @param string $ReturnType Type of output from this function (defaults to selector) * -* @return depending on $ReturnType param, returns a straight "array" of question types, or an list +* @return array|string depending on $ReturnType param, returns a straight "array" of question types, or an list * * Explanation of questiontype array: * @@ -369,7 +369,7 @@ function getQuestions($surveyid,$gid,$selectedqid) * @param string $surveyid * @param string $gid * -* @return The Gid of the previous group +* @return int The Gid of the previous group */ function getGidPrevious($surveyid, $gid) { @@ -400,7 +400,7 @@ function getGidPrevious($surveyid, $gid) * @param string $gid * @param string $qid * -* @return This Qid of the previous question +* @return integer This Qid of the previous question */ function getQidPrevious($surveyid, $gid, $qid) { @@ -433,7 +433,7 @@ function getQidPrevious($surveyid, $gid, $qid) * @param string $surveyid * @param string $gid * -* @return The Gid of the next group +* @return integer The Gid of the next group */ function getGidNext($surveyid, $gid) { @@ -466,7 +466,7 @@ function getGidNext($surveyid, $gid) * @param string $gid * @param string $qid * -* @return This Qid of the previous question +* @return integer This Qid of the previous question */ function getQidNext($surveyid, $gid, $qid) { @@ -1109,7 +1109,7 @@ function getUserList($outputformat='fullinfoarray') * * @param string $surveyid The survey ID * @param string $languagecode The language code - if not given the base language of the particular survey is used -* @return array Returns array with survey info or false, if survey does not exist +* @return array|bool Returns array with survey info or false, if survey does not exist */ function getSurveyInfo($surveyid, $languagecode='') { @@ -1119,22 +1119,17 @@ function getSurveyInfo($surveyid, $languagecode='') $thissurvey=false; $oSurvey = Survey::model()->findByPk($surveyid); // Do job only if this survey exist - if(!$oSurvey) - { + if(!$oSurvey) { return false; } // if no language code is set then get the base language one - if ((!isset($languagecode) || $languagecode=='')) - { + if ((!isset($languagecode) || $languagecode=='')) { $languagecode=Survey::model()->findByPk($surveyid)->language; } - if(isset($staticSurveyInfo[$surveyid][$languagecode]) ) - { + if(isset($staticSurveyInfo[$surveyid][$languagecode]) ) { $thissurvey=$staticSurveyInfo[$surveyid][$languagecode]; - } - else - { + } else { $result = SurveyLanguageSetting::model()->with('survey')->findByPk(array('surveyls_survey_id' => $surveyid, 'surveyls_language' => $languagecode)); if (is_null($result)) { // When additional language was added, but not saved it does not exists @@ -1622,18 +1617,17 @@ function validateEmailAddress($sEmailAddress){ /** * Validate an list of email addresses - either as array or as semicolon-limited text -* @returns List with valid email addresses - invalid email addresses are filtered - false if none of the email addresses are valid +* @return string List with valid email addresses - invalid email addresses are filtered - false if none of the email addresses are valid * * @param mixed $aEmailAddressList Email address to check */ function validateEmailAddresses($aEmailAddressList){ $aOutList=false; - if (!is_array($aEmailAddressList)) - { + if (!is_array($aEmailAddressList)) { $aEmailAddressList=explode(';',$aEmailAddressList); } - foreach ($aEmailAddressList as $sEmailAddress) - { + + foreach ($aEmailAddressList as $sEmailAddress) { $sEmailAddress= trim($sEmailAddress); if (validateEmailAddress($sEmailAddress)){ $aOutList=$sEmailAddress; @@ -2375,7 +2369,6 @@ function createFieldMap($surveyid, $style='short', $force_refresh=false, $questi /** * Returns true if the given survey has a File Upload Question Type -* @param $surveyid The survey ID * @param integer $iSurveyID * @return bool */ @@ -2514,9 +2507,9 @@ function buildLabelSetCheckSumArray() /** * Returns a flat array with all question attributes for the question only (and the qid we gave it)! -* @depecated : use QuestionAttribute::model()->getQuestionAttributes($iQID); directly -* @param $iQID The question ID -* @return array$bOrderByNative=>value, attribute=>value} or false if the question ID does not exist (anymore) +* @deprecated : use QuestionAttribute::model()->getQuestionAttributes($iQID); directly +* @param integer $iQID The question ID +* @return array $bOrderByNative=>value, attribute=>value} or false if the question ID does not exist (anymore) */ function getQuestionAttributeValues($iQID) { @@ -2604,12 +2597,11 @@ function dbQuoteAll($value) * - it is intended to be used before any response data is saved to the response table * * @param mixed $sValue A string to be sanitized -* @return A sanitized string, otherwise the unmodified original variable +* @return string A sanitized string, otherwise the unmodified original variable */ function stripCtrlChars($sValue) { - if (is_string($sValue)) - { + if (is_string($sValue)) { $sValue=preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\x9F]/u', '', $sValue); } return $sValue; @@ -2820,7 +2812,7 @@ function SendEmailMessage($body, $subject, $to, $from, $sitename, $ishtml=false, $sent=$mail->Send(); $maildebug=$mail->ErrorInfo; if ($emailsmtpdebug>0) { - $maildebug .= '
  • '. gT('SMTP debug output:').'
  • '.strip_tags(ob_get_contents()).'
    '; + $maildebug .= '
    '. gT('SMTP debug output:').'
    '.\CHtml::encode(ob_get_contents()).'
    '; ob_end_clean(); } $maildebugbody=$mail->Body; @@ -2880,7 +2872,7 @@ function flattenText($sTextToFlatten, $bKeepSpan=false, $bDecodeHTMLEntities=fal /** * getArrayFilterExcludesCascadesForGroup() queries the database and produces a list of array_filter_exclude questions and targets with in the same group -* @return returns a keyed nested array, keyed by the qid of the question, containing cascade information +* @return array a keyed nested array, keyed by the qid of the question, containing cascade information */ function getArrayFilterExcludesCascadesForGroup($surveyid, $gid="", $output="qid") { @@ -2974,7 +2966,8 @@ function getArrayFilterExcludesCascadesForGroup($surveyid, $gid="", $output="qid /** * getArrayFiltersForQuestion($qid) finds out if a question has an array_filter attribute and what codes where selected on target question -* @return returns an array of codes that were selected else returns false +* @return array an array of codes that were selected else returns false +* @deprecated not used */ function getArrayFiltersForQuestion($qid) { @@ -2991,6 +2984,7 @@ function getArrayFiltersForQuestion($qid) { if ($fields[2] == $val) { + /** Broken code below ... // we found the target question, now we need to know what the answers where, we know its a multi! $fields[0]=sanitize_int($fields[0]); //$query = "SELECT title FROM ".db_table_name('questions')." where parent_qid='{$fields[0]}' AND language='".Yii::app()->session[$surveyid]['s_lang']."' order by question_order"; @@ -3003,6 +2997,8 @@ function getArrayFiltersForQuestion($qid) || Yii::app()->session[$fields[1]] == $code['title']) array_push($selected,$code['title']); } + */ + //Now we also need to find out if (a) the question had "other" enabled, and (b) if that was selected //$query = "SELECT other FROM ".db_table_name('questions')." where qid='{$fields[0]}'"; $qresult=Question::model()->findAllByAttributes(array("qid"=>$fields[0])); @@ -3024,7 +3020,8 @@ function getArrayFiltersForQuestion($qid) /** * getGroupsByQuestion($surveyid) -* @return returns a keyed array of groups to questions ie: array([1]=>[2]) question qid 1, is in group gid 2. +* @return array a keyed array of groups to questions ie: array([1]=>[2]) question qid 1, is in group gid 2. +* @deprecated not used */ function getGroupsByQuestion($surveyid) { $output=array(); @@ -3032,7 +3029,7 @@ function getGroupsByQuestion($surveyid) { $surveyid=sanitize_int($surveyid); $result=Question::model()->findAllByAttributes(array("sid"=>$surveyid)); - foreach ($qresult->readAll() as $val) + foreach ($result->readAll() as $val) { $output[$val['qid']]=$val['gid']; } @@ -3042,7 +3039,7 @@ function getGroupsByQuestion($surveyid) { /** * getArrayFilterExcludesForQuestion($qid) finds out if a question has an array_filter_exclude attribute and what codes where selected on target question -* @return returns an array of codes that were selected else returns false +* @return array returns an array of codes that were selected else returns false */ function getArrayFilterExcludesForQuestion($qid) { @@ -3312,17 +3309,14 @@ function isCaptchaEnabled($screen, $captchamode='') break; case 'saveandloadscreen': if ($captchamode == 'A' || - $captchamode == 'C' || - $captchamode == 'D' || - $captchamode == 'S') - { + $captchamode == 'C' || + $captchamode == 'D' || + $captchamode == 'S') { + return true; - } - else - { + } else { return false; } - return true; break; default: return true; @@ -3471,6 +3465,8 @@ function getNextCode($sourcecode) */ function translateLinks($sType, $iOldSurveyID, $iNewSurveyID, $sString) { + $iOldSurveyID = (int)$iOldSurveyID; + $iNewSurveyID = (int)$iNewSurveyID; // To avoid injection of a /e regex modifier without having to check all execution paths if ($sType == 'survey') { $sPattern = '(http(s)?:\/\/)?(([a-z0-9\/\.])*(?=(\/upload))\/upload\/surveys\/'.$iOldSurveyID.'\/)'; @@ -3890,9 +3886,13 @@ function useFirebug() */ function convertDateTimeFormat($value, $fromdateformat, $todateformat) { - Yii::import('application.libraries.Date_Time_Converter', true); - $date = new Date_Time_Converter($value, $fromdateformat); - return $date->convert($todateformat); + $date = DateTime::createFromFormat($fromdateformat, $value); + if ($date) { + return $date->format($todateformat); + } else { + $date = new DateTime($value); + return $date->format($todateformat); + } } /** @@ -3900,7 +3900,7 @@ function convertDateTimeFormat($value, $fromdateformat, $todateformat) * Check if the time shoul be rendered also * * @param string $sDate -* @param boolean withTime +* @param boolean $withTime * @return string */ function convertToGlobalSettingFormat($sDate,$withTime=false) @@ -4019,12 +4019,13 @@ function getTemplateURL($sTemplateName) } /** -* Return an array of subquestions for a given sid/qid -* -* @param int $sid -* @param int $qid -* @param $sLanguage Language of the subquestion text -*/ + * Return an array of subquestions for a given sid/qid + * + * @param int $sid + * @param int $qid + * @param string $sLanguage Language of the subquestion text + * @return array + */ function getSubQuestions($sid, $qid, $sLanguage) { static $subquestions; @@ -4245,30 +4246,21 @@ function isNumericInt($mStr) */ function short_implode($sDelimeter, $sHyphen, $aArray) { - if (sizeof($aArray) < Yii::app()->getConfig('minlengthshortimplode')) - { + if (sizeof($aArray) < Yii::app()->getConfig('minlengthshortimplode')) { sort($aArray); return implode($sDelimeter, $aArray); - } - else - { + } else { sort($aArray); $iIndexA = 0; $iIndexB = 1; - while ($iIndexA < sizeof($aArray)) - { - if ($iIndexA == 0) - { + $sResult = null; + while ($iIndexA < sizeof($aArray)) { + if ($iIndexA == 0) { $sResult = $aArray[$iIndexA]; - } - else - { - if (strlen($sResult) > Yii::app()->getConfig('maxstringlengthshortimplode') - strlen($sDelimeter) - 3) - { + } else { + if (strlen($sResult) > Yii::app()->getConfig('maxstringlengthshortimplode') - strlen($sDelimeter) - 3) { return $sResult.$sDelimeter.'...'; - } - else - { + } else { $sResult = $sResult.$sDelimeter.$aArray[$iIndexA]; } } @@ -4541,7 +4533,7 @@ function translateInsertansTags($newsid,$oldsid,$fieldnames) 'language' => $language ); - Answer::model()->update($data,$where); + Answer::model()->updateRecord($data,$where); } // Enf if modified } // end while qentry @@ -4564,7 +4556,7 @@ function replaceExpressionCodes ($iSurveyID, $aCodeMap) // Don't search/replace old codes that are too short or were numeric (because they would not have been usable in EM expressions anyway) if (strlen($sOldCode)>1 && !is_numeric($sOldCode[0])) { - $sOldCode=preg_quote($sOldCode,'/'); + $sOldCode=preg_quote($sOldCode,'~'); $arQuestion->relevance=preg_replace("~{[^}]*\K{$sOldCode}(?=[^}]*?})~",$sNewCode,$arQuestion->relevance,-1,$iCount); $bModified = $bModified || $iCount; $arQuestion->question=preg_replace("~{[^}]*\K{$sOldCode}(?=[^}]*?})~",$sNewCode,$arQuestion->question,-1,$iCount); @@ -4582,7 +4574,7 @@ function replaceExpressionCodes ($iSurveyID, $aCodeMap) $bModified=false; foreach ($aCodeMap as $sOldCode=>$sNewCode) { - $sOldCode=preg_quote($sOldCode,'/'); + $sOldCode=preg_quote($sOldCode,'~'); $arGroup->grelevance=preg_replace("~{[^}]*\K{$sOldCode}(?=[^}]*?})~",$sNewCode,$arGroup->grelevance,-1,$iCount); $bModified = $bModified || $iCount; $arGroup->description=preg_replace("~{[^}]*\K{$sOldCode}(?=[^}]*?})~",$sNewCode,$arGroup->description,-1,$iCount); @@ -5361,7 +5353,7 @@ function getUserGroupList($ugid=NULL,$outputformat='optionlist') if ($gn['ugid'] == $ugid) {$selecter .= " selected='selected'"; $svexist = 1;} $link = Yii::app()->getController()->createUrl("/admin/usergroups/sa/view/ugid/".$gn['ugid']); - $selecter .=" value='{$link}'>{$gn['name']}\n"; + $selecter .=" value='{$link}'>".\CHtml::encode($gn['name'])."\n"; $simplegidarray[] = $gn['ugid']; } } @@ -5400,7 +5392,7 @@ function getGroupUserList($ugid) foreach($surveynames as $sv) { $surveyselecter .= "\n"; } } $surveyselecter = "\n".$surveyselecter; @@ -5606,9 +5598,14 @@ function doFooter() echo getFooter(); } +/** + * @param $surveyid + * @return array|bool + * @deprecated + */ function getDBTableUsage($surveyid){ Yii::app()->loadHelper('admin/activate'); - $arrCols = activateSurvey($surveyid,$surveyid,'admin.php',true); + $arrCols = activateSurvey($surveyid,true); $length = 1; foreach ($arrCols['fields'] as $col){ @@ -5629,7 +5626,7 @@ function getDBTableUsage($surveyid){ $length = $length + 8; break; case 'L': - $legth++; + $length++; break; case 'I': case 'I4': @@ -5780,7 +5777,7 @@ function getSurveyUserList($bIncludeOwner=true, $bIncludeSuperAdmins=true,$surve in_array($sv['uid'],$authorizedUsersList)) { $surveyselecter .= "\n"; $svexist = true; } } @@ -5905,8 +5902,8 @@ function ls_json_encode($content) /** * Decode a json string, sometimes needs stripslashes * - * @param type $jsonString - * @return type + * @param string $jsonString + * @return mixed */ function json_decode_ls($jsonString) { @@ -6000,10 +5997,10 @@ function arraySwapAssoc($key1, $key2, $array) { * * This public static function will strip tags from a string, split it at its max_length and ellipsize * -* @param string string to ellipsize -* @param integer max length of string -* @param mixed int (1|0) or float, .5, .2, etc for position to split -* @param string ellipsis ; Default '...' +* @param string $sString string to ellipsize +* @param integer $iMaxLength max length of string +* @param mixed $fPosition int (1|0) or float, .5, .2, etc for position to split +* @param string $sEllipsis ellipsis ; Default '...' * @return string ellipsized string */ function ellipsize($sString, $iMaxLength, $fPosition = 1, $sEllipsis = '…') @@ -6105,9 +6102,10 @@ function array_diff_assoc_recursive($array1, $array2) { } - /** - * @param string $sSize - */ +/** + * @param string $sSize + * @return bool|int|string + */ function convertPHPSizeToBytes($sSize) { //This function transforms the php.ini notation for numbers (like '2M') to an integer (2*1024*1024 in this case) diff --git a/application/helpers/export_helper.php b/application/helpers/export_helper.php index ae83a089cfe..bca2b82165f 100644 --- a/application/helpers/export_helper.php +++ b/application/helpers/export_helper.php @@ -68,14 +68,15 @@ function strSplitUnicode($str, $l = 0) { } /** -* Exports CSV response data for SPSS and R -* -* @param mixed $iSurveyID The survey ID -* @param string $iLength Maximum text lenght data, usually 255 for SPSS db->getDriverName(); $oRecordSet->where("1=1"); - if ($sEmailFiter!='') - { - if (in_array($databasetype, array('mssql', 'sqlsrv', 'dblib'))) - { - $oRecordSet->andWhere("CAST(email as varchar) like ".dbQuoteAll('%'.$sEmailFiter.'%', true)); - } - else - { - $oRecordSet->andWhere("email like ".dbQuoteAll('%'.$sEmailFiter.'%', true)); + if ($sEmailFiter!='') { + if (in_array($databasetype, array('mssql', 'sqlsrv', 'dblib'))) { + $oRecordSet->andWhere("CAST(email as varchar) like ".dbQuoteAll('%'.$sEmailFiter.'%')); + } else { + $oRecordSet->andWhere("email like ".dbQuoteAll('%'.$sEmailFiter.'%')); } } - if ($iTokenStatus==1) - { + if ($iTokenStatus==1) { $oRecordSet->andWhere("completed<>'N'"); - } - elseif ($iTokenStatus==2) - { + } elseif ($iTokenStatus==2) { $oRecordSet->andWhere("completed='N'"); - if ($bIsNotAnonymous) - { + if ($bIsNotAnonymous) { $oRecordSet->andWhere("token not in (select token from {{survey_$iSurveyID}} group by token)"); } } @@ -1830,7 +1830,7 @@ function tokensExport($iSurveyID) $aExportedTokens[] = $brow['tid']; } - if (Yii::app()->request->getPost('tokendeleteexported') && !empty($aExportedTokens)) + if (Yii::app()->request->getPost('tokendeleteexported') && Permission::model()->hasSurveyPermission($iSurveyId, 'tokens', 'delete') && !empty($aExportedTokens)) { Token::model($iSurveyID)->deleteByPk($aExportedTokens); } diff --git a/application/helpers/expressions/em_core_helper.php b/application/helpers/expressions/em_core_helper.php index 4b8b562cad5..3f79b56363f 100644 --- a/application/helpers/expressions/em_core_helper.php +++ b/application/helpers/expressions/em_core_helper.php @@ -499,7 +499,7 @@ public function RDP_Evaluate($expr, $onlyparse=false) } else { - $this-RDP_AddError(self::gT("Unbalanced equation - values left on stack"),NULL); + $this->RDP_AddError(self::gT("Unbalanced equation - values left on stack"),NULL); return false; } } @@ -1659,7 +1659,7 @@ public function GetPrettyPrintString() * Get information about the variable, including JavaScript name, read-write status, and whether set on current page. * @param string $name * @param string|null $attr - * @param string default + * @param string $default * @return string */ private function GetVarAttribute($name,$attr,$default) @@ -2175,11 +2175,11 @@ private function RDP_SetVariableValue($op,$name,$value) } /** - * Split a soure string into STRING vs. EXPRESSION, where the latter is surrounded by unescaped curly braces. - * This verson properly handles nested curly braces and curly braces within strings within curly braces - both of which are needed to better support JavaScript + * Split a source string into STRING vs. EXPRESSION, where the latter is surrounded by unescaped curly braces. + * This version properly handles nested curly braces and curly braces within strings within curly braces - both of which are needed to better support JavaScript * Users still need to add a space or carriage return after opening braces (and ideally before closing braces too) to avoid having them treated as expressions. * @param string $src - * @return string + * @return array */ public function asSplitStringOnExpressions($src) { @@ -2720,12 +2720,12 @@ function exprmgr_sumifop($args) * * @author Johannes Weberhofer, 2013 * - * @param numeric $fValueToReplace - * @param numeric $iStrict - 1 for exact matches only otherwise interpolation the - * closest value should be returned + * @param double $fValueToReplace + * @param integer $iStrict - 1 for exact matches only otherwise interpolation the + * closest value should be returned * @param string $sTranslateFromList - comma seperated list of numeric values to translate from * @param string $sTranslateToList - comma seperated list of numeric values to translate to - * @return numeric + * @return integer|null */ function exprmgr_convert_value($fValueToReplace, $iStrict, $sTranslateFromList, $sTranslateToList) { @@ -3027,4 +3027,3 @@ function exprmgr_unique($args) } return true; } -?> diff --git a/application/helpers/expressions/em_manager_helper.php b/application/helpers/expressions/em_manager_helper.php index feedef9c3d1..9c1aa6817bb 100644 --- a/application/helpers/expressions/em_manager_helper.php +++ b/application/helpers/expressions/em_manager_helper.php @@ -943,21 +943,16 @@ public static function ConvertConditionsToRelevance($surveyId=NULL, $qid=NULL) } $_subqid = $subqid; - // fix values if (preg_match('/^@\d+X\d+X\d+.*@$/',$value)) { $value = substr($value,1,-1); - } - else if (preg_match('/^{.+}$/',$value)) { + } elseif (preg_match('/^{.+}$/',$value)) { $value = substr($value,1,-1); + } elseif ($row['method'] == 'RX') { + if (!preg_match('#^/.*/$#',$value)) { + $value = '"/' . $value . '/"'; // if not surrounded by slashes, add them. } - else if ($row['method'] == 'RX') { - if (!preg_match('#^/.*/$#',$value)) - { - $value = '"/' . $value . '/"'; // if not surrounded by slashes, add them. - } - } - else { - $value = '"' . $value . '"'; + } elseif ((string)(float) $value !== (string) $value ) { + $value = '"' . $value . '"'; } // add equation @@ -2659,6 +2654,7 @@ public function _CreateSubQLevelRelevanceAndValidationEqns($onlyThisQseq=NULL) { case 'K': //MULTI NUMERICAL QUESTION TYPE (Need a attribute, not set in 131014) $subqValidSelector = $sq['jsVarName_on']; + break; case 'N': //NUMERICAL QUESTION TYPE $sq_name = ($this->sgqaNaming)?$sq['rowdivid'].".NAOK":$sq['varName'].".NAOK"; $sq_eqn = '( is_int('.$sq_name.') || is_empty('.$sq_name.') )'; @@ -3530,11 +3526,11 @@ public function _CreateSubQLevelRelevanceAndValidationEqns($onlyThisQseq=NULL) ); } // now combine all classes of validation equations - $veqns = array(); foreach ($parts as $vclass=>$eqns) { $veqns[$vclass] = '(' . implode(' and ', $eqns) . ')'; } + $veqns = array(); $this->qid2validationEqn[$qid] = array( @@ -3642,7 +3638,13 @@ private function setVariableAndTokenMappingsForExpressionManager($surveyid,$forc $this->qid2validationEqn = array(); $this->groupSeqInfo = array(); $this->gseq2relevanceStatus = array(); - + /* Fill some static know vars , the used is always $this->knownVars (even if set in templatereplace function) */ + $this->knownVars['SID'] = array( + 'code'=>$this->sid, + 'jsName_on'=>'', + 'jsName'=>'', + 'readWrite'=>'N', + ); /* Add the core replacement before question code : needed if use it in equation , use SID to never send error */ templatereplace("{SID}"); @@ -4235,6 +4237,12 @@ private function setVariableAndTokenMappingsForExpressionManager($surveyid,$forc 'jsName'=>'', 'readWrite'=>'N', ); + $this->knownVars['TOKEN'] = array( + 'code'=>$_SESSION[$this->sessid]['token'], + 'jsName_on'=>'', + 'jsName'=>'', + 'readWrite'=>'N', + ); $token = Token::model($surveyid)->findByToken($_SESSION[$this->sessid]['token']); if($token) { @@ -4255,13 +4263,13 @@ private function setVariableAndTokenMappingsForExpressionManager($surveyid,$forc $attrs = array_keys(getTokenFieldsAndNames($surveyid)); $blankVal = array( - 'code'=>'', - 'type'=>'', - 'jsName_on'=>'', - 'jsName'=>'', - 'readWrite'=>'N', + 'code'=>'', + 'type'=>'', + 'jsName_on'=>'', + 'jsName'=>'', + 'readWrite'=>'N', ); - + // DON'T set $this->knownVars['TOKEN'] = $blankVal; becuase optout/optin can need it, then don't replace this from templatereplace foreach ($attrs as $key) { if (preg_match('/^(firstname|lastname|email|usesleft|token|attribute_\d+)$/',$key)) @@ -4294,7 +4302,6 @@ private function setVariableAndTokenMappingsForExpressionManager($surveyid,$forc 'default'=>'', 'rootVarName'=>'this', 'subqtext'=>'', - 'rowdivid'=>'', ); $this->runtimeTimings[] = array(__METHOD__ . ' - process fieldMap',(microtime(true) - $now)); @@ -4992,7 +4999,7 @@ static function StartSurvey($surveyid,$surveyMode='group',$aSurveyOptions=NULL,$ } /** - * @return void + * @return mixed */ static function NavigateBackwards() { @@ -6211,7 +6218,7 @@ function _ValidateQuestion($questionSeq,$force=false) { $relevantSQs[] = $sgqa; } - // This just remove the last ranking : don't control validity of answers done: user can rank unrelevant answers .... See Bug #09774 + // This just remove the last ranking : don't control validity of answers done: user can rank irrelevant answers .... See Bug #09774 continue; } @@ -6308,6 +6315,7 @@ function _ValidateQuestion($questionSeq,$force=false) $_SESSION[$LEM->sessid]['relevanceStatus'][$sq['rowdivid']]=false; } } + break; case 'A': //ARRAY (5 POINT CHOICE) radio-buttons case 'B': //ARRAY (10 POINT CHOICE) radio-buttons case 'C': //ARRAY (YES/UNCERTAIN/NO) radio-buttons @@ -6680,7 +6688,7 @@ function _ValidateQuestion($questionSeq,$force=false) /** * Control value against value from survey : see #11611 */ - $sgqas = explode('|',$LEM->qid2code[$qid]); /* Must remove all session alert, even if unrelevant or hidden */ + $sgqas = explode('|',$LEM->qid2code[$qid]); /* Must remove all session alert, even if irrelevant or hidden */ foreach($sgqas as $sgqa) { $validityString=self::getValidityString($sgqa); @@ -7313,22 +7321,7 @@ static function GetRelevanceAndTailoringJavaScript() foreach ($subqParts as $sq) { $rowdividList[$sq['rowdivid']] = $sq['result']; - // make sure to update headings and colors for filtered questions (array filter and individual SQ relevance) - if( ! empty($sq['type'])) { - // js to fix colors - $relParts[] = "updateColors($('#question".$arg['qid']."').find('table.question'));\n"; - // js to fix headings - $repeatheadings = Yii::app()->getConfig("repeatheadings"); - if(isset($LEM->qattr[$arg['qid']]['repeat_headings']) && $LEM->qattr[$arg['qid']]['repeat_headings'] !== "") { - $repeatheadings = $LEM->qattr[$arg['qid']]['repeat_headings']; - } - if($repeatheadings > 0) - { - $relParts[] = "updateHeadings($('#question".$arg['qid']."').find('table.question'), " - .$repeatheadings.");\n"; - } - } - // end + //this change is optional....changes to array should prevent "if( )" $relParts[] = " if ( " . (empty($sq['relevancejs'])?'1':$sq['relevancejs']) . " ) {\n"; if ($afHide) @@ -7363,7 +7356,7 @@ static function GetRelevanceAndTailoringJavaScript() $relParts[] = " $('#javatbd" . $sq['rowdivid'] . "').trigger('relevance:on',{ style : 'disabled' });\n"; if ($afHide) { - $relParts[] = " $('#javatbd" . $sq['rowdivid'] . "').rtrigger('relevance:off');\n"; + $relParts[] = " $('#javatbd" . $sq['rowdivid'] . "').trigger('relevance:off');\n"; } else { @@ -8726,25 +8719,33 @@ static function ProcessCurrentResponses() $lang = $_SESSION['LEMlang']; $value = self::convertNonLatinNumerics($value, $lang); - $value=trim($value); - if ($value!="" && $value!="INVALID") - { - $aAttributes=$LEM->getQuestionAttributesForEM($LEM->sid, $qid,$_SESSION['LEMlang']); + $value = trim($value); + if ($value != "" && $value != "INVALID") { + $aAttributes = $LEM->getQuestionAttributesForEM($LEM->sid, $qid,$_SESSION['LEMlang']); if (!isset($aAttributes[$qid])) { $aAttributes[$qid]=array(); } - $aDateFormatData=getDateFormatDataForQID($aAttributes[$qid],$LEM->surveyOptions); + $aDateFormatData = getDateFormatDataForQID($aAttributes[$qid],$LEM->surveyOptions); // We don't really validate date here : if date is invalid : return 1999-12-01 00:00 - $oDateTimeConverter = new Date_Time_Converter(trim($value), $aDateFormatData['phpdate']); - $newValue=$oDateTimeConverter->convert("Y-m-d H:i"); - $oDateTimeConverter = new Date_Time_Converter($newValue, "Y-m-d H:i"); - if($value==$oDateTimeConverter->convert($aDateFormatData['phpdate'])) // control if inverse function original value - { - $value=$newValue; - } - else - { - $value="";// Or $value="INVALID" ? : dropdown is OK with this not default. + // For an explanation of the exclamation mark, see this thread: + // http://stackoverflow.com/questions/43740037/datetime-converts-wrong-when-system-time-is-30-march + $dateTime = DateTime::createFromFormat('!' . $aDateFormatData['phpdate'], trim($value)); + + if ($dateTime === false) { + $message = sprintf( + 'Could not convert date %s to format %s. Please check your date format settings.', + trim($value), + $aDateFormatData['phpdate'] + ); + LimeExpressionManager::addFrontendFlashMessage('error', $message, $LEM->sid); + } else { + $newValue = $dateTime->format("Y-m-d H:i"); + $newDateTime = DateTime::createFromFormat("!Y-m-d H:i", $newValue); + if($value == $newDateTime->format($aDateFormatData['phpdate'])) { // control if inverse function original value + $value = $newValue; + } else { + $value = "";// Or $value="INVALID" ? : dropdown is OK with this not default. + } } } break; @@ -9162,7 +9163,7 @@ private function _GetVarAttribute($name,$attr,$default,$gseq,$qseq) /** * @param string $op * @param string $name - * @param string $value + * @param double $value * @return int */ public static function SetVariableValue($op,$name,$value) @@ -10282,8 +10283,8 @@ public static function addFrontendFlashMessage($type, $message, $surveyid) { * Convert non-latin numerics in string to latin numerics * Used for datepicker (Hindi, Arabic numbers) * - * @param string str - * @param string lang + * @param string $str + * @param string $lang * @return string */ public static function convertNonLatinNumerics($str, $lang) @@ -10343,7 +10344,7 @@ private static function checkValidityAnswer($type,$value,$sgq,$qinfo) break; case '!': //List - dropdown case 'L': //LIST drop-down/radio-button list - if(substr($sgq,-5)!='other')// We must validate $value==="0", then don't use empty. $value is not set if unrelevant , then don't use $value!==null + if(substr($sgq,-5)!='other')// We must validate $value==="0", then don't use empty. $value is not set if irrelevant , then don't use $value!==null { if($value=="-oth-") { @@ -10522,6 +10523,16 @@ private static function getValidityString($sgqa) } } + /** + * Set currentQset. Used by unit-tests. + * @param array $val + * @return void + */ + public function setCurrentQset(array $val) + { + $this->currentQset = $val; + } + } /** @@ -10546,6 +10557,3 @@ function cmpQuestionSeq($a, $b) } return ($a['qseq'] < $b['qseq']) ? -1 : 1; } - - -?> diff --git a/application/helpers/frontend_helper.php b/application/helpers/frontend_helper.php index b93a5618409..551934f3a31 100644 --- a/application/helpers/frontend_helper.php +++ b/application/helpers/frontend_helper.php @@ -1690,7 +1690,7 @@ function doAssessment($surveyid) $aAttributes = getQuestionAttributeValues($field['qid']); $assessmentValue = (int)$aAttributes['assessment_value']; - $total = $total+(int)$aAttributes['assessment_value']; + // $total = $total+(int)$aAttributes['assessment_value']; $assessmentValue = (int)$aAttributes['assessment_value']; } }else{ @@ -1701,7 +1701,7 @@ function doAssessment($surveyid) if ($usresult){ $usrow = $usresult->read(); $assessmentValue = $usrow['assessment_value']; - $total = $total+$usrow['assessment_value']; + // $total = $total+$usrow['assessment_value']; } } @@ -1799,8 +1799,7 @@ function doAssessment($surveyid) /** * Update SESSION VARIABLE: grouplist * A list of groups in this survey, ordered by group name. -* @param int surveyid -* @param string language +* @param string $language * @param integer $surveyid */ function UpdateGroupList($surveyid, $language) @@ -1914,7 +1913,7 @@ function checkCompletedQuota($surveyid,$return=false) ////Create filtering // Array of field with quota array value $aQuotaFields=array(); - // Array of fieldnames with relevance value : EM fill $_SESSION with default value even is unrelevant (em_manager_helper line 6548) + // Array of fieldnames with relevance value : EM fill $_SESSION with default value even is irrelevant (em_manager_helper line 6548) $aQuotaRelevantFieldnames=array(); // To count number of hidden questions $aQuotaQid=array(); diff --git a/application/helpers/globals.php b/application/helpers/globals.php index e6f668f2f6c..374e48c2046 100644 --- a/application/helpers/globals.php +++ b/application/helpers/globals.php @@ -12,7 +12,9 @@ */ function App() { - return Yii::app(); + /** @var LSYii_Application $app */ + $app = Yii::app(); + return $app; } @@ -33,5 +35,3 @@ function traceVar($variable, $depth = 10) { } Yii::trace($msg, 'vardump'); } - -?> \ No newline at end of file diff --git a/application/helpers/globalsettings_helper.php b/application/helpers/globalsettings_helper.php index 3ce262c863c..59b2ef43691 100644 --- a/application/helpers/globalsettings_helper.php +++ b/application/helpers/globalsettings_helper.php @@ -82,5 +82,3 @@ function setGlobalSetting($settingname, $settingvalue) Yii::app()->setConfig($settingname, $settingvalue); } - -?> diff --git a/application/helpers/ldap_helper.php b/application/helpers/ldap_helper.php index 4d19a539161..eb04f9605b5 100644 --- a/application/helpers/ldap_helper.php +++ b/application/helpers/ldap_helper.php @@ -315,5 +315,3 @@ function prepareLdapQuery($queryId) $ldap_queries[$queryId] = array_map('strtolower',$ldap_queries[$queryId]); $ldap_queries[$queryId]['name']=$QueryName; } - -?> diff --git a/application/helpers/qanda_helper.php b/application/helpers/qanda_helper.php index 4c81c0136db..a17802a164a 100644 --- a/application/helpers/qanda_helper.php +++ b/application/helpers/qanda_helper.php @@ -648,7 +648,6 @@ function return_timer_script($aQuestionAttributes, $ia, $disable=null) 'time_limit_warning'=>$time_limit_warning, 'time_limit_warning_2'=>$time_limit_warning_2, 'time_limit_warning_display_time'=>$time_limit_warning_display_time, - 'time_limit_warning_display_time'=>$time_limit_warning_display_time, 'time_limit_warning_2_display_time'=>$time_limit_warning_2_display_time, 'disable'=>$disable, ), @@ -656,6 +655,40 @@ function return_timer_script($aQuestionAttributes, $ia, $disable=null) return $output; } +/** + * Return class of a specific row (hidden by relevance) + * @param int $surveyId actual survey id + * @param string $baseName the base name of the question + * @param string $name The name of the question/row to test + * @param array $aQuestionAttributes the question attributes + * @return string + */ + +function currentRelevecanceClass($surveyId,$baseName,$name,$aQuestionAttributes) { + $relevanceStatus=!isset($_SESSION["survey_{$surveyId}"]['relevanceStatus'][$name]) || $_SESSION["survey_{$surveyId}"]['relevanceStatus'][$name]; + if($relevanceStatus) { + return ""; + } + $sExcludeAllOther = isset($aQuestionAttributes['exclude_all_others']) ? trim($aQuestionAttributes['exclude_all_others']) : ''; + /* EM don't set difference between relevance in session, if exclude_all_others is set , just ls-disabled */ + if($sExcludeAllOther) { + foreach(explode(';',$sExcludeAllOther) as $sExclude) + { + $sExclude = $baseName . $sExclude; + if ((!isset($_SESSION["survey_{$surveyId}"]['relevanceStatus'][$sExclude]) || $_SESSION["survey_{$surveyId}"]['relevanceStatus'][$sExclude]) + && (isset($_SESSION["survey_{$surveyId}"][$sExclude]) && $_SESSION["survey_{$surveyId}"][$sExclude] == "Y") + ) { + return "ls-irrelevant ls-disabled"; + } + } + } + + $filterStyle=!empty($aQuestionAttributes['array_filter_style']); // Currently null/0/false=> hidden , 1 : disabled + if($filterStyle) { + return "ls-irrelevant ls-disabled"; + } + return "ls-irrelevant ls-hidden"; +} /** * @param string $rowname */ @@ -668,45 +701,7 @@ function return_display_style($ia, $aQuestionAttributes, $thissurvey, $rowname) //~ if (isset($_SESSION["survey_{$surveyid}"]['relevanceStatus'][$rowname]) && !$_SESSION["survey_{$surveyid}"]['relevanceStatus'][$rowname]) //~ { //~ // If using exclude_all_others, then need to know whether irrelevant rows should be hidden or disabled - //~ if (isset($aQuestionAttributes['exclude_all_others'])) - //~ { - //~ $disableit=false; - //~ foreach(explode(';',trim($aQuestionAttributes['exclude_all_others'])) as $eo) - //~ { - //~ $eorow = $ia[1] . $eo; - //~ if ((!isset($_SESSION["survey_{$surveyid}"]['relevanceStatus'][$eorow]) || $_SESSION["survey_{$surveyid}"]['relevanceStatus'][$eorow]) - //~ && (isset($_SESSION[$eorow]) && $_SESSION[$eorow] == "Y")) - //~ { - //~ $disableit = true; - //~ } - //~ } - //~ if ($disableit) - //~ { - //~ $htmltbody2 .= " disabled='disabled'"; - //~ } - //~ else - //~ { - //~ if (!isset($aQuestionAttributes['array_filter_style']) || $aQuestionAttributes['array_filter_style'] == '0') - //~ { - //~ $htmltbody2 .= " style='display: none'"; - //~ } - //~ else - //~ { - //~ $htmltbody2 .= " disabled='disabled'"; - //~ } - //~ } - //~ } - //~ else - //~ { - //~ if (!isset($aQuestionAttributes['array_filter_style']) || $aQuestionAttributes['array_filter_style'] == '0') - //~ { - //~ $htmltbody2 .= " style='display: none'"; - //~ } - //~ else - //~ { - //~ $htmltbody2 .= " disabled='disabled'"; - //~ } - //~ } + //~ } //~ return $htmltbody2; @@ -716,9 +711,13 @@ function return_display_style($ia, $aQuestionAttributes, $thissurvey, $rowname) * @param integer $surveyid : the survey id * @param string $subquestionName : the target name * @param array $aQuestionAttributes : the attribute of the question (for array_filter_style actually) + * @deprecated not used & broken */ function getExpressionManagerClass($surveyid,$subquestionName,$aQuestionAttributes=null) { + /** + FIXME $rowname not defined!! + */ if (isset($_SESSION["survey_{$surveyid}"]['relevanceStatus'][$rowname]) && !$_SESSION["survey_{$surveyid}"]['relevanceStatus'][$rowname]) { @@ -1138,8 +1137,12 @@ function do_date($ia) $dateoutput=trim($_SESSION['survey_'.Yii::app()->getConfig('surveyID')][$ia[1]]); if ($dateoutput != '' && $dateoutput != 'INVALID') { - $datetimeobj = new Date_Time_Converter($dateoutput , "Y-m-d H:i"); - $dateoutput = $datetimeobj->convert($dateformatdetails['phpdate']); + $datetimeobj = DateTime::createFromFormat('!Y-m-d H:i', fillDate(trim($dateoutput))); + if($datetimeobj) { + $dateoutput = $datetimeobj->format($dateformatdetails['phpdate']); + } else { + $dateoutput = ''; // Imported value and some old survey can have 0000-00-00 00:00:00 + } } @@ -1164,8 +1167,12 @@ function do_date($ia) $dateoutput = trim($_SESSION['survey_'.Yii::app()->getConfig('surveyID')][$ia[1]]); if ($dateoutput != '' && $dateoutput != 'INVALID') { - $datetimeobj = new Date_Time_Converter($dateoutput , "Y-m-d H:i"); - $dateoutput = $datetimeobj->convert($dateformatdetails['phpdate']); + $datetimeobj = DateTime::createFromFormat('!Y-m-d H:i', fillDate(trim($dateoutput))); + if ($datetimeobj) { + $dateoutput = $datetimeobj->format($dateformatdetails['phpdate']); + } else { + $dateoutput = ''; + } } // Max length of date : Get the date of 1999-12-30 at 32:59:59 to be sure to have space with non leading 0 format @@ -1574,6 +1581,8 @@ function do_list_radio($ia) $iColumnWidth = ''; if ($iNbCols > 1) { + // Add a class on the wrapper + $coreClass .= " multiple-list nbcol-{$iNbCols}"; // First we calculate the width of each column // Max number of column is 12 http://getbootstrap.com/css/#grid $iColumnWidth = round(12 / $iNbCols); @@ -2122,7 +2131,6 @@ function do_ranking($ia) 'basename' => $ia[1], 'max_answers' => $max_answers, 'min_answers' => $min_answers, - 'answers' => $answers, 'choice_title' => $choice_title, 'rank_title' => $rank_title, 'showpopups' => $aQuestionAttributes["showpopups"], @@ -2180,8 +2188,9 @@ function do_multiplechoice($ia) $iRowCount = 0; $isOpen = false; // Is a column opened - // TODO: check if still used - if($iNbCols > 1) { + if ($iNbCols > 1) { + // Add a class on the wrapper + $coreClass .= " multiple-list nbcol-{$iNbCols}"; // First we calculate the width of each column // Max number of column is 12 http://getbootstrap.com/css/#grid $iColumnWidth = round(12 / $iNbCols); @@ -2208,12 +2217,9 @@ function do_multiplechoice($ia) $i++; // general count of loop, to check if the item is the last one for column process. Never reset. $iRowCount++; // counter of number of row by column. Is reset to zero each time a column is full. $myfname = $ia[1].$ansrow['title']; - $extra_class =""; - /* Check for array_filter */ - $sDisplayStyle = return_display_style($ia, $aQuestionAttributes, $thissurvey, $myfname); + $relevanceClass=currentRelevecanceClass($iSurveyId,$ia[1],$myfname,$aQuestionAttributes); $checkedState = ''; - /* If the question has already been ticked, check the checkbox */ if (isset($_SESSION['survey_'.Yii::app()->getConfig('surveyID')][$myfname])) { @@ -2245,8 +2251,6 @@ function do_multiplechoice($ia) // Insert row // Display the answer row $sRows .= doRender('/survey/questions/answer/multiplechoice/rows/answer_row', array( - 'extra_class' => $extra_class, - 'sDisplayStyle' => $sDisplayStyle, 'name' => $ia[1], // field name 'title' => $ansrow['title'], 'question' => $ansrow['question'], @@ -2255,6 +2259,7 @@ function do_multiplechoice($ia) 'sCheckconditionFunction' => $sCheckconditionFunction, 'myfname' => $myfname, 'sValue' => $sValue, + 'relevanceClass' => $relevanceClass, ), true); //// @@ -2277,7 +2282,7 @@ function do_multiplechoice($ia) { $iRowCount++; $myfname = $ia[1].'other'; - + $relevanceClass=currentRelevecanceClass($iSurveyId,$ia[1],$myfname,$aQuestionAttributes); $checkedState = ''; // othercbox can be not display, because only input text goes to database if (isset($_SESSION['survey_'.Yii::app()->getConfig('surveyID')][$myfname]) && trim($_SESSION['survey_'.Yii::app()->getConfig('surveyID')][$myfname])!='') @@ -2326,7 +2331,6 @@ function do_multiplechoice($ia) // Display the answer row $sRows .= doRender('/survey/questions/answer/multiplechoice/rows/answer_row_other', array( 'myfname' => $myfname, - 'sDisplayStyle' => (isset($sDisplayStyle))?$sDisplayStyle:'', 'othertext' => $othertext, 'checkedState' => $checkedState, 'kpclass' => $kpclass, @@ -2334,6 +2338,7 @@ function do_multiplechoice($ia) 'oth_checkconditionFunction' => $oth_checkconditionFunction, 'checkconditionFunction' => $checkconditionFunction, 'sValueHidden' => $sValueHidden, + 'relevanceClass' => $relevanceClass, ), true); //// @@ -2372,7 +2377,7 @@ function do_multiplechoice_withcomments($ia) global $thissurvey; $kpclass = testKeypad($thissurvey['nokeyboard']); // Virtual keyboard (probably obsolete today) $inputnames = array(); - + $coreClass="ls-answers answers-list checkbox-text-list"; $checkconditionFunction = "checkconditions"; $aQuestionAttributes = QuestionAttribute::model()->getQuestionAttributes($ia[0]); @@ -2466,16 +2471,12 @@ function do_multiplechoice_withcomments($ia) } $sRows = ""; - $sDisplayStyle = ''; $inputCOmmentValue = ''; $checked = ''; foreach ($toIterate as $ansrow) { $myfname = $ia[1].$ansrow['title']; - /* Check for array_filter */ - $sDisplayStyle = return_display_style($ia, $aQuestionAttributes, $thissurvey, $myfname); - if($label_width < strlen(trim(strip_tags($ansrow['question'])))) { $label_width = strlen(trim(strip_tags($ansrow['question']))); @@ -2502,7 +2503,6 @@ function do_multiplechoice_withcomments($ia) $inputCOmmentValue = htmlspecialchars($_SESSION['survey_'.Yii::app()->getConfig('surveyID')][$myfname2],ENT_QUOTES); $sRows .= doRender('/survey/questions/answer/multiplechoice_with_comments/rows/answer_row', array( - 'sDisplayStyle' => (isset($sDisplayStyle))?$sDisplayStyle:'', 'kpclass' => $kpclass, 'title' => '', 'liclasses' => 'responsive-content question-item answer-item checkbox-text-item', @@ -2558,7 +2558,6 @@ function do_multiplechoice_withcomments($ia) 'liid' => 'javatbd'.$myfname, 'kpclass' => $kpclass, 'title' => gT('Other'), - 'sDisplayStyle' => $sDisplayStyle, 'name' => $myfname, 'id' => 'answer'.$myfname, 'value' => $value, // TODO : check if it should be the same than javavalue @@ -2580,8 +2579,6 @@ function do_multiplechoice_withcomments($ia) $inputnames[]=$myfname2; } - $coreClass = ''; // TODO - $answer = doRender('/survey/questions/answer/multiplechoice_with_comments/answer', array( 'sRows' => $sRows, 'coreClass'=>$coreClass, @@ -2737,10 +2734,10 @@ function upload_$ia[1]() {