/** * Build links to interfaces to solve the violation * @return array */ public function getLinks() { $session = Session::singleton(); $links = array(); foreach ($session->getInterfacesToReadConcept($this->src->concept) as $interface) { $links[] = "#/{$interface->id}/{$this->src->getJsonRepresentation()}"; } foreach ($session->getInterfacesToReadConcept($this->tgt->concept) as $interface) { $links[] = "#/{$interface->id}/{$this->tgt->getJsonRepresentation()}"; } return array_unique($links); }
/** * Get session variables (from 'SessionVars' interface) * @return mixed|false session variables (if interface 'SessionVars' is defined in &-script) or false otherwise */ public function getSessionVars() { if (InterfaceObject::interfaceExists('SessionVars')) { try { $this->logger->debug("Getting interface 'SessionVars' for {$this->sessionAtom->__toString()}"); return $this->sessionAtom->ifc('SessionVars')->read(['metaData' => false, 'navIfc' => false]); } catch (Exception $e) { $this->logger->warning("Error while getting SessionVars interface: " . $e->getMessage()); return false; } } else { return false; } }
/** * How to use Relation::deleteLink() to delete link (a1,b1) from r: * r :: A * B * deleteLink(a1[A], b1[B], false); * deleteLink(b1[B], a1[A], true); * * @param Atom $leftAtom * @param Atom $rightAtom * @param boolean $isFlipped * @param string $source specifies who calls this function (e.g. 'User' or 'ExecEngine') * @return void */ public function deleteLink($leftAtom, $rightAtom, $isFlipped = false, $source = 'User') { $this->logger->debug("Delete link ({$leftAtom->__toString()},{$rightAtom->__toString()}) from relation '{$this->__toString()}{({$isFlipped} ? '~' : '')}'"); // Determine src and tgt atom based on $isFlipped $srcAtom = $isFlipped ? $rightAtom : $leftAtom; $tgtAtom = $isFlipped ? $leftAtom : $rightAtom; // Checks if (!in_array($srcAtom->concept, $this->srcConcept->getSpecializationsIncl())) { throw new Exception("Cannot delete link ({$srcAtom->__toString()},{$tgtAtom->__toString()}) from relation '{$this->__toString()}', because source concept does not match relation source or its specializations", 500); } if (!in_array($tgtAtom->concept, $this->tgtConcept->getSpecializationsIncl())) { throw new Exception("Cannot delete link ({$srcAtom->__toString()},{$tgtAtom->__toString()}) from relation '{$this->__toString()}', because target concept does not match relation target or its specializations", 500); } // Delete link from relation table $this->db->deleteLink($this, $srcAtom, $tgtAtom); // Flag session var as affected when src or tgt concept of this relation is SESSION if ($srcAtom->concept->isSession() || $tgtAtom->concept->isSession()) { Session::singleton()->setSessionVarAffected(); } }
include_once Config::get('absolutePath') . Config::get('logPath') . "{$file}"; // check if all concepts and relations are defined foreach ((array) $allAtoms as $cpt => $atoms) { if (!empty($atoms)) { Concept::getConcept($cpt); } } foreach ((array) $allLinks as $rel => $links) { if (!empty($links)) { Relation::getRelation($rel); } } foreach ((array) $allAtoms as $cpt => $atoms) { $concept = Concept::getConcept($cpt); foreach ($atoms as $atomId) { $atom = new Atom($atomId, $concept); $atom->addAtom(); } } foreach ((array) $allLinks as $rel => $links) { if (!empty($links)) { $relation = Relation::getRelation($rel); } foreach ($links as $link) { if (is_null($link['src']) || is_null($link['tgt'])) { continue; } // skip $relation->addLink(new Atom($link['src'], $relation->srcConcept), new Atom($link['tgt'], $relation->tgtConcept)); } }
$result = array('patches' => $app->request->getBody(), 'content' => $content, 'notifications' => Notifications::getAll(), 'invariantRulesHold' => $session->database->getInvariantRulesHold(), 'requestType' => $session->database->getRequestType(), 'sessionRefreshAdvice' => $session->getSessionRefreshAdvice()); print json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); }); $app->post('/resources/:resourceType/:resourceId/:ifcPath+', function ($resourceType, $resourceId, $ifcPath) use($app) { $session = Session::singleton(); $roleIds = $app->request->params('roleIds'); $session->activateRoles($roleIds); $options = $app->request->params(); $ifcPath = implode('/', $ifcPath); $atom = new Atom($resourceId, Concept::getConcept($resourceType)); $atomOrIfc = $atom->walkIfcPath($ifcPath); // Perform create $content = $atomOrIfc->create($app->request->getBody(), $options); // Return result $result = array('content' => $content, 'notifications' => Notifications::getAll(), 'invariantRulesHold' => $session->database->getInvariantRulesHold(), 'requestType' => $session->database->getRequestType(), 'sessionRefreshAdvice' => $session->getSessionRefreshAdvice()); print json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); }); $app->delete('/resources/:resourceType/:resourceId/:ifcPath+', function ($resourceType, $resourceId, $ifcPath) use($app) { $session = Session::singleton(); $roleIds = $app->request->params('roleIds'); $session->activateRoles($roleIds); $options = $app->request->params(); $ifcPath = implode('/', $ifcPath); $atom = new Atom($resourceId, Concept::getConcept($resourceType)); $atomOrIfc = $atom->walkIfcPath($ifcPath); // Perform delete $atomOrIfc->delete($options); // Return result $result = array('notifications' => Notifications::getAll(), 'invariantRulesHold' => $session->database->getInvariantRulesHold(), 'requestType' => $session->database->getRequestType(), 'sessionRefreshAdvice' => $session->getSessionRefreshAdvice()); print json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); });
/** * * @param array $lines */ private function ParseLines($lines) { $relations = $concept = $separator = $flipped = array(); foreach ($lines as $linenr => $line) { $totalcolumns = count($line); // First line specifies relation names if ($linenr == 0) { for ($col = 0; $col < $totalcolumns; $col++) { $relations[$col] = trim($line[$col]); // No leading/trailing spaces around relation names. } // Second line specifies concepts (and optionally: separators) } elseif ($linenr == 1) { // In the Haskell importer, separators are the last character before the ']' if the concept is surrounded by such block quotes. Alternatively, you could specify a separator following such block-quotes, allowing for multiple-character separators. for ($col = 0; $col < $totalcolumns; $col++) { $cellvalue = trim($line[$col]); // No leading/trailing spaces around cell values in second line if ($cellvalue == '') { $concept[$col] = null; // The cell contains either 'Concept' or '[Conceptx]' where x is a separator character (e.g. ';', ',', ...) } elseif (substr($cellvalue, 0, 1) == '[' && substr($cellvalue, -1) == ']') { if ($col == 0) { throw new Exception("Seperator character not allowed for first column of excel import. Specified '{$line[$col]}'", 500); } $concept[$col] = Concept::getConceptByLabel(substr($cellvalue, 1, -2)); $separator[$col] = substr($cellvalue, -2, 1); } else { $concept[$col] = Concept::getConceptByLabel($cellvalue); $separator[$col] = false; } // Determine relations for all cols except col 0 if ($col > 0) { if ($relations[$col] == '' || $concept[$col] == '') { $relations[$col] = null; } elseif (substr($relations[$col], -1) == '~') { // Relation is flipped is last character is a tilde (~) $relations[$col] = Relation::getRelation(substr($relations[$col], 0, -1), $concept[$col], $concept[0]); $flipped[$col] = true; } else { $relations[$col] = Relation::getRelation($relations[$col], $concept[0], $concept[$col]); $flipped[$col] = false; } } } // All other lines specify atoms } else { $line[0] = trim($line[0]); // Trim cell content (= dirty identifier) // Determine left atom (column 0) of line if ($line[0] == '') { continue; } elseif ($line[0] == '_NEW') { $leftAtom = $concept[0]->createNewAtom(); } else { $leftAtom = new Atom($line[0], $concept[0]); } // Insert $leftAtom into the DB if it does not yet exist $leftAtom->addAtom(); // Process other columns of line for ($col = 1; $col < $totalcolumns; $col++) { if (is_null($concept[$col])) { continue; } // If no concept is specified, the cell is skipped if (is_null($relations[$col])) { continue; } // If no relation is specified, the cell is skipped // Determine right atom(s) $rightAtoms = array(); $cell = trim($line[$col]); // Start of check for multiple atoms in single cell if ($cell == '') { continue; } elseif ($cell == '_NEW') { $rightAtoms[] = $leftAtom; } elseif ($separator[$col]) { $atomsIds = explode($separator[$col], $cell); // atomnames may have surrounding whitespace foreach ($atomsIds as $atomId) { $rightAtoms[] = new Atom(trim($atomId), $concept[$col]); } } else { $rightAtoms[] = new Atom($line[$col], $concept[$col]); // DO NOT TRIM THIS CELL CONTENTS as it contains an atom that may need leading/trailing spaces } foreach ($rightAtoms as $rightAtom) { $relations[$col]->addLink($leftAtom, $rightAtom, $flipped[$col], 'ExcelImport'); } } } } }
/** * Add (src,tgt) tuple in relation provided in this interface * @var array $patch * @throws Exception * @return void */ public function doPatchAdd($patch) { // CRUD check if (!$this->crudU) { throw new Exception("Update is not allowed for path '{$this->path}'", 403); } if ($this->isRef()) { throw new Exception("Cannot update on reference interface in '{$this->path}'. See #498", 501); } // Check if patch value is provided if (!array_key_exists('value', $patch)) { throw new Exception("Cannot patch add. No 'value' specfied in '{$this->path}'", 400); } $tgtAtom = new Atom($patch['value'], $this->tgtConcept); // Interface is property if ($this->isProp()) { // Properties must be treated as a 'replace', so not handled here throw new Exception("Cannot patch add for property '{$this->path}'. Use patch replace instead", 500); // Interface is a relation to an object } elseif ($this->tgtConcept->isObject) { // Check if atom exists and may be created (crudC) if (!$tgtAtom->atomExists()) { if ($this->crudC) { $tgtAtom->addAtom(); } else { throw new Exception("Resource '{$tgtAtom->__toString()}' does not exist and may not be created in {$this->path}", 403); } } // Add link when possible (relation is specified) if (is_null($this->relation)) { $this->logger->debug("addLink skipped because '{$this->path}' is not an editable expression"); } else { $this->relation()->addLink($this->srcAtom, $tgtAtom, $this->relationIsFlipped); } // Interface is a relation to a scalar (i.e. not an object) } elseif (!$this->tgtConcept->isObject) { // Check: If interface is univalent, throw exception if ($this->isUni) { throw new Exception("Cannot patch add for univalent interface {$this->path}. Use patch replace instead", 500); } $this->relation()->addLink($this->srcAtom, $tgtAtom, $this->relationIsFlipped); } else { throw new Exception("Unknown patch add. Please contact the application administrator", 500); } }
private function login($email) { if (empty($email)) { throw new Exception("No emailaddress provided to login", 500); } $session = Session::singleton(); $db = Database::singleton(); $conceptUserID = Concept::getConceptByLabel('UserID'); $conceptDomain = Concept::getConceptByLabel('Domain'); $conceptDateTime = Concept::getConceptByLabel('DateTime'); $conceptOrg = Concept::getConceptByLabel('Organization'); $conceptAccount = Concept::getConceptByLabel('Account'); $conceptSession = Concept::getConceptByLabel('SESSION'); // Set sessionUser $atom = new Atom($email, $conceptUserID); $accounts = $atom->ifc('AccountForUserid')->getTgtAtoms(); // create new user if (empty($accounts)) { $newAccount = Concept::getConceptByLabel('Account')->createNewAtom(); // Save email as accUserid $relAccUserid = Relation::getRelation('accUserid', $newAccount->concept, $conceptUserID); $relAccUserid->addLink($newAccount, new Atom($email, $conceptUserID), false, 'OAuthLoginExtension'); // If possible, add account to organization(s) based on domain name $domain = explode('@', $email)[1]; $atom = new Atom($domain, $conceptDomain); $orgs = $atom->ifc('DomainOrgs')->getTgtAtoms(); $relAccOrg = Relation::getRelation('accOrg', $newAccount->concept, $conceptOrg); foreach ($orgs as $org) { $relAccOrg->addLink($newAccount, $org, false, 'OAuthLoginExtension'); } // Account created, add to $accounts list (used lateron) $accounts[] = $newAccount; } if (count($accounts) > 1) { throw new Exception("Multiple users registered with email {$email}", 401); } $relSessionAccount = Relation::getRelation('sessionAccount', $conceptSession, $conceptAccount); $relAccMostRecentLogin = Relation::getRelation('accMostRecentLogin', $conceptAccount, $conceptDateTime); $relAccLoginTimestamps = Relation::getRelation('accLoginTimestamps', $conceptAccount, $conceptDateTime); foreach ($accounts as $account) { // Set sessionAccount $relSessionAccount->addLink($session->sessionAtom, $account, false, 'OAuthLoginExtension'); // Timestamps $ts = new Atom(date(DATE_ISO8601), $conceptDateTime); $relAccMostRecentLogin->addLink($account, $ts, false, 'OAuthLoginExtension'); $relAccLoginTimestamps->addLink($account, $ts, false, 'OAuthLoginExtension'); } $db->closeTransaction('Login successfull', true); }
/** * Return content of all atoms for this concept * @return mixed[] */ public function getAllAtomObjects() { // Query all atoms in table if (isset($this->def['allAtomsQuery'])) { $query = $this->def['allAtomsQuery']; } else { $firstCol = current($this->mysqlConceptTable->getCols()); // We can query an arbitrary concept col for checking the existence of an atom $query = "SELECT DISTINCT `{$firstCol->name}` as `atomId` FROM `{$this->mysqlConceptTable->name}` WHERE `{$firstCol->name}` IS NOT NULL"; } $arr = array(); foreach ((array) $this->database->Exe($query) as $row) { $tgtAtom = new Atom($row['atomId'], $this, null, $row); $arr[] = $tgtAtom->getAtom(); } return $arr; }
/** * Remove all occurrences of $atom in the database (all concept tables and all relation tables) * In tables where the atom may not be null, the entire row is removed. * TODO: If all relation fields in a wide table are null, the entire row could be deleted, but this doesn't happen now. As a result, relation queries may return some nulls, but these are filtered out anyway. * @param \Ampersand\Core\Atom $atom * @return void */ function deleteAtom($atom) { $this->logger->debug("deleteAtom({$atom->__toString()})"); // This function is under control of transaction check! if (!isset($this->transaction)) { $this->startTransaction(); } $concept = $atom->concept; // Delete atom from concept table $conceptTable = $concept->getConceptTableInfo(); $query = "DELETE FROM `{$conceptTable->name}` WHERE `{$conceptTable->getFirstCol()->name}` = '{$atom->idEsc}' LIMIT 1"; $this->Exe($query); // Check if query resulted in an affected row $this->checkForAffectedRows(); $this->addAffectedConcept($concept); // add concept to affected concepts. Needed for conjunct evaluation. // Delete atom from relation tables where atom is mentioned as src or tgt atom foreach (Relation::getAllRelations() as $relation) { $tableName = $relation->getMysqlTable()->name; $cols = array(); if ($relation->srcConcept->inSameClassificationTree($concept)) { $cols[] = $relation->getMysqlTable()->srcCol(); } if ($relation->tgtConcept->inSameClassificationTree($concept)) { $cols[] = $relation->getMysqlTable()->tgtCol(); } foreach ($cols as $col) { // If n-n table, remove row if (is_null($relation->getMysqlTable()->tableOf)) { $query = "DELETE FROM `{$tableName}` WHERE `{$col->name}` = '{$atom->idEsc}'"; } elseif ($col->null) { $query = "UPDATE `{$tableName}` SET `{$col->name}` = NULL WHERE `{$col->name}` = '{$atom->idEsc}'"; } else { $query = "DELETE FROM `{$tableName}` WHERE `{$col->name}` = '{$atom->idEsc}'"; } $this->Exe($query); $this->addAffectedRelations($relation); } } $this->logger->debug("Atom '{$atom->__toString()}' (and all related links) deleted in database"); Hooks::callHooks('postDatabaseDeleteAtom', get_defined_vars()); }
function DelAtom($concept, $atomId) { Logger::getLogger('EXECENGINE')->info("DelAtom({$concept},{$atomId})"); if (func_num_args() != 2) { throw new Exception("Wrong number of arguments supplied for function DelAtom(): " . func_num_args() . " arguments", 500); } try { $atom = new Atom($atomId, Concept::getConceptByLabel($concept)); $atom->deleteAtom(); // delete atom + all relations with other atoms Logger::getLogger('EXECENGINE')->debug("Atom '{$atom}' deleted"); } catch (Exception $e) { Logger::getUserLogger()->error('DelAtom: ' . $e->getMessage()); } }