/** * * @throws Exception when segment type is unknown * @throws Exception when segment expression return more that 1 tgt atom * @return string */ public function getViolationMessage() { $database = Database::singleton(); $strArr = array(); foreach ($this->rule->violationSegments as $segment) { // text segment if ($segment['segmentType'] == 'Text') { $strArr[] = $segment['Text']; // expressie segment } elseif ($segment['segmentType'] == 'Exp') { // select starting atom depending on whether the segment uses the src of tgt atom. $atom = $segment['srcOrTgt'] == 'Src' ? $this->src : $this->tgt; // quering the expression $query = "SELECT DISTINCT `tgt` FROM ({$segment['expSQL']}) AS `results` WHERE `src` = '{$atom->idEsc}'"; // SRC of TGT kunnen door een expressie gevolgd worden $rows = $database->Exe($query); // returning the result if (count($rows) > 1) { throw new Exception("Expression of pairview results in more than one tgt atom", 501); } // 501: Not implemented $strArr[] = $rows[0]['tgt']; // unknown segment } else { $errorMessage = "Unknown segmentType '{$segment['segmentType']}' in violationSegments of rule '{$this->rule->id}'"; throw new Exception($errorMessage, 501); // 501: Not implemented } } // If empty array of strings (i.e. no violation segments defined), use default violation representation: '<srcAtom>,<tgtAtom>' $this->message = empty($strArr) ? "{$this->src->getLabel()},{$this->tgt->getLabel()}" : implode($strArr); return $this->message; }
/** * Constructor of Session class * private to prevent any outside instantiation of this object */ private function __construct() { $this->logger = Logger::getLogger('FW'); $this->database = Database::singleton(); $conceptSession = Concept::getConceptByLabel('SESSION'); // Also checks if 'SESSION' is defined as concept in Ampersand script $this->id = session_id(); $this->sessionAtom = new Atom($this->id, $conceptSession); $this->logger->debug("Session id: {$this->id}"); // Remove expired Ampersand sessions from __SessionTimeout__ and all concept tables and relations where it appears. $expiredSessionsAtoms = array_column((array) $this->database->Exe("SELECT SESSION FROM `__SessionTimeout__` WHERE `lastAccess` < " . (time() - Config::get('sessionExpirationTime'))), 'SESSION'); foreach ($expiredSessionsAtoms as $expiredSessionAtom) { if ($expiredSessionAtom == $this->id) { // Notify user that session is expired when login functionality is enabled if (Config::get('loginEnabled')) { Logger::getUserLogger()->warning("Your session has expired, please login again"); } // 440 Login Timeout -> is redirected by frontend to login page } $this->destroyAmpersandSession($expiredSessionAtom); } // Create a new Ampersand session atom if not yet in SESSION table (browser started a new session or Ampersand session was expired) $sessionAtom = new Atom($this->id, $conceptSession); if (!$sessionAtom->atomExists()) { $sessionAtom->addAtom(); $this->database->commitTransaction(); //TODO: ook door Database->closeTransaction() laten doen, maar die verwijst terug naar Session class voor de checkrules. Oneindige loop } $this->database->Exe("INSERT INTO `__SessionTimeout__` (`SESSION`,`lastAccess`) VALUES ('" . $this->id . "', '" . time() . "') ON DUPLICATE KEY UPDATE `lastAccess` = '" . time() . "'"); // Add public interfaces $this->accessibleInterfaces = InterfaceObject::getPublicInterfaces(); }
/** * Relation constructor * Private function to prevent outside instantiation of Relations. Use Relation::getRelation($relationSignature) * * @param array $relationDef */ public function __construct($relationDef) { $this->db = Database::singleton(); $this->logger = Logger::getLogger('FW'); $this->name = $relationDef['name']; $this->srcConcept = Concept::getConcept($relationDef['srcConceptId']); $this->tgtConcept = Concept::getConcept($relationDef['tgtConceptId']); $this->signature = $relationDef['signature']; $this->isUni = $relationDef['uni']; $this->isTot = $relationDef['tot']; $this->isInj = $relationDef['inj']; $this->isSur = $relationDef['sur']; $this->isProp = $relationDef['prop']; foreach ((array) $relationDef['affectedConjuncts'] as $conjId) { $conj = Conjunct::getConjunct($conjId); $this->affectedConjuncts[] = $conj; if ($conj->isSigConj()) { $this->affectedSigConjuncts[] = $conj; } if ($conj->isInvConj()) { $this->affectedInvConjuncts[] = $conj; } // if (!$conj->isSigConj() && !$conj->isInvConj()) $this->logger->warning("Affected conjunct '{$conj->id}' (specified for relation '{$this->__toString()}') is not part of an invariant or signal rule"); } // Specify mysql table information $this->mysqlTable = new RelationTable($relationDef['mysqlTable']['name'], $relationDef['mysqlTable']['tableOf']); $srcCol = $relationDef['mysqlTable']['srcCol']; $tgtCol = $relationDef['mysqlTable']['tgtCol']; $this->mysqlTable->addSrcCol(new DatabaseTableCol($srcCol['name'], $srcCol['null'], $srcCol['unique'])); $this->mysqlTable->addTgtCol(new DatabaseTableCol($tgtCol['name'], $tgtCol['null'], $tgtCol['unique'])); }
$allLinks = array(); foreach (Relation::getAllRelations() as $rel) { $allLinks[$rel->signature] = $rel->getAllLinks(); } $strFileContent = '<?php' . PHP_EOL . '$allAtoms = ' . var_export($allAtoms, true) . ';' . PHP_EOL . '$allLinks = ' . var_export($allLinks, true) . ';' . PHP_EOL . '?>'; file_put_contents(Config::get('absolutePath') . Config::get('logPath') . "export-" . date('Y-m-d_H-i-s') . ".php", $strFileContent); }); $app->get('/admin/import', function () use($app) { if (Config::get('productionEnv')) { throw new Exception("Import not allowed in production environment", 403); } $file = $app->request->params('file'); if (is_null($file)) { throw new Exception("Import file not specified", 500); } $database = Database::singleton(); 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) {
/** * InterfaceObject constructor * @param array $ifcDef Interface object definition as provided by Ampersand generator * @param string $pathEntry * @param boolean $rootIfc Specifies if this interface object is a toplevel interface (true) or subinterface (false) */ public function __construct($ifcDef, $pathEntry = null, $rootIfc = false) { $this->database = Database::singleton(); $this->logger = Logger::getLogger('FW'); $this->isRoot = $rootIfc; // Set attributes from $ifcDef $this->id = $ifcDef['id']; $this->label = $ifcDef['label']; $this->view = is_null($ifcDef['viewId']) ? null : View::getView($ifcDef['viewId']); $this->path = is_null($pathEntry) ? $this->id : "{$pathEntry}/{$this->id}"; // Information about the (editable) relation if applicable $this->relation = is_null($ifcDef['relation']) ? null : Relation::getRelation($ifcDef['relation']); $this->relationIsFlipped = $ifcDef['relationIsFlipped']; // Interface expression information $this->srcConcept = Concept::getConcept($ifcDef['expr']['srcConceptId']); $this->tgtConcept = Concept::getConcept($ifcDef['expr']['tgtConceptId']); $this->isUni = $ifcDef['expr']['isUni']; $this->isTot = $ifcDef['expr']['isTot']; $this->isIdent = $ifcDef['expr']['isIdent']; $this->query = $ifcDef['expr']['query']; // CRUD rights $this->crudC = $ifcDef['crud']['create']; $this->crudR = $ifcDef['crud']['read']; $this->crudU = $ifcDef['crud']['update']; $this->crudD = $ifcDef['crud']['delete']; if ($this->crudU && $this->tgtConcept->isObject) { $this->editableConcepts[] = $this->tgtConcept; } // Interface expression must equal (editable) relation when crudU is specified if ($this->crudU && is_null($this->relation)) { $this->logger->warning("Update rights (crUd) specified while interface expression is not an editable relation for (sub)interface: {$this->path}"); } // Check for unsupported patchReplace functionality due to missing 'old value'. Related with issue #318 if (!is_null($this->relation) && $this->crudU && !$this->tgtConcept->isObject && $this->isUni) { // Only applies to editable relations // Only applies to crudU, because issue is with patchReplace, not with add/remove // Only applies to scalar, because objects don't use patchReplace, but Remove and Add // Only if interface expression (not! the relation) is univalent, because else a add/remove option is used in the UI if (!$this->relationIsFlipped && $this->relation->getMysqlTable()->tableOf == 'tgt' || $this->relationIsFlipped && $this->relation->getMysqlTable()->tableOf == 'src') { $this->logger->warning("Unsupported edit functionality due to combination of factors for (sub)interface: '{$this->path}' - {$this->relation->__toString()}" . ($this->relationIsFlipped ? '~' : '') . " administrated in table of '{$this->relation->getMysqlTable()->tableOf}'"); } } // Subinterfacing if (!is_null($ifcDef['subinterfaces'])) { // Subinterfacing is not supported/possible for tgt concepts with a scalar representation type (i.e. non-objects) if (!$this->tgtConcept->isObject) { throw new Exception("Subinterfacing is not supported for concepts with a scalar representation type (i.e. non-objects). (Sub)Interface '{$this->path}' with target {$this->tgtConcept->__toString()} (type:{$this->tgtConcept->type}) has subinterfaces specified", 501); } // Reference to top level interface $this->refInterfaceId = $ifcDef['subinterfaces']['refSubInterfaceId']; $this->isLinkTo = $ifcDef['subinterfaces']['refIsLinTo']; // Inline subinterface definitions foreach ((array) $ifcDef['subinterfaces']['ifcObjects'] as $subIfcDef) { $ifc = new InterfaceObject($subIfcDef, $this->path); $this->subInterfaces[$ifc->id] = $ifc; $this->editableConcepts = array_merge($this->editableConcepts, $ifc->editableConcepts); } } }
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); }
global $app; // Path to API is 'api/v1/excelimport/import' $app->post('/excelimport/import', function () use($app) { $session = Session::singleton(); $roleIds = $app->request->params('roleIds'); $session->activateRoles($roleIds); // Check sessionRoles if allowedRolesForExcelImport is specified $allowedRoles = Config::get('allowedRolesForExcelImport', 'excelImport'); if (!is_null($allowedRoles)) { $ok = false; foreach ($session->getSessionRoles() as $role) { if (in_array($role->label, $allowedRoles)) { $ok = true; } } if (!$ok) { throw new Exception("You do not have access to import excel files", 401); } } if (is_uploaded_file($_FILES['file']['tmp_name'])) { // Parse: $parser = new ExcelImport(); $parser->ParseFile($_FILES['file']['tmp_name']); Database::singleton()->closeTransaction("File {$_FILES['file']['tmp_name']} imported successfully", true); unlink($_FILES['file']['tmp_name']); } else { Logger::getUserLogger()->error("No file uploaded"); } $result = array('notifications' => Notifications::getAll(), 'files' => $_FILES); print json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); });
/** * Concept constructor * Private function to prevent outside instantiation of concepts. Use Concept::getConcept($conceptName) * * @param array $conceptDef */ private function __construct($conceptDef) { $this->database = Database::singleton(); $this->logger = Logger::getLogger('FW'); $this->def = $conceptDef; $this->name = $conceptDef['id']; $this->label = $conceptDef['label']; $this->type = $conceptDef['type']; $this->isObject = $this->type == "OBJECT" ? true : false; $this->affectedConjunctIds = (array) $conceptDef['affectedConjuncts']; foreach ($this->affectedConjunctIds as $conjId) { $conj = Conjunct::getConjunct($conjId); if ($conj->isSigConj()) { $this->affectedSigConjuncts[] = $conj; } if ($conj->isInvConj()) { $this->affectedInvConjuncts[] = $conj; } // if (!$conj->isSigConj() && !$conj->isInvConj()) $this->logger->warning("Affected conjunct '{$conj->id}' (specified for concept '[{$this->name}]') is not part of an invariant or signal rule"); } $this->specializations = (array) $conceptDef['specializations']; $this->generalizations = (array) $conceptDef['generalizations']; $this->interfaceIds = (array) $conceptDef['interfaces']; $this->largestConceptId = $conceptDef['largestConcept']; if (!is_null($conceptDef['defaultViewId'])) { $this->defaultView = View::getView($conceptDef['defaultViewId']); } $this->mysqlConceptTable = new DatabaseTable($conceptDef['conceptTable']['name']); foreach ($conceptDef['conceptTable']['cols'] as $colName) { $this->mysqlConceptTable->addCol(new DatabaseTableCol($colName)); } }
/** * Overwrites getViolationMessage() method from Violation class * @throws Exception when segment type is unknown * @throws Exception when segment expression return more that 1 tgt atom * @return string */ public function getViolationMessage() { $database = Database::singleton(); $strArr = array(); foreach ($this->rule->violationSegments as $segment) { // text segment if ($segment['segmentType'] == 'Text') { $strArr[] = $segment['Text']; // expressie segment } elseif ($segment['segmentType'] == 'Exp') { // select starting atom depending on whether the segment uses the src of tgt atom. $atom = $segment['srcOrTgt'] == 'Src' ? $this->src : $this->tgt; $rows = array(); if ($segment['expIsIdent']) { // when segment expression isIdent (i.e. SRC I or TGT I), we don't have to query the database. $rows[] = array('tgt' => $atom->id); } else { // quering the expression $query = "SELECT DISTINCT `tgt` FROM ({$segment['expSQL']}) AS `results` WHERE `src` = '{$atom->idEsc}'"; // SRC of TGT kunnen door een expressie gevolgd worden $rows = $database->Exe($query); } // returning the result if (count($rows) == 0) { $strArr[] = '_NULL'; } else { $str = ''; foreach ($rows as $row) { $str .= $row['tgt'] . '_AND'; } $str = substr($str, 0, -4); // strip the last _AND $strArr[] = str_replace(array('{EX}', '{php}'), '', $str); // prevent php interpreter by user input. Only allowed as Text segments specified in &-script } // unknown segment } else { $errorMessage = "Unknown segmentType '{$segment['segmentType']}' in violationSegments of rule '{$this->rule->id}'"; throw new Exception($errorMessage, 501); // 501: Not implemented } } return $this->message = implode($strArr); }
function OverwritePopulation($rArray, $relationName, $conceptName) { try { $database = Database::singleton(); $concept = Concept::getConceptByLabel($conceptName); $relation = Relation::getRelation($relationName, $concept, $concept); $relationTable = $relation->getMysqlTable(); $srcCol = $relationTable->srcCol(); $tgtCol = $relationTable->tgtCol(); $query = "DELETE FROM `{$relationTable->name}`"; // Do not use TRUNCATE statement, this causes an implicit commit $database->Exe($query); foreach ($rArray as $src => $tgtArray) { foreach ($tgtArray as $tgt => $bool) { if ($bool) { $query = "INSERT INTO `{$relationTable->name}` (`{$srcCol->name}`, `{$tgtCol->name}`) VALUES ('{$src}','{$tgt}')"; $database->Exe($query); } } } } catch (Exception $e) { throw new Exception('OverwritePopulation: ' . $e->getMessage(), 500); } }
/** * Function to evaluate conjunct * @param boolean $cacheConjuncts * @return array[] array(array('src' => '<srcAtomId>', 'tgt' => '<tgtAtomId>')) */ public function evaluateConjunct($cacheConjuncts = true) { $this->logger->debug("Checking conjunct '{$this->id}' cache:" . var_export($cacheConjuncts, true)); try { // If conjunct is already evaluated and conjunctCach may be used -> return violations if (isset($this->conjunctViolations) && $cacheConjuncts) { $this->logger->debug("Conjunct is already evaluated, getting violations from cache"); return $this->conjunctViolations; // Otherwise evaluate conjunct, cache and return violations } else { $db = Database::singleton(); $dbsignalTableName = Config::get('dbsignalTableName', 'mysqlDatabase'); $violations = array(); // Execute conjunct query $violations = (array) $db->Exe($this->query); // Cache violations in php Conjunct object if ($cacheConjuncts) { $this->conjunctViolations = $violations; } if (count($violations) == 0) { $this->logger->debug("Conjunct '{$this->id}' holds"); // Remove "old" conjunct violations from database $query = "DELETE FROM `{$dbsignalTableName}` WHERE `conjId` = '{$this->id}'"; $db->Exe($query); } else { $this->logger->debug("Conjunct '{$this->id}' broken, updating violations in database"); // Remove "old" conjunct violations from database $query = "DELETE FROM `{$dbsignalTableName}` WHERE `conjId` = '{$this->id}'"; $db->Exe($query); // Add new conjunct violation to database $query = "INSERT IGNORE INTO `{$dbsignalTableName}` (`conjId`, `src`, `tgt`) VALUES "; $values = array(); foreach ($violations as $violation) { $values[] = "('{$this->id}', '" . $db->escape($violation['src']) . "', '" . $db->escape($violation['tgt']) . "')"; } $query .= implode(',', $values); $db->Exe($query); } return $violations; } } catch (Exception $e) { Logger::getUserLogger()->error("While checking conjunct '{$this->id}': " . $e->getMessage()); return array(); } }
/** * Atom constructor * @param string $atomId * @param Concept $concept * @param InterfaceObject $ifc * @param array $qData the row data (from database query) from which this atom is created * @return void */ public function __construct($atomId, Concept $concept, InterfaceObject $ifc = null, array $qData = null) { $this->database = Database::singleton(); $this->logger = Logger::getLogger('FW'); $this->concept = $concept; $this->parentIfc = $ifc; $this->qData = $qData; $this->setId($atomId); // JSON-LD attributes $this->url = Config::get('serverURL') . Config::get('apiPath') . '/resource/' . $this->concept->name . '/' . $this->getJsonRepresentation(); }
function ClearConcept($concept, $atom) { Logger::getLogger('EXECENGINE')->info("ClearConcept({$concept},{$atom})"); if (func_num_args() != 2) { throw new Exception("Wrong number of arguments supplied for function ClearConcept(): " . func_num_args() . " arguments", 500); } try { $database = Database::singleton(); $atom = new Atom($atom, Concept::getConceptByLabel($concept)); $database->atomClearConcept($atom); Logger::getLogger('EXECENGINE')->debug("Atom '{$atom->__toString()}' removed as member from concept '{$concept}'"); } catch (Exception $e) { Logger::getUserLogger()->error('ClearConcept: ' . $e->getMessage()); } }