Пример #1
0
 /**
  * Returns static instance
  * @return \Gems_Log
  */
 public static function getLogger()
 {
     if (empty(self::$_instance)) {
         self::$_instance = new \Gems_Log();
     }
     return self::$_instance;
 }
 /**
  * Returns true if and only if $value meets the validation requirements
  *
  * If $value fails validation, then this method returns false, and
  * getMessages() will return an array of messages that explain why the
  * validation failed.
  *
  * @param  mixed $value
  * @return boolean
  * @throws \Zend_Valid_Exception If validation of $value is impossible
  */
 public function isValid($value)
 {
     if ($throttleSettings = $this->project->getAskThrottleSettings()) {
         // Prune the database for (very) old attempts
         $where = $this->db->quoteInto('gta_datetime < DATE_SUB(NOW(), INTERVAL ? second)', $throttleSettings['period'] * 20);
         $this->db->delete('gems__token_attempts', $where);
         // Retrieve the number of failed attempts that occurred within the specified window
         $select = $this->db->select();
         $select->from('gems__token_attempts', array(new \Zend_Db_Expr('COUNT(*) AS attempts'), new \Zend_Db_Expr('UNIX_TIMESTAMP(MAX(gta_datetime)) - UNIX_TIMESTAMP() AS last')))->where('gta_datetime > DATE_SUB(NOW(), INTERVAL ? second)', $throttleSettings['period']);
         $attemptData = $this->db->fetchRow($select);
         $remainingDelay = $attemptData['last'] + $throttleSettings['delay'];
         // \MUtil_Echo::track($throttleSettings, $attemptData, $remainingDelay);
         if ($attemptData['attempts'] > $throttleSettings['threshold'] && $remainingDelay > 0) {
             $this->logger->log("Possible token brute force attack, throttling for {$remainingDelay} seconds", \Zend_Log::ERR);
             $this->_messages = $this->translate->_('The server is currently busy, please wait a while and try again.');
             return false;
         }
     }
     // The pure token check
     if ($this->isValidToken($value)) {
         return true;
     }
     $max_length = $this->tracker->getTokenLibrary()->getLength();
     $this->db->insert('gems__token_attempts', array('gta_id_token' => substr($value, 0, $max_length), 'gta_ip_address' => $this->getRequest()->getClientIp()));
     return false;
 }
 /**
  * Action for displaying an error, CLI as well as HTTP
  */
 public function errorAction()
 {
     $errors = $this->_getParam('error_handler');
     $exception = $errors->exception;
     $info = null;
     $message = 'Application error';
     $responseCode = 200;
     switch ($errors->type) {
         case \Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
         case \Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
             // 404 error -- controller or action not found
             $responseCode = 404;
             $message = 'Page not found';
             break;
         case \Zend_Controller_Plugin_ErrorHandler::EXCEPTION_OTHER:
             if ($exception instanceof \Gems_Exception) {
                 $responseCode = $exception->getCode();
                 $message = $exception->getMessage();
                 $info = $exception->getInfo();
                 break;
             }
             // Intentional fall through
         // Intentional fall through
         default:
             $message = $exception->getMessage();
             break;
     }
     \Gems_Log::getLogger()->logError($errors->exception, $errors->request);
     if (\MUtil_Console::isConsole()) {
         $this->_helper->viewRenderer->setNoRender(true);
         echo $message . "\n\n";
         if ($info) {
             echo $info . "\n\n";
         }
         $next = $exception->getPrevious();
         while ($next) {
             echo '  ' . $next->getMessage() . "\n";
             $next = $next->getPrevious();
         }
         echo $exception->getTraceAsString();
     } else {
         if ($responseCode) {
             $this->getResponse()->setHttpResponseCode($responseCode);
         }
         $this->view->exception = $exception;
         $this->view->message = $message;
         $this->view->request = $errors->request;
         if ($info) {
             $this->view->info = $info;
         }
     }
 }
 /**
  *
  * @param array $job
  */
 public function execute($jobId = null)
 {
     $sql = $this->db->select()->from('gems__comm_jobs')->join('gems__comm_templates', 'gcj_id_message = gct_id_template')->where('gcj_active = 1')->where('gcj_id_job = ?', $jobId);
     $job = $this->db->fetchRow($sql);
     if (empty($job)) {
         throw new Exception($this->_('Mail job not found!'));
     }
     $dbLookup = $this->loader->getUtil()->getDbLookup();
     $mailLoader = $this->loader->getMailLoader();
     $sendByMail = $this->getUserEmail($job['gcj_id_user_as']);
     $filter = $dbLookup->getFilterForMailJob($job);
     $tracker = $this->loader->getTracker();
     $model = $tracker->getTokenModel();
     // Fix for #680: token with the valid from the longest in the past should be the
     // used as first token and when multiple rounds start at the same date the
     // lowest round order should be used.
     $model->setSort(array('gto_valid_from' => SORT_ASC, 'gto_round_order' => SORT_ASC));
     $multipleTokensData = $model->load($filter);
     $errors = 0;
     $mails = 0;
     $updates = 0;
     if (count($multipleTokensData)) {
         $sentMailAddresses = array();
         foreach ($multipleTokensData as $tokenData) {
             $mailer = $mailLoader->getMailer('token', $tokenData);
             /* @var $mailer \Gems_Mail_TokenMailer */
             $token = $mailer->getToken();
             $email = $token->getEmail();
             $respondentId = $token->getRespondent()->getId();
             $mail = false;
             $update = false;
             if (!empty($email)) {
                 // Set the from address to use in this job
                 switch ($job['gcj_from_method']) {
                     case 'O':
                         // Send on behalf of organization
                         $organization = $mailer->getOrganization();
                         $from = $organization->getEmail();
                         //$organization->getName() . ' <' . $organization->getEmail() . '>';
                         break;
                     case 'U':
                         // Send on behalf of fixed user
                         $from = $sendByMail;
                         break;
                     case 'F':
                         // Send on behalf of fixed email address
                         $from = $job['gcj_from_fixed'];
                         break;
                     default:
                         throw new \Gems_Exception(sprintf($this->_('Invalid option for `%s`'), $this->_('From address used')));
                 }
                 $mailer->setFrom($from);
                 $mailer->setBy($sendByMail);
                 try {
                     switch ($job['gcj_process_method']) {
                         case 'M':
                             // Each token sends an email
                             $mail = true;
                             $update = true;
                             break;
                         case 'A':
                             // Only first token mailed and marked
                             if (!isset($sentMailAddresses[$respondentId][$email])) {
                                 // When not mailed before
                                 $mail = true;
                                 $update = true;
                             }
                             break;
                         case 'O':
                             // Only first token mailed, all marked
                             if (!isset($sentMailAddresses[$respondentId][$email])) {
                                 // When not mailed before
                                 $mail = true;
                             }
                             $update = true;
                             break;
                         default:
                             throw new \Gems_Exception(sprintf($this->_('Invalid option for `%s`'), $this->_('Processing Method')));
                     }
                     if ($mail == true) {
                         $mailer->setTemplate($job['gcj_id_message']);
                         $mailer->send();
                         $mails++;
                         $sentMailAddresses[$respondentId][$email] = true;
                     }
                     if ($update == true) {
                         $mailer->updateToken();
                         $updates++;
                     }
                 } catch (\Zend_Mail_Exception $exception) {
                     $fields = $mailer->getMailFields(false);
                     $info = sprintf("Error mailing to %s respondent %s with email address %s.", $fields['organization'], $fields['full_name'], $fields['email']);
                     // Use a gems exception to pass extra information to the log
                     $gemsException = new \Gems_Exception($info, 0, $exception);
                     \Gems_Log::getLogger()->logError($gemsException);
                     $errors++;
                 }
             }
         }
     }
     $this->getBatch()->addMessage(sprintf($this->_('Sent %d e-mails with template %s, updated %d tokens.'), $mails, $job['gct_name'], $updates));
     if ($errors) {
         $this->getBatch()->addMessage(sprintf($this->_('%d error(s) occurred while creating mails for template %s. Check error log for details.'), $errors, $job['gct_name']));
     }
 }
 /**
  * Handles receiving and storing the data from a form, files are stored on actual upload process
  * this only handles storing form data and can be used for resubmission too.
  *
  * @param type $xmlFile
  * @return string ResultID or false on failure
  */
 private function processReceivedForm($answerXmlFile)
 {
     //Log what we received
     $log = \Gems_Log::getLogger();
     //$log->log(print_r($xmlFile, true), \Zend_Log::ERR);
     $xml = simplexml_load_file($answerXmlFile);
     $formId = $xml->attributes()->id;
     $formVersion = $xml->attributes()->version;
     //Lookup what form belongs to this formId and then save
     $model = $this->getModel();
     $filter = array('gof_form_id' => $formId, 'gof_form_version' => $formVersion);
     if ($formData = $model->loadFirst($filter)) {
         $this->openrosaFormID = $formData['gof_id'];
         // Safeguard for when the form definition no longer exists
         try {
             $form = new OpenRosa_Tracker_Source_OpenRosa_Form($this->formDir . $formData['gof_form_xml']);
             $answers = $form->saveAnswer($answerXmlFile);
             return $answers['orf_id'];
         } catch (\Exception $exc) {
             return false;
         }
     } else {
         return false;
     }
 }
Пример #6
0
 /**
  * Reset de ACL en bouw opnieuw op
  */
 private function _initAcl()
 {
     $this->_acl = new \MUtil_Acl();
     if (get_class(self::$_instanceOfSelf) !== 'Gems_Roles') {
         throw new \Gems_Exception_Coding("Don't use project specific roles file anymore, you can now do so by using the gems_roles tabel and setup->roles from the interface.");
     }
     // Probeer eerst uit db in te lezen met fallback als dat niet lukt
     try {
         $this->loadDbAcl();
     } catch (\Exception $e) {
         \Gems_Log::getLogger()->logError($e);
         // Reset all roles
         unset($this->_acl);
         $this->_acl = new \MUtil_Acl();
         //Voeg standaard rollen en privileges in
         $this->loadDefaultRoles();
         $this->loadDefaultPrivileges();
     }
     // Now allow 'master' all access, except for the actions that have the
     // nologin privilege (->the login action)
     if (!$this->_acl->hasRole('master')) {
         //Add role if not already present
         $this->_acl->addRole('master');
     }
     $this->_acl->allow('master');
     $this->_acl->deny('master', null, 'pr.nologin');
 }
Пример #7
0
 /**
  * Handle sending responses to the response database (if used)
  *
  * Triggered by checkTokenCompletion
  *
  * @param int $userId The id of the gems user
  */
 protected function toResponseDatabase($userId)
 {
     $db = $this->project->getResponseDatabase();
     // WHY EXPLANATION!!
     //
     // For some reason mysql prepared parameters do nothing with a \Zend_Db_Expr
     // object and that causes an error when using CURRENT_TIMESTAMP
     $current = \MUtil_Date::now()->toString(\Gems_Tracker::DB_DATETIME_FORMAT);
     $rValues = array('gdr_id_token' => $this->_tokenId, 'gdr_changed' => $current, 'gdr_changed_by' => $userId, 'gdr_created' => $current, 'gdr_created_by' => $userId);
     $responses = $this->getRawAnswers();
     unset($responses['token'], $responses['id'], $responses['lastpage'], $responses['startlanguage'], $responses['submitdate'], $responses['startdate'], $responses['datestamp']);
     // first read current responses to differentiate between insert and update
     $responseSelect = $db->select()->from('gemsdata__responses', array('gdr_answer_id', 'gdr_response'))->where('gdr_id_token = ?', $this->_tokenId);
     $currentResponses = $db->fetchPairs($responseSelect);
     if (!$currentResponses) {
         $currentResponses = array();
     }
     // \MUtil_Echo::track($currentResponses, $responses);
     // Prepare sql
     $sql = "UPDATE gemsdata__responses\n            SET `gdr_response` = ?, `gdr_changed` = ?, `gdr_changed_by` = ?\n            WHERE gdr_id_token = ? AND gdr_answer_id = ? AND gdr_answer_row = 1";
     $stmt = $db->prepare($sql);
     $inserts = array();
     foreach ($responses as $fieldName => $response) {
         $rValues['gdr_answer_id'] = $fieldName;
         if (is_array($response)) {
             $response = join('|', $response);
         }
         $rValues['gdr_response'] = $response;
         if (array_key_exists($fieldName, $currentResponses)) {
             // Already exists, do update
             // But only if value changed
             if ($currentResponses[$fieldName] != $response) {
                 try {
                     // \MUtil_Echo::track($sql, $rValues['gdr_id_token'], $fieldName, $response);
                     $stmt->execute(array($response, $rValues['gdr_changed'], $rValues['gdr_changed_by'], $rValues['gdr_id_token'], $fieldName));
                 } catch (\Zend_Db_Statement_Exception $e) {
                     error_log($e->getMessage());
                     \Gems_Log::getLogger()->logError($e);
                 }
             }
         } else {
             // We add the inserts together in the next prepared statement to improve speed
             $inserts[$fieldName] = $rValues;
         }
     }
     if (count($inserts) > 0) {
         // \MUtil_Echo::track($inserts);
         try {
             $fields = array_keys(reset($inserts));
             $fields = array_map(array($db, 'quoteIdentifier'), $fields);
             $sql = 'INSERT INTO gemsdata__responses (' . implode(', ', $fields) . ') VALUES (' . implode(', ', array_fill(1, count($fields), '?')) . ')';
             // \MUtil_Echo::track($sql);
             $stmt = $db->prepare($sql);
             foreach ($inserts as $insert) {
                 // \MUtil_Echo::track($insert);
                 $stmt->execute($insert);
             }
         } catch (\Zend_Db_Statement_Exception $e) {
             error_log($e->getMessage());
             \Gems_Log::getLogger()->logError($e);
         }
     }
 }
Пример #8
0
 /**
  * Stores the current log entry
  *
  * @param \Zend_Controller_Request_Abstract $request
  * @param array $row
  * @param boolean $force     Should we force the logentry to be inserted or should we try to skip duplicates?
  * @return boolean True when a log entry was stored
  */
 private function _storeLogEntry(\Zend_Controller_Request_Abstract $request, array $row, $force)
 {
     if (!$force) {
         if (isset($this->_sessionStore->last) && $row === $this->_sessionStore->last) {
             return false;
         }
         // Now save the variables to the session to prevent duplicates if needed
         //
         // We skip $force as they are always saved and this prevents double logging in case of
         // e.g. a show => edit => show cycle
         $this->_sessionStore->last = $row;
     }
     try {
         $this->_db->insert('gems__log_activity', $row);
         return true;
     } catch (\Exception $exc) {
         \Gems_Log::getLogger()->logError($exc, $request);
         $this->_warn();
         return false;
     }
 }
 /**
  * Initialize the logger
  *
  * @return \Gems_Log
  */
 protected function _initLogger()
 {
     $this->bootstrap('project');
     // Make sure the project object is available
     $logger = \Gems_Log::getLogger();
     $logPath = GEMS_ROOT_DIR . '/var/logs';
     try {
         $writer = new \Zend_Log_Writer_Stream($logPath . '/errors.log');
     } catch (Exception $exc) {
         try {
             // Try to solve the problem, otherwise fail heroically
             \MUtil_File::ensureDir($logPath);
             $writer = new \Zend_Log_Writer_Stream($logPath . '/errors.log');
         } catch (Exception $exc) {
             $this->bootstrap(array('locale', 'translate'));
             die(str_replace(GEMS_ROOT_DIR . '/', '', sprintf($this->translateAdapter->_('Path %s not writable') . "\n%s\n", $logPath, $exc->getMessage())));
         }
     }
     $filter = new \Zend_Log_Filter_Priority($this->project->getLogLevel());
     $writer->addFilter($filter);
     $logger->addWriter($writer);
     // OPTIONAL STARTY OF FIREBUG LOGGING.
     if ($this->_startFirebird) {
         $logger->addWriter(new \Zend_Log_Writer_Firebug());
         //We do not add the logLevel here, as the firebug window is intended for use by
         //developers only and it is only written to the active users' own screen.
     }
     \Zend_Registry::set('logger', $logger);
     return $logger;
 }
Пример #10
0
 public function saveAnswer($file, $remove = true)
 {
     if (!file_exists($file)) {
         throw new \Gems_Exception_Coding(sprintf($this->translate->_('File not found: %s'), $file));
     }
     //We read the xml file
     $xml = simplexml_load_file($file);
     if ($xml === false) {
         throw new \Gems_Exception_Coding(sprintf($this->translate->_('Could not read form definition for form %s'), $file));
     }
     $formId = (string) $xml->attributes()->id;
     if ($formId != $this->getFormID()) {
         //Can not save to this object as it is a different form!
         throw new \Gems_Exception_Coding(sprintf($this->translate->_('Response is for a different formId: %s <-> %s'), $formId, $this->getFormID()));
     }
     $model = $this->getModel();
     $answers = $this->flattenAnswers($xml);
     //Now we should parse the response, extract the options given for a (multi)select
     $output = array();
     foreach ($this->instance as $name => $element) {
         $bindName = $this->_getBindName($name);
         if (array_key_exists($bindName, $this->bind)) {
             $bindInfo = $this->bind[$bindName];
         } else {
             $bindInfo['type'] = 'string';
         }
         if (array_key_exists($bindName, $this->body) && array_key_exists('repeat', $this->body[$bindName])) {
             // CHECK NESTED
             // We found a field that should go into the nested record
             // Now process all answers
             $group = $this->body[$bindName]['repeat'];
             foreach ($answers[$group] as $idx => $element) {
                 if (!array_key_exists($group, $output)) {
                     $output[$group] = array();
                 }
                 if (!array_key_exists($idx, $output[$group])) {
                     $output[$group][$idx] = array();
                 }
                 $output[$group][$idx] = $output[$group][$idx] + $this->_processAnswer($name, $element, $bindInfo['type']);
             }
         } else {
             $output = $output + $this->_processAnswer($name, $answers, $bindInfo['type']);
         }
     }
     $output['orf_id'] = null;
     $answers = $model->save($output);
     if ($model->getChanged() && $remove) {
         $log = \Gems_Log::getLogger();
         $log->log($file . '-->' . substr($file, 0, -4) . '.bak', \Zend_Log::ERR);
         rename($file, substr($file, 0, -4) . '.bak');
     }
     // @@TODO: make hook for respondentID lookup too
     if (isset($answers['token'])) {
         // We receveid a form linked to a token, signal the 'inSource' for this token.
         $loader = GemsEscort::getInstance()->getLoader();
         $token = $loader->getTracker()->getToken($answers['token']);
         $token->getUrl($loader->getCurrentUser()->getLocale(), $loader->getCurrentUser()->getUserId());
     }
     return $answers;
 }
Пример #11
0
 /**
  * Perform automatic job mail
  */
 public function commJob()
 {
     /*
             \Zend_Mail::setDefaultTransport(new \Zend_Mail_Transport_File(array(
                 'callback' => function ($transport) {
                     // throw new \Zend_Mail_Transport_Exception('Invalid e-mail address');
                     return $transport->recipients . '_' . time() . '_' . mt_rand() . '.tmp';
                 },
                 'path'     => GEMS_ROOT_DIR . '/var/sentmails'
             )));
             // */
     $dbLookup = $this->util->getDbLookup();
     $mailLoader = $this->loader->getMailLoader();
     $tracker = $this->loader->getTracker();
     $model = $tracker->getTokenModel();
     // Fix for #680: token with the valid from the longest in the past should be the
     // used as first token and when multiple rounds start at the same date the
     // lowest round order should be used.
     $model->setSort(array('gto_valid_from' => SORT_ASC, 'gto_round_order' => SORT_ASC));
     // Check for unprocessed tokens
     $tracker->processCompletedTokens(null, $this->currentUser->getUserId());
     $sql = "SELECT *\r\n            FROM gems__comm_jobs INNER JOIN\r\n                gems__comm_templates ON gcj_id_message = gct_id_template\r\n            WHERE gcj_active = 1\r\n            ORDER BY CASE WHEN gcj_id_survey IS NULL THEN 1 ELSE 0 END,\r\n                CASE WHEN gcj_round_description IS NULL THEN 1 ELSE 0 END,\r\n                CASE WHEN gcj_id_track IS NULL THEN 1 ELSE 0 END,\r\n                CASE WHEN gcj_id_organization IS NULL THEN 1 ELSE 0 END";
     $jobs = $this->db->fetchAll($sql);
     $mailed = false;
     if ($jobs) {
         foreach ($jobs as $job) {
             $sendByMail = $this->getUserEmail($job['gcj_id_user_as']);
             $filter = $dbLookup->getFilterForMailJob($job);
             $multipleTokensData = $model->load($filter);
             if (count($multipleTokensData)) {
                 $errors = 0;
                 $mails = 0;
                 $updates = 0;
                 $sentMailAddresses = array();
                 foreach ($multipleTokensData as $tokenData) {
                     $mailer = $mailLoader->getMailer('token', $tokenData);
                     /* @var $mailer \Gems_Mail_TokenMailer */
                     $token = $mailer->getToken();
                     $email = $token->getEmail();
                     $respondentId = $token->getRespondent()->getId();
                     if (!empty($email)) {
                         if ($job['gcj_from_method'] == 'O') {
                             $organization = $mailer->getOrganization();
                             $from = $organization->getEmail();
                             //$organization->getName() . ' <' . $organization->getEmail() . '>';
                             $mailer->setFrom($from);
                         } elseif ($job['gcj_from_method'] == 'U') {
                             $from = $sendByMail;
                             $mailer->setFrom($from);
                         } elseif ($job['gcj_from_method'] == 'F') {
                             $mailer->setFrom($job['gcj_from_fixed']);
                         }
                         $mailer->setBy($sendByMail);
                         try {
                             if ($job['gcj_process_method'] == 'M') {
                                 $mailer->setTemplate($job['gcj_id_message']);
                                 $mailer->send();
                                 $mailed = true;
                                 $mails++;
                                 $updates++;
                             } elseif (!isset($sentMailAddresses[$respondentId][$email])) {
                                 $mailer->setTemplate($job['gcj_id_message']);
                                 $mailer->send();
                                 $mailed = true;
                                 $mails++;
                                 $updates++;
                                 $sentMailAddresses[$respondentId][$email] = true;
                             } elseif ($job['gcj_process_method'] == 'O') {
                                 $mailer->updateToken();
                                 $updates++;
                             }
                         } catch (\Zend_Mail_Exception $exception) {
                             $fields = $mailer->getMailFields(false);
                             $info = sprintf("Error mailing to %s respondent %s with email address %s.", $fields['organization'], $fields['full_name'], $fields['email']);
                             // Use a gems exception to pass extra information to the log
                             $gemsException = new \Gems_Exception($info, 0, $exception);
                             \Gems_Log::getLogger()->logError($gemsException);
                             $errors++;
                         }
                     }
                 }
                 $this->addMessage(sprintf($this->_('Sent %d e-mails with template %s, updated %d tokens.'), $mails, $job['gct_name'], $updates));
                 if ($errors) {
                     $this->addMessage(sprintf($this->_('%d error(s) occurred while creating mails for template %s. Check error log for details.'), $errors, $job['gct_name']));
                 }
             }
             $tokensData = null;
         }
     }
     if (!$mailed) {
         $this->addMessage($this->_('No mails sent.'));
     }
 }