Add scripts to create myops-getqueryview:
[myops.git] / web / query / lists / nodelist.js
1 function(head, req) {
2   var ddoc = this;
3   var Mustache = require("lib/mustache");
4   var List = require("vendor/couchapp/lib/list");
5   var path = require("vendor/couchapp/lib/path").init(req);
6   var Atom = require("vendor/couchapp/lib/atom");
7
8   var within = 0;
9         if ( 'within' in req.query ) {
10                 within = Number(req.query['within']);
11                 log("within: " + within);
12         } else {
13                 within = 60 * 60 * 3;   // within three hours;
14         }
15   var ts = (new Date()).getTime()/1000 - within; // convert milliseconds to seconds
16
17   var indexPath = path.list('nodelist','node-status',{descending:true, limit:10});
18   var feedPath = path.list('nodelist','node-status',{descending:true, limit:10, format:"atom"});
19   var commentsFeed = path.list('comments','comments',{descending:true, limit:10, format:"atom"});
20
21   var path_parts = req.path;
22   var EQ=1;
23   var NE=2;
24   var LE=3;
25   var GE=4;
26   var MATCH=5;
27   var AND=6;
28   var OR=7;
29   var NOT_MATCH=8;
30
31   function check_field(query, field, def) { 
32         var ret = def;
33         if ( field in query ) {
34                 ret = query[field];
35                 log(field + ": " + ret);
36         }
37         return ret;
38   }
39
40   function token_get(sf) {
41                 var ret = null;
42                 var fields = null;
43                 var r = null;
44                 var f_eq = /==/;
45                 var f_ne = /!=/;
46                 var f_le = /<=|%3C=|%3c=/;
47                 var f_ge = />=|%3E=|%3e=/;
48                 var f_match = /=~/;
49                 var f_not_match = /!~/;
50
51                 if ( sf.match(f_eq) ) {
52                         fields = sf.split("==");
53                         ret = [fields[0], fields[1], EQ];
54                 } else if ( sf.match(f_ne) ) {
55                         fields = sf.split("!=");
56                         ret = [fields[0], fields[1], NE] ;
57                 } else if ( sf.match(f_le) ) {
58                         fields = sf.split("<=");
59                         ret = [fields[0], Number(fields[1]), LE] ;
60                 } else if ( sf.match(f_ge) ) {
61                         fields = sf.split(">=");
62                         ret = [fields[0], Number(fields[1]), GE] ;
63                 } else if ( sf.match(f_not_match) ) {
64                         fields = sf.split("!~");
65                         r = fields[1];
66                         ret = [fields[0], r, NOT_MATCH] ;
67
68                 } else if ( sf.match(f_match) ) {
69                         log("sf: " + sf);
70                         fields = sf.split("=~");
71
72                         log("fields: " + fields);
73                         //r = RegExp(fields[1]);
74                         r = fields[1];
75                         log("regex: " + r);
76                         ret = [fields[0], r, MATCH] ;
77                         log("ret: " + ret);
78                 } else {
79                         log("no match!")
80                 }
81                 return ret;
82   }
83   function token_conjunction_get(sf) {
84                 var f_and = /AND|%%|&&/;
85                 var f_or = /OR|\|\|/;
86
87                 var l = [];
88                 var tcg = {}; 
89                 var type=AND;
90                 var fields = null;
91
92                 log("sfilter: " + sf);
93                 if ( sf.match(f_and) ) {
94                         fields = sf.split(f_and);
95                         type = AND;
96
97                 } else if ( sf.match(f_or) ) {
98                         fields = sf.split(f_or);
99                         type = OR;
100
101                 } else {
102                         type = AND;
103                         fields = [ sf ];
104                 }
105
106                 for ( var i=0; i < fields.length ; i++)
107                 {
108                         var t = token_get(fields[i]);
109                         log("t:" + t);
110                         l.push(t);
111                 }
112                 log("l:" + l);
113                 tcg['list'] = l;
114                 tcg['type'] = type;
115                 log("tcg:" + JSON.stringify(tcg));
116                 return tcg;
117   }
118
119   function token_test(token, row)
120   {
121         var     prop = token[0];
122         var val = token[1];
123         var op = token[2];
124         var result_minor = true;
125
126                 if ( op == EQ ) {
127                         result_minor &= val == row[prop];
128                 } else if ( op == NE ) {
129                         result_minor &= val != row[prop];
130                 } else if ( op == LE && prop in row ) {
131                         result_minor &= Number(row[prop]) <= val;
132                         //result_minor &= parseFloat(row[prop]) <= val;
133                 } else if ( op == GE && prop in row ) {
134                         //#result_minor &= Number(row[prop]) >= val;
135                         result_minor &= parseFloat(row[prop]) >= val;
136                 } else if ( ( op == MATCH || op == NOT_MATCH ) && prop in row ) {
137                         val = new RegExp(val);
138                         if ( typeof(row[prop]) == "object" ) {
139                                 var found = false;
140                                 for (var i=0; i < row[prop].length ; i++ ) {
141                                         if ( val.test(row[prop][i]) ) { 
142                                                 found = true;
143                                                 break; 
144                                         }
145                                 }
146                                 result_minor &= found;
147                         } else {
148                                 result_minor &= val.test(row[prop]);
149                         }
150                         if ( op == NOT_MATCH ) {
151                                 // reverse the result if we actually want a non-match
152                             result_minor = !result_minor;
153                         }
154                 } else {
155                         result_minor = false;
156                 }
157         return result_minor;
158   }
159
160   function parse_filter (sfilter) { 
161
162                 log("sfilter: " + sfilter);
163                 if ( sfilter == "" ) { return null; }
164                 var ret = token_conjunction_get(sfilter);
165                 log("tcg2: " + JSON.stringify(ret));
166                 return ret;
167   } 
168
169   function filter_matches (row, pfilter) { 
170                 var result_minor = true;
171                 var result = true;
172                 if ( pfilter != null ) {
173
174                         // set defaults based on conjunction type
175                         if ( pfilter['type'] == AND ) {
176                                 result = true;
177                         } else if ( pfilter['type'] == OR ) {
178                                 result = false;
179                         }
180
181                         for ( var i=0; i < pfilter['list'].length ; i++ )
182                         {
183                                 tok = pfilter['list'][i];
184                                 result_minor = token_test(tok, row);
185
186                                 if (pfilter['type'] == AND ) {
187                                         result &= result_minor;
188                                 } else if ( pfilter['type'] == OR ) {
189                                         result |= result_minor;
190                                 }
191                         }
192                         //log("filter:" + JSON.stringify(pfilter) + " result: " +  result);
193
194                 }
195                 return result; 
196         } 
197   // The provides function serves the format the client requests.
198   // The first matching format is sent, so reordering functions changes 
199   // thier priority. In this case HTML is the preferred format, so it comes first.
200   provides("text", function() {
201                 var row, first_row = true;
202                 var skip_header = false;
203                 var skip_props = {'_id' : "", '_rev' : "", '_deleted_conflicts' : '',}; // 'hardware' : '', };
204
205                 var more_props = true;
206                 var header;
207                 var count=0;
208                 var rowstring;
209                 var pfilter = null;
210                 var pattern = null;
211                 var prop_start = [ "hostname", 'ts' ];
212                 var prop_list = {'hostname' : '', 'ts' : ''};
213                 var show = check_field(req.query, 'show', null);
214
215                 if ( show != null ) { show = Number(show); }
216
217                 log("req: ");
218                 log(req);
219                 log(head);
220
221                 if ( 'filter' in req.query ) {
222                         pfilter = parse_filter(req.query['filter']);
223                         log("pf: " + JSON.stringify(pfilter));
224                 }
225
226                 if ( 'rpmpattern' in req.query ) {
227                         pattern = req.query['rpmpattern'];
228                         log("found pattern");
229                         log(pattern);
230                 }
231
232                 if ( 'prop_list' in req.query || 'fields' in req.query ) {
233                         if ( 'prop_list' in req.query ) { 
234                                 prop_start = req.query['prop_list'].split(',');
235                         } else {
236                                 prop_start = req.query['fields'].split(',');
237                         }
238                         prop_list = {'hostname' : '', 'ts' : ''};
239                         for ( var i=0; i < prop_start.length ; i++) {
240                                 prop_list[prop_start[i]] = "";
241                         }
242                         more_props = false;
243                 }
244                 if ( 'skip_header' in req.query ) { 
245                         skip_header = true;
246                 }
247
248                 while (row = getRow()) {
249                         if ( row.key[0] < ts ) { continue; }
250                         if ( show != null && count >= show ) { break; }
251
252                         if ( first_row == true )
253                         {
254                                 header = "";
255                                 // get a list of all properties
256                                 for (var prop in row.value ) {
257                                         if ( ! (prop in prop_list) && more_props ) {
258                                                 prop_start.push(prop);
259                                                 prop_list[prop] = "";
260                                         }
261                                 }
262                                 if ( ! skip_header ) {
263                                         // create a header for all the data to follow
264                                         for (var i=0 ; i < prop_start.length ; i++) {
265                                                 prop = prop_start[i];
266                                                 if ( ! (prop in skip_props) ) {
267                                                         header += prop + ',';
268                                                 }
269                                         }
270                                         send(header.substring(0,header.length-1) + '\n');
271                                 }
272                                 first_row = false;
273                         }
274                         rowstring = "";
275
276                         if ( filter_matches(row.value, pfilter) )
277                         {
278                                 //send(header.substring(0,-1) + '\n');
279                                 // Send the data that matches the filter when present
280                                 for (var i=0 ; i < prop_start.length ; i++) {
281                                         prop = prop_start[i];
282                                         if ( ! (prop in skip_props) )
283                                         {
284                                                 if ( (prop == 'rpm_versions') && (pattern != null) && ('rpm_versions' in prop_list) ) {
285                                                         if ( typeof(row.value['rpm_versions']) == "object" ) {
286                                                                 for (var i; i < row.value['rpm_versions'].length ; i++ ) {
287                                                                         var rpm = row.value['rpm_versions'][i].match(pattern);
288                                                                         if ( rpm ) { break; }
289                                                                 }
290                                                                 log(rpm);
291                                                                 if ( rpm ) { 
292                                                                         rowstring += rpm.join(' ') + ',';
293                                                                 } else {
294                                                                         rowstring += ',';
295                                                                 }
296                                                         } else {
297                                                                 log("not a string");
298                                                                 log(typeof(row.value['rpm_versions']));
299                                                                 rowstring += ',';
300                                                         }
301                                                 //if ( false ) {
302                                                 //      log("test");
303                                                 } else {
304                                                         if ( typeof(row.value[prop]) == "object" )
305                                                         {
306                                                                 rowstring += row.value[prop].join(" ") + ',';
307                                                         } else {
308                                                                 rowstring += row.value[prop] + ',';
309                                                         }
310                                                 }
311                                         }
312                                 }
313                                 send(rowstring.substring(0,rowstring.length-1) + '\n');
314                                 count += 1;
315                         }
316                 } 
317                 // tail 
318                 return '\n';
319   });
320   provides("3mtl", function() {
321     var key = "";
322     // render the html head using a template
323     var stash = {
324       header : {
325         index : indexPath,
326         blogName : ddoc.blog.title,
327         feedPath : feedPath,
328         commentsFeed : commentsFeed
329       },
330       scripts : {},
331       db : req.path[0],
332       design : req.path[2],
333       feedPath : feedPath,
334       newPostPath : path.show("edit"),
335       assets : path.asset(),
336       nodes : List.withRows(function(row) {
337         var node = row.value;
338         key = row.key;
339         return {
340           name : node.hostname,
341           site : node.site,
342           date : node.date_created,
343           link : path.list('node','node-page', {startkey : [row.id]}),
344           has_slices : false,
345                   slices : [],
346         };
347       }),
348       older : function() {
349         return path.older(key);
350       },
351       "5" : path.limit(5),
352       "10" : path.limit(10),
353       "25" : path.limit(25)
354     };
355     return Mustache.to_html(ddoc.templates.nodelist, stash, ddoc.templates.partials, List.send);
356   });
357
358 };