X-Git-Url: http://git.onelab.eu/?p=myops.git;a=blobdiff_plain;f=web%2Fquery%2Flists%2Fnodelist.js;fp=web%2Fquery%2Flists%2Fnodelist.js;h=f5061286f666e23c8c4265d7cd2b0f7046dc7d79;hp=0000000000000000000000000000000000000000;hb=85070b3d456667f238051af1a2f1f2a0c12300ab;hpb=607f0e13927eb18075c375fa9ba5527da4fcbb44 diff --git a/web/query/lists/nodelist.js b/web/query/lists/nodelist.js new file mode 100644 index 0000000..f506128 --- /dev/null +++ b/web/query/lists/nodelist.js @@ -0,0 +1,358 @@ +function(head, req) { + var ddoc = this; + var Mustache = require("lib/mustache"); + var List = require("vendor/couchapp/lib/list"); + var path = require("vendor/couchapp/lib/path").init(req); + var Atom = require("vendor/couchapp/lib/atom"); + + var within = 0; + if ( 'within' in req.query ) { + within = Number(req.query['within']); + log("within: " + within); + } else { + within = 60 * 60 * 3; // within three hours; + } + var ts = (new Date()).getTime()/1000 - within; // convert milliseconds to seconds + + var indexPath = path.list('nodelist','node-status',{descending:true, limit:10}); + var feedPath = path.list('nodelist','node-status',{descending:true, limit:10, format:"atom"}); + var commentsFeed = path.list('comments','comments',{descending:true, limit:10, format:"atom"}); + + var path_parts = req.path; + var EQ=1; + var NE=2; + var LE=3; + var GE=4; + var MATCH=5; + var AND=6; + var OR=7; + var NOT_MATCH=8; + + function check_field(query, field, def) { + var ret = def; + if ( field in query ) { + ret = query[field]; + log(field + ": " + ret); + } + return ret; + } + + function token_get(sf) { + var ret = null; + var fields = null; + var r = null; + var f_eq = /==/; + var f_ne = /!=/; + var f_le = /<=|%3C=|%3c=/; + var f_ge = />=|%3E=|%3e=/; + var f_match = /=~/; + var f_not_match = /!~/; + + if ( sf.match(f_eq) ) { + fields = sf.split("=="); + ret = [fields[0], fields[1], EQ]; + } else if ( sf.match(f_ne) ) { + fields = sf.split("!="); + ret = [fields[0], fields[1], NE] ; + } else if ( sf.match(f_le) ) { + fields = sf.split("<="); + ret = [fields[0], Number(fields[1]), LE] ; + } else if ( sf.match(f_ge) ) { + fields = sf.split(">="); + ret = [fields[0], Number(fields[1]), GE] ; + } else if ( sf.match(f_not_match) ) { + fields = sf.split("!~"); + r = fields[1]; + ret = [fields[0], r, NOT_MATCH] ; + + } else if ( sf.match(f_match) ) { + log("sf: " + sf); + fields = sf.split("=~"); + + log("fields: " + fields); + //r = RegExp(fields[1]); + r = fields[1]; + log("regex: " + r); + ret = [fields[0], r, MATCH] ; + log("ret: " + ret); + } else { + log("no match!") + } + return ret; + } + function token_conjunction_get(sf) { + var f_and = /AND|%%|&&/; + var f_or = /OR|\|\|/; + + var l = []; + var tcg = {}; + var type=AND; + var fields = null; + + log("sfilter: " + sf); + if ( sf.match(f_and) ) { + fields = sf.split(f_and); + type = AND; + + } else if ( sf.match(f_or) ) { + fields = sf.split(f_or); + type = OR; + + } else { + type = AND; + fields = [ sf ]; + } + + for ( var i=0; i < fields.length ; i++) + { + var t = token_get(fields[i]); + log("t:" + t); + l.push(t); + } + log("l:" + l); + tcg['list'] = l; + tcg['type'] = type; + log("tcg:" + JSON.stringify(tcg)); + return tcg; + } + + function token_test(token, row) + { + var prop = token[0]; + var val = token[1]; + var op = token[2]; + var result_minor = true; + + if ( op == EQ ) { + result_minor &= val == row[prop]; + } else if ( op == NE ) { + result_minor &= val != row[prop]; + } else if ( op == LE && prop in row ) { + result_minor &= Number(row[prop]) <= val; + //result_minor &= parseFloat(row[prop]) <= val; + } else if ( op == GE && prop in row ) { + //#result_minor &= Number(row[prop]) >= val; + result_minor &= parseFloat(row[prop]) >= val; + } else if ( ( op == MATCH || op == NOT_MATCH ) && prop in row ) { + val = new RegExp(val); + if ( typeof(row[prop]) == "object" ) { + var found = false; + for (var i=0; i < row[prop].length ; i++ ) { + if ( val.test(row[prop][i]) ) { + found = true; + break; + } + } + result_minor &= found; + } else { + result_minor &= val.test(row[prop]); + } + if ( op == NOT_MATCH ) { + // reverse the result if we actually want a non-match + result_minor = !result_minor; + } + } else { + result_minor = false; + } + return result_minor; + } + + function parse_filter (sfilter) { + + log("sfilter: " + sfilter); + if ( sfilter == "" ) { return null; } + var ret = token_conjunction_get(sfilter); + log("tcg2: " + JSON.stringify(ret)); + return ret; + } + + function filter_matches (row, pfilter) { + var result_minor = true; + var result = true; + if ( pfilter != null ) { + + // set defaults based on conjunction type + if ( pfilter['type'] == AND ) { + result = true; + } else if ( pfilter['type'] == OR ) { + result = false; + } + + for ( var i=0; i < pfilter['list'].length ; i++ ) + { + tok = pfilter['list'][i]; + result_minor = token_test(tok, row); + + if (pfilter['type'] == AND ) { + result &= result_minor; + } else if ( pfilter['type'] == OR ) { + result |= result_minor; + } + } + //log("filter:" + JSON.stringify(pfilter) + " result: " + result); + + } + return result; + } + // The provides function serves the format the client requests. + // The first matching format is sent, so reordering functions changes + // thier priority. In this case HTML is the preferred format, so it comes first. + provides("text", function() { + var row, first_row = true; + var skip_header = false; + var skip_props = {'_id' : "", '_rev' : "", '_deleted_conflicts' : '',}; // 'hardware' : '', }; + + var more_props = true; + var header; + var count=0; + var rowstring; + var pfilter = null; + var pattern = null; + var prop_start = [ "hostname", 'ts' ]; + var prop_list = {'hostname' : '', 'ts' : ''}; + var show = check_field(req.query, 'show', null); + + if ( show != null ) { show = Number(show); } + + log("req: "); + log(req); + log(head); + + if ( 'filter' in req.query ) { + pfilter = parse_filter(req.query['filter']); + log("pf: " + JSON.stringify(pfilter)); + } + + if ( 'rpmpattern' in req.query ) { + pattern = req.query['rpmpattern']; + log("found pattern"); + log(pattern); + } + + if ( 'prop_list' in req.query || 'fields' in req.query ) { + if ( 'prop_list' in req.query ) { + prop_start = req.query['prop_list'].split(','); + } else { + prop_start = req.query['fields'].split(','); + } + prop_list = {'hostname' : '', 'ts' : ''}; + for ( var i=0; i < prop_start.length ; i++) { + prop_list[prop_start[i]] = ""; + } + more_props = false; + } + if ( 'skip_header' in req.query ) { + skip_header = true; + } + + while (row = getRow()) { + if ( row.key[0] < ts ) { continue; } + if ( show != null && count >= show ) { break; } + + if ( first_row == true ) + { + header = ""; + // get a list of all properties + for (var prop in row.value ) { + if ( ! (prop in prop_list) && more_props ) { + prop_start.push(prop); + prop_list[prop] = ""; + } + } + if ( ! skip_header ) { + // create a header for all the data to follow + for (var i=0 ; i < prop_start.length ; i++) { + prop = prop_start[i]; + if ( ! (prop in skip_props) ) { + header += prop + ','; + } + } + send(header.substring(0,header.length-1) + '\n'); + } + first_row = false; + } + rowstring = ""; + + if ( filter_matches(row.value, pfilter) ) + { + //send(header.substring(0,-1) + '\n'); + // Send the data that matches the filter when present + for (var i=0 ; i < prop_start.length ; i++) { + prop = prop_start[i]; + if ( ! (prop in skip_props) ) + { + if ( (prop == 'rpm_versions') && (pattern != null) && ('rpm_versions' in prop_list) ) { + if ( typeof(row.value['rpm_versions']) == "object" ) { + for (var i; i < row.value['rpm_versions'].length ; i++ ) { + var rpm = row.value['rpm_versions'][i].match(pattern); + if ( rpm ) { break; } + } + log(rpm); + if ( rpm ) { + rowstring += rpm.join(' ') + ','; + } else { + rowstring += ','; + } + } else { + log("not a string"); + log(typeof(row.value['rpm_versions'])); + rowstring += ','; + } + //if ( false ) { + // log("test"); + } else { + if ( typeof(row.value[prop]) == "object" ) + { + rowstring += row.value[prop].join(" ") + ','; + } else { + rowstring += row.value[prop] + ','; + } + } + } + } + send(rowstring.substring(0,rowstring.length-1) + '\n'); + count += 1; + } + } + // tail + return '\n'; + }); + provides("3mtl", function() { + var key = ""; + // render the html head using a template + var stash = { + header : { + index : indexPath, + blogName : ddoc.blog.title, + feedPath : feedPath, + commentsFeed : commentsFeed + }, + scripts : {}, + db : req.path[0], + design : req.path[2], + feedPath : feedPath, + newPostPath : path.show("edit"), + assets : path.asset(), + nodes : List.withRows(function(row) { + var node = row.value; + key = row.key; + return { + name : node.hostname, + site : node.site, + date : node.date_created, + link : path.list('node','node-page', {startkey : [row.id]}), + has_slices : false, + slices : [], + }; + }), + older : function() { + return path.older(key); + }, + "5" : path.limit(5), + "10" : path.limit(10), + "25" : path.limit(25) + }; + return Mustache.to_html(ddoc.templates.nodelist, stash, ddoc.templates.partials, List.send); + }); + +};