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 /* If a 'validate' method is supplied, then it will be called
74 automatically on save. Unfortunately, save calls neither the
75 'error' nor the 'success' callback if the validator fails.
77 For now, we're calling our validator 'xosValidate' so this
78 autoamtic validation doesn't occur.
81 xosValidate: function(attrs, options) {
84 _.each(this.validators, function(validatorList, fieldName) {
85 _.each(validatorList, function(validator) {
86 if (fieldName in attrs) {
87 validatorResult = validateField(validator, attrs[fieldName], this)
88 if (validatorResult != true) {
89 errors[fieldName] = validatorResult;
98 // backbone.js semantics -- on successful validate, return nothing
101 /* uncommenting this would make validate() call xosValidate()
102 validate: function(attrs, options) {
103 r = this.xosValidate(attrs, options);
104 console.log("validate");
110 XOSCollection = Backbone.Collection.extend({
111 objects: function() {
112 return this.models.map(function(element) { return element.attributes; });
115 initialize: function(){
116 this.isLoaded = false;
117 this.failedLoad = false;
118 this.startedLoad = false;
119 this.sortVar = 'name';
\r
120 this.sortOrder = 'asc';
\r
121 this.on( "sort", this.sorted );
\r
124 relatedCollections: [],
\r
125 foreignCollections: [],
\r
127 sorted: function() {
\r
128 //console.log("sorted " + this.modelName);
\r
131 simpleComparator: function( model ){
\r
132 parts=this.sortVar.split(".");
\r
133 result = model.get(parts[0]);
\r
134 for (index=1; index<parts.length; ++index) {
\r
135 result=result[parts[index]];
\r
140 comparator: function (left, right) {
\r
141 var l = this.simpleComparator(left);
\r
142 var r = this.simpleComparator(right);
\r
144 if (l === void 0) return -1;
\r
145 if (r === void 0) return 1;
\r
147 if (this.sortOrder=="desc") {
\r
148 return l < r ? 1 : l > r ? -1 : 0;
\r
150 return l < r ? -1 : l > r ? 1 : 0;
\r
154 fetchSuccess: function(collection, response, options) {
\r
155 //console.log("fetch succeeded " + collection.modelName);
\r
156 this.failedLoad = false;
\r
157 this.fetching = false;
\r
158 if (!this.isLoaded) {
\r
159 this.isLoaded = true;
\r
160 Backbone.trigger("xoslib:collectionLoadChange", this);
\r
162 this.trigger("fetchStateChange");
\r
163 if (options["orig_success"]) {
\r
164 options["orig_success"](collection, response, options);
\r
168 fetchFailure: function(collection, response, options) {
\r
169 //console.log("fetch failed " + collection.modelName);
\r
170 this.fetching = false;
\r
171 if ((!this.isLoaded) && (!this.failedLoad)) {
\r
172 this.failedLoad=true;
\r
173 Backbone.trigger("xoslib:collectionLoadChange", this);
\r
175 this.trigger("fetchStateChange");
\r
176 if (options["orig_failure"]) {
\r
177 options["orig_failure"](collection, response, options);
\r
181 fetch: function(options) {
\r
183 this.fetching=true;
\r
184 //console.log("fetch " + this.modelName);
\r
185 if (!this.startedLoad) {
\r
186 this.startedLoad=true;
\r
187 Backbone.trigger("xoslib:collectionLoadChange", this);
\r
189 this.trigger("fetchStateChange");
\r
190 if (options == undefined) {
\r
193 options["orig_success"] = options["success"];
\r
194 options["orig_failure"] = options["failure"];
\r
195 options["success"] = function(collection, response, options) { self.fetchSuccess.call(self, collection, response, options); };
\r
196 options["failure"] = this.fetchFailure;
\r
197 Backbone.Collection.prototype.fetch.call(this, options);
\r
200 startPolling: function() {
\r
201 if (!this._polling) {
\r
203 setInterval(function() { collection.fetch(); }, 10000);
209 refresh: function(refreshRelated) {
210 if (!this.fetching) {
213 if (refreshRelated) {
214 for (related in this.relatedCollections) {
215 related = xos[related];
216 if (!related.fetching) {
223 maybeFetch: function(options){
224 // Helper function to fetch only if this collection has not been fetched before.
226 // If this has already been fetched, call the success, if it exists
227 options.success && options.success();
228 console.log("alreadyFetched");
232 // when the original success function completes mark this collection as fetched
234 successWrapper = function(success){
236 self._fetched = true;
237 success && success.apply(this, arguments);
240 options.success = successWrapper(options.success);
241 console.log("call fetch");
245 getOrFetch: function(id, options){
246 // Helper function to use this collection as a cache for models on the server
247 var model = this.get(id);
250 options.success && options.success(model);
254 model = new this.model({
258 model.fetch(options);
261 filterBy: function(fieldName, value) {
262 filtered = this.filter(function(obj) {
263 return obj.get(fieldName) == value;
265 return new this.constructor(filtered);
268 /* from backbone-tastypie.js */
269 url: function( models ) {
270 var url = this.urlRoot || ( models && models.length && models[0].urlRoot );
271 url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );
273 // Build a url to retrieve a set of models. This assume the last part of each model's idAttribute
274 // (set to 'resource_uri') contains the model's id.
275 if ( models && models.length ) {
276 var ids = _.map( models, function( model ) {
277 var parts = _.compact( model.id.split('/') );
278 return parts[ parts.length - 1 ];
280 url += 'set/' + ids.join(';') + '/';
283 url && ( url += "?no_hyperlinks=1" );
288 listMethods: function() {
290 for(var m in this) {
\r
291 if(typeof this[m] == "function") {
\r
299 function define_model(lib, attrs) {
300 modelName = attrs.modelName;
301 modelClassName = modelName;
302 collectionClassName = modelName + "Collection";
304 if (!attrs.collectionName) {
305 attrs.collectionName = modelName + "s";
307 collectionName = attrs.collectionName;
314 if ($.inArray(key, ["urlRoot", "modelName", "collectionName", "validate"])>=0) {
315 modelAttrs[key] = value;
317 if ($.inArray(key, ["urlRoot", "modelName", "collectionName", "relatedCollections", "foreignCollections"])>=0) {
318 collectionAttrs[key] = value;
322 if (xosdefaults && xosdefaults[modelName]) {
323 modelAttrs["defaults"] = xosdefaults[modelName];
326 if (xosvalidators && xosvalidators[modelName]) {
327 modelAttrs["validators"] = xosvalidators[modelName];
330 lib[modelName] = XOSModel.extend(modelAttrs);
332 collectionAttrs["model"] = lib[modelName];
334 lib[collectionClassName] = XOSCollection.extend(collectionAttrs);
335 lib[collectionName] = new lib[collectionClassName]();
337 lib.allCollectionNames.push(collectionName);
338 lib.allCollections.push(lib[collectionName]);
342 this.allCollectionNames = [];
343 this.allCollections = [];
345 define_model(this, {urlRoot: SLIVER_API,
346 relatedCollections: {"networkSlivers": "sliver"},
347 foreignCollections: ["slices", "deployments", "images", "nodes", "users"],
348 modelName: "sliver"});
350 define_model(this, {urlRoot: SLICE_API,
351 relatedCollections: {"slivers": "slice", "sliceDeployments": "slice", "slicePrivileges": "slice", "networks": "owner"},
352 foreignCollections: ["services", "sites"],
354 xosValidate: function(attrs, options) {
355 errors = XOSModel.prototype.xosValidate(this, attrs, options);
356 // validate that slice.name starts with site.login_base
357 site = attrs.site || this.site;
358 if ((site!=undefined) && (attrs.name!=undefined)) {
359 site = xos.sites.get(site);
360 if (attrs.name.indexOf(site.attributes.login_base+"_") != 0) {
361 errors = errors || {};
362 errors["name"] = "must start with " + site.attributes.login_base + "_";
369 define_model(this, {urlRoot: SLICEDEPLOYMENT_API,
370 foreignCollections: ["slices", "deployments"],
371 modelName: "sliceDeployment"});
373 define_model(this, {urlRoot: SLICEPRIVILEGE_API,
374 foreignCollections: ["slices", "users", "sliceRoles"],
375 modelName: "slicePrivilege"});
377 define_model(this, {urlRoot: SLICEROLE_API,
378 modelName: "sliceRole"});
380 define_model(this, {urlRoot: NODE_API,
381 foreignCollections: ["sites", "deployments"],
384 define_model(this, {urlRoot: SITE_API,
385 relatedCollections: {"users": "site", "slices": "site", "nodes": "site"},
388 define_model(this, {urlRoot: USER_API,
389 relatedCollections: {"slicePrivileges": "user", "slices": "owner", "userDeployments": "user"},
390 foreignCollections: ["sites"],
393 define_model(this, {urlRoot: USERDEPLOYMENT_API,
394 foreignCollections: ["users","deployments"],
395 modelName: "userDeployment"});
397 define_model(this, { urlRoot: DEPLOYMENT_API,
398 relatedCollections: {"nodes": "deployment", "slivers": "deploymentNetwork", "networkDeployments": "deployment", "userDeployments": "deployment"},
399 modelName: "deployment"});
401 define_model(this, {urlRoot: IMAGE_API,
403 modelName: "image"});
405 define_model(this, {urlRoot: NETWORKTEMPLATE_API,
406 modelName: "networkTemplate"});
408 define_model(this, {urlRoot: NETWORK_API,
409 relatedCollections: {"networkDeployments": "network", "networkSlivers": "network"},
410 foreignCollections: ["slices", "networkTemplates"],
411 modelName: "network"});
413 define_model(this, {urlRoot: NETWORKSLIVER_API,
414 modelName: "networkSliver"});
416 define_model(this, {urlRoot: NETWORKDEPLOYMENT_API,
417 modelName: "networkDeployment"});
419 define_model(this, {urlRoot: SERVICE_API,
420 modelName: "service"});
423 define_model(this, {urlRoot: SLICEPLUS_API,
424 relatedCollections: {'slivers': "slice"},
425 modelName: "slicePlus",
426 collectionName: "slicesPlus"});
428 this.listObjects = function() { return this.allCollectionNames; };
430 this.getCollectionStatus = function() {
431 stats = {isLoaded: 0, failedLoad: 0, startedLoad: 0};
432 for (index in this.allCollections) {
433 collection = this.allCollections[index];
434 if (collection.isLoaded) {
435 stats["isLoaded"] = stats["isLoaded"] + 1;
437 if (collection.failedLoad) {
438 stats["failedLoad"] = stats["failedLoad"] + 1;
440 if (collection.startedLoad) {
441 stats["startedLoad"] = stats["startedLoad"] + 1;
444 stats["completedLoad"] = stats["failedLoad"] + stats["isLoaded"];
451 function getCookie(name) {
452 var cookieValue = null;
\r
453 if (document.cookie && document.cookie != '') {
\r
454 var cookies = document.cookie.split(';');
\r
455 for (var i = 0; i < cookies.length; i++) {
\r
456 var cookie = jQuery.trim(cookies[i]);
\r
457 // Does this cookie string begin with the name we want?
\r
458 if (cookie.substring(0, name.length + 1) == (name + '=')) {
\r
459 cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
\r
464 return cookieValue;
\r
468 var _sync = Backbone.sync;
\r
469 Backbone.sync = function(method, model, options){
\r
470 options.beforeSend = function(xhr){
\r
471 var token = getCookie("csrftoken");
\r
472 xhr.setRequestHeader('X-CSRFToken', token);
\r
474 return _sync(method, model, options);
\r