From: <gem...@li...> - 2012-02-16 17:15:42
|
Revision: 498 http://gemstracker.svn.sourceforge.net/gemstracker/?rev=498&view=rev Author: matijsdejong Date: 2012-02-16 17:15:30 +0000 (Thu, 16 Feb 2012) Log Message: ----------- refreshTokenAttributesBatch works, but could yet be implemented at other levels than source level LimeSurvey token tables now have token length corrected when needed LimeSurvey 1.91 token tables now get usesleft field when it does not exists Modified Paths: -------------- trunk/library/classes/Gems/Default/SourceAction.php trunk/library/classes/Gems/Menu/MenuAbstract.php trunk/library/classes/Gems/Tracker/Source/LimeSurvey1m91Database.php trunk/library/classes/Gems/Tracker/Source/LimeSurvey1m9Database.php trunk/library/classes/Gems/Tracker/TrackerInterface.php trunk/library/classes/Gems/Tracker.php trunk/library/configs/db/patches.sql Added Paths: ----------- trunk/library/classes/Gems/Tracker/Batch/RefreshTokenAttributesBatch.php Modified: trunk/library/classes/Gems/Default/SourceAction.php =================================================================== --- trunk/library/classes/Gems/Default/SourceAction.php 2012-02-16 15:22:35 UTC (rev 497) +++ trunk/library/classes/Gems/Default/SourceAction.php 2012-02-16 17:15:30 UTC (rev 498) @@ -103,6 +103,22 @@ } /** + * Check all token attributes for a single source + */ + public function attributesAction() + { + $sourceId = $this->getSourceId(); + $where = $this->db->quoteInto('gsu_id_source = ?', $sourceId); + + $batch = $this->loader->getTracker()->refreshTokenAttributesBatch('sourceCheck' . $sourceId, $where); + + $title = sprintf($this->_('Refreshing token attributes for for %s source.'), + $this->db->fetchOne("SELECT gso_source_name FROM gems__sources WHERE gso_id_source = ?", $sourceId)); + + $this->_helper->BatchRunner($batch, $title); + } + + /** * Check all the tokens for a single source */ public function checkAction() Modified: trunk/library/classes/Gems/Menu/MenuAbstract.php =================================================================== --- trunk/library/classes/Gems/Menu/MenuAbstract.php 2012-02-16 15:22:35 UTC (rev 497) +++ trunk/library/classes/Gems/Menu/MenuAbstract.php 2012-02-16 17:15:30 UTC (rev 498) @@ -412,6 +412,7 @@ $page->addAction($this->_('Check status'), null, 'ping')->addParameters(MUtil_Model::REQUEST_ID); $page->addAction($this->_('Synchronize surveys'), 'pr.source.synchronize', 'synchronize')->addParameters(MUtil_Model::REQUEST_ID); $page->addAction($this->_('Check answers'), 'pr.source.check-answers', 'check')->addParameters(MUtil_Model::REQUEST_ID); + $page->addAction($this->_('Check attributes'), 'pr.source.check-attributes', 'attributes')->addParameters(MUtil_Model::REQUEST_ID); $page->addAction($this->_('Synchronize all surveys'), 'pr.source.synchronize-all', 'synchronize-all'); $page->addAction($this->_('Check all answers'), 'pr.source.check-answers-all', 'check-all'); Added: trunk/library/classes/Gems/Tracker/Batch/RefreshTokenAttributesBatch.php =================================================================== --- trunk/library/classes/Gems/Tracker/Batch/RefreshTokenAttributesBatch.php (rev 0) +++ trunk/library/classes/Gems/Tracker/Batch/RefreshTokenAttributesBatch.php 2012-02-16 17:15:30 UTC (rev 498) @@ -0,0 +1,133 @@ +<?php + +/** + * Copyright (c) 2011, Erasmus MC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Erasmus MC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * @package Gems + * @subpackage Tracker + * @author Matijs de Jong <mj...@ma...> + * @copyright Copyright (c) 2011 Erasmus MC + * @license New BSD License + * @version $Id$ + */ + +/** + * Refresh the attributes of all tokens + * + * @package Gems + * @subpackage Tracker + * @copyright Copyright (c) 2011 Erasmus MC + * @license New BSD License + * @since Class available since version 1.5 + */ +class Gems_Tracker_Batch_RefreshTokenAttributesBatch extends MUtil_Batch_BatchAbstract +{ + /** + * + * @var Gems_Tracker + */ + protected $tracker; + + /** + * + * @var Zend_Translate + */ + protected $translate; + + /** + * Add a token check step to the batch + * + * @param string $tokenId A token id + * @return Gems_Tracker_Batch_UpdateAttributesBatch (Continuation pattern) + */ + public function addToken($tokenId) + { + $this->addStep('updateAttributes', $tokenId); + + return $this; + } + + /** + * Add token check steps to the batch + * + * @param array $tokenIds An array of token ids + * @return Gems_Tracker_Batch_UpdateAttributesBatch (Continuation pattern) + */ + public function addTokens(array $tokenIds) + { + foreach ($tokenIds as $tokenId) { + $this->addStep('updateAttributes', $tokenId); + } + + return $this; + } + + /** + * String of messages from the batch + * + * Do not forget to reset() the batch if you're done with it after + * displaying the report. + * + * @param boolean $reset When true the batch is reset afterwards + * @return array + */ + public function getMessages($reset = false) + { + + $cAll = $this->count(); + $cTokens = $this->getCounter('changedTokens'); + + $messages = parent::getMessages($reset); + + array_unshift($messages, sprintf($this->translate->_('Checked %d token.'), $cAll)); + if ($cTokens == 0) { + $messages[] = $this->translate->_('No attributes were updated.'); + } else { + $messages[] = sprintf($this->translate->plural('%d token changed.', '%d tokens changed.', $cTokens), $cTokens); + } + + return $messages; + } + + /** + * Update the attributes of a token, if the token is + * already in the source. + * + * @param string $tokenId A token id + */ + protected function updateAttributes($tokenId) + { + $token = $this->tracker->getToken($tokenId); + + if ($token->inSource()) { + $survey = $token->getSurvey(); + if ($survey->copyTokenToSource($token, '')) { + $this->addToCounter('changedTokens'); + } + } + } +} Modified: trunk/library/classes/Gems/Tracker/Source/LimeSurvey1m91Database.php =================================================================== --- trunk/library/classes/Gems/Tracker/Source/LimeSurvey1m91Database.php 2012-02-16 15:22:35 UTC (rev 497) +++ trunk/library/classes/Gems/Tracker/Source/LimeSurvey1m91Database.php 2012-02-16 17:15:30 UTC (rev 498) @@ -1,4 +1,5 @@ <?php + /** * Copyright (c) 2011, Erasmus MC * All rights reserved. @@ -54,4 +55,38 @@ */ protected $_anonymizedField = 'anonymized'; + /** + * Returns a list of field names that should be set in a newly inserted token. + * + * Added the usesleft value. + * + * @param Gems_Tracker_Token $token + * @return array Of fieldname => value type + */ + protected function _fillAttributeMap(Gems_Tracker_Token $token) + { + $values = parent::_fillAttributeMap($token); + + // Not really an attribute, but it is the best place to set this + $values['usesleft'] = $token->isCompleted() ? 0 : 1; + + return $values; + } + + /** + * Check a token table for any changes needed by this version. + * + * @param array $tokenTable + * @return array Fieldname => change field commands + */ + protected function _checkTokenTable(array $tokenTable) + { + $missingFields = parent::_checkTokenTable($tokenTable); + + if (! isset($tokenTable['usesleft'])) { + $missingFields['usesleft'] = "ADD `usesleft` INT( 11 ) NULL DEFAULT '1' AFTER `completed`"; + } + + return $missingFields; + } } \ No newline at end of file Modified: trunk/library/classes/Gems/Tracker/Source/LimeSurvey1m9Database.php =================================================================== --- trunk/library/classes/Gems/Tracker/Source/LimeSurvey1m9Database.php 2012-02-16 15:22:35 UTC (rev 497) +++ trunk/library/classes/Gems/Tracker/Source/LimeSurvey1m9Database.php 2012-02-16 17:15:30 UTC (rev 498) @@ -48,8 +48,9 @@ { const CACHE_TOKEN_INFO = 'tokenInfo'; - const LS_DB_DATE_FORMAT = 'yyyy-MM-dd'; - const LS_DB_DATETIME_FORMAT = 'yyyy-MM-dd HH:mm:ss'; + const LS_DB_COMPLETION_FORMAT = 'yyyy-MM-dd HH:mm'; + const LS_DB_DATE_FORMAT = 'yyyy-MM-dd'; + const LS_DB_DATETIME_FORMAT = 'yyyy-MM-dd HH:mm:ss'; const QUESTIONS_TABLE = 'questions'; const SURVEY_TABLE = 'survey_'; @@ -119,9 +120,41 @@ protected $util; /** + * Check a token table for any changes needed by this version. + * + * @param array $tokenTable + * @return array Fieldname => change field commands + */ + protected function _checkTokenTable(array $tokenTable) + { + $missingFields = array(); + + $lengths = array(); + if (preg_match('/\(([^\)]+)\)/', $tokenTable['token']['Type'], $lengths)) { + $tokenLength = $lengths[1]; + } else { + $tokenLength = 0; + } + $token_library = $this->tracker->getTokenLibrary(); + if ($tokenLength < $token_library->getLength()) { + $tokenLength = $token_library->getLength(); + $missingFields['token'] = "CHANGE COLUMN `token` `token` varchar($tokenLength) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' NULL"; + } + + foreach ($this->_attributeMap as $name => $field) { + if (! isset($tokenTable[$field])) { + $missingFields[$field] = "ADD $field varchar(255) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'"; + } + } + + return $missingFields; + } + + /** * Returns a list of field names that should be set in a newly inserted token. * * @param Gems_Tracker_Token $token + * @return array Of fieldname => value type */ protected function _fillAttributeMap(Gems_Tracker_Token $token) { @@ -377,7 +410,7 @@ $messages[] = sprintf($this->translate->_('The \'%s\' survey is no longer active. The survey was removed from LimeSurvey!'), $survey->getName()); } } else { - $lsDb = $this->getSourceDatabase(); + $lsDb = $this->getSourceDatabase(); // SELECT sid, surveyls_title AS short_title, surveyls_description AS description, active, datestamp, ' . $this->_anonymizedField . ' $select = $lsDb->select(); @@ -401,7 +434,7 @@ break; default: // This is for the case that $this->_anonymizedField is empty, we show an update statement. - // The answers already in the table can only be linked to the repsonse based on the completion time + // The answers already in the table can only be linked to the response based on the completion time // this requires a manual action as token table only hold minuts while survey table holds seconds // and we might have responses with the same timestamp. $lsDb->query("UPDATE " . $this->_getSurveysTableName() . " SET `" . $this->_anonymizedField . "` = 'N' WHERE sid = ?;", $sourceSurveyId); @@ -425,34 +458,21 @@ } if ($tokenTable) { - $lengths = array(); - if (preg_match('/\(([^\)]+)\)/', $tokenTable['token']['Type'], $lengths)) { - $tokenLength = $lengths[1]; - } else { - $tokenLength = 0; - } - $token_library = $this->tracker->getTokenLibrary(); - if ($tokenLength < $token_library->getLength()) { - $surveyor_status .= 'Token field length is too short. '; - } + $missingFields = $this->_checkTokenTable($tokenTable); - $missingFields = array(); - foreach ($this->_attributeMap as $name => $field) { - if (! isset($tokenTable[$field])) { - $missingFields[$field] = "ADD $field varchar(255) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'"; - } - } if ($missingFields) { - $sql = "ALTER TABLE " . $this->_getTokenTableName($sourceSurveyId) . " " . implode(', ', $missingFields); + $sql = "ALTER TABLE " . $this->_getTokenTableName($sourceSurveyId) . " " . implode(', ', $missingFields); + $fields = implode($this->translate->_(', '), array_keys($missingFields)); + // MUtil_Echo::track($missingFields, $sql); try { $lsDb->query($sql); - $messages[] = sprintf($this->translate->_("Added attribute fields to token table for '%s'"), $surveyor_title); + $messages[] = sprintf($this->translate->_("Added to token table '%s' the field(s): %s"), $surveyor_title, $fields); } catch (Zend_Exception $e) { $surveyor_status .= 'Token attributes could not be created. '; $surveyor_status .= $e->getMessage() . ' '; $messages[] = sprintf($this->translate->_("Attribute fields not created for token table for '%s'"), $surveyor_title); - $messages[] = sprintf($this->translate->_('Required fields: %s', implode($this->translate->_(', '), array_keys($missingFields)))); + $messages[] = sprintf($this->translate->_('Required fields: %s', $fields)); $messages[] = $e->getMessage(); // Maximum reporting for this case @@ -587,7 +607,12 @@ // Get the mapped values $values = $this->_fillAttributeMap($token); - $values['completed'] = 'N'; // Apparently it is possible to have this value filled without a survey questionnaire. + // Apparently it is possible to have this value filled without a survey questionnaire. + if ($token->isCompleted()) { + $values['completed'] = $token->getCompletionTime()->toString(self::LS_DB_COMPLETION_FORMAT); + } else { + $values['completed'] = 'N'; + } $result = 0; if ($oldValues = $lsDb->fetchRow("SELECT * FROM $lsTokens WHERE token = ? LIMIT 1", $tokenId)) { @@ -974,7 +999,7 @@ $result = $token->cacheGet(self::CACHE_TOKEN_INFO); } - if ($fields !== null) $result = array_intersect_key((array) $result, array_flip ($fields)); + if ($fields !== null) $result = array_intersect_key((array) $result, array_flip($fields)); return $result; } Modified: trunk/library/classes/Gems/Tracker/TrackerInterface.php =================================================================== --- trunk/library/classes/Gems/Tracker/TrackerInterface.php 2012-02-16 15:22:35 UTC (rev 497) +++ trunk/library/classes/Gems/Tracker/TrackerInterface.php 2012-02-16 17:15:30 UTC (rev 498) @@ -301,4 +301,13 @@ * @return Gems_Tracker_Batch_ProcessTokensBatch A batch to process the changes */ public function recalculateTokensBatch($batch_id, $userId = null, $cond = null); + + /** + * Refreshes the tokens in the source + * + * @param string $batch_id A unique identifier for the current batch + * @param string $cond An optional where statement + * @return Gems_Tracker_Batch_ProcessTokensBatch A batch to process the changes + */ + public function refreshTokenAttributesBatch($batch_id, $cond = null); } Modified: trunk/library/classes/Gems/Tracker.php =================================================================== --- trunk/library/classes/Gems/Tracker.php 2012-02-16 15:22:35 UTC (rev 497) +++ trunk/library/classes/Gems/Tracker.php 2012-02-16 17:15:30 UTC (rev 498) @@ -887,6 +887,7 @@ return $batch; } + /** * Recalculates all token dates, timing and results * and outputs text messages. @@ -916,4 +917,37 @@ self::$verbose = true; return $this->processTokensBatch($batch_id, $tokenSelect, $userId); } + + /** + * Refreshes the tokens in the source + * + * @param string $batch_id A unique identifier for the current batch + * @param string $cond An optional where statement + * @return Gems_Tracker_Batch_ProcessTokensBatch A batch to process the changes + */ + public function refreshTokenAttributesBatch($batch_id, $cond = null) + { + $batch = $this->_loadClass('Batch_RefreshTokenAttributesBatch', true, array($batch_id)); + + if (! $batch->isLoaded()) { + $tokenSelect = $this->getTokenSelect(array('gto_id_token')); + $tokenSelect->andSurveys(array()) + ->forWhere('gsu_surveyor_active = 1') + ->forWhere('gto_in_source = 1'); + + if ($cond) { + // Add all connections for filtering, but select only surveys that are active in the source + $tokenSelect->andReceptionCodes(array()) + ->andRespondents(array()) + ->andRespondentOrganizations(array()) + ->andConsents(array()) + ->forWhere($cond); + } + + $batch->addTokens($this->db->fetchCol($tokenSelect->getSelect())); + } + self::$verbose = true; + + return $batch; + } } Modified: trunk/library/configs/db/patches.sql =================================================================== --- trunk/library/configs/db/patches.sql 2012-02-16 15:22:35 UTC (rev 497) +++ trunk/library/configs/db/patches.sql 2012-02-16 17:15:30 UTC (rev 498) @@ -375,3 +375,7 @@ -- PATCH: Add track completion event ALTER TABLE `gems__tracks` ADD gtr_completed_event varchar(64) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' AFTER gtr_track_class; + +-- GEMS VERSION: 45 +-- PATCH: Assign attribute sync to super role +UPDATE gems__roles SET grl_privileges = CONCAT(grl_privileges,',pr.source.check-attributes') WHERE grl_name = 'super' AND grl_privileges NOT LIKE '%pr.source.check-attributes%'; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |