[], 'users' => ['*'], //everybody ], [ 'allow', 'actions' => [ 'view', 'delete', 'index', 'insert', 'listsurveys', 'newSurvey', 'regenerateQuestionCode', 'renderItemsSelected', 'applythemeoptions', 'changeMultipleSurveyGroup', 'changeMultipleTheme', 'deleteMultiple', 'fakebrowser', 'getAjaxMenuArray', 'getAjaxQuestionGroupArray', 'getAjaxSurveyList', 'getCurrentEditorValues', 'getDataSecTextSettings', 'getDateFormatOptions', 'getAllSurveyIds', 'updateAccessMode', '' ], 'users' => ['@'], //only login users ], ['deny'], //always deny all actions not mentioned above ]; } /** * Set filters for all actions * @return string[] */ public function filters() { return [ 'postOnly + copy' ]; } /** * SurveyAdministrationController constructor. * @param $id * @param null $module * @throws CException */ public function __construct($id, $module = null) { Yii::app()->request->updateNavigationStack(); // Make sure viewHelper can be autoloaded Yii::import('application.helpers.viewHelper'); parent::__construct($id, $module); } /** * Prepare controller state before rendering a view. * * Sets the controller layout based on whether a survey context is present, initializes * the LimeExpressionManager for the current survey when applicable, and registers * editor-related client scripts unless the request is an Ajax request. * * @param string $view The view name about to be rendered. * @return bool True to continue with rendering, false to abort. */ protected function beforeRender($view) { if (!empty($this->aData['surveyid'])) { $this->aData['oSurvey'] = $this->aData['oSurvey'] ?? Survey::model()->findByPk($this->aData['surveyid']); // Needed to evaluate EM expressions in question summary // See bug #11845 LimeExpressionManager::SetSurveyId($this->aData['surveyid']); LimeExpressionManager::StartProcessingPage(false, true); $this->layout = 'layout_questioneditor'; } else { $this->layout = 'main'; } // Used in question editor (pjax). App()->getClientScript()->registerPackage('ace'); App()->getClientScript()->registerPackage('jquery-ace'); return parent::beforeRender($view); } /** * Load complete view of survey properties and actions specified by $iSurveyID * * @return void * @throws CException */ public function actionView() { $iSurveyID = $this->getSurveyIdFromGetRequest(); if (!Permission::model()->hasSurveyPermission((int)$iSurveyID, 'survey', 'read')) { Yii::app()->user->setFlash('error', gT("No permission or survey does not exist.")); $this->redirect(Yii::app()->request->urlReferrer); } $beforeSurveyAdminView = new PluginEvent('beforeSurveyAdminView'); $beforeSurveyAdminView->set('surveyId', $iSurveyID); App()->getPluginManager()->dispatchEvent($beforeSurveyAdminView); // We load the panel packages for quick actions $iSurveyID = sanitize_int($iSurveyID); //todo: first check if survey is new and DO NOT try to access model attributes without isset-check ... $survey = Survey::model()->findByPk($iSurveyID); //yii standard is overwritten here ... $baselang = $survey->language; $aData = array('aAdditionalLanguages' => $survey->additionalLanguages); // Reinit LEMlang and LEMsid: ensure LEMlang are set to default lang, surveyid are set to this survey ID // Ensure Last GetLastPrettyPrintExpression get info from this sid and default lang LimeExpressionManager::SetEMLanguage($baselang); LimeExpressionManager::SetSurveyId($iSurveyID); LimeExpressionManager::StartProcessingPage(false, true); //breadcrumb if (isset($survey->currentLanguageSettings) && isset($survey->currentLanguageSettings->surveyls_title)) { $aData['title_bar']['title'] = $survey->currentLanguageSettings->surveyls_title . " (" . gT("ID") . ":" . $iSurveyID . ")"; } else { $aData['title_bar']['title'] = 'Unknown_language_title' . " (" . gT("ID") . ":" . $iSurveyID . ")"; } //buttons in topbar $topbarData = TopbarConfiguration::getSurveyTopbarData($iSurveyID); $aData['topbar']['middleButtons'] = $this->renderPartial( 'partial/topbar/surveyTopbarLeft_view', $topbarData, true ); $aData['topbar']['rightButtons'] = $this->renderPartial( 'partial/topbar/surveyTopbarRight_view', $topbarData, true ); $aData['surveyid'] = $iSurveyID; $aData['sid'] = $iSurveyID; //frontend need this to render topbar for the view // Last survey visited SettingsUser::setUserSetting('last_survey', $iSurveyID); $aData['sidemenu']["survey_menu"] = true; // We get the last question visited by user for this survey // 2025-02-19 seem not used , we are inside survey $aData['showLastQuestion'] = false; $lastquestionID = SettingsUser::getUserSetting('last_question', $iSurveyID, 'Survey'); if ($lastquestionID) { $question = Question::model()->findByPk(intval($lastquestionID)); if ($question) { $survey = Survey::model()->findByPk($question->sid); $baselang = $survey->language; $aData['last_question_name'] = $question['title']; if (!empty($question->questionl10ns[$baselang]['question'])) { $aData['last_question_name'] .= ' : ' . $question->questionl10ns[$baselang]['question']; } $aData['last_question_link'] = $this->createUrl( "questionAdministration/view", [ 'surveyid' => $question->sid, 'gid' => $question->gid, 'qid' => $question->qid ] ); } } $aData['templateapiversion'] = Template::model()->getTemplateConfiguration(null, $iSurveyID)->getApiVersion(); $user = User::model()->findByPk(App()->session['loginID']); $aData['owner'] = $user->attributes; // if ((empty($aData['display']['menu_bars']['surveysummary']) || !is_string($aData['display']['menu_bars']['surveysummary'])) && !empty($aData['gid'])) { // $aData['display']['menu_bars']['surveysummary'] = 'viewgroup'; // } $surveyUrls = []; foreach ($survey->allLanguages as $language) { $surveyUrls[$language] = $survey->getSurveyUrl($language); } $aData['surveyUrls'] = $surveyUrls; $this->surveysummary($aData); // Display 'Overview' in Green Bar // $aData['subaction'] = gT('Overview'); $surveyActivationFeedback = Yii::app()->request->getParam('surveyActivationFeedback', null); $aData['surveyActivationFeedback'] = $surveyActivationFeedback; $this->aData = $aData; $this->render('sidebody'); } /** * List Surveys. * * @return void */ public function actionListsurveys() { Yii::app()->loadHelper('surveytranslator'); $aData = array(); $aData['issuperadmin'] = false; if (Permission::model()->hasGlobalPermission('superadmin', 'read')) { $aData['issuperadmin'] = true; } $aData['model'] = new Survey('search'); $aData['groupModel'] = new SurveysGroups('search'); $aData['topbar']['title'] = gT('Survey list'); $aData['topbar']['backLink'] = App()->createUrl('dashboard/view'); $aData['topbar']['middleButtons'] = $this->renderPartial('partial/topbarBtns/leftSideButtons', [], true); $this->aData = $aData; $this->render('listSurveys_view', $aData); } /** * Delete multiple survey * * @return void * @throws CException */ public function actionDeleteMultiple() { $aSurveys = json_decode(Yii::app()->request->getPost('sItems', '')); $aResults = array(); foreach ($aSurveys as $iSurveyID) { $iSurveyID = sanitize_int($iSurveyID); $oSurvey = Survey::model()->findByPk($iSurveyID); $aResults[$iSurveyID]['title'] = $oSurvey->correct_relation_defaultlanguage->surveyls_title; if (Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'delete')) { $aResults[$iSurveyID]['result'] = Survey::model()->deleteSurvey($iSurveyID); } else { $aResults[$iSurveyID]['result'] = false; $aResults[$iSurveyID]['error'] = gT("User does not have valid permissions"); } } $this->renderPartial( 'ext.admin.survey.ListSurveysWidget.views.massive_actions._action_results', array( 'aResults' => $aResults, 'successLabel' => gT('Deleted') ) ); } /** * Render selected items for massive action * * @return void */ public function actionRenderItemsSelected() { $aSurveys = json_decode(Yii::app()->request->getPost('$oCheckedItems', '')); $aResults = []; $tableLabels = array(gT('Survey ID'), gT('Survey title'), gT('Status')); foreach ($aSurveys as $iSurveyID) { if (!is_numeric($iSurveyID)) { continue; } $oSurvey = Survey::model()->findByPk($iSurveyID); $aResults[$iSurveyID]['title'] = $oSurvey->correct_relation_defaultlanguage->surveyls_title; $aResults[$iSurveyID]['result'] = 'selected'; } $this->renderPartial( 'ext.admin.grid.MassiveActionsWidget.views._selected_items', array( 'aResults' => $aResults, 'successLabel' => gT('Selected'), 'tableLabels' => $tableLabels, 'caption' => gT('Selected surveys'), ) ); } /** * Returns all survey IDs matching the current filter as a JSON array. * Used by the "Select all" button in the floating actions bar to select * all surveys across pagination. * * @return void */ public function actionGetAllSurveyIds() { if (!Yii::app()->request->isAjaxRequest) { throw new CHttpException(400, 'Invalid request'); } $model = new Survey('search'); // Reset active attribute to '' so search() does not filter by the DB column default ('N'). // This mirrors ListSurveysWidget which explicitly sets $this->model->active = "". $model->active = ''; // Apply Survey[...] grid filters (e.g. searched_value) $filters = Yii::app()->request->getParam('Survey', []); if (is_array($filters)) { $model->setAttributes($filters, false); } // Apply the status filter that ListSurveysWidget reads from $_GET['active'] $activeFilter = Yii::app()->request->getParam('active', ''); if (!empty($activeFilter)) { $model->active = $activeFilter; } // Apply survey-group filter $gsid = Yii::app()->request->getParam('gsid', ''); if (!empty($gsid)) { $model->gsid = (int) $gsid; } // Fetch every matching ID in a single unbounded query. // getData() only returns one page, so a large fixed pageSize can still miss // rows on larger installations. Disabling pagination removes the LIMIT/OFFSET // entirely so all matching survey IDs are always returned. $dataProvider = $model->search(); $dataProvider->setPagination(false); $surveys = $dataProvider->getData(); $ids = array_map(static function ($survey) { return (int) $survey->sid; }, $surveys); header('Content-Type: application/json'); echo json_encode(array_values($ids)); Yii::app()->end(); } /** * Regeerates the question code * Automatically renumbers the "question codes" so that they follow * a methodical numbering method. * * @return void * */ public function actionRegenerateQuestionCodes() { $iSurveyID = $this->getSurveyIdFromGetRequest(); $sSubAction = Yii::app()->request->getParam('subaction'); if (!Permission::model()->hasSurveyPermission($iSurveyID, 'surveycontent', 'update')) { Yii::app()->setFlashMessage(gT("You do not have permission to access this page."), 'error'); $this->redirect(array('surveyAdministration/view', 'surveyid' => $iSurveyID)); } $oSurvey = Survey::model()->findByPk($iSurveyID); if ($oSurvey->isActive) { Yii::app()->setFlashMessage(gT("You can't update question code for an active survey."), 'error'); $this->redirect(array('surveyAdministration/view', 'surveyid' => $iSurveyID)); } //check subaction if (!($sSubAction === 'straight' || $sSubAction === 'bygroup')) { Yii::app()->setFlashMessage(gT("Invalid parameters."), 'error'); $this->redirect(array('surveyAdministration/view', 'surveyid' => $iSurveyID)); } //Automatically renumbers the "question codes" so that they follow //a methodical numbering method $iQuestionNumber = 1; $iGroupNumber = 0; $iGroupSequence = 0; $oQuestions = Question::model() ->with(['group' => ['alias' => 'g'], 'questionl10ns']) ->findAll( array( 'select' => 't.qid,t.gid', 'condition' => "t.sid=:sid and questionl10ns.language=:language and parent_qid=0", 'order' => 'g.group_order, question_order', 'params' => array(':sid' => $iSurveyID, ':language' => $oSurvey->language) ) ); foreach ($oQuestions as $oQuestion) { if ($sSubAction == 'bygroup' && $iGroupNumber != $oQuestion->gid) { //If we're doing this by group, restart the numbering when the group number changes $iQuestionNumber = 1; $iGroupNumber = $oQuestion->gid; $iGroupSequence++; } $sNewTitle = (($sSubAction == 'bygroup') ? ('G' . $iGroupSequence) : '') . "Q" . str_pad($iQuestionNumber, 5, "0", STR_PAD_LEFT); Question::model()->updateAll(array('title' => $sNewTitle), 'qid=:qid', array(':qid' => $oQuestion->qid)); $iQuestionNumber++; $iGroupNumber = $oQuestion->gid; } /* Expression text need to be update from condition */ LimeExpressionManager::RevertUpgradeConditionsToRelevance($iSurveyID); LimeExpressionManager::UpgradeConditionsToRelevance($iSurveyID); LimeExpressionManager::SetDirtyFlag(); Yii::app()->setFlashMessage(gT("Question codes were successfully regenerated.")); $this->redirect(array('surveyAdministration/view/surveyid/' . $iSurveyID)); } /** * This function prepares the classic view for a new survey * * @return void */ public function actionNewSurvey() { if (!Permission::model()->hasGlobalPermission('surveys', 'create')) { Yii::app()->user->setFlash('error', gT("Access denied!")); $this->redirect(Yii::app()->request->urlReferrer); } $survey = new Survey(); // set 'inherit' values to survey attributes $survey->setToInherit(); Yii::app()->loadHelper('surveytranslator'); Yii::app()->loadHelper('admin.htmleditor'); $aData = $this->generalTabNewSurvey(); $aData = array_merge($aData, $this->getGeneralTemplateData(0)); $esrow = $survey->attributes; $esrow['googleanalyticsapikeysetting'] = $survey->getGoogleanalyticsapikeysetting(); $aData['esrow'] = $esrow; $aData['oSurvey'] = $survey; $aData['bShowAllOptions'] = true; $aData['bShowInherited'] = true; $oSurveyOptions = $survey; $oSurveyOptions->bShowRealOptionValues = false; $oSurveyOptions->setOptions(); $aData['oSurveyOptions'] = $oSurveyOptions->oOptionLabels; $aData['optionsOnOff'] = array( 'Y' => gT('On', 'unescaped'), 'N' => gT('Off', 'unescaped'), ); $aData['optionsAdmin'] = array( 'default' => gT('Default', 'unescaped'), 'owner' => gT('Current user', 'unescaped'), 'custom' => gT('Custom', 'unescaped'), ); $testLanguages = getLanguageDataRestricted(true, 'short'); $aData['edittextdata']['listLanguagesCode'] = $testLanguages; $aData['edittextdata']['aSurveyGroupList'] = SurveysGroups::getSurveyGroupsList(); $arrayed_data = array(); $arrayed_data['oSurvey'] = $survey; $arrayed_data['data'] = $aData; $arrayed_data['title_bar']['title'] = gT('New survey'); // topbar $aData['topbar']['title'] = gT('Create survey'); $aData['topbar']['rightButtons'] = $this->renderPartial( 'partial/topbarBtns_create_survey/rightSideButtons', [], true ); $this->aData = $aData; //this is not the layout $this->render('newSurvey_view', [ 'arrayed_data' => $arrayed_data ]); } /** * Saves the new survey after the creation screen is submitted * * @return string * @throws CException */ public function actionInsert() { if (Permission::model()->hasGlobalPermission('surveys', 'create')) { $user = Yii::app()->user; // CHECK IF USER OWNS PREVIOUS SURVEYS BEGIN if ($user !== null) { $userid = (int) $user->getId(); $ownsPreviousSurveys = Survey::model()->findByAttributes(array('owner_id' => $userid)); if ($ownsPreviousSurveys === null) { $ownsPreviousSurveys = false; } else { $ownsPreviousSurveys = true; } } // CHECK IF USER OWNS PREVIOUS SURVEYS END // Check if survey title was set $surveyTitle = Yii::app()->request->getPost('surveyls_title'); $surveyTitle = trim((string) $surveyTitle); if ($surveyTitle == '') { $alertError = gT("Survey could not be created because it did not have a title"); return Yii::app()->getController()->renderPartial( '/admin/super/_renderJson', array( 'data' => array( 'alertData' => $alertError, 'missingField' => 'surveyls_title' ) ), false, false ); } Yii::app()->loadHelper("surveytranslator"); $simpleSurveyValues = new \LimeSurvey\Datavalueobjects\SimpleSurveyValues(); $baseLanguage = App()->request->getPost('language'); if ($baseLanguage === null) { $baseLanguage = 'en'; //shoulb be const somewhere ... or get chosen language from user } $simpleSurveyValues->baseLanguage = $baseLanguage; $simpleSurveyValues->surveyGroupId = (int) App()->request->getPost('gsid', '1'); $simpleSurveyValues->title = $surveyTitle; $administrator = Yii::app()->request->getPost('administrator'); if ($administrator == 'custom') { $simpleSurveyValues->admin = Yii::app()->request->getPost('admin'); $simpleSurveyValues->adminEmail = Yii::app()->request->getPost('adminemail'); } $overrideAdministrator = ($administrator != 'owner'); $surveyCreator = new \LimeSurvey\Models\Services\CreateSurvey(new Survey(), new SurveyLanguageSetting()); $newSurvey = $surveyCreator->createSimple( $simpleSurveyValues, (int)Yii::app()->user->getId(), Permission::model(), $overrideAdministrator ); if (!$newSurvey) { Yii::app()->setFlashMessage(gT("Survey could not be created."), 'error'); $this->redirect(Yii::app()->request->urlReferrer); } $iNewSurveyid = $newSurvey->sid; $this->aData['surveyid'] = $newSurvey->sid; //import to render correct layout in before_render // This will force the generation of the entry for survey group TemplateConfiguration::checkAndcreateSurveyConfig($iNewSurveyid); $createSample = SettingsUser::getUserSettingValue('createsample'); if ($createSample === null || $createSample === 'default') { $createSample = Yii::app()->getConfig('createsample'); } // Figure out destination if ($createSample) { $iNewGroupID = $this->createSampleGroup($iNewSurveyid); $iNewQuestionID = $this->createSampleQuestion($iNewSurveyid, $iNewGroupID); Yii::app()->setFlashMessage(gT("Your new survey was created. We also created a first question group and an example question for you."), 'info'); $redirecturl = $this->getSurveyAndSidemenueDirectionURL( $iNewSurveyid, $iNewGroupID, $iNewQuestionID, 'structure' ); } elseif (!$ownsPreviousSurveys) { // SET create question and create question group as default view. $redirecturl = $this->createUrl( 'questionGroupsAdministration/add/', ['surveyid' => $iNewSurveyid] ); } else { $redirecturl = $this->createUrl( 'surveyAdministration/view/', ['iSurveyID' => $iNewSurveyid] ); Yii::app()->setFlashMessage(gT("Your new survey was created."), 'info'); } return Yii::app()->getController()->renderPartial( '/admin/super/_renderJson', array( 'data' => array( 'redirecturl' => $redirecturl, ) ), false, false ); } $this->redirect(Yii::app()->request->urlReferrer); } /** * New create survey process with default values. * Includes to open new question editor (in cloud) when editor is activated by user. * * @return void */ public function actionCreateSurvey() { if (Permission::model()->hasGlobalPermission('surveys', 'create')) { $userId = App()->user->id; $currentUser = User::model()->findByPk($userId); $currentUserLanguage = $currentUser->lang; //we need the language short if ($currentUserLanguage === 'auto') { $currentUserLanguage = Yii::app()->getConfig('defaultlang'); } $simpleSurveyValues = new \LimeSurvey\Datavalueobjects\SimpleSurveyValues(); $simpleSurveyValues->title = gt('Untitled survey'); $simpleSurveyValues->surveyGroupId = 1; $simpleSurveyValues->baseLanguage = $currentUserLanguage; $surveyCreator = new \LimeSurvey\Models\Services\CreateSurvey(new Survey(), new SurveyLanguageSetting()); $newSurvey = $surveyCreator->createSimple( $simpleSurveyValues, (int)Yii::app()->user->getId(), Permission::model() ); if ($newSurvey) { //create example group and example question $iNewGroupID = $this->createSampleGroup($newSurvey->sid); $iNewQuestionID = $this->createSampleQuestion($newSurvey->sid, $iNewGroupID); App()->setFlashMessage(gT("Your new survey was created. We also created a first question group and an example question for you."), 'info'); $redirectUrl = $this->getSurveyAndSidemenueDirectionURL( $newSurvey->sid, $iNewGroupID, $iNewQuestionID, 'structure' ); $this->redirect($redirectUrl); } else { App()->setFlashMessage(gT("Survey could not be created."), 'error'); $this->redirect(Yii::app()->request->urlReferrer); } } else { App()->setFlashMessage(gT('Access denied!'), 'error'); $this->redirect(Yii::app()->request->urlReferrer); } } /** * todo: what is this? why do we need it? *(it'S just an js-script alert window rendert here ...) * * @return void * @throws CException */ public function actionFakebrowser() { $this->renderPartial('/admin/survey/newSurveyBrowserMessage', array()); } /** * Function responsible to import survey resources from a '.zip' file. * * @todo is this function used? the function editlocalsetting does not exists (also not in old controller surveyadmin) * * @return void */ public function actionImportsurveyresources() { $iSurveyID = sanitize_int(Yii::app()->request->getPost('surveyid')); if (!Permission::model()->hasSurveyPermission($iSurveyID, 'surveycontent', 'update')) { Yii::app()->user->setFlash('error', gT("Access denied!")); $this->redirect(Yii::app()->request->urlReferrer); } if (!empty($iSurveyID)) { if (Yii::app()->getConfig('demoMode')) { Yii::app()->user->setFlash('error', gT("Demo mode only: Uploading files is disabled in this system.")); $this->redirect(array('surveyAdministration/rendersidemenulink/', 'surveyid' => $iSurveyID, 'subaction' => 'generalsettings')); } // Create temporary directory // If dangerous content is unzipped // then no one will know the path Yii::import('application.helpers.common_helper', true); $extractdir = createRandomTempDir(); $zipfilename = $_FILES['the_file']['tmp_name']; $basedestdir = Yii::app()->getConfig('uploaddir') . "/surveys"; $destdir = $basedestdir . "/$iSurveyID/"; if (!is_writeable($basedestdir)) { Yii::app()->user->setFlash('error', sprintf( gT("Incorrect permissions in your %s folder."), $basedestdir )); $this->redirect(array('surveyAdministration/rendersidemenulink/', 'surveyid' => $iSurveyID, 'subaction' => 'generalsettings')); } if (!is_dir($destdir)) { mkdir($destdir); } $aImportedFilesInfo = array(); $aErrorFilesInfo = array(); if (is_file($zipfilename)) { $zip = new LimeSurvey\Zip(); if ($zip->open($zipfilename) !== true || $zip->extractTo($extractdir) !== true) { Yii::app()->user->setFlash( 'error', gT("This file is not a valid ZIP file archive. Import failed. ") . $zip->getStatusString() ); $this->redirect(array('surveyAdministration/rendersidemenulink/', 'surveyid' => $iSurveyID, 'subaction' => 'generalsettings')); } $zip->close(); // now read tempdir and copy authorized files only $folders = array('flash', 'files', 'images'); $filteredImportedResources = new FilterImportedResources(); foreach ($folders as $folder) { list($_aImportedFilesInfo, $_aErrorFilesInfo) = $filteredImportedResources->filterImportedResources( $extractdir . "/" . $folder, $destdir . $folder ); $aImportedFilesInfo = array_merge($aImportedFilesInfo, $_aImportedFilesInfo); $aErrorFilesInfo = array_merge($aErrorFilesInfo, $_aErrorFilesInfo); } // Deletes the temp directory rmdirr($extractdir); // Delete the temporary file unlink($zipfilename); if (empty($aErrorFilesInfo) && empty($aImportedFilesInfo)) { Yii::app()->user->setFlash( 'error', gT("This ZIP archive contains no valid Resources files. Import failed.") ); $this->redirect(array('surveyAdministration/rendersidemenulink/', 'surveyid' => $iSurveyID, 'subaction' => 'resources')); } } else { Yii::app()->setFlashMessage( gT("An error occurred uploading your file. This may be caused by incorrect permissions for the application /tmp folder."), 'error' ); $this->redirect(array('surveyAdministration/rendersidemenulink/', 'surveyid' => $iSurveyID, 'subaction' => 'resources')); } $aData = array( 'aErrorFilesInfo' => $aErrorFilesInfo, 'aImportedFilesInfo' => $aImportedFilesInfo, 'surveyid' => $iSurveyID ); $aData['display']['menu_bars']['surveysummary'] = true; $survey = Survey::model()->findByPk($iSurveyID); $aData['title_bar']['title'] = $survey->currentLanguageSettings->surveyls_title . " (" . gT("ID") . ":" . $iSurveyID . ")"; $this->aData = $aData; $this->render('importSurveyResources_view', $this->aData); } } /** * Function to call current Editor Values by Ajax * * @param int $sid Given Survey ID * * is still used in sidemenu Text elements (see vue.js ajaxcall) * * @return void * @throws CException */ public function actionGetCurrentEditorValues($sid) { //Permission check if (!Permission::model()->hasSurveyPermission($sid, 'surveycontent', 'read')) { return $this->renderPartial( '/admin/super/_renderJson', array( 'data' => [ 'success' => false, 'message' => gT("No permission"), 'debug' => null ] ), false, false ); } $iSurveyId = (int)$sid; $oSurvey = Survey::model()->findByPk($iSurveyId); $updatePermission = $oSurvey == null ? Permission::model()->hasGlobalPermission('surveys', 'create') : Permission::model()->hasSurveyPermission($iSurveyId, 'surveylocale', 'update'); $aLanguages = []; $aReturner = [ "surveyTitle" => [], "welcome" => [], "description" => [], "endText" => [], "endUrl" => [], "endUrlDescription" => [], "dateFormat" => [], "decimalDivider" => [], "permissions" => [ "update" => $updatePermission, "editorpreset" => Yii::app()->session['htmleditormode'], ] ]; if ($oSurvey == null) { $defaultLanguage = Yii::app()->getConfig('defaultlang'); $aLanguageDetails = getLanguageDetails($defaultLanguage); $aLanguages = [$defaultLanguage => getLanguageCodefromLanguage($defaultLanguage)]; $aReturner["surveyTitle"][$defaultLanguage] = ""; $aReturner["welcome"][$defaultLanguage] = ""; $aReturner["description"][$defaultLanguage] = ""; $aReturner["endText"][$defaultLanguage] = ""; $aReturner["endUrl"][$defaultLanguage] = ""; $aReturner["endUrlDescription"][$defaultLanguage] = ""; $aReturner["dateFormat"][$defaultLanguage] = $aLanguageDetails['dateformat']; $aReturner["decimalDivider"][$defaultLanguage] = $aLanguageDetails['radixpoint']; return Yii::app()->getController()->renderPartial( '/admin/super/_renderJson', [ 'data' => [ "textdata" => $aReturner, "languages" => $aLanguages ] ], false, false ); } foreach ($oSurvey->allLanguages as $sLanguage) { $aLanguages[$sLanguage] = getLanguageNameFromCode($sLanguage, false); $aReturner["surveyTitle"][$sLanguage] = $oSurvey->languagesettings[$sLanguage]->surveyls_title; $aReturner["welcome"][$sLanguage] = $oSurvey->languagesettings[$sLanguage]->surveyls_welcometext; $aReturner["description"][$sLanguage] = $oSurvey->languagesettings[$sLanguage]->surveyls_description; $aReturner["endText"][$sLanguage] = $oSurvey->languagesettings[$sLanguage]->surveyls_endtext; $aReturner["endUrl"][$sLanguage] = $oSurvey->languagesettings[$sLanguage]->surveyls_url; $aReturner["endUrlDescription"][$sLanguage] = $oSurvey->languagesettings[$sLanguage]->surveyls_urldescription; $aReturner["dateFormat"][$sLanguage] = $oSurvey->languagesettings[$sLanguage]->surveyls_dateformat; $aReturner["decimalDivider"][$sLanguage] = $oSurvey->languagesettings[$sLanguage]->surveyls_numberformat; } return Yii::app()->getController()->renderPartial( '/admin/super/_renderJson', [ 'data' => [ "textdata" => $aReturner, "languages" => $aLanguages ] ], false, false ); } /** * Massive action in ListSurveysWidget ... * Ajax request * * @return void * @throws CException */ public function actionChangeMultipleTheme() { $sSurveys = $_POST['sItems'] ?? ''; $aSIDs = json_decode($sSurveys); $aResults = array(); $sTemplate = App()->request->getPost('theme'); foreach ($aSIDs as $iSurveyID) { $aResults = $this->changeTemplate($iSurveyID, $sTemplate, $aResults, true); } $this->renderPartial( 'ext.admin.survey.ListSurveysWidget.views.massive_actions._action_results', array('aResults' => $aResults, 'successLabel' => $sTemplate) ); } /** * Change survey group for multiple survey at once. * Called from survey list massive actions * * @return void * @throws CException */ public function actionChangeMultipleSurveyGroup() { $sSurveys = $_POST['sItems'] ?? ''; $aSIDs = json_decode($sSurveys); $aResults = array(); $iSurveyGroupId = sanitize_int(App()->request->getPost('surveygroupid')); foreach ($aSIDs as $iSurveyID) { $oSurvey = Survey::model()->findByPk((int)$iSurveyID); $aResults[$iSurveyID]['title'] = $oSurvey->correct_relation_defaultlanguage->surveyls_title; /* Permission must be checked with current SurveyGroup, SurveyGroup give Surveys Permission, see mantis issue #19169 */ if (!Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'update')) { $aResults[$iSurveyID]['result'] = false; $aResults[$iSurveyID]['error'] = gT("User does not have valid permissions"); continue; } $oSurvey->gsid = $iSurveyGroupId; if ($oSurvey->save()) { $aResults[$iSurveyID]['result'] = true; } else { $aResults[$iSurveyID]['result'] = false; $aResults[$iSurveyID]['error'] = gT("Survey update failed"); } } Yii::app()->getController()->renderPartial( 'ext.admin.survey.ListSurveysWidget.views.massive_actions._action_results', array('aResults' => $aResults, 'successLabel' => gT("Success")) ); } /** * Toggles Quick action * * @return string | null * @throws CException */ public function actionToggleQuickAction() { $quickactionstate = (int)SettingsUser::getUserSettingValue('quickaction_state'); switch ($quickactionstate) { case null: case 0: $save = SettingsUser::setUserSetting('quickaction_state', 1); break; case 1: $save = SettingsUser::setUserSetting('quickaction_state', 0); break; default: $save = null; } return Yii::app()->getController()->renderPartial( '/admin/super/_renderJson', array( 'data' => [ 'success' => $save, 'newState' => SettingsUser::getUserSettingValue('quickaction_state') ], ), false, false ); } /** * AjaxRequest get questionGroup with containing questions * * @todo this could go to the questiongroupAdministrationController ? * * @param int $surveyid Given Survey ID * * @return string|string[] * @throws CException */ public function actionGetAjaxQuestionGroupArray($surveyid) { $iSurveyID = sanitize_int($surveyid); if (!Permission::model()->hasSurveyPermission($iSurveyID, 'surveycontent', 'read')) { Yii::app()->user->setFlash('error', gT("Access denied!")); $this->redirect(Yii::app()->createUrl('/admin')); } $survey = Survey::model()->findByPk($iSurveyID); $baselang = $survey->language; $lastquestionID = SettingsUser::getUserSetting('last_question', $iSurveyID, 'Survey'); $lastquestiongroupID = SettingsUser::getUserSetting('last_group', $iSurveyID, 'Survey'); $aGroups = QuestionGroup::model()->findAllByAttributes( array('sid' => $iSurveyID), array('order' => 'group_order ASC') ); $aGroupViewable = array(); $aData = ['topBar' => ['name' => 'questionTopbar_view'], "sid" => $iSurveyID]; $topbarConfig = TopbarConfiguration::createFromViewData($aData); $configData = $topbarConfig->getData(); if (count($aGroups)) { foreach ($aGroups as $group) { $curGroup = $group->attributes; // Cast identifiers to int so the JSON stays consistent with jQuery's // numeric .data() conversion on the client (see issue 20625). $curGroup['gid'] = (int) $curGroup['gid']; $curGroup['sid'] = (int) $curGroup['sid']; $curGroup['group_order'] = (int) $curGroup['group_order']; $curGroup['group_name'] = viewHelper::flatEllipsizeText($group->questiongroupl10ns[$baselang]->group_name, true, 150); $curGroup['groupDropdown'] = []; $condarray = getGroupDepsForConditions($surveyid, "all", $group->gid, "by-targgid"); $curGroup['link'] = $this->createUrl( "questionGroupsAdministration/view", ['surveyid' => $surveyid, 'gid' => $group->gid] ); $group->aQuestions = Question::model()->findAllByAttributes( array( "sid" => $iSurveyID, "gid" => $group['gid'], 'parent_qid' => 0 ), array('order' => 'question_order ASC') ); if ($configData['hasSurveyContentReadPermission']) { $curGroup['groupDropdown']['language'] = [ 'id' => '', 'label' => gT("Check logic"), 'icon' => 'ri-checkbox-fill', 'url' => Yii::App()->createUrl("admin/expressions/sa/survey_logic_file/sid/{$iSurveyID}/gid/$group->gid") ]; } if ($configData['hasSurveyContentExportPermission']) { $curGroup['groupDropdown']['export'] = [ 'id' => '', 'label' => gT("Export"), 'icon' => 'ri-download-fill', 'url' => Yii::App()->createUrl("admin/export/sa/group/surveyid/$iSurveyID/gid/$group->gid") ]; } if ($configData['hasSurveyContentDeletePermission']) { if ($configData['oSurvey']->active !== 'Y') { if (is_null($condarray)) { $curGroup['groupDropdown']['delete'] = [ 'id' => '', 'label' => gT("Delete group"), 'icon' => 'ri-delete-bin-fill text-danger', 'dataTitle' => gT('Delete group'), 'dataBtnText' => gT('Delete'), 'dataOnclick' => '(function() { ' . convertGETtoPOST( Yii::app()->createUrl( "questionGroupsAdministration/delete/", [ "asJson" => true, "surveyid" => $iSurveyID, "gid" => $group->gid, "landOnSideMenuTab" => "structure", ] ) ) . '})', 'dataMessage' => gT("Deleting this group will also delete any questions and answers it contains. Are you sure you want to continue?", 'unescaped') ]; } else { $curGroup['groupDropdown']['delete'] = [ 'id' => '', 'label' => gT("Delete group"), 'icon' => 'ri-delete-bin-fill text-danger', 'dataTitle' => gT('Delete group'), 'disabled' => true, 'title' => gT("Impossible to delete this group because there is at least one question having a condition on its content", 'unescaped') ]; } } else { $curGroup['groupDropdown']['delete'] = [ 'id' => '', 'label' => gT("Delete group"), 'icon' => 'ri-delete-bin-fill text-danger', 'dataTitle' => gT('Delete group'), 'disabled' => true, 'title' => gT("It is not possible to add/delete groups if the survey is active.", 'unescaped') ]; } } $curGroup['questions'] = array(); foreach ($group->aQuestions as $question) { if (is_object($question)) { $curQuestion = $question->attributes; // Cast identifiers to int so the JSON stays consistent with jQuery's // numeric .data() conversion on the client (see issue 20625). $curQuestion['qid'] = (int) $curQuestion['qid']; $curQuestion['gid'] = (int) $curQuestion['gid']; $curQuestion['sid'] = (int) $curQuestion['sid']; $curQuestion['parent_qid'] = (int) $curQuestion['parent_qid']; $curQuestion['question_order'] = (int) $curQuestion['question_order']; $curQuestion['link'] = $this->createUrl( "questionAdministration/view", ['surveyid' => $surveyid, 'gid' => $group->gid, 'qid' => $question->qid] ); $curQuestion['hidden'] = isset($question->questionattributes['hidden']) && !empty($question->questionattributes['hidden']->value); $questionText = isset($question->questionl10ns[$baselang]) ? $question->questionl10ns[$baselang]->question : ''; // We have to limit the question text length here, otherwise the whole question is loaded into the navigation tree $curQuestion['question_flat'] = viewHelper::flatEllipsizeText($questionText, true, 150); $hasdefaultvalues = (QuestionTheme::findQuestionMetaData($question->type)['settings'])->hasdefaultvalues; $curQuestion['questionDropdown'] = []; if ($configData['hasSurveyContentUpdatePermission']) { $curQuestion['questionDropdown']['conditionDesigner'] = [ 'id' => 'conditions_button', 'label' => gT("Condition designer"), 'icon' => 'ri-git-branch-fill icon', 'url' => Yii::App()->createUrl("admin/conditions/sa/index/subaction/editconditionsform/surveyid/$iSurveyID/gid/$question->gid/qid/$question->qid") ]; } $curQuestion['questionDropdown']['editDefault'] = [ 'id' => 'default_value_button', 'label' => gT("Edit default answers"), 'icon' => 'ri-grid-line ', 'url' => Yii::App()->createUrl("questionAdministration/editdefaultvalues/surveyid/$iSurveyID/gid/$question->gid/qid/$question->qid"), 'active' => $configData['hasSurveyContentUpdatePermission'] && $hasdefaultvalues > 0 ? 1 : 0 ]; if ($configData['hasSurveyContentExportPermission']) { $curQuestion['questionDropdown']['export'] = [ 'id' => '', 'label' => gT("Export"), 'icon' => 'ri-download-fill', 'url' => Yii::App()->createUrl("admin/export/sa/question/surveyid/$iSurveyID/gid/$question->gid/qid/$question->qid") ]; } if ($configData['hasSurveyContentCreatePermission'] && ($configData['oSurvey']->active != 'Y')) { $curQuestion['questionDropdown']['copy'] = [ 'id' => 'copy_button', 'label' => gT("Copy"), 'icon' => 'ri-file-copy-line icon', 'url' => Yii::App()->createUrl("questionAdministration/copyQuestion/surveyId/$iSurveyID/questionGroupId/$question->gid/questionId/$question->qid") ]; } if ($configData['hasSurveyContentReadPermission']) { if (count($configData['surveyLanguages']) > 1) { $curQuestion['questionDropdown']['language'] = []; foreach ($configData['surveyLanguages'] as $languageCode => $languageName) { array_push( $curQuestion['questionDropdown']['language'], [ 'id' => '', 'label' => gT($languageName), 'icon' => 'ri-checkbox-fill', 'url' => Yii::App()->createUrl("admin/expressions/sa/survey_logic_file/sid/{$iSurveyID}/gid/$question->gid/qid/$question->qid/lang/" . $languageCode) ] ); } } else { $curQuestion['questionDropdown']['language'] = [ 'id' => '', 'label' => gT("Check logic"), 'icon' => 'ri-checkbox-fill', 'url' => Yii::App()->createUrl("admin/expressions/sa/survey_logic_file/sid/{$iSurveyID}/gid/$question->gid/qid/$question->qid") ]; } } if ($configData['oSurvey']->active !== 'Y') { $curQuestion['questionDropdown']['delete'] = [ 'id' => '', 'label' => gT("Delete question"), 'icon' => 'ri-delete-bin-fill text-danger', 'dataTitle' => gT('Delete this question'), 'dataBtnText' => gT('Delete'), 'dataOnclick' => '(function() { ' . convertGETtoPOST(Yii::app()->createUrl("questionAdministration/delete/", ["qid" => $question->qid, "redirectTo" => "groupoverview"])) . '})', 'dataMessage' => gT("Deleting this question will also delete any answer options and subquestions it includes. Are you sure you want to continue?", 'unescaped') ]; } else { $curQuestion['questionDropdown']['delete'] = [ 'id' => '', 'label' => gT("Delete question"), 'icon' => 'ri-delete-bin-fill text-danger', 'dataTitle' => gT('Delete this question'), 'disabled' => true, 'title' => gT("You can not delete a question if the survey is active.", 'unescaped'), ]; } $curGroup['questions'][] = $curQuestion; } } $aGroupViewable[] = $curGroup; } } return $this->renderPartial( '/admin/super/_renderJson', array( 'data' => array( 'groups' => $aGroupViewable, 'settings' => array( 'lastquestion' => $lastquestionID, 'lastquestiongroup' => $lastquestiongroupID, ), ) ), false, false ); } /** * Returns a JSON list of surveys the current user has read permission on, * filtered by an optional search term. Used by Select2 AJAX in the copy survey modal. * * Reuses Survey::search() so that the filtering logic (SID, title, admin, owner, * survey group) and permission scoping stay consistent with the main survey list grid. * * Note: The permission scope filters by read only. The actual copy action (actionCopy) * additionally checks surveycontent.export permission server-side. * * @return void */ public function actionGetAjaxSurveyList() { $term = Yii::app()->request->getParam('term', ''); $model = new Survey('search'); $model->searched_value = $term; $model->active = null; $dataProvider = $model->search([ 'pageSize' => 10, 'currentPage' => 0, 'skipCacheFlush' => true, ]); $results = []; foreach ($dataProvider->getData() as $survey) { $title = isset($survey->correct_relation_defaultlanguage->surveyls_title) ? $survey->correct_relation_defaultlanguage->surveyls_title : ''; $results[] = [ 'id' => (int) $survey->sid, 'text' => $survey->sid . ' - ' . $title, 'title' => $title, ]; } return $this->renderPartial( '/admin/super/_renderJson', array('data' => ['results' => $results]) ); } /** * Ajaxified get MenuItems with containing questions * * @todo this could go into surveymenucontroller * * @param int $surveyid Given Survey ID * @param string $position Given Position * * @return string|string[] * @throws CException */ public function actionGetAjaxMenuArray($surveyid, $position = '') { $iSurveyID = sanitize_int($surveyid); //todo permission check ?!? $survey = Survey::model()->findByPk($iSurveyID); $menus = $survey->getSurveyMenus($position); return $this->renderPartial( '/admin/super/_renderJson', array( 'data' => [ 'menues' => $menus, 'settings' => array( 'extrasettings' => false, 'parseHTML' => false, ) ] ), false, false ); } /** * Method to call current date information by ajax * * @return JSON | string * @throws CException */ public function actionGetDateFormatOptions() { $aRawDateFormats = getDateFormatData(); //todo: does this action needs a permission check? what permission should be checked? return $this->renderPartial( '/admin/super/_renderJson', [ 'data' => array_map( function ($aDateFormats) { return $aDateFormats['dateformat']; }, $aRawDateFormats ) ], false, false ); } /** * Method to store data edited in the text editor component * * integer $sid Survey ID * * @return JSON | string * @throws CException */ public function actionSaveTextData($sid) { $iSurveyId = (int)$sid; $changes = Yii::app()->request->getPost('changes'); $aSuccess = []; if (!Permission::model()->hasSurveyPermission($iSurveyId, 'surveycontent', 'update')) { return $this->renderPartial( '/admin/super/_renderJson', array( 'data' => [ 'success' => false, 'message' => gT("No permission"), 'debug' => null ] ), false, false ); } foreach ($changes as $sLanguage => $contentChange) { //todo: better not to use sql-statement like this in a foreach (performance!!!) $oSurveyLanguageSetting = SurveyLanguageSetting::model()->findByPk( ["surveyls_survey_id" => $iSurveyId, "surveyls_language" => $sLanguage] ); if ($oSurveyLanguageSetting == null) { $oSurveyLanguageSetting = new SurveyLanguageSetting(); $oSurveyLanguageSetting->surveyls_survey_id = $iSurveyId; $oSurveyLanguageSetting->surveyls_language = $sLanguage; } $oSurveyLanguageSetting->surveyls_title = $contentChange['surveyTitle']; $oSurveyLanguageSetting->surveyls_welcometext = $contentChange['welcome']; $oSurveyLanguageSetting->surveyls_description = $contentChange['description']; $oSurveyLanguageSetting->surveyls_endtext = $contentChange['endText']; $oSurveyLanguageSetting->surveyls_url = $contentChange['endUrl']; $oSurveyLanguageSetting->surveyls_urldescription = $contentChange['endUrlDescription']; $oSurveyLanguageSetting->surveyls_dateformat = $contentChange['dateFormat']; $oSurveyLanguageSetting->surveyls_numberformat = $contentChange['decimalDivider']; $aSuccess[$sLanguage] = $oSurveyLanguageSetting->save(); unset($oSurveyLanguageSetting); } $success = array_reduce( $aSuccess, function ($carry, $subsuccess) { return $carry = $carry && $subsuccess; }, true ); return $this->renderPartial( '/admin/super/_renderJson', [ 'data' => [ "success" => $success, "message" => ($success ? gT("Survey texts were saved successfully.") : gT("Error saving survey texts")) ] ], false, false ); } /** * Collect the data necessary for the data security settings and return a JSON document * * @param int|null $sid Survey ID * * @return void * @throws CException */ public function actionGetDataSecTextSettings($sid = null) { $iSurveyId = (int)$sid; //permission check ... if (!Permission::model()->hasSurveyPermission($iSurveyId, 'surveycontent', 'read')) { return $this->renderPartial( '/admin/super/_renderJson', array( 'data' => [ 'success' => false, 'message' => gT("No permission"), 'debug' => null ] ), false, false ); } $oSurvey = Survey::model()->findByPk($iSurveyId); $aLanguages = []; $aReturner = [ "dataseclabel" => [], "datasecmessage" => [], "datasecerror" => [], ]; if ($oSurvey == null) { $defaultLanguage = Yii::app()->getConfig('defaultlang'); $aLanguages = [$defaultLanguage => getLanguageCodefromLanguage($defaultLanguage)]; $aReturner["datasecmessage"][$defaultLanguage] = ""; $aReturner["datasecerror"][$defaultLanguage] = ""; $aReturner["dataseclabel"][$defaultLanguage] = ""; return $this->renderPartial( '/admin/super/_renderJson', [ 'data' => [ "showsurveypolicynotice" => 0, "textdata" => $aReturner, "languages" => $aLanguages, "permissions" => [ "update" => Permission::model()->hasGlobalPermission('surveys', 'create'), "editorpreset" => Yii::app()->session['htmleditormode'], ] ] ], false, false ); } foreach ($oSurvey->allLanguages as $sLanguage) { $aLanguages[$sLanguage] = getLanguageNameFromCode($sLanguage, false); $aReturner["datasecmessage"][$sLanguage] = $oSurvey->languagesettings[$sLanguage]->surveyls_policy_notice; $aReturner["datasecerror"][$sLanguage] = $oSurvey->languagesettings[$sLanguage]->surveyls_policy_error; $aReturner["dataseclabel"][$sLanguage] = $oSurvey->languagesettings[$sLanguage]->surveyls_policy_notice_label; } return $this->renderPartial( '/admin/super/_renderJson', [ 'data' => [ "showsurveypolicynotice" => $oSurvey->showsurveypolicynotice, "textdata" => $aReturner, "languages" => $aLanguages, "permissions" => [ "update" => Permission::model()->hasSurveyPermission($iSurveyId, 'surveysecurity', 'update'), "editorpreset" => Yii::app()->session['htmleditormode'], ] ] ], false, false ); } /** * Method to store data edited in the data security text editor component * * @param int $sid Survey ID * * @return void * @throws CException */ public function actionSaveDataSecTextData($sid) { $iSurveyId = (int)$sid; if (!Permission::model()->hasSurveyPermission($iSurveyId, 'surveycontent', 'update')) { return $this->renderPartial( '/admin/super/_renderJson', array( 'data' => [ 'success' => false, 'message' => gT("No permission"), 'debug' => null ] ), false, false ); } $oSurvey = Survey::model()->findByPk($iSurveyId); $changes = Yii::app()->request->getPost('changes', []); $aSuccess = []; $oSurvey->showsurveypolicynotice = $changes['showsurveypolicynotice'] ?? 0; $aSuccess[] = $oSurvey->save(); foreach ($oSurvey->allLanguages as $sLanguage) { $oSurveyLanguageSetting = SurveyLanguageSetting::model()->findByPk([ "surveyls_survey_id" => $iSurveyId, "surveyls_language" => $sLanguage ]); if ($oSurveyLanguageSetting == null) { $oSurveyLanguageSetting = new SurveyLanguageSetting(); $oSurveyLanguageSetting->surveyls_title = ""; $oSurveyLanguageSetting->surveyls_survey_id = $iSurveyId; $oSurveyLanguageSetting->surveyls_language = $sLanguage; } $oSurveyLanguageSetting->surveyls_policy_notice = $changes['datasecmessage'][$sLanguage] ?? ''; $oSurveyLanguageSetting->surveyls_policy_error = $changes['datasecerror'][$sLanguage] ?? ''; $oSurveyLanguageSetting->surveyls_policy_notice_label = $changes['dataseclabel'][$sLanguage] ?? ''; $aSuccess[$sLanguage] = $oSurveyLanguageSetting->save(); unset($oSurveyLanguageSetting); } $success = array_reduce( $aSuccess, function ($carry, $subsuccess) { return $carry = $carry && $subsuccess; }, true ); return $this->renderPartial( '/admin/super/_renderJson', [ 'data' => [ "success" => $success, "message" => ($success ? gT("Successfully saved privacy policy text") : gT("Error saving privacy policy text")) ] ], false, false ); } /** * Apply current theme options for imported survey theme * * @param int $iSurveyID The survey ID of imported survey * * @return void */ public function actionApplythemeoptions(int $surveyid = 0) { $iSurveyID = $surveyid; if ((int)$iSurveyID > 0 && Yii::app()->request->isPostRequest) { $oSurvey = Survey::model()->findByPk($iSurveyID); $sTemplateName = $oSurvey->template; $aThemeOptions = json_decode(App()->request->getPost('themeoptions', '')); if (!empty($aThemeOptions)) { $oSurveyConfig = TemplateConfiguration::getInstance($sTemplateName, null, $iSurveyID); if ($oSurveyConfig->options === 'inherit') { $oSurveyConfig->setOptionKeysToInherit(); } foreach ($aThemeOptions as $key => $value) { $oSurveyConfig->setOption($key, $value); } $oSurveyConfig->save(); } } $this->redirect(array('surveyAdministration/view/surveyid/' . $iSurveyID)); } /** * Upload an image in directory * * @return json |string * * @throws CException */ public function actionUploadimagefile() { $debug = [$_FILES]; // Check file size and render JSON on error. // This is done before checking the survey permissions because, if the max POST size was exceeded, // there is no Survey ID to check for permissions, so the error could be misleading. $uploadValidator = new LimeSurvey\Models\Services\UploadValidator(); $uploadValidator->renderJsonOnError('file', $debug); $iSurveyID = (int)Yii::app()->request->getPost('surveyid'); $success = false; $debug = []; if ( Permission::model()->hasSurveyPermission( $iSurveyID, 'surveycontent', 'update' ) ) { $checkImage = LSYii_ImageValidator::validateImage($_FILES["file"]); if ($checkImage['check'] !== false) { $diContainer = \LimeSurvey\DI::getContainer(); $fileUploadService = $diContainer->get( FileUploadService::class ); $destDir = $fileUploadService->getSurveyUploadDirectory( $iSurveyID ); if (is_writeable($destDir)) { $returnedData = $fileUploadService->saveFileInDirectory( $_FILES['file'], $destDir ); $message = $returnedData['uploadResultMessage']; $debug = $returnedData['debug']; $success = $returnedData['success']; } else { $message = sprintf( gT("Incorrect permissions in your %s folder."), $destDir ); } } else { $message = $checkImage['uploadresult']; $debug = $checkImage['debug']; } } else { $message = gT( "You don't have sufficient permissions to upload images in this survey" ); } return $this->renderPartial( '/admin/super/_renderJson', array( 'data' => [ 'success' => $success, 'message' => $message, 'debug' => $debug ] ), ); } /** * Returns JSON Data for Token Top Bar. * * @param int $sid Given Survey ID * @param bool $onlyclose Close * * @return string * @todo: this should go into tokens controller ... * */ public function actionGetTokenTopBar(int $sid) { $oSurvey = Survey::model()->findByPk($sid); return $this->renderPartial( 'token_bar', array( 'oSurvey' => $oSurvey, 'sid' => $sid, 'onlyclose' => !$oSurvey->hasTokensTable ), false, false ); } /** * Function responsible to deactivate a survey. * * @return void * @throws CException */ public function actionDeactivate() { $iSurveyID = $this->getSurveyIdFromGetRequest(); if (!Permission::model()->hasSurveyPermission($iSurveyID, 'surveyactivation', 'update')) { Yii::app()->user->setFlash('error', gT("Access denied!")); $this->redirect(Yii::app()->request->urlReferrer); } $diContainer = \LimeSurvey\DI::getContainer(); $surveyDeactivate = $diContainer->get( LimeSurvey\Models\Services\SurveyDeactivate::class ); $aData = array(); $datestamp = time(); $date = date('YmdHis', $datestamp); //'His' adds 24hours+minutes to name to allow multiple deactiviations in a day $survey = Survey::model()->findByPk($iSurveyID); $aData['aSurveysettings'] = getSurveyInfo($iSurveyID); $aData['surveyid'] = $iSurveyID; $aData['sid'] = $iSurveyID; $aData['title_bar']['title'] = $survey->currentLanguageSettings->surveyls_title . " (" . gT("ID") . ":" . $iSurveyID . ")"; $aData['topBar']['hide'] = true; $ok = Yii::app()->request->getPost('ok'); if ($ok == '') { $aData['date'] = $date; $aData['dbprefix'] = Yii::app()->db->tablePrefix; $aData['sNewSurveyTableName'] = Yii::app()->db->tablePrefix . "old_responses_{$iSurveyID}_{$date}"; $aData['step1'] = true; } else { try { $result = $surveyDeactivate->deactivate($iSurveyID, ['ok' => $ok]); } catch (Exception $e) { App()->user->setFlash('error', $e->getMessage()); } if (!empty($result["beforeDeactivate"]["message"])) { Yii::app()->user->setFlash('error', $result["beforeDeactivate"]["message"]); } if ($result["beforeDeactivate"]["message"] === false) { // @todo: What if two plugins change this? $aData = []; $aData['nostep'] = true; $this->aData = $aData; } else { if (!$result["surveyTableExists"]) { $_SESSION['flashmessage'] = gT("Error: Response table does not exist. Survey cannot be deactivated."); $this->redirect($this->createUrl("surveyAdministration/view/surveyid/{$iSurveyID}")); } $aData = $result['aData']; $aData['sidemenu']['state'] = false; } } $this->aData = $aData; $this->render('deactivateSurvey_view', $aData); } /** * fixes the numbering of questions * This can happen if question 1 have subquestion code 1 and * have question 11 in same survey and group (then same SGQA). * * @todo: maybe this one could not happen anymore ? * * @return array|false|string|string[]|null * @throws CException */ public function actionFixNumbering() { //get params surveyid and questionid $surveyId = sanitize_int(Yii::app()->request->getParam('iSurveyID', 0)); $questionId = sanitize_int(Yii::app()->request->getParam('questionId', 0)); $success = false; if (($surveyId > 0) && ($questionId > 0)) { App()->loadHelper('admin.activate'); fixNumbering($questionId, $surveyId); $success = true; } return $this->renderPartial( '/admin/super/_renderJson', [ 'data' => [ 'success' => $success, //'html' => $html, todo: should we give any feedback here? ] ], ); } /** * This action renders the view for survey activation where * the user can preselect some options like "ipanonymize" etc. * It is also possible to switch between the "open access mode" and * the "close-access-mode" before the survey is activated. * The action also checks if it is even possible to activate the survey * (see checkGroup() and checkQuestions() for more information). * * @return void */ public function actionActivateSurvey() { $surveyId = (int) Yii::app()->request->getPost('surveyId'); if (!Permission::model()->hasSurveyPermission($surveyId, 'surveyactivation', 'update')) { Yii::app()->user->setFlash('error', gT("Access denied!")); $this->redirect(Yii::app()->request->urlReferrer); } $oSurvey = Survey::model()->findByPk($surveyId); $aSurveysettings = getSurveyInfo($surveyId); Yii::app()->loadHelper("admin.activate"); $failedgroupcheck = checkGroup($surveyId); $failedcheck = checkQuestions($surveyId, $surveyId); $error = ""; if (!$oSurvey->countTotalQuestions) { $error = gT("There are no questions in this survey."); } $checkFailed = (isset($failedcheck) && $failedcheck) || (isset($failedgroupcheck) && $failedgroupcheck) || !empty($error); $footerButton = $this->renderPartial( '/surveyAdministration/surveyActivation/_activateFooterBtns', [], true ); if ($checkFailed) { //survey can not be activated $html = $this->renderPartial( '/surveyAdministration/surveyActivation/_activateSurveyCheckFailed', [ 'failedcheck' => $failedcheck, 'failedgroupcheck' => $failedgroupcheck, 'error' => $error, 'surveyid' => $oSurvey->sid ], true ); $footerButton = $this->renderPartial( '/surveyAdministration/surveyActivation/_failedFooterBtn', [], true ); } else { //check if survey is in "open-access-mode" $survey = Survey::model()->findByPk($surveyId); $surveyActivator = new SurveyActivator($survey); $html = $this->renderPartial( '/surveyAdministration/surveyActivation/_activateSurveyOptions', [ 'oSurvey' => $oSurvey, 'aSurveysettings' => $aSurveysettings, 'closeAccessMode' => $surveyActivator->isCloseAccessMode(), ], true ); } return $this->renderPartial( '/admin/super/_renderJson', [ 'data' => [ 'success' => true, 'html' => $html, 'checkFailed' => $checkFailed, 'footerButton' => $footerButton ] ], ); } /** * This action activates the survey with selected options. * * @return void */ public function actionActivate() { $surveyId = (int) App()->request->getPost('surveyId'); if (!Permission::model()->hasSurveyPermission($surveyId, 'surveyactivation', 'update')) { Yii::app()->user->setFlash('error', gT("Access denied!")); $this->redirect(Yii::app()->request->urlReferrer); } // Avoid reactivating a survey that is already active // Doing so might override the survey settings, causing an "Error: didn't save" issue if (Survey::model()->findByPk($surveyId)->getIsActive()) { App()->user->setFlash('error', gT("The survey is already active.")); $this->redirect(App()->request->urlReferrer); } $diContainer = \LimeSurvey\DI::getContainer(); $surveyActivate = $diContainer->get( LimeSurvey\Models\Services\SurveyActivate::class ); try { $result = $surveyActivate->activate($surveyId); } catch (Exception $e) { App()->user->setFlash('error', $e->getMessage()); } ######### OLD ######### if ( (isset($result['error']) && $result['error'] == 'plugin') || (isset($result['blockFeedback']) && $result['blockFeedback']) ) { // Got false from plugin, redirect to survey front-page $this->redirect(['surveyAdministration/view', 'surveyid' => $surveyId]); } elseif (isset($result['pluginFeedback'])) { // Special feedback from plugin should be given to user //todo: what should be done here ... $this->render('surveyActivation/_activation_feedback', $result); } elseif (isset($result['error'])) { $data['result'] = $result; //$this->aData = $aData; //todo: what should be done here ... $this->render('surveyActivation/_activation_error', $data); } else { $warning = (isset($result['warning'])) ? true : false; $allowregister = $result['isAllowRegister']; //todo: where to ask for this one here $openAccessMode = Yii::app()->request->getPost('openAccessMode', null); if ($openAccessMode !== null) { $modes = [ 'Y' => 'O', 'N' => 'C' ]; $mode = ($modes[$openAccessMode] ?? 'O'); $surveyAccessModeService = new SurveyAccessModeService( Permission::model(), Survey::model(), Yii::app(), ); $surveyAccessModeService->changeAccessMode($surveyId, $mode); switch ($openAccessMode) { case 'Y': //show a modal or give feedback on another page $this->redirect([ '/surveyAdministration/view/', 'surveyid' => $surveyId, 'surveyActivationFeedback' => 'surveyActivationFeedback' ]); break; case 'N': //check if token table exists or 'allowRegister' set to true $this->redirect([ '/admin/tokens/sa/index/', 'surveyid' => $surveyId, 'surveyActivationFeedback' => 'surveyActivationFeedback' ]); break; default: //this should never happen exception ... } } $activationData = [ 'iSurveyID' => $surveyId, 'survey' => $result['oSurvey'], 'warning' => $warning, 'allowregister' => $allowregister, ]; $this->aData = $result; $this->render('surveyActivation/_activation_feedback', $activationData); } } /** * Function responsible to delete a survey. * * @return string */ public function actionDelete() { //todo: delete should always be a post-request $iSurveyID = $this->getSurveyIdFromGetRequest(); if (!Permission::model()->hasSurveyPermission($iSurveyID, 'survey', 'delete')) { Yii::app()->user->setFlash('error', gT("Access denied!")); $this->redirect(Yii::app()->request->urlReferrer); } $aData = []; $iSurveyID = sanitize_int($iSurveyID); $aData['surveyid'] = $iSurveyID; $aData['sid'] = $aData['surveyid']; $survey = Survey::model()->findByPk($iSurveyID); $aData['sidemenu']['state'] = false; $aData['title_bar']['title'] = $survey->currentLanguageSettings->surveyls_title . " (" . gT("ID") . ":" . $iSurveyID . ")"; $aData['sidemenu']['state'] = false; $aData['survey'] = $survey; if (Yii::app()->request->getPost("delete") == 'yes') { $aData['issuperadmin'] = Permission::model()->hasGlobalPermission('superadmin', 'read'); Survey::model()->deleteSurvey($iSurveyID); Yii::app()->session['flashmessage'] = gT("Survey deleted."); $this->redirect(array("dashboard/view")); } $this->aData = $aData; $this->render('deleteSurvey_view', $aData); } /** * Remove files not deleted properly. * Purge is only available for surveys that were already deleted but for some reason * left files behind. * * @param int $purge_sid Given ID * * @return void */ public function actionPurge($purge_sid) { $purge_sid = (int) $purge_sid; if (Permission::model()->hasGlobalPermission('superadmin', 'delete')) { $survey = Survey::model()->findByPk($purge_sid); if (empty($survey)) { $result = rmdirr(Yii::app()->getConfig('uploaddir') . '/surveys/' . $purge_sid); if ($result) { Yii::app()->user->setFlash('success', gT('Survey files deleted.')); } else { Yii::app()->user->setFlash('error', gT('Error: Could not delete survey files.')); } } else { // Should not be possible. Yii::app()->user->setFlash( 'error', gT('Error: Cannot purge files for a survey that is not deleted. Please delete the survey normally in the survey view.') ); } } else { Yii::app()->user->setFlash('error', gT('Access denied!')); } $this->redirect($this->createUrl('admin/globalsettings')); } /** * New system of rendering content * Based on yii submenu rendering * * @param int $surveyid Given Survey ID * @param string $subaction Given subaction (subaction decides which view to render) * * @return void * * @throws Exception * * The below 'uses' are mentioned * @uses self::generalTabEditSurvey() * @uses self::pluginTabSurvey() * @uses self::tabPresentationNavigation() * @uses self::tabPublicationAccess() * @uses self::tabNotificationDataManagement() * @uses self::tabTokens() * @uses self::tabPanelIntegration() * @uses self::tabResourceManagement() * */ public function actionRendersidemenulink($surveyid, $subaction) { $iSurveyID = (int) $surveyid; $menuaction = (string) $subaction; $survey = Survey::model()->findByPk($iSurveyID); $aData['oSurvey'] = $survey; // set values from database to survey attributes if (empty($survey)) { throw new Exception('Found no survey with id ' . $iSurveyID); } $survey->setOptionsFromDatabase(); //Get all languages $grplangs = $survey->additionalLanguages; $baselang = $survey->language; array_unshift($grplangs, $baselang); //@TODO add language checks here $menuEntry = SurveymenuEntries::model()->find('name=:name', array(':name' => $menuaction)); if (!(Permission::model()->hasSurveyPermission($iSurveyID, $menuEntry->permission, $menuEntry->permission_grade))) { Yii::app()->setFlashMessage(gT("You do not have permission to access this page."), 'error'); $this->redirect(array('surveyAdministration/view', 'surveyid' => $iSurveyID)); } $templateData = is_array($menuEntry->data) ? $menuEntry->data : []; if (!empty($menuEntry->getdatamethod)) { $templateData = array_merge($templateData, call_user_func_array( array($this, $menuEntry->getdatamethod), //info: getdatamethod is the name of a function here in this controller!!! array('survey' => $survey) )); } $templateData = array_merge($this->getGeneralTemplateData($iSurveyID), $templateData); // For Text elements Tab. if ($menuaction === 'surveytexts') { $temp = []; $languages = $survey->allLanguages; foreach ($languages as $i => $language) { $temp = $this->getGeneralTemplateData($iSurveyID); App()->loadHelper('database'); App()->loadHelper('surveytranslator'); App()->loadHelper('admin.htmleditor'); $surveyLanguageSetting = SurveyLanguageSetting::model()->findByPk( array( 'surveyls_survey_id' => $iSurveyID, 'surveyls_language' => $language ) )->getAttributes(); $aTabTitles[$language] = getLanguageNameFromCode($surveyLanguageSetting['surveyls_language'], false); if ($surveyLanguageSetting['surveyls_language'] == $survey->language) { $aTabTitles[$language] .= ' (' . gT("Base language") . ')'; } $temp['aSurveyLanguageSettings'] = $surveyLanguageSetting; $temp['action'] = "surveygeneralsettings"; $temp['i'] = $i; $temp['dateformatdetails'] = getDateFormatData(App()->session['dateformat']); $temp['oSurvey'] = $survey; Yii::app()->session['FileManagerContext'] = "edit:survey:{$iSurveyID}"; $aTabContents[$language] = $this->renderPartial('/admin/survey/editLocalSettings_view', $temp, true); } $aData['aTabContents'] = $aTabContents; $aData['aTabTitles'] = $aTabTitles; $aData['moreInfo'] = $temp; } // override survey settings if global settings exist $templateData['showqnumcode'] = Yii::app()->getConfig('showqnumcode') !== 'choose' ? Yii::app()->getConfig('showqnumcode') : $survey->showqnumcode; $templateData['shownoanswer'] = Yii::app()->getConfig('shownoanswer') !== 'choose' ? Yii::app()->getConfig('shownoanswer') : $survey->shownoanswer; $templateData['showgroupinfo'] = Yii::app()->getConfig('showgroupinfo') !== '2' ? Yii::app()->getConfig('showgroupinfo') : $survey->showgroupinfo; $templateData['showxquestions'] = Yii::app()->getConfig('showxquestions') !== 'choose' ? Yii::app()->getConfig('showxquestions') : $survey->showxquestions; //Start collecting aData $aData['surveyid'] = $iSurveyID; $aData['sid'] = $iSurveyID; $aData['menuaction'] = $menuaction; $aData['template'] = $menuEntry->template; $aData['templateData'] = $templateData; $aData['surveyls_language'] = $baselang; $aData['action'] = $menuEntry->action; $aData['entryData'] = $menuEntry->attributes; $aData['dateformatdetails'] = getDateFormatData(Yii::app()->session['dateformat']); $aData['subaction'] = $menuEntry->title; $aData['display']['menu_bars']['surveysummary'] = $menuEntry->title; $aData['title_bar']['title'] = $survey->currentLanguageSettings->surveyls_title . " (" . gT("ID") . ":" . $iSurveyID . ")"; if ($subaction === 'resources' || $subaction === 'panelintegration') { $aData['topBar']['showSaveButton'] = false; } else { // Since the save action for survey texts checks two permissions and survey menu entries only support one permission, // we need to check the permissions here and decide whether to show the save button or not for that screen. /** @todo: Generalize for other subactions */ if ( $subaction === 'surveytexts' && !Permission::model()->hasSurveyPermission($iSurveyID, 'surveylocale', 'update') && !Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'update') ) { $aData['topBar']['showSaveButton'] = false; } else { $aData['topBar']['showSaveButton'] = true; } } $topbarData = TopbarConfiguration::getSurveyTopbarData($iSurveyID); $topbarData = array_merge($topbarData, $aData['topBar']); $aData['topbar']['middleButtons'] = $this->renderPartial( 'partial/topbar/surveyTopbarLeft_view', $topbarData, true ); $aData['topbar']['rightButtons'] = $this->renderPartial( 'partial/topbar/surveyTopbarRight_view', $topbarData, true ); $aData['topBar']['closeUrl'] = $this->createUrl("surveyAdministration/view/", ['surveyid' => $iSurveyID]); // Close button $aData['optionsOnOff'] = array( 'Y' => gT('On', 'unescaped'), 'N' => gT('Off', 'unescaped'), ); $this->aData = $aData; $this->render($menuEntry->template, $aData); } /** * Load ordering of question group screen. * questiongroup::organize() * @TODO Reordering should be handled by existing function in new QuestionGroupService class * * @param int $iSurveyID Given Survey ID * * @return void */ public function actionOrganize() { $request = Yii::app()->request; $iSurveyID = $this->getSurveyIdFromGetRequest(); $iSurveyID = sanitize_int($iSurveyID); $thereIsPostData = $request->getPost('orgdata') !== null; $userHasPermissionToUpdate = Permission::model()->hasSurveyPermission( $iSurveyID, 'surveycontent', 'update' ); if (!$userHasPermissionToUpdate) { Yii::app()->user->setFlash('error', gT("Access denied!")); $this->redirect(Yii::app()->request->urlReferrer); } if ($thereIsPostData) { // Save the new ordering. $orgdata = $this->getOrgdata(); $groupHelper = new LimeSurvey\Models\Services\GroupHelper(); $result = $groupHelper->reorderGroup($iSurveyID, $orgdata); if ($result['type'] === 'success') { App()->setFlashMessage(gT("The new question group/question order was successfully saved.")); } elseif ($result['type'] === 'error') { foreach ($result['question-titles'] as $questionTitle) { App()->setFlashMessage(sprintf(gT("Unable to reorder question %s."), $questionTitle), 'warning'); } } $closeAfterSave = $request->getPost('close-after-save') === 'true'; if ($closeAfterSave) { // save reordering redirect to listquestion page as this part is moved there $this->redirect($this->createUrl('questionAdministration/listQuestions', ['surveyid' => $iSurveyID , 'activeTab' => 'reorder'])); } } $aData = $this->showReorderForm($iSurveyID); $aData['topBar']['showSaveButton'] = true; $topbarData = TopbarConfiguration::getSurveyTopbarData($iSurveyID); $topbarData = array_merge($topbarData, $aData['topBar']); $aData['topbar']['middleButtons'] = $this->renderPartial( 'partial/topbar/surveyTopbarLeft_view', $topbarData, true ); $aData['topbar']['rightButtons'] = $this->renderPartial( 'partial/topbar/surveyTopbarRight_view', $topbarData, true ); // Display 'Reorder question/question groups' in Green Bar $aData['subaction'] = gT('Reorder questions/question groups'); $this->aData = $aData; $this->render('/admin/survey/organizeGroupsAndQuestions_view', $aData); } /** * @param int $surveyid Given Survey ID. * * @return void * @todo Add TypeDoc. */ public function actionGetUrlParamsJSON($surveyid) { $iSurveyID = (int) $surveyid; $sBaseLanguage = Survey::model()->findByPk($iSurveyID)->language; $aSurveyParameters = SurveyURLParameter::model()->findAll('sid=:sid', [':sid' => $iSurveyID]); $aData = array( 'rows' => [] ); foreach ($aSurveyParameters as $oSurveyParameter) { $row = $oSurveyParameter->attributes; if ($oSurveyParameter->targetqid != '') { $row['questionTitle'] = $oSurveyParameter->question->title . ": " . ellipsize(flattenText($oSurveyParameter->question->questionl10ns[$sBaseLanguage]->question, false, true), 43, .70); } if ($oSurveyParameter->targetsqid != '') { $row['questionTitle'] .= (' - ' . ellipsize(flattenText($oSurveyParameter->subquestion->questionl10ns[$sBaseLanguage]->question, false, true), 30, .75)); } $row['qid'] = $oSurveyParameter->targetqid; $row['sqid'] = $oSurveyParameter->targetsqid; $aData['rows'][] = $row; } $aData['page'] = 1; $aData['records'] = count($aSurveyParameters); $aData['total'] = 1; echo ls_json_encode($aData); } /** * Function responsible to copy a survey. * * @return void * @throws CException * @throws Exception */ public function actionCopy() { //everybody who has permission to create surveys if (!Permission::model()->hasGlobalPermission('surveys', 'create')) { App()->user->setFlash('error', gT("Access denied!")); $this->redirect(App()->request->urlReferrer); } $surveyId = sanitize_int(App()->request->getPost('surveyIdToCopy')); $survey = Survey::model()->findByPk($surveyId); if (!$survey) { App()->user->setFlash('error', gT("Survey does not exist.")); $this->redirect(App()->request->urlReferrer); } if (!Permission::model()->hasSurveyPermission($surveyId, 'surveycontent', 'export')) { App()->user->setFlash('error', gT("Access denied!")); $this->redirect(App()->request->urlReferrer); } //the new survey id $rawNewSid = App()->request->getPost('copysurveyid'); $newSurveyId = ($rawNewSid === '' || $rawNewSid === null) ? null : sanitize_int($rawNewSid, 1, 999999); //the source survey id $sourceSurveyId = sanitize_int(App()->request->getPost('surveyIdToCopy')); $sourceSurvey = Survey::model()->findByPk($sourceSurveyId); $options = $this->getPostParamsForCopySurvey(App()->request); $copySurveyService = new \LimeSurvey\Models\Services\CopySurvey( $sourceSurvey, $options, $newSurveyId, ); $copyResults = $copySurveyService->copy(); $copiedSurvey = $copyResults->getCopiedSurvey(); if ($copiedSurvey !== null) { $groupList = QuestionGroup::model()->findAllByAttributes(['sid' => $copiedSurvey->sid]); $this->resetExpressionManager($copiedSurvey, $groupList); } $aData = []; $aData['copyResults'] = $copyResults; if ($copiedSurvey !== null) { $aData['sLink'] = $this->createUrl('surveyAdministration/view/', ['iSurveyID' => $copiedSurvey->sid]); $aData['sLinkApplyThemeOptions'] = 'surveyAdministration/applythemeoptions/surveyid/' . $copiedSurvey->sid; $questionGroupList = QuestionGroup::model()->findAllByAttributes(['sid' => $copiedSurvey->sid]); // Make the link point to the first group/question if available if (!empty($questionGroupList)) { $oFirstGroup = $questionGroupList[0]; $oFirstQuestion = Question::model()->primary()->findByAttributes( ['gid' => $oFirstGroup->gid], ['order' => 'question_order ASC'] ); $aData['sLink'] = $this->getSurveyAndSidemenueDirectionURL( $copiedSurvey->sid, $oFirstGroup->gid, !empty($oFirstQuestion) ? $oFirstQuestion->qid : null, 'structure' ); } } $this->aData = $aData; $this->render('copySurveyResult_view', $this->aData); } /** * Reads POST parameters from the copy survey form and builds a CopySurveyOptions container. * Handles all checkbox options (resources, quotas, permissions, etc.) and the optional custom title. * * @param CHttpRequest $request * @return CopySurveyOptions */ private function getPostParamsForCopySurvey($request): CopySurveyOptions { $optionsDataContainer = new CopySurveyOptions(); //Survey resource files and adapt links $option = $request->getPost('copyResourcesAndLinks'); $optionsDataContainer->setResourcesAndLinks(isset($option) && $option == "1"); $option = $request->getPost('copySurveyQuotas'); $optionsDataContainer->setQuotas(isset($option) && $option == "1"); $option = $request->getPost('copySurveyPermissions'); $optionsDataContainer->setPermissions(isset($option) && $option == "1"); $option = $request->getPost('copyAnswerOptions'); $optionsDataContainer->setAnswerOptions(isset($option) && $option == "1"); $option = $request->getPost('copySurveyConditions'); $optionsDataContainer->setConditions(isset($option) && $option == "1"); $option = $request->getPost('copyStartEndDate'); $optionsDataContainer->setStartAndEndDate(isset($option) && $option == "1"); $option = $request->getPost('resetResponseStartId'); $optionsDataContainer->setResetResponseStartId(isset($option) && $option == "1"); $newTitle = $request->getPost('copysurveytitle'); if (is_string($newTitle) && trim($newTitle) !== '') { $optionsDataContainer->setNewTitle(trim($newTitle)); } return $optionsDataContainer; } /** * Import an uploaded survey file, create the survey if valid, and render the import summary view. * * Validates upload permissions and file type/size, moves the uploaded file to a temporary location, * calls importSurveyFile(...) (passing the "translinksfields" flag and optional "surveysgroup" request parameter), * translates import results into view data (including links to the new survey and theme-apply action), * resets the expression manager for the newly created survey (if any), cleans up the temporary file, * and renders the importSurvey_view with import results or error information. */ public function actionImport() { //everybody who has permission to create surveys if (!Permission::model()->hasGlobalPermission('surveys', 'create')) { App()->user->setFlash('error', gT("Access denied!")); $this->redirect(App()->request->urlReferrer); } $aData = []; $sExtension = ""; $aData['sHeader'] = gT("Import survey data"); $aData['sSummaryHeader'] = gT("Survey structure import summary"); $aData['textCompleted'] = gT("Import of survey is completed."); $aPathInfo = pathinfo((string) $_FILES['the_file']['name']); if (isset($aPathInfo['extension'])) { $sExtension = $aPathInfo['extension']; } $aData['bFailed'] = false; $sFullFilepath = Yii::app()->getConfig('tempdir') . DIRECTORY_SEPARATOR . randomChars(30) . '.' . $sExtension; if ($_FILES['the_file']['error'] == 1 || $_FILES['the_file']['error'] == 2) { $aData['sErrorMessage'] = sprintf(gT("Sorry, this file is too large. Only files up to %01.2f MB are allowed."), getMaximumFileUploadSize() / 1024 / 1024) . '
'; $aData['bFailed'] = true; } elseif (!in_array(strtolower($sExtension), array('lss', 'txt', 'tsv', 'lsa'))) { $aData['sErrorMessage'] = sprintf(gT("Import failed. You specified an invalid file type '%s'."), CHtml::encode($sExtension)); $aData['bFailed'] = true; } elseif ($aData['bFailed'] || !@move_uploaded_file($_FILES['the_file']['tmp_name'], $sFullFilepath)) { $aData['sErrorMessage'] = gT("An error occurred uploading your file. This may be caused by incorrect permissions for the application /tmp folder."); $aData['bFailed'] = true; } App()->loadHelper('admin.import'); if (!$aData['bFailed']) { $targetSurveysGroup = App()->request->getPost('surveysgroup'); if (!in_array($targetSurveysGroup, ['default', 'from_survey'], true)) { $targetSurveysGroup = 'default'; } $aImportResults = importSurveyFile($sFullFilepath, (App()->request->getPost('translinksfields') == '1'), null, null, null, $targetSurveysGroup); if (is_null($aImportResults)) { $aImportResults = array( 'error' => gT("Unknown error while reading the file, no survey created.") ); } } else { $aData['bFailed'] = true; } // If the import failed, set the status and error message in order to keep consistency with other errors if (!empty($aImportResults['error'])) { $aData['sErrorMessage'] = $aImportResults['error']; $aData['bFailed'] = true; } if (isset($sFullFilepath) && file_exists($sFullFilepath)) { unlink($sFullFilepath); } if (!$aData['bFailed'] && isset($aImportResults)) { $aData['aImportResults'] = $aImportResults; if (isset($aImportResults['newsid'])) { // Set link pointing to survey administration overview. This link will be updated if the survey has groups $aData['sLink'] = $this->createUrl('surveyAdministration/view/', ['iSurveyID' => $aImportResults['newsid']]); $aData['sLinkApplyThemeOptions'] = 'surveyAdministration/applythemeoptions/surveyid/' . $aImportResults['newsid']; } } if (!empty($aImportResults['newsid'])) { $oSurvey = Survey::model()->findByPk($aImportResults['newsid']); $aGrouplist = QuestionGroup::model()->findAllByAttributes(['sid' => $aImportResults['newsid']]); $this->resetExpressionManager($oSurvey, $aGrouplist); // Make the link point to the first group/question if available if (!empty($aGrouplist)) { $oFirstGroup = $aGrouplist[0]; $oFirstQuestion = Question::model()->primary()->findByAttributes( ['gid' => $oFirstGroup->gid], ['order' => 'question_order ASC'] ); $aData['sLink'] = $this->getSurveyAndSidemenueDirectionURL( $aImportResults['newsid'], $oFirstGroup->gid, !empty($oFirstQuestion) ? $oFirstQuestion->qid : null, 'structure' ); } } $this->aData = $aData; $this->render('importSurvey_view', $this->aData); } /** * Called via ajax request from survey summary quick action "Show questions group by group". * * @param int $iSurveyID Given Survey ID * @param string $format Given Format * * @return void */ public function actionChangeFormat(int $iSurveyID, $format) { if (Permission::model()->hasSurveyPermission($iSurveyID, 'surveycontent', 'update')) { if (in_array($format, array('S', 'G', 'A'))) { $survey = Survey::model()->findByPk($iSurveyID); $survey->format = $format; $survey->save(); echo $survey->format; } } } /** * Expires the survey. * * @return void */ public function actionExpire() { $iSurveyID = $this->getSurveyIdFromGetRequest(); if (!Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'update')) { Yii::app()->setFlashMessage(gT("You do not have permission to access this page."), 'error'); $this->redirect(array('surveyAdministration/view', 'surveyid' => $iSurveyID)); } Yii::app()->session['flashmessage'] = gT("The survey was successfully expired by setting an expiration date in the survey settings."); Survey::model()->expire($iSurveyID); $this->redirect(array('surveyAdministration/view/surveyid/' . $iSurveyID)); } /** * Ajaxrequest returning 'session['dateformat']' * and some other parameters to the frontend * * @return void * * @todo this function should be moved to another controller (?) */ public function actionDatetimesettings() { if (Permission::model()->hasGlobalPermission('surveys', 'read')) { $data = array( 'dateformatsettings' => getDateFormatData(Yii::app()->session['dateformat']), 'showClear' => true, 'allowInputToggle' => true, ); echo json_encode($data); } } /** * Action to set expiry date to multiple surveys. * (ajax request) * * @return void * @throws CException */ public function actionExpireMultipleSurveys() { $sSurveys = $_POST['sItems'] ?? ''; $aSIDs = json_decode($sSurveys); $aResults = array(); $expires = App()->request->getPost('expires'); $formatdata = getDateFormatData(Yii::app()->session['dateformat']); Yii::import('application.libraries.Date_Time_Converter', true); if (trim((string) $expires) == "") { $expires = null; } else { $datetimeobj = new Date_Time_Converter($expires, $formatdata['phpdate'] . ' H:i'); $expires = $datetimeobj->convert("Y-m-d H:i:s"); } foreach ($aSIDs as $sid) { if ((int)$sid > 0) { $survey = Survey::model()->findByPk($sid); $survey->expires = $expires; $aResults[$survey->primaryKey]['title'] = ellipsize( $survey->correct_relation_defaultlanguage->surveyls_title, 30 ); if (!Permission::model()->hasSurveyPermission($sid, 'surveysettings', 'update')) { $aResults[$survey->primaryKey]['result'] = false; $aResults[$survey->primaryKey]['error'] = gT("User does not have valid permissions"); } else { if ($survey->save()) { $aResults[$survey->primaryKey]['result'] = true; } else { $aResults[$survey->primaryKey]['result'] = false; $aResults[$survey->primaryKey]['error'] = gT("Survey update failed"); } } } } $this->renderPartial( 'ext.admin.survey.ListSurveysWidget.views.massive_actions._action_results', array('aResults' => $aResults, 'successLabel' => gT('OK')) ); } /** ************************************************************************************************************ */ /** The following functions could be moved to model or service classes */ /** **********************************************************************************************************++ */ /** * Reset expression manager values * * @param Survey $oSurvey * @param array $aGrouplist * @return void */ private function resetExpressionManager($oSurvey, $aGrouplist) { LimeExpressionManager::SetDirtyFlag(); LimeExpressionManager::singleton(); // Why this @ ! LimeExpressionManager::SetSurveyId($oSurvey->sid); LimeExpressionManager::RevertUpgradeConditionsToRelevance($oSurvey->sid); LimeExpressionManager::UpgradeConditionsToRelevance($oSurvey->sid); @LimeExpressionManager::StartSurvey($oSurvey->sid, 'survey', $oSurvey->attributes, true); LimeExpressionManager::StartProcessingPage(true, true); foreach ($aGrouplist as $aGroup) { LimeExpressionManager::StartProcessingGroup( $aGroup['gid'], $oSurvey->anonymized != 'Y', $oSurvey->sid ); LimeExpressionManager::FinishProcessingGroup(); } LimeExpressionManager::FinishProcessingPage(); } /** * Try to get the get-parameter from request. * At the moment there are three namings for a survey ID: * 'sid' * 'surveyid' * 'iSurveyID' * * Returns the id as integer or null if not exists any of them. * * @return int | null * * @todo While refactoring (at some point) this function should be removed and only one unique identifier should be used */ private function getSurveyIdFromGetRequest() { $surveyId = Yii::app()->request->getParam('sid'); if ($surveyId === null) { $surveyId = Yii::app()->request->getParam('surveyid'); } if ($surveyId === null) { $surveyId = Yii::app()->request->getParam('iSurveyID'); } return (int) $surveyId; } /** * Returns data for Tab Resourves. * survey::_tabResourceManagement() * Load "Resources" tab. * * @todo is this new implementation??? * * @param Survey $survey Given Survey * * @return array */ protected function tabResourceManagement($survey) { global $sCKEditorURL; // TAB Uploaded Resources Management $ZIPimportAction = " onclick='if (window.LS.validatefilename(this.form,\"" . gT('Please select a file to import!', 'js') . "\")) { this.form.submit();}'"; if (!class_exists('ZipArchive')) { $ZIPimportAction = " onclick='alert(\"" . gT("The ZIP library is not activated in your PHP configuration thus importing ZIP files is currently disabled.", "js") . "\");'"; } $disabledIfNoResources = ''; if (hasResources($survey->sid, 'survey') === false) { $disabledIfNoResources = " disabled='disabled'"; } $aData = []; $aData['ZIPimportAction'] = $ZIPimportAction; $aData['disabledIfNoResources'] = $disabledIfNoResources; $aData['sCKEditorURL'] = $sCKEditorURL; $aData['noform'] = true; //KCFINDER SETTINGS Yii::app()->session['FileManagerContext'] = "edit:survey:{$survey->sid}"; Yii::app()->loadHelper('admin.htmleditor'); initKcfinder(); return $aData; } /** * Show the form for Organize question groups/questions * * @param int $iSurveyID Given Survey ID * * @return array * @todo Change function name to _showOrganizeGroupsAndQuestions? * @todo Does actually not show anything, but gets data. So getReorderFormData()? */ private function showReorderForm($iSurveyID) { $survey = Survey::model()->findByPk($iSurveyID); $aData = []; $aData['title_bar']['title'] = $survey->currentLanguageSettings->surveyls_title . " (" . gT("ID") . ":" . $iSurveyID . ")"; $aData['sid'] = $iSurveyID; //frontend need this to render topbar for the view // Prepare data for the view $sBaseLanguage = Survey::model()->findByPk($iSurveyID)->language; LimeExpressionManager::StartSurvey($iSurveyID, 'survey'); LimeExpressionManager::StartProcessingPage(true, Yii::app()->baseUrl); $groups = $survey->groups; $groupData = []; $initializedReplacementFields = false; $aData['organizebar']['savebuttonright'] = true; $aData['organizebar']['closebuttonright']['url'] = $this->createUrl("surveyAdministration/view/", array('surveyid' => $iSurveyID)); $aData['organizebar']['saveandclosebuttonright']['url'] = true; $aData['surveybar']['buttons']['view'] = true; $aData['surveybar']['savebutton']['form'] = 'frmOrganize'; $aData['topBar']['showSaveButton'] = true; foreach ($groups as $iGID => $oGroup) { $groupData[$iGID]['gid'] = $oGroup->gid; $groupData[$iGID]['group_text'] = $oGroup->gid . ' ' . $oGroup->questiongroupl10ns[$sBaseLanguage]->group_name; LimeExpressionManager::StartProcessingGroup($oGroup->gid, false, $iSurveyID); if (!$initializedReplacementFields) { templatereplace("{SITENAME}"); // Hack to ensure the EM sets values of LimeReplacementFields $initializedReplacementFields = true; } $qs = array(); foreach ($oGroup->questions as $question) { $relevance = $question->relevance == '' ? 1 : $question->relevance; $questionText = sprintf( '[{%s}] %s % s', $relevance, $question->title, $question->questionl10ns[$sBaseLanguage]->question ); LimeExpressionManager::ProcessString($questionText, $question->qid); $questionData['question'] = viewHelper::stripTagsEM(LimeExpressionManager::GetLastPrettyPrintExpression()); $questionData['gid'] = $oGroup->gid; $questionData['qid'] = $question->qid; $questionData['title'] = $question->title; $qs[] = $questionData; } $groupData[$iGID]['questions'] = $qs; LimeExpressionManager::FinishProcessingGroup(); } LimeExpressionManager::FinishProcessingPage(); $aData['aGroupsAndQuestions'] = $groupData; $aData['surveyid'] = $iSurveyID; $aData['surveyActivated'] = $survey->getIsActive(); return $aData; } /** * Get the new question organization from the post data. * This function replaces parse_str, since parse_str * is bound by max_input_vars. * * @return array */ private function getOrgdata() { $request = Yii::app()->request; $orgdata = $request->getPost('orgdata', ''); $ex = explode('&', $orgdata); $vars = array(); foreach ($ex as $str) { list($list, $target) = explode('=', $str); $list = str_replace('list[', '', $list); $list = str_replace(']', '', $list); $vars[$list] = $target; } return $vars; } /** * Returns Data for Plugin tab. * survey::_pluginTabSurvey() * Load "Simple Plugin" page in specific survey. * * @param Survey $survey Given Survey * * @return array * * This method is called via call_user_func in self::rendersidemenulink() * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ protected function pluginTabSurvey($survey) { $aData = array(); $beforeSurveySettings = new PluginEvent('beforeSurveySettings'); $beforeSurveySettings->set('survey', $survey->sid); App()->getPluginManager()->dispatchEvent($beforeSurveySettings); $aData['pluginSettings'] = $beforeSurveySettings->get('surveysettings'); return $aData; } /** * Update the theme of a survey * * @param int $iSurveyID Survey ID * @param string $template The survey theme name * @param array $aResults If the method is called from changeMultipleTheme(), it will update its array of results * @param boolean $bReturn Should the method update and return aResults * * @return mixed null or array * * @access public */ public function changeTemplate($iSurveyID, $template, $aResults = null, $bReturn = false) { $iSurveyID = sanitize_int($iSurveyID); $sTemplate = sanitize_dirname($template); $survey = Survey::model()->findByPk($iSurveyID); if (!Permission::model()->hasSurveyPermission($iSurveyID, 'surveysettings', 'update')) { if (!empty($bReturn)) { $aResults[$iSurveyID]['title'] = $survey->correct_relation_defaultlanguage->surveyls_title; $aResults[$iSurveyID]['result'] = false; $aResults[$iSurveyID]['error'] = gT("User does not have valid permissions"); return $aResults; } else { die('No permission'); } } elseif (!Permission::model()->hasGlobalPermission('templates', 'read') && !Permission::model()->hasTemplatePermission($template)) { if (!empty($bReturn)) { $aResults[$iSurveyID]['title'] = $survey->correct_relation_defaultlanguage->surveyls_title; $aResults[$iSurveyID]['result'] = false; $aResults[$iSurveyID]['error'] = gT("User does not have permission to use this theme"); return $aResults; } else { die('No permission'); } } $survey->template = $sTemplate; $survey->save(); $oTemplateConfiguration = $survey->surveyTemplateConfiguration; $oTemplateConfiguration->template_name = $sTemplate; $oTemplateConfiguration->save(); // This will force the generation of the entry for survey group TemplateConfiguration::checkAndcreateSurveyConfig($iSurveyID); if (!empty($bReturn)) { $aResults[$iSurveyID]['title'] = $survey->correct_relation_defaultlanguage->surveyls_title; $aResults[$iSurveyID]['result'] = true; return $aResults; } } /** * This method will return the url for the current survey and set * the direction for the sidemenue. * * @param int $sid Given Survey ID * @param int $gid Given Group ID * @param int $qid Given Question ID * @param string $landOnSideMenuTab Given SideMenuTab * * @return string */ public function getSurveyAndSidemenueDirectionURL($sid, $gid, $qid, $landOnSideMenuTab) { $url = !empty($qid) ? 'questionAdministration/view/' : 'questionGroupsAdministration/view/'; $params = [ 'surveyid' => $sid, 'gid' => $gid, ]; if (!empty($qid)) { $params['qid'] = $qid; } $params['landOnSideMenuTab'] = $landOnSideMenuTab; return $this->createUrl($url, $params); } /** * This private function creates a sample group * * @param int $iSurveyID The survey ID that the sample group will belong to * * @return int */ private function createSampleGroup($iSurveyID) { // Now create a new dummy group $sLanguage = Survey::model()->findByPk($iSurveyID)->language; $oGroup = new QuestionGroup(); $oGroup->sid = $iSurveyID; $oGroup->group_order = 1; $oGroup->grelevance = '1'; $oGroup->save(); $oGroupL10ns = new QuestionGroupL10n(); $oGroupL10ns->gid = $oGroup->gid; $oGroupL10ns->group_name = gT('My first question group', 'html', $sLanguage); $oGroupL10ns->language = $sLanguage; $oGroupL10ns->save(); LimeExpressionManager::SetEMLanguage($sLanguage); return $oGroup->gid; } /** * This private function creates a sample question * * @param int $iSurveyID The survey ID that the sample question will belong to * @param int $iGroupID The group ID that the sample question will belong to * * @return int */ private function createSampleQuestion($iSurveyID, $iGroupID) { // Now create a new dummy question $sLanguage = Survey::model()->findByPk($iSurveyID)->language; $oQuestion = new Question(); $oQuestion->sid = $iSurveyID; $oQuestion->gid = $iGroupID; $oQuestion->type = Question::QT_M_MULTIPLE_CHOICE; $oQuestion->title = 'Q00'; $oQuestion->mandatory = 'N'; $oQuestion->relevance = '1'; $oQuestion->question_order = 1; $oQuestion->save(); $oQuestionLS = new QuestionL10n(); $oQuestionLS->question = ''; $oQuestionLS->help = ''; $oQuestionLS->language = $sLanguage; $oQuestionLS->qid = $oQuestion->qid; $oQuestionLS->save(); $this->createSampleSubquestion( 1, $iSurveyID, $iGroupID, $oQuestion->qid, $sLanguage, gT('Option A') ); $this->createSampleSubquestion( 2, $iSurveyID, $iGroupID, $oQuestion->qid, $sLanguage, gT('Option B') ); return $oQuestion->qid; } /** * Creates a sample subquestion for a parent question in a survey * * This method creates a new subquestion with the specified parameters and saves it to the database. * It also creates the corresponding localization entry for the subquestion. * * @param int $number The sequence number for the subquestion, used for ordering and title generation * @param int $surveyId The ID of the survey to which this subquestion belongs * @param int $groupId The ID of the question group to which this subquestion belongs * @param int $questionId The ID of the parent question to which this subquestion is attached * @param string $language The language code for the subquestion's text * @param string $text The actual text content of the subquestion * * @return void */ private function createSampleSubquestion( int $number, int $surveyId, int $groupId, int $questionId, string $language, string $text ) { $subQuestion = new Question(); $subQuestion->parent_qid = $questionId; $subQuestion->sid = $surveyId; $subQuestion->gid = $groupId; $subQuestion->type = Question::QT_T_LONG_FREE_TEXT; $subQuestion->title = 'SQ00' . $number; $subQuestion->question_order = $number; $subQuestion->relevance = 1; $subQuestion->save(); $subQuestionL10n = new QuestionL10n(); $subQuestionL10n->question = $text; $subQuestionL10n->help = ''; $subQuestionL10n->language = $language; $subQuestionL10n->qid = $subQuestion->qid; $subQuestionL10n->save(); } /** * Adds some other important adata variables for frontend * * this function came from Layouthelper * * @param array $aData pointer to array (this array will be changed here!!) * * @throws CException */ private function surveysummary(&$aData) { $iSurveyID = $aData['surveyid']; $aSurveyInfo = getSurveyInfo($iSurveyID); /** @var Survey $oSurvey */ if (!isset($aData['oSurvey'])) { $aData['oSurvey'] = Survey::model()->findByPk($aData['surveyid']); } $oSurvey = $aData['oSurvey']; $activated = $aSurveyInfo['active']; $condition = array('sid' => $iSurveyID, 'parent_qid' => 0); $sumcount3 = Question::model()->countByAttributes($condition); //Checked $sumcount2 = QuestionGroup::model()->countByAttributes(array('sid' => $iSurveyID)); $accessMode = $aSurveyInfo['access_mode']; //SURVEY SUMMARY $aAdditionalLanguages = $oSurvey->additionalLanguages; $surveysummary2 = []; if ($aSurveyInfo['anonymized'] != "N") { $surveysummary2[] = gT("Responses to this survey are anonymized."); } else { $surveysummary2[] = gT("Responses to this survey are NOT anonymized."); } if ($aSurveyInfo['format'] == "S") { $surveysummary2[] = gT("It is presented question by question."); } elseif ($aSurveyInfo['format'] == "G") { $surveysummary2[] = gT("It is presented group by group."); } else { $surveysummary2[] = gT("It is presented on one single page."); } if ($aSurveyInfo['questionindex'] > 0) { if ($aSurveyInfo['format'] == 'A') { $surveysummary2[] = gT("No question index will be shown with this format."); } elseif ($aSurveyInfo['questionindex'] == 1) { $surveysummary2[] = gT("A question index will be shown; participants will be able to jump between viewed questions."); } elseif ($aSurveyInfo['questionindex'] == 2) { $surveysummary2[] = gT("A full question index will be shown; participants will be able to jump between relevant questions."); } } if ($oSurvey->isDateStamp) { $surveysummary2[] = gT("Responses will be date stamped."); } if ($oSurvey->isIpAddr) { $surveysummary2[] = gT("IP addresses will be saved."); } if ($oSurvey->isRefUrl) { $surveysummary2[] = gT("Referrer URL will be saved."); } if ($oSurvey->isUseCookie) { $surveysummary2[] = gT("It uses cookies for access control."); } if ($oSurvey->isAllowRegister) { $surveysummary2[] = gT("If participant access codes are used, the public may register for this survey"); } if ($oSurvey->isAllowSave && !$oSurvey->isTokenAnswersPersistence) { $surveysummary2[] = gT("Participants can save partially finished surveys"); } if ($oSurvey->emailnotificationto != '') { $surveysummary2[] = gT("Basic email notification is sent to:") . ' ' . htmlspecialchars((string)$aSurveyInfo['emailnotificationto']); } if ($oSurvey->emailresponseto != '') { $surveysummary2[] = gT("Detailed email notification with response data is sent to:") . ' ' . htmlspecialchars((string)$aSurveyInfo['emailresponseto']); } $dateformatdetails = getDateFormatData(Yii::app()->session['dateformat']); if (trim((string)$oSurvey->startdate) != '') { Yii::import('application.libraries.Date_Time_Converter'); $startdate = getDateOfUTC(($oSurvey->startdate)); $datetimeobj = new Date_Time_Converter($startdate, 'Y-m-d H:i:s'); $aData['startdate'] = $datetimeobj->convert($dateformatdetails['phpdate'] . ' H:i'); } else { $aData['startdate'] = "-"; } if (trim((string)$oSurvey->expires) != '') { Yii::import('application.libraries.Date_Time_Converter'); $expires = getDateOfUTC(($oSurvey->expires)); $datetimeobj = new Date_Time_Converter($expires, 'Y-m-d H:i:s'); $aData['expdate'] = $datetimeobj->convert($dateformatdetails['phpdate'] . ' H:i'); } else { $aData['expdate'] = "-"; } $aData['language'] = getLanguageNameFromCode($oSurvey->language, false); if ($oSurvey->currentLanguageSettings->surveyls_urldescription == "") { $aSurveyInfo['surveyls_urldescription'] = htmlspecialchars((string) $aSurveyInfo['surveyls_url']); } if ($oSurvey->currentLanguageSettings->surveyls_url != "") { $aData['endurl'] = " " . flattenText($oSurvey->currentLanguageSettings->surveyls_url) . ""; } else { $aData['endurl'] = "-"; } $aData['sumcount3'] = $sumcount3; $aData['sumcount2'] = $sumcount2; $aData['accessMode'] = $accessMode; if ($activated == "N") { $aData['activatedlang'] = gT("No"); } else { $aData['activatedlang'] = gT("Yes"); } $aData['activated'] = $activated; if ($oSurvey->isActive) { $aData['surveydb'] = Yii::app()->db->tablePrefix . "responses_" . $iSurveyID; } $aData['warnings'] = []; if ($activated == "N" && $sumcount3 == 0) { $aData['warnings'][] = gT("Survey cannot be activated yet."); 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')) { $aData['warnings'][] = "" . gT("You need to add questions") . ""; } } $aData['hints'] = $surveysummary2; //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 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) $aData['tableusage'] = false; $aData['aAdditionalLanguages'] = $aAdditionalLanguages; $aData['groups_count'] = $sumcount2; // We get the state of the quickaction // If the survey is new (ie: it has no group), it is opened by default $quickactionState = SettingsUser::getUserSettingValue('quickaction_state'); if ($quickactionState === null || $quickactionState === 0) { $quickactionState = 1; SettingsUser::setUserSetting('quickaction_state', 1); } $aData['quickactionstate'] = $quickactionState !== null ? intval($quickactionState) : 1; $aData['subviewData'] = $aData; Yii::app()->getClientScript()->registerPackage('surveysummary'); } /** * Load "General" tab of new survey screen. * survey::_generalTabNewSurvey() * * @return array */ private function generalTabNewSurvey() { // use survey option inheritance $user = User::model()->findByPk(Yii::app()->session['loginID']); $owner = $user->attributes; $owner['full_name'] = 'inherit'; $owner['email'] = 'inherit'; $owner['bounce_email'] = 'inherit'; $aData = []; $aData['action'] = "newsurvey"; $aData['owner'] = $owner; $aLanguageDetails = getLanguageDetails(Yii::app()->session['adminlang']); $aData['sRadixDefault'] = $aLanguageDetails['radixpoint']; $aData['sDateFormatDefault'] = $aLanguageDetails['dateformat']; $aRadixPointData = []; foreach (getRadixPointData() as $index => $radixptdata) { $aRadixPointData[$index] = $radixptdata['desc']; } $aData['aRadixPointData'] = $aRadixPointData; foreach (getDateFormatData(0, Yii::app()->session['adminlang']) as $index => $dateformatdata) { $aDateFormatData[$index] = $dateformatdata['dateformat']; } $aData['aDateFormatData'] = $aDateFormatData; return $aData; } /** * Returns Data for general template. * * @param int $iSurveyID Given Survey ID * * @return array */ private function getGeneralTemplateData($iSurveyID) { $aData = []; $aData['surveyid'] = $iSurveyID; $oSurvey = Survey::model()->findByPk($iSurveyID); if (empty($oSurvey)) { $oSurvey = new Survey(); } $inheritOwner = empty($oSurvey->oOptions->ownerLabel) ? $oSurvey->owner_id : $oSurvey->oOptions->ownerLabel; $users = getUserList(); $aData['users'] = array(); $aData['users']['-1'] = gT('Inherit') . ' [' . $inheritOwner . ']'; foreach ($users as $user) { $aData['users'][$user['uid']] = $user['user'] . ($user['full_name'] ? ' - ' . $user['full_name'] : ''); } // Sort users by name asort($aData['users']); $aData['aSurveyGroupList'] = SurveysGroups::getSurveyGroupsList(); return $aData; } /** * Returns data for text edit. * * BE CAREFUL (this function is not called directly, but by call_user_func_array and the name of function in db .. ) * * @param Survey $survey Given Survey. * * @return array */ protected function getTextEditData($survey) { Yii::app()->getClientScript()->registerScript( "TextEditDataGlobal", //todo: this has to be changed, also in frontend packages/textelements/... //NEW: connectorBaseUrl: '".Yii::app()->getController()->createUrl('/surveyAdministration/getDateFormatOptions', ['sid' => $survey->sid])."', //// ['sid' => $survey->sid]) . "', --> sid should be taken from frontend ... "window.TextEditData = { connectorBaseUrl: '" . Yii::app()->getController()->createUrl('surveyAdministration/') . "', isNewSurvey: " . ($survey->getIsNewRecord() ? "true" : "false") . ", sid: $survey->sid, i10N: { 'Survey title' : '" . gT('Survey title') . "', 'Date format' : '" . gT('Date format') . "', 'Decimal mark' : '" . gT('Decimal mark') . "', 'End url' : '" . gT('End url') . "', 'URL description (link text)' : '" . gT('URL description (link text)') . "', 'Description' : '" . gT('Description') . "', 'Welcome' : '" . gT('Welcome') . "', 'End message' : '" . gT('End message') . "' } };", LSYii_ClientScript::POS_BEGIN ); App()->getClientScript()->registerPackage('ace'); return []; } /** * Returns Date for Data Security Edit. * tab_edit_view_datasecurity * editDataSecurityLocalSettings_view * * @param Survey $survey Given Survey * * @return array */ protected function getDataSecurityEditData($survey) { Yii::app()->loadHelper("admin.htmleditor"); $aData = $aTabTitles = $aTabContents = array(); $aData['scripts'] = PrepareEditorScript(false, $this); $aLanguageData = []; foreach ($survey->allLanguages as $i => $sLang) { $aLanguageData = $this->getGeneralTemplateData($survey->sid); // this one is created to get the right default texts fo each language Yii::app()->loadHelper('database'); Yii::app()->loadHelper('surveytranslator'); $aSurveyLanguageSettings = SurveyLanguageSetting::model()->findByPk(array('surveyls_survey_id' => $survey->sid, 'surveyls_language' => $sLang))->getAttributes(); $aTabTitles[$sLang] = getLanguageNameFromCode($aSurveyLanguageSettings['surveyls_language'], false); if ($aSurveyLanguageSettings['surveyls_language'] == $survey->language) { $aTabTitles[$sLang] .= ' (' . gT("Base language") . ')'; } $aLanguageData['aSurveyLanguageSettings'] = $aSurveyLanguageSettings; $aLanguageData['action'] = "surveygeneralsettings"; $aLanguageData['subaction'] = gT('Add a new question'); $aLanguageData['i'] = $i; $aLanguageData['dateformatdetails'] = getDateFormatData(Yii::app()->session['dateformat']); $aLanguageData['oSurvey'] = $survey; $aTabContents[$sLang] = $this->renderPartial('/admin/survey/editDataSecurityLocalSettings_view', $aLanguageData, true); } $aData['aTabContents'] = $aTabContents; $aData['aTabTitles'] = $aTabTitles; return $aData; } /** * Returns Data for Tab General Edit Survey. * survey::_generalTabEditSurvey() * Load "General" tab of edit survey screen. * * @param Survey $survey Given Survey * * @return mixed */ protected function generalTabEditSurvey($survey) { $aData['survey'] = $survey; // Prepare theme configuration data for the view $themeService = DI::getContainer()->get(SurveyThemeConfiguration::class); $aData = array_merge($aData, $themeService->getThemeViewData($survey->template, $survey->oOptions ?? null)); return $aData; } /** * Returns data for tab Presentation navigation. * survey::_tabPresentationNavigation() * Load "Presentation & navigation" tab. * * @param mixed $survey ? * * @return array */ protected function tabPresentationNavigation($survey) { $aData = []; $aData['esrow'] = $survey; return $aData; } /** * Returns the data for Tab Publication Access control. * survey::_tabPublicationAccess() * Load "Publication * access control" tab. * * @param Survey $survey Given Survey * * @return array */ protected function tabPublicationAccess($survey) { $aDateFormatDetails = getDateFormatData(Yii::app()->session['dateformat']); $aData = []; $aData['dateformatdetails'] = $aDateFormatDetails; $aData['survey'] = $survey; return $aData; } /** * Returns the data for Tab Notification and Data Management. * survey::_tabNotificationDataManagement() * Load "Notification & data management" tab. * * @param mixed $survey ? * * @return array */ protected function tabNotificationDataManagement($survey) { $aData = []; $aData['esrow'] = $survey; return $aData; } /** * Returns the data for Tab Tokens. * survey::_tabTokens() * Load "Tokens" tab. * * @param mixed $survey ? * * @return array */ protected function tabTokens($survey) { $aData = []; $aData['esrow'] = $survey; return $aData; } /** * Returns the data for Tab Panel Integration. * * @param Survey $survey Given Survey * @param string|null $sLang Given Language * * @return array */ protected function tabPanelIntegration($survey, $sLang = null) { $aData = []; $oResult = Question::model()->with('subquestions')->findAll("t.sid={$survey->sid} AND (t.type = 'T' OR t.type = 'Q' OR t.type = 'S') AND t.parent_qid = 0"); $aQuestions = []; foreach ($oResult as $oRecord) { if (count($oRecord->subquestions)) { foreach ($oRecord->subquestions as $oSubquestion) { $aQuestions[] = array_merge( $oRecord->attributes, $oRecord->questionl10ns[$survey->language]->attributes, array( 'sqid' => $oSubquestion->qid, 'sqtitle' => $oSubquestion->title, 'sqquestion' => $oSubquestion->questionl10ns[$survey->language]->question ) ); } } else { $aQuestions[] = array_merge( $oRecord->attributes, $oRecord->questionl10ns[$survey->language]->attributes, array( 'sqid' => null, 'sqtitle' => null, 'sqquestion' => null ) ); } } $aData['jsData'] = [ 'i10n' => [ 'ID' => gT('ID'), 'Action' => gT('Action'), 'Parameter' => gT('Parameter'), 'Target question' => gT('Target question'), 'Survey ID' => gT('Survey ID'), 'Question ID' => gT('Question ID'), 'Subquestion ID' => gT('Subquestion ID'), 'Add URL parameter' => gT('Add URL parameter'), 'Edit URL parameter' => gT('Edit URL parameter'), 'No target question' => gT('(No target question)'), 'Are you sure you want to delete this URL parameter?' => gT('Are you sure you want to delete this URL parameter?'), 'No parameters defined' => gT('No parameters defined'), 'Search prompt' => gT('Search:'), 'Progress' => gT('Showing _START_ to _END_ of _TOTAL_ entries'), 'No, cancel' => gT('Cancel'), 'Yes, delete' => gT('Delete'), 'Save' => gT('Save'), 'Cancel' => gT('Cancel'), ], "surveyid" => $survey->sid, "getParametersUrl" => Yii::app()->createUrl('surveyAdministration/getUrlParamsJson', array('surveyid' => $survey->sid)), ]; $aData['questions'] = $aQuestions; $model = new SurveyURLParameter('search'); $model->sid = $survey->sid; $model->searched_value = Yii::app()->request->getParam('search_query'); $aData['updateUrl'] = Yii::app()->createUrl('surveyAdministration/rendersidemenulink', ['surveyid' => $survey->sid, 'subaction' => 'panelintegration']); if (isset($_GET['pageSize'])) { Yii::app()->user->setState('pageSize', (int) $_GET['pageSize']); } $aData['model'] = $model; App()->getClientScript()->registerPackage('jquery-datatable-bs5'); return $aData; } /** * Method to save URL Params (Panel Integration) * * @throws CException */ public function actionSaveUrlParam() { $paramData = Yii::app()->request->getPost('URLParam'); if (empty($paramData)) { return $this->renderPartial( '/admin/super/_renderJson', ['data' => ['success' => false, 'message' => gT("Invalid request")]] ); } $surveyId = sanitize_int(Yii::app()->request->getPost('surveyId')); if (!Permission::model()->hasSurveyPermission($surveyId, 'surveysettings', 'update')) { return $this->renderPartial( '/admin/super/_renderJson', ['data' => ['success' => false, 'message' => gT("Access denied!")]] ); } // Based on Database::actionUpdateSurveyLocaleSettings() $paramData['parameter'] = trim($paramData['parameter'] ?? ''); if ( $paramData['parameter'] == '' || !preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $paramData['parameter']) || $paramData['parameter'] == 'sid' || $paramData['parameter'] == 'newtest' || $paramData['parameter'] == 'token' || $paramData['parameter'] == 'lang' ) { return $this->renderPartial( '/admin/super/_renderJson', ['data' => ['success' => false, 'message' => gT("Invalid URL parameter")]] ); } if ($paramData['targetqid'] == '') { $paramData['targetqid'] = null; } if ($paramData['targetsqid'] == '') { $paramData['targetsqid'] = null; } $paramId = !empty($paramData['id']) ? sanitize_int($paramData['id']) : null; if (empty($paramId)) { $URLParam = new SurveyURLParameter(); $paramData['sid'] = $surveyId; } else { $URLParam = SurveyURLParameter::model()->findByPk($paramId); if (empty($URLParam || $URLParam->sid != $surveyId)) { return $this->renderPartial( '/admin/super/_renderJson', ['data' => ['success' => false, 'message' => gT("URL parameter not found")]] ); } unset($paramData['id']); } $URLParam->setAttributes($paramData); if ($URLParam->save()) { return $this->renderPartial( '/admin/super/_renderJson', ['data' => ['success' => true, 'message' => gT("URL parameter saved")]] ); } else { return $this->renderPartial( '/admin/super/_renderJson', ['data' => ['success' => false, 'message' => gT("Could not save URL parameter"), 'errors' => $URLParam->getErrors()]] ); } } /** * Method to delete URL Params (Panel Integration) * * @return void * @throws CDbException * @throws CHttpException */ public function actionDeleteUrlParam() { $surveyId = sanitize_int(Yii::app()->request->getPost('surveyId')); $redirectUrl = ['surveyAdministration/rendersidemenulink', 'surveyid' => $surveyId, 'subaction' => 'panelintegration']; $paramId = Yii::app()->request->getPost('urlParamId'); if (empty($paramId)) { throw new CHttpException(400, gT('Invalid request')); } if (!Permission::model()->hasSurveyPermission($surveyId, 'surveysettings', 'update')) { throw new CHttpException(403, gT("Access denied!")); } $paramId = sanitize_int($paramId); $URLParam = SurveyURLParameter::model()->findByPk($paramId); if (empty($URLParam)) { throw new CHttpException(400, gT("URL parameter not found")); } // Delete the record if ($URLParam->delete()) { Yii::app()->user->setFlash('success', gT("URL parameter deleted")); } else { Yii::app()->user->setFlash('error', gT("Could not delete URL parameter")); } $this->redirect($redirectUrl); } /** * Retrieves and renders a list of surveys with optional active status filter for the box widget Ajax. * * @return string|false Rendered partial view if surveys are found, otherwise false. * @throws CException */ public function actionBoxList() { $limit = (int)App()->request->getQuery('limit'); $page = (int)App()->request->getQuery('page'); $model = Survey::model(); if ($state = App()->request->getQuery('active')) { $model->active = $state; $surveys = $model ->search(['pageSize' => $limit, 'currentPage' => $page]); } else { $surveys = $model ->search(['pageSize' => $limit, 'currentPage' => $page]); } $boxes = []; foreach ($surveys->getData() as $survey) { $state = strip_tags($survey->getRunning()); $boxes[] = [ 'survey' => $survey, 'type' => 0, 'external' => false, 'iconAlter' => $state, 'state' => $survey->getState(), 'buttons' => $survey->getButtons(), 'link' => App()->createUrl('/surveyAdministration/view/surveyid/' . $survey->sid), ]; } return $this->renderPartial( 'ext.admin.BoxesWidget.views.box', array( 'items' => $boxes ) ); } /** * AJAX action to update survey access mode */ public function actionUpdateAccessMode() { $surveyId = (int) Yii::app()->request->getPost('surveyId'); $accessMode = Yii::app()->request->getPost('accessMode'); if (!$surveyId || !$accessMode) { $this->renderJSON(['success' => false, 'message' => 'Missing parameters']); return; } try { $surveyAccessModeService = new SurveyAccessModeService( Permission::model(), Survey::model(), Yii::app() ); $result = $surveyAccessModeService->changeAccessMode($surveyId, $accessMode); if ($result) { $this->renderJSON([ 'success' => true, 'message' => 'Access mode updated successfully', 'accessMode' => $accessMode ]); } else { $this->renderJSON(['success' => false, 'message' => 'No changes made']); } } catch (Exception $e) { $this->renderJSON(['success' => false, 'message' => $e->getMessage()]); } } }