1 if (! window.XOSLIB_LOADED ) {
2 window.XOSLIB_LOADED=true;
4 SLIVER_API = "/plstackapi/slivers/";
5 SLICE_API = "/plstackapi/slices/";
6 SLICEROLE_API = "/plstackapi/slice_roles/";
7 NODE_API = "/plstackapi/nodes/";
8 SITE_API = "/plstackapi/sites/";
9 USER_API = "/plstackapi/users/";
10 USERDEPLOYMENT_API = "/plstackapi/user_deployments/";
11 DEPLOYMENT_API = "/plstackapi/deployments/";
12 IMAGE_API = "/plstackapi/images/";
13 NETWORKTEMPLATE_API = "/plstackapi/networktemplates/";
14 NETWORK_API = "/plstackapi/networks/";
15 NETWORKSLIVER_API = "/plstackapi/networkslivers/";
16 SERVICE_API = "/plstackapi/services/";
17 SLICEPRIVILEGE_API = "/plstackapi/slice_privileges/";
18 NETWORKDEPLOYMENT_API = "/plstackapi/networkdeployments/";
20 /* changed as a side effect of the big rename
21 SLICEDEPLOYMENT_API = "/plstackapi/slice_deployments/";
22 USERDEPLOYMENT_API = "/plstackapi/user_deployments/";
25 SLICEDEPLOYMENT_API = "/plstackapi/slicedeployments/";
26 USERDEPLOYMENT_API = "/plstackapi/userdeployments/";
28 SLICEPLUS_API = "/xoslib/slicesplus/";
30 XOSModel = Backbone.Model.extend({
31 /* from backbone-tastypie.js */
32 //idAttribute: 'resource_uri',
34 /* from backbone-tastypie.js */
36 var url = this.attributes.resource_uri;
40 url = this.urlRoot + this.id;
42 // this happens when creating a new model.
48 // XXX I'm not sure this does anything useful
49 url = ( _.isFunction( this.collection.url ) ? this.collection.url() : this.collection.url );
50 url = url || this.urlRoot;
53 // remove any existing query parameters
54 url && ( url.indexOf("?") > -1 ) && ( url = url.split("?")[0] );
56 url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );
58 url && ( url += "?no_hyperlinks=1" );
63 listMethods: function() {
65 for(var m in this) {
\r
66 if(typeof this[m] == "function") {
\r
73 validate: function(attrs, options) {
76 _.each(this.validators, function(validatorList, fieldName) {
77 _.each(validatorList, function(validator) {
78 if (fieldName in attrs) {
79 validatorResult = validateField(validator, attrs[fieldName], this)
80 if (validatorResult != true) {
81 errors[fieldName] = validatorResult;
90 // backbone.js semantics -- on successful validate, return nothing
94 XOSCollection = Backbone.Collection.extend({
96 return this.models.map(function(element) { return element.attributes; });
99 initialize: function(){
100 this.isLoaded = false;
101 this.failedLoad = false;
102 this.startedLoad = false;
103 this.sortVar = 'name';
\r
104 this.sortOrder = 'asc';
\r
105 this.on( "sort", this.sorted );
\r
108 relatedCollections: [],
\r
109 foreignCollections: [],
\r
111 sorted: function() {
\r
112 //console.log("sorted " + this.modelName);
\r
115 simpleComparator: function( model ){
\r
116 parts=this.sortVar.split(".");
\r
117 result = model.get(parts[0]);
\r
118 for (index=1; index<parts.length; ++index) {
\r
119 result=result[parts[index]];
\r
124 comparator: function (left, right) {
\r
125 var l = this.simpleComparator(left);
\r
126 var r = this.simpleComparator(right);
\r
128 if (l === void 0) return -1;
\r
129 if (r === void 0) return 1;
\r
131 if (this.sortOrder=="desc") {
\r
132 return l < r ? 1 : l > r ? -1 : 0;
\r
134 return l < r ? -1 : l > r ? 1 : 0;
\r
138 fetchSuccess: function(collection, response, options) {
\r
139 //console.log("fetch succeeded " + collection.modelName);
\r
140 this.failedLoad = false;
\r
141 this.fetching = false;
\r
142 if (!this.isLoaded) {
\r
143 this.isLoaded = true;
\r
144 Backbone.trigger("xoslib:collectionLoadChange", this);
\r
146 this.trigger("fetchStateChange");
\r
147 if (options["orig_success"]) {
\r
148 options["orig_success"](collection, response, options);
\r
152 fetchFailure: function(collection, response, options) {
\r
153 //console.log("fetch failed " + collection.modelName);
\r
154 this.fetching = false;
\r
155 if ((!this.isLoaded) && (!this.failedLoad)) {
\r
156 this.failedLoad=true;
\r
157 Backbone.trigger("xoslib:collectionLoadChange", this);
\r
159 this.trigger("fetchStateChange");
\r
160 if (options["orig_failure"]) {
\r
161 options["orig_failure"](collection, response, options);
\r
165 fetch: function(options) {
\r
167 this.fetching=true;
\r
168 //console.log("fetch " + this.modelName);
\r
169 if (!this.startedLoad) {
\r
170 this.startedLoad=true;
\r
171 Backbone.trigger("xoslib:collectionLoadChange", this);
\r
173 this.trigger("fetchStateChange");
\r
174 if (options == undefined) {
\r
177 options["orig_success"] = options["success"];
\r
178 options["orig_failure"] = options["failure"];
\r
179 options["success"] = function(collection, response, options) { self.fetchSuccess.call(self, collection, response, options); };
\r
180 options["failure"] = this.fetchFailure;
\r
181 Backbone.Collection.prototype.fetch.call(this, options);
\r
184 startPolling: function() {
\r
185 if (!this._polling) {
\r
187 setInterval(function() { collection.fetch(); }, 10000);
193 refresh: function(refreshRelated) {
194 if (!this.fetching) {
197 if (refreshRelated) {
198 for (related in this.relatedCollections) {
199 related = xos[related];
200 if (!related.fetching) {
207 maybeFetch: function(options){
208 // Helper function to fetch only if this collection has not been fetched before.
210 // If this has already been fetched, call the success, if it exists
211 options.success && options.success();
212 console.log("alreadyFetched");
216 // when the original success function completes mark this collection as fetched
218 successWrapper = function(success){
220 self._fetched = true;
221 success && success.apply(this, arguments);
224 options.success = successWrapper(options.success);
225 console.log("call fetch");
229 getOrFetch: function(id, options){
230 // Helper function to use this collection as a cache for models on the server
231 var model = this.get(id);
234 options.success && options.success(model);
238 model = new this.model({
242 model.fetch(options);
245 filterBy: function(fieldName, value) {
246 filtered = this.filter(function(obj) {
247 return obj.get(fieldName) == value;
249 return new this.constructor(filtered);
252 /* from backbone-tastypie.js */
253 url: function( models ) {
254 var url = this.urlRoot || ( models && models.length && models[0].urlRoot );
255 url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );
257 // Build a url to retrieve a set of models. This assume the last part of each model's idAttribute
258 // (set to 'resource_uri') contains the model's id.
259 if ( models && models.length ) {
260 var ids = _.map( models, function( model ) {
261 var parts = _.compact( model.id.split('/') );
262 return parts[ parts.length - 1 ];
264 url += 'set/' + ids.join(';') + '/';
267 url && ( url += "?no_hyperlinks=1" );
272 listMethods: function() {
274 for(var m in this) {
\r
275 if(typeof this[m] == "function") {
\r
283 function define_model(lib, attrs) {
284 modelName = attrs.modelName;
285 modelClassName = modelName;
286 collectionClassName = modelName + "Collection";
288 if (!attrs.collectionName) {
289 attrs.collectionName = modelName + "s";
291 collectionName = attrs.collectionName;
298 if ($.inArray(key, ["urlRoot", "modelName", "validate"])>=0) {
299 modelAttrs[key] = value;
301 if ($.inArray(key, ["urlRoot", "modelName", "relatedCollections", "foreignCollections"])>=0) {
302 collectionAttrs[key] = value;
306 if (xosdefaults && xosdefaults[modelName]) {
307 modelAttrs["defaults"] = xosdefaults[modelName];
310 if (xosvalidators && xosvalidators[modelName]) {
311 modelAttrs["validators"] = xosvalidators[modelName];
314 lib[modelName] = XOSModel.extend(modelAttrs);
316 collectionAttrs["model"] = lib[modelName];
318 lib[collectionClassName] = XOSCollection.extend(collectionAttrs);
319 lib[collectionName] = new lib[collectionClassName]();
321 lib.allCollectionNames.push(collectionName);
322 lib.allCollections.push(lib[collectionName]);
326 this.allCollectionNames = [];
327 this.allCollections = [];
329 define_model(this, {urlRoot: SLIVER_API,
330 relatedCollections: {"networkSlivers": "sliver"},
331 foreignCollections: ["slices", "deployments", "images", "nodes", "users"],
332 modelName: "sliver"});
334 define_model(this, {urlRoot: SLICE_API,
335 relatedCollections: {"slivers": "slice", "sliceDeployments": "slice", "slicePrivileges": "slice", "networks": "owner"},
336 foreignCollections: ["services", "sites"],
338 validate: function(attrs, options) {
339 errors = XOSModel.prototype.validate(this, attrs, options);
340 // validate that slice.name starts with site.login_base
341 site = attrs.site || this.site;
342 if ((site!=undefined) && (attrs.name!=undefined)) {
343 site = xos.sites.get(site);
344 if (attrs.name.indexOf(site.attributes.login_base+"_") != 0) {
345 errors = errors || {};
346 errors["name"] = "must start with " + site.attributes.login_base + "_";
353 define_model(this, {urlRoot: SLICEDEPLOYMENT_API,
354 foreignCollections: ["slices", "deployments"],
355 modelName: "sliceDeployment"});
357 define_model(this, {urlRoot: SLICEPRIVILEGE_API,
358 foreignCollections: ["slices", "users", "sliceRoles"],
359 modelName: "slicePrivilege"});
361 define_model(this, {urlRoot: SLICEROLE_API,
362 modelName: "sliceRole"});
364 define_model(this, {urlRoot: NODE_API,
365 foreignCollections: ["sites", "deployments"],
368 define_model(this, {urlRoot: SITE_API,
369 relatedCollections: {"users": "site", "slices": "site", "nodes": "site"},
372 define_model(this, {urlRoot: USER_API,
373 relatedCollections: {"slicePrivileges": "user", "slices": "owner", "userDeployments": "user"},
374 foreignCollections: ["sites"],
377 define_model(this, {urlRoot: USERDEPLOYMENT_API,
378 foreignCollections: ["users","deployments"],
379 modelName: "userDeployment"});
381 define_model(this, { urlRoot: DEPLOYMENT_API,
382 relatedCollections: {"nodes": "deployment", "slivers": "deploymentNetwork", "networkDeployments": "deployment", "userDeployments": "deployment"},
383 modelName: "deployment"});
385 define_model(this, {urlRoot: IMAGE_API,
387 modelName: "image"});
389 define_model(this, {urlRoot: NETWORKTEMPLATE_API,
390 modelName: "networkTemplate"});
392 define_model(this, {urlRoot: NETWORK_API,
393 relatedCollections: {"networkDeployments": "network", "networkSlivers": "network"},
394 foreignCollections: ["slices", "networkTemplates"],
395 modelName: "network"});
397 define_model(this, {urlRoot: NETWORKSLIVER_API,
398 modelName: "networkSliver"});
400 define_model(this, {urlRoot: NETWORKDEPLOYMENT_API,
401 modelName: "networkDeployment"});
403 define_model(this, {urlRoot: SERVICE_API,
404 modelName: "service"});
407 define_model(this, {urlRoot: SLICEPLUS_API,
408 relatedCollections: {'slivers': "slice"},
409 modelName: "slicePlus",
410 collectionName: "slicesPlus"});
412 this.listObjects = function() { return this.allCollectionNames; };
414 this.getCollectionStatus = function() {
415 stats = {isLoaded: 0, failedLoad: 0, startedLoad: 0};
416 for (index in this.allCollections) {
417 collection = this.allCollections[index];
418 if (collection.isLoaded) {
419 stats["isLoaded"] = stats["isLoaded"] + 1;
421 if (collection.failedLoad) {
422 stats["failedLoad"] = stats["failedLoad"] + 1;
424 if (collection.startedLoad) {
425 stats["startedLoad"] = stats["startedLoad"] + 1;
428 stats["completedLoad"] = stats["failedLoad"] + stats["isLoaded"];
435 function getCookie(name) {
436 var cookieValue = null;
\r
437 if (document.cookie && document.cookie != '') {
\r
438 var cookies = document.cookie.split(';');
\r
439 for (var i = 0; i < cookies.length; i++) {
\r
440 var cookie = jQuery.trim(cookies[i]);
\r
441 // Does this cookie string begin with the name we want?
\r
442 if (cookie.substring(0, name.length + 1) == (name + '=')) {
\r
443 cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
\r
448 return cookieValue;
\r
452 var _sync = Backbone.sync;
\r
453 Backbone.sync = function(method, model, options){
\r
454 options.beforeSend = function(xhr){
\r
455 var token = getCookie("csrftoken");
\r
456 xhr.setRequestHeader('X-CSRFToken', token);
\r
458 return _sync(method, model, options);
\r