/** * Function to support the services/data_cleaner/verify web-service. * Receives a list of proposed records and applies verification rules to them, then * returns a list of verification notices. * Input is provided in the $_GET or $_POST data sent to the method as follows: * auth_token - read authorisation token * nonce - read nonce * sample - Provides details of the sample being verified. If verifying a list * of records from different places or dates then the sample entry can be ommitted or only partially * filled-in with the missing information provided on a record by record bases. A JSON formatted * object with entries for sample:survey_id, sample:date, sample:entered_sref and sample:entered_sref_system, plus * optional sample:geom (WKT format). * occurrences - JSON format, provide an array of the occurrence record to verify. Each record is an object * with occurrence:taxa_taxon_list_id, an optional stage plus any of the values for the sample which need to be * specified on a record by record bases. I.e. provide sample:date if the sample information sent * does not include a date, or a date is included but this record is for a different date. * rule_types - JSON formatted array of the rule types to run. If not provided, then all rule types are run. * E.g. ["WithoutPolygon","PeriodWithinYear"] to run just without polygon and period within year checks. * @return JSON A JSON array containing a list of notifications. Each notification is a JSON * object, with taxa_taxon_list_id and message properties. */ public function verify() { // authenticate requesting website for this service $this->authenticate('read'); if (isset($_REQUEST['sample'])) { $sample = json_decode($_REQUEST['sample'], true); } if (isset($_REQUEST['occurrences'])) { $occurrences = json_decode($_REQUEST['occurrences'], true); } if (empty($sample) || empty($occurrences)) { $this->response = 'Invalid parameters'; } else { $db = new Database(); // Create an empty template table $db->query("select * into temporary occdelta from cache_occurrences limit 0;"); try { $this->prepareOccdelta($db, $sample, $occurrences); $r = $this->runRules($db); $db->query('drop table occdelta'); $this->content_type = 'Content-Type: application/json'; $this->response = json_encode($r); } catch (Exception $e) { $db->query('drop table occdelta'); $this->response = "Query failed"; error::log_error('Error occurred calling verification rule service', $e); } } $this->send_response(); }
/** * Provides the services/data_utils/bulk_verify service. This takes a report plus params (json object) in the $_POST * data and verifies all the records returned by the report according to the filter. Pass ignore=true to allow this to * ignore any verification check rule failures (use with care!). */ public function bulk_verify() { $db = new Database(); $this->authenticate('write'); $report = $_POST['report']; $params = json_decode($_POST['params'], true); $params['sharing'] = 'verification'; $websites = $this->website_id ? array($this->website_id) : null; $this->reportEngine = new ReportEngine($websites, $this->user_id); try { // Load the report used for the verification grid with the same params $data = $this->reportEngine->requestReport("{$report}.xml", 'local', 'xml', $params); // now get a list of all the occurrence ids $ids = array(); foreach ($data['content']['records'] as $record) { if ($record['record_status'] !== 'V' && (!empty($record['pass']) || $_POST['ignore'] === 'true')) { $ids[$record['occurrence_id']] = $record['occurrence_id']; $db->insert('occurrence_comments', array('occurrence_id' => $record['occurrence_id'], 'comment' => 'This record is assumed to be correct', 'created_by_id' => $this->user_id, 'created_on' => date('Y-m-d H:i:s'), 'updated_by_id' => $this->user_id, 'updated_on' => date('Y-m-d H:i:s'))); } } $db->from('occurrences')->set(array('record_status' => 'V', 'verified_by_id' => $this->user_id, 'verified_on' => date('Y-m-d H:i:s'), 'updated_by_id' => $this->user_id, 'updated_on' => date('Y-m-d H:i:s')))->in('id', array_keys($ids))->update(); echo count($ids); $db->from('cache_occurrences')->set(array('record_status' => 'V', 'cache_updated_on' => date('Y-m-d H:i:s')))->in('id', array_keys($ids))->update(); } catch (Exception $e) { echo $e->getMessage(); error::log_error('Exception during bulk verify', $e); } }
/** * Convert PHP errors to exceptions so that they can be handled nicely. */ public static function indicia_error_handler($errno, $errstr, $errfile, $errline) { // if error reporting has been switched off completely we don't want to convert the error to an exception // should really do a binary AND between error_reporting() and $errno; which would only raise exceptions for those which are // flagged by error_reporting(), but this may impact unknown assumptions elsewhere. if (error_reporting() == 0) { return true; } try { throw new ErrorException($errstr, $errno, 0, $errfile, $errline); } catch (Exception $e) { error::log_error('Error converted to exception', $e); throw $e; } }
/** * Performs the actual task of table population. */ public static function populate_cache_table($db, $table, $last_run_date) { $queries = kohana::config("cache_builder.{$table}"); try { $count = cache_builder::get_changelist($db, $table, $queries, $last_run_date); if ($count > 0) { cache_builder::do_delete($db, $table, $queries); // preprocess some of the tags in the queries if (is_array($queries['update'])) { foreach ($queries['update'] as $key => &$sql) { $sql = str_replace('#join_needs_update#', $queries['join_needs_update'], $sql); } } else { $queries['update'] = str_replace('#join_needs_update#', $queries['join_needs_update'], $queries['update']); } cache_builder::run_statement($db, $table, $queries['update'], 'update'); // preprocess some of the tags in the queries if (is_array($queries['insert'])) { foreach ($queries['insert'] as $key => &$sql) { $sql = str_replace('#join_needs_update#', $queries['join_needs_update'] . ' and (nu.deleted=false or nu.deleted is null)', $sql); } } else { $queries['insert'] = str_replace('#join_needs_update#', $queries['join_needs_update'] . ' and (nu.deleted=false or nu.deleted is null)', $queries['insert']); } cache_builder::run_statement($db, $table, $queries['insert'], 'insert'); if (isset($queries['extra_multi_record_updates'])) { cache_builder::run_statement($db, $table, $queries['extra_multi_record_updates'], 'final update'); } if (!variable::get("populated-{$table}")) { $cacheQuery = $db->query("select count(*) from cache_{$table}")->result_array(false); if (isset($queries['count'])) { $totalQuery = $db->query($queries['count'])->result_array(false); } else { $totalQuery = $db->query("select count(*) from {$table} where deleted='f'")->result_array(false); } $percent = round($cacheQuery[0]['count'] * 100 / $totalQuery[0]['count']); echo "{$table} population in progress - {$percent}% done"; } echo '<br/>'; } $db->query("drop table needs_update_{$table}"); } catch (Exception $e) { error::log_error('Building cache', $e); echo $e->getMessage(); $db->query("drop table needs_update_{$table}"); } }
private static function populate_summary_table_for_survey($db, $last_run_date, $definition, $missing_check) { $YearTaxonLocationUser = array(); $YearTaxonLocation = array(); $YearTaxonUser = array(); $YearTaxon = array(); try { $count = summary_builder::get_changelist($db, $last_run_date, $definition, $YearTaxonLocationUser, $YearTaxonLocation, $YearTaxonUser, $YearTaxon, $missing_check); if ($count > 0) { summary_builder::do_summary($db, $definition, $YearTaxonLocationUser, $YearTaxonLocation, $YearTaxonUser, $YearTaxon); } } catch (Exception $e) { error::log_error('Building summary', $e); echo $e->getMessage(); } return; }
/** * Postprocessing for building a geom from the list of grid squares to make an SQL based check easy */ function data_cleaner_without_polygon_data_cleaner_postprocess($id, $db) { $db->query('create temporary table geoms_without_polygon (geom geometry)'); try { $r = $db->select('key, header_name')->from('verification_rule_data')->where('verification_rule_id', $id)->in('header_name', array('10km_GB', '10km_Ireland', '1km_GB', '1km_Ireland', '10km_CI', '1km_CI'))->get()->result(); $wktList = array(); foreach ($r as $gridSquare) { switch ($gridSquare->header_name) { case '10km_GB': case '1km_GB': $system = 'osgb'; break; case '10km_Ireland': case '1km_Ireland': $system = 'osie'; break; case '10km_CI': case '1km_CI': $system = 'utm30ed50'; break; default: continue; // we don't know this grid square type - should not have come back from the query } $srid = kohana::config('sref_notations.internal_srid'); try { $wktList[] = "(st_geomfromtext('" . spatial_ref::sref_to_internal_wkt($gridSquare->key, $system) . "', {$srid}))"; } catch (Exception $e) { kohana::debug('alert', 'Did not import grid square ' . $gridSquare->key . " for rule {$id}"); error::log_error('Importing without polygon rules', $e); } } if (!empty($wktList)) { $db->query("insert into geoms_without_polygon values " . implode(',', $wktList)); } $date = date("Ymd H:i:s"); $uid = $_SESSION['auth_user']->id; $db->query("delete from verification_rule_data where verification_rule_id={$id} and header_name='geom'"); $db->query('insert into verification_rule_data (verification_rule_id, header_name, data_group, key, value, value_geom, created_on, created_by_id, updated_on, updated_by_id) ' . "select {$id}, 'geom', 1, 'geom', '-', st_union(geom), '{$date}', {$uid}, '{$date}', {$uid} from geoms_without_polygon"); $db->query('drop table geoms_without_polygon'); } catch (Exception $e) { $db->query('drop table geoms_without_polygon'); throw $e; } }
/** * Controller action called when Save clicked. Perform the import when text has been pasted into the import text area. */ public function save() { $surveyId = $_POST['survey_id']; $survey = $this->db->select('website_id, title')->from('surveys')->where(array('id' => $surveyId))->get()->result_array(FALSE); $this->website_id = $survey[0]['website_id']; if (empty($_POST['import_survey_structure'])) { $this->template->title = 'Error during survey structure import'; $this->view = new View('templates/error_message'); $this->view->message = 'Please ensure you copy the details of a survey\'s attributes into the "Import survey structure" box before importing.'; $this->template->content = $this->view; } else { // start a transaction $this->db->query('BEGIN;'); try { $importData = json_decode($_POST['import_survey_structure'], true); $this->doImport($importData); $this->template->title = 'Import Complete'; $this->view = new View('survey_structure_export/import_complete'); $this->view->log = $this->log; $this->template->content = $this->view; $this->db->query('COMMIT;'); } catch (Exception $e) { $this->db->query('ROLLBACK;'); error::log_error('Exception during survey structure import', $e); $this->template->title = 'Error during survey structure import'; $this->view = new View('templates/error_message'); $this->view->message = 'An error occurred during the survey structure import and no changes have been made to the database. ' . 'Please make sure the import data is valid. More information can be found in the warehouse logs.'; $this->template->content = $this->view; } } $this->surveyTitle = $survey[0]['title']; $this->page_breadcrumbs[] = html::anchor('survey', 'Surveys'); $this->page_breadcrumbs[] = html::anchor('survey/edit/' . $surveyId, $this->surveyTitle); $this->page_breadcrumbs[] = $this->template->title; }
/** * After submitting a user record, we also need to preserve the users_websites settings if the * submission came from the warehouse form which lets the users_websites be set up from the same * submission. If this is the case, the users_websites data will be stored in $this->droppedFields * since it is not part of the main user submission. */ public function postSubmit($isInsert) { if (count($this->droppedFields) > 0) { try { $websites = ORM::factory('website')->in_allowed_websites()->find_all(); foreach ($websites as $website) { $users_websites = ORM::factory('users_website', array('user_id' => $this->id, 'website_id' => $website->id)); $save_array = array('id' => $users_websites->object_name, 'fields' => array('user_id' => array('value' => $this->id), 'website_id' => array('value' => $website->id)), 'fkFields' => array(), 'superModels' => array()); if ($users_websites->loaded || is_numeric($this->droppedFields['website_' . $website->id]['value'])) { // If this is an existing users_websites record, preserve the id. if ($users_websites->loaded) { $save_array['fields']['id'] = array('value' => $users_websites->id); } $save_array['fields']['site_role_id'] = array('value' => is_numeric($this->droppedFields['website_' . $website->id]['value']) ? $this->droppedFields['website_' . $website->id]['value'] : null); $users_websites->submission = $save_array; $users_websites->submit(); } } } catch (Exception $e) { $this->errors['general'] = '<strong>An error occurred</strong><br/>' . $e->getMessage(); error::log_error('Exception during postSubmit in user model.', $e); return false; } } return true; }
/** * Adds a new relationship to between this model and another. * * @param object related ORM model * @return boolean */ public function add(ORM $model) { if ($this->has($model)) { return TRUE; } // Get the faked column name $column = $model->object_plural; // Add the new relation to the update $this->changed_relations[$column][] = $model->primary_key_value; try { throw new exception(); } catch (Exception $e) { error::log_error('trace', $e); } if (isset($this->related[$column])) { // Force a reload of the relationships unset($this->related[$column]); } return TRUE; }
protected function createAttributeRecord($attrId, $valueId, $value, $attrDef) { // There are particular circumstances when $value is actually an array: when a attribute is multi value, // AND has yet to be created, AND is passed in as multiple ***Attr:<n>[] POST variables. This should only happen when // the attribute has yet to be created, as after this point the $valueID is filled in and that specific attribute POST variable // is no longer multivalue - only one value is stored per attribute value record, though more than one record may exist // for a given attribute. There may be others with th same <n> without a $valueID. // If attrId = fk_* (e.g. when importing data) then the value is a term whose id needs to be looked up. if (is_array($value)) { if (is_null($valueId)) { $retVal = true; foreach ($value as $singlevalue) { // recurse over array. $retVal = $this->createAttributeRecord($attrId, $valueId, $singlevalue, $attrDef) && $retVal; } return $retVal; } else { $this->errors['general'] = 'INTERNAL ERROR: multiple values passed in for ' . $this->object_name . ' ' . $valueId . ' ' . print_r($value, true); return false; } } $fk = false; if (substr($attrId, 0, 3) == 'fk_') { // value is a term that needs looking up $fk = true; $attrId = substr($attrId, 3); $value = trim($value); } // Create a attribute value, loading the existing value id if it exists, or search for the existing record // if not multivalue but no id supplied and not a new record // @todo: Optimise attribute saving by using query builder rather than ORM if ($this->existing && !is_null($valueId) && !$attrDef->multi_value == 'f') { $attrValueModel = ORM::factory($this->object_name . '_attribute_value')->where(array($this->object_name . '_attribute_id' => $attrId, $this->object_name . '_id' => $this->id))->find(); } if (!isset($attrValueModel) || !$attrValueModel->loaded) { $attrValueModel = ORM::factory($this->object_name . '_attribute_value', $valueId); } $oldValues = array_merge($attrValueModel->as_array()); $dataType = $attrDef->data_type; $vf = null; $fieldPrefix = array_key_exists('field_prefix', $this->submission) ? $this->submission['field_prefix'] . ':' : ''; // For attribute value errors, we need to report e.g smpAttr:attrId[:attrValId] as the error key name, not // the table and field name as normal. $fieldId = $fieldPrefix . $this->attrs_field_prefix . ':' . $attrId; if ($attrValueModel->id) { $fieldId .= ':' . $attrValueModel->id; } switch ($dataType) { case 'T': $vf = 'text_value'; break; case 'F': $vf = 'float_value'; break; case 'D': case 'V': // Date if (!empty($value)) { $vd = vague_date::string_to_vague_date($value); if ($vd) { $attrValueModel->date_start_value = $vd[0]; $attrValueModel->date_end_value = $vd[1]; $attrValueModel->date_type_value = $vd[2]; kohana::log('debug', "Accepted value {$value} for attribute {$fieldId}"); kohana::log('debug', " date_start_value=" . $attrValueModel->date_start_value); kohana::log('debug', " date_end_value=" . $attrValueModel->date_end_value); kohana::log('debug', " date_type_value=" . $attrValueModel->date_type_value); } else { $this->errors[$fieldId] = "Invalid value {$value} for attribute " . $attrDef->caption; kohana::log('debug', "Could not accept value {$value} into date fields for attribute {$fieldId}."); return false; } } else { $attrValueModel->date_start_value = null; $attrValueModel->date_end_value = null; $attrValueModel->date_type_value = null; } break; case 'G': $vf = 'geom_value'; break; case 'B': // Boolean $vf = 'int_value'; if (!empty($value)) { $lower = strtolower($value); if ($lower == 'false' || $lower == 'f' || $lower == 'no' || $lower == 'n' || $lower == 'off') { $value = 0; } elseif ($lower == 'true' || $lower == 't' || $lower == 'yes' || $lower == 'y' || $lower == 'on') { $value = 1; } } break; case 'L': // Lookup list $vf = 'int_value'; if (!empty($value) && $fk) { // value must be looked up $r = $this->fkLookup(array('fkTable' => 'lookup_term', 'fkSearchField' => 'term', 'fkSearchValue' => $value, 'fkSearchFilterField' => 'termlist_id', 'fkSearchFilterValue' => $attrDef->termlist_id)); if ($r) { $value = $r; } else { $this->errors[$fieldId] = "Invalid value {$value} for attribute " . $attrDef->caption; kohana::log('debug', "Could not accept value {$value} into field {$vf} for attribute {$fieldId}."); return false; } } break; default: // Integer $vf = 'int_value'; break; } if ($vf != null) { $attrValueModel->{$vf} = $value; // Test that ORM accepted the new value - it will reject if the wrong data type for example. // Use a string compare to get a proper test but with type tolerance. // A wkt geometry gets translated to a proper geom so this will look different - just check it is not empty. // A float may loose precision or trailing 0 - just check for small percentage difference if (strcmp($attrValueModel->{$vf}, $value) === 0 || $dataType === 'G' && !empty($attrValueModel->{$vf})) { kohana::log('debug', "Accepted value {$value} into field {$vf} for attribute {$fieldId}."); } else { if ($dataType === 'F' && abs($attrValueModel->{$vf} - $value) < 1.0E-5 * $attrValueModel->{$vf}) { kohana::log('alert', "Lost precision accepting value {$value} into field {$vf} for attribute {$fieldId}. Value=" . $attrValueModel->{$vf}); } else { $this->errors[$fieldId] = "Invalid value {$value} for attribute " . $attrDef->caption; kohana::log('debug', "Could not accept value {$value} into field {$vf} for attribute {$fieldId}."); return false; } } } // set metadata $exactMatches = array_intersect_assoc($oldValues, $attrValueModel->as_array()); // which fields do we have in the submission? $fieldsWithValuesInSubmission = array_intersect_key($oldValues, $attrValueModel->as_array()); // Hook to the owning entity (the sample, location, taxa_taxon_list or occurrence) $thisFk = $this->object_name . '_id'; $attrValueModel->{$thisFk} = $this->id; // and hook to the attribute $attrFk = $this->object_name . '_attribute_id'; $attrValueModel->{$attrFk} = $attrId; // we'll update metadata only if at least one of the fields have changed $wantToUpdateAttrMetadata = count($exactMatches) !== count($fieldsWithValuesInSubmission); if (!$wantToUpdateAttrMetadata) { $attrValueModel->wantToUpdateMetadata = false; } try { $v = $attrValueModel->validate(new Validation($attrValueModel->as_array()), true); } catch (Exception $e) { $v = false; $this->errors[$fieldId] = $e->getMessage(); error::log_error('Exception during validation', $e); } if (!$v) { foreach ($attrValueModel->errors as $key => $value) { // concatenate the errors if more than one per field. $this->errors[$fieldId] = array_key_exists($fieldId, $this->errors) ? $this->errors[$fieldId] . ' ' . $value : $value; } return false; } $attrValueModel->save(); if ($wantToUpdateAttrMetadata && !$this->wantToUpdateMetadata) { // we didn't update the parent's metadata. But a custom attribute value has changed, so it makes sense to update it now. $this->wantToUpdateMetadata = true; $this->set_metadata(); $this->validate(new Validation($this->as_array()), true); } $this->nestedChildModelIds[] = $attrValueModel->get_submitted_ids(); return true; }
/** * Overrides the post submit function to add in synonomies */ protected function postSubmit($isInsert) { $success = true; if ($this->submission['fields']['preferred']['value'] == 't') { try { if (isset($this->submission['metaFields']) && array_key_exists('synonyms', $this->submission['metaFields'])) { $arrSyn = $this->parseRelatedNames($this->submission['metaFields']['synonyms']['value'], 'set_synonym_sub_array'); } else { $arrSyn = array(); } $meaning_id = $this->submission['fields']['meaning_id']['value']; $existingSyn = $this->getSynonomy('meaning_id', $meaning_id); // Iterate through existing synonomies, discarding those that have // been deleted and removing existing ones from the list to add // Not sure this is correct way of doing it as it would appear that you can only have one synonym per language.... foreach ($existingSyn as $syn) { // Is the term from the db in the list of synonyms? if (array_key_exists($syn->term->language->iso, $arrSyn) && $arrSyn[$syn->term->language->iso] == $syn->term->term) { // This one already in db, so can remove from our array $arrSyn = array_diff_key($arrSyn, array($syn->term->language->iso => '')); } else { // Synonym has been deleted - remove it from the db $syn->deleted = 't'; $syn->save(); } } // $arraySyn should now be left only with those synonyms // we wish to add to the database Kohana::log("info", "Synonyms remaining to add: " . count($arrSyn)); $sm = ORM::factory('termlists_term'); foreach ($arrSyn as $lang => $term) { $sm->clear(); $syn = array(); // Wrap a new submission Kohana::log("debug", "Wrapping submission for synonym " . $term); $lang_id = ORM::factory('language')->where(array('iso' => $lang))->find()->id; // If language not found, use english as the default. Future versions may wish this to be // user definable. $lang_id = $lang_id ? $lang_id : ORM::factory('language')->where(array('iso' => 'eng'))->find()->id; // copy the original post array to pick up the common things, first the taxa_taxon_list data foreach (array('parent', 'sort_order', 'termlist_id') as $field) { if (isset($this->submission['fields'][$field])) { $syn["termlists_term:{$field}"] = is_array($this->submission['fields'][$field]) ? $this->submission['fields'][$field]['value'] : $this->submission['fields'][$field]; } } // unlike the taxa there are no term based shared data. // Now update the record with specifics for this synonym $syn['term:id'] = null; $syn['term:term'] = $term; $syn['term:language_id'] = $lang_id; $syn['termlists_term:id'] = ''; $syn['termlists_term:preferred'] = 'f'; // meaning Id cannot be copied from the submission, since for new data it is generated when saved $syn['termlists_term:meaning_id'] = $meaning_id; // Prevent a recursion by not posting synonyms with a synonym $syn['metaFields:synonyms'] = ''; $sub = $this->wrap($syn); // Don't resubmit the meaning record, again we can't rely on the order of the supermodels in the list foreach ($sub['superModels'] as $idx => $supermodel) { if ($supermodel['model']['id'] == 'meaning') { unset($sub['superModels'][$idx]); break; } } $sm->submission = $sub; if (!$sm->submit()) { $success = false; foreach ($sm->errors as $key => $value) { $this->errors[$sm->object_name . ':' . $key] = $value; } } } } catch (Exception $e) { $this->errors['general'] = '<strong>An error occurred</strong><br/>' . $e->getMessage(); error::log_error('Exception during postSubmit in termlists_term model.', $e); $success = false; } } return $success; }
$context["h1"] = ""; $context["fake_h1"] = _("User") ." ". $a_path[0]; break; case "userprofile-added-quotes": echo "lisatud tsitaadid"; die(); break; default: if (!redirect_url($_SERVER["REDIRECT_SCRIPT_URI"])) { header("HTTP/1.0 404 Not Found"); $context["h1"] = _(""); $context["fake_h1"] = _("Sorry, but the page was not found!"); error::log_error($_SERVER["HTTP_HOST"], $_SERVER["SCRIPT_URI"], $_SERVER["HTTP_REFERER"]); $to = $config_q["admin_email"]; $subject = "Katkine link " . $_SERVER["HTTP_HOST"] . "'s"; $body = "Hei, avastasin katkise lingi,\n\n". "Täpsemalt:\n". "domeen -> " . $_SERVER["HTTP_HOST"] . "\n". "katkine link -> " . $_SERVER["SCRIPT_URI"] . "\n". "http_referer -> " . $_SERVER["HTTP_REFERER"]; mail($to, $subject, $body); } /* foreach($redirects as $key=>$var) { if ($_SERVER["REDIRECT_SCRIPT_URI"] == $var["from"]) {
/** * Perform the import */ public function save() { $surveyId = $_POST['survey_id']; try { $importData = json_decode($_POST['import_survey_structure'], true); $this->doImport($importData, $_POST['survey_id']); $this->template->title = 'Import Complete'; $this->view = new View('survey_structure_export/import_complete'); $this->view->log = $this->log; $this->template->content = $this->view; } catch (Exception $e) { error::log_error('Exception during survey structure import', $e); $this->template->title = 'Error during survey structure import'; $this->view = new View('templates/error_message'); $this->view->message = 'An error occurred during the survey structure import. ' . 'Please make sure the import data is valid. More information can be found in the warehouse logs.'; $this->template->content = $this->view; } $this->page_breadcrumbs[] = html::anchor('survey', 'Surveys'); $this->page_breadcrumbs[] = html::anchor('survey/edit/' . $surveyId, $this->surveyTitle); $this->page_breadcrumbs[] = $this->template->title; }
/** * When the scheduled task is run, we need to send a notification to all users who have passed a new milestone */ function milestones_scheduled_task($last_run_date, $db) { //Get a list of distinct user/website combinations and milestones that each combination will need testing for, //these are milestones associated with each website the user is associated with, where the milestone has not been //awarded yet) $occurrenceMilestonesToCheck = get_user_website_combinations_with_unawarded_milestones_for_changed_occurrences($db); $mediaMilestonesToCheck = get_user_website_combinations_with_unawarded_milestones_for_changed_occ_media($db); //Supply a config of which websites to take into account. try { $website_ids = kohana::config('milestones.website_ids'); //Handle config file not present } catch (Exception $e) { $website_ids = array(); } //handle if config file present but option is not supplied if (empty($website_ids)) { $website_ids = array(); } //Supply 1 as the user id to give the code maximum privileges $reportEngine = new ReportEngine($website_ids, 1); $notificationCount = 0; //Cycle through all the occurrence media milestones that haven't been awarded yet and could potentially need to be awarded since last run. foreach ($mediaMilestonesToCheck as $milestoneToCheck) { $report = 'library/occurrences/filterable_occurrence_media_counts_per_user_website'; $params = json_decode($milestoneToCheck['definition'], true); $params['user_id'] = $milestoneToCheck['created_by_id']; $params['website_id'] = $milestoneToCheck['website_id']; try { //Get the report data for all new occurrences that match the filter,user,website. $data = $reportEngine->requestReport("{$report}.xml", 'local', 'xml', $params); } catch (Exception $e) { echo $e->getMessage(); error::log_error('Error occurred when creating verification notifications based on new occurrences and user\'s filters.', $e); } foreach ($data['content']['records'] as $milestoneCountData) { if ($milestoneCountData['count'] >= $milestoneToCheck['count']) { create_milestone_reached_notification($milestoneToCheck); $notificationCount++; } } } //Cycle through all the occurrence taxa/occurrence milestones that haven't been awarded yet and could potentially need to be awarded since the last run foreach ($occurrenceMilestonesToCheck as $milestoneToCheck) { if ($milestoneToCheck['milestone_entity'] == 'T') { $report = 'library/occurrences/filterable_taxa_counts_per_user_website'; } else { $report = 'library/occurrences/filterable_occurrence_counts_per_user_website'; } $params = json_decode($milestoneToCheck['definition'], true); $params['user_id'] = $milestoneToCheck['created_by_id']; $params['website_id'] = $milestoneToCheck['website_id']; try { //Get the report data for all new occurrences that match the filter/user/website $data = $reportEngine->requestReport("{$report}.xml", 'local', 'xml', $params); } catch (Exception $e) { echo $e->getMessage(); error::log_error('Error occurred when creating verification notifications based on new occurrences and user\'s filters.', $e); } foreach ($data['content']['records'] as $milestoneCountData) { if ($milestoneCountData['count'] >= $milestoneToCheck['count']) { create_milestone_reached_notification($milestoneToCheck); $notificationCount++; } } } if ($notificationCount == 0) { echo 'No new milestone notifications have been created.</br>'; } elseif ($notificationCount == 1) { echo '1 new milestone notification has been created.</br>'; } else { echo $notificationCount . ' new milestone notifications have been created.</br>'; } }
/** * AJAX callback to handle upload of a single chunk of designations spreadsheet. */ public function csv_upload() { try { $this->auto_render = false; $csvTempFile = DOCROOT . "upload/" . $_GET['uploaded_csv']; $cache = Cache::instance(); if (file_exists($csvTempFile)) { // Following helps for files from Macs ini_set('auto_detect_line_endings', 1); // create the file pointer, plus one for errors $handle = fopen($csvTempFile, "r"); $count = 0; $limit = isset($_GET['limit']) ? $_GET['limit'] : false; $filepos = isset($_GET['filepos']) ? $_GET['filepos'] : 0; $offset = isset($_GET['offset']) ? $_GET['offset'] : 0; // skip rows to allow for the last file position fseek($handle, $filepos); if ($filepos == 0) { // skip the headers fgetcsv($handle, 1000, ","); } $obj = $cache->get(basename($_GET['uploaded_csv']) . 'metadata'); $errors = array(); while (($data = fgetcsv($handle, 1000, ",")) !== FALSE && ($limit === false || $count < $limit)) { $line = implode('', $data); // skip blank lines if (empty($line)) { continue; } $count++; $filepos = ftell($handle); $ruleSettings = $this->parse_csv_row($obj['headings'], $data); $uniqueId = $data[$obj['ruleIdColIdx']]; if (!empty($uniqueId)) { try { $this->read_rule_content($ruleSettings, $uniqueId, 'csv'); } catch (Exception $e) { $errors[] = $e->getMessage(); error::log_error('Error during Data Cleaner module CSV upload.', $e); } } } } $progress = $filepos * 100 / filesize($csvTempFile); $r = array('uploaded' => $count, 'progress' => $progress, 'filepos' => $filepos, 'errors' => $errors); if (count($errors)) { kohana::log('debug', 'Upload CSV rule errors: ' . print_r($errors, true)); } else { kohana::log('debug', 'no errors'); } ob_clean(); echo json_encode($r); fclose($handle); } catch (Exception $e) { error::log_error('Error during Data Cleaner module CSV upload.', $e); throw $e; } }
/** * Override the load view behaviour to display better error information when a view * fails to load. */ public function _kohana_load_view($kohana_view_filename, $kohana_input_data) { if ($kohana_view_filename == '') { return; } // Buffering on ob_start(); // Import the view variables to local namespace extract($kohana_input_data, EXTR_SKIP); // Views are straight HTML pages with embedded PHP, so importing them // this way insures that $this can be accessed as if the user was in // the controller, which gives the easiest access to libraries in views // Put the include in a try catch block try { include $kohana_view_filename; } catch (Exception $e) { // Put the error out error::log_error('Error occurred when loading view.', $e); // Can't set a flash message here, as view has already failed to load. echo "<div class=\"ui-widget-content ui-corner-all ui-state-error page-notice\">" . "<strong>Error occurred when loading page.</strong><br/>" . $e->getMessage() . "<br/>For more information refer to the application log file.</div>"; } // Fetch the output and close the buffer return ob_get_clean(); }
function loop_through_filters_and_create_notifications($db, $filters, $params) { $report = 'library/occdelta/filterable_occdelta_count'; $notificationCounter = 0; //Supply 1 as the user id to give the code maximum privileges. Also force the main database connection //to allow access to the temporary occdelta table. $reportEngine = new ReportEngine(array($params['website_id']), 1, $db); //When creating notifications keep a track of user's we have created notifications for per verification page, this allows us to //avoid creating multiple notifications per user without having to check the database. $alreadyCreatedNotification = array(); //Go through each filter for users who don't have an outstanding VT/PT notification. foreach ($filters as $filterIdx => $filter) { $extraParams = array('sharing' => $params['sharingFilterFullName']); if ($params['notificationSourceType'] === 'VT') { //Only look for completed record_status, we don't want to pick up V for instance, as these records are already verified $extraParams = array_merge($extraParams, array('record_status' => 'C')); } else { //If we are only interested in detecting Pending records then provide a release_status P parameter, this will //override the release_status R parameter that automatically appears in the report. $extraParams = array_merge($extraParams, array('release_status' => 'P')); } $reportParams = json_decode($filter['definition'], true) + $extraParams; try { // don't run the filter unless we we haven't already created a notification for that user if (!in_array($filter['user_id'], $alreadyCreatedNotification)) { //Get the report data for all new occurrences that match the filter. //Use the filter as the params $output = $reportEngine->requestReport("{$report}.xml", 'local', 'xml', $reportParams); //If records are returned then continue if ($output['content']['records'][0]['count'] > 0) { //Save the new notification $notificationObj = ORM::factory('notification'); $notificationObj->source = $params['notificationSource']; $notificationObj->acknowledged = 'false'; $notificationObj->triggered_on = date("Ymd H:i:s"); $notificationObj->user_id = $filter['user_id']; //Use VT "Verifier Task" or PT "Pending Record Task" notification type as we are informing the verifier that they need to perform a task. $notificationObj->source_type = $params['notificationSourceType']; $notificationObj->data = json_encode(array('username' => $params['title'], 'comment' => "<a href=\"{$params['url']}\">{$params['notificationComment']}</a>", 'auto_generated' => 't')); $notificationObj->save(); $notificationCounter++; $alreadyCreatedNotification[] = $filter['user_id']; } } } catch (Exception $e) { echo $e->getMessage(); error::log_error('Error occurred when creating notifications based on new occurrences and user\'s filters.', $e); } } //Display message to show how many notifications were created. if ($notificationCounter == 0) { echo $params['noNotificationsCreatedMessage'] . '</br>'; } elseif ($notificationCounter == 1) { echo $notificationCounter . ' ' . $params['oneNotificationCreatedMessage'] . '</br>'; } else { echo $notificationCounter . ' ' . $params['multipleNotificationsCreatedMessage'] . '</br>'; } }