uid == 1) { ini_set("display_errors", "On"); $_GET['wsf_debug'] = 1; error_reporting(E_ALL); } */ // cache_clear_all('variables', 'cache'); /*!@brief Main Drupal hook procedure @details This hook is the first one called by Drupal when one of the module's page is accessed. We use this hook to: \li Get the URI that has been accessed by the user \li Trigger the conStruct tool related to this URI by calling its main procedure. \n @return A string containing the HTML page description generated by the conStruct tool @author Frederick Giasson, Structured Dynamics LLC. \n\n\n */ function conStruct_main() { global $base_url; cache_clear_all('variables', 'cache'); drupal_set_html_head(""); // Get the extension of the URI requested to Drupal. $uri = $_GET['q']; if (stripos($uri, "conStruct/settings/cache") !== FALSE) { return conStruct_cache(); } return (t("Check conStruct tools in the right sidebar")); } /*! @brief Define menu items and page callbacks. @details This hook enables modules to register paths, which determines whose requests are to be handled. Depending on the type of registration requested by each path, a link is placed in the the navigation block and/or an item appears in the menu administration page (q=admin/menu). \n @return An array of menu items. Each menu item has a key corresponding to the Drupal path being registered. The item is an associative array. @author Frederick Giasson, Structured Dynamics LLC. @see http://api.drupal.org/api/function/hook_block \n\n\n */ function conStruct_menu() { $items = array(); // Registration of the conStruct module settings page path $items['admin/settings/conStruct'] = array( 'title' => t('conStruct Settings'), 'description' => t('Basic settings for a conStruct instance'), 'page callback' => 'drupal_get_form', 'page arguments' => array('conStruct_admin'), 'access arguments' => array('access administration pages'), 'type' => MENU_NORMAL_ITEM ); // Access settings menu $items['admin/settings/conStruct/access'] = array( 'title' => t('Access Settings'), 'description' => t('Access settings for node functions'), 'page callback' => 'drupal_get_form', 'page arguments' => array('conStruct_access_settings'), 'access arguments' => array('access administration pages'), 'type' => MENU_NORMAL_ITEM ); // Registration of the main conStruct module page path $items['conStruct'] = array( 'page callback' => 'conStruct_main', 'access callback' => 'conStruct_access_callback', 'type' => MENU_CALLBACK ); return $items; } function conStruct_form_alter(&$form, $form_state, $form_id) { if ($form_id == "dataset_node_form") { $form['#after_build'] = array('_conStruct_form_afterbuild'); } } function _conStruct_form_afterbuild($form, &$form_state) { // Change the field_wsf field of the Dataset type to add all the possible, registered, structWSF network addresses. if(isset($form["field_wsf"])) { $wsfAddresses = array(); $wsfRegistry = variable_get("WSF-Registry", array()); foreach($wsfRegistry as $s => $wsfs) { // get domain preg_match("/^(http:\/\/)?([^\/]+)/i", $wsfs, $domain_only); $host = $domain_only[2]; $wsfAddresses[$host] = $host; } $form['field_wsf']['value']['#options'] = $wsfAddresses; } return $form; } /*! @brief Declare a block or set of blocks. @details Any module can export a block (or blocks) to be displayed by defining the _block hook. This hook is called by theme.inc to display a block, and also by block.module to procure the list of available blocks. The functions mymodule_display_block_1 and 2, as used in the example, should of course be defined somewhere in your module and return the content you want to display to your users. If the "content" element is empty, no block will be displayed even if "subject" is present. After completing your blocks, do not forget to enable them in the block admin menu. \n @param[in] $op What kind of information to retrieve about the block or blocks. Possible values: @li 'list': A list of all blocks defined by the module. @li 'configure': Configuration form for the block. @li 'save': Save the configuration options. @li 'view': Process the block when enabled in a region in order to view its contents. @param[in] $delta Which block to return (not applicable if $op is 'list'). Although it is most commonly an integer starting at 0, this is not mandatory. For instance, aggregator.module uses string values for $delta. @param[in] $edit If $op is 'save', the submitted form data from the configuration form. @return If $op is 'list': An array of block descriptions. Each block description is an associative array. @author Frederick Giasson, Structured Dynamics LLC. @see http://api.drupal.org/api/function/hook_block \n\n\n */ function conStruct_block($op = 'list', $delta = 0, $edit = array()) { global $base_url; // The $op parameter determines what piece of information is being requested. switch ($op) { case 'list': // If $op is "list", we just need to return a list of block descriptions. // This is used to provide a list of possible blocks to the administrator, // end users will not see these descriptions. $blocks[0]['info'] = t('conStruct Settings'); return $blocks; case 'configure': // If $op is "configure", we need to provide the administrator with a // configuration form. The $delta parameter tells us which block is being // configured. In this example, we'll allow the administrator to customize // the text of the first block. $form = array(); if ($delta == 0) { // All we need to provide is a text field, Drupal will take care of // the other block configuration options and the save button. $form['block_example_string'] = array( '#type' => 'textfield', '#title' => t('Block contents'), '#size' => 100, '#description' => t('This string will appear in the conStruct Tools menu'), '#default_value' => variable_get('conStruct_string', t('')) ); } return $form; case 'save': // If $op is "save", we need to save settings from the configuration form. // Since the first block is the only one that allows configuration, we // need to check $delta to make sure we only save it. if ($delta == 0) { // Have Drupal save the string to the database. variable_set('conStruct_string', $edit['conStruct_string']); } return; case 'view': default: // If $op is "view", then we need to generate the block for display // purposes. The $delta parameter tells us which block is being requested. switch ($delta) { case 0: // The subject is displayed at the top of the block. Note that it // should be passed through t() for translation. $block['subject'] = t('conStruct Tools'); // The content of the block is typically generated by calling a custom // function. $block['content'] = conStruct_contents(1); break; } return $block; } } /*! @brief Display the conStruct side-bar menu items @details This function is called to generate the HTML of the tool lists being displayed in the side-bar. \n @return A string where the HTML menus have been defined. @author Frederick Giasson, Structured Dynamics LLC. \n\n\n */ function conStruct_contents($which_block) { global $base_url; global $user; if ($which_block == 1) { // Modules would typically perform some database queries to fetch the // content for their blocks. Here, we'll just use the variable set in the // block configuration or, if none has set, a default value. $localPath = $base_url . "/" . drupal_get_path("module", "conStruct") . "/imgs/"; $menuItems = ""; // For a specific user if (user_access('administer conStruct')) { $menuItems .= "\"\"" . t("Settings") . "
"; } if (user_access('access conStruct') && $user->uid) { /*! note: this procedure can have performence issue with big structWSF instances (big datasets). */ $menuItems .= "\"\"Access Settings
"; } if (user_access('access conStruct') && $user->uid && module_exists("structOntology")) { /*! note: this procedure can have performence issue with big structWSF instances (big datasets). */ $menuItems .= "\"\"Ontology Settings
"; } if (user_access('access conStruct') && $user->uid && module_exists("structScones")) { /*! note: this procedure can have performence issue with big structWSF instances (big datasets). */ $menuItems .= "\"\"Scones Settings
"; } return variable_get('conStruct_string', t($menuItems)); } } /*! @brief Define user permissions. @details This hook can supply permissions that the module defines, so that they can be selected on the user permissions page and used to restrict access to actions the module performs. The permissions in the array do not need to be wrapped with the function t(), since the string extractor takes care of extracting permission names defined in the perm hook for translation. Permissions are checked using user_access(). \n @note Currently only two kind of users exist: (1) "access" and (2) "administer". However, we expect to have more kind of users in the future for different node maintenance purposes @note Once new permissions are created, the node administrator has to set their permissions in the setting panel of the node @return An array of permissions strings. @author Frederick Giasson, Structured Dynamics LLC. @see http://api.drupal.org/api/function/hook_perm \n\n\n */ function conStruct_perm() { return array( 'access conStruct', 'administer conStruct' ); } /*! @brief Define access restrictions. @details This hook allows node modules to limit access to the node types they define. The administrative account (user ID #1) always passes any access check, so this hook is not called in that case. If this hook is not defined for a node type, all access checks will fail, so only the administrator will be able to see content of that type. However, users with the "administer nodes" permission may always view and edit content through the administrative interface. \n @warning The access hook is not yet implemented @param[in] $op The operation to be performed. Possible values: @li "create" @li "delete" @li "update" @li "view @param[in] $node The node on which the operation is to be performed, or, if it does not yet exist, the type of node to be created. @param[in] $account A user object representing the user for whom the operation is to be performed. @return TRUE if the operation is to be allowed; FALSE if the operation is to be denied; NULL to not override the settings in the node_access table, or access control modules. @author Frederick Giasson, Structured Dynamics LLC. @todo Implementing the access hook properly @see http://api.drupal.org/api/function/hook_access \n\n\n */ function conStruct_access($op, $node, $account) { return TRUE; } /*! @brief Access callback for the conStruct_main() page \n @warning The access hook callback function is not yet implemented @return TRUE if the operation is to be allowed; FALSE if the operation is to be denied; NULL to not override the settings in the node_access table, or access control modules. @author Frederick Giasson, Structured Dynamics LLC. @todo Implementing the callback function for the access hook @see http://api.drupal.org/api/function/hook_access \n\n\n */ function conStruct_access_callback() { return TRUE; } /*! @brief Create the settings form @details This procedure is called to create the settings form displayed to the administrator when the settings page of the conStruct module is accessed \n @note This procedure has been registered to Drupal in the conStruct_menu() procedure. @return A form object where all the settings have been defined. @author Frederick Giasson, Structured Dynamics LLC. @see http://drupal.org/node/206761 @see http://drupal.org/node/37775 \n\n\n */ function conStruct_admin() { global $base_url; // Nomalization of the URL of the node. Here we remove the "www" to normalize it. $normalized_base_url = str_replace("www.", "", $base_url); $graph = variable_get('conStruct_UrisDomain', str_replace("http://", "", get_domain($normalized_base_url))); // Creation of the settings form $form['conStruct_UrisDomain'] = array( '#type' => 'textfield', '#title' => t('Domain name used to resolve resources URIs'), '#default_value' => $graph, '#size' => 60, '#maxlength' => 1024, '#description' => t( "Each resource create, imported and updated on this system can be resolved on the Web. A conStruct website can have one or multiple domain names that can be used to access the resources indexed in the system. To make sure everything resolves to the same URIs, we have to set the canonical domain name used to create, and resolve, the resources identifiers."), '#required' => TRUE ); $form['conStruct_enableAutomaticIpChangeOnLogin'] = array( '#type' => 'checkbox', '#title' => t('Automatic users IP Change on login'), '#description' => t( "This option let you turn on/off the feature that automatically update the IP of the users if they change computer. This option is turned off by default. In that case, users have to change it manually using the 'access settings' page."), '#default_value' => variable_get('conStruct_enableAutomaticIpChangeOnLogin', 0), ); return system_settings_form($form); } /*! @brief Validate the settings form @details This procedure validate the fields filled by the administrator \n @note This procedure is called by Drupal Core each time a setting is saved. @param[in] $form is the form ID of the passed form @param[out] $form_state are the form values which you may perform validation on @return Nothing is successful. Returns a form error with the error message if the validation failed. @author Frederick Giasson, Structured Dynamics LLC. @see http://drupal.org/node/206761 @see http://drupal.org/node/37775 \n\n\n */ function conStruct_admin_validate($form, &$form_state) { // Get the current graph URI parameter $uri = $form_state['values']['conStruct_UrisDomain']; // If the URI is lesser tan 16 characters, return an error if (strlen($uri) <= 8) { form_set_error('conStruct_UrisDomain', t('The URI of the base graph should have at least 8 characters')); } else{ // Perform special handling of that URI } } /*! @brief Access settings \n @note This procedure has been registered to Drupal in the conStruct_menu() procedure. @return A form object where all the settings have been defined. @author Frederick Giasson, Structured Dynamics LLC. @see http://drupal.org/node/206761 @see http://drupal.org/node/37775 \n\n\n */ function conStruct_access_settings() { global $base_url; global $user; // Creation of the settings form $form["conStruct_AccessUser" . $user->uid] = array( '#type' => 'textfield', '#title' => t('The IP address you will use to query the web services related to this node. (you current IP: ' . $_SERVER['REMOTE_ADDR'] . ')'), '#default_value' => variable_get("conStruct_AccessUser" . $user->uid, ""), '#size' => 60, '#maxlength' => 1024, '#description' => t( "Each node user can be bound with a IP address. This IP address is the address that can be used to query any web services, and datasets, available to that user."), '#required' => FALSE ); return system_settings_form($form); } /*! @brief Validate access settings \n @param[in] $form Form to validate @param[out] $form_state @author Frederick Giasson, Structured Dynamics LLC. @see http://drupal.org/node/206761 @see http://drupal.org/node/37775 \n\n\n */ function conStruct_access_settings_validate($form, &$form_state) { global $user; updateUserIpOnNetworks($form_state['values']["conStruct_AccessUser" . $user->uid]); } /*! @brief Update the IP of a user on linked structWSF instances. \n @param[in] $newIP The new IP of the user to update. @return Returns final (it could have been changed from the input variable) the new IP assigned by the procedure. @author Frederick Giasson, Structured Dynamics LLC. \n\n\n */ function updateUserIpOnNetworks($newIP) { global $user; // Check if the IP is being changed. $oldIP = variable_get("conStruct_AccessUser" . $user->uid, ""); if ($newIP == "") { $newIP = "self::$user->uid"; } if ($oldIP == "") { $oldIP = "self::$user->uid"; } include_once('./' . drupal_get_path('module', 'conStruct') . '/framework/WebServiceQuerier.php'); include_once('./' . drupal_get_path('module', 'conStruct') . '/framework/ProcessorXML.php'); // If it changed, we have to fix the access accordingly. if ($oldIP != $newIP) { // Fix for each linked WSF $wsfRegistry = variable_get("WSF-Registry", array()); if(count($wsfRegistry) > 0) { $includedWsfAddresses = array(); $sidRegistry = variable_get("SID-Registry", ""); foreach ($wsfRegistry as $wsfAddress) { $sid = ""; // Make sure that we don't query the same server twice foreach ($sidRegistry as $s => $wsfs) { if (array_search($wsfAddress, $wsfs) !== FALSE) { $sid = $s; } } if ($sid !== FALSE && array_search($sid, $includedWsfAddresses) === FALSE) { array_push($includedWsfAddresses, $sid); } else { continue; } // Get all access descriptions for the old IP $wsq = new WebServiceQuerier($wsfAddress . "auth/lister/", "get", "text/xml", "registered_ip=" . urlencode($oldIP) . "&mode=access_user"); if ($wsq->getStatus() == 200) { $xml = new ProcessorXML(); $xml->loadXML($wsq->getResultset()); $accesses = $xml->getSubjectsByType("wsf:Access"); foreach ($accesses as $access) { $webServiceAccesses = ""; $datasetAccess = ""; $crud = ""; $registeredIP = ""; $access_uri = $xml->getURI($access); // Get registered ip $predicates = $xml->getPredicatesByType($access, "wsf:registeredIP"); $objects = $xml->getObjectsByType($predicates->item(0), "rdfs:Literal"); $registeredIP = $xml->getContent($objects->item(0)); // Get datasetAccess $predicates = $xml->getPredicatesByType($access, "wsf:datasetAccess"); $objects = $xml->getObjectsByType($predicates->item(0), "void:Dataset"); $datasetAccess = $xml->getURI($objects->item(0)); // Get crud $predicates = $xml->getPredicatesByType($access, "wsf:create"); $objects = $xml->getObjectsByType($predicates->item(0), "rdfs:Literal"); $crud = $xml->getContent($objects->item(0)) . ";"; $predicates = $xml->getPredicatesByType($access, "wsf:read"); $objects = $xml->getObjectsByType($predicates->item(0), "rdfs:Literal"); $crud .= $xml->getContent($objects->item(0)) . ";"; $predicates = $xml->getPredicatesByType($access, "wsf:update"); $objects = $xml->getObjectsByType($predicates->item(0), "rdfs:Literal"); $crud .= $xml->getContent($objects->item(0)) . ";"; $predicates = $xml->getPredicatesByType($access, "wsf:delete"); $objects = $xml->getObjectsByType($predicates->item(0), "rdfs:Literal"); $crud .= $xml->getContent($objects->item(0)); // Get webServiceAccess(es) $webservicesType = $xml->getPredicatesByType($access, "wsf:webServiceAccess"); foreach ($webservicesType as $webserviceElement) { $webservicesTypeObj = $xml->getObjects($webserviceElement); foreach ($webservicesTypeObj as $wto) { $webServiceAccesses .= $xml->getURI($wto) . ";"; } } $webServiceAccesses = substr($webServiceAccesses, 0, strlen($webServiceAccesses) - 1); // Make sure we don't change the permissions of the World Readable default IP (0.0.0.0) if ($registeredIP != "0.0.0.0") { // Update the access for this new IP for this Access. $wsq = new WebServiceQuerier($wsfAddress . "auth/registrar/access/", "post", "text/xml", "registered_ip=" . urlencode($newIP) . "&crud=$crud&ws_uris=" . urlencode($webServiceAccesses) . "&dataset=" . urlencode($datasetAccess) . "&action=update&target_access_uri=" . urlencode($access_uri)); if ($wsq->getStatus() != 200) { // Throw an error $wsq->displayError(); } } } } else { // Throw an error $wsq->displayError(); } } } } return($newIP); } /*! @brief Handle user action (implementation of the hook_user Drupal hook) @details This hook allows modules to react when operations are performed on user accounts. This hook is implemented to change the IP address of a user each time he log in. If its IP address changed, then it will be updated on some related structWSF instances. @param[in] $op What kind of action is being performed. Possible values (in alphabetical order) @param[in] $edit The array of form values submitted by the user. @param[in] $account The user object on which the operation is being performed. @param[in] $category The active category of user information being edited. \n @author Frederick Giasson, Structured Dynamics LLC. @see http://api.drupal.org/api/function/hook_user \n\n\n */ function conStruct_user($op, &$edit, &$account, $category = NULL) { switch($op) { case "login": case "view": $enabled = variable_get("conStruct_enableAutomaticIpChangeOnLogin", 0); if($enabled == 1) { global $user; /* Each time a user login, or view its user page, we have to check if its his IP address changed. If it did, then we will change it on the different structWSF instances where he has accesses defined for him. We do exactly the same procedure for a "view", because some users can still be logged in with their laptop computer, and changed their location (from home to internet coffee by exaple). */ /* A special case. If the operation is "view", then we have to make sure that the user that view the page, is the one that is logged in. Otherwise, it would "spoof" the user! */ if($op == "view" && ($account->uid != $user->uid)) { return; } /* Get the current IP of the user and process the IP change */ if(isset($_SERVER['REMOTE_ADDR'])) { $newIP = updateUserIpOnNetworks($_SERVER['REMOTE_ADDR']); /* Assign the newIP into Drupal's variable registry. */ /* If the new IP is a "self" IP, then we simply assign an empty string to it. We have to proceed that way because it is what the software is expecting. We are only mimicing what the "settings save" behavior of Drupal. */ if(strtolower(substr($newIP, 0, 4)) == "self") { $newIP = ""; } variable_set("conStruct_AccessUser" . $user->uid, $newIP); } return; } break; } } /*! @brief Handle Organic Groups changes @details Hook Organic Groups to handle user subscription / unsubscription @param[in] $op Operation done by OG @param[in] $gid Group ID @param[in] $uid User ID @param[in] $args Arguments of the hook \n @author Frederick Giasson, Structured Dynamics LLC. @see http://api.drupal-contrib.org/api/function/hook_og @see http://api.freestylesystems.co.uk/api/function/og_og/6 \n\n\n */ function conStruct_og($op, $gid, $uid, $args) { include_once('./' . drupal_get_path('module', 'conStruct') . '/framework/WebServiceQuerier.php'); include_once('./' . drupal_get_path('module', 'conStruct') . '/framework/ProcessorXML.php'); global $base_url; switch ($op) { case "user insert": // We have to check if a "dataset" is already created for that group. If it is not, this means that // this user is the owner of this dataset. The problem here is the execution order of hooks in drupal. // "hook_og" which manage the subscription of users is executed BEFORE hook_nodeapi which manage the // creation of groups (datasets). $wsfAddress = variable_get("Dataset-" . $gid . "-WSF", ""); $wsfAddressCreated = variable_get("Dataset-" . $gid . "-WSF-Created", ""); // Make sure we don't recreate the admin of this dataset twice if ($wsfAddressCreated != "") { variable_del("Dataset-" . $gid . "-WSF-Created"); return; } if ($wsfAddress != "") { // If we are in face of a linked dataset, we have to use the linked dataset URI as the // target URI for this WSF query. $linkedDatasetRegistry = variable_get("Linked-Dataset-Registry", ""); $targetDataset = variable_get("Dataset-" . $gid . "-ID", get_domain($base_url) . "/wsf/datasets/" . $gid . "/"); if ($linkedDatasetRegistry != "") { if (isset($linkedDatasetRegistry[$gid])) { $targetDataset = $linkedDatasetRegistry[$gid]; } } $wsq = new WebServiceQuerier($wsfAddress . "dataset/read/", "get", "text/xml", "uri=" . urlencode($targetDataset)); $datasetCreated = TRUE; if ($wsq->getStatus() != 200) { // Throw an error if ($wsq->getStatusMessageDescription() != "This dataset doesn't exist in this WSF") { $wsq->displayError(); } } else { // If a new user get subscribed to a group, we have to check if an access IP is defined for him. // If there is one, we have to create an access for it. $userIP = variable_get("conStruct_AccessUser" . $uid, ""); if ($userIP == "") { // If there is no IP for that user, we overload the IP of the node with "::" $userIP = "self::$uid"; } $wsfAddress = variable_get("Dataset-" . $gid . "-WSF", ""); if ($wsfAddress != "") { $wsq = new WebServiceQuerier($wsfAddress . "auth/lister/", "get", "text/xml", "mode=ws"); if ($wsq->getStatus() == 200) { // Get all web services $webservices = ""; $xml = new ProcessorXML(); $xml->loadXML($wsq->getResultset()); $webServiceElements = $xml->getXPath('//predicate/object[attribute::type="wsf:WebService"]'); foreach ($webServiceElements as $element) { $webservices .= $xml->getURI($element) . ";"; } $webservices = substr($webservices, 0, strlen($webservices) - 1); unset($wsq); unset($xml); global $base_url; // By default CRUD is to "False;True;False;False". It is the duty of the dataset administrator // to setup the proper CUD permissions for each user that have access to the dataset. /* $wsq = new WebServiceQuerier($wsfAddress."auth/registrar/access/", "post", "text/xml", "registered_ip=$userIP&crud=False;True;False;False&ws_uris". "=$webservices&dataset=$targetDataset&action=create"); */ // If the user is an administrator, we give him full CRU. Otherwiser we give only R $resultset = db_query( 'SELECT {role}.name FROM {users_roles} INNER JOIN {role} ON {role}.rid = {users_roles}.rid WHERE uid=%d ', $uid); $roleNames = array(); // Get all WSF address still in use while ($roleName = db_result($resultset)) { array_push($roleNames, $roleName); } if (array_search("owner/curator", $roleNames) !== FALSE) { $wsq = new WebServiceQuerier($wsfAddress . "auth/registrar/access/", "post", "text/xml", "registered_ip=" . urlencode($userIP) . "&crud=True;True;True;True&ws_uris" . "=" . urlencode($webservices) . "&dataset=" . urlencode($targetDataset) . "&action=create"); } elseif (array_search("admin", $roleNames) !== FALSE) { $wsq = new WebServiceQuerier($wsfAddress . "auth/registrar/access/", "post", "text/xml", "registered_ip=" . urlencode($userIP) . "&crud=True;True;True;True&ws_uris" . "=" . urlencode($webservices) . "&dataset=" . urlencode($targetDataset) . "&action=create"); } else { $wsq = new WebServiceQuerier($wsfAddress . "auth/registrar/access/", "post", "text/xml", "registered_ip=" . urlencode($userIP) . "&crud=False;True;False;False&ws_uris" . "=" . urlencode($webservices) . "&dataset=" . urlencode($targetDataset) . "&action=create"); } if ($wsq->getStatus() != 200) { // Throw an error if ($wsq->getStatusMessageDescription() != "This dataset doesn't exist in this WSF") { $wsq->displayError(); } } unset($wsq); // We have to add a reference, as a contributor of the dataset, in the description of the dataset. $wsq = new WebServiceQuerier($wsfAddress . "dataset/read/", "get", "text/xml", "uri=" . urlencode($targetDataset)); $contributors = ""; if ($wsq->getStatus() != 200) { // Throw an error if ($wsq->getStatusMessageDescription() != "This dataset doesn't exist in this WSF") { $wsq->displayError(); } } else { $xml = new ProcessorXML(); $xml->loadXML($wsq->getResultset()); $datasets = $xml->getSubjectsByType("void:Dataset"); $predicates = $xml->getPredicatesByType($datasets->item(0), "dcterms:contributor"); foreach ($predicates as $predicate) { $objects = $xml->getObjectsByType($predicate, "sioc:User"); $contributors .= $xml->getURI($objects->item(0)) . ";"; } } $contributors .= $base_url . "/user/" . $uid . "/;"; $contributors = substr($contributors, 0, strlen($contributors) - 1); unset($wsq); $wsq = new WebServiceQuerier($wsfAddress . "dataset/update/", "post", "text/xml", "uri=" . urlencode($targetDataset) . "&contributors=" . urlencode($contributors)); if ($wsq->getStatus() != 200) { // Throw an error if ($wsq->getStatusMessageDescription() != "This dataset doesn't exist in this WSF") { $wsq->displayError(); } } } else { $wsq->displayError(); } } else { drupal_set_message(t("No WSF address linked to this dataset"), "error", TRUE); } } } break; case "user update": // Trigged at dataset creation. // Trigged when the manager of a group is changed. break; case "user delete": global $base_url; // Delete the Access for that user since he has been unsubscribed from that group. $userIP = variable_get("conStruct_AccessUser" . $uid, ""); if ($userIP == "") { // If there is no IP for that user, we overload the IP of the node with "::" $userIP = "self::$uid"; } // If we are in face of a linked dataset, we have to use the linked dataset URI as the target URI for this // WSF query. $linkedDatasetRegistry = variable_get("Linked-Dataset-Registry", ""); $targetDataset = variable_get("Dataset-" . $gid . "-ID", get_domain($base_url) . "/wsf/datasets/" . $gid . "/"); if ($linkedDatasetRegistry != "") { if (isset($linkedDatasetRegistry[$gid])) { $targetDataset = $linkedDatasetRegistry[$gid]; } } $wsfAddress = variable_get("Dataset-" . $gid . "-WSF", ""); if ($wsfAddress != "") { $wsq = new WebServiceQuerier($wsfAddress . "auth/registrar/access/", "post", "text/xml", "registered_ip=" . urlencode($userIP) . "&dataset=" . urlencode($targetDataset) . "&action=delete_target"); if ($wsq->getStatus() != 200) { $wsq->displayError(); } unset($wsq); // Delete the contributor reference in the dataset description $wsq = new WebServiceQuerier($wsfAddress . "dataset/read/", "get", "text/xml", "uri=" . urlencode($targetDataset)); $contributors = ""; if ($wsq->getStatus() != 200) { $wsq->displayError(); } else { $xml = new ProcessorXML(); $xml->loadXML($wsq->getResultset()); $datasets = $xml->getSubjectsByType("void:Dataset"); $predicates = $xml->getPredicatesByType($datasets->item(0), "dcterms:contributor"); foreach ($predicates as $predicate) { $objects = $xml->getObjectsByType($predicate, "sioc:User"); if ($xml->getURI($objects->item(0)) != $base_url . "/user/" . $uid . "/") { $contributors .= $xml->getURI($objects->item(0)) . ";"; } } } $contributors = substr($contributors, 0, strlen($contributors) - 1); unset($wsq); $wsq = new WebServiceQuerier($wsfAddress . "dataset/update/", "post", "text/xml", "uri=" . urlencode($targetDataset) . "&contributors=" . urlencode($contributors)); if ($wsq->getStatus() != 200) { $wsq->displayError(); } } else { drupal_set_message(t("No WSF address linked to this dataset"), "error", TRUE); } break; /* case "admin new": break; case "admin create": break; */ } } /*! @brief Monitor everything tha happens on Drupal \n @author Frederick Giasson, Structured Dynamics LLC. \n\n\n */ function conStruct_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) { include_once('./' . drupal_get_path('module', 'conStruct') . '/framework/WebServiceQuerier.php'); include_once('./' . drupal_get_path('module', 'conStruct') . '/framework/ProcessorXML.php'); switch ($op) { case 'validate': if (strtolower($node->op) != "delete") // Don't validate on a delete operation { if (og_is_group_type($node->type) && $node->type == "dataset") { // Make sure the WSF is registered to that node $wsfn = variable_get("WSF-Registry", array()); if(array_search("http://".$node->field_wsf[0]["value"]."/ws/", $wsfn) === FALSE) { form_set_error($node->field_wsf[0]["_error_element"], t("This WSF is not registered in this conStruct node. Please register it using the Networks module.")); return; } if(isset($node->field_custom_dataset_uri[0]["value"]) && $node->field_custom_dataset_uri[0]["value"] != "") { // Make sure that if a custom dataset has been defined that we don't duplicate it. $resultset = db_query('SELECT nid FROM {og}'); while($datasetId = db_result($resultset)) { if(variable_get("Dataset-" . $datasetId . "-ID", "") == $node->field_custom_dataset_uri[0]["value"]) { if($node->body == "Import") { form_set_error($node->field_custom_dataset_uri[0]["_error_element"], t("The dataset file you imported has been appended to the existing dataset referenced by the custom URI you provided.")); } else { form_set_error($node->field_custom_dataset_uri[0]["_error_element"], t("This custom dataset URI is already used by another dataset. Please choose another one and create it again.")); } return; } } } if ($node->field_existing_dataset_uri[0]["value"] != "") { // Make sure that the linked dataset is not already linked by another group $linkedDatasetRegistry = variable_get("Linked-Dataset-Registry", ""); if ($linkedDatasetRegistry != "") { $id = array_search($node->field_existing_dataset_uri[0]["value"], $linkedDatasetRegistry); if($id !== FALSE && $id != $node->nid) { form_set_error($node->field_existing_dataset_uri[0]["_error_element"], t("A group of this Drupal node is already linked to this dataset URI")); return; } } // Make sure the WSF is existing & that the dataset is existing $wsq = new WebServiceQuerier("http://" . $node->field_wsf[0]["value"] . "/ws/" . "dataset/read/", "get", "text/xml", "uri=" . urlencode($node->field_existing_dataset_uri[0]["value"])); if ($wsq->getStatus() != 200) { if ($wsq->getStatus() == 503) { form_set_error($node->field_wsf[0]["_error_element"], t("This WSF address is not existing or unreachable")); return; } form_set_error($node->field_existing_dataset_uri[0]["_error_element"], t("Web service error: (status: @status) @status_message - @status_message_description", array( "status_message" => strip_tags($wsq->getStatusMessage()), "status_message_description" => strip_tags($wsq->getStatusMessageDescription()) ))); return; } } } } break; case 'insert': // Handling OG group creation if (og_is_group_type($node->type) && $node->type == "dataset") { global $user; global $base_url; // Save the WSF IP for this newly created dataset variable_set("Dataset-" . $node->nid . "-WSF", "http://" . $node->field_wsf[0]["value"] . "/ws/"); variable_set("Dataset-" . $node->nid . "-WSF-Created", "true"); if(isset($node->field_custom_dataset_uri[0]["value"]) && $node->field_custom_dataset_uri[0]["value"] != "") { variable_set("Dataset-" . $node->nid . "-ID", $node->field_custom_dataset_uri[0]["value"]); } else { variable_set("Dataset-" . $node->nid . "-ID", ""); } $wsfAddress = variable_get("Dataset-" . $node->nid . "-WSF", ""); // Save this new WSF address into the WSF registery $wsfRegistry = variable_get("WSF-Registry", array()); if (array_search($wsfAddress, $wsfRegistry) === FALSE) { array_push($wsfRegistry, $wsfAddress); variable_set("WSF-Registry", $wsfRegistry); } // Now, lets recreate the SID-Registry structure $sidRegistry = array(); foreach ($wsfRegistry as $wsfa) { $ch = curl_init(); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_URL, $wsfa . "index.php"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); $data = curl_exec($ch); if (curl_errno($ch)) { curl_close($ch); continue; } $data = trim($data); if (!isset($sidRegistry[$data])) { $sidRegistry[$data] = array($wsfa); } else { array_push($sidRegistry[$data], $wsfa); } curl_close($ch); } // Save the SID-Registry variable_set("SID-Registry", $sidRegistry); // Check if a remote dataset URI as been defined if(isset($node->field_existing_dataset_uri[0]["value"]) && $node->field_existing_dataset_uri[0]["value"] != "") { // Save the local group ID and the remote group ID in the Remote WSF registry $linkedDatasetRegistry = variable_get("Linked-Dataset-Registry", ""); if ($linkedDatasetRegistry == "") { $linkedDatasetRegistry = array(); } $linkedDatasetRegistry[$node->nid] = $node->field_existing_dataset_uri[0]["value"]; $targetDataset = $linkedDatasetRegistry[$node->nid]; variable_set("Dataset-" . $node->nid . "-ID", $targetDataset); variable_set("Linked-Dataset-Registry", $linkedDatasetRegistry); // If we link to an existing dataset, we register the user with full crud if he is an admin, or the // owner/curator of the conStruct node instance (CRUD == True;True;True;True.) Otherwise, he will get the // collaborator (CRUD == False;True;False;False) permissions. // it is up to the creator of the remote dataset to change these permissions to this user. // Note: we can't create this permission in hook_og.php for the only reason that this hook get executed // BEFORE this one. So the linkage is not yet done at that time. $wsq = new WebServiceQuerier($wsfAddress . "dataset/read/", "get", "text/xml", "uri=" . urlencode($targetDataset)); if($wsq->getStatus() == 200) { // If a new user get subscribed to a group, we have to check if an access IP is defined for him. If there // is one, we have to create an access for it. $userIP = variable_get("conStruct_AccessUser" . $user->uid, ""); if ($userIP == "") { // If there is no IP for that user, we overload the IP of the node with "::" $userIP = "self::$user->uid"; } $wsfAddress = variable_get("Dataset-" . $node->nid . "-WSF", ""); if ($wsfAddress != "") { $wsq = new WebServiceQuerier($wsfAddress . "auth/lister/", "get", "text/xml", "mode=ws"); if ($wsq->getStatus() == 200) { // Get all web services $webservices = ""; $xml = new ProcessorXML(); $xml->loadXML($wsq->getResultset()); $webServiceElements = $xml->getXPath('//predicate/object[attribute::type="wsf:WebService"]'); foreach ($webServiceElements as $element) { $webservices .= $xml->getURI($element) . ";"; } $webservices = substr($webservices, 0, strlen($webservices) - 1); unset($wsq); unset($xml); global $base_url; // Check to see what role the user has on the node, and then specify the proper permissions for him. $resultset = db_query( 'SELECT {role}.name FROM {users_roles} INNER JOIN {role} ON {role}.rid = {users_roles}.rid WHERE uid=%d ', $user->uid); $roleNames = array(); // Get all WSF address still in use while ($roleName = db_result($resultset)) { array_push($roleNames, $roleName); } if (array_search("owner/curator", $roleNames) !== FALSE) { $wsq = new WebServiceQuerier($wsfAddress . "auth/registrar/access/", "post", "text/xml", "registered_ip=" . urlencode($userIP) . "&crud=True;True;True;True&ws_uris" . "=" . urlencode($webservices) . "&dataset=" . urlencode($targetDataset) . "&action=create"); } elseif (array_search("admin", $roleNames) !== FALSE) { $wsq = new WebServiceQuerier($wsfAddress . "auth/registrar/access/", "post", "text/xml", "registered_ip=" . urlencode($userIP) . "&crud=True;True;True;True&ws_uris" . "=" . urlencode($webservices) . "&dataset=" . urlencode($targetDataset) . "&action=create"); } else { $wsq = new WebServiceQuerier($wsfAddress . "auth/registrar/access/", "post", "text/xml", "registered_ip=" . urlencode($userIP) . "&crud=False;True;False;False&ws_uris" . "=" . urlencode($webservices) . "&dataset=" . urlencode($targetDataset) . "&action=create"); } if ($wsq->getStatus() != 200) { // Throw an error if ($wsq->getStatusMessageDescription() != "This dataset doesn't exist in this WSF") { $wsq->displayError(); } } unset($wsq); // We have to register the VO node with all permission to properly manage this dataset $wsq = new WebServiceQuerier($wsfAddress . "auth/registrar/access/", "post", "text/xml", "registered_ip=self&crud=True;True;True;True&ws_uris=" . urlencode($webservices) . "&dataset=" . urlencode($targetDataset) . "&action=create"); if ($wsq->getStatus() != 200) { // Throw an error if ($wsq->getStatusMessageDescription() != "This dataset doesn't exist in this WSF") { $wsq->displayError(); } } unset($wsq); // We have to add a reference, as a contributor of the dataset, in the description of the dataset. $wsq = new WebServiceQuerier($wsfAddress . "dataset/read/", "get", "text/xml", "uri=" . urlencode($targetDataset)); $contributors = ""; if ($wsq->getStatus() != 200) { // Throw an error if ($wsq->getStatusMessageDescription() != "This dataset doesn't exist in this WSF") { $wsq->displayError(); } } else { $xml = new ProcessorXML(); $xml->loadXML($wsq->getResultset()); $datasets = $xml->getSubjectsByType("void:Dataset"); $predicates = $xml->getPredicatesByType($datasets->item(0), "dcterms:contributor"); foreach ($predicates as $predicate) { $objects = $xml->getObjectsByType($predicate, "sioc:User"); $contributors .= $xml->getURI($objects->item(0)) . ";"; } } $contributors .= $base_url . "/user/" . $user->uid . "/;"; $contributors = substr($contributors, 0, strlen($contributors) - 1); unset($wsq); $wsq = new WebServiceQuerier($wsfAddress . "dataset/update/", "post", "text/xml", "uri=" . urlencode($targetDataset) . "&contributors=" . urlencode($contributors)); if ($wsq->getStatus() != 200) { // Throw an error if ($wsq->getStatusMessageDescription() != "This dataset doesn't exist in this WSF") { $wsq->displayError(); } } } else { $wsq->displayError(); } } else { drupal_set_message(t("No WSF address linked to this dataset"), "error", TRUE); } } else { $wsq->displayError(); } } else { // If we are not linking the group to an existing dataset, we have to create it on the WSF // Creating new Dataset $title = db_result(db_query('SELECT title FROM {node} WHERE nid=%d LIMIT 1', $node->nid)); $description = db_result(db_query('SELECT og_description FROM {og} WHERE nid=%d LIMIT 1', $node->nid)); $baseDomain = variable_get("conStruct_UrisDomain", get_domain($base_url)); $newDatasetUri = variable_get("Dataset-" . $node->nid . "-ID", ""); if($newDatasetUri == "") { // If no custom datasets have been defined, we use a generic one composed of its organic groups ID. $newDatasetUri = (strpos($baseDomain, "http://") === FALSE ? "http://" . $baseDomain : $baseDomain) . "/wsf/datasets/" . $node->nid . "/"; variable_set("Dataset-" . $node->nid . "-ID", $newDatasetUri); } $wsq = new WebServiceQuerier($wsfAddress . "dataset/create/", "post", "text/xml", "uri=" . urlencode($newDatasetUri) . "&title=" . urlencode($title) . "&description=" . urlencode($description) . "&creator=" . urlencode($base_url . "/user/" . $user->uid . "/")); if ($wsq->getStatus() != 200) { $wsq->displayError(); return; } unset($wsq); // Creation of a full access for this VO node. Once it is done, it is the node that will manage interaction // between users and the dataset. // create a new cURL resource if (isset($_SERVER['REMOTE_ADDR'])) { $wsq = new WebServiceQuerier($wsfAddress . "auth/lister/", "get", "text/xml", "mode=ws"); if ($wsq->getStatus() == 200) { // Get all web services $webservices = ""; $xml = new ProcessorXML(); $xml->loadXML($wsq->getResultset()); $webServiceElements = $xml->getXPath('//predicate/object[attribute::type="wsf:WebService"]'); foreach ($webServiceElements as $element) { $webservices .= $xml->getURI($element) . ";"; } $webservices = substr($webservices, 0, strlen($webservices) - 1); unset($xml); if ($webservices == "") { $wsq->displayError(); return; } unset($wsq); // Create the access, of this VO node, to all registered web services of the WSF global $base_url; // Take care with PHP's $_SERVER['SERVER_ADDR'] and EC2 instances. This variable is the private DNS IP // of the instance, AND NOT its IP accessible on the web. $baseDomain = variable_get("conStruct_UrisDomain", get_domain($base_url)); $wsq = new WebServiceQuerier($wsfAddress . "auth/registrar/access/", "post", "text/xml", "registered_ip=self&crud=true;true;true;true&ws_uris=" . urlencode($webservices) . "&dataset=" . urlencode($newDatasetUri) . "&action=create"); if ($wsq->getStatus() != 200) { $wsq->displayError(); } } else { $wsq->displayError(); } } // We have to register the "public" user that has the "0.0.0.0" IP address // By default this public user has no permissions $baseDomain = variable_get("conStruct_UrisDomain", get_domain($base_url)); $wsq = new WebServiceQuerier($wsfAddress . "auth/registrar/access/", "post", "text/xml", "registered_ip=0.0.0.0&crud=False;False;False;False&ws_uris=" . urlencode($webservices) . "&dataset=" . urlencode($newDatasetUri) . "&action=create"); if ($wsq->getStatus() != 200) { // Throw an error if ($wsq->getStatusMessageDescription() != "This dataset doesn't exist in this WSF") { $wsq->displayError(); } } unset($wsq); // Registration of the administrator of this node global $user; $userIP = variable_get("conStruct_AccessUser" . $user->uid, ""); if ($userIP == "") { // If there is no IP for that user, we overload the IP of the node with "::" $userIP = "self::$user->uid"; } $wsq = new WebServiceQuerier($wsfAddress . "auth/lister/", "get", "text/xml", "mode=ws"); if ($wsq->getStatus() == 200) { // Get all web services $webservices = ""; $xml = new ProcessorXML(); $xml->loadXML($wsq->getResultset()); $webServiceElements = $xml->getXPath('//predicate/object[attribute::type="wsf:WebService"]'); foreach ($webServiceElements as $element) { $webservices .= $xml->getURI($element) . ";"; } $webservices = substr($webservices, 0, strlen($webservices) - 1); unset($wsq); unset($xml); $baseDomain = variable_get("conStruct_UrisDomain", get_domain($base_url)); $wsq = new WebServiceQuerier($wsfAddress . "auth/registrar/access/", "post", "text/xml", "registered_ip=" . urlencode($userIP) . "&crud=True;True;True;True&ws_uris=$webservices&dataset=" . urlencode($newDatasetUri) . "&action=create"); if ($wsq->getStatus() != 200) { $wsq->displayError(); } unset($wsq); } else { $wsq->displayError(); } } } break; case 'delete': // Handling OG group deletation if (og_is_group_type($node->type) && $node->type == "dataset") { $wsfAddress = variable_get("Dataset-" . $node->nid . "-WSF", ""); variable_del("Dataset-" . $node->nid . "-WSF"); $datasetUri = variable_get("Dataset-" . $node->nid . "-ID", get_domain($base_url) . "/wsf/datasets/" . $node->nid . "/"); variable_del("Dataset-" . $node->nid . "-ID"); // Clean up the WSF-Registry /* Not necessary anymore since we are now using structNetwork to manage the WSF-Registry. */ /* $resultset = db_query('SELECT nid FROM {og}'); $usedWsf = array(); // Get all WSF address still in use while ($nid = db_result($resultset)) { $wsf = variable_get("Dataset-" . $nid . "-WSF", ""); if (array_search($wsf, $usedWsf) === FALSE && $wsf != "") { array_push($usedWsf, $wsf); } } // Recreate the WSF-Registry according to this list variable_set("WSF-Registry", $usedWsf); */ // Check if it was a linked dataset. If it was, we only remove it from the linked dataset registry of this // drupal node $linkedDatasetRegistry = variable_get("Linked-Dataset-Registry", ""); if ($linkedDatasetRegistry != "") { if (isset($linkedDatasetRegistry[$node->nid])) { // Lets remove the remove accesses to this dataset for each user of this group $resultset = db_query('SELECT uid FROM {og_uid} WHERE nid=%d', $node->nid); while ($uid = db_result($resultset)) { $userIP = variable_get("conStruct_AccessUser" . $uid, ""); if ($userIP == "") { // If there is no IP for that user, we overload the IP of the node with "::" $userIP = "self::$uid"; } $wsq = new WebServiceQuerier($wsfAddress . "auth/registrar/access/", "post", "text/xml", "registered_ip=" . urlencode($userIP) . "&dataset=" . urlencode($linkedDatasetRegistry[$node->nid]) . "&action=delete_target"); if ($wsq->getStatus() != 200) { $wsq->displayError(); } unset($wsq); } // Then remove the access of this VO node $wsq = new WebServiceQuerier($wsfAddress . "auth/registrar/access/", "post", "text/xml", "registered_ip=self&dataset=" . urlencode($linkedDatasetRegistry[$node->nid]) . "&action=delete_target"); // Finally, lets drop the linkage to this dataset and this group unset($linkedDatasetRegistry[$node->nid]); variable_set("Linked-Dataset-Registry", $linkedDatasetRegistry); return; } } // Otherwise, we delete the dataset that has been previously created global $base_url; if ($wsfAddress != "") { $wsq = new WebServiceQuerier($wsfAddress . "dataset/delete/", "get", "text/xml", "uri=" . urlencode($datasetUri)); if ($wsq->getStatus() != 200) { $wsq->displayError(); return; } } else { drupal_set_message(t("No WSF address linked to this dataset"), "error", TRUE); } } break; case 'update': // Handling OG group update if (og_is_group_type($node->type) && $node->type == "dataset") { global $base_url; $wsfAddress = variable_get("Dataset-" . $node->nid . "-WSF", ""); if ($wsfAddress != "") { // if the WSF address changed, we first have to change it here. if ($wsfAddress != "http://" . $node->field_wsf[0]["value"] . "/ws/") { // Save the WSF IP for this newly created dataset variable_set("Dataset-" . $node->nid . "-WSF", "http://" . $node->field_wsf[0]["value"] . "/ws/"); $wsfAddress = variable_get("Dataset-" . $node->nid . "-WSF", ""); // Save this new WSF address into the WSF registery $wsfRegistry = variable_get("WSF-Registry", array()); if (array_search($wsfAddress, $wsfRegistry) === FALSE) { array_push($wsfRegistry, $wsfAddress); variable_set("WSF-Registry", $wsfRegistry); } // Now, lets recreate the SID-Registry structure $sidRegistry = array(); foreach ($wsfRegistry as $wsfAddress) { $ch = curl_init(); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_URL, $wsfAddress . "index.php"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); $data = curl_exec($ch); if (curl_errno($ch)) { curl_close($ch); continue; } $data = trim($data); if (!isset($sidRegistry[$data])) { $sidRegistry[$data] = array($wsfAddress); } else { array_push($sidRegistry[$data], $wsfAddress); } curl_close($ch); } // Save the SID-Registry variable_set("SID-Registry", $sidRegistry); } // Then we check if the address of the linked dataset changed $linkedDatasetRegistry = variable_get("Linked-Dataset-Registry", ""); if ($linkedDatasetRegistry == "") { if (isset($linkedDatasetRegistry[$node->nid])) { $linkedDatasetRegistry[$node->nid] = $node->field_existing_dataset_uri[0]["value"]; variable_set("Linked-Dataset-Registry", $linkedDatasetRegistry); return; } } // If not, we update the description of the dataset $wsq = new WebServiceQuerier($wsfAddress . "dataset/update/", "post", "text/xml", "uri=" . urlencode(variable_get("Dataset-" . $node->nid . "-ID", get_domain($base_url) . "/wsf/datasets/" . $node->nid . "/")) . "&title=" . urlencode($node->title) . "&description=" . urlencode($node->og_description)); if ($wsq->getStatus() != 200) { $wsq->displayError(); } } else { drupal_set_message(t("No WSF address linked to this dataset"), "error", TRUE); } } break; } } //@} ?>