/** * Handles creating or replacing the view for this survey * * @param \Gems_Tracker_Survey $viewName * @param \MUtil_Model_ModelAbstract $answerModel */ protected function replaceCreateView(\Gems_Tracker_Survey $survey, \MUtil_Model_ModelAbstract $answerModel) { $viewName = $this->getViewName($survey); $responseDb = $this->project->getResponseDatabase(); $fieldSql = ''; foreach ($answerModel->getItemsOrdered() as $name) { if (true === $answerModel->get($name, 'survey_question') && !in_array($name, array('submitdate', 'startdate', 'datestamp')) && !$answerModel->is($name, 'type', \MUtil_Model::TYPE_NOVALUE)) { // Only real answers $fieldSql .= ',MAX(IF(gdr_answer_id = ' . $responseDb->quote($name) . ', gdr_response, NULL)) AS ' . $responseDb->quoteIdentifier($name); } } if ($fieldSql > '') { $dbConfig = $this->db->getConfig(); $tokenTable = $this->db->quoteIdentifier($dbConfig['dbname'] . '.gems__tokens'); $createViewSql = 'CREATE OR REPLACE VIEW ' . $responseDb->quoteIdentifier($viewName) . ' AS SELECT gdr_id_token'; $createViewSql .= $fieldSql; $createViewSql .= "FROM gemsdata__responses join " . $tokenTable . " on (gto_id_token=gdr_id_token and gto_id_survey=" . $survey->getSurveyId() . ") GROUP BY gdr_id_token;"; try { $responseDb->query($createViewSql)->execute(); } catch (Exception $exc) { $responseConfig = $responseDb->getConfig(); $dbUser = $this->db->quoteIdentifier($responseConfig['username']) . '@' . $this->db->quoteIdentifier($responseConfig['host']); $statement = "GRANT SELECT ON " . $tokenTable . " TO " . $dbUser; $this->getBatch()->addMessage(sprintf($this->_("Creating view failed, try adding rights using the following statement: %s"), $statement)); } } }
/** * Returns the data to show in the index action * * Allows to easily add or modifiy the information at project level * * @return array */ protected function _getData() { $versions = $this->loader->getVersions(); $data[$this->_('Project name')] = $this->project->getName(); $data[$this->_('Project version')] = $versions->getProjectVersion(); $data[$this->_('Gems version')] = $versions->getGemsVersion(); $data[$this->_('Gems build')] = $versions->getBuild(); $data[$this->_('Gems project')] = GEMS_PROJECT_NAME; $data[$this->_('Gems web directory')] = $this->getDirInfo(GEMS_WEB_DIR); $data[$this->_('Gems root directory')] = $this->getDirInfo(GEMS_ROOT_DIR); $data[$this->_('Gems code directory')] = $this->getDirInfo(GEMS_LIBRARY_DIR); $data[$this->_('Gems variable directory')] = $this->getDirInfo(GEMS_ROOT_DIR . '/var'); $data[$this->_('MUtil version')] = \MUtil_Version::get(); $data[$this->_('Zend version')] = \Zend_Version::VERSION; $data[$this->_('Application environment')] = APPLICATION_ENV; $data[$this->_('Application baseuri')] = $this->loader->getUtil()->getCurrentURI(); $data[$this->_('Application directory')] = $this->getDirInfo(APPLICATION_PATH); $data[$this->_('Application encoding')] = APPLICATION_ENCODING; $data[$this->_('PHP version')] = phpversion(); $data[$this->_('Server Hostname')] = php_uname('n'); $data[$this->_('Server OS')] = php_uname('s'); $data[$this->_('Time on server')] = date('r'); $driveVars = array($this->_('Session directory') => \Zend_Session::getOptions('save_path'), $this->_('Temporary files directory') => realpath(getenv('TMP'))); if ($system = getenv('SystemDrive')) { $driveVars[$this->_('System Drive')] = realpath($system); } foreach ($driveVars as $name => $drive) { $data[$name] = $this->getDirInfo($drive); } return $data; }
/** * Should handle execution of the task, taking as much (optional) parameters as needed * * The parameters should be optional and failing to provide them should be handled by * the task */ public function execute($trackId = null, $exportOrganizations = false) { $versions = $this->loader->getVersions(); $data = array('gems_version' => $versions->getGemsVersion(), 'project' => $this->project->getName(), 'project_env' => APPLICATION_ENV, 'project_url' => $this->util->getCurrentURI(), 'project_version' => $versions->getProjectVersion()); // Main version data $this->exportTypeHeader('version', false); $this->exportFieldHeaders($data); $this->exportFieldData($data); $this->exportFlush(); }
/** * Should handle execution of the task, taking as much (optional) parameters as needed * * The parameters should be optional and failing to provide them should be handled by * the task */ public function execute($tableName = '', $idField = '', $passwordField = '', $methodField = '') { $passwords = $this->db->fetchPairs("SELECT {$idField}, {$passwordField} FROM {$tableName} WHERE {$passwordField} IS NOT NULL AND {$methodField} IS NULL"); if ($passwords) { $values[$methodField] = 'default'; foreach ($passwords as $key => $password) { $values[$passwordField] = $this->project->encrypt($password, $values[$methodField]); $this->db->update($tableName, $values, "{$idField} = '{$key}'"); } $this->getBatch()->addMessage(sprintf($this->_('%d passwords encrypted for table %s.'), count($passwords), $tableName)); } else { $this->getBatch()->addMessage(sprintf($this->_('No passwords found in table %s.'), $tableName)); } }
/** * Create the snippets content * * This is a stub function either override getHtmlOutput() or override render() * * @param \Zend_View_Abstract $view Just in case it is needed here * @return \MUtil_Html_HtmlInterface Something that can be rendered */ public function getHtmlOutput(\Zend_View_Abstract $view) { $delay = $this->project->getAskDelay($this->request, $this->wasAnswered); $href = $this->getTokenHref($this->showToken); $html = $this->getHtmlSequence(); $org = $this->showToken->getOrganization(); $url = $href->render($this->view); switch ($delay) { case 0: // Redirect at once header('Location: ' . $url); exit; case -1: break; default: // Let the page load after stated interval $this->view->headMeta()->appendHttpEquiv('Refresh', $delay . '; url=' . $url); } $html->h3($this->_('Token')); if ($this->token->hasRelation()) { $p = $html->pInfo(sprintf($this->_('Welcome %s,'), $this->showToken->getRelation()->getName())); $html->pInfo(sprintf($this->_('We kindly ask you to answer a survey about %s.'), $this->showToken->getRespondent()->getName())); } else { $p = $html->pInfo(sprintf($this->_('Welcome %s,'), $this->showToken->getRespondentName())); } if ($this->wasAnswered) { $html->pInfo(sprintf($this->_('Thank you for answering the "%s" survey.'), $this->token->getSurveyName())); $html->pInfo($this->_('Please click the button below to answer the next survey.')); } else { if ($welcome = $org->getWelcome()) { $html->pInfo()->raw(\MUtil_Markup::render($this->_($welcome), 'Bbcode', 'Html')); } $html->pInfo(sprintf($this->_('Please click the button below to answer the survey for token %s.'), strtoupper($this->showToken->getTokenId()))); } if ($delay > 0) { $html->pInfo(sprintf($this->plural('Wait one second to open the survey automatically or click on Cancel to stop.', 'Wait %d seconds to open the survey automatically or click on Cancel to stop.', $delay), $delay)); } $buttonDiv = $html->buttonDiv(array('class' => 'centerAlign')); $buttonDiv->actionLink($href, $this->showToken->getSurveyName()); if ($delay > 0) { $buttonDiv->actionLink(array('delay_cancelled' => 1), $this->_('Cancel')); } if ($next = $this->showToken->getTokenCountUnanswered()) { $html->pInfo(sprintf($this->plural('After this survey there is one other survey we would like you to answer.', 'After this survey there are another %d surveys we would like you to answer.', $next), $next)); } if ($sig = $org->getSignature()) { $html->pInfo()->raw(\MUtil_Markup::render($this->_($sig), 'Bbcode', 'Html')); } return $html; }
/** * Returns the data for a user object. It may be empty if the user is unknown. * * @param string $login_name * @param int $organization * @return array Of data to fill the user with. */ public function getUserData($login_name, $organization) { $orgs = null; try { $orgs = $this->db->fetchPairs("SELECT gor_id_organization, gor_name FROM gems__organizations WHERE gor_active = 1 ORDER BY gor_name"); natsort($orgs); } catch (\Zend_Db_Exception $zde) { } if (!$orgs) { // Table might not exist or be empty, so do something failsafe $orgs = array($organization => 'create db first'); } return array('user_id' => \Gems_User_UserLoader::SYSTEM_USER_ID, 'user_login' => $login_name, 'user_name' => $login_name, 'user_group' => 800, 'user_role' => $this->project->getConsoleRole(), 'user_style' => 'gems', 'user_base_org_id' => $organization, 'user_allowed_ip_ranges' => null, 'user_blockable' => false, '__allowedOrgs' => $orgs); }
/** * Returns the source choices in an array. * * @param boolean $validAfter True if it concerns _valid_after_ dates * @param boolean $firstRound List for first round * @param boolean $detailed Return extended info * @return array source_name => label */ protected function getSourceList($validAfter, $firstRound, $detailed = true) { if (!($validAfter || $this->project->isValidUntilRequired())) { $results[self::NO_TABLE] = array($this->_('Does not expire')); } if (!($validAfter && $firstRound)) { $results[self::ANSWER_TABLE] = array($this->_('Answers'), $this->_('Use an answer from a survey.')); } if ($this->_fieldsDefinition->hasAppointmentFields()) { $results[self::APPOINTMENT_TABLE] = array($this->_('Appointment'), $this->_('Use an appointment linked to this track.')); } if (!($validAfter && $firstRound)) { $results[self::TOKEN_TABLE] = array($this->_('Token'), $this->_('Use a standard token date.')); } $results[self::RESPONDENT_TRACK_TABLE] = array($this->_('Track'), $this->_('Use a track level date.')); if ($detailed) { foreach ($results as $key => $value) { if (is_array($value)) { $results[$key] = \MUtil_Html::raw(sprintf('<strong>%s</strong> %s', reset($value), next($value))); } } } else { foreach ($results as $key => $value) { if (is_array($value)) { $results[$key] = reset($value); } } } return $results; }
/** * A ModelAbstract->setOnSave() function that returns the input * date as a valid date. * * @see \MUtil_Model_ModelAbstract * * @param mixed $value The value being saved * @param boolean $isNew True when a new item is being saved * @param string $name The name of the current field * @param array $context Optional, the other values being saved * @return \Zend_Date */ public function saveValue($value, $isNew = false, $name = null, array $context = array()) { if ($value) { // \MUtil_Echo::track($value); return $this->project->encrypt($value, 'default'); } }
/** * Load extra data not from the model into the form */ protected function loadFormData() { parent::loadFormData(); $this->loadMailer(); if (isset($this->formData['gctt'])) { $multi = false; if (count($this->formData['gctt']) > 1) { $multi = true; $allLanguages = $this->util->getLocalized()->getLanguages(); } $preview = $this->getPreview($this->formData['gctt']); $this->formData['preview_html'] = $preview['html']; $this->formData['preview_text'] = $preview['text']; } if (!isset($this->formData['to'])) { $organization = $this->mailer->getOrganization(); $this->formData['to'] = $this->formData['from'] = null; if ($organization->getEmail()) { $this->formData['to'] = $this->formData['from'] = $organization->getEmail(); } elseif ($this->project->getSiteEmail()) { $this->formData['to'] = $this->formData['from'] = $this->project->getSiteEmail(); } } $this->formData['available_fields'] = $this->mailElements->displayMailFields($this->mailer->getMailFields()); }
/** * Called after the check that all required registry values * have been set correctly has run. * * @return void */ public function afterRegistry() { parent::afterRegistry(); if ($this->project instanceof \Gems_Project_ProjectSettings) { $this->useCsrf = $this->project->useCsrfCheck(); } }
/** * Send an e-mail to this user * * @param string $subjectTemplate A subject template in which {fields} are replaced * @param string $bbBodyTemplate A BB Code body template in which {fields} are replaced * @param boolean $useResetFields When true get a reset key for this user * @param string $locale Optional locale * @return mixed String or array of warnings when something went wrong */ public function sendMail($subjectTemplate, $bbBodyTemplate, $useResetFields = false, $locale = null) { if ($useResetFields && !$this->canResetPassword()) { return $this->_('Trying to send a password reset to a user that cannot be reset.'); } $mail = $this->loader->getMail(); $mail->setTemplateStyle($this->getBaseOrganization()->getStyle()); $mail->setFrom($this->getFrom()); $mail->addTo($this->getEmailAddress(), $this->getFullName(), $this->project->getEmailBounce()); if ($bcc = $this->project->getEmailBcc()) { $mail->addBcc($bcc); } if ($useResetFields) { $fields = $this->getResetPasswordMailFields($locale); } else { $fields = $this->getMailFields($locale); } // \MUtil_Echo::track($fields, $bbBodyTemplate); $fields = \MUtil_Ra::braceKeys($fields, '{', '}'); $mail->setSubject(strtr($subjectTemplate, $fields)); $mail->setBodyBBCode(strtr($bbBodyTemplate, $fields)); try { $mail->send(); return null; } catch (\Exception $e) { return array($this->_('Unable to send e-mail.'), $e->getMessage()); } }
/** * 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; }
/** * Get the db adapter for this source * * @return \Zend_Db_Adapter_Abstract */ protected function getSourceDatabase() { if (!$this->_sourceDb) { if ($dbConfig['dbname'] = $this->_sourceData['gso_ls_database']) { // Default config values from gemsDb $gemsConfig = $this->_gemsDb->getConfig(); $gemsName = $gemsConfig['dbname']; if ($dbConfig['dbname'] != $gemsName && ($adapter = $this->_sourceData['gso_ls_adapter'])) { //If upgrade has run and we have a 'charset' use it if (array_key_exists('gso_ls_charset', $this->_sourceData)) { $dbConfig['charset'] = $this->_sourceData['gso_ls_charset'] ? $this->_sourceData['gso_ls_charset'] : $gemsConfig['charset']; } $dbConfig['host'] = $this->_sourceData['gso_ls_dbhost'] ? $this->_sourceData['gso_ls_dbhost'] : $gemsConfig['host']; $dbConfig['username'] = $this->_sourceData['gso_ls_username'] ? $this->_sourceData['gso_ls_username'] : $gemsConfig['username']; $dbConfig['password'] = $this->_sourceData['gso_ls_password'] ? $this->project->decrypt($this->_sourceData['gso_ls_password'], $this->_sourceData['gso_encryption']) : $gemsConfig['password']; $this->_sourceDb = \Zend_Db::factory($adapter, $dbConfig); } } // In all other cases use $_gemsDb if (!$this->_sourceDb) { $this->_sourceDb = $this->_gemsDb; } } return $this->_sourceDb; }
/** * * @param boolean $detailed True when the current action is not in $summarizedActions. * @param string $action The current action. * @param int $defaultOrgId The default organization id or null if current organization * @return \Gems_Model_StaffModel */ public function applySettings($detailed, $action, $defaultOrgId) { $this->resetOrder(); $dbLookup = $this->util->getDbLookup(); $editing = $action == 'edit' || $action == 'create'; $translated = $this->util->getTranslated(); $user = $this->loader->getCurrentUser(); $yesNo = $translated->getYesNo(); if ($editing) { $ucfirst = new \Zend_Filter_Callback('ucfirst'); if ($this->project->isLoginShared()) { $this->set('gsf_login', 'validator', $this->createUniqueValidator('gsf_login', array('gsf_id_user'))); } else { // per organization $this->set('gsf_login', 'validator', $this->createUniqueValidator(array('gsf_login', 'gsf_id_organization'), array('gsf_id_user'))); } } else { $ucfirst = null; } $this->set('gsf_login', 'label', $this->_('Username'), 'minlength', 4, 'required', true, 'size', 15); if ($user->hasPrivilege('pr.staff.see.all') || !$editing) { // Select organization $options = $dbLookup->getOrganizations(); } else { $options = $user->getAllowedOrganizations(); } $this->set('gsf_id_organization', 'label', $this->_('Organization'), 'multiOptions', $options, 'required', true); if ($detailed) { $this->set('gsf_first_name', 'label', $this->_('First name'), 'filters[ucfirst]', $ucfirst); $this->set('gsf_surname_prefix', 'label', $this->_('Surname prefix'), 'description', $this->_('de, van der, \'t, etc...')); $this->set('gsf_last_name', 'label', $this->_('Last name'), 'required', true, 'filters[ucfirst]', $ucfirst); } else { $this->set('name', 'label', $this->_('Name')); } $this->set('gsf_gender', 'label', $this->_('Gender'), 'elementClass', 'Radio', 'multiOptions', $translated->getGenders(), 'separator', ' '); $this->set('gsf_email', 'label', $this->_('E-Mail'), 'itemDisplay', array('MUtil_Html_AElement', 'ifmail'), 'size', 30, 'validators[email]', 'SimpleEmail'); $this->set('gsf_id_primary_group', 'label', $this->_('Primary function'), 'multiOptions', $editing ? $user->getAllowedStaffGroups() : $dbLookup->getStaffGroups()); if ($detailed) { // Now try to load the current organization and find out if it has a default user definition // otherwise use the defaultStaffDefinition $organization = $this->loader->getOrganization($defaultOrgId ? $defaultOrgId : $user->getCurrentOrganizationId()); $this->set('gsf_id_organization', 'default', $organization->getId()); $this->set('gul_user_class', 'label', $this->_('User Definition'), 'default', $organization->get('gor_user_class', $this->defaultStaffDefinition), 'multiOptions', $this->loader->getUserLoader()->getAvailableStaffDefinitions()); if ($editing) { $this->set('gul_user_class', 'order', 1, 'required', true); } $this->set('gsf_iso_lang', 'label', $this->_('Language'), 'default', $this->project->locale['default'], 'multiOptions', $this->util->getLocalized()->getLanguages()); $this->set('gul_can_login', 'label', $this->_('Can login'), 'default', 1, 'description', $this->_('Users can only login when this box is checked.'), 'elementClass', 'Checkbox', 'multiOptions', $yesNo); $this->set('gsf_logout_on_survey', 'label', $this->_('Logout on survey'), 'description', $this->_('If checked the user will logoff when answering a survey.'), 'elementClass', 'Checkbox', 'multiOptions', $yesNo); $this->set('gsf_mail_watcher', 'label', $this->_('Check cron job mail'), 'description', $this->_('If checked the user will be mailed when the cron job does not run on time.'), 'elementClass', 'Checkbox', 'multiOptions', $yesNo); } $this->set('gsf_active', 'label', $this->_('Active'), 'elementClass', 'None', 'multiOptions', $yesNo); $this->setDeleteValues('gsf_active', 0, 'gul_can_login', 0); if (!$user->hasPrivilege('pr.staff.edit.all')) { $this->set('gsf_id_organization', 'elementClass', 'Exhibitor'); } return $this; }
/** * Returns the current 'base site' url, optionally with a subpath. * * @staticvar string $uri * @param string $subpath Optional string * @return string The Url + basePath plus the optional subpath */ public function getCurrentURI($subpath = '') { static $uri; if (!$uri) { $uri = \MUtil_Https::on() || $this->project->isHttpsRequired() ? 'https' : 'http'; $uri .= '://'; $uri .= isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $this->project->getConsoleUrl(); $uri .= $this->basepath->getBasePath(); } if ($subpath && $subpath[0] != '/') { $subpath = '/' . $subpath; } return $uri . $subpath; }
/** * Check for password weakness. * * @param \Gems_User_User $user * @param string $password Or null when you want a report on all the rules for this password. * @param array $codes An array of code names that identify rules that should be used only for those codes. * @return mixed String or array of strings containing warning messages */ public function reportPasswordWeakness(\Gems_User_User $user, $password, array $codes) { $this->user = $user; $this->_errors = array(); $rules = $this->project->getPasswordRules($codes); // \MUtil_Echo::track($rules); foreach ($rules as $rule => $parameter) { if (method_exists($this, $rule)) { $this->{$rule}($parameter, $password); } } // \MUtil_Echo::track($this->_errors); return $this->_errors; }
/** * Set those values needed for editing * * @return \Gems_Model_OrganizationModel */ public function applyEditSettings() { $this->applyDetailSettings(); $this->resetOrder(); // GENERAL TAB $this->set('general', 'tab', 'general', 'elementClass', 'Tab', 'value', $this->_('General')); $this->set('gor_name', 'tab', 'general', 'size', 25, 'validator', $this->createUniqueValidator('gor_name')); $this->set('gor_location', 'tab', 'general', 'size', 50, 'maxlength', 255); $this->set('gor_task', 'tab', 'general', 'size', 25); $this->set('gor_url', 'tab', 'general', 'size', 50); $this->setIfExists('gor_url_base', 'tab', 'general', 'size', 50, 'filter', 'TrailingSlash'); $this->setIfExists('gor_code', 'tab', 'general', 'size', 10); $this->set('gor_provider_id', 'tab', 'general'); $this->setIfExists('gor_active', 'tab', 'general', 'elementClass', 'Checkbox'); // EMAIL TAB $this->set('email', 'tab', 'email', 'elementClass', 'Tab', 'order', $this->getOrder('gor_active') + 1000, 'value', $this->_('Email') . ' & ' . $this->_('Token')); $this->set('gor_contact_name', 'tab', 'email', 'size', 25); $this->set('gor_contact_email', 'tab', 'email', 'size', 50, 'validator', 'SimpleEmail'); $this->set('gor_welcome', 'tab', 'email', 'elementClass', 'Textarea', 'rows', 5); $this->set('gor_signature', 'tab', 'email', 'elementClass', 'Textarea', 'rows', 5); $this->set('gor_create_account_template', 'tab', 'email'); $this->set('gor_reset_pass_template', 'tab', 'email'); // ACCESS TAB $this->set('access', 'tab', 'access', 'elementClass', 'Tab', 'order', $this->getOrder('gor_reset_pass_template') + 1000, 'value', $this->_('Access')); $this->set('gor_has_login', 'tab', 'access', 'elementClass', 'CheckBox'); $this->set('gor_add_respondents', 'tab', 'access', 'elementClass', 'CheckBox'); $this->set('gor_has_respondents', 'tab', 'access', 'elementClass', 'Exhibitor'); $this->set('gor_respondent_group', 'tab', 'access'); $this->set('gor_accessible_by', 'tab', 'access', 'elementClass', 'MultiCheckbox'); $this->set('allowed', 'tab', 'access', 'label', $this->_('Can access'), 'elementClass', 'Html'); $this->setIfExists('gor_allowed_ip_ranges', 'tab', 'access', 'size', 50, 'validator', new \Gems_Validate_IPRanges(), 'maxlength', 500); $this->setIfExists('gor_user_class', 'tab', 'access'); $definitions = $this->get('gor_user_class', 'multiOptions'); if ($definitions && count($definitions) > 1) { reset($definitions); $this->setIfExists('gor_user_class', 'default', key($definitions), 'required', true); } // OTHER TAB $this->set('other', 'tab', 'other', 'elementClass', 'Tab', 'order', $this->getOrder('gor_user_class') + 1000, 'value', $this->_('Other')); $this->setIfExists('gor_iso_lang', 'tab', 'other', 'default', $this->project->getLocaleDefault()); if ($this->_styles) { $this->setIfExists('gor_style', 'tab', 'other'); } return $this; }
/** * Add the token to every page of a pdf * * @param \Zend_Pdf $pdf * @param string $tokenId * @param int $surveyId */ protected function addTokenToDocument(\Zend_Pdf $pdf, $tokenId, $surveyId) { $token = strtoupper($tokenId); foreach (array('Title', 'Subject', 'Keywords') as $name) { if (isset($pdf->properties[$name])) { $value = rtrim($pdf->properties[$name]) . ' ' . $token; } else { $value = $token; } $pdf->properties[$name] = $value; } // Acrobat defined date format D:YYYYMMDDHHmmSSOHH'mm $pdf->properties['ModDate'] = 'D:' . str_replace(':', "'", date('YmdHisP')) . "'"; $pdf->properties['Producer'] = $this->project->getName(); // Avoid warning on Word with a (R) symbol $pdf->properties['Creator'] = $this->project->getName(); // Avoid warning on Word with a (R) symbol }
/** * Start the cron mail monitor * * @return boolean True when the job was started */ public function startCronMailMonitor() { $to = $this->_getMailTo('cronmail', 'gsf_mail_watcher = 1'); if (!$to) { return false; } $job = $this->getCronMailMonitor(); switch ($this->project->getLocaleDefault()) { case 'nl': $subject = "{name} opdracht draait al meer dan {periodHours} uur niet"; $messageBbText = "L.S.,\n\nDe [b]{name}[/b] opdracht heeft op {setTime} voor het laatst gedraait en zou voor {firstCheck} opnieuw gedraait moeten hebben.\n\nDit is waarschuwing nummer [b]{mailCount}[/b]. Controleer s.v.p. wat verkeerd gegaan is.\n\nDit is een automatische waarschuwing."; break; default: $subject = "{name} job has not run for over {periodHours} hours"; $messageBbText = "L.S.,\n\nThe [b]{name}[/b] job ran at {setTime} for the last time and should have run again before {firstCheck}.\n\nThis is notice number {mailCount}. Please check what went wrong.\n\nThis messages was send automatically."; break; } $job->setFrom($this->project->getMonitorFrom('cronmail'))->setMessage($messageBbText)->setPeriod($this->project->getMonitorPeriod('cronmail'))->setSubject($subject)->setTo($to)->start(); return true; }
/** * Add form elements when a responseDatabase is present * @param \Gems_Form $form existing form type * @param array data existing options set in the form * @return array of form elements */ protected function addResponseDatabaseForm($form, &$data, &$elements) { if (isset($data['tid']) && !empty($data['tid'])) { // If we have a responsedatabase and a track id, try something cool ;-) $responseDb = $this->project->getResponseDatabase(); if ($this->db === $responseDb) { // We are in the same database, now put that to use by allowing to filter respondents based on an answer in any survey $empty = $this->util->getTranslated()->getEmptyDropdownArray(); $allSurveys = $empty + $this->util->getDbLookup()->getSurveysForExport(); $element = new \Zend_Form_Element_Select('filter_sid'); $element->setLabel($this->_('Survey'))->setMultiOptions($allSurveys); $groupElements = array($element); if (isset($data['filter_sid']) && !empty($data['filter_sid'])) { $filterSurvey = $this->loader->getTracker()->getSurvey($data['filter_sid']); $filterQuestions = $empty + $filterSurvey->getQuestionList($this->locale->getLanguage()); $element = new \Zend_Form_Element_Select('filter_answer'); $element->setLabel($this->_('Question'))->setMultiOptions($filterQuestions); $groupElements[] = $element; } if (isset($filterSurvey) && isset($data['filter_answer']) && !empty($data['filter_answer'])) { $questionInfo = $filterSurvey->getQuestionInformation($this->locale->getLanguage()); if (array_key_exists($data['filter_answer'], $questionInfo)) { $questionInfo = $questionInfo[$data['filter_answer']]; } else { $questionInfo = array(); } if (array_key_exists('answers', $questionInfo) && is_array($questionInfo['answers']) && count($questionInfo['answers']) > 1) { $element = new \Zend_Form_Element_Multiselect('filter_value'); $element->setMultiOptions($empty + $questionInfo['answers']); $element->setAttrib('size', count($questionInfo['answers']) + 1); } else { $element = new \Zend_Form_Element_Text('filter_value'); } $element->setLabel($this->_('Value')); $groupElements[] = $element; } $form->addDisplayGroup($groupElements, 'filter', array('showLabels' => true, 'Description' => $this->_('Filter'))); array_shift($elements); } } }
/** * A specific report on the escort class */ protected function addEscortReport() { $this->html->h2('Project and escort class report'); $escortClass = get_class($this->escort); $foundNone = true; $projectName = $this->project->getName(); $oldInterfaces = array('Gems_Project_Log_LogRespondentAccessInterface', 'Gems_Project_Organization_MultiOrganizationInterface', 'Gems_Project_Organization_SingleOrganizationInterface', 'Gems_Project_Tracks_FixedTracksInterface', 'Gems_Project_Tracks_StandAloneSurveysInterface', 'Gems_Project_Tracks_TracksOnlyInterface'); foreach ($oldInterfaces as $interface) { if ($this->escort instanceof $interface) { $foundNone = false; $this->html->pInfo(sprintf('%s implements the deprecated %s interface. Remove this interface.', $escortClass, $interface)); } } $snippetsDir = APPLICATION_PATH . '\\snippets'; if (file_exists($snippetsDir)) { $foundNone = false; $this->html->pInfo(sprintf('%s still uses the deprecated %s directory for snippets. This directory is deprecated and will be removed in 1.7.2.', $projectName, $snippetsDir)); } if ($foundNone) { $this->html->pInfo(sprintf('%s and %s are up to date.', $projectName, $escortClass)); } }
/** * The place to check if the data set in the snippet is valid * to generate the snippet. * * When invalid data should result in an error, you can throw it * here but you can also perform the check in the * checkRegistryRequestsAnswers() function from the * {@see \MUtil_Registry_TargetInterface}. * * @return boolean */ public function hasHtmlOutput() { if ($this->menu) { $default = $this->project->getDefaultTrackId(); if ($default) { if ($this->respondent->getReceptionCode()->isSuccess()) { $track = $this->loader->getTracker()->getTrackEngine($default); if ($track->isUserCreatable()) { $list = $this->menu->getMenuList()->addByController('track', 'create', sprintf($this->_('Add %s track to this respondent'), $track->getTrackName()))->addParameterSources(array(\Gems_Model::TRACK_ID => $default, 'gtr_id_track' => $default, 'track_can_be_created' => 1), $this->request); $this->onEmpty = $list->getActionLink('track', 'create'); } } } if (!$this->onEmpty) { if ($this->respondent->getReceptionCode()->isSuccess()) { $list = $this->menu->getMenuList()->addByController('track', 'show-track', $this->_('Add a track to this respondent'))->addParameterSources($this->request); $this->onEmpty = $list->getActionLink('track', 'show-track'); } else { $this->onEmpty = \MUtil_Html::create('em', $this->_('No valid tokens found')); } } } return parent::hasHtmlOutput(); }
/** * Returns \Zend_Mail_Transport_Abstract when something else than the default mail protocol should be used. * * @staticvar array $mailServers * @param email address $from * @return \Zend_Mail_Transport_Abstract or null */ public function checkTransport($from) { if (!array_key_exists($from, self::$mailServers)) { $sql = 'SELECT * FROM gems__mail_servers WHERE ? LIKE gms_from ORDER BY LENGTH(gms_from) DESC LIMIT 1'; // Always set cache, se we know when not to check for this row. $serverData = $this->escort->db->fetchRow($sql, $from); // \MUtil_Echo::track($serverData); if (isset($serverData['gms_server'])) { $options = array(); if (isset($serverData['gms_user'], $serverData['gms_password'])) { $options['auth'] = 'login'; $options['username'] = $serverData['gms_user']; $options['password'] = $this->project->decrypt($serverData['gms_password'], $serverData['gms_encryption']); } if (isset($serverData['gms_port'])) { $options['port'] = $serverData['gms_port']; } if (isset($serverData['gms_ssl'])) { switch ($serverData['gms_ssl']) { case self::MAIL_SSL: $options['ssl'] = 'ssl'; break; case self::MAIL_TLS: $options['ssl'] = 'tls'; break; default: // intentional fall through } } self::$mailServers[$from] = new \Zend_Mail_Transport_Smtp($serverData['gms_server'], $options); } else { self::$mailServers[$from] = $this->getDefaultTransport(); } } return self::$mailServers[$from]; }
/** * Shows a support page */ public function supportAction() { $this->initHtml(); $this->html->h3($this->_('Support')); $this->html->pInfo()->sprintf($this->_('There is more than one way to get support for %s.'), $this->project->getName()); if ($url = $this->project->getDocumentationUrl()) { $this->html->h4($this->_('Documentation')); $this->html->pInfo()->sprintf($this->_('All available documentation is gathered at: %s'))->a($url, array('rel' => 'external', 'target' => 'documentation')); } if ($url = $this->project->getManualUrl()) { $this->html->h4($this->_('Manual')); $this->html->pInfo()->sprintf($this->_('The manual is available here: %s'))->a($url, array('rel' => 'external', 'target' => 'manual')); } if ($url = $this->project->getForumUrl()) { $this->html->h4($this->_('The forum')); $this->html->pInfo()->sprintf($this->_('You will find questions asked by other users and ask new questions at our forum site: %s'))->a($url, array('rel' => 'external', 'target' => 'forum')); } if ($url = $this->project->getSupportUrl()) { $this->html->h4($this->_('Support site')); $this->html->pInfo()->sprintf($this->_('Check our support site at %s.'))->a($url, array('rel' => 'external', 'target' => 'support')); } $this->html->h4($this->_('Or contact')); $this->html->append($this->_getOrganizationsList()); }
/** * 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); } } }
/** * Check: is this user the super user defined * in project.ini? * * @param string $login_name * @return boolean */ protected function isProjectUser($login_name) { return $this->project->getSuperAdminName() == $login_name; }
/** * Return a hashed version of the input value. * * @param mixed $value The value being saved * @param boolean $isNew True when a new item is being saved * @param string $name The name of the current field * @param array $context Optional, the other values being saved * @return string The salted hash as a 32-character hexadecimal number. */ public function saveSSN($value, $isNew = false, $name = null, array $context = array()) { if ($value) { return $this->project->getValueHash($value, $this->hashAlgorithm); } }
/** * Allow overruling of password hashing. * * @param string $password * @return string */ protected function hashNewPassword($password) { return $this->project->getValueHash($password); }
/** * Get the directory to use as the root for automatic import * * @return string */ public function getFileImportRoot() { return $this->project->getFileImportRoot(); }
/** * Creates a model for getModel(). Called only for each new $action. * * The parameters allow you to easily adapt the model to the current action. The $detailed * parameter was added, because the most common use of action is a split between detailed * and summarized actions. * * @param boolean $detailed True when the current action is not in $summarizedActions. * @param string $action The current action. * @return \MUtil_Model_ModelAbstract */ protected function createModel($detailed, $action) { $dbLookup = $this->util->getDbLookup(); $survey = null; $translated = $this->util->getTranslated(); $yesNo = $translated->getYesNo(); if ($detailed) { $surveyId = $this->_getIdParam(); if ($surveyId) { $survey = $this->loader->getTracker()->getSurvey($surveyId); } } $model = new \Gems_Model_JoinModel('surveys', 'gems__surveys', 'gus'); $model->addTable('gems__sources', array('gsu_id_source' => 'gso_id_source')); $model->setCreate(false); $model->addColumn("CASE WHEN gsu_survey_pdf IS NULL OR CHAR_LENGTH(gsu_survey_pdf) = 0 THEN 0 ELSE 1 END", 'gsu_has_pdf'); $model->addColumn(sprintf("CASE WHEN (gsu_status IS NULL OR gsu_status = '') THEN '%s' ELSE gsu_status END", $this->_('OK')), 'gsu_status_show', 'gsu_status'); $model->addColumn("CASE WHEN gsu_surveyor_active THEN '' ELSE 'deleted' END", 'row_class'); $model->resetOrder(); $model->set('gsu_survey_name', 'label', $this->_('Name'), 'elementClass', 'Exhibitor'); $model->set('gsu_survey_description', 'label', $this->_('Description'), 'elementClass', 'Exhibitor', 'formatFunction', array(__CLASS__, 'formatDescription')); $model->set('gso_source_name', 'label', $this->_('Source'), 'elementClass', 'Exhibitor'); $model->set('gsu_surveyor_active', 'label', $this->_('Active in source'), 'elementClass', 'Exhibitor', 'multiOptions', $yesNo); $model->set('gsu_status_show', 'label', $this->_('Status in source'), 'elementClass', 'Exhibitor'); $model->set('gsu_active', 'label', sprintf($this->_('Active in %s'), $this->project->getName()), 'elementClass', 'Checkbox', 'multiOptions', $yesNo); $model->set('gsu_id_primary_group', 'label', $this->_('Group'), 'description', $this->_('If empty, survey will never show up!'), 'multiOptions', $dbLookup->getGroups()); if ($detailed) { $model->addDependency('CanEditDependency', 'gsu_surveyor_active', array('gsu_active')); $model->set('gsu_active', 'validators[group]', new \MUtil_Validate_Require($model->get('gsu_active', 'label'), 'gsu_id_primary_group', $model->get('gsu_id_primary_group', 'label'))); } $model->set('gsu_insertable', 'label', $this->_('Insertable'), 'description', $this->_('Can this survey be manually inserted into a track?'), 'elementClass', 'Checkbox', 'multiOptions', $yesNo, 'onclick', 'this.form.submit()'); if ($detailed) { $model->set('gsu_valid_for_length', 'label', $this->_('Add to inserted end date'), 'description', $this->_('Add to the start date to calculate the end date when inserting.'), 'filter', 'Int'); $model->set('gsu_valid_for_unit', 'label', $this->_('Inserted end date unit'), 'description', $this->_('The unit used to calculate the end date when inserting the survey.'), 'multiOptions', $translated->getPeriodUnits()); $model->set('gsu_insert_organizations', 'label', $this->_('Insert organizations'), 'description', $this->_('The organizations where the survey may be inserted.'), 'elementClass', 'MultiCheckbox', 'multiOptions', $dbLookup->getOrganizations(), 'required', true); $ct = new \MUtil_Model_Type_ConcatenatedRow('|', $this->_(', ')); $ct->apply($model, 'gsu_insert_organizations'); // if ('edit' == $action) { // $element = new \Gems_JQuery_Form_Element_ToggleCheckboxes('toggleOrg', array('selector'=>'input[name^=gtr_organizations]')); // $element->setLabel($this->_('Toggle')); // $model->set('toggleOrg', 'elementClass', $element); // } $switches = array(0 => array('gsu_valid_for_length' => array('elementClass' => 'Hidden', 'label' => null), 'gsu_valid_for_unit' => array('elementClass' => 'Hidden', 'label' => null), 'gsu_insert_organizations' => array('elementClass' => 'Hidden', 'label' => null))); $model->addDependency(array('ValueSwitchDependency', $switches), 'gsu_insertable'); } if ($detailed) { $model->set('track_usage', 'label', $this->_('Usage'), 'elementClass', 'Exhibitor', 'noSort', true, 'no_text_search', true); $model->setOnLoad('track_usage', array($this, 'calculateTrackUsage')); $model->set('calc_duration', 'label', $this->_('Duration calculated'), 'elementClass', 'Html'); $model->setOnLoad('calc_duration', array($this, 'calculateDuration')); $model->set('gsu_duration', 'label', $this->_('Duration description'), 'description', $this->_('Text to inform the respondent, e.g. "20 seconds" or "1 minute".')); if ($survey instanceof \Gems_Tracker_Survey) { $surveyFields = $this->util->getTranslated()->getEmptyDropdownArray() + $survey->getQuestionList($this->locale->getLanguage()); $model->set('gsu_result_field', 'label', $this->_('Result field'), 'multiOptions', $surveyFields); // $model->set('gsu_agenda_result', 'label', $this->_('Agenda field')); } } else { $model->set('track_count', 'label', ' ', 'elementClass', 'Exhibitor', 'noSort', true, 'no_text_search', true); $model->setOnLoad('track_count', array($this, 'calculateTrackCount')); } $model->set('gsu_code', 'label', $this->_('Survey code'), 'description', $this->_('Optional code name to link the survey to program code.'), 'size', 10); $model->set('gsu_export_code', 'label', $this->_('Survey export code'), 'description', $this->_('A unique code indentifying this survey during track import'), 'size', 20); if ($detailed) { $events = $this->loader->getEvents(); $beforeOptions = $events->listSurveyBeforeAnsweringEvents(); if (count($beforeOptions) > 1) { $model->set('gsu_beforeanswering_event', 'label', $this->_('Before answering'), 'multiOptions', $beforeOptions, 'elementClass', 'Select'); } $completedOptions = $events->listSurveyCompletionEvents(); if (count($completedOptions) > 1) { $model->set('gsu_completed_event', 'label', $this->_('After completion'), 'multiOptions', $completedOptions, 'elementClass', 'Select'); } $displayOptions = $events->listSurveyDisplayEvents(); if (count($displayOptions) > 1) { $model->set('gsu_display_event', 'label', $this->_('Answer display'), 'multiOptions', $displayOptions, 'elementClass', 'Select'); } if ('show' !== $action || $survey->hasPdf()) { // Only the action changes from the current page // and the right to see the pdf is the same as // the right to see this page. $pdfLink = \MUtil_Html::create('a', array($this->getRequest()->getActionKey() => 'pdf'), array('class' => 'pdf', 'target' => '_blank', 'type' => 'application/pdf', 'onclick' => 'event.cancelBubble = true;')); $model->set('gsu_survey_pdf', 'label', 'Pdf', 'accept', 'application/pdf', 'destination', $this->loader->getPdf()->getUploadDir('survey_pdfs'), 'elementClass', 'File', 'extension', 'pdf', 'filename', $surveyId, 'required', false, 'itemDisplay', $pdfLink, 'validators[pdf]', new \MUtil_Validate_Pdf()); } } return $model; }