metadata_id); } protected static function getSqlOptions($orderBy, $limit, $offset) { $additionalSql = array(); // order by if (count($orderBy) > 0) { $orderByArray = array(); foreach ($orderBy as $column => $order) { if (preg_match("/[A-Za-z][A-Za-z0-9_]{1,63}/", $column)) { $orderByArray[]= $column . " " . ($order ? $order : "ASC"); } } $additionalSql[]= "ORDER BY " . implode(",", $orderByArray); } // limit if (is_integer($limit)) { $additionalSql[]= "LIMIT " . $limit; } // offset if (is_integer($offset)) { $additionalSql[]= "OFFSET " . $offset; } return implode(" ", $additionalSql); } public function __construct () { if (func_num_args() === 1) { $this->metadata_id = intval(func_get_arg(0)); } try{ if (!is_null($this->metadata_id)) { $this->load(); } } catch(Exception $E) { new mb_exception($E->getMessage()); } } public static function byUUID($uuid){ $sql = "SELECT metadata_id FROM view_mb_metadata"; $filter = new Filter("AND", array( new Filter("=", "uuid", $uuid), self::getReadAccessFilter() )); $sqlObject = $filter->toSql(); $sql .= $sqlObject->sql !== "" ? " WHERE " . $sqlObject->sql : ""; $v = $sqlObject->v; $t = $sqlObject->t; $res = db_prep_query($sql, $v, $t); $row = db_fetch_assoc($res); if ($row) { return new self($row['metadata_id']); } else { throw new Exception("Trying to load Record with invalid UUID: $uuid, $sql"); } } public function setUuid ($aUuid) { if (!Uuid::isuuid($aUuid)) { return false; } if (get_class($this->xml) === "MdMetadataXml" && $this->xml->setUuid($aUuid)) { $this->uuid = $aUuid; return true; } return false; } public static function loadFile ($filename) { $metadata = new MdMetadata(); $xmlObj = MdMetadataXml::loadFile($filename); return MdMetadata::loadXml($xmlObj); } public static function loadXml ($xmlObj) { $metadata = new MdMetadata(); $metadata->xml = $xmlObj; $metadata->uuid = $xmlObj->getUuid(); $metadata->title = $xmlObj->getTitle(); $metadata->status = MdMetadata::STATUS_REGISTER; $metadata->responsible_party_name = $xmlObj->getResponsibleParty(); $myGroup = Group::byName($xmlObj->getResponsibleParty()); if (!is_null($myGroup) && $myGroup->isValid()) { $metadata->responsible_party = $myGroup->getId(); } $myUser = User::byName($xmlObj->getIndividualName()); if (!is_null($myUser) && $myUser->isValid()) { $metadata->individual_name = $myUser->id; } $metadata->type = $xmlObj->getType(); return $metadata; } public static function getDataFilter ($data) { $filterArray = array(); foreach ($data as $item) { if ($item->value === "") { continue; } if ($item->name === "title") { $filterArray[]= new Filter("ILIKE", "title", "%" . $item->value . "%"); } elseif ($item->name === "responsible_party") { $group = RegistrationOfficeGroup::byName($item->value); if (!is_null($group)) { $filterArray[]= new Filter("=", $item->name, $item->value); } else { // if no group is found, result set is empty $filterArray[]= new Filter("FALSE"); } } elseif ($item->name === "individual_name" || $item->name === "fkey_mb_user_id") { $user = User::byName($item->value); if (!is_null($user)) { $filterArray[]= new Filter("=", $item->name, $item->value); } else { // if no user is found, result set is empty $filterArray[]= new Filter("FALSE"); } } elseif ($item->name === "status") { $filterArray[]= new Filter("=", $item->name, strtoupper($item->value)); } elseif ($item->name === "date_min") { $filterArray[]= new Filter(">=", "date", $item->value); } elseif ($item->name === "date_max") { $filterArray[]= new Filter("<=", "date", $item->value); } } return new Filter("AND", $filterArray); } public static function getTypeFilter ($type, $typeArray) { switch ($type) { case $typeArray[0]: return new Filter("=", "type", "application"); break; case $typeArray[1]: return new Filter("=", "type", "service"); break; case $typeArray[2]: return new Filter("IN", "type", array('dataset', 'series')); break; default: return new Filter("FALSE"); } } public function userHasWriteAccess () { return true; $me = new User(); if (!$me->isValid()) { throw new Exception ("Invalid user."); } $acls = self::lookupACL($this->status); $groups = array(); $groupIds = $me->getGroupsByUser(); //This is an array of ids foreach($groupIds as $groupId){ $group = new Group($groupId); $groups[] = $group->name; } $acls = self::lookupACL($this->status); $owneruser = $this->fkey_mb_user_id ? new User($this->fkey_mb_user_id) : null; $ownergroup = $this->responsible_party ? new Group($this->responsible_party) : null; $accessmap = self::calculateACL($me->name,$groups, $acls, $owneruser->name, $ownergroup->name); return !!($accessmap & self::WRITE); } private static function getReadAccessFilter () { $me = new Registrar(); if ($me->isMetadataAdmin()) { // MetadataAdmin is god, so no further restrictions } else if ($me->isMetadataGroupAdmin() || $me->isMetadataRegistrar()) { $myRegistrarGroups = RegistrationOfficeGroup::getGroupsByUser( Mapbender::session()->get("mb_user_id") ); $filterStatus = new Filter("=", "status", "FREIGEGEBEN"); if (count($myRegistrarGroups) > 0) { // return only these registrars that have metadata sets $ids = array(); foreach ($myRegistrarGroups as $reg) { $ids[]= $reg->getId(); } $filterResponsibleParty = new Filter("IN", "responsible_party_id", $ids); $orFilter = new Filter("OR", array( $filterStatus, $filterResponsibleParty )); $filterArray[]= $orFilter; } else { $filterArray[]= $filterStatus; } } else { $filterArray[]= new Filter("=", "status", "FREIGEGEBEN"); } return new Filter("AND", $filterArray); } public function load () { $sql = "SELECT metadata_id, uuid, copyof, title, status, responsible_party,responsible_party_name, responsible_party_id, fkey_mb_user_id, individual_name,individual_name_id, lastchanged, data, visibility, type FROM view_mb_metadata"; $filter = new Filter("AND", array( new Filter("=", "metadata_id", $this->getId()), self::getReadAccessFilter() )); $sqlObject = $filter->toSql(); $sql .= $sqlObject->sql !== "" ? " WHERE " . $sqlObject->sql : ""; $v = $sqlObject->v; $t = $sqlObject->t; $res = db_prep_query($sql, $v, $t); $row = db_fetch_assoc($res); if ($row) { $this->uuid = $row["uuid"]; $this->copyof = $row["copyof"]; $this->title = $row["title"]; $this->status = $row["status"]; $this->responsible_party = $row["responsible_party_id"]; // 2010-11-26 | apour | we dont need mb_goupmembers //$this->responsible_party_name = $row["responsible_party"]; $this->responsible_party_name = $row["responsible_party_name"]; $this->fkey_mb_user_id = $row["fkey_mb_user_id"]; $this->individual_name = $row["individual_name_id"]; $this->individual_name_name = $row["individual_name"]; $this->date = $row["lastchanged"]; $this->xml = new MdMetadataXml($row["data"]); $this->type = $row["type"]; $this->visibility = $row["visibility"]; } else { $this->metadata_id = null; } } /** * checks if the uuid already exists or not * * @return Boolean * @param $uuid String */ public static function uuidExists ($uuid){ if (!Uuid::isuuid($uuid)) { new mb_exception($uuid . " is not a Uuid!"); return false; } $sql = "SELECT uuid from mb_metadata where uuid = $1"; $v = array($uuid); $t = array('s'); $res = db_prep_query($sql,$v,$t); if($row = db_fetch_array($res)){ return true; } return false; } public static function getCount ($aFilter) { $sql = "SELECT COUNT(metadata_id) FROM view_mb_metadata"; $filter = new Filter("AND", array( self::getReadAccessFilter(), is_a($aFilter, "Filter") ? $aFilter : new Filter() )); $sqlObject = $filter->toSql(); $sql = $sqlObject->sql !== "" ? trim($sql . " WHERE " . $sqlObject->sql) : $sql; $v = $sqlObject->v; $t = $sqlObject->t; $res = db_prep_query($sql, $v, $t); if ($row = db_fetch_array($res)) { return intval($row[0]); } return 0; } public static function getList ($aFilter) { $orderBy = func_num_args() >= 2 ? func_get_arg(1) : array(); $limit = func_num_args() >= 3 ? func_get_arg(2) : null; $offset = func_num_args() >= 4 ? func_get_arg(3) : null; $sql = "SELECT metadata_id FROM view_mb_metadata"; $filter = new Filter("AND", array( self::getReadAccessFilter(), is_a($aFilter, "Filter") ? $aFilter : new Filter() )); $sqlObject = $filter->toSql(); $sqlOptions = self::getSqlOptions($orderBy, $limit, $offset); $where = $sqlObject->sql . " " . $sqlOptions; $sql = trim($where) !== "" ? trim($sql . " WHERE " . $where) : $sql; $v = $sqlObject->v; $t = $sqlObject->t; $res = db_prep_query($sql, $v, $t); $metadataArray = array(); while ($row = db_fetch_assoc($res)) { $metadata_id = intval($row["metadata_id"]); $metadata = new MdMetadata($metadata_id); if ($metadata->isValid()) { $metadataArray[]= $metadata; } } return $metadataArray; } public function isValid () { if (!is_null($this->metadata_id)) { return true; } return false; } // something is wrong here, "bypasspermissions" smells of bad design public function commit ($bypassPermissions = false) { if (!$this->userHasWriteAccess() && !$bypassPermissions) { throw new Exception (_mb("Not allowed to update metadata record.")); } $this->date = date("Y-m-d"); $sql = <<get('mb_user_id'), $this->date, $this->status, strval($this->xml), $this->title, $this->responsible_party, $this->individual_name, $this->type, $this->visibility, $this->copyof, $this->uuid, $this->responsible_party_name, 'MeTaDoR-full' ); $t = array('i', 's', 's', 's', 's', 'i', 'i', 's', 's', 's','s','s','s'); if($this->metadata_id){ $sql .= " WHERE metadata_id = $14"; $v[] = $this->metadata_id; $t[] = 'i'; }else{ $sql .= " WHERE uuid = $14"; $v[] = $this->uuid; $t[] = 's'; } if(!db_prep_query($sql,$v,$t)){ throw new Exception (_mb("Unable to update metadata record")); } $this->publish(); } public static function toDatatables() { } public function change ($changes) { } public function remove () { if (!$this->userHasWriteAccess()) { throw new Exception (_mb("Not allowed to remove metadata record.")); } $sql = "DELETE FROM mb_metadata"; $filter = new Filter("=", "metadata_id", $this->getId()); $sqlObject = $filter->toSql(); $sql .= " WHERE " . $sqlObject->sql; $v = $sqlObject->v; $t = $sqlObject->t; $res = db_prep_query($sql, $v, $t); if (!$res) { throw new Exception (_mb("Invalid metadata record.")); } } public function getFields () { } public static function byName ($name) { } public function create () { if (is_null($this->uuid)) { throw new Exception(_mb("Can't create without a uuid")); } if (!$this->userHasWriteAccess()) { throw new Exception (_mb("Not allowed to create metadata record.")); } db_begin(); $sql_group_create = "INSERT INTO mb_metadata (uuid) VALUES ($1)"; $v = array($this->uuid); $t = array("s"); $insert_result = db_prep_query($sql_group_create, $v, $t); if (!$insert_result) { db_rollback(); throw new Exception (_mb("Could not insert new metadata record.")); } $metadata_id = db_insertid($insert_result,'mb_metadata', 'metadata_id'); if ($metadata_id != 0) { $this->metadata_id = intval($metadata_id); } try { $this->commit(); } catch (Exception $e) { db_rollback(); throw new Exception (_mb("Could not store initial values of metadata record.")); } db_commit(); new mb_exception("CREATED ".$this->uuid); } private function publish() { // Todo: use the xml-import $filename = MdMetadata::HARVESTING_DIR . $this->uuid.".xml"; if($this->status === MdMetadata::STATUS_APPROVED && $this->visibility === 'PUBLIC'){ if (!$handle = fopen($filename, 'w')) { throw new Exception (_mb("Could not open file: " . $filename)); } if (fwrite($handle, $this->xml) === FALSE) { throw new Exception (_mb("Could not write to file: " . $filename)); } fclose($handle); } else if(is_file($filename)) { unlink($filename); } } public function copy(){ $copy = new MdMetadata(); $copy->xml = $this->xml; $copy->individual_name = $this->individual_name; $copy->individual_name_name = $this->individual_name_name; $copy->responsible_party = $this->responsible_party; $copy->responsible_party_name = $this->responsible_party_name; $copy->title = $this->title; $copy->visibility = $this->visibility; $copy->type = $this->type; $copy->date = $this->date; $copy->setUuid(strval(new Uuid())); $copy->copyof = $this->uuid; $copy->status = $this->status; $copy->create(); return $copy; } /** This function calculates a bitmap according where each bit specifies a right as defined by the constants above Each entry in an acl can bes specified as follows: :: where can be: g for group u for user ou for owneruser og for ownergroup d for default for g and d is the group- or username this entry is to apply for, otherwise it's the empty string is an integer specifying the kind of access you which to give the selected group or user there is a special syntax if you whish an entry to apply only if the user matches a set of criteria (:,:,...): example: //give read access to group users g:users:128 // give readwrite access to group users g:users:192 // give read,write and s_pruef access if someone is a member of the group users and also the owner (g:users,og:):200 @param String The current user name @param Array An Array of the current users groups' names @param Array An array of Access control definitions @param String The Owneruser of a record (optional) @param String The Ownergroup of a record (optional) */ private static function calculateACL($user,$groups,$acls, $owneruser=null,$ownergroup=null){ // default access is no access $accessmap = 0; foreach($acls as $acl){ if(strlen($acls <1)){ //invalid acl continue; } // if a fieldname starts with a '(' // then the first field contains an array of identifiers // like this (g:Meta,go:):READ // this can be used to express things like: If you are a member of the group Meta and of the owner group THEN you may have READAccess if(substr($acl,0,1) == '(') { $endPos = strpos($acl,')'); if($endPos === false){ // ( not closed, invalid acl continue; } $objects = explode(',',substr($acl,1,$endPos-1)); $objectaccess = explode(':',substr($acl,$endPos+1)); if(count($objectaccess) !=2){ // probably a missing ':' 0> invalid continue; } $objectaccess = $objectaccess[1]; // loop and see if all objects mentioned here are present in groups,user,ownergroup,owneruser or default $foundcounter = 0; foreach($objects as $object){ $objectfields = explode(":",$object); if(count($objectfields) != 2){ continue;} switch($objectfields[0]){ case "g": if(in_array($objectfields[1],$groups)){ $foundcounter++; } break; case "u": if($aclfields[1] ==$user){ $foundcounter++;} break; case "ou": if($owneruser &&($user == $owneruser)){ $foundcounter++;} break; case "og": if($ownergroup && (in_array($ownergroup,$groups))){$foundcounter++; } break; case "d": $foundcounter++; break; default: //invalid acl: continue; } } if($foundcounter == count($objects)){ $accessmap = $accessmap | $objectaccess; } continue; } $aclfields = explode(":",$acl); if(count($aclfields) != 3){ continue; } switch($aclfields[0]){ case "g": if(in_array($aclfields[1],$groups)){ $accessmap = $accessmap | $aclfields[2]; } break; case "u": if($aclfields[1] ==$user){ $accessmap = $accessmap | $aclfields[2]; } break; case "ou": if($owneruser &&($user == $owneruser)){ $accessmap = $accessmap | $aclfields[2]; } break; case "og": if($ownergroup && (in_array($ownergroup,$groups))){ $accessmap = $accessmap | $aclfields[2];} break; case "d": $accessmap = $accessmap | $aclfields[2]; break; default: //invalid acl: continue; } }; $e = new mb_notice("Accessmap for user: '$user', groups: ". print_r($groups,true) .". ACLs: ".print_r($acls,true). "owner: $owneruser:$ownergroup \n = ". base_convert($accessmap,10,2)); return $accessmap; } private static function lookupACL($status){ switch($status){ case "NEU": // must be in any of the three special groups to create records return array( "g:Metadatenerfasser:" . (string)(self::READ | self::WRITE | self::S_ERF), "g:Gruppenadministratoren:" . (string)(self::READ | self::WRITE | self::S_ERF), "g:Fachadministratoren:" . (string)(self::READ | self::WRITE | self::S_ERF) ); break; case MdMetadata::STATUS_REGISTER: return array( "ou::" . (string)(self::READ|self::WRITE), "og::" . (string)(self::READ), "(g:Metadatenerfasser,og:):" . (string)(self::WRITE| self::S_ERF | self::S_PRUEF), "(g:Gruppenadministratoren,og:):" . (string)(self::WRITE | self::S_ERF | self::S_PRUEF|self::S_GEPR), "g:Fachadministratoren:" . (string)(self::READ | self::WRITE|self::S_ERF|self::S_PRUEF| self::S_GEPR) ); break; case MdMetadata::STATUS_CHECK: return array( "ou::" . (string)(self::READ|self::WRITE), "og::" . (string)(self::READ), "g:Metadatenerfasser:" . (string)(self::READ), "(g:Metadatenerfasser,og:):" . (string)(self::WRITE|self::S_ERF|self::S_PRUEF), "(g:Gruppenadministratoren,og:):" . (string)(self::WRITE | self::S_ERF | self::S_PRUEF|self::S_GEPR), "g:Fachadministrator:" . (string)(self::READ | self::WRITE|self::S_ERF|self::S_PRUEF| self::S_GEPR) ); break; case MdMetadata::STATUS_CHECKED: return array( "ou::" . (string)(self::READ|self::WRITE), "og::" . (string)(self::READ), "g:Metadatenerfasser:".(string)(self::READ), "(g:Gruppenadministratoren,og:):" . (string)(self::WRITE | self::S_ERF | self::S_PRUEF|self::S_GEPR), "g:Fachadministratoren:" . (string)(self::READ | self::WRITE|self::S_ERF|self::S_PRUEF| self::S_GEPR|self::S_FREI) ); break; case MdMetadata::STATUS_APPROVED: return array( "d::". (string)(self::READ), "(og:,g:Metadatenerfasser):" . (string)(self::CLONE_DOC), "g:Fachadministratoren:" . (string)(self::READ | self::WRITE|self::S_ERF|self::S_PRUEF| self::S_GEPR|self::S_FREI) ); break; default: return array("d::0"); } } } ?>