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; function check_field(query, field, def) { var ret = def; if ( field in query ) { ret = query[field]; log(field + ": " + ret); } return ret; } function tokenize(sf) { var ret = null; var fields = null; var f_eq = /==/; var f_ne = /!=/; var f_le = /<=|%3C=|%3c=/; var f_ge = />=|%3E=|%3e=/; var f_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_match) ) { fields = sf.split("=~"); ret = [fields[0], new RegExp(fields[1]), MATCH] ; } return ret; } function pf(x) { return 0; }; function parse_filter (sfilter) { var f_and_or = /AND|%%|&&|\|\|/; var f_eq = /==/; var f_ne = /!=/; var f_le = /<=|%3C=|%3c=/; var f_ge = />=|%3E=|%3e=/; var f_match = /=~/; var eq = {}; var kv_list = [ ]; var pfilter = [ ] ; log("sfilter: " + sfilter); if ( sfilter.match(f_and_or) ) { sfilter_list = sfilter.split(f_and_or); log("sfilter_list: " + sfilter_list); } else { sfilter_list = [ sfilter ] ; } for ( var i=0; i < sfilter_list.length ; i++ ) { sf = sfilter_list[i]; t = tokenize(sf); kv_list[i] = t; if ( sf.match(f_eq) ) { var fields = sf.split("=="); eq[fields[0]] = [fields[1], EQ] ; } else if ( sf.match(f_ne) ) { var fields = sf.split("!="); eq[fields[0]] = [fields[1], NE] ; } else if ( sf.match(f_le) ) { var fields = sf.split("<="); eq[fields[0]] = [Number(fields[1]), LE] ; } else if ( sf.match(f_ge) ) { var fields = sf.split(">="); eq[fields[0]] = [Number(fields[1]), GE] ; } else if ( sf.match(f_match) ) { var fields = sf.split("=~"); eq[fields[0]] = [new RegExp(fields[1]), MATCH] ; } } pfilter = [ eq ]; //log("kv_list: " + JSON.stringify(kv_list)); //pfilter = [ kv_list, AND ]; return pfilter; } function filter_matches (row, pfilter) { var result = true; if ( pfilter != null ) { for ( var i=0; i < pfilter.length ; i++ ) { //log("starting filter_matches"); for ( var prop in pfilter[i] ) { f = pfilter[i][prop]; //for ( var p in row ) { // log("row[" + p + "] == " + row[p]); //} //log("filter:" + f); //log("row[prop]: " + row[prop]); //log("typeof(row[prop]): " + typeof(row[prop])); if ( f[1] == EQ ) { result &= f[0] == row[prop]; } else if ( f[1] == NE ) { result &= f[0] != row[prop]; } else if ( f[1] == LE && prop in row ) { result &= Number(row[prop]) <= f[0]; } else if ( f[1] == GE && prop in row ) { result &= Number(row[prop]) >= f[0]; } else if ( f[1] == MATCH && prop in row ) { if ( typeof(row[prop]) == "object" ) { var found = false; for (var i; i < row[prop].length ; i++ ) { if ( f[0].test(row[prop][i]) ) { found = true; break; } } result &= found; } else { result &= f[0].test(row[prop]); } } else { result = false; } //log("result: " + result); } } //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' : '', }; //send(JSON.stringify(req)+'\n'); var more_props = true; var header; var count=0; var rowstring; var pfilter = null; var rpmpattern = 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(pfilter); } if ( 'rpmpattern' in req.query ) { rpmpattern = req.query['rpmpattern']; log("found rpmpattern"); log(rpmpattern); } 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') && (rpmpattern != 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(rpmpattern); if ( rpm ) { break; } } log(rpm); if ( rpm ) { rowstring += rpm.join(' ') + ','; } else { rowstring += ','; } } else { log("not a string"); log(typeof(row.value['rpm_versions'])); rowstring += ','; } } 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); }); // if the client requests an atom feed and not html, // we run this function to generate the feed. provides("atom", function() { var path = require("vendor/couchapp/lib/path").init(req); var markdown = require("vendor/couchapp/lib/markdown"); var textile = require("vendor/textile/textile"); // we load the first row to find the most recent change date var row = getRow(); // generate the feed header var feedHeader = Atom.header({ updated : (row ? new Date(row.value.created_at) : new Date()), title : ddoc.blog.title, feed_id : path.absolute(indexPath), feed_link : path.absolute(feedPath), }); // send the header to the client send(feedHeader); // loop over all rows if (row) { do { if (row.value.format == "markdown") { var html = markdown.encode(row.value.body); } else if (row.value.format == "textile") { var html = textile.encode(row.value.body); } else { var html = Mustache.escape(row.value.html); } // generate the entry for this row var feedEntry = Atom.entry({ entry_id : path.absolute('/'+encodeURIComponent(req.info.db_name)+'/'+encodeURIComponent(row.id)), title : row.value.title, content : html, updated : new Date(row.value.created_at), author : row.value.author, alternate : path.absolute(path.show('post', row.id)) }); // send the entry to client send(feedEntry); } while (row = getRow()); } // close the loop after all rows are rendered return ""; }); };