<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>MetacatUI Dev Docs: Source: models/UserModel.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> <link type="text/css" rel="stylesheet" href="style.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: models/UserModel.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>/*global define */ define(['jquery', 'underscore', 'backbone', 'jws', 'models/Search', "collections/SolrResults"], function($, _, Backbone, JWS, SearchModel, SearchResults) { 'use strict'; /** * @class UserModel * @extends Backbone.Model * @constructor */ var UserModel = Backbone.Model.extend( /** @lends UserModel.prototype */{ defaults: function(){ return{ type: "person", //assume this is a person unless we are told otherwise - other possible type is a "group" checked: false, //Is set to true when we have checked the account/subject info of this user tokenChecked: false, //Is set to true when the uer auth token has been checked basicUser: false, //Set to true to only query for basic info about this user - prevents sending queries for info that will never be displayed in the UI lastName: null, firstName: null, fullName: null, email: null, logo: null, description: null, verified: null, username: null, usernameReadable: null, orcid: null, searchModel: null, searchResults: null, loggedIn: false, ldapError: false, //Was there an error logging in to LDAP registered: false, isMemberOf: [], isOwnerOf: [], identities: [], identitiesUsernames: [], allIdentitiesAndGroups: [], pending: [], token: null, expires: null, timeoutId: null, rawData: null, portalQuota: -1, isAuthorizedCreatePortal: null } }, initialize: function(options){ if(typeof options !== "undefined"){ if(options.username) this.set("username", options.username); if(options.rawData) this.set(this.parseXML(options.rawData)); } this.on("change:identities", this.pluckIdentityUsernames); this.on("change:username change:identities change:type", this.updateSearchModel); this.createSearchModel(); this.on("change:username", this.createReadableUsername()); //Create a search results model for this person var searchResults = new SearchResults([], { rows: 5, start: 0 }); this.set("searchResults", searchResults); }, createSearchModel: function(){ //Create a search model that will retrieve data created by this person this.set("searchModel", new SearchModel()); this.updateSearchModel(); }, updateSearchModel: function(){ if(this.get("type") == "node"){ this.get("searchModel").set("dataSource", [this.get("node").identifier]); this.get("searchModel").set("username", []); } else{ //Get all the identities for this person var ids = [this.get("username")]; _.each(this.get("identities"), function(equivalentUser){ ids.push(equivalentUser.get("username")); }); this.get("searchModel").set("username", ids); } this.trigger("change:searchModel"); }, parseXML: function(data){ var model = this, username = this.get("username"); //Reset the group list so we don't just add it to it with push() this.set("isMemberOf", this.defaults().isMemberOf, {silent: true}); this.set("isOwnerOf", this.defaults().isOwnerOf, {silent: true}); //Reset the equivalent id list so we don't just add it to it with push() this.set("identities", this.defaults().identities, {silent: true}); //Find this person's node in the XML var userNode = null; if(!username) var username = $(data).children("subject").text(); if(username){ var subjects = $(data).find("subject"); for(var i=0; i<subjects.length; i++){ if($(subjects[i]).text().toLowerCase() == username.toLowerCase()){ userNode = $(subjects[i]).parent(); break; } } } if(!userNode) userNode = $(data).first(); //Get the type of user - either a person or group var type = $(userNode).prop("tagName"); if(type) type = type.toLowerCase(); if(type == "group"){ var fullName = $(userNode).find("groupName").first().text(); } else if(type){ //Find the person's info var firstName = $(userNode).find("givenName").first().text(), lastName = $(userNode).find("familyName").first().text(), email = $(userNode).find("email").first().text(), verified = $(userNode).find("verified").first().text(), memberOf = this.get("isMemberOf"), ownerOf = this.get("isOwnerOf"), identities = this.get("identities"); //Sometimes names are saved as "NA" when they are not available - translate these to false values if(firstName == "NA") firstName = null; if(lastName == "NA") lastName = null; //Construct the fullname from the first and last names, but watch out for falsely values var fullName = ""; fullName += firstName? firstName : ""; fullName += lastName? (" " + lastName) : ""; if(!fullName) fullName = this.getNameFromSubject(username); //Don't get this detailed info about basic users if(!this.get("basicUser")){ //Get all the equivalent identities for this user var equivalentIds = $(userNode).find("equivalentIdentity"); if(equivalentIds.length > 0) var allPersons = $(data).find("person subject"); _.each(equivalentIds, function(identity, i){ //push onto the list var username = $(identity).text(), equivUserNode; //Find the matching person node in the response _.each(allPersons, function(person){ if($(person).text().toLowerCase() == username.toLowerCase()){ equivUserNode = $(person).parent().first(); allPersons = _.without(allPersons, person); } }); var equivalentUser = new UserModel({ username: username, basicUser: true, rawData: equivUserNode }); identities.push(equivalentUser); }); } //Get each group and save _.each($(data).find("group"), function(group, i){ //Save group ID var groupId = $(group).find("subject").first().text(), groupName = $(group).find("groupName").text(); memberOf.push({ groupId: groupId, name: groupName }); //Check if this person is a rightsholder var allRightsHolders = []; _.each($(group).children("rightsHolder"), function(rightsHolder){ allRightsHolders.push($(rightsHolder).text().toLowerCase()); }); if(_.contains(allRightsHolders, username.toLowerCase())) ownerOf.push(groupId); }); } var allSubjects = _.pluck( this.get("isMemberOf"), "groupId" ); allSubjects.push(this.get("username")); allSubjects.push(this.get("identities")); return { isMemberOf: memberOf, isOwnerOf: ownerOf, identities: identities, allIdentitiesAndGroups: allSubjects, verified: verified, username: username, firstName: firstName, lastName: lastName, fullName: fullName, email: email, registered: true, type: type, rawData: data } }, getInfo: function(){ var model = this; //If the accounts service is not on, flag this user as checked/completed if(!MetacatUI.appModel.get("accountsUrl")){ this.set("fullName", this.getNameFromSubject()); this.set("checked", true); return; } //Only proceed if there is a username if(!this.get("username")) return; //Get the user info using the DataONE API var url = MetacatUI.appModel.get("accountsUrl") + encodeURIComponent(this.get("username")); var requestSettings = { type: "GET", url: url, success: function(data, textStatus, xhr) { //Parse the XML response to get user info var userProperties = model.parseXML(data); //Filter out all the falsey values _.each(userProperties, function(v, k) { if(!v) { delete userProperties[k]; } }); model.set(userProperties); //Trigger the change events model.trigger("change:isMemberOf"); model.trigger("change:isOwnerOf"); model.trigger("change:identities"); model.set("checked", true); }, error: function(xhr, textStatus, errorThrown){ // Sometimes the node info has not been received before this getInfo() is called. // If the node info was received while this getInfo request was pending, and this user was determined // to be a node, then we can skip any further action here. if(model.get("type") == "node") return; if((xhr.status == 404) && MetacatUI.nodeModel.get("checked")){ model.set("fullName", model.getNameFromSubject()); model.set("checked", true); } else if((xhr.status == 404) && !MetacatUI.nodeModel.get("checked")){ model.listenToOnce(MetacatUI.nodeModel, "change:checked", function(){ if(!model.isNode()){ model.set("fullName", model.getNameFromSubject()); model.set("checked", true); } }); } else{ //As a backup, search for this user instead var requestSettings = { type: "GET", url: MetacatUI.appModel.get("accountsUrl") + "?query=" + encodeURIComponent(model.get("username")), success: function(data, textStatus, xhr) { //Parse the XML response to get user info model.set(model.parseXML(data)); //Trigger the change events model.trigger("change:isMemberOf"); model.trigger("change:isOwnerOf"); model.trigger("change:identities"); model.set("checked", true); }, error: function(){ //Set some blank values and flag as checked //model.set("username", ""); //model.set("fullName", ""); model.set("notFound", true); model.set("checked", true); } } //Send the request $.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings())); } } } //Send the request $.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings())); }, //Get the pending identity map requests, if the service is turned on getPendingIdentities: function(){ if(!MetacatUI.appModel.get("pendingMapsUrl")) return false; var model = this; //Get the pending requests var requestSettings = { url: MetacatUI.appModel.get("pendingMapsUrl") + encodeURIComponent(this.get("username")), success: function(data, textStatus, xhr){ //Reset the equivalent id list so we don't just add it to it with push() model.set("pending", model.defaults().pending); var pending = model.get("pending"); _.each($(data).find("person"), function(person, i) { //Don't list yourself as a pending map request var personsUsername = $(person).find("subject").text(); if(personsUsername.toLowerCase() == model.get("username").toLowerCase()) return; //Create a new User Model for this pending identity var pendingUser = new UserModel({ rawData: person }); if(pendingUser.isOrcid()) pendingUser.getInfo(); pending.push(pendingUser); }); model.set("pending", pending); model.trigger("change:pending"); //Trigger the change event }, error: function(xhr, textStatus){ if(xhr.responseText.indexOf("error code 34")){ model.set("pending", model.defaults().pending); model.trigger("change:pending"); //Trigger the change event } } } $.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings())); }, getNameFromSubject: function(username){ var username = username || this.get("username"), fullName = ""; if(!username) return; if((username.indexOf("uid=") > -1) && (username.indexOf(",") > -1)) fullName = username.substring(username.indexOf("uid=") + 4, username.indexOf(",")); else if((username.indexOf("CN=") > -1) && (username.indexOf(",") > -1)) fullName = username.substring(username.indexOf("CN=") + 3, username.indexOf(",")); //Cut off the last string after the name when it contains digits - not part of this person's names if(fullName.lastIndexOf(" ") > fullName.indexOf(" ")){ var lastWord = fullName.substring(fullName.lastIndexOf(" ")); if(lastWord.search(/\d/) > -1) fullName = fullName.substring(0, fullName.lastIndexOf(" ")); } //Default to the username if(!fullName) fullName = this.get("fullname") || username; return fullName; }, isOrcid: function(orcid){ var username = (typeof orcid === "string")? orcid : this.get("username"); //Have we already verified this? if((typeof orcid == "undefined") && (username == this.get("orcid"))) return true; //Checks for ORCIDs using the orcid base URL as a prefix if(username.indexOf("orcid.org/") > -1){ return true; } //If the ORCID base url is not present, we will check if this is a 19-digit ORCID ID //A simple and fast check first //ORCiDs are 16 digits and 3 dashes - 19 characters if(username.length != 19) return false; /* The ORCID checksum algorithm to determine is a character string is an ORCiD * http://support.orcid.org/knowledgebase/articles/116780-structure-of-the-orcid-identifier */ var total = 0, baseDigits = username.replace(/-/g, "").substr(0, 15); for(var i=0; i<baseDigits.length; i++){ var digit = parseInt(baseDigits.charAt(i)); total = (total + digit) * 2; } var remainder = total % 11, result = (12 - remainder) % 11, checkDigit = (result == 10) ? "X" : result.toString(), isOrcid = (checkDigit == username.charAt(username.length-1)); if(isOrcid) this.set("orcid", username); return isOrcid; }, isNode: function(){ var node = _.where(MetacatUI.nodeModel.get("members"), { shortIdentifier: this.get("username") }); return (node && node.length) }, // Will check if this user is a Member Node. If so, it will save the MN info to the model saveAsNode: function(){ if(!this.isNode()) return; var node = _.where(MetacatUI.nodeModel.get("members"), { shortIdentifier: this.get("username") })[0]; this.set({ type: "node", logo: node.logo, description: node.description, node: node, fullName: node.name, usernameReadable: this.get("username") }); this.updateSearchModel(); this.set("checked", true); }, loginLdap: function(formData, success, error){ if(!formData || !appModel.get("signInUrlLdap")) return false; var model = this; var requestSettings = { type: "POST", url: MetacatUI.appModel.get("signInUrlLdap") + window.location.href, data: formData, success: function(data, textStatus, xhr){ if(success) success(this); model.getToken(); }, error: function(){ /*if(error) error(this); */ model.getToken(); } } $.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings())); }, logout: function(){ //Construct the sign out url and redirect var signOutUrl = MetacatUI.appModel.get('signOutUrl'), target = Backbone.history.location.href; // DO NOT include the route otherwise we have an infinite redirect // target = target.split("#")[0]; target = target.slice(0, -8); // make sure to include the target signOutUrl += "?target=" + target; // do it! window.location.replace(signOutUrl); }, // call Metacat or the DataONE CN to validate the session and tell us the user's name checkStatus: function(onSuccess, onError) { var model = this; if (!MetacatUI.appModel.get("tokenUrl")) { // look up the URL var metacatUrl = MetacatUI.appModel.get('metacatServiceUrl'); // ajax call to validate the session/get the user info var requestSettings = { type: "POST", url: metacatUrl, data: { action: "validatesession" }, success: function(data, textStatus, xhr) { // the Metacat (XML) response should have a fullName element var username = $(data).find("name").text(); // set in the model model.set('username', username); //Are we logged in? if(username){ model.set("loggedIn", true); model.getInfo(); } else{ model.set("loggedIn", false); model.trigger("change:loggedIn"); model.set("checked", true); } if(onSuccess) onSuccess(data); }, error: function(data, textStatus, xhr){ //User is not logged in model.reset(); if(onError) onError(); } } $.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings())); } else { // use the token method for checking authentication this.getToken(); } }, getToken: function(customCallback) { var tokenUrl = MetacatUI.appModel.get('tokenUrl'); var model = this; if(!tokenUrl) return false; //Set up the function that will be called when we retrieve a token var callback = (typeof customCallback === "function") ? customCallback : function(data, textStatus, xhr) { // the response should have the token var payload = model.parseToken(data), username = payload ? payload.userId : null, fullName = payload ? payload.fullName : model.getNameFromSubject(username) || null, token = payload ? data : null, loggedIn = payload ? true : false; // set in the model model.set('fullName', fullName); model.set('username', username); model.set("token", token); model.set("loggedIn", loggedIn); model.set("tokenChecked", true); model.getTokenExpiration(payload); if(username) model.getInfo(); else model.set("checked", true); }; // ajax call to get token var requestSettings = { type: "GET", dataType: "text", xhrFields: { withCredentials: true }, url: tokenUrl, data: {}, success: callback, error: function(xhr, textStatus, errorThrown){ model.set("checked", true); } } $.ajax(requestSettings); }, getTokenExpiration: function(payload){ if(!payload && this.get("token")) var payload = this.parseToken(this.get("token")); if(!payload) return; //The exp claim should be standard - it is in UTC seconds var expires = payload.exp? new Date(payload.exp * 1000) : null; //Use the issuedAt and ttl as a backup (only used in d1 2.0.0 and 2.0.1) if(!expires){ var issuedAt = payload.issuedAt? new Date(payload.issuedAt) : null, lifeSpan = payload.ttl? payload.ttl : null; if(issuedAt && lifeSpan && (lifeSpan > 99999)) issuedAt.setMilliseconds(lifeSpan); else if(issuedAt && lifeSpan) issuedAt.setSeconds(lifeSpan); expires = issuedAt; } this.set("expires", expires); }, checkToken: function(onSuccess, onError){ //First check if the token has expired if(MetacatUI.appUserModel.get("expires") > new Date()){ if(onSuccess) onSuccess(); return; } var model = this; var url = MetacatUI.appModel.get("tokenUrl"); if(!url) return; var requestSettings = { type: "GET", url: url, headers: { "Cache-Control": "no-cache" }, success: function(data, textStatus, xhr){ if(data){ // the response should have the token var payload = model.parseToken(data), username = payload ? payload.userId : null, fullName = payload ? payload.fullName : null, token = payload ? data : null, loggedIn = payload ? true : false; // set in the model model.set('fullName', fullName); model.set('username', username); model.set("token", token); model.set("loggedIn", loggedIn); model.getTokenExpiration(payload); MetacatUI.appUserModel.set("checked", true); if(onSuccess) onSuccess(data, textStatus, xhr); } else if(onError) onError(data, textStatus, xhr); }, error: function(data, textStatus, xhr){ //If this token in invalid, then reset the user model/log out MetacatUI.appUserModel.reset(); if(onError) onError(data, textStatus, xhr); } } $.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings())); }, parseToken: function(token) { if(typeof token == "undefined") var token = this.get("token"); var jws = new KJUR.jws.JWS(); var result = 0; try { result = jws.parseJWS(token); } catch (ex) { result = 0; } if(!jws.parsedJWS) return ""; var payload = $.parseJSON(jws.parsedJWS.payloadS); return payload; }, update: function(onSuccess, onError){ var model = this; var person = '<?xml version="1.0" encoding="UTF-8"?>' + '<d1:person xmlns:d1="http://ns.dataone.org/service/types/v1">' + '<subject>' + this.get("username") + '</subject>' + '<givenName>' + this.get("firstName") + '</givenName>' + '<familyName>' + this.get("lastName") + '</familyName>' + '<email>' + this.get("email") + '</email>' + '</d1:person>'; var xmlBlob = new Blob([person], {type : 'application/xml'}); var formData = new FormData(); formData.append("subject", this.get("username")); formData.append("person", xmlBlob, "person"); var updateUrl = MetacatUI.appModel.get("accountsUrl") + encodeURIComponent(this.get("username")); // ajax call to update var requestSettings = { type: "PUT", cache: false, contentType: false, processData: false, url: updateUrl, data: formData, success: function(data, textStatus, xhr) { if(typeof onSuccess != "undefined") onSuccess(data); //model.getInfo(); }, error: function(data, textStatus, xhr) { if(typeof onError != "undefined") onError(data); } } $.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings())); }, confirmMapRequest: function(otherUsername, onSuccess, onError){ if(!otherUsername) return; var mapUrl = MetacatUI.appModel.get("pendingMapsUrl") + encodeURIComponent(otherUsername), model = this; if(!onSuccess) var onSuccess = function(){}; if(!onError) var onError = function(){}; // ajax call to confirm map var requestSettings = { type: "PUT", url: mapUrl, success: function(data, textStatus, xhr) { if(onSuccess) onSuccess(data, textStatus, xhr); //Get updated info model.getInfo(); }, error: function(xhr, textStatus, error) { if(onError) onError(xhr, textStatus, error); } } $.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings())); }, denyMapRequest: function(otherUsername, onSuccess, onError){ if(!otherUsername) return; var mapUrl = MetacatUI.appModel.get("pendingMapsUrl") + encodeURIComponent(otherUsername), model = this; // ajax call to reject map var requestSettings = { type: "DELETE", url: mapUrl, success: function(data, textStatus, xhr) { if(typeof onSuccess == "function") onSuccess(data, textStatus, xhr); model.getInfo(); }, error: function(xhr, textStatus, error) { if(typeof onError == "function") onError(xhr, textStatus, error); } } $.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings())); }, addMap: function(otherUsername, onSuccess, onError){ if(!otherUsername) return; var mapUrl = MetacatUI.appModel.get("pendingMapsUrl"), model = this; if(mapUrl.charAt(mapUrl.length-1) == "/"){ mapUrl = mapUrl.substring(0, mapUrl.length-1) } // ajax call to map var requestSettings = { type: "POST", xhrFields: { withCredentials: true }, headers: { "Authorization": "Bearer " + this.get("token") }, url: mapUrl, data: { subject: otherUsername }, success: function(data, textStatus, xhr) { if(typeof onSuccess == "function") onSuccess(data, textStatus, xhr); model.getInfo(); }, error: function(xhr, textStatus, error) { //Check if the username might have been spelled or formatted incorrectly //ORCIDs, in particular, have different formats that we should account for if(xhr.responseText.indexOf("LDAP: error code 32 - No Such Object") > -1 && model.isOrcid(otherUsername)){ if(otherUsername.length == 19) model.addMap("http://orcid.org/" + otherUsername, onSuccess, onError); else if(otherUsername.indexOf("https://orcid.org") == 0) model.addMap(otherUsername.replace("https", "http"), onSuccess, onError); else if(otherUsername.indexOf("orcid.org") == 0) model.addMap("http://" + otherUsername, onSuccess, onError); else if(otherUsername.indexOf("www.orcid.org") == 0) model.addMap(otherUsername.replace("www.", "http://"), onSuccess, onError); else if(otherUsername.indexOf("http://www.orcid.org") == 0) model.addMap(otherUsername.replace("www.", ""), onSuccess, onError); else if(otherUsername.indexOf("https://www.orcid.org") == 0) model.addMap(otherUsername.replace("https://www.", "http://"), onSuccess, onError); else if(typeof onError == "function") onError(xhr, textStatus, error); } else{ if(typeof onError == "function") onError(xhr, textStatus, error); } } } $.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings())); }, removeMap: function(otherUsername, onSuccess, onError){ if(!otherUsername) return; var mapUrl = MetacatUI.appModel.get("accountsMapsUrl") + encodeURIComponent(otherUsername), model = this; // ajax call to remove mapping var requestSettings = { type: "DELETE", url: mapUrl, success: function(data, textStatus, xhr) { if(typeof onSuccess == "function") onSuccess(data, textStatus, xhr); model.getInfo(); }, error: function(xhr, textStatus, error) { if(typeof onError == "function") onError(xhr, textStatus, error); } } $.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings())); }, failedLdapLogin: function(){ this.set("loggedIn", false); this.set("checked", true); this.set("ldapError", true); }, pluckIdentityUsernames: function(){ var models = this.get("identities"), usernames = []; _.each(models, function(m){ usernames.push(m.get("username").toLowerCase()); }); this.set("identitiesUsernames", usernames); this.trigger("change:identitiesUsernames"); }, createReadableUsername: function(){ if(!this.get("username")) return; var username = this.get("username"), readableUsername = username.substring(username.indexOf("=")+1, username.indexOf(",")) || username; this.set("usernameReadable", readableUsername); }, createAjaxSettings: function(){ if(!this.get("token")) return {} return { xhrFields: { withCredentials: true }, headers: { "Authorization": "Bearer " + this.get("token") } } }, /** * Checks if this user has the quota to perform the given action * @param {string} action - The action to be performed * @param {string} customerGroup - The subject or identifier of the customer/membership group * to use this quota against */ checkQuota: function(action, customerGroup){ //Temporarily reset the quota so a trigger event is changed when the XHR is complete this.set("portalQuota", -1, {silent: true}); //Start of temporary code //TODO: Replace this function with real code once the quota service is working this.set("portalQuota", 999); return; //End of temporary code var model = this; var requestSettings = { url: "", type: "GET", success: function(data, textStatus, xhr) { model.set("portalQuota", data.remainingQuota); }, error: function(xhr, textStatus, errorThrown) { model.set("portalQuota", 0); } } $.ajax(_.extend(requestSettings, this.createAjaxSettings())); }, /** * Checks if the user has authorization to perform the given action. */ isAuthorizedCreatePortal: function(){ //Reset the isAuthorized attribute silently so a change event is always triggered this.set("isAuthorizedCreatePortal", null, {silent: true}); //If the user isn't logged in, set authorization to false if( !this.get("loggedIn") ){ this.set("isAuthorizedCreatePortal", false); return; } //If creating portals has bbeen disabled app-wide, then set to false if( MetacatUI.appModel.get("enableCreatePortals") === false ){ this.set("isAuthorizedCreatePortal", false); return; } //If creating portals has been limited to only certain subjects, check if this user is one of them else if( MetacatUI.appModel.get("limitPortalsToSubjects").length ){ if( !this.get("allIdentitiesAndGroups").length ){ this.on("change:allIdentitiesAndGroups", this.isAuthorizedCreatePortal); return; } //Find the subjects that have access to create portals. Could be specific users or groups. var subjectsThatHaveAccess = _.intersection(MetacatUI.appModel.get("limitPortalsToSubjects"), this.get("allIdentitiesAndGroups")); if( !subjectsThatHaveAccess.length ){ //If this user is not in the whitelist, set to false this.set("isAuthorizedCreatePortal", false); } else{ //If this user is in the whitelist, set to true this.set("isAuthorizedCreatePortal", true); } return; } //If anyone is allowed to create a portal, check if they have the quota to create a portal else{ //Listen to the response from the quota check this.once("change:portalQuota", function(){ //If the quota is at least 1, set to true if( this.get("portalQuota") > 0 ){ this.set("isAuthorizedCreatePortal", true); } //If the quota is less than or equal to zero, set to false else{ this.set("isAuthorizedCreatePortal", false); } }); //Check the quota this.checkQuota("createPortal"); return; } }, /** * Given a list of user and/or group subjects, this function checks if this user * has an equivalent identity in that list, or is a member of a group in the list. * A single subject string can be passed instead of an array of subjects. * TODO: This needs to support nested group membership. * @param {string|string[]} subjects * @returns {boolean} */ hasIdentityOverlap: function(subjects){ try{ //If only a single subject is given, put it in an array if( typeof subjects == "string" ){ subjects = [subjects]; } //If the subjects are not a string or an array, or if it's an empty array, exit this function. else if( !Array.isArray(subjects) || !subjects.length ){ return false; } return _.intersection(this.get("allIdentitiesAndGroups"), subjects).length; } catch(e){ console.error(e); return false; } }, reset: function(){ var defaults = _.omit(this.defaults(), ["searchModel", "searchResults"]); this.set(defaults); } }); return UserModel; }); </code></pre> </article> </section> </div> <nav> <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="AccessPolicy.html">AccessPolicy</a></li><li><a href="AccessPolicyView.html">AccessPolicyView</a></li><li><a href="AccessRule.html">AccessRule</a></li><li><a href="AppModel.html">AppModel</a></li><li><a href="BooleanFilter.html">BooleanFilter</a></li><li><a href="ChoiceFilter.html">ChoiceFilter</a></li><li><a href="Citations.html">Citations</a></li><li><a href="CollectionModel.html">CollectionModel</a></li><li><a href="ColorPaletteView.html">ColorPaletteView</a></li><li><a href="DataCatalogView_drawTiles-TextOverlay.html">TextOverlay</a></li><li><a href="DataCatalogViewWithFilters.html">DataCatalogViewWithFilters</a></li><li><a href="DataItemView.html">DataItemView</a></li><li><a href="DataPackage.html">DataPackage</a></li><li><a href="DateFilter.html">DateFilter</a></li><li><a href="EditCollectionView.html">EditCollectionView</a></li><li><a href="EditorView.html">EditorView</a></li><li><a href="EML211EditorView.html">EML211EditorView</a></li><li><a href="EMLEntity.html">EMLEntity</a></li><li><a href="EMLGeoCoverage.html">EMLGeoCoverage</a></li><li><a href="EMlGeoCoverageView.html">EMlGeoCoverageView</a></li><li><a href="EMLNonNumericDomain.html">EMLNonNumericDomain</a></li><li><a href="EMLNumericDomain.html">EMLNumericDomain</a></li><li><a href="EMLPartyView.html">EMLPartyView</a></li><li><a href="EMLTemporalCoverage.html">EMLTemporalCoverage</a></li><li><a href="Filter.html">Filter</a></li><li><a href="FilterGroup.html">FilterGroup</a></li><li><a href="FilterGroupsView.html">FilterGroupsView</a></li><li><a href="Filters.html">Filters</a></li><li><a href="ImageUploaderView.html">ImageUploaderView</a></li><li><a href="MetadataView.html">MetadataView</a></li><li><a href="NavbarView.html">NavbarView</a></li><li><a href="NumericFilter.html">NumericFilter</a></li><li><a href="ObjectFormats.html">ObjectFormats</a></li><li><a href="PortalDataView.html">PortalDataView</a></li><li><a href="PortalEditorView.html">PortalEditorView</a></li><li><a href="PortalListView.html">PortalListView</a></li><li><a href="PortalMembersView.html">PortalMembersView</a></li><li><a href="PortalModel.html">PortalModel</a></li><li><a href="PortalSectionView.html">PortalSectionView</a></li><li><a href="PortalView.html">PortalView</a></li><li><a href="PortEditorDataView.html">PortEditorDataView</a></li><li><a href="PortEditorImageView.html">PortEditorImageView</a></li><li><a href="PortEditorLogosView.html">PortEditorLogosView</a></li><li><a href="PortEditorMdSectionView.html">PortEditorMdSectionView</a></li><li><a href="PortEditorSectionsView.html">PortEditorSectionsView</a></li><li><a href="PortEditorSectionView.html">PortEditorSectionView</a></li><li><a href="PortEditorSettingsView.html">PortEditorSettingsView</a></li><li><a href="QualityReport.html">QualityReport</a></li><li><a href="Search.html">Search</a></li><li><a href="SolrResultList.html">SolrResultList</a></li><li><a href="SpatialFilter.html">SpatialFilter</a></li><li><a href="Stats.html">Stats</a></li><li><a href="ToggleFilter.html">ToggleFilter</a></li><li><a href="UIRouter.html">UIRouter</a></li><li><a href="UserView.html">UserView</a></li></ul><h3>Global</h3><ul><li><a href="global.html#addKeyword">addKeyword</a></li><li><a href="global.html#addNewKeyword">addNewKeyword</a></li><li><a href="global.html#checkIncompatibility">checkIncompatibility</a></li><li><a href="global.html#clearOldDrafts">clearOldDrafts</a></li><li><a href="global.html#friendlyTimeDiff">friendlyTimeDiff</a></li><li><a href="global.html#getSizeOfIndexQueue">getSizeOfIndexQueue</a></li><li><a href="global.html#hideTemporaryMessage">hideTemporaryMessage</a></li><li><a href="global.html#listenForActivity">listenForActivity</a></li><li><a href="global.html#listenForTimeout">listenForTimeout</a></li><li><a href="global.html#movePartyDown">movePartyDown</a></li><li><a href="global.html#movePartyUp">movePartyUp</a></li><li><a href="global.html#movePersonDown">movePersonDown</a></li><li><a href="global.html#movePersonUp">movePersonUp</a></li><li><a href="global.html#renderSupport">renderSupport</a></li><li><a href="global.html#saveDraft">saveDraft</a></li><li><a href="global.html#showAlert">showAlert</a></li><li><a href="global.html#showTemporaryMessage">showTemporaryMessage</a></li><li><a href="global.html#showTimeoutSignIn">showTimeoutSignIn</a></li></ul> </nav> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.3</a> on Wed Jun 03 2020 12:45:11 GMT-0500 (Central Daylight Time) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>