Merge branch 'master' of ssh://git.planet-lab.org/git/plstackapi
[plstackapi.git] / planetstack / core / xoslib / static / js / xoslib / xos-backbone.js
1 if (! window.XOSLIB_LOADED ) {
2     window.XOSLIB_LOADED=true;
3
4     SLIVER_API = "/plstackapi/slivers/";
5     SLICE_API = "/plstackapi/slices/";
6     SLICEDEPLOYMENT_API = "/plstackapi/slice_deployments/";
7     SLICEPRIVILEGE_API = "/plstackapi/slice_privileges/";
8     SLICEROLE_API = "/plstackapi/slice_roles/";
9     NODE_API = "/plstackapi/nodes/";
10     SITE_API = "/plstackapi/sites/";
11     USER_API = "/plstackapi/users/";
12     USERDEPLOYMENT_API = "/plstackapi/user_deployments/";
13     DEPLOYMENT_API = "/plstackapi/deployments/";
14     IMAGE_API = "/plstackapi/images/";
15     NETWORKTEMPLATE_API = "/plstackapi/networktemplates/";
16     NETWORKDEPLOYMENT_API = "/plstackapi/networkdeployments/";
17     NETWORK_API = "/plstackapi/networks/";
18     NETWORKSLIVER_API = "/plstackapi/networkslivers/";
19     SERVICE_API = "/plstackapi/services/";
20
21     SLICEPLUS_API = "/xoslib/slicesplus/";
22
23     XOSModel = Backbone.Model.extend({
24         /* from backbone-tastypie.js */
25         //idAttribute: 'resource_uri',
26
27         /* from backbone-tastypie.js */
28         url: function() {
29                     var url = this.attributes.resource_uri;
30
31                     if (!url) {
32                         if (this.id) {
33                             url = this.urlRoot + this.id;
34                         } else {
35                             // this happens when creating a new model.
36                             url = this.urlRoot;
37                         }
38                     }
39
40                     if (!url) {
41                         // XXX I'm not sure this does anything useful
42                         url = ( _.isFunction( this.collection.url ) ? this.collection.url() : this.collection.url );
43                         url = url || this.urlRoot;
44                     }
45
46                     // remove any existing query parameters
47                     url && ( url.indexOf("?") > -1 ) && ( url = url.split("?")[0] );
48
49                     url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );
50
51                     url && ( url += "?no_hyperlinks=1" );
52
53                     return url;
54             },
55
56             listMethods: function() {
57                 var res = [];\r
58                 for(var m in this) {\r
59                     if(typeof this[m] == "function") {\r
60                         res.push(m)\r
61                     }\r
62                 }\r
63                 return res;\r
64             }
65     });
66
67     XOSCollection = Backbone.Collection.extend({
68         objects: function() {
69                     return this.models.map(function(element) { return element.attributes; });
70                  },
71
72         initialize: function(){
73           this.isLoaded = false;
74           this.sortVar = 'name';\r
75           this.sortOrder = 'asc';\r
76           this.on( "sort", this.sorted );\r
77         },\r
78 \r
79         relatedCollections: [],\r
80         foreignCollections: [],\r
81 \r
82         sorted: function() {\r
83             this.isLoaded = true;\r
84         },\r
85 \r
86         simpleComparator: function( model ){\r
87           parts=this.sortVar.split(".");\r
88           result = model.get(parts[0]);\r
89           for (index=1; index<parts.length; ++index) {\r
90               result=result[parts[index]];\r
91           }\r
92           return result;\r
93         },\r
94 \r
95         comparator: function (left, right) {\r
96             var l = this.simpleComparator(left);\r
97             var r = this.simpleComparator(right);\r
98 \r
99             if (l === void 0) return -1;\r
100             if (r === void 0) return 1;\r
101 \r
102             if (this.sortOrder=="desc") {\r
103                 return l < r ? 1 : l > r ? -1 : 0;\r
104             } else {\r
105                 return l < r ? -1 : l > r ? 1 : 0;\r
106             }\r
107         },\r
108 \r
109         startPolling: function() {\r
110             if (!this._polling) {\r
111                 var collection=this;
112                 setInterval(function() { collection.fetch(); }, 10000);
113                 this._polling=true;
114                 this.fetch();
115             }
116         },
117
118         maybeFetch: function(options){
119                 // Helper function to fetch only if this collection has not been fetched before.
120             if(this._fetched){
121                     // If this has already been fetched, call the success, if it exists
122                 options.success && options.success();
123                 console.log("alreadyFetched");
124                 return;
125             }
126
127                 // when the original success function completes mark this collection as fetched
128             var self = this,
129             successWrapper = function(success){
130                 return function(){
131                     self._fetched = true;
132                     success && success.apply(this, arguments);
133                 };
134             };
135             options.success = successWrapper(options.success);
136             console.log("call fetch");
137             this.fetch(options);
138         },
139
140         getOrFetch: function(id, options){
141                 // Helper function to use this collection as a cache for models on the server
142             var model = this.get(id);
143
144             if(model){
145                 options.success && options.success(model);
146                 return;
147             }
148
149             model = new this.model({
150                 resource_uri: id
151             });
152
153             model.fetch(options);
154         },
155
156         filterBy: function(fieldName, value) {
157              filtered = this.filter(function(obj) {
158                  return obj.get(fieldName) == value;
159                  });
160              return new this.constructor(filtered);
161         },
162
163         /* from backbone-tastypie.js */
164         url: function( models ) {
165                     var url = this.urlRoot || ( models && models.length && models[0].urlRoot );
166                     url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );
167
168                     // Build a url to retrieve a set of models. This assume the last part of each model's idAttribute
169                     // (set to 'resource_uri') contains the model's id.
170                     if ( models && models.length ) {
171                             var ids = _.map( models, function( model ) {
172                                             var parts = _.compact( model.id.split('/') );
173                                             return parts[ parts.length - 1 ];
174                                     });
175                             url += 'set/' + ids.join(';') + '/';
176                     }
177
178                     url && ( url += "?no_hyperlinks=1" );
179
180                     return url;
181             },
182
183         listMethods: function() {
184                 var res = [];\r
185                 for(var m in this) {\r
186                     if(typeof this[m] == "function") {\r
187                         res.push(m)\r
188                     }\r
189                 }\r
190                 return res;\r
191             },
192     });
193
194     function define_model(lib, attrs) {
195         modelName = attrs.modelName;
196         modelClassName = modelName;
197         collectionClassName = modelName + "Collection";
198         collectionName = modelName + "s";
199
200         modelAttrs = {}
201         collectionAttrs = {}
202
203         for (key in attrs) {
204             value = attrs[key];
205             if ($.inArray(key, ["urlRoot", "modelName"])>=0) {
206                 modelAttrs[key] = value;
207             }
208             if ($.inArray(key, ["urlRoot", "modelName", "relatedCollections", "foreignCollections"])>=0) {
209                 collectionAttrs[key] = value;
210             }
211         }
212
213         if (xosdefaults && xosdefaults[modelName]) {
214             modelAttrs["defaults"] = xosdefaults[modelName];
215         }
216
217         lib[modelName] = XOSModel.extend(modelAttrs);
218
219         collectionAttrs["model"] = lib[modelName];
220
221         lib[collectionClassName] = XOSCollection.extend(collectionAttrs);
222         lib[collectionName] = new lib[collectionClassName]();
223
224         lib.allCollectionNames.push(collectionName);
225     };
226
227     function xoslib() {
228         this.allCollectionNames = [];
229
230         define_model(this, {urlRoot: SLIVER_API,
231                             relatedCollections: {"networkSlivers": "sliver"},
232                             foreignCollections: ["slices", "deployments", "images", "nodes", "users"],
233                             modelName: "sliver"});
234
235         define_model(this, {urlRoot: SLICE_API,
236                            relatedCollections: {"slivers": "slice", "sliceDeployments": "slice", "slicePrivileges": "slice", "networks": "owner"},
237                            foreignCollections: ["services", "sites"],
238                            modelName: "slice"});
239
240         define_model(this, {urlRoot: SLICEDEPLOYMENT_API,
241                            foreignCollections: ["slices", "deployments"],
242                            modelName: "sliceDeployment"});
243
244         define_model(this, {urlRoot: SLICEPRIVILEGE_API,
245                             foreignCollections: ["slices", "users", "sliceRoles"],
246                             modelName: "slicePrivilege"});
247
248         define_model(this, {urlRoot: SLICEROLE_API,
249                             modelName: "sliceRole"});
250
251         define_model(this, {urlRoot: NODE_API,
252                             foreignCollections: ["sites", "deployments"],
253                             modelName: "node"});
254
255         define_model(this, {urlRoot: SITE_API,
256                             relatedCollections: {"users": "site", "slices": "site", "nodes": "site"},
257                             modelName: "site"});
258
259         define_model(this, {urlRoot: USER_API,
260                             relatedCollections: {"slicePrivileges": "user", "slices": "owner", "userDeployments": "user"},
261                             foreignCollections: ["sites"],
262                             modelName: "user"});
263
264         define_model(this, {urlRoot: USERDEPLOYMENT_API,
265                             foreignCollections: ["users","deployments"],
266                             modelName: "userDeployment"});
267
268         define_model(this, { urlRoot: DEPLOYMENT_API,
269                              relatedCollections: {"nodes": "deployment", "slivers": "deploymentNetwork", "networkDeployments": "deployment", "userDeployments": "deployment"},
270                              modelName: "deployment"});
271
272         define_model(this, {urlRoot: IMAGE_API,
273                             model: this.image,
274                             modelName: "image"});
275
276         define_model(this, {urlRoot: NETWORKTEMPLATE_API,
277                             modelName: "networkTemplate"});
278
279         define_model(this, {urlRoot: NETWORK_API,
280                             relatedCollections: {"networkDeployments": "network", "networkSlivers": "network"},
281                             foreignCollections: ["slices", "networkTemplates"],
282                             modelName: "network"});
283
284         define_model(this, {urlRoot: NETWORKSLIVER_API,
285                             modelName: "networkSliver"});
286
287         define_model(this, {urlRoot: NETWORKDEPLOYMENT_API,
288                             modelName: "networkDeployment"});
289
290         define_model(this, {urlRoot: SERVICE_API,
291                             modelName: "service"});
292
293         // enhanced REST
294         define_model(this, {urlRoot: SLICEPLUS_API,
295                             relatedCollections: {'slivers': "slice"},
296                             modelName: "slicePlus"});
297
298         this.listObjects = function() { return this.allCollectionNames; };
299     };
300
301     xos = new xoslib();
302
303     function getCookie(name) {
304         var cookieValue = null;\r
305         if (document.cookie && document.cookie != '') {\r
306             var cookies = document.cookie.split(';');\r
307             for (var i = 0; i < cookies.length; i++) {\r
308                 var cookie = jQuery.trim(cookies[i]);\r
309                 // Does this cookie string begin with the name we want?\r
310                 if (cookie.substring(0, name.length + 1) == (name + '=')) {\r
311                     cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\r
312                     break;\r
313                 }\r
314             }\r
315         }\r
316         return cookieValue;\r
317     }
318
319     (function() {
320       var _sync = Backbone.sync;\r
321       Backbone.sync = function(method, model, options){\r
322         options.beforeSend = function(xhr){\r
323           var token = getCookie("csrftoken");\r
324           xhr.setRequestHeader('X-CSRFToken', token);\r
325         };\r
326         return _sync(method, model, options);\r
327       };\r
328     })();
329 }