/*global define */ define(['jquery', 'underscore', 'backbone'], function($, _, Backbone) { 'use strict'; // Node Model // ------------------ var Node = Backbone.Model.extend({ // This model contains all of the information retrieved from calling listNodes() using the DataONE API defaults: { members: [], coordinators: [], hiddenMembers: [], currentMemberNode: MetacatUI.appModel.get("nodeId") || null, checked: false, error: false }, initialize: function(){ var model = this; if(MetacatUI.appModel.get('nodeServiceUrl')){ //Get the node information from the CN this.getNodeInfo(); } }, getMember: function(memberInfo){ if(!memberInfo) return false; //Get the member ID var memberId = null; if((typeof memberInfo === "object") && memberInfo.type == "SolrResult") memberId = memberInfo.get("datasource"); else if(typeof memberInfo === "string") memberId = memberInfo; else return false; //Find the member by its ID var member = _.findWhere(this.get("members"), {identifier: memberId}); if(!member) return false; return member; }, getMembers: function(memberInfo){ if(!memberInfo) return false; if(!Array.isArray(memberInfo)) memberInfo = [memberInfo]; var members = []; _.each(memberInfo, function(info){ var foundMember = this.getMember(info); if(foundMember) members.push(foundMember); }, this); if(members.length) return members; else return false; }, getNodeInfo: function(){ var thisModel = this, memberList = this.get('members'), coordList = this.get('coordinators'); $.ajax({ url: MetacatUI.appModel.get('nodeServiceUrl'), dataType: "text", success: function(data, textStatus, xhr) { var xmlResponse = $.parseXML(data) || null; if(!xmlResponse) return; thisModel.saveNodeInfo(xmlResponse); thisModel.set("checked", true); }, error: function(xhr, textStatus, errorThrown){ //Log the error to the console console.error("Couldn't get the DataONE Node info document: ", textStatus, errorThrown); //Send this exception to Google Analytics if(MetacatUI.appModel.get("googleAnalyticsKey") && (typeof ga !== "undefined")){ ga("send", "exception", { "exDescription": "Couldn't get the DataONE Node info document: " + textStatus + ", " + errorThrown + " | v. " + MetacatUI.metacatUIVersion, "exFatal": false }); } //Trigger an error on this model thisModel.set("error", true); thisModel.trigger("error"); thisModel.set("checked", true); } }); }, saveNodeInfo: function(xml){ var thisModel = this, memberList = this.get('members'), coordList = this.get('coordinators'), children = xml.children || xml.childNodes; //Traverse the XML response to get the MN info _.each(children, function(d1NodeList){ var d1NodeListChildren = d1NodeList.children || d1NodeList.childNodes; //The first (and only) child should be the d1NodeList _.each(d1NodeListChildren, function(thisNode){ //Ignore parts of the XML that is not MN info if(!thisNode.attributes) return; //'node' will be a single node var node = {}, nodeProperties = thisNode.children || thisNode.childNodes; //Grab information about this node from XML nodes _.each(nodeProperties, function(nodeProperty){ if(nodeProperty.nodeName == "property") node[$(nodeProperty).attr("key")] = nodeProperty.textContent; else node[nodeProperty.nodeName] = nodeProperty.textContent; //Check if this member node has v2 read capabilities - important for the Package service if((nodeProperty.nodeName == "services") && nodeProperty.childNodes.length){ var v2 = $(nodeProperty).find("service[name='MNRead'][version='v2'][available='true']").length; node["readv2"] = v2; } }); //Grab information about this node from XLM attributes _.each(thisNode.attributes, function(attribute){ node[attribute.nodeName] = attribute.nodeValue; }); //Create some aliases for node info properties if(node.CN_logo_url) node.logo = node.CN_logo_url; if(node.CN_node_name) node.name = node.CN_node_name; if(node.CN_operational_status) node.status = node.CN_operational_status; if(node.CN_date_operational) node.memberSince = node.CN_date_operational; node.shortIdentifier = node.identifier.substring(node.identifier.lastIndexOf(":") + 1); // Push only if the node is not present in the list if ( node.type == "mn" ) { if ( !thisModel.containsObject(node, memberList) ) { memberList.push(node); } } // Push only if the node is not present in the list if ( node.type == "cn" ) { if ( !thisModel.containsObject(node, coordList) ) { coordList.push(node); } } }); //Save the cn and mn lists in the model when all members have been added thisModel.set('members', memberList); thisModel.trigger('change:members'); thisModel.set('coordinators', coordList); thisModel.trigger('change:coordinators'); //If we don't have a current member node yet, find it if(!thisModel.get("currentMemberNode")){ // Find the current member node by matching the current DataONE MN API base URL // with the DataONE MN API base URLs in the member list var thisMember = _.findWhere(thisModel.get("members"), { baseURL: (MetacatUI.appModel.get("baseUrl") + MetacatUI.appModel.get('context') + MetacatUI.appModel.get("d1Service")).replace("/v2", "").replace("/v1", "") }); if(thisMember !== undefined){ //If a matching member node is found, set the node ID thisModel.set("currentMemberNode", thisMember.identifier); //If the node ID is not set in the appModel user the matching MN we found if(!MetacatUI.appModel.get("nodeId")) MetacatUI.appModel.set("nodeId", thisMember.identifier); } //Trigger a change so the rest of the app knows we at least looked for the current MN thisModel.trigger("change:currentMemberNode"); } }); }, // Checks if the node already exists in the List containsObject: function (obj, list) { var res = _.find(list, function(val){ return _.isEqual(obj, val)}); return (_.isObject(res))? true:false; }, /* * Returns true if the given nodeId is a Coordinating Node */ isCN: function(nodeId){ return _.findWhere(this.get("coordinators"), { identifier: nodeId }); } }); return Node; });