Example #1
0
  function found (article, next) {
    if (!article) {
      res.status(404).json({ messages: ['Article not found'] }); return;
    }
    contra.concurrent([removal, unlinkLeft, unlinkRight], next);

    function removal (next) {
      article.remove(next);
    }

    function unlinkLeft (next) {
      if (!article.prev) {
        next(); return;
      }
      article.prev.next = article.next;
      article.prev.save(function saved (err) {
        next(err);
      });
    }

    function unlinkRight (next) {
      if (!article.next) {
        next(); return;
      }
      article.next.prev = article.prev;
      article.next.save(function saved (err) {
        next(err);
      });
    }
  }
Example #2
0
      ], function(err, fb){
        if(err) return t.end(err);

        λ.concurrent({
          one_row:         λ.curry(q, fb, [["a", "->", "?va"]]),

          no_join:         λ.curry(q, fb, [["a", "->", "?va"],
                                           ["b", "->", "?vb"]]),

          da_join:         λ.curry(q, fb, [["a", "->", "?va"],
                                           ["b", "->", "?vb"],
                                           ["?va", "->", "?vb"]]),

          da_join_reverse: λ.curry(q, fb, [["?va", "->", "?vb"],
                                           ["a", "->", "?va"],
                                           ["b", "->", "?vb"]]),

          da_join_mix:     λ.curry(q, fb, [["a", "->", "?va"],
                                           ["?va", "->", "?vb"],
                                           ["b", "->", "?vb"]])
        }, function(err, r){
          if(err) return t.end(err);

          t.equal(r.one_row.length, 3, "should return everthing a points to");
          t.equal(r.no_join.length, 9, "should return every combination of a and b pointers");

          t.deepEqual(r.da_join, [{'?va': 'd', '?vb': 'g'}]);
          t.deepEqual(r.da_join_reverse, r.da_join, "q tuple order shouldn't matter");
          t.deepEqual(r.da_join_mix, r.da_join, "q tuple order shouldn't matter");

          t.end();
        });
      });
Example #3
0
 ], function(err){
   if(err) return t.end(err);
   var fb = transactor.connection.snap();
   λ.concurrent({
     should_be_a_var:      λ.curry(q, fb, [["?id", "name", "?notavar"]]),
     bind_it:              λ.curry(q, fb, [["?id", "name", "?name"]], [{"?name": "?notavar"}]),
     escape_it:            λ.curry(q, fb, [["?id", "name", "\\?notavar"]]),
     bind_it2:             λ.curry(q, fb, [["?id", "name", "?name"]], [{"?name": "\\?notavar"}]),
     not_actually_escaped: λ.curry(q, fb, [["?id", "name", "\\\\?notavar"]]),
     double_slash:         λ.curry(q, fb, [["?id", "name", "\\\\\\"]]),
     double_slash_bind:    λ.curry(q, fb, [["?id", "name", "?name"]], [{"?name": "\\\\"}]),
     not_a_throw_away:     λ.curry(q, fb, [["?id", "name", "\\?_"]]),
     not_a_throw_away2:    λ.curry(q, fb, [["?id", "name", "?name"]], [{"?name": "?_"}]),
   }, function(err, r){
     t.deepEqual(_.sortBy(r.should_be_a_var, "?id"), [{"?id": "1", "?notavar": "?notavar"}, {"?id": "2", "?notavar": "notavar"}, {"?id": "3", "?notavar": "\\?notavar"}, {"?id": "4", "?notavar": "\\\\"}, {"?id": "5", "?notavar": "?_"}]);
     t.deepEqual(r.bind_it, [{"?id": "1", "?name": "?notavar"}]);
     t.deepEqual(r.escape_it, [{"?id": "1"}]);
     t.deepEqual(r.bind_it2, [{"?id": "3", "?name": "\\?notavar"}]);
     t.deepEqual(r.not_actually_escaped, [{"?id": "3"}]);
     t.deepEqual(r.double_slash, [{"?id": "4"}]);
     t.deepEqual(r.double_slash_bind, [{"?id": "4", "?name": "\\\\"}]);
     t.deepEqual(r.not_a_throw_away, [{"?id": "5"}]);
     t.deepEqual(r.not_a_throw_away2, [{"?id": "5", "?name": "?_"}]);
     t.end(err);
   });
 });
Example #4
0
function getModel (req, res, next) {
  contra.concurrent({
    live: function (next) {
      settingService.getKey('PONYFOOWEEKLY_CRON', next);
    },
    weeklies: function (next) {
      WeeklyIssue.find({}).sort([['publication', -1], ['updated', -1]]).exec(next);
    }
  }, respond);

  function respond (err, result) {
    if (err) {
      next(err); return;
    }
    var models = result.weeklies.map(weeklyService.toMetadata);
    var sorted = _.sortBy(models, sortByStatus);
    res.viewModel = {
      model: {
        title: 'Newsletter Review',
        meta: {
          canonical: '/author/weeklies'
        },
        weeklies: sorted,
        live: result.live
      }
    };
    next();
  }
}
Example #5
0
 next => contra.concurrent([
   next => console.log(date + article.slug), next(),
   next => write('source/metadata.json', JSON.stringify({
     id: article._id,
     title: article.titleMarkdown,
     slug: article.slug,
     tags: article.tags,
     publication: moment(article.publication).format('DD-MM-YYYY HH:mm'),
     status: article.status,
     social: {
       email: article.email,
       tweet: article.tweet,
       fb: article.fb,
       echojs: article.echojs,
       lobsters: article.lobsters,
       hn: article.hn
     }
   }, null, 2), next),
   next => dec('source/summary.markdown', article.summaryHtml, next),
   next => dec('source/teaser.markdown', article.teaserHtml, next),
   next => dec('source/introduction.markdown', article.introductionHtml, next),
   next => dec('source/body.markdown', article.bodyHtml, next),
   next => abs('summary.html', article.summaryHtml, next),
   next => abs('teaser.html', article.teaserHtml, next),
   next => abs('introduction.html', article.introductionHtml, next),
   next => abs('body.html', article.bodyHtml, next)
 ], next)
Example #6
0
  function updateArticle (dir, next) {
    const readFile = file => next => fs.readFile(path.join(dir, file), 'utf8', next);

    contra.concurrent({
      metadata: readFile('metadata.json'),
      summary: readFile('summary.markdown'),
      teaser: readFile('teaser.markdown'),
      editorNote: readFile('editor-notes.markdown'),
      introduction: readFile('introduction.markdown'),
      body: readFile('body.markdown')
    }, mergeFiles);

    function mergeFiles (err, data) {
      if (err) {
        next(err); return;
      }
      const metadata = JSON.parse(data.metadata);
      const query = {
        _id: metadata.id,
        author: metadata.author
      };

      Article.findOne(query).exec(found);

      function found (err, article) {
        if (err) {
          next(err); return;
        }
        if (!article) {
          next(new Error(`Article couldn't be found!`)); return;
        }
        const fromGit = {
          titleMarkdown: metadata.title,
          slug: metadata.slug,
          status: article.status,
          summary: data.summary,
          teaser: data.teaser,
          editorNote: data.editorNote,
          introduction: data.introduction,
          body: data.body,
          tags: metadata.tags,
          heroImage: metadata.heroImage || ''
        };
        const sign = articleService.computeSignature(fromGit);
        if (sign === article.sign) {
          next(null); return;
        }
        article.titleMarkdown = fromGit.titleMarkdown;
        article.slug = fromGit.slug;
        article.summary = fromGit.summary;
        article.teaser = fromGit.teaser;
        article.editorNote = fromGit.editorNote;
        article.introduction = fromGit.introduction;
        article.body = fromGit.body;
        article.tags = fromGit.tags;
        article.heroImage = fromGit.heroImage;
        article.save(but(next));
      }
    }
  }
Example #7
0
 var testFB = function(fb, callback){
   λ.concurrent({
     q:         errPassingCurry(q, fb, [["?sue", "mother", "?mother"],
                                        ["?sibling", "mother", "?mother"]], [{"?sue": "sue"}]),
     qTuple:    errPassingCurry(qTuple, fb, ["axl", "mother", "?mother"]),
     getEntity: errPassingCurry(getEntity, fb, "axl")
   }, callback);
 };
Example #8
0
module.exports = function (req, res, next) {
  var max = 100;
  var page = parseInt(req.params.page, 10) || 1;
  var p = page - 1;
  var start = max * p;

  contra.concurrent({
    subscriberGraph: pullData,
    subscribers: pullSubscribers
  }, ready);

  function pullSubscribers (next) {
    Subscriber
      .find({})
      .sort('-created')
      .skip(p * max)
      .limit(max)
      .lean()
      .exec(found);
    function found (err, subscribers) {
      if (err) {
        next(err); return;
      }
      next(null, subscribers.map(toModel));
    }
  }

  function toModel (subscriber) {
    return {
      created: datetimeService.field(subscriber.created),
      email: subscriber.email,
      avatar: userService.getAvatar(subscriber),
      topics: subscriber.topics,
      source: subscriber.source.split('+')[0],
      verified: subscriber.verified,
      hash: subscriberService.getHash(subscriber)
    };
  }

  function ready (err, result) {
    if (err) {
      next(err); return;
    }

    res.viewModel = {
      model: {
        title: 'Subscribers \u2014 Pony Foo',
        subscriberGraph: result.subscriberGraph,
        subscribers: result.subscribers,
        allTopics: subscriberService.getTopics(),
        more: result.subscribers.length >= max,
        page: page
      }
    };
    next();
  }
};
Example #9
0
function campaign (article, done) {
  if (done === void 0) {
    done = noop;
  }
  contra.concurrent([
    contra.curry(email, article),
    contra.curry(tweet, article)
  ], done);
}
function pollCards (done) {
  if (!username || !password || !ads || (!articles && !newsletter)) {
    done(new Error('Method not implemented.')); return;
  }

  var tasks = [];
  if (articles) {
    tasks.push(makeTask('', articles));
  }
  if (newsletter) {
    tasks.push(makeTask('+newsletter', newsletter));
  }
  contra.concurrent(tasks, done);

  function makeTask (key, id) {
    return function pull (next) {
      Subscriber
        .findOne({ source: 'twitter' + key })
        .sort('-created')
        .exec(found);
      function found (err, last) {
        if (err) {
          next(err); return;
        }
        var since = last ? last.created : new Date(0);
        var options = {
          username: username,
          password: password,
          ads: ads,
          card: id,
          since: since
        };
        leads(options, pulled);
      }
      function pulled (err, leads) {
        if (err) {
          next(err); return;
        }
        if (leads.length) {
          winston.info('Found %s lead%s via Twitter Cards %s', leads.length, leads.length === 1 ? '' : 's', key || '+articles');
        } else {
          winston.debug('No new leads via Twitter Cards %s', key || '+articles');
        }
        contra.each(leads, 3, follow, next);
      }
      function follow (lead, next) {
        subscriberService.add({
          created: lead.time,
          email: lead.email,
          name: lead.name,
          source: 'twitter' + key,
          verified: true
        }, next);
      }
    };
  }
}
Example #11
0
function getModelData (done) {
  contra.concurrent({
    engagements: function (next) {
      Engagement.find({}).lean().exec(next);
    },
    presentations: function (next) {
      Presentation.find({}).sort('-presented').limit(5).lean().exec(next);
    }
  }, done);
}
Example #12
0
 function notify (article) {
   contra.concurrent({
     recipients: contra.curry(findRecipients, article),
     html: absolutizeHtml,
     gravatar: fetchGravatar
   }, function prepare (err, data) {
     data.article = article;
     send(err, data);
   });
 }
Example #13
0
function getFeed (done) {
  contra.concurrent({
    weekly: contra.curry(weeklyFeedService.getFeed),
    articles: contra.curry(articleFeedService.getFeed)
  }, merge);
  function merge (err, result) {
    if (err) {
      done(err); return;
    }
    done(null, result.weekly.concat(result.articles));
  }
}
Example #14
0
function verify (t, req) {
  var expected = path.join(__dirname, 'expected.png');
  var actual = tmp.tmpNameSync({ postfix: '.png' });
  var diff = tmp.tmpNameSync({ postfix: '.png' });
  var tunnel;

  contra.concurrent({ psi: insights, screenshot: screenshot }, assessment);

  function insights (next) {
    console.log('\n' + exercise.__('tunnel', { port: req.port }));
    localtunnel(req.port, tunneled);

    function tunneled (err, tune) {
      if (err) {
        next(err); return;
      }
      tunnel = tune;
      console.log(exercise.__('get_feedback', { url: tune.url }));
      psi(tune.url, next);
    }
  }

  function screenshot (done) {
    contra.series({
      take: function take (next) {
        webshot(req.url, actual, next);
      },
      compare: function compare (next) {
        imageDiff({
          actualImage: actual,
          expectedImage: expected,
          diffImage: diff,
          threshold: 0.1
        }, next);
      }
    }, done);
  }

  function assessment (err, result) {
    if (err) {
      t.error(err); return;
    }
    var amount = result.psi.pageStats.numberResources;
    tunnel.close();
    t.fgroup('overall');
    t.fpass('psi_score', { amount: amount }, amount < 5);
    t.fpass('visualcomp', result.screenshot.compare);
    t.end();
  }
}
Example #15
0
 setupMiddleDataset(function(err, fb){
   if(err) return t.end(err);
   λ.concurrent({
     axl_mother:           λ.curry(qTuple, fb, ["axl",       "mother", "?mother"]),
     axl_relation_to_mike: λ.curry(qTuple, fb, ["axl",    "?relation", "mike"], {}),
     mikes_children:       λ.curry(qTuple, fb, ["?children", "father", "?father"], {"?father": "mike"}),
     axl_has_no_children:  λ.curry(qTuple, fb, ["?children", "father", "axl"])
   }, function(err, r){
     t.deepEqual(_.pluck(r.axl_mother, "?mother"), ["frankie"]);
     t.deepEqual(_.pluck(r.axl_relation_to_mike, "?relation"), ["father"]);
     t.deepEqual(_.pluck(r.mikes_children, "?children").sort(), ["axl", "brick", "sue"]);
     t.equal(r.axl_has_no_children.length, 0);
     t.end(err);
   });
 });
Example #16
0
module.exports = function (done) {
  contra.concurrent({
    subscribers: contra.curry(pullSubscribers),
    pageviews: contra.curry(pullPageViews)
  }, render);
  function render (err, result) {
    if (err) {
      done(err); return;
    }
    done(null, {
      subscribers: result.subscribers.list,
      verified: result.subscribers.verified,
      pageviews: result.pageviews
    });
  }
}
Example #17
0
    function jsonx () {
      var strategy = 'callback' in req.query ? 'jsonp' : 'json';
      var hijacked = 'hijacker' in req.query;
      var response = {
        version: data.version
      };

      if (hijacked === false) {
        response.model = data.model;
      }

      if (action !== route.action && !hijacked) {
        respond(); // only add view/controller for the default route action or hijackers
      } else {
        contra.concurrent([
          add('template', 'views'),
          add('controller', 'client_controllers')
        ], respond);
      }

      function add (demand, base) {
        return function addModule (done) {
          var needsModule = demand in req.query;
          if (needsModule === false) {
            done(); return;
          }
          var a = req.query.hijacker || action;
          var file = path.join(rc[base], a + '.js');
          bro(file, include);

          function include (err, data) {
            if (!err) {
              response[demand] = data;
            }
            done(err);
          }
        };
      }

      function respond (err) {
        if (err) {
          next(err); return;
        }
        end(strategy, response);
      }
    }
Example #18
0
 setupMiddleDataset(function(err, fb){
   if(err) return t.end(err);
   λ.concurrent({
     all_entities: λ.curry(q, fb, [["?entity"]]),
     all_fathers:  λ.curry(q, fb, [["?_", "father", "?father"]]),
     sue_siblings: λ.curry(q, fb, [[    "?sue", "mother", "?_"],
                                   ["?sibling", "mother", "?_"]], [{"?sue": "sue"}])
   }, function(err, r){
     t.deepEqual(_.pluck(r.all_entities, "?entity").sort(), ['01', '02', '_txid1', '_txid2', 'axl', 'brick', 'frankie', 'janet', 'mike', 'rusty', 'sue']);
     t.deepEqual(_.sortBy(r.all_fathers, "?father"), [{"?father": 'big mike'}, {"?father": 'mike'}, {"?father": 'tag'}], "should not have ?_ bound to anything");
     t.deepEqual(_.sortBy(r.sue_siblings, "?sibling"), [{'?sibling': 'axl', '?sue': 'sue'},
                                                        {'?sibling': 'brick', '?sue': 'sue'},
                                                        {'?sibling': 'frankie', '?sue': 'sue'},
                                                        {'?sibling': 'janet', '?sue': 'sue'},
                                                        {'?sibling': 'sue', '?sue': 'sue'}], "should be everyone with a mother b/c ?_ shouldn't join");
     t.end(err);
   });
 });
Example #19
0
    ], function(err, fb_versions){
      if(err) return t.end(err);
      var fb = transactor.connection.snap();

      λ.concurrent({
        my_emails:    λ.curry(q, fb, [["me", "emails", "?emails"]]),
        the_first_me: λ.curry(getEntity, fb_versions[1], "me"),
        the_last_me:  λ.curry(getEntity, fb, "me")
      }, function(err, r){
        if(err) return t.end(err);

        t.deepEqual(_.pluck(r.my_emails, "?emails"), ["1@email", "2@email", "3@email"]);
        t.deepEqual(r.the_first_me, {emails: ["1@email"]});
        t.deepEqual(r.the_last_me, {emails: ["1@email", "2@email", "3@email"]});

        t.end();
      });
    });
Example #20
0
 setupProphetDataset(function(err, fb_versions){
   if(err) return t.end(err);
   var fb = _.last(fb_versions);
   λ.concurrent({
     first:          λ.curry(q, fb, [["prophet", "is", "?name",      2]]),
     third:          λ.curry(q, fb, [["prophet", "is", "?name",      4]]),
     when_was_young: λ.curry(q, fb, [["prophet", "is", "young", "?txn"]]),
     who_is_current: λ.curry(q, fb, [["prophet", "is", "?name"        ]]),
     names_in_order: λ.curry(q, fb, [["prophet", "is", "?name", "?txn"]])
   }, function(err, r){
     t.deepEqual(_.pluck(r.first, "?name"), ["smith"]);
     t.deepEqual(_.pluck(r.third, "?name"), ["taylor"]);
     t.deepEqual(_.pluck(r.when_was_young, "?txn"), [3]);
     t.deepEqual(_.pluck(r.who_is_current, "?name"), ["monson"]);
     t.deepEqual(_.pluck(_.sortBy(r.names_in_order, "?txn"), "?name"), prophets);
     t.end(err);
   });
 });
Example #21
0
function operational () {
  winston.info('Connected to target database!');
  models();

  contra.concurrent([
    function (next) { Article.remove({}, next); },
    function (next) { Subscriber.remove({}, next); },
    function (next) { User.remove({}, next); },
    function (next) { UnverifiedUser.remove({}, next); },
    function (next) { UserVerificationToken.remove({}, next); },
    function (next) { PasswordResetToken.remove({}, next); }
  ], prod);

  function prod () {
    production = mongoose.createConnection(prd, options);
    production.once('connected', connected);
    production.on('error', error);
  }
}
Example #22
0
function getDefaultViewModel (done) {
  contra.concurrent({
    bioHtml: bioService.getHtml.bind(null, authorEmail),
    popularArticles: popularityService.getArticles,
    javascriptLoader: read('.bin/inline/javascript.js'),
    styleLoader: read('.bin/inline/styles.js'),
    fontLoader: read('.bin/inline/fonts.js')
  }, forward);

  function forward (err, data) {
    if (err) {
      done(err); return;
    }

    done(null, {
      rss: 'https://feeds.feedburner.com/ponyfoo',
      author: {
        contact: 'Nicolás Bevacqua <*****@*****.**>',
        twitter: '@nzgb'
      },
      description: '',
      model: {
        authority: authority,
        title: 'Pony Foo \u2014 JavaScript consulting, modularity, front-end architecture, performance, and more. Authored by Nicolás Bevacqua',
        pkg: {
          version: pkg.version
        },
        meta: {
          description: 'Pony Foo is a technical blog maintained by Nicolás Bevacqua, where he shares his thoughts on JavaScript and the web. Nico likes writing, public speaking, and open-source.',
          images: [authority + staticService.unroll('/img/thumbnail.png')],
          keywords: []
        },
        bioHtml: data.bioHtml,
        popularArticles: data.popularArticles
      },
      javascriptLoader: data.javascriptLoader,
      styleLoader: data.styleLoader,
      fontLoader: data.fontLoader
    });
  }
}
Example #23
0
  setupMiddleDataset(function(err, fb){
    if(err) return t.end(err);
    λ.concurrent({
      husbands_and_wifes:   λ.curry(q, fb, [["?child", "mother", "?wife"],
                                            ["?child", "father", "?husband"]]),

      sue_grandfathers:     λ.curry(q, fb, [[    "sue", "father", "?father"],
                                            [    "sue", "mother", "?mother"],
                                            ["?mother", "father", "?grandpa1"],
                                            ["?father", "father", "?grandpa2"]], [{}]),

      sue_siblings:         λ.curry(q, fb, [[    "?sue", "mother", "?mother"],
                                            ["?sibling", "mother", "?mother"]], [{"?sue": "sue"}]),
    }, function(err, r){
      t.deepEqual(_.unique(_.map(r.husbands_and_wifes, function(result){
        return result["?husband"] + " & " + result["?wife"]
      }).sort()), ["mike & frankie", "tag & pat"]);
      t.deepEqual(_.unique(_.pluck(r.sue_grandfathers, "?grandpa1").concat(_.pluck(r.sue_grandfathers, "?grandpa2"))).sort(), ["big mike", "tag"]);
      t.deepEqual(_.unique(_.pluck(r.sue_siblings, "?sibling")).sort(), ["axl", "brick", "sue"]);
      t.end(err);
    });
  });
Example #24
0
function share (article, done) {
  if (done === void 0) {
    done = noop;
  }
  contra.concurrent([
    curried('email', email),
    curried('tweet', tweet),
    curried('fb', facebook),
    curried('echojs', echojs),
    curried('hn', hackernews),
    curried('lobsters', lobsters)
  ], done);

  function curried (key, fn) {
    return function shareVia (next) {
      if (article[key] === false) {
        next(); return;
      }
      fn(article, {}, next);
    };
  }
}
function share (article, done) {
  if (done === void 0) {
    done = noop;
  }
  contra.concurrent([
    medium('email', 'email'),
    medium('tweet', 'twitter'),
    medium('fb', 'facebook'),
    medium('echojs', 'echojs'),
    medium('hn', 'hackernews')
  ], done);

  function medium (key, method) {
    return function shareVia (next) {
      if (article[key] === false) {
        winston.info('Sharing turned off via "%s" channel for article %s.', method, article.title);
        next(); return;
      }
      winston.info('Sharing article %s via "%s" channel.', article.title, method);
      articleSharingService[method](article, {}, next);
    };
  }
}
Example #26
0
function rebuild () {
  contra.concurrent({
    articles: fetchArticles,
    weeklies: fetchWeeklies
  }, models);

  function models (err, result) {
    if (err) {
      done(err); return;
    }
    var modified = toLastMod(result.articles[0] ? result.articles[0].updated : Date.now());
    var urls = getArticleUrls(result.articles)
      .concat(getWeeklyUrls(result.weeklies))
      .concat(getOtherUrls());
    var map = sitemap.createSitemap({
      hostname: authority,
      cacheTime: 15 * 60 * 1000, // 15 minutes
      urls: urls
    });
    var xml = map.toXML();
    persist(xml, done);
  }
}
Example #27
0
function getModel (req, res, next) {
  contra.concurrent({
    live: function (next) {
      settingService.getKey('PONYFOOWEEKLY_CRON', next);
    },
    level: function (next) {
      settingService.getKey('PONYFOOWEEKLY_CRON_LEVEL', next);
    },
    weeklies: function (next) {
      WeeklyIssue
        .find({})
        .sort([['publication', -1], ['created', -1]])
        .populate('author', 'slug email avatar')
        .exec(next);
    }
  }, respond);

  function respond (err, result) {
    if (err) {
      next(err); return;
    }
    var sorted = _.sortBy(result.weeklies, sortByStatus);
    var models = sorted.map(weeklyService.toMetadata);
    res.viewModel = {
      model: {
        title: 'Newsletter Review',
        meta: {
          canonical: '/weekly/review'
        },
        weeklies: models,
        live: result.live,
        level: result.level
      }
    };
    next();
  }
}
Example #28
0
    ], function(err, fb_versions){
      if(err) return t.end(err);
      var fb = transactor.connection.snap();

      t.ok(fb.schema.time["_db/is-multi-valued"] === true, "must also decode db default schema values");

      λ.concurrent({
        time1:    λ.curry(q, fb, [["1", "time", "?val"]]),
        integer1: λ.curry(q, fb, [["2", "int", "?val"]]),
        number1:  λ.curry(q, fb, [["3", "float", "?val"]]),

        //query with variable attribute name
        time2:    λ.curry(q, fb, [["1", "?a", "?val"]]),
        integer2: λ.curry(q, fb, [["2", "?a", "?val"]]),
        number2:  λ.curry(q, fb, [["3", "?a", "?val"]]),

        //query with unknown attribute name
        time3:    λ.curry(q, fb, [["1", "?_", "?val"]]),
        integer3: λ.curry(q, fb, [["2", "?_", "?val"]]),
        number3:  λ.curry(q, fb, [["3", "?_", "?val"]]),
        
        //encode values at query with known attribute name
        time4:    λ.curry(q, fb, [["?e", "time", new Date(2010, 11, 25)]]),
        integer4: λ.curry(q, fb, [["?e", "int", 123]]),
        number4:  λ.curry(q, fb, [["?e", "float", 123.45]]),

        //encode values at query with variable attribute name
        time5:    λ.curry(q, fb, [["?e", "?a", new Date(2010, 11, 25)]]),
        integer5: λ.curry(q, fb, [["?e", "?a", 123]]),
        number5:  λ.curry(q, fb, [["?e", "?a", 123.45]]),

        //encode values at query with unknown attribute name
        time6:    λ.curry(q, fb, [["?e", "?_", new Date(2010, 11, 25)]]),
        integer6: λ.curry(q, fb, [["?e", "?_", 123]]),
        number6:  λ.curry(q, fb, [["?e", "?_", 123.45]])
      }, function(err, r){
        if(err) return t.end(err);

        _.each(r, function(results, key){
          t.equal(results.length, 1, "all these type encode/decode queries should return 1 result");
        });

        t.ok(_.isDate(r.time1[0]['?val']));
        t.ok(_.isDate(r.time2[0]['?val']));
        t.ok(_.isDate(r.time3[0]['?val']));

        t.ok(_.isNumber(r.integer1[0]['?val']));
        t.ok(_.isNumber(r.integer2[0]['?val']));
        t.ok(_.isNumber(r.integer3[0]['?val']));
        t.equal(r.integer1[0]['?val'], 123);
        t.equal(r.integer2[0]['?val'], 123);
        t.equal(r.integer3[0]['?val'], 123);

        t.ok(_.isNumber(r.number1[0]['?val']));
        t.ok(_.isNumber(r.number2[0]['?val']));
        t.ok(_.isNumber(r.number3[0]['?val']));
        t.equal(r.number1[0]['?val'], 123.45);
        t.equal(r.number2[0]['?val'], 123.45);
        t.equal(r.number3[0]['?val'], 123.45);

        t.equal(r.time4[0]['?e'], "1");
        t.equal(r.time5[0]['?e'], "1");
        t.equal(r.time6[0]['?e'], "1");
        t.equal(r.integer4[0]['?e'], "2");
        t.equal(r.integer5[0]['?e'], "2");
        t.equal(r.integer6[0]['?e'], "2");
        t.equal(r.number4[0]['?e'], "3");
        t.equal(r.number5[0]['?e'], "3");
        t.equal(r.number6[0]['?e'], "3");

        t.end();
      });
    });
Example #29
0
  function send (model, done) {
    var provider = model.provider || {};
    var providerTags = provider.tags || [];
    var merge = provider.merge || {};
    var domain = addrs.parseOneAddress(model.from).domain;
    var authority = model.authority || options.authority
    var client = mailgunjs({
      apiKey: options.apiKey,
      domain: domain
    });

    contra.concurrent({
      html: inlineHtml,
      images: getImages,
      attachments: getAttachments,
    }, ready);

    function inlineHtml (next) {
      var config = {
        url: authority
      };
      inlineCss(model.html, config)
        .then(function inlined (html) { next(null, html); })
        .catch(function failed (err) { next(err); });
    }

    function getImages (next) {
      var images = model.images ? model.images : [];
      if (model._header) {
        images.unshift({
          name: '_header',
          data: model._header.data,
          mime: model._header.mime
        });
      }
      next(null, images.map(transform));
      function transform (image) {
        return new client.Attachment({
          data: new Buffer(image.data, 'base64'),
          filename: image.name,
          contentType: image.mime
        });
      }
    }

    function getAttachments (next) {
      var attachments = model.attachments ? model.attachments : [];
      next(null, attachments.map(transform));
      function transform (attachment) {
        return new client.Attachment({
          data: attachment.file,
          filename: attachment.name
        });
      }
    }

    function ready (err, result) {
      if (err) {
        done(err); return;
      }
      post(result.html, result.images, result.attachments);
    }

    function post (html, images, attachments) {
      var inferConfig = {
        wordwrap: 130,
        linkHrefBaseUrl: authority,
        hideLinkHrefIfSameAsText: true
      };
      var inferredText = htmlToText.fromString(html, inferConfig);
      var tags = [model._template].concat(providerTags);
      var batches = getRecipientBatches();
      expandWildcard(model.to, model.cc, model.bcc);
      contra.each(batches, 4, postBatch, responses);

      function postBatch (batch, next) {
        var req = {
          from: model.from,
          to: batch,
          cc: model.cc,
          bcc: model.bcc,
          subject: model.subject,
          html: html,
          text: inferredText,
          inline: images.slice(),
          attachment: attachments.slice(),
          'o:tag': tags.slice(),
          'o:tracking': true,
          'o:tracking-clicks': true,
          'o:tracking-opens': true,
          'recipient-variables': parseMergeVariables(batch, model.cc, model.bcc)
        };
        client.messages().send(req, next);
      }
      function responses (err, results) {
        done(err, results);
      }
    }
    function getRecipientBatches () {
      var size = 250; // "Note: The maximum number of recipients allowed for Batch Sending is 1,000."
      var batches = [];
      for (var i = 0; i < model.to.length; i += size) {
        batches.push(model.to.slice(i, i + size));
      }
      return batches;
    }
    function parseMergeVariables (to, cc, bcc) {
      var variables = {};
      to
        .concat(cc)
        .concat(bcc)
        .forEach(addVariables);
      return variables;
      function addVariables (recipient) {
        if (merge[recipient]) {
          variables[recipient] = merge[recipient];
        }
      }
    }
    function expandWildcard (to, cc, bcc) {
      if ('*' in merge) {
        wildcarding();
      }
      function wildcarding () {
        var wildcard = merge['*'];
        to
          .concat(cc)
          .concat(bcc)
          .forEach(addWildcardToRecipient);
        function addWildcardToRecipient (recipient) {
          Object.keys(wildcard).forEach(addWildcardKeyToRecipient);
          function addWildcardKeyToRecipient (key) {
            // don't override: wildcard has default values
            if (!merge[recipient]) {
              merge[recipient] = {};
            }
            if (!merge[recipient].hasOwnProperty(key)) {
              merge[recipient][key] = wildcard[key];
            }
          }
        }
      }
    }
  }
Example #30
0
 next => contra.concurrent(filenames.map(filename =>
   next => write(filename, files[filename], next)
 ), next)