Skip to content

Commit

Permalink
Merge branch 'master' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
olleharstedt committed May 3, 2021
2 parents 8207964 + b434183 commit 7686aca
Show file tree
Hide file tree
Showing 18 changed files with 210 additions and 170 deletions.
4 changes: 2 additions & 2 deletions application/config/version.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
* See COPYRIGHT.php for copyright notices and details.
*/

$config['versionnumber'] = '4.6.0-dev';
$config['versionnumber'] = '4.7.0-dev';
$config['dbversionnumber'] = 444;
$config['buildnumber'] = '';
$config['updatable'] = true;
$config['templateapiversion'] = 3;
$config['assetsversionnumber'] = '30202';
$config['assetsversionnumber'] = '30203';
return $config;
2 changes: 1 addition & 1 deletion application/controllers/admin/PluginHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public function fullpagewrapper($plugin, $method)
$content = $this->getContent(null, $plugin, $method);

$aData['content'] = $content;
$this->_renderWrappedTemplate(null, 'super/dummy', $aData);
$this->_renderWrappedTemplate(null, 'super/dummy', $aData, 'layout_main.php');
}

/**
Expand Down
9 changes: 9 additions & 0 deletions application/helpers/admin/import_helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,15 @@ function XMLImportGroup($sFullFilePath, $iNewSID, $bTranslateLinksFields)
LimeExpressionManager::RevertUpgradeConditionsToRelevance($iNewSID);
LimeExpressionManager::UpgradeConditionsToRelevance($iNewSID);

if (count($aQuestionCodeReplacements)) {
array_unshift(
$results['importwarnings'],
"<span class='warningtitle'>"
. gT('Attention: Several question codes were updated. Please check these carefully as the update may not be perfect with customized expressions.')
. '</span>'
);
}

$results['newgid'] = $newgid;
$results['labelsets'] = 0;
$results['labels'] = 0;
Expand Down
157 changes: 74 additions & 83 deletions application/helpers/frontend_helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,113 +29,104 @@ function loadanswers()


$scid = Yii::app()->request->getQuery('scid');
if (Yii::app()->request->getParam('loadall') == "reload") {
if (Yii::app()->request->getParam('loadall') === "reload") {
$sLoadName = Yii::app()->request->getParam('loadname');
$sLoadPass = Yii::app()->request->getParam('loadpass');
$oCriteria = new CDbCriteria();
$oCriteria->join = "LEFT JOIN {{saved_control}} ON t.id={{saved_control}}.srid";
$oCriteria->condition = "{{saved_control}}.sid=:sid";
$aParams = array(':sid' => $surveyid);
$oCriteria->select = 'sc.*';
$oCriteria->join = "LEFT JOIN {{saved_control}} as sc ON t.id=sc.srid";
$oCriteria->condition = "sc.sid=:sid";
$aParams = [':sid' => $surveyid];
if (isset($scid)) {
//Would only come from email : we don't need it ....
$oCriteria->addCondition("{{saved_control}}.scid=:scid");
//Would only come from email : we don't need it ....
$oCriteria->addCondition("sc.scid=:scid");
$aParams[':scid'] = $scid;
}
$oCriteria->addCondition("{{saved_control}}.identifier=:identifier");
$oCriteria->addCondition("sc.identifier=:identifier");
$aParams[':identifier'] = $sLoadName;

if (in_array(Yii::app()->db->getDriverName(), array('mssql', 'sqlsrv', 'dblib'))) {
// To be validated with mssql, think it's not needed
$oCriteria->addCondition("(CAST({{saved_control}}.access_code as varchar(64))=:md5_code OR CAST({{saved_control}}.access_code as varchar(64))=:sha256_code)");
} else {
$oCriteria->addCondition("({{saved_control}}.access_code=:md5_code OR {{saved_control}}.access_code=:sha256_code)");
}
$aParams[':md5_code'] = md5($sLoadPass);
$aParams[':sha256_code'] = hash('sha256', $sLoadPass);
} elseif (isset($_SESSION['survey_' . $surveyid]['srid'])) {
$oCriteria = new CDbCriteria();
$oCriteria->condition = "id=:id";
$aParams = array(':id' => $_SESSION['survey_' . $surveyid]['srid']);
$aParams = [':id' => $_SESSION['survey_' . $surveyid]['srid']];
} else {
return;
return false;
}
$oCriteria->params = $aParams;
$oResponses = SurveyDynamic::model($surveyid)->find($oCriteria);
$oResponses = SurveyDynamic::model($surveyid)->with('saved_control')->find($oCriteria);

if (!$oResponses) {
return false;
} else {
//A match has been found. Let's load the values!
//If this is from an email, build surveysession first
$_SESSION['survey_' . $surveyid]['LEMtokenResume'] = true;

// If survey come from reload (GET or POST); some value need to be found on saved_control, not on survey
if (Yii::app()->request->getParam('loadall') == "reload") {
$oSavedSurvey = SavedControl::model()->find(
"sid = :sid AND identifier = :identifier AND (access_code = :access_code OR access_code = :sha256_code)",
array(
':sid' => $surveyid,
':identifier' => $sLoadName,
':access_code' => md5($sLoadPass),
':sha256_code' => hash('sha256', $sLoadPass)
)
);
// We don't need to control if we have one, because we do the test before
$_SESSION['survey_' . $surveyid]['scid'] = $oSavedSurvey->scid;
$_SESSION['survey_' . $surveyid]['step'] = ($oSavedSurvey->saved_thisstep > 1) ? $oSavedSurvey->saved_thisstep : 1;
$thisstep = $_SESSION['survey_' . $surveyid]['step'] - 1; // deprecated ?
$_SESSION['survey_' . $surveyid]['srid'] = $oSavedSurvey->srid; // Seems OK without
$_SESSION['survey_' . $surveyid]['refurl'] = $oSavedSurvey->refurl;
}
}

// Get if survey is been answered
$submitdate = $oResponses->submitdate;
$aRow = $oResponses->attributes;
foreach ($aRow as $column => $value) {
if ($column == "token") {
$clienttoken = $value;
$token = $value;
} elseif ($column == 'lastpage' && !isset($_SESSION['survey_' . $surveyid]['step'])) {
if (is_null($submitdate) || $submitdate == "N") {
$_SESSION['survey_' . $surveyid]['step'] = ($value > 1 ? $value : 1);
$thisstep = $_SESSION['survey_' . $surveyid]['step'] - 1;
} else {
$_SESSION['survey_' . $surveyid]['maxstep'] = ($value > 1 ? $value : 1);
}
} elseif ($column == "datestamp") {
$_SESSION['survey_' . $surveyid]['datestamp'] = $value;
if (isset($oResponses->saved_control) && $oResponses->saved_control) {
$saved_control = $oResponses->saved_control;
$access_code = $oResponses->saved_control->access_code;
$md5_code = md5($sLoadPass);
$sha256_code = hash('sha256', $sLoadPass);
if ($md5_code === $access_code || $sha256_code === $access_code || password_verify($sLoadPass, $access_code)) {
//A match has been found. Let's load the values!
//If this is from an email, build surveysession first
$_SESSION['survey_' . $surveyid]['LEMtokenResume'] = true;

// If survey come from reload (GET or POST); some value need to be found on saved_control, not on survey
if (Yii::app()->request->getParam('loadall') === "reload") {
// We don't need to control if we have one, because we do the test before
$_SESSION['survey_' . $surveyid]['scid'] = $saved_control->scid;
$_SESSION['survey_' . $surveyid]['step'] = ($saved_control->saved_thisstep > 1) ? $saved_control->saved_thisstep : 1;
$thisstep = $_SESSION['survey_' . $surveyid]['step'] - 1; // deprecated ?
$_SESSION['survey_' . $surveyid]['srid'] = $saved_control->srid; // Seems OK without
$_SESSION['survey_' . $surveyid]['refurl'] = $saved_control->refurl;
}
if ($column == "startdate") {
$_SESSION['survey_' . $surveyid]['startdate'] = $value;
}
}
// Get if survey is been answered
$submitdate = $oResponses->submitdate;
$aRow = $oResponses->attributes;
foreach ($aRow as $column => $value) {
if ($column === "token") {
$clienttoken = $value;
$token = $value;
} elseif ($column === 'lastpage' && !isset($_SESSION['survey_' . $surveyid]['step'])) {
if (is_null($submitdate) || $submitdate === "N") {
$_SESSION['survey_' . $surveyid]['step'] = ($value > 1 ? $value : 1);
$thisstep = $_SESSION['survey_' . $surveyid]['step'] - 1;
} else {
//Only make session variables for those in insertarray[]
if (in_array($column, $_SESSION['survey_' . $surveyid]['insertarray']) && isset($_SESSION['survey_' . $surveyid]['fieldmap'][$column])) {
if (
($_SESSION['survey_' . $surveyid]['fieldmap'][$column]['type'] == Question::QT_N_NUMERICAL ||
$_SESSION['survey_' . $surveyid]['maxstep'] = ($value > 1 ? $value : 1);
}
} elseif ($column === "datestamp") {
$_SESSION['survey_' . $surveyid]['datestamp'] = $value;
}
if ($column === "startdate") {
$_SESSION['survey_' . $surveyid]['startdate'] = $value;
} else {
//Only make session variables for those in insertarray[]
if (in_array($column, $_SESSION['survey_' . $surveyid]['insertarray']) && isset($_SESSION['survey_' . $surveyid]['fieldmap'][$column])) {
if (
($_SESSION['survey_' . $surveyid]['fieldmap'][$column]['type'] == Question::QT_N_NUMERICAL ||
$_SESSION['survey_' . $surveyid]['fieldmap'][$column]['type'] == Question::QT_K_MULTIPLE_NUMERICAL_QUESTION ||
$_SESSION['survey_' . $surveyid]['fieldmap'][$column]['type'] == Question::QT_D_DATE) && $value == null
) {
) {
// For type N,K,D NULL in DB is to be considered as NoAnswer in any case.
// We need to set the _SESSION[field] value to '' in order to evaluate conditions.
// This is especially important for the deletenonvalue feature,
// otherwise we would erase any answer with condition such as EQUALS-NO-ANSWER on such
// question types (NKD)
$_SESSION['survey_' . $surveyid][$column] = '';
} else {
$_SESSION['survey_' . $surveyid][$column] = $value;
}
if (isset($token) && !empty($token)) {
$_SESSION['survey_' . $surveyid][$column] = $value;
}
} // if (in_array(
} // else
} // foreach
return true;
}
// We need to set the _SESSION[field] value to '' in order to evaluate conditions.
// This is especially important for the deletenonvalue feature,
// otherwise we would erase any answer with condition such as EQUALS-NO-ANSWER on such
// question types (NKD)
$_SESSION['survey_' . $surveyid][$column] = '';
} else {
$_SESSION['survey_' . $surveyid][$column] = $value;
}
if (isset($token) && !empty($token)) {
$_SESSION['survey_' . $surveyid][$column] = $value;
}
} // if (in_array(
} // else
} // foreach
return true;
}


/**
* This function creates the language selector for a particular survey
* This function creates the language selector for a particular survey
*
* @param string $sSelectedLanguage : lang to be selected (forced)
*
Expand Down Expand Up @@ -1198,7 +1189,7 @@ function renderRenderWayForm($renderWay, array $scenarios, $sTemplateViewPath, $
$thissurvey['include_content'] = 'userforms';

Yii::app()->clientScript->registerScriptFile(Yii::app()->getConfig("generalscripts") . 'nojs.js', CClientScript::POS_HEAD);

// Language selector
if ($aSurveyInfo['alanguageChanger']['show']) {
$aSurveyInfo['alanguageChanger']['datas']['targetUrl'] = $thissurvey['surveyUrl'];
Expand Down
2 changes: 1 addition & 1 deletion application/libraries/Save.php
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ function saveSurvey()
$saved_control->sid = $surveyid;
$saved_control->srid = $_SESSION['survey_'.$surveyid]['srid'];
$saved_control->identifier = $_POST['savename']; // Binding does escape, so no quoting/escaping necessary
$saved_control->access_code = hash('sha256', $_POST['savepass']);
$saved_control->access_code = password_hash($_POST['savepass'], PASSWORD_DEFAULT);
$saved_control->email = $_POST['saveemail'];
$saved_control->ip = ($thissurvey['ipaddr'] == 'Y') ?getIPAddress() : '';
$saved_control->saved_thisstep = $thisstep;
Expand Down
7 changes: 5 additions & 2 deletions application/models/SurveyDynamic.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,13 @@ public function relations()
TokenDynamic::sid(self::$sid);
return array(
'survey' => array(self::HAS_ONE, 'Survey', array(), 'condition' => ('sid = ' . self::$sid)),
'tokens' => array(self::HAS_ONE, 'TokenDynamic', array('token' => 'token'))
'tokens' => array(self::HAS_ONE, 'TokenDynamic', array('token' => 'token')),
'saved_control' => array(self::HAS_ONE, 'SavedControl', array('srid' => 'id'))
);
} else {
return array();
return array(
'saved_control' => array(self::HAS_ONE, 'SavedControl', array('srid' => 'id'))
);
}
}

Expand Down
12 changes: 6 additions & 6 deletions application/models/services/CreateSurvey.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,22 @@
class CreateSurvey
{
/** @var int number of attempts to find a valid survey id */
private const ATTEMPTS_CREATE_SURVEY_ID = 50;
const ATTEMPTS_CREATE_SURVEY_ID = 50;

/** @var string all attributes that have the value "NO" */
private const STRING_VALUE_FOR_NO_FALSE = 'N';
const STRING_VALUE_FOR_NO_FALSE = 'N';

/** @var string all attributes that have the value "YES" */
private const STRING_VALUE_FOR_YES_TRUE = 'Y';
const STRING_VALUE_FOR_YES_TRUE = 'Y';

/** @var string value to set attribute to inherit */
private const STRING_SHORT_VALUE_INHERIT = 'I';
const STRING_SHORT_VALUE_INHERIT = 'I';

/** @var int */
private const INTEGER_VALUE_FOR_INHERIT = -1;
const INTEGER_VALUE_FOR_INHERIT = -1;

/** @var int this is the default value for DB table (it corresponds to ) */
private const DEFAULT_DATE_FORMAT = 1;
const DEFAULT_DATE_FORMAT = 1;

/** @var Survey the survey */
private $survey;
Expand Down
3 changes: 1 addition & 2 deletions application/models/services/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
The newly added service classes are expected to have a higher quality than older code in LimeSurvey. Especially:

* PSR-12 compliant
* Don't use Hungarian notation, but instead proper docblocks and @var annotations
* Don't use Hungarian notation, but instead proper docblocks and @var annotations that can be checked by Psalm
* All methods are expected to be testable with unit-tests, which means that all dependencies should be injected _or_ side-effects isolated in small, mockable methods
* Don't use static methods unless you can prove that they don't need to be mocked. Maybe a separate function outside a class would be better?
* Eventually, Psalm will be used to validate that docblocks are correct
* MessDetector might be used to enforce maximum class and method length
* A [dependency injection container](https://www.yiiframework.com/doc/guide/2.0/en/concept-di-container) will be used to coordinate dependencies in the future

Expand Down
11 changes: 11 additions & 0 deletions application/views/questionGroupsAdministration/import_view.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@
<li><?php echo gT("Question attributes:") . $aImportResults['question_attributes'] ?></li>
</ul>
</p>

<!-- Warnings -->
<?php if (count($aImportResults['importwarnings'])>0): ?>
<h2 class="warning"><?php eT("Warnings");?>:</h2>
<ul class="list-unstyled">
<?php foreach ($aImportResults['importwarnings'] as $warning): ?>
<li><?php echo $warning; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>

<p class="text-info"><?php eT("Question group import is complete.") ?></p>

<!-- button -->
Expand Down
19 changes: 19 additions & 0 deletions docs/release_notes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,25 @@ Thank you to everyone who helped with this new release!

CHANGE LOG
------------------------------------------------------
Changes from 4.5.2 (build 210426) to 4.6.0 (build 210504) May 3, 2021
+New feature #17262: Create new getQuestionAttributes() endpoint for Limesurvey API (#1857) (Gabriel Jenik)
-Fixed issue: Remove logo from survey list breadcrumb and replace with naming "List Surveys" (Jessica Höck)
-Fixed issue #17276: Error with survey expiration date and using MSSQL (Carsten Schmitz)
-Fixed issue #17237: Zip attachments on email templates are not attached to the email (#1856) (Gabriel Jenik)
-Fixed issue #17205: When displaying assessment messages, empty lines are being displayed (#1855) (Gabriel Jenik)
-Fixed issue #16677: Group relevance condition dissapears after importing group (#1854) (Gabriel Jenik)
-Fixed issue #16638: EXPIRY keyword does not work in survey description (#1853) (Gabriel Jenik)
-Fixed issue #16339: pluginhelper fullpagewrapper doesnt show content (#1860) (Gabriel Jenik)
-Fixed issue #15196: Passwords of participants who saved their survey progress are stored without salt (Patrick Teichmann)
#Updated translation: Turkish by kayazeren, bulent
#Updated translation: Portuguese (Portugal) by c_schmitz, holch, soniagouveia, pmduque, lucaspcs, marcelovincenzi, marciojv, jbfloripa, cassiofs, samarta
#Updated translation: German by c_schmitz
#Updated translation: Finnish by Jmantysalo
#Updated translation: Czech by c_schmitz, slansky, VBraun, jelen1
#Updated translation: Czech (Informal) by slansky, jelen1
#Updated translation: Catalan by qualitatuvic


Changes from 4.5.1 (build 210420) to 4.5.2 (build 210426) April 26, 2021
-Fixed issue: Question theme should not be deletable if it is used in a survey (Patrick Teichmann)
-Fixed issue: Group table name is not escaped for PostgreSQL in quick translation view (Olle Haerstedt)
Expand Down

0 comments on commit 7686aca

Please sign in to comment.