PageRenderTime 33ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/application/controllers/admin/participantsaction.php

https://bitbucket.org/machaven/limesurvey
PHP | 1753 lines | 1316 code | 161 blank | 276 comment | 187 complexity | 76093fb7fbbe8384582aa539524a4a48 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause, GPL-3.0, LGPL-3.0
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /*
  3. * LimeSurvey
  4. * Copyright (C) 2007-2011 The LimeSurvey Project Team / Carsten Schmitz
  5. * All rights reserved.
  6. * License: GNU/GPL License v2 or later, see LICENSE.php
  7. * LimeSurvey is free software. This version may have been modified pursuant
  8. * to the GNU General Public License, and as distributed it includes or
  9. * is derivative of works licensed under the GNU General Public License or
  10. * other free or open source software licenses.
  11. * See COPYRIGHT.php for copyright notices and details.
  12. *
  13. * $Id$
  14. */
  15. function subval_sort($a, $subkey, $order)
  16. {
  17. $b = array();
  18. $c = array();
  19. foreach ($a as $k => $v)
  20. {
  21. $b[$k] = strtolower($v[$subkey]);
  22. }
  23. if ($order == "asc")
  24. {
  25. asort($b, SORT_REGULAR);
  26. }
  27. else
  28. {
  29. arsort($b, SORT_REGULAR);
  30. }
  31. foreach ($b as $key => $val)
  32. {
  33. $c[] = $a[$key];
  34. }
  35. return $c;
  36. }
  37. /*
  38. * This is the main controller for Participants Panel
  39. */
  40. class participantsaction extends Survey_Common_Action
  41. {
  42. public function runWithParams($params)
  43. {
  44. if (!hasGlobalPermission('USER_RIGHT_PARTICIPANT_PANEL'))
  45. {
  46. die('No permission');
  47. }
  48. parent::runWithParams($params);
  49. }
  50. /**
  51. * Loads jqGrid for the view
  52. * @param string $sScript Subaction
  53. */
  54. private function _loadjqGrid($sScript = '', $aData = array())
  55. {
  56. $this->getController()->_js_admin_includes(Yii::app()->getConfig('generalscripts') . 'jquery/jqGrid/js/i18n/grid.locale-en.js');
  57. $this->getController()->_js_admin_includes(Yii::app()->getConfig('generalscripts') . 'jquery/jqGrid/js/jquery.jqGrid.min.js');
  58. $this->getController()->_js_admin_includes(Yii::app()->getConfig('generalscripts') . 'jquery/jqGrid/plugins/jquery.searchFilter.js');
  59. $this->getController()->_js_admin_includes(Yii::app()->getConfig('generalscripts') . 'jquery/jqGrid/src/grid.celledit.js');
  60. $this->getController()->_css_admin_includes(Yii::app()->getConfig('generalscripts') . 'jquery/jqGrid/css/ui.jqgrid.css');
  61. $this->getController()->_css_admin_includes(Yii::app()->getConfig('generalscripts') . 'jquery/jqGrid/css/jquery.ui.datepicker.css');
  62. if (!empty($sScript))
  63. {
  64. $this->getController()->_js_admin_includes(Yii::app()->getConfig('adminscripts') . $sScript . '.js');
  65. $this->_renderWrappedTemplate('participants', array('participantsPanel', $sScript), $aData);
  66. }
  67. }
  68. /**
  69. * Renders template(s) wrapped in header and footer
  70. *
  71. * @param string $sAction Current action, the folder to fetch views from
  72. * @param string|array $aViewUrls View url(s)
  73. * @param array $aData Data to be passed on. Optional.
  74. */
  75. protected function _renderWrappedTemplate($sAction = 'participants', $aViewUrls = array(), $aData = array())
  76. {
  77. $aData['display']['menu_bars'] = false;
  78. foreach((array) $aViewUrls as $sViewUrl)
  79. {
  80. $a_ViewUrls[] = $sViewUrl . '_view';
  81. }
  82. parent::_renderWrappedTemplate($sAction, $a_ViewUrls, $aData);
  83. }
  84. /**
  85. * Export to csv using optional search/filter
  86. *
  87. * @param type $search
  88. */
  89. private function csvExport($search = null) {
  90. Yii::app()->loadHelper('export');
  91. $attid = ParticipantAttributeNames::model()->getVisibleAttributes();
  92. //If super admin all the participants will be visible
  93. if (Yii::app()->session['USER_RIGHT_SUPERADMIN'])
  94. {
  95. $iUserID = null;
  96. } else {
  97. $iUserID = Yii::app()->session['loginID'];
  98. }
  99. $query = Participants::model()->getParticipants(0, 0, $attid, null, $search, $iUserID);
  100. if (!$query)
  101. return false;
  102. // Field names in the first row
  103. $fields = array('participant_id', 'firstname', 'lastname', 'email', 'language', 'blacklisted', 'owner_uid');
  104. $outputarray = array(); // The array to be passed to the export helper to be written to a csv file
  105. $outputarray[0] = $fields; //fields written to output array
  106. // If attribute fields are selected, add them to the output
  107. $queryId = Yii::app()->request->getQuery('id');
  108. if (!is_null($queryId) && $queryId != "null") {
  109. $iAttributeId = explode(",", $queryId);
  110. foreach ($iAttributeId as $key => $value)
  111. {
  112. $fields[] = 'a'.$value;
  113. $attributename = ParticipantAttributeNames::model()->getAttributeNames($value);
  114. $outputarray[0][] = $attributename[0]['attribute_name'];
  115. }
  116. }
  117. $fieldKeys = array_flip($fields);
  118. foreach ($query as $field => $aData)
  119. {
  120. $outputarray[] = array_intersect_key($aData, $fieldKeys);
  121. }
  122. CPDBExport($outputarray, "central_" . time());
  123. }
  124. /**
  125. * Returns a string with the number of participants available for export or 0
  126. *
  127. * @param type $search
  128. * @return string|0
  129. */
  130. protected function csvExportCount($search = null)
  131. {
  132. $clang = $this->getController()->lang;
  133. $attid = ParticipantAttributeNames::model()->getVisibleAttributes();
  134. //If super admin all the participants will be visible
  135. if (Yii::app()->session['USER_RIGHT_SUPERADMIN'])
  136. {
  137. $iUserID = null;
  138. } else {
  139. $iUserID = Yii::app()->session['loginID'];
  140. }
  141. $count = Participants::model()->getParticipantsCount($attid, $search, $iUserID);
  142. if ($count > 0) {
  143. return sprintf($clang->gT("Export %s participant(s) to CSV"), $count);
  144. } else {
  145. return $count;
  146. }
  147. }
  148. /**
  149. * Loads the view 'participantsPanel'
  150. */
  151. function index()
  152. {
  153. $iUserID = Yii::app()->session['loginID'];
  154. // if superadmin all the records in the cpdb will be displayed
  155. if (Yii::app()->session['USER_RIGHT_SUPERADMIN'])
  156. {
  157. $iTotalRecords = Participants::model()->count();
  158. }
  159. // if not only the participants on which he has right on (shared and owned)
  160. else
  161. {
  162. $iTotalRecords = Participants::model()->getParticipantsOwnerCount($iUserID);
  163. }
  164. // gets the count of participants, their attributes and other such details
  165. $aData = array(
  166. 'totalrecords' => $iTotalRecords,
  167. 'owned' => Participants::model()->count('owner_uid = ' . $iUserID),
  168. 'shared' => Participants::model()->getParticipantsSharedCount($iUserID),
  169. 'attributecount' => ParticipantAttributeNames::model()->count(),
  170. 'blacklisted' => Participants::model()->count('owner_uid = ' . $iUserID . ' AND blacklisted = \'Y\'')
  171. );
  172. // loads the participant panel and summary view
  173. $this->_renderWrappedTemplate('participants', array('participantsPanel', 'summary'), $aData);
  174. }
  175. /**
  176. * Loads the view 'importCSV'
  177. */
  178. function importCSV()
  179. {
  180. $this->_renderWrappedTemplate('participants', array('participantsPanel', 'importCSV'));
  181. }
  182. /**
  183. * Loads the view 'displayParticipants' which contains the main grid
  184. */
  185. function displayParticipants()
  186. {
  187. $lang = Yii::app()->session['adminlang'];
  188. // loads the survey names to be shown in add to survey
  189. // if user is superadmin, all survey names
  190. $urlSearch=Yii::app()->request->getQuery('searchurl');
  191. $urlSearch=!empty($urlSearch) ? "getParticipantsResults_json/search/$urlSearch" : "getParticipants_json";
  192. //Get list of surveys.
  193. //Should be all surveys owned by user (or all surveys for super admin)
  194. $surveys = Survey::model();
  195. //!!! Is this even possible to execute?
  196. if (empty(Yii::app()->session['USER_RIGHT_SUPERADMIN']))
  197. $surveys->permission(Yii::app()->user->getId());
  198. $aSurveyNames = $surveys->model()->with(array('languagesettings'=>array('condition'=>'surveyls_language=language'), 'owner'))->findAll();
  199. /* Build a list of surveys that have tokens tables */
  200. $tSurveyNames=array();
  201. foreach($aSurveyNames as $row)
  202. {
  203. $row = array_merge($row->attributes, $row->languagesettings[0]->attributes);
  204. $bTokenExists = tableExists('{{tokens_' . $row['sid'] . '}}');
  205. if ($bTokenExists) //If tokens table exists
  206. {
  207. $tSurveyNames[]=$row;
  208. }
  209. }
  210. // data to be passed to view
  211. $aData = array(
  212. 'names' => User::model()->findAll(),
  213. 'attributes' => ParticipantAttributeNames::model()->getVisibleAttributes(),
  214. 'allattributes' => ParticipantAttributeNames::model()->getAllAttributes(),
  215. 'attributeValues' => ParticipantAttributeNames::model()->getAllAttributesValues(),
  216. 'surveynames' => $aSurveyNames,
  217. 'tokensurveynames' => $tSurveyNames,
  218. 'urlsearch' => $urlSearch
  219. );
  220. $this->getController()->_js_admin_includes(Yii::app()->getConfig('generalscripts') . 'jquery/jqGrid/js/i18n/grid.locale-en.js');
  221. $this->getController()->_js_admin_includes(Yii::app()->getConfig('generalscripts') . 'jquery/jqGrid/js/jquery.jqGrid.min.js');
  222. $this->getController()->_css_admin_includes(Yii::app()->getConfig('publicstyleurl') . 'jquery.multiselect.css');
  223. $this->getController()->_css_admin_includes(Yii::app()->getConfig('publicstyleurl') . 'jquery.multiselect.filter.css');
  224. $this->getController()->_css_admin_includes(Yii::app()->getConfig('adminstyleurl') . 'displayParticipants.css');
  225. $this->getController()->_css_admin_includes(Yii::app()->getConfig('generalscripts') . 'jquery/jqGrid/css/ui.jqgrid.css');
  226. $this->getController()->_css_admin_includes(Yii::app()->getConfig('generalscripts') . 'jquery/jqGrid/css/jquery.ui.datepicker.css');
  227. // loads the participant panel view and display participant view
  228. $this->_renderWrappedTemplate('participants', array('participantsPanel', 'displayParticipants'), $aData);
  229. }
  230. /**
  231. * Loads the view 'blacklistControl'
  232. */
  233. function blacklistControl()
  234. {
  235. $aData = array(
  236. 'blacklistallsurveys' => Yii::app()->getConfig('blacklistallsurveys'),
  237. 'blacklistnewsurveys' => Yii::app()->getConfig('blacklistnewsurveys'),
  238. 'blockaddingtosurveys' => Yii::app()->getConfig('blockaddingtosurveys'),
  239. 'hideblacklisted' => Yii::app()->getConfig('hideblacklisted'),
  240. 'deleteblacklisted' => Yii::app()->getConfig('deleteblacklisted'),
  241. 'allowunblacklist' => Yii::app()->getConfig('allowunblacklist')
  242. );
  243. $this->_renderWrappedTemplate('participants', array('participantsPanel', 'blacklist'), $aData);
  244. }
  245. /**
  246. * Loads the view 'userControl'
  247. */
  248. function userControl()
  249. {
  250. $aData = array(
  251. 'userideditable' => Yii::app()->getConfig('userideditable')
  252. );
  253. $this->_renderWrappedTemplate('participants', array('participantsPanel', 'userControl'), $aData);
  254. }
  255. /**
  256. * Loads the view 'sharePanel'
  257. */
  258. function sharePanel()
  259. {
  260. $this->_loadjqGrid('sharePanel');
  261. }
  262. /**
  263. * Sends the shared participant info to the share panel using JSON encoding
  264. * Called after the share panel grid is loaded
  265. * Returns the json depending on the user logged in by checking it from the session
  266. * @return JSON encoded string containg sharing information
  267. */
  268. function getShareInfo_json()
  269. {
  270. $aData = new stdClass();
  271. $aData->page = 1;
  272. // If super administrator all the share info in the links table will be shown
  273. if (Yii::app()->session['USER_RIGHT_SUPERADMIN'])
  274. {
  275. $records = Participants::model()->getParticipantSharedAll();
  276. $aData->records = count($records);
  277. $aData->total = ceil($aData->records / 10);
  278. $i = 0;
  279. foreach ($records as $row)
  280. {
  281. $oShared = User::model()->getName($row['share_uid']); //for conversion of uid to human readable names
  282. $owner = User::model()->getName($row['owner_uid']);
  283. $aData->rows[$i]['id'] = $row['participant_id']."--".$row['share_uid']; //This is the unique combination per record
  284. $aData->rows[$i]['cell'] = array($row['firstname'], $row['lastname'], $row['email'], $oShared[0]['full_name'], $row['share_uid'], $owner[0]['full_name'], $row['date_added'], $row['can_edit']);
  285. $i++;
  286. }
  287. echo ls_json_encode($aData);
  288. }
  289. // otherwise only the shared participants by that user
  290. else
  291. {
  292. $records = Participants::model()->getParticipantShared(Yii::app()->session['loginID']);
  293. $aData->records = count($records);
  294. $aData->total = ceil($aData->records / 10);
  295. $i = 0;
  296. foreach ($records as $row)
  297. {
  298. $sharename = User::model()->getName($row['share_uid']); //for conversion of uid to human readable names
  299. $aData->rows[$i]['id'] = $row['participant_id'];
  300. $aData['rows'][$i]['cell'] = array($row['firstname'], $row['lastname'], $row['email'], $sharename['full_name'], $row['share_uid'], $row['date_added'], $row['can_edit']);
  301. $i++;
  302. }
  303. echo ls_json_encode($aData);
  304. }
  305. }
  306. /**
  307. * Takes the edit call from the share panel, which either edits or deletes the share information
  308. * Basically takes the call on can_edit
  309. */
  310. function editShareInfo()
  311. {
  312. $operation = Yii::app()->request->getPost('oper');
  313. $shareIds = Yii::app()->request->getPost('id');
  314. if ($operation == 'del') // If operation is delete , it will delete, otherwise edit it
  315. {
  316. ParticipantShares::model()->deleteRow($shareIds);
  317. }
  318. else
  319. {
  320. $aData = array(
  321. 'participant_id' => Yii::app()->request->getPost('participant_id'),
  322. 'can_edit' => Yii::app()->request->getPost('can_edit'),
  323. 'share_uid' => Yii::app()->request->getPost('shared_uid')
  324. );
  325. ParticipantShares::model()->updateShare($aData);
  326. }
  327. }
  328. /**
  329. * Loads the view 'attributeControl'
  330. */
  331. function attributeControl()
  332. {
  333. $this->_loadjqGrid('attributeControl');
  334. }
  335. /**
  336. * Sends the attributes info using JSON encoding
  337. * Called after the Attribute management grid is loaded
  338. * @return JSON encoded string containg sharing information
  339. */
  340. function getAttributeInfo_json()
  341. {
  342. $clang = Yii::app()->lang;
  343. $page = Yii::app()->request->getPost('page');
  344. $limit = Yii::app()->request->getPost('rows');
  345. $limit = isset($limit) ? $limit : 50; //Stop division by zero errors
  346. $records = ParticipantAttributeNames::model()->with('participant_attribute_names_lang')->findAll();
  347. $attribute_types = array(
  348. 'DD' => $clang->gT("Drop-down list"),
  349. 'DP' => $clang->gT("Date"),
  350. 'TB' => $clang->gT("Text box")
  351. );
  352. $aData = new stdClass();
  353. $aData->page = $page;
  354. $aData->records = count($records);
  355. $aData->total = ceil(ParticipantAttributeNames::model()->getAttributes(true) / $limit);
  356. $i = 0;
  357. foreach($records as $row) { //Iterate through each attribute
  358. $thisname="";
  359. foreach($row->participant_attribute_names_lang as $names) { //Iterate through each language version of this attribute
  360. if($thisname=="") {$thisname=$names->attribute_name;} //Choose the first item by default
  361. if($names->lang == Yii::app()->session['adminlang']) {$thisname=$names->attribute_name;} //Override the default with the admin language version if found
  362. }
  363. $aData->rows[$i]['id'] = $row->attribute_id;
  364. $aData->rows[$i]['cell'] = array('', $thisname, $attribute_types[$row->attribute_type], $row->visible);
  365. $i++;
  366. }
  367. echo ls_json_encode($aData);
  368. }
  369. /**
  370. * Takes the edit call from the share panel, which either edits or deletes the share information
  371. * Basically takes the call on can_edit
  372. */
  373. function editAttributeInfo()
  374. {
  375. $clang = Yii::app()->lang;
  376. $operation = Yii::app()->request->getPost('oper');
  377. if ($operation == 'del' && Yii::app()->request->getPost('id'))
  378. {
  379. $aAttributeIds = (array) explode(',', Yii::app()->request->getPost('id'));
  380. $aAttributeIds = array_map('trim', $aAttributeIds);
  381. $aAttributeIds = array_map('intval', $aAttributeIds);
  382. foreach ($aAttributeIds as $iAttributeId)
  383. {
  384. ParticipantAttributeNames::model()->delAttribute($iAttributeId);
  385. }
  386. }
  387. elseif ($operation == 'add' && Yii::app()->request->getPost('attribute_name'))
  388. {
  389. $aData = array(
  390. 'attribute_name' => Yii::app()->request->getPost('attribute_name'),
  391. 'attribute_type' => Yii::app()->request->getPost('attribute_type'),
  392. 'visible' => Yii::app()->request->getPost('visible') == 'TRUE' ? 'TRUE' : 'FALSE'
  393. );
  394. echo ParticipantAttributeNames::model()->storeAttribute($aData);
  395. }
  396. elseif ($operation == 'edit' && Yii::app()->request->getPost('id'))
  397. {
  398. $aData = array(
  399. 'attribute_id' => Yii::app()->request->getPost('id'),
  400. 'attribute_name' => Yii::app()->request->getPost('attribute_name'),
  401. 'attribute_type' => Yii::app()->request->getPost('attribute_type'),
  402. 'visible' => Yii::app()->request->getPost('visible') == 'TRUE' ? 'TRUE' : 'FALSE'
  403. );
  404. ParticipantAttributeNames::model()->saveAttribute($aData);
  405. $clang->eT("Attribute display setting updated");
  406. }
  407. }
  408. /**
  409. * Takes the delete call from the display participants and take appropriate action depending on the condition
  410. */
  411. function delParticipant()
  412. {
  413. $selectoption = Yii::app()->request->getPost('selectedoption');
  414. $iParticipantId = Yii::app()->request->getPost('participant_id');
  415. //echo $selectoption." -- ".$iParticipantId."<br />"; die();
  416. // Deletes from participants only
  417. if ($selectoption == 'po')
  418. {
  419. Participants::model()->deleteParticipant($iParticipantId);
  420. }
  421. // Deletes from central and token table
  422. elseif ($selectoption == 'ptt')
  423. {
  424. Participants::model()->deleteParticipantToken($iParticipantId);
  425. }
  426. // Deletes from central , token and assosiated responses as well
  427. elseif ($selectoption == 'ptta')
  428. {
  429. Participants::model()->deleteParticipantTokenAnswer($iParticipantId);
  430. }
  431. }
  432. /**
  433. * Resposible for editing data on the jqGrid
  434. */
  435. function editParticipant()
  436. {
  437. $operation = Yii::app()->request->getPost('oper');
  438. //In case the uid is not editable, then user id is not posted and hence the current user is added in the uid
  439. if (Yii::app()->request->getPost('owner_uid') == '')
  440. {
  441. $oid = Yii::app()->session['loginID'];
  442. }
  443. //otherwise the one which is posted is added
  444. else
  445. {
  446. $oid = Yii::app()->request->getPost('owner_uid');
  447. }
  448. if (Yii::app()->request->getPost('language') == '')
  449. {
  450. $lang = Yii::app()->session['adminlang'];
  451. }
  452. else
  453. {
  454. $lang = Yii::app()->request->getPost('language');
  455. }
  456. // if edit it will update the row
  457. if ($operation == 'edit')
  458. {
  459. $aData = array(
  460. 'participant_id' => Yii::app()->request->getPost('id'),
  461. 'firstname' => Yii::app()->request->getPost('firstname'),
  462. 'lastname' => Yii::app()->request->getPost('lastname'),
  463. 'email' => Yii::app()->request->getPost('email'),
  464. 'language' => Yii::app()->request->getPost('language'),
  465. 'blacklisted' => Yii::app()->request->getPost('blacklisted'),
  466. 'owner_uid' => $oid
  467. );
  468. Participants::model()->updateRow($aData);
  469. }
  470. // if add it will insert a new row
  471. elseif ($operation == 'add')
  472. {
  473. $uuid = $this->gen_uuid();
  474. $aData = array(
  475. 'participant_id' => $uuid,
  476. 'firstname' => Yii::app()->request->getPost('firstname'),
  477. 'lastname' => Yii::app()->request->getPost('lastname'),
  478. 'email' => Yii::app()->request->getPost('email'),
  479. 'language' => Yii::app()->request->getPost('language'),
  480. 'blacklisted' => Yii::app()->request->getPost('blacklisted'),
  481. 'owner_uid' => $oid
  482. );
  483. Participants::model()->insertParticipant($aData);
  484. }
  485. }
  486. /**
  487. * Stores the user control setting to the database
  488. */
  489. function storeUserControlValues()
  490. {
  491. if ($find = Settings_global::model()->findByPk('userideditable'))
  492. {
  493. Settings_global::model()->updateByPk('userideditable', array('stg_value'=>Yii::app()->request->getPost('userideditable')));
  494. }
  495. else
  496. {
  497. $stg = new Settings_global;
  498. $stg ->stg_name='userideditable';
  499. $stg ->stg_value=Yii::app()->request->getPost('userideditable');
  500. $stg->save();
  501. }
  502. Yii::app()->getController()->redirect(Yii::app()->getController()->createUrl('admin/participants/sa/userControl'));
  503. }
  504. /**
  505. * Stores the blacklist setting to the database
  506. */
  507. function storeBlacklistValues()
  508. {
  509. $values = Array('blacklistallsurveys', 'blacklistnewsurveys', 'blockaddingtosurveys', 'hideblacklisted', 'deleteblacklisted', 'allowunblacklist', 'userideditable');
  510. foreach ($values as $value)
  511. {
  512. if ($find = Settings_global::model()->findByPk($value))
  513. {
  514. Settings_global::model()->updateByPk($value, array('stg_value'=>Yii::app()->request->getPost($value)));
  515. }
  516. else
  517. {
  518. $stg = new Settings_global;
  519. $stg ->stg_name=$value;
  520. $stg ->stg_value=Yii::app()->request->getPost($value);
  521. $stg->save();
  522. }
  523. }
  524. Yii::app()->getController()->redirect(Yii::app()->getController()->createUrl('admin/participants/sa/blacklistControl'));
  525. }
  526. /**
  527. * Receives an ajax call containing the participant id in the fourth segment of the url
  528. * Supplies list of survey links - surveys of which this participant is on the tokens table
  529. * URL: [localurl]/limesurvey/admin/participants/getSurveyInfo_json/pid/[participant_id]
  530. * RETURNS: json data containing linked survey information (Survey name, survey id, token_id and date_added)
  531. */
  532. function getSurveyInfo_json()
  533. {
  534. $participantid = Yii::app()->request->getQuery('pid');
  535. $records = Survey_links::model()->findAllByAttributes((array('participant_id' => $participantid)));
  536. $aData = new stdClass();
  537. $aData->page = 1;
  538. $aData->records = count($records);
  539. $aData->total = ceil($aData->records / 10);
  540. $i = 0;
  541. foreach ($records as $row)
  542. {
  543. $surveyname = Surveys_languagesettings::model()->getSurveyNames($row['survey_id']);
  544. $surveylink = "";
  545. /* Check permissions of each survey before creating a link*/
  546. if (!hasSurveyPermission($row['survey_id'], 'tokens', 'read'))
  547. {
  548. $surveylink = $row['survey_id'];
  549. } else
  550. {
  551. $surveylink = '<a href=' . Yii::app()->getController()->createUrl("/admin/tokens/sa/browse/surveyid/{$row['survey_id']}") . '>' . $row['survey_id'].'</a>';
  552. }
  553. $aData->rows[$i]['cell'] = array($surveyname[0]['surveyls_title'], $surveylink, $row['token_id'], $row['date_created'], $row['date_invited'], $row['date_completed']);
  554. $i++;
  555. }
  556. echo ls_json_encode($aData);
  557. }
  558. /**
  559. * Returns the count of the participants in the CSV and show it in the title of the modal box
  560. * This is to give the user the hint to see the number of participants he is exporting
  561. */
  562. function exporttocsvcount()
  563. {
  564. $searchconditionurl = Yii::app()->request->getPost('searchcondition');
  565. $searchcondition = basename($searchconditionurl);
  566. if ($searchcondition != 'getParticipants_json') // if there is a search condition then only the participants that match the search criteria are counted
  567. {
  568. $condition = explode("||", $searchcondition);
  569. $search = Participants::model()->getParticipantsSearchMultipleCondition($condition);
  570. } else {
  571. $search = null;
  572. }
  573. echo $this->csvExportCount($search);
  574. }
  575. /**
  576. * Outputs the count of participants when using the export all button on the top
  577. */
  578. function exporttocsvcountAll()
  579. {
  580. echo $this->csvExportCount();
  581. }
  582. /**
  583. * Responsible to export all the participants in the central table
  584. */
  585. function exporttocsvAll()
  586. {
  587. $this->csvExport(); // no search
  588. }
  589. /**
  590. * Similar to export to all message where it counts the number to participants to be copied
  591. * and echo them to be displayed in modal box header
  592. */
  593. function getaddtosurveymsg()
  594. {
  595. $searchcondition = basename(Yii::app()->request->getPost('searchcondition'));
  596. // If there is a search condition in the url of the jqGrid
  597. if ($searchcondition != 'getParticipants_json')
  598. {
  599. $participantid = "";
  600. $condition = explode("||", $searchcondition);
  601. $query = Participants::model()->getParticipantsSearchMultiple($condition, 0, 0);
  602. printf( $this->getController()->lang->gT("%s participant(s) are to be copied "), count($query));
  603. }
  604. // if there is no search condition the participants will be counted on the basis of who is logged in
  605. else
  606. {
  607. if (Yii::app()->session['USER_RIGHT_SUPERADMIN']) //If super admin all the participants will be visible
  608. {
  609. $count = Participants::model()->getParticipantsCountWithoutLimit();
  610. }
  611. else
  612. {
  613. $query = Participants::model()->getParticipantsOwner(Yii::app()->session['loginID']);
  614. $count = count($query);
  615. }
  616. printf($this->getController()->lang->gT("%s participant(s) are to be copied "), $count);
  617. }
  618. }
  619. /**
  620. * Gets the ids of participants to be copied to the individual survey
  621. */
  622. function getSearchIDs()
  623. {
  624. $searchcondition = basename(Yii::app()->request->getPost('searchcondition')); // get the search condition from the URL
  625. /* a search contains posted data inside $_POST['searchcondition'].
  626. * Each seperate query is made up of 3 fields, seperated by double-pipes ("|")
  627. * EG: fname||eq||jason||lname||ct||c
  628. *
  629. */
  630. if ($searchcondition != 'getParticipants_json') // if there is a search condition present
  631. {
  632. $participantid = "";
  633. $condition = explode("||", $searchcondition); // explode the condition to the array
  634. $query = Participants::model()->getParticipantsSearchMultiple($condition, 0, 0);
  635. foreach ($query as $key => $value)
  636. {
  637. if (Yii::app()->session['USER_RIGHT_SUPERADMIN'])
  638. {
  639. $participantid .= "," . $value['participant_id']; // combine the participant id's in an string
  640. } else
  641. {
  642. if(Participants::model()->is_owner($value['participant_id']))
  643. {
  644. $participantid .= "," . $value['participant_id']; // combine the participant id's in an string
  645. }
  646. }
  647. }
  648. echo $participantid; //echo the participant id's
  649. }
  650. else// if no search condition
  651. {
  652. $participantid = ""; // initiallise the participant id to blank
  653. if (Yii::app()->session['USER_RIGHT_SUPERADMIN']) //If super admin all the participants will be visible
  654. {
  655. $query = Participants::model()->getParticipantsWithoutLimit(); // get all the participant id if it is a super admin
  656. }
  657. else // get participants on which the user has right on
  658. {
  659. $query = Participants::model()->getParticipantsOwner(Yii::app()->session['loginID']);
  660. }
  661. foreach ($query as $key => $value)
  662. {
  663. $participantid = $participantid . "," . $value['participant_id']; // combine the participant id's in an string
  664. }
  665. echo $participantid; //echo the participant id's
  666. }
  667. }
  668. /**
  669. * Responsible for reading the CSV file line by line, check for duplicate participants
  670. * invalid participants and invalid attributes and copy them to the central table
  671. * Also responsible for creation of new attribute and mapping of old attribute to attribute in csv
  672. */
  673. function exporttocsv()
  674. {
  675. $searchconditionurl = Yii::app()->request->getPost('searchcondition');
  676. $searchcondition = basename($searchconditionurl);
  677. if ($searchcondition != 'getParticipants_json') // if there is a search condition then only the participants that match the search criteria are counted
  678. {
  679. $condition = explode("||", $searchcondition);
  680. $search = Participants::model()->getParticipantsSearchMultipleCondition($condition);
  681. } else {
  682. $search = null;
  683. }
  684. $this->csvExport($search);
  685. }
  686. /**
  687. * Equal to getParticipants_json() but now with a search
  688. */
  689. function getParticipantsResults_json()
  690. {
  691. $searchcondition = Yii::app()->request->getQuery('search');
  692. $searchcondition = urldecode($searchcondition);
  693. $finalcondition = array();
  694. $condition = explode("||", $searchcondition);
  695. $search = Participants::model()->getParticipantsSearchMultipleCondition($condition);
  696. return $this->getParticipants_json($search);
  697. }
  698. /*
  699. * Sends the data in JSON format extracted from the database to be displayed using the jqGrid
  700. */
  701. function getParticipants_json($search = null)
  702. {
  703. $page = Yii::app()->request->getPost('page');
  704. $limit = Yii::app()->request->getPost('rows');
  705. $limit = isset($limit) ? $limit : 50; //Stop division by zero errors
  706. $attid = ParticipantAttributeNames::model()->getVisibleAttributes();
  707. $participantfields = array('participant_id', 'can_edit', 'firstname', 'lastname', 'email', 'blacklisted', 'survey', 'language', 'owner_uid');
  708. foreach ($attid as $key => $value)
  709. {
  710. array_push($participantfields, $value['attribute_id']);
  711. }
  712. $sidx = Yii::app()->request->getPost('sidx');
  713. $sidx = !empty($sidx) ? $sidx : "lastname";
  714. $sord = Yii::app()->request->getPost('sord');
  715. $sord = !empty($sord) ? $sord : "asc";
  716. $order = $sidx. " ". $sord;
  717. $aData = new stdClass;
  718. //If super admin all the participants will be visible
  719. if (Yii::app()->session['USER_RIGHT_SUPERADMIN'])
  720. {
  721. $iUserID = null;
  722. } else {
  723. $iUserID = Yii::app()->session['loginID'];
  724. }
  725. $aData->records = Participants::model()->getParticipantsCount($attid, $search, $iUserID);
  726. $aData->total = ceil($aData->records / $limit);
  727. if ($page>$aData->total) {
  728. $page = $aData->total;
  729. }
  730. $aData->page = $page;
  731. $records = Participants::model()->getParticipants($page, $limit,$attid, $order, $search, $iUserID);
  732. $aRowToAdd=array();
  733. foreach ($records as $key => $row)
  734. {
  735. if (array_key_exists('can_edit', $row)) {
  736. $sCanEdit = $row['can_edit'];
  737. if (is_null($sCanEdit)) {
  738. $sCanEdit = 'true';
  739. }
  740. } else {
  741. // Super admin
  742. $sCanEdit = "true";
  743. }
  744. $aRowToAdd['cell'] = array($row['participant_id'], $sCanEdit, $row['firstname'], $row['lastname'], $row['email'], $row['blacklisted'], $row['survey'], $row['language'], $row['ownername']);
  745. $aRowToAdd['id'] = $row['participant_id'];
  746. unset($row['participant_id'], $row['firstname'], $row['lastname'], $row['email'], $row['blacklisted'], $row['language'],$row['ownername'],$row['owner_uid'], $row['can_edit'], $row['survey']);
  747. foreach($row as $key=>$attvalue)
  748. {
  749. $aRowToAdd['cell'][] = $attvalue;
  750. }
  751. $aData->rows[] = $aRowToAdd;
  752. }
  753. echo ls_json_encode($aData);
  754. }
  755. /*
  756. * Fetches the attributes of a participant to be displayed in the attribute subgrid
  757. */
  758. function getAttribute_json()
  759. {
  760. $iParticipantId = Yii::app()->request->getQuery('pid');
  761. $records = ParticipantAttributeNames::model()->getParticipantVisibleAttribute($iParticipantId);
  762. //$getallattributes = ParticipantAttributeNames::model()->with('participant_attribute_names_lang')->findAll();
  763. $records = subval_sort($records, "attribute_name", "asc");
  764. $i = 0;
  765. $doneattributes = array(); //If the user has any actual attribute values, they'll be stored here
  766. /* Iterate through each attribute owned by this user */
  767. foreach ($records as $row)
  768. {
  769. $outputs[$i] = array("", $row['participant_id']."_".$row['attribute_id'], $row['attribute_type'], $row['attribute_id'], $row['attribute_name'], $row['value']);
  770. /* Collect allowed values for a DropDown attribute */
  771. if ($row['attribute_type'] == "DD")
  772. {
  773. $attvalues = ParticipantAttributeNames::model()->getAttributesValues($row['attribute_id']);
  774. if (!empty($attvalues))
  775. {
  776. $attval = "";
  777. foreach ($attvalues as $val)
  778. {
  779. $attval .= $val['value'] . ":" . $val['value'];
  780. $attval .= ";";
  781. }
  782. $attval = substr($attval, 0, -1);
  783. array_push($outputs[$i], $attval);
  784. }
  785. else
  786. {
  787. array_push($outputs[$i], "");
  788. }
  789. }
  790. else
  791. {
  792. array_push($outputs[$i], "");
  793. }
  794. array_push($doneattributes, $row['attribute_id']);
  795. $i++;
  796. }
  797. /* Build a list of attribute names for which this user has NO values stored, keep it in $attributenotdone */
  798. $attributenotdone=array();
  799. /* The user has NO values stored against any attribute */
  800. if (count($doneattributes) == 0)
  801. {
  802. $attributenotdone = ParticipantAttributeNames::model()->getAttributes();
  803. }
  804. /* The user has SOME values stored against attributes */
  805. else
  806. {
  807. $attributenotdone = ParticipantAttributeNames::model()->getnotaddedAttributes($doneattributes);
  808. }
  809. /* Go through the empty attributes and build an entry in the output for them */
  810. foreach ($attributenotdone as $row)
  811. {
  812. $outputs[$i] = array("", $iParticipantId."_".$row['attribute_id'], $row['attribute_type'], $row['attribute_id'], $row['attribute_name'], "");
  813. if ($row['attribute_type'] == "DD")
  814. {
  815. $attvalues = ParticipantAttributeNames::model()->getAttributesValues($row['attribute_id']);
  816. if (!empty($attvalues))
  817. {
  818. $attval = "";
  819. foreach ($attvalues as $val)
  820. {
  821. $attval .= $val['value'] . ":" . $val['value'];
  822. $attval .= ";";
  823. }
  824. $attval = substr($attval, 0, -1);
  825. array_push($outputs[$i], $attval);
  826. }
  827. else
  828. {
  829. array_push($outputs[$i], "");
  830. }
  831. }
  832. else
  833. {
  834. array_push($outputs[$i], "");
  835. }
  836. $i++;
  837. }
  838. $outputs=subval_sort($outputs, 3, "asc");
  839. $aData = new stdClass();
  840. $aData->page = 1;
  841. $aData->rows[0]['id'] = $iParticipantId;
  842. $aData->rows[0]['cell'] = array();
  843. $aData->records = count($outputs);
  844. $aData->total = ceil($aData->records / 10);
  845. foreach($outputs as $key=>$output) {
  846. $aData->rows[$key]['id']=$output[1];
  847. $aData->rows[$key]['cell']=$output;
  848. }
  849. /* TODO: It'd be nice to do a natural sort on the attribute list at some point.
  850. Currently they're returned in order of attributes WITH values, then WITHOUT values
  851. */
  852. echo ls_json_encode($aData);
  853. }
  854. /*
  855. * Gets the data from the form for add participants and pass it to the participants model
  856. */
  857. function storeParticipants()
  858. {
  859. $aData = array('participant_id' => uniqid(),
  860. 'firstname' => Yii::app()->request->getPost('firstname'),
  861. 'lastname' => Yii::app()->request->getPost('lastname'),
  862. 'email' => Yii::app()->request->getPost('email'),
  863. 'language' => Yii::app()->request->getPost('language'),
  864. 'blacklisted' => Yii::app()->request->getPost('blacklisted'),
  865. 'owner_uid' => Yii::app()->request->getPost('owner_uid'));
  866. Participants::model()->insertParticipant($aData);
  867. }
  868. /*
  869. * Responsible for showing the additional attribute for central database
  870. */
  871. function viewAttribute()
  872. {
  873. $iAttributeId = Yii::app()->request->getQuery('aid');
  874. $aData = array(
  875. 'attributes' => ParticipantAttributeNames::model()->getAttribute($iAttributeId),
  876. 'attributenames' => ParticipantAttributeNames::model()->getAttributeNames($iAttributeId),
  877. 'attributevalues' => ParticipantAttributeNames::model()->getAttributesValues($iAttributeId)
  878. );
  879. $this->getController()->_css_admin_includes(Yii::app()->getConfig('adminstyleurl') . 'participants.css');
  880. $this->getController()->_css_admin_includes(Yii::app()->getConfig('adminstyleurl') . 'viewAttribute.css');
  881. $this->_renderWrappedTemplate('participants', array('participantsPanel', 'viewAttribute'), $aData);
  882. }
  883. /*
  884. * Responsible for saving the additional attribute. It iterates through all the new attributes added dynamically
  885. * and iterates through them
  886. */
  887. function saveAttribute()
  888. {
  889. $iAttributeId = Yii::app()->request->getQuery('aid');
  890. $aData = array(
  891. 'attribute_id' => $iAttributeId,
  892. 'attribute_type' => Yii::app()->request->getPost('attribute_type'),
  893. 'visible' => Yii::app()->request->getPost('visible')
  894. );
  895. ParticipantAttributeNames::model()->saveAttribute($aData);
  896. foreach ($_POST as $key => $value)
  897. {
  898. // check for language code in the post variables this is a hack as the only way to check for language data
  899. if (strlen($key) == 2)
  900. {
  901. $langdata = array(
  902. 'attribute_id' => $iAttributeId,
  903. 'attribute_name' => $value,
  904. 'lang' => $key
  905. );
  906. ParticipantAttributeNames::model()->saveAttributeLanguages($langdata);
  907. }
  908. }
  909. if (Yii::app()->request->getPost('langdata'))
  910. {
  911. $langdata = array(
  912. 'attribute_id' => $iAttributeId,
  913. 'attribute_name' => Yii::app()->request->getPost('attname'),
  914. 'lang' => Yii::app()->request->getPost('langdata')
  915. );
  916. ParticipantAttributeNames::model()->saveAttributeLanguages($langdata);
  917. }
  918. /* Create new attribute value */
  919. if (Yii::app()->request->getPost('attribute_value_name_1') || Yii::app()->request->getPost('attribute_value_name_1') == "0")
  920. {
  921. $i = 1;
  922. $attvaluename = 'attribute_value_name_' . $i;
  923. while (array_key_exists($attvaluename, $_POST) && $_POST[$attvaluename] != "")
  924. {
  925. if ($_POST[$attvaluename] != "")
  926. {
  927. $aDatavalues[$i] = array(
  928. 'attribute_id' => $iAttributeId,
  929. 'value' => Yii::app()->request->getPost($attvaluename)
  930. );
  931. }
  932. $attvaluename = 'attribute_value_name_' . ++$i;
  933. };
  934. ParticipantAttributeNames::model()->storeAttributeValues($aDatavalues);
  935. }
  936. /* Save updated attribute values */
  937. if (Yii::app()->request->getPost('editbox') || Yii::app()->request->getPost('editbox')=="0")
  938. {
  939. $editattvalue = array(
  940. 'attribute_id' => $iAttributeId,
  941. 'value_id' => Yii::app()->request->getPost('value_id'),
  942. 'value' => Yii::app()->request->getPost('editbox')
  943. );
  944. ParticipantAttributeNames::model()->saveAttributeValue($editattvalue);
  945. }
  946. Yii::app()->getController()->redirect(Yii::app()->getController()->createUrl('admin/participants/sa/attributeControl'));
  947. }
  948. /*
  949. * Responsible for deleting the additional attribute values in case of drop down.
  950. */
  951. function delAttributeValues()
  952. {
  953. $iAttributeId = Yii::app()->request->getQuery('aid');
  954. $iValueId = Yii::app()->request->getQuery('vid');
  955. ParticipantAttributeNames::model()->delAttributeValues($iAttributeId, $iValueId);
  956. Yii::app()->getController()->redirect(Yii::app()->getController()->createUrl('/admin/participants/sa/viewAttribute/aid/' . $iAttributeId));
  957. }
  958. /*
  959. * Responsible for editing the additional attributes values
  960. */
  961. function editAttributevalue()
  962. {
  963. if (Yii::app()->request->getPost('oper') == "edit" && (Yii::app()->request->getPost('attvalue') || Yii::app()->request->getPost('attvalue')=="0"))
  964. {
  965. $pid = explode('_',Yii::app()->request->getPost('participant_id'));
  966. $iAttributeId = Yii::app()->request->getPost('attid');
  967. $aData = array('participant_id' => $pid[0], 'attribute_id' => $iAttributeId, 'value' => Yii::app()->request->getPost('attvalue'));
  968. ParticipantAttributeNames::model()->editParticipantAttributeValue($aData);
  969. }
  970. }
  971. function attributeMapCSV()
  972. {
  973. $config['upload_path'] = './tmp/upload';
  974. $config['allowed_types'] = 'text/x-csv|text/plain|application/octet-stream|csv';
  975. $config['max_size'] = '1000';
  976. $clang = $this->getController()->lang;
  977. $sFilePath = preg_replace('/\\\/', '/', Yii::app()->getConfig('tempdir')) . "/" . $_FILES['the_file']['name'];
  978. $bMoveFileResult = @move_uploaded_file($_FILES['the_file']['tmp_name'], $sFilePath);
  979. $errorinupload = '';
  980. $filterblankemails = Yii::app()->request->getPost('filterbea');
  981. if (!$bMoveFileResult)
  982. {
  983. $templateData['error_msg'] = sprintf($clang->gT("An error occurred uploading your file. This may be caused by incorrect permissions in your %s folder."), Yii::app()->getConfig('tempdir'));
  984. $errorinupload = array('error' => $this->upload->display_errors());
  985. Yii::app()->session['summary'] = array('errorinupload' => $errorinupload);
  986. $this->_renderWrappedTemplate('participants', array('participantsPanel', 'uploadSummary'));
  987. }
  988. else
  989. {
  990. $aData = array('upload_data' => $_FILES['the_file']);
  991. $sFileName = $_FILES['the_file']['name'];
  992. $regularfields = array('firstname', 'participant_id', 'lastname', 'email', 'language', 'blacklisted', 'owner_uid');
  993. $csvread = fopen($sFilePath, 'r');
  994. $seperator = Yii::app()->request->getPost('seperatorused');
  995. $firstline = fgetcsv($csvread, 1000, ',');
  996. $selectedcsvfields = array();
  997. foreach ($firstline as $key => $value)
  998. {
  999. $testvalue = preg_replace('/[^(\x20-\x7F)]*/','', $value); //Remove invalid characters from string
  1000. if (!in_array(strtolower($testvalue), $regularfields))
  1001. {
  1002. array_push($selectedcsvfields, $value);
  1003. }
  1004. $fieldlist[]=$value;
  1005. }
  1006. $linecount = count(file($sFilePath));
  1007. $attributes = ParticipantAttributeNames::model()->model()->getAttributes();
  1008. $aData = array(
  1009. 'attributes' => $attributes,
  1010. 'firstline' => $selectedcsvfields,
  1011. 'fullfilepath' => $sFilePath,
  1012. 'linecount' => $linecount - 1,
  1013. 'filterbea' => $filterblankemails,
  1014. 'participant_id_exists' => in_array('participant_id', $fieldlist)
  1015. );
  1016. $this->_renderWrappedTemplate('participants', 'attributeMapCSV', $aData);
  1017. }
  1018. }
  1019. /*
  1020. * Uploads the file to the server and process it for valid enteries and import them into database
  1021. */
  1022. function uploadCSV()
  1023. {
  1024. unset(Yii::app()->session['summary']);
  1025. $characterset = Yii::app()->request->getPost('characterset');
  1026. $seperator = Yii::app()->request->getPost('seperatorused');
  1027. $newarray = Yii::app()->request->getPost('newarray');
  1028. $mappedarray = Yii::app()->request->getPost('mappedarray');
  1029. $sFilePath = Yii::app()->request->getPost('fullfilepath');
  1030. $filterblankemails = Yii::app()->request->getPost('filterbea');
  1031. $overwrite = Yii::app()->request->getPost('overwrite');
  1032. $errorinupload = "";
  1033. $recordcount = 0;
  1034. $mandatory = 0;
  1035. $mincriteria = 0;
  1036. $imported = 0;
  1037. $dupcount = 0;
  1038. $overwritten = 0;
  1039. $dupreason="nameemail"; //Default duplicate comparison method
  1040. $duplicatelist = array();
  1041. $invalidemaillist = array();
  1042. $invalidformatlist = array();
  1043. $invalidattribute = array();
  1044. $invalidparticipantid = array();
  1045. /* Adjust system settings to read file with MAC line endings */
  1046. @ini_set('auto_detect_line_endings', true);
  1047. /* Open the uploaded file into an array */
  1048. $tokenlistarray = file($sFilePath);
  1049. // open it and trim the endings
  1050. $separator = Yii::app()->request->getPost('seperatorused');
  1051. $uploadcharset = Yii::app()->request->getPost('characterset');
  1052. /* The $newarray contains a list of fields that will be used
  1053. to create new attributes */
  1054. if (!empty($newarray))
  1055. {
  1056. /* Create a new entry in the lime_participant_attribute_names table,
  1057. and it's associated lime_participant_attribute_names_lang table
  1058. for each NEW attribute being created in this import process */
  1059. foreach ($newarray as $key => $value)
  1060. {
  1061. $aData = array('attribute_type' => 'TB', 'attribute_name' => $value, 'visible' => 'FALSE');
  1062. $insertid = ParticipantAttributeNames::model()->storeAttributeCSV($aData);
  1063. /* Keep a record of the attribute_id for this new attribute
  1064. in the $mappedarray string. For example, if the new attribute
  1065. has attribute_id of 35 and is called "gender",
  1066. $mappedarray['35']='gender' */
  1067. $mappedarray[$insertid] = $value;
  1068. }
  1069. }
  1070. if (!isset($uploadcharset))
  1071. {
  1072. $uploadcharset = 'auto';
  1073. }
  1074. foreach ($tokenlistarray as $buffer) //Iterate through the CSV file line by line
  1075. {
  1076. $buffer = @mb_convert_encoding($buffer, "UTF-8", $uploadcharset);
  1077. $firstname = "";
  1078. $lastname = "";
  1079. $email = "";
  1080. $language = "";
  1081. if ($recordcount == 0) {
  1082. //The first time we iterate through the file we look at the very
  1083. //first line, which contains field names, not values to import
  1084. // Pick apart the first line
  1085. $buffer = removeBOM($buffer);
  1086. $attrid = ParticipantAttributeNames::model()->getAttributeID();
  1087. $allowedfieldnames = array('participant_id', 'firstname', 'lastname', 'email', 'language', 'blacklisted');
  1088. if (!empty($mappedarray))
  1089. {
  1090. foreach ($mappedarray as $key => $value)
  1091. {
  1092. array_push($allowedfieldnames, $value);
  1093. }
  1094. }
  1095. //For Attributes
  1096. switch ($separator)
  1097. {
  1098. case 'comma':
  1099. $separator = ',';
  1100. break;
  1101. case 'semicolon':
  1102. $separator = ';';
  1103. break;
  1104. default:
  1105. $comma = substr_count($buffer, ',');
  1106. $semicolon = substr_count($buffer, ';');
  1107. if ($semicolon > $comma)
  1108. $separator = ';'; else
  1109. $separator = ',';
  1110. }
  1111. $firstline = convertCSVRowToArray($buffer, $separator, '"');
  1112. $firstline = array_map('trim', $firstline);
  1113. $ignoredcolumns = array();
  1114. //now check the first line for invalid fields
  1115. foreach ($firstline as $index => $fieldname)
  1116. {
  1117. $firstline[$index] = preg_replace("/(.*) <[^,]*>$/", "$1", $fieldname);
  1118. $fieldname = $firstline[$index];
  1119. if (!in_array(strtolower($fieldname), $allowedfieldnames))
  1120. {
  1121. $ignoredcolumns[] = $fieldname;
  1122. } else {
  1123. $firstline[$index] = strtolower($fieldname);
  1124. }
  1125. }
  1126. if ((!in_array('firstname', $firstline) && !in_array('lastname', $firstline) && !in_array('email', $firstline)) && !in_array('participant_id', $firstline))
  1127. {
  1128. $recordcount = count($tokenlistarray);
  1129. break;
  1130. }
  1131. } else {
  1132. // After looking at the first line, we now import the actual values
  1133. $line = convertCSVRowToArray($buffer, $separator, '"');
  1134. if (count($firstline) != count($line))
  1135. {
  1136. $invalidformatlist[] = $recordcount;
  1137. continue;
  1138. }
  1139. $writearray = array_combine($firstline, $line);
  1140. //kick out ignored columns
  1141. foreach ($ignoredcolumns as $column)
  1142. {
  1143. unset($writearray[$column]);
  1144. }
  1145. $invalidemail = false;
  1146. $dupfound = false;
  1147. $thisduplicate = 0;
  1148. $filterduplicatefields = array('firstname', 'lastname', 'email');
  1149. //Check for duplicate participants
  1150. $aData = array(
  1151. 'firstname' => $writearray['firstname'],
  1152. 'lastname' => $writearray['lastname'],
  1153. 'email' => $writearray['email'],
  1154. 'owner_uid' => Yii::app()->session['loginID']
  1155. );
  1156. //HACK - converting into SQL instead of doing an array search
  1157. if(in_array('participant_id', $firstline)) {
  1158. $dupreason="participant_id";
  1159. $aData = "participant_id = ".Yii::app()->db->quoteValue($writearray['participant_id']);
  1160. } else {
  1161. $dupreason="nameemail";
  1162. $aData = "firstname = ".Yii::app()->db->quoteValue($writearray['firstname'])." AND lastname = ".Yii::app()->db->quoteValue($writearray['lastname'])." AND email = ".Yii::app()->db->quoteValue($writearray['email'])." AND owner_uid = '".Yii::app()->session['loginID']."'";
  1163. }
  1164. //End of HACK
  1165. $aData = Participants::model()->checkforDuplicate($aData, "participant_id");
  1166. if ($aData !== false) {
  1167. $thisduplicate = 1;
  1168. $dupcount++;
  1169. if($overwrite=="true")
  1170. {
  1171. //Although this person already exists, we want to update the mapped attribute values
  1172. if (!empty($mappedarray)) {
  1173. //The mapped array contains the attributes we are
  1174. //saving in this import
  1175. foreach ($mappedarray as $attid => $attname) {
  1176. if (!empty($attname)) {
  1177. $bData = array('participant_id' => $aData,
  1178. 'attribute_id' => $attid,
  1179. 'value' => $writearray[$attname]);
  1180. Participant_attribute::model()->updateParticipantAttributeValue($bData);
  1181. } else {
  1182. //If the value is empty, don't write the value
  1183. }
  1184. }
  1185. $overwritten++;
  1186. }
  1187. }
  1188. }
  1189. if ($thisduplicate == 1) {
  1190. $dupfound = true;
  1191. $duplicatelist[] = $writearray['firstname'] . " " . $writearray['lastname'] . " (" . $writearray['email'] . ")";
  1192. }
  1193. //Checking the email address is in a valid format
  1194. $invalidemail = false;
  1195. $writearray['email'] = trim($writearray['email']);
  1196. if ($writearray['email'] != '') {
  1197. $aEmailAddresses = explode(';', $writearray['email']);
  1198. foreach ($aEmailAddresses as $sEmailaddress) {
  1199. if (!validateEmailAddress($sEmailaddress)) {
  1200. $invalidemail = true;
  1201. $invalidemaillist[] = $line[0] . " " . $line[1] . " (" . $line[2] . ")";
  1202. }
  1203. }
  1204. }
  1205. if (!$dupfound && !$invalidemail) {
  1206. //If it isn't a duplicate value or an invalid email, process the entry as a new participant
  1207. //First, process the known fields
  1208. if (!isset($writearray['participant_id']) || $writearray['participant_id'] == "") {
  1209. $uuid = $this->gen_uuid(); //Generate a UUID for the new participant
  1210. $writearray['participant_id'] = $uuid;
  1211. }
  1212. if (isset($writearray['emailstatus']) && trim($writearray['emailstatus'] == '')) {
  1213. unset($writearray['emailstatus']);
  1214. }
  1215. if (!isset($writearray['language']) || $writearray['language'] == "") {
  1216. $writearray['language'] = "en";
  1217. }
  1218. if (!isset($writearray['blacklisted']) || $writearray['blacklisted'] == "") {
  1219. $writearray['blacklisted'] = "N";
  1220. }
  1221. $writearray['owner_uid'] = Yii::app()->session['loginID'];
  1222. if (isset($writearray['validfrom']) && trim($writearray['validfrom'] == '')) {
  1223. unset($writearray['validfrom']);
  1224. }
  1225. if (isset($writearray['validuntil']) && trim($writearray['validuntil'] == '')) {
  1226. unset($writearray['validuntil']);
  1227. }
  1228. $dontimport=false;
  1229. if (($filterblankemails == "accept" && $writearray['email'] == "") || $writearray['firstname'] == "" || $writearray['lastname'] == "") {
  1230. //The mandatory fields of email, firstname and lastname
  1231. //must be filled, but one or more are empty
  1232. $mandatory++;
  1233. $dontimport=true;
  1234. } else {
  1235. foreach ($writearray as $key => $value) {
  1236. if (!empty($mappedarray)) {
  1237. //The mapped array contains the attributes we are
  1238. //saving in this import
  1239. if (in_array($key, $allowedfieldnames)) {
  1240. foreach ($mappedarray as $attid => $attname) {
  1241. if ($attname == $key) {
  1242. if (!empty($value)) {
  1243. $aData = array('participant_id' => $writearray['participant_id'],
  1244. 'attribute_id' => $attid,
  1245. 'value' => $value);
  1246. ParticipantAttributeNames::model()->saveParticipantAttributeValue($aData);
  1247. } else {
  1248. //If the value is empty, don't write the value
  1249. }
  1250. }
  1251. }
  1252. }
  1253. }
  1254. }
  1255. }
  1256. //If any of the mandatory fields are blank, then don't import this user
  1257. if(!$dontimport)
  1258. {
  1259. Participants::model()->insertParticipantCSV($writearray);
  1260. $imported++;
  1261. }
  1262. }
  1263. $mincriteria++;
  1264. }
  1265. $recordcount++;
  1266. }
  1267. unlink($sFilePath);
  1268. $clang = $this->getController()->lang;
  1269. $aData = array();
  1270. $aData['clang'] = $clang;
  1271. $aData['recordcount'] = $recordcount - 1;
  1272. $aData['duplicatelist'] = $duplicatelist;
  1273. $aData['mincriteria'] = $mincriteria;
  1274. $aData['imported'] = $imported;
  1275. $aData['errorinupload'] = $errorinupload;
  1276. $aData['invalidemaillist'] = $invalidemaillist;
  1277. $aData['mandatory'] = $mandatory;
  1278. $aData['invalidattribute'] = $invalidattribute;
  1279. $aData['mandatory'] = $mandatory;
  1280. $aData['invalidparticipantid'] = $invalidparticipantid;
  1281. $aData['overwritten'] = $overwritten;
  1282. $aData['dupreason'] = $dupreason;
  1283. $this->getController()->render('/admin/participants/uploadSummary_view', $aData);
  1284. }
  1285. function summaryview()
  1286. {
  1287. $this->_renderWrappedTemplate('participants', array('participantsPanel', 'uploadSummary'));
  1288. }
  1289. /*
  1290. * Responsible for setting the session variables for attribute map page redirect
  1291. */
  1292. function setSession()
  1293. {
  1294. unset(Yii::app()->session['participantid']);
  1295. Yii::app()->session['participantid'] = Yii::app()->request->getPost('participantid');
  1296. }
  1297. /*
  1298. * Generation of unique id
  1299. */
  1300. function gen_uuid()
  1301. {
  1302. return sprintf(
  1303. '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
  1304. mt_rand(0, 0xffff),
  1305. mt_rand(0, 0xffff),
  1306. mt_rand(0, 0xffff),
  1307. mt_rand(0, 0x0fff) | 0x4000,
  1308. mt_rand(0, 0x3fff) | 0x8000,
  1309. mt_rand(0, 0xffff),
  1310. mt_rand(0, 0xffff),
  1311. mt_rand(0, 0xffff)
  1312. );
  1313. }
  1314. /*
  1315. * Stores the shared participant information in participant_shares
  1316. */
  1317. function shareParticipants()
  1318. {
  1319. $clang = $this->getController()->lang;
  1320. $iParticipantId = Yii::app()->request->getPost('participantid');
  1321. $iShareUserId = Yii::app()->request->getPost('shareuser');
  1322. $bCanEdit = Yii::app()->request->getPost('can_edit');
  1323. $i = 0;
  1324. foreach ($iParticipantId as $iId)
  1325. {
  1326. $time = time();
  1327. $aData = array('participant_id' => $iId,
  1328. 'share_uid' => $iShareUserId,
  1329. 'date_added' => date('Y-m-d H:i:s', $time),
  1330. 'can_edit' => $bCanEdit);
  1331. ParticipantShares::model()->storeParticipantShare($aData);
  1332. $i++;
  1333. }
  1334. printf($clang->gT("%s participants have been shared"), $i);
  1335. }
  1336. /*
  1337. * Responsible for copying the participant from tokens to the central Database
  1338. *
  1339. * TODO: Most of the work for this function is in the participants model file
  1340. * but it doesn't belong there.
  1341. */
  1342. function addToCentral()
  1343. {
  1344. $newarr = Yii::app()->request->getPost('newarr');
  1345. $mapped = Yii::app()->request->getPost('mapped');
  1346. $overwriteauto = Yii::app()->request->getPost('overwriteauto');
  1347. $overwriteman = Yii::app()->request->getPost('overwriteman');
  1348. $createautomap = Yii::app()->request->getPost('createautomap');
  1349. $response = Participants::model()->copyToCentral(Yii::app()->request->getPost('surveyid'), $newarr, $mapped, $overwriteauto, $overwriteman);
  1350. $clang = $this->getController()->lang;
  1351. printf($clang->gT("%s participants have been copied to the central participants table"), $response['success']);
  1352. if($response['duplicate'] > 0) {
  1353. echo "\r\n";
  1354. printf($clang->gT("%s entries were not copied because they already existed"), $response['duplicate']);
  1355. }
  1356. if($response['overwriteman']=="true" || $response['overwriteauto']) {
  1357. echo "\r\n";
  1358. $clang->eT("Attribute values for existing participants have been updated from the token records");
  1359. }
  1360. }
  1361. /*
  1362. * Responsible for adding the participant to the specified survey
  1363. */
  1364. function addToToken()
  1365. {
  1366. $response = Participants::model()->copytoSurvey(Yii::app()->request
  1367. ->getPost('participantid'),
  1368. Yii::app()->request
  1369. ->getPost('surveyid'), Yii::app()
  1370. ->request->getPost('attributeid')
  1371. );
  1372. $clang = $this->getController()->lang;
  1373. printf($clang->gT("%s participants have been copied to the survey token table"), $response['success']);
  1374. if($response['duplicate']>0) {
  1375. echo "\r\n";
  1376. printf($clang->gT("%s entries were not copied because they already existed"), $response['duplicate']);
  1377. }
  1378. if($response['overwrite']=="true") {
  1379. echo "\r\n";
  1380. $clang->eT("Attribute values for existing participants have been updated from the participants records");
  1381. }
  1382. }
  1383. /*
  1384. * Responsible for adding the participant to the specified survey with attribute mapping
  1385. */
  1386. function addToTokenattmap()
  1387. {
  1388. $iParticipantId = Yii::app()->request->getPost('participant_id');
  1389. $iSurveyId = Yii::app()->request->getPost('surveyid');
  1390. $mapped = Yii::app()->request->getPost('mapped');
  1391. $newcreate = Yii::app()->request->getPost('newarr');
  1392. $overwriteauto = Yii::app()->request->getPost('overwrite');
  1393. $overwriteman = Yii::app()->request->getPost('overwriteman');
  1394. $overwritest = Yii::app()->request->getPost('overwritest');
  1395. $createautomap = Yii::app()->request->getPost('createautomap');
  1396. $clang = $this->getController()->lang;
  1397. if (empty($newcreate[0])) { $newcreate = array(); }
  1398. $response = Participants::model()->copytosurveyatt($iSurveyId, $mapped, $newcreate, $iParticipantId, $overwriteauto, $overwriteman, $overwritest, $createautomap);
  1399. printf($clang->gT("%s participants have been copied to the survey token table"), $response['success']);
  1400. if($response['duplicate']>0) {
  1401. echo "\r\n";
  1402. printf($clang->gT("%s entries were not copied because they already existed"), $response['duplicate']);
  1403. }
  1404. if($response['overwriteauto']=="true" || $response['overwriteman']=="true") {
  1405. echo "\r\n";
  1406. $clang->eT("Attribute values for existing participants have been updated from the participants records");
  1407. }
  1408. }
  1409. /*
  1410. * Responsible for attribute mapping while copying participants from cpdb to token's table
  1411. */
  1412. function attributeMap()
  1413. {
  1414. Yii::app()->loadHelper('common');
  1415. $this->getController()->_js_admin_includes(Yii::app()->getConfig('adminscripts') . "attributeMap.js");
  1416. $this->getController()->_css_admin_includes(Yii::app()->getConfig('adminstyleurl') ."attributeMap.css");
  1417. $iSurveyId = Yii::app()->request->getPost('survey_id');
  1418. $redirect = Yii::app()->request->getPost('redirect');
  1419. $count = Yii::app()->request->getPost('count');
  1420. $iParticipantId = Yii::app()->request->getPost('participant_id');
  1421. $attributes = ParticipantAttributeNames::model()->getAttributes();
  1422. $tokenattributefieldnames = getTokenFieldsAndNames($iSurveyId, TRUE);
  1423. /* $arr = Yii::app()->db
  1424. ->createCommand()
  1425. ->select('*')
  1426. ->from("{{tokens_$iSurveyId}}")
  1427. ->queryRow();
  1428. if (is_array($arr))
  1429. {
  1430. $tokenfieldnames = array_keys($arr);
  1431. $tokenattributefieldnames = array_filter($tokenfieldnames, 'filterForAttributes');
  1432. }
  1433. else
  1434. {
  1435. $tokenattributefieldnames = array();
  1436. } */
  1437. $selectedattribute = array(); //List of existing attribute fields that are not mapped
  1438. $selectedcentralattribute = array(); //List of attributes that haven't already been mapped
  1439. $alreadymappedattid = array(); //List of fields already mapped to this tokens table
  1440. $alreadymappedattname = array();
  1441. $i = 0;
  1442. $j = 0;
  1443. foreach ($tokenattributefieldnames as $key => $value)
  1444. {
  1445. if (is_numeric($key[10])) //Assumes that if the 11th character is a number, it must be a token-table created attribute
  1446. {
  1447. $selectedattribute[$key] = $value['description'];
  1448. $i++;
  1449. }
  1450. else
  1451. {
  1452. array_push($alreadymappedattid, substr($key, 15));
  1453. }
  1454. }
  1455. foreach ($attributes as $row)
  1456. {
  1457. if (!in_array($row['attribute_id'], $alreadymappedattid))
  1458. {
  1459. $selectedcentralattribute[$row['attribute_id']] = $row['attribute_name'];
  1460. }
  1461. else
  1462. {
  1463. array_push($alreadymappedattname, $row['attribute_name']);
  1464. }
  1465. }
  1466. $aData = array(
  1467. 'selectedcentralattribute' => $selectedcentralattribute,
  1468. 'selectedtokenattribute' => $selectedattribute,
  1469. 'alreadymappedattributename' => $alreadymappedattname,
  1470. 'survey_id' => $iSurveyId,
  1471. 'redirect' => $redirect,
  1472. 'participant_id' => $iParticipantId,
  1473. 'count' => $count
  1474. );
  1475. $this->_renderWrappedTemplate('participants', 'attributeMap', $aData);
  1476. }
  1477. /*
  1478. * This function is responsible for attribute mapping while copying participants from cpdb to token's table
  1479. */
  1480. function attributeMapToken()
  1481. {
  1482. Yii::app()->loadHelper('common');
  1483. $this->getController()->_js_admin_includes(Yii::app()->getConfig('adminscripts') . "attributeMapToken.js");
  1484. $this->getController()->_css_admin_includes(Yii::app()->getConfig('adminstyleurl') ."attributeMapToken.css");
  1485. $iSurveyId = Yii::app()->request->getQuery('sid');
  1486. $attributes = ParticipantAttributeNames::model()->getAttributes();
  1487. $tokenattributefieldnames = getTokenFieldsAndNames($iSurveyId, TRUE);
  1488. $selectedattribute = array();
  1489. $selectedcentralattribute = array();
  1490. $alreadymappedattid = array();
  1491. $alreadymappedattdisplay = array();
  1492. $alreadymappedattnames = array();
  1493. $i = 0;
  1494. $j = 0;
  1495. foreach ($tokenattributefieldnames as $key => $value)
  1496. {
  1497. if (is_numeric($key[10]))
  1498. {
  1499. $selectedattribute[$value['description']] = $key;
  1500. }
  1501. else
  1502. {
  1503. $attributeid=substr($key,15);
  1504. $continue=false;
  1505. foreach($attributes as $attribute) {
  1506. if($attribute['attribute_id']==$attributeid) {
  1507. $continue=true;
  1508. }
  1509. }
  1510. if($continue) {
  1511. array_push($alreadymappedattid, $attributeid);
  1512. array_push($alreadymappedattdisplay, $key);
  1513. $alreadymappedattnames[$key]=$value['description'];
  1514. } else {
  1515. $selectedattribute[$value['description']]=$key;
  1516. }
  1517. }
  1518. }
  1519. foreach ($attributes as $row)
  1520. {
  1521. if (!in_array($row['attribute_id'], $alreadymappedattid))
  1522. {
  1523. $selectedcentralattribute[$row['attribute_id']] = $row['attribute_name'];
  1524. }
  1525. }
  1526. $aData = array(
  1527. 'attribute' => $selectedcentralattribute,
  1528. 'tokenattribute' => $selectedattribute,
  1529. 'alreadymappedattributename' => $alreadymappedattdisplay,
  1530. 'alreadymappedattdescription' => $alreadymappedattnames
  1531. );
  1532. $this->_renderWrappedTemplate('participants', 'attributeMapToken', $aData);
  1533. }
  1534. /**
  1535. * This function deletes the uploaded csv file if the import is cancelled
  1536. *
  1537. */
  1538. function mapCSVcancelled()
  1539. {
  1540. unlink(Yii::app()->getConfig('tempdir') . '/' . basename(Yii::app()->request->getPost('fullfilepath')));
  1541. }
  1542. function blacklistParticipant()
  1543. {
  1544. $this->load->model('participants_model');
  1545. $iParticipantId = $this->uri->segment(4);
  1546. $iSurveyId = $this->uri->segment(5);
  1547. $clang = $this->limesurvey_lang;
  1548. if (!is_numeric($iSurveyId))
  1549. {
  1550. $blacklist = $this->uri->segment(5);
  1551. if ($blacklist == 'Y' || $blacklist == 'N')
  1552. {
  1553. $aData = array('blacklisted' => $blacklist, 'participant_id' => $iParticipantId);
  1554. $aData = $this->participants_model->blacklistparticipantglobal($aData);
  1555. $aData['global'] = 1;
  1556. $aData['clang'] = $clang;
  1557. $aData['blacklist'] = $blacklist;
  1558. $this->load->view('admin/participants/blacklist_view', $aData);
  1559. }
  1560. else
  1561. {
  1562. $aData['is_participant'] = 0;
  1563. $aData['is_updated'] = 0;
  1564. $aData['clang'] = $clang;
  1565. $this->load->view('admin/participants/blacklist_view', $aData);
  1566. }
  1567. }
  1568. else
  1569. {
  1570. $blacklist = $this->uri->segment(6);
  1571. if ($blacklist == 'Y' || $blacklist == 'N')
  1572. {
  1573. $aData = array('blacklisted' => $blacklist);
  1574. $aData = $this->participants_model->blacklistparticipantlocal($aData, $iSurveyId, $iParticipantId);
  1575. $aData['global'] = 1;
  1576. $aData['clang'] = $clang;
  1577. $aData['local'] = 1;
  1578. $aData['blacklist'] = $blacklist;
  1579. $this->load->view('admin/participants/blacklist_view', $aData);
  1580. }
  1581. else
  1582. {
  1583. $aData['is_participant'] = 0;
  1584. $aData['is_updated'] = 0;
  1585. $aData['clang'] = $clang;
  1586. $this->load->view('admin/participants/blacklist_view', $aData);
  1587. }
  1588. }
  1589. }
  1590. }
  1591. ?>