--- /dev/null
+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);
+ });
+
+};