/** * Don't save aerodrome if another aerodrome is in same place or exists with same ICAO */ public function _on_creating() { if ($this->longitude && $this->latitude) { $qb = org_routamc_positioning_aerodrome_dba::new_query_builder(); $qb->add_constraint('longitude', '=', $this->longitude); $qb->add_constraint('latitude', '=', $this->latitude); $qb->set_limit(1); $matches = $qb->execute_unchecked(); if (count($matches) > 0) { // We don't need to save duplicate entries return false; } } if (!empty($this->icao)) { $qb = org_routamc_positioning_aerodrome_dba::new_query_builder(); $qb->add_constraint('icao', '=', $this->icao); $qb->set_limit(1); $matches = $qb->execute_unchecked(); if (count($matches) > 0) { // We don't need to save duplicate entries midcom_connection::set_error(MGD_ERR_DUPLICATE); return false; } } return true; }
public function _on_updating() { if (!$this->verify_can_reserve()) { midcom_connection::set_error(MGD_ERR_ACCESS_DENIED); return false; } return true; }
public function _on_updating() { if ($this->_check_duplicates($this->code)) { midcom_connection::set_error(MGD_ERR_OBJECT_NAME_EXISTS); return false; } return true; }
public function _on_updating() { if (!$this->validate_code($this->code)) { midcom_connection::set_error(MGD_ERR_OBJECT_NAME_EXISTS); return false; } return true; }
public function _on_creating() { $mc = self::new_collector('linkGuid', $this->linkGuid); if ($mc->count() > 0) { midcom_connection::set_error(MGD_ERR_DUPLICATE); return false; } return true; }
/** * Check if all the fields contain required information upon update * * @return boolean Indicating success */ public function _on_updating() { if (!$this->topic || !$this->article) { debug_add('Failed to update the link, either topic or article was undefined', MIDCOM_LOG_WARN); midcom_connection::set_error(MGD_ERR_ERROR); return false; } return true; }
/** * Don't save log if previous log is in same place */ public function _on_creating() { $previous = $this->get_previous(); if ($previous && round($previous->longitude, 4) == round($this->longitude, 4) && round($previous->latitude, 4) == round($this->latitude, 4) && $previous->altitude == $this->altitude && date('Y-m-d', $previous->date) == date('Y-m-d', $this->date)) { // We don't need to save duplicate entries on same day debug_add("Not saving log, previous log \"{$previous->guid}\" on same day is in same place.", MIDCOM_LOG_WARN); midcom_connection::set_error(MGD_ERR_DUPLICATE); return false; } return true; }
/** * Don't save country if another country with name exists */ public function _on_creating() { $qb = org_routamc_positioning_country_dba::new_query_builder(); $qb->add_constraint('name', '=', (string) $this->name); $qb->set_limit(1); $matches = $qb->execute_unchecked(); if (count($matches) > 0) { // We don't need to save duplicate entries midcom_connection::set_error(MGD_ERR_DUPLICATE); return false; } return true; }
/** * Don't save city if another city is in same place */ public function _on_creating() { $qb = org_routamc_positioning_city_dba::new_query_builder(); $qb->add_constraint('longitude', '=', (double) $this->longitude); $qb->add_constraint('latitude', '=', (double) $this->latitude); $qb->set_limit(1); $matches = $qb->execute_unchecked(); if (!empty($matches) && $matches[0]->longitude === $this->longitude && $matches[0]->latitude === $this->latitude) { // We don't need to save duplicate entries midcom_connection::set_error(MGD_ERR_DUPLICATE); return false; } return true; }
public function _on_creating() { if ($this->title == '' || !$this->topic) { // We must have wikiword and topic at this stage return false; } // Check for duplicates $qb = net_nemein_wiki_wikipage::new_query_builder(); $qb->add_constraint('topic', '=', $this->topic); $qb->add_constraint('title', '=', $this->title); $result = $qb->execute(); if (count($result) > 0) { midcom_connection::set_error(MGD_ERR_OBJECT_NAME_EXISTS); return false; } // Generate URL-clean name if ($this->name != 'index') { $this->name = midcom_helper_misc::generate_urlname_from_string($this->title); } return true; }
/** * Directly set a metadata option. * * The passed value will be stored using the follow transformations: * * - Storing into the approver field will automatically recognize Person Objects and simple * IDs and transform them into a GUID. * - created can only be set with articles. * - creator, editor and edited cannot be set. * * Any error will trigger midcom_error. * * @param string $key The key to set. * @param mixed $value The value to set. */ private function _set_property($key, $value) { if (is_object($value)) { $classname = get_class($value); debug_add("Can not set metadata '{$key}' property with '{$classname}' object as value", MIDCOM_LOG_WARN); return false; } // Store the RCS mode $rcs_mode = $this->__object->_use_rcs; switch ($key) { // Read-only properties case 'creator': case 'created': case 'revisor': case 'revised': case 'locker': case 'locked': case 'revision': case 'size': case 'deleted': case 'exported': case 'imported': midcom_connection::set_error(MGD_ERR_ACCESS_DENIED); return false; // Writable properties // Writable properties case 'published': case 'schedulestart': case 'scheduleend': // Cast to ISO datetime if (!is_numeric($value)) { $value = 0; } if ($value == 0) { $this->__metadata->{$key} = '0000-00-00 00:00:00'; } else { $this->__metadata->{$key} = gmstrftime('%Y-%m-%d %T', $value); } if (extension_loaded('midgard2')) { if ($this->__metadata->{$key} == '0000-00-00 00:00:00') { $this->__metadata->{$key} = null; } else { $this->__metadata->{$key} = new midgard_datetime($this->__metadata->{$key}); } } $value = true; break; case 'approver': case 'approved': // Prevent lock changes from creating new revisions $this->__object->_use_rcs = false; // Fall through // Fall through case 'authors': case 'owner': case 'hidden': case 'navnoentry': case 'score': $this->__metadata->{$key} = $value; $value = true; break; // Fall-back for non-core properties // Fall-back for non-core properties default: $value = $this->__object->set_parameter('midcom.helper.metadata', $key, $value); break; } // Return the original RCS mode $this->__object->_use_rcs = $rcs_mode; return $value; }
/** * This is an internal helper function, which may only be called statically. * * It is used by get_all_privileges in case that there is no cache hit. It will query the * database and construct all necessary objects out of it. * * @param string $guid The GUID of the object for which to query ACL data. * @param string $type SELF or CONTENT * @return Array A list of midcom_core_privilege instances. */ protected static function _query_privileges($guid, $type) { $result = array(); $mc = new midgard_collector('midcom_core_privilege_db', 'objectguid', $guid); $mc->add_constraint('value', '<>', MIDCOM_PRIVILEGE_INHERIT); if ($type == 'CONTENT') { $mc->add_constraint('assignee', '<>', 'SELF'); } else { $mc->add_constraint('assignee', '=', 'SELF'); } $mc->set_key_property('guid'); $mc->add_value_property('id'); $mc->add_value_property('privilegename'); $mc->add_value_property('assignee'); $mc->add_value_property('classname'); $mc->add_value_property('value'); midcom_connection::set_error(MGD_ERR_OK); $mc->execute(); $privileges = $mc->list_keys(); if (!$privileges) { if (midcom_connection::get_error() != MGD_ERR_OK) { debug_add("Failed to retrieve all {$type} privileges for the Object GUID {$guid}: " . midcom_connection::get_error_string(), MIDCOM_LOG_INFO); debug_print_r('Result was:', $result); if (isset($php_errormsg)) { debug_add("Error message was: {$php_errormsg}", MIDCOM_LOG_ERROR); } throw new midcom_error('Privilege collector failed to execute: ' . midcom_connection::get_error_string()); } return $result; } foreach ($privileges as $privilege_guid => $value) { $privilege = $mc->get($privilege_guid); $privilege['objectguid'] = $guid; $privilege['guid'] = $privilege_guid; $privilege_object = new midcom_core_privilege($privilege); if (!isset($privilege_object->assignee)) { // Invalid privilege, skip continue; } $privilege_object->scope = $privilege_object->_get_scope(); $return[] = $privilege_object; } return $return; }
public function get($key) { if ($this->_user_id && !midcom::get('auth')->acl->can_do_byguid('midgard:read', $key, $this->_real_class, $this->_user_id)) { midcom_connection::set_error(MGD_ERR_ACCESS_DENIED); return false; } return $this->_query->get($key); }
/** * Return next object in URL path */ public function get_object() { if ($this->argc == 0) { // No arguments left return false; } if (empty($this->url)) { $object_url = "{$this->argv[0]}/"; } else { $object_url = "{$this->url}/{$this->argv[0]}/"; } if (array_key_exists($object_url, $this->objects)) { // Remove this component from path $this->argc -= 1; array_shift($this->argv); // Set as current object $this->url = $object_url; $this->current_object = $this->objects[$object_url]; return $this->objects[$object_url]; } $qb = midcom_db_topic::new_query_builder(); $qb->add_constraint('name', '=', $this->argv[0]); $qb->add_constraint('up', '=', $this->current_object->id); if ($qb->count() == 0) { //last load returned ACCESS DENIED, no sense to dig deeper if ($qb->denied > 0) { midcom_connection::set_error(MGD_ERR_ACCESS_DENIED); return false; } // No topics matching path, check for attachments $att_qb = midcom_db_attachment::new_query_builder(); $att_qb->add_constraint('name', '=', $this->argv[0]); $att_qb->add_constraint('parentguid', '=', $this->current_object->guid); if ($att_qb->count() == 0) { // allow for handler switches to work return false; } $atts = $att_qb->execute(); // Remove this component from path $this->argc -= 1; array_shift($this->argv); // Set as current object $this->url = $object_url; $this->current_object = $atts[0]; $this->objects[$object_url] = $this->current_object; return $this->objects[$object_url]; } $topics = $qb->execute(); // Set to current topic $this->current_object = $topics[0]; $this->objects[$object_url] = $this->current_object; if ($GLOBALS['midcom_config']['symlinks'] && !empty($this->current_object->symlink)) { try { $topic = midcom_db_topic::get_cached($this->current_object->symlink); $this->current_object = $topic; } catch (midcom_error $e) { debug_add("Could not get target for symlinked topic #{$this->current_object->id}: " . $e->getMessage(), MIDCOM_LOG_ERROR); } } // TODO: Remove $this->check_style_inheritance($this->current_object); // Remove this component from path $this->argc -= 1; array_shift($this->argv); $this->url .= $this->objects[$object_url]->name . '/'; return $this->objects[$object_url]; }
public function _on_deleting() { $this->update_cache(false); if ($this->reportedHours > 0) { midcom_connection::set_error(MGD_ERR_HAS_DEPENDANTS); midcom::get('uimessages')->add(midcom::get('i18n')->get_string('org.openpsa.projects', 'org.openpsa.projects'), midcom::get('i18n')->get_string('task deletion now allowed because of hour reports', 'org.openpsa.projects'), 'warning'); return false; } return parent::_on_deleting(); }
/** * Check for potential busy conflicts to allow more graceful handling of those conditions * * Also allows normal events to "rob" resources from tentative ones. * NOTE: return false for *no* (or resolved automatically) conflicts and true for unresolvable conflicts */ function run($rob_tentative = false) { //If we're not busy it's not worth checking if (!$this->_event->busy) { debug_add('we allow overlapping, so there is no point in checking others'); return true; } //If this event is tentative always disallow robbing resources from other tentative events if ($this->_event->tentative) { $rob_tentative = false; } //We need sudo to see busys in events we normally don't see and to rob resources from tentative events midcom::get('auth')->request_sudo('org.openpsa.calendar'); //Storage for events that have been modified due the course of this method $modified_events = array(); /* * Look for duplicate events only if we have participants or resources, otherwise we incorrectly get all events at * the same timeframe as duplicates since there are no participant constraints to narrow things down */ $ret_ev = $this->_load_participants(); $ret_ev2 = $this->_load_resources(); // TODO: Shared tasks need a separate check (different member object) // Both QBs returned empty sets if (empty($ret_ev) && empty($ret_ev2)) { //No busy events found within the timeframe midcom::get('auth')->drop_sudo(); debug_add('no overlaps found'); return true; } foreach ($ret_ev as $member) { $this->_process_participant($member, $modified_events, $rob_tentative); } foreach ($ret_ev2 as $member) { $this->_process_resource($member, $modified_events, $rob_tentative); } if (is_array($this->busy_members) || is_array($this->busy_resources)) { //Unresolved conflicts (note return value is for conflicts not lack of them) midcom::get('auth')->drop_sudo(); debug_print_r('unresolvable conflicts found', $this->busy_members); midcom_connection::set_error(MGD_ERR_ERROR); return false; } foreach ($modified_events as $event) { //These events have been robbed of (some of) their resources $creator = midcom_db_person::get_cached($event->metadata->creator); if ((count($event->participants) == 0 || count($event->participants) == 1 && array_key_exists($creator->id, $event->participants)) && count($event->resources) == 0) { /* If modified event has no-one or only creator as participant and no resources then delete it (as it's unlikely the stub event is useful anymore) */ debug_add("event {$event->title} (#{$event->id}) has been robbed of all of its resources, calling delete"); //TODO: take notifications and repeats into account $event->delete(); } else { //Otherwise just commit the changes //TODO: take notifications and repeats into account debug_add("event {$event->title} (#{$event->id}) has been robbed of some its resources, calling update"); $event->update(); } } midcom::get('auth')->drop_sudo(); //No conflicts found or they could be automatically resolved $this->busy_members = false; $this->busy_resources = false; return true; }
private function _check_timerange() { //Force types $this->start = (int) $this->start; $this->end = (int) $this->end; if (!$this->start || !$this->end) { debug_add('Event must have start and end timestamps'); midcom_connection::set_error(MGD_ERR_RANGE); return false; } /* * Force start and end seconds to 1 and 0 respectively * (to avoid stupid one second overlaps) */ $this->start = mktime(date('G', $this->start), date('i', $this->start), 1, date('n', $this->start), date('j', $this->start), date('Y', $this->start)); $this->end = mktime(date('G', $this->end), date('i', $this->end), 0, date('n', $this->end), date('j', $this->end), date('Y', $this->end)); if ($this->end < $this->start) { debug_add('Event cannot end before it starts, aborting'); midcom_connection::set_error(MGD_ERR_RANGE); return false; } return true; }
/** * Import object unserialized with midgard_replicator::unserialize() * * This method does ACL checks and triggers watchers etc. * * @param object $unserialized_object object gotten from midgard_replicator::unserialize() * @param boolean $use_force set use of force for the midcom_helper_replicator_import_object() call * @return boolean indicating success/failure * @todo refactor to smaller methods * @todo Add some magic to prevent importing of replication loops (see documentation/TODO for details about the potential problem) * @todo Verify support for the special cases of privilege * @todo Make sure older version is not imported over newer one (maybe configurable override ?) */ function import(&$unserialized_object, $use_force = false) { if (is_a($unserialized_object, 'midgard_blob')) { debug_add("You must use import_blob method to import BLOBs", MIDCOM_LOG_ERROR); midcom_connection::set_error(MGD_ERR_ERROR); return false; } // We need this helper (workaround Zend bug) if (!function_exists('midcom_helper_replicator_import_object')) { midcom::get('componentloader')->load('midcom.helper.replicator'); } if (!midcom::get('dbclassloader')->is_mgdschema_object($unserialized_object)) { debug_add("Unserialized object " . get_class($unserialized_object) . " is not recognized as supported MgdSchema class.", MIDCOM_LOG_ERROR); midcom_connection::set_error(MGD_ERR_ERROR); return false; } // Load the required component for DBA class $midcom_dba_classname = midcom::get('dbclassloader')->get_midcom_class_name_for_mgdschema_object($unserialized_object); if (!midcom::get('dbclassloader')->load_mgdschema_class_handler($midcom_dba_classname)) { debug_add("Failed to load the handling component for {$midcom_dba_classname}, cannot import.", MIDCOM_LOG_ERROR); midcom_connection::set_error(MGD_ERR_ERROR); return false; } // Get an object for ACL checks, use existing one if possible $acl_object = new $midcom_dba_classname($unserialized_object->guid); if (is_object($acl_object) && $acl_object->id) { if (!midcom::get('dbfactory')->is_a($acl_object, get_class($unserialized_object))) { $acl_class = get_class($acl_object); $unserialized_class = get_class($unserialized_object); debug_add("The local object we got is not of compatible type ({$acl_class} vs {$unserialized_class}), this means duplicate GUID", MIDCOM_LOG_ERROR); midcom_connection::set_error(MGD_ERR_DUPLICATE); return false; } // Got an existing object $acl_object_in_db = true; $actual_object_in_db = true; /* PONDER: should we copy values from unserialized here as well ?? likely we should (think moving article) midcom_baseclasses_core_dbobject::cast_object($acl_object, $unserialized_object) */ } else { $error_code = midcom_connection::get_error(); // switch is a loop, get the value only once this way switch ($error_code) { case MGD_ERR_ACCESS_DENIED: $actual_object_in_db = true; debug_add("Could not instantiate ACL object due to ACCESS_DENIED error, this means we can abort early", MIDCOM_LOG_ERROR); return false; break; case MGD_ERR_OBJECT_DELETED: case MGD_ERR_OBJECT_PURGED: $actual_object_in_db = true; break; default: $actual_object_in_db = false; break; } // Copy-construct $acl_object_in_db = false; $acl_object = new $midcom_dba_classname(); if (!midcom_baseclasses_core_dbobject::cast_object($acl_object, $unserialized_object)) { debug_add('Failed to cast MidCOM DBA object for ACL checks from $unserialized_object', MIDCOM_LOG_ERROR); debug_print_r('$unserialized_object: ', $unserialized_object); return false; } } // Magic to check for various corner cases to determine the action to take later on switch (true) { case $unserialized_object->action == 'purged': // Purges not supported yet debug_add("Purges not supported yet (they require extra special love)", MIDCOM_LOG_ERROR); midcom_connection::set_error(MGD_ERR_OBJECT_PURGED); return false; break; // action is created but object is already in db, cast to update // action is created but object is already in db, cast to update case $unserialized_object->action == 'created' && $actual_object_in_db: $handle_action = 'updated'; break; case $unserialized_object->action == 'updated' && !$actual_object_in_db: $handle_action = 'created'; break; default: if ($unserialized_object->action) { $handle_action = $unserialized_object->action; } else { $handle_action = 'updated'; } break; } if (!$acl_object->_on_importing()) { debug_add("The _on_importing event handler returned false.", MIDCOM_LOG_ERROR); // set errno if not set if (midcom_connection::get_error() === MGD_ERR_OK) { midcom_connection::set_error(MGD_ERR_ERROR); } return false; } switch ($handle_action) { case 'deleted': if (!$actual_object_in_db) { midcom_helper_replicator_import_object($unserialized_object, $use_force); break; } if (!midcom_baseclasses_core_dbobject::delete_pre_checks($acl_object)) { debug_add('delete pre-flight check returned false', MIDCOM_LOG_ERROR); return false; } // Actual import if (!midcom_helper_replicator_import_object($unserialized_object, $use_force)) { /** * BEGIN workaround * For http://trac.midgard-project.org/ticket/200 */ if (midcom_connection::get_error() === MGD_ERR_OBJECT_IMPORTED) { debug_add('Trying to workaround problem importing deleted action, calling $acl_object->delete()', MIDCOM_LOG_WARN); if ($acl_object->delete()) { debug_add('$acl_object->delete() succeeded, returning true early', MIDCOM_LOG_INFO); return true; } debug_add("\$acl_object->delete() failed for {$acl_object->guid}, errstr: " . midcom_connection::get_error_string(), MIDCOM_LOG_ERROR); // reset errno() midcom_connection::set_error(MGD_ERR_OBJECT_IMPORTED); } /** END workaround */ debug_add('midcom_helper_replicator_import_object returned false, errstr: ' . midcom_connection::get_error_string(), MIDCOM_LOG_ERROR); return false; } midcom_baseclasses_core_dbobject::delete_post_ops($acl_object); break; case 'updated': if (!midcom_baseclasses_core_dbobject::update_pre_checks($acl_object)) { debug_add('update pre-flight check returned false', MIDCOM_LOG_ERROR); return false; } // Actual import if (!midcom_helper_replicator_import_object($unserialized_object, $use_force)) { debug_add('midcom_helper_replicator_import_object returned false, errstr: ' . midcom_connection::get_error_string(), MIDCOM_LOG_ERROR); return false; } // "refresh" acl_object if (!midcom_baseclasses_core_dbobject::cast_object($acl_object, $unserialized_object)) { // this shouldn't happen, but shouldn't be fatal either... } midcom_baseclasses_core_dbobject::update_post_ops($acl_object); break; case 'created': if (!midcom_baseclasses_core_dbobject::create_pre_checks($acl_object)) { debug_add('creation pre-flight check returned false', MIDCOM_LOG_ERROR); return false; } // Actual import if (!midcom_helper_replicator_import_object($unserialized_object, $use_force)) { debug_add('midcom_helper_replicator_import_object returned false, errstr: ' . midcom_connection::get_error_string(), MIDCOM_LOG_ERROR); return false; } // refresh object to avoid issues with _on_created requiring ID $acl_object_refresh = new $midcom_dba_classname($unserialized_object->guid); if (is_object($acl_object_refresh) && $acl_object_refresh->id) { $acl_object = $acl_object_refresh; midcom_baseclasses_core_dbobject::create_post_ops($acl_object); } else { // refresh failed (it really shouldn't), what to do ?? } break; default: debug_add("Do not know how to handle action '{$handle_action}'", MIDCOM_LOG_ERROR); midcom_connection::set_error(MGD_ERR_ERROR); return false; break; } $acl_object->_on_imported(); midcom::get('componentloader')->trigger_watches(MIDCOM_OPERATION_DBA_IMPORT, $acl_object); return true; }
/** * "Pre-flight" checks for delete method * * Separated so that dbfactory->import() can reuse the code * * @param midcom_core_dbaobject $object The DBA object we're working on */ public static function delete_pre_checks(midcom_core_dbaobject $object) { if (!$object->id) { debug_add("Failed to delete object, object " . get_class($object) . " is non-persistent (empty ID).", MIDCOM_LOG_ERROR); return false; } if (!$object->can_do('midgard:delete')) { debug_add("Failed to delete object, delete privilege on the " . get_class($object) . " {$object->guid} not granted for the current user.", MIDCOM_LOG_ERROR); midcom_connection::set_error(MGD_ERR_ACCESS_DENIED); return false; } if (!$object->_on_deleting()) { return false; } return true; }