<commit_before>var addic7edApi = require('addic7ed-api');
var fs = require('fs');
var Common = require('../common.js');
var Mongoose = require('mongoose');
var Mongo = require('../db/mongo.js');
var ScheduleManager = require('../schedule/scheduleManager.js');
var TvMaze = require('../libs/tvMaze.js');
var Logger = require('../log/logger.js');

exports.addic7edGetSubtitle = function (session, languages, bot, chat, sessionsList) {
    if(session.choosenEpisode.indexOf('-')===-1){
        getSingleEpisodeSubs(session, languages, bot, chat, sessionsList, session.choosenEpisode, true)
    }else{
        var start = +session.choosenEpisode.substr(0, session.choosenEpisode.indexOf('-'));
        var end = +session.choosenEpisode.substr(session.choosenEpisode.indexOf('-') + 1, session.choosenEpisode.length);
        while (start <= end){
            getSingleEpisodeSubs(session, languages, bot, chat, sessionsList, start, start == end),
            start++;
        }
    }
}

function getSingleEpisodeSubs (session, languages = [], bot, chat, sessionsList, episode, sendAmbiguousMessage) {
    //Logger.logEvent("get", languages, session);
    addic7edApi.search(session.choosenSeries.show.name, session.choosenSeason,
        episode, languages).then(function (subtitlesList) {
            var subInfo = subtitlesList[0];
            if (subInfo != undefined) {
                var filename = session.choosenSeries.show.name + '_S' + session.choosenSeason + '_E' + episode + '.srt';
                addic7edApi.download(subInfo, filename).then(function () {
                    fs.exists(filename, function (exists) {
                        if (exists) {
                            console.log('Subtitles file saved.');
                            Common.removeSession(sessionsList, session);
                            bot.sendMessage(chat, Common.buildLinkMessage(subInfo.link));
                            bot.sendDocument(chat, filename).then(function () {
                                fs.unlinkSync(filename);
                            });
                            if (sendAmbiguousMessage && session.choosenSeries.show.name.indexOf("(") > -1 && session.choosenSeries.show.name.indexOf(")") > -1) {
                                bot.sendMessage(chat, Common.ambigousSubtitleMessage);
                            }
                        }
                    });
                 }).catch(function (err) {
                    console.log("error downloading subs");
                });
            }
            else
                bot.sendMessage(chat, Common.subtitleNotFoundInAddic7edMessage);
         }).catch(function (err) {
            console.log("error searching subs - ", session);
        });
}

exports.addic7edGetSubtitleAlert = function (alert, job, bot, doneJobInterval) {
    addic7edApi.search(alert.show_name, alert.nextepisode_season, alert.nextepisode_episode, alert.language).then(function (subtitlesList) {
        var subInfo = subtitlesList[0];
        if (subInfo != undefined) {
            var filename = alert.show_name + '_S' + alert.nextepisode_season + '_E' + alert.nextepisode_episode + '.srt';
            addic7edApi.download(subInfo, filename).then(function () {
                fs.exists(filename, function (exists) {
                    if (exists) {
                        console.log('Subtitles file saved.');
                        Mongo.User.find({ alerts: alert._id.toString() }, function (err, users) {
                            users.forEach(function (user) {
                                var userDoc = user._doc;
                                bot.sendMessage(userDoc.chatId, Common.newEpisodeAlertMessage(userDoc.first_name, alert.show_name));
                                bot.sendMessage(userDoc.chatId, Common.buildLinkMessage(subInfo.link));
                                bot.sendDocument(userDoc.chatId, filename).then(function () {
                                    console.log("File sent to user " + userDoc.first_name);
                                });
                                if (Common.isAmbiguousTitle(alert.show_name)) {
                                    bot.sendMessage(userDoc.chatId, Common.ambigousSubtitleMessage);
                                }
                            });
                            job.attrs.data.hasToBeRemoved = true;
                            fs.unlinkSync(filename);
                            doneJobInterval();
                        });
                    }
                });
             }).catch(function (err) {
                console.log("error download subs - ", alert);
            });
        } else {
            job.attrs.data.hasToBeRemoved = false;
            doneJobInterval();
        }
     }).catch(function (err) {
        console.log("error searching subs - ", alert);
    });
}<commit_msg>fixed _doc bug in alert<commit_after>var addic7edApi = require('addic7ed-api');
var fs = require('fs');
var Common = require('../common.js');
var Mongoose = require('mongoose');
var Mongo = require('../db/mongo.js');
var ScheduleManager = require('../schedule/scheduleManager.js');
var TvMaze = require('../libs/tvMaze.js');
var Logger = require('../log/logger.js');

exports.addic7edGetSubtitle = function (session, languages, bot, chat, sessionsList) {
    if(session.choosenEpisode.indexOf('-')===-1){
        getSingleEpisodeSubs(session, languages, bot, chat, sessionsList, session.choosenEpisode, true)
    }else{
        var start = +session.choosenEpisode.substr(0, session.choosenEpisode.indexOf('-'));
        var end = +session.choosenEpisode.substr(session.choosenEpisode.indexOf('-') + 1, session.choosenEpisode.length);
        while (start <= end){
            getSingleEpisodeSubs(session, languages, bot, chat, sessionsList, start, start == end),
            start++;
        }
    }
}

function getSingleEpisodeSubs (session, languages = [], bot, chat, sessionsList, episode, sendAmbiguousMessage) {
    //Logger.logEvent("get", languages, session);
    addic7edApi.search(session.choosenSeries.show.name, session.choosenSeason,
        episode, languages).then(function (subtitlesList) {
            var subInfo = subtitlesList[0];
            if (subInfo != undefined) {
                var filename = session.choosenSeries.show.name + '_S' + session.choosenSeason + '_E' + episode + '.srt';
                addic7edApi.download(subInfo, filename).then(function () {
                    fs.exists(filename, function (exists) {
                        if (exists) {
                            console.log('Subtitles file saved.');
                            Common.removeSession(sessionsList, session);
                            bot.sendMessage(chat, Common.buildLinkMessage(subInfo.link));
                            bot.sendDocument(chat, filename).then(function () {
                                fs.unlinkSync(filename);
                            });
                            if (sendAmbiguousMessage && session.choosenSeries.show.name.indexOf("(") > -1 && session.choosenSeries.show.name.indexOf(")") > -1) {
                                bot.sendMessage(chat, Common.ambigousSubtitleMessage);
                            }
                        }
                    });
                 }).catch(function (err) {
                    console.log("error downloading subs");
                });
            }
            else
                bot.sendMessage(chat, Common.subtitleNotFoundInAddic7edMessage);
         }).catch(function (err) {
            console.log("error searching subs - ", session);
        });
}

exports.addic7edGetSubtitleAlert = function (alert, job, bot, doneJobInterval) {
    addic7edApi.search(alert.show_name, alert.nextepisode_season, alert.nextepisode_episode, alert.language).then(function (subtitlesList) {
        var subInfo = subtitlesList[0];
        if (subInfo != undefined) {
            var filename = alert.show_name + '_S' + alert.nextepisode_season + '_E' + alert.nextepisode_episode + '.srt';
            addic7edApi.download(subInfo, filename).then(function () {
                fs.exists(filename, function (exists) {
                    if (exists) {
                        console.log('Subtitles file saved.');
                        Mongo.User.find({ alerts: alert._doc._id.toString() }, function (err, users) {
                            users.forEach(function (user) {
                                var userDoc = user._doc;
                                bot.sendMessage(userDoc.chatId, Common.newEpisodeAlertMessage(userDoc.first_name, alert._doc.show_name));
                                bot.sendMessage(userDoc.chatId, Common.buildLinkMessage(subInfo.link));
                                bot.sendDocument(userDoc.chatId, filename).then(function () {
                                    console.log("File sent to user " + userDoc.first_name);
                                });
                                if (Common.isAmbiguousTitle(alert._doc.show_name)) {
                                    bot.sendMessage(userDoc.chatId, Common.ambigousSubtitleMessage);
                                }
                            });
                            job.attrs.data.hasToBeRemoved = true;
                            fs.unlinkSync(filename);
                            doneJobInterval();
                        });
                    }
                });
             }).catch(function (err) {
                console.log("error download subs - ", alert);
            });
        } else {
            job.attrs.data.hasToBeRemoved = false;
            doneJobInterval();
        }
     }).catch(function (err) {
        console.log("error searching subs - ", alert);
    });
}<|endoftext|>


<commit_before>var _; //globals

describe("About Applying What We Have Learnt", function() {

  var products;

  beforeEach(function () {
    products = [
       { name: "Sonoma", ingredients: ["artichoke", "sundried tomatoes", "mushrooms"], containsNuts: false },
       { name: "Pizza Primavera", ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"], containsNuts: false },
       { name: "South Of The Border", ingredients: ["black beans", "jalapenos", "mushrooms"], containsNuts: false },
       { name: "Blue Moon", ingredients: ["blue cheese", "garlic", "walnuts"], containsNuts: true },
       { name: "Taste Of Athens", ingredients: ["spinach", "kalamata olives", "sesame seeds"], containsNuts: true }
    ];
  });

  /*********************************************************************************/

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (imperative)", function () {

    var i,j,hasMushrooms, productsICanEat = [];

    for (i = 0; i < products.length; i+=1) {
        if (products[i].containsNuts === false) {
            hasMushrooms = false;
            for (j = 0; j < products[i].ingredients.length; j+=1) {
               if (products[i].ingredients[j] === "mushrooms") {
                  hasMushrooms = true;
               }
            }
            if (!hasMushrooms) productsICanEat.push(products[i]);
        }
    }

    expect(productsICanEat.length).toBe(1);
  });

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (functional)", function () {

      var productsICanEat = [];

      /* solve using filter() & all() / any() */
      var testObject = function(obj){
        return _.all(obj.ingredients, function(x){return x !== "mushrooms";}) && !obj.containsNuts;
      };

      productsICanEat = _.filter(products,testObject);

      expect(productsICanEat.length).toBe(1);
  });

  /*********************************************************************************/

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (imperative)", function () {

    var sum = 0;
    for(var i=1; i<1000; i+=1) {
      if (i % 3 === 0 || i % 5 === 0) {
        sum += i;
      }
    }

    expect(sum).toBe(FILL_ME_IN);
  });

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (functional)", function () {

    var sum = FILL_ME_IN;    /* try chaining range() and reduce() */

    expect(233168).toBe(FILL_ME_IN);
  });

  /*********************************************************************************/
   it("should count the ingredient occurrence (imperative)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    for (i = 0; i < products.length; i+=1) {
        for (j = 0; j < products[i].ingredients.length; j+=1) {
            ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1;
        }
    }

    expect(ingredientCount['mushrooms']).toBe(FILL_ME_IN);
  });

  it("should count the ingredient occurrence (functional)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    /* chain() together map(), flatten() and reduce() */

    expect(ingredientCount['mushrooms']).toBe(FILL_ME_IN);
  });

  /*********************************************************************************/
  /* UNCOMMENT FOR EXTRA CREDIT */
  /*
  it("should find the largest prime factor of a composite number", function () {

  });

  it("should find the largest palindrome made from the product of two 3 digit numbers", function () {

  });

  it("should find the smallest number divisible by each of the numbers 1 to 20", function () {

  });

  it("should find the difference between the sum of the squares and the square of the sums", function () {

  });

  it("should find the 10001st prime", function () {

  });
  */
});
<commit_msg>Enlightenment! Also, _.chain(x) has a type error but _(x).chain() works???<commit_after>var _; //globals

describe("About Applying What We Have Learnt", function() {

  var products;

  beforeEach(function () {
    products = [
       { name: "Sonoma", ingredients: ["artichoke", "sundried tomatoes", "mushrooms"], containsNuts: false },
       { name: "Pizza Primavera", ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"], containsNuts: false },
       { name: "South Of The Border", ingredients: ["black beans", "jalapenos", "mushrooms"], containsNuts: false },
       { name: "Blue Moon", ingredients: ["blue cheese", "garlic", "walnuts"], containsNuts: true },
       { name: "Taste Of Athens", ingredients: ["spinach", "kalamata olives", "sesame seeds"], containsNuts: true }
    ];
  });

  /*********************************************************************************/

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (imperative)", function () {

    var i,j,hasMushrooms, productsICanEat = [];

    for (i = 0; i < products.length; i+=1) {
        if (products[i].containsNuts === false) {
            hasMushrooms = false;
            for (j = 0; j < products[i].ingredients.length; j+=1) {
               if (products[i].ingredients[j] === "mushrooms") {
                  hasMushrooms = true;
               }
            }
            if (!hasMushrooms) productsICanEat.push(products[i]);
        }
    }

    expect(productsICanEat.length).toBe(1);
  });

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (functional)", function () {

      var productsICanEat = [];

      /* solve using filter() & all() / any() */
      var testObject = function(obj){
        return _.all(obj.ingredients, function(x){return x !== "mushrooms";}) && !obj.containsNuts;
      };

      productsICanEat = _.filter(products,testObject);

      expect(productsICanEat.length).toBe(1);
  });

  /*********************************************************************************/

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (imperative)", function () {

    var sum = 0;
    for(var i=1; i<1000; i+=1) {
      if (i % 3 === 0 || i % 5 === 0) {
        sum += i;
      }
    }

    expect(sum).toBe(233168);
  });

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (functional)", function () {

    var sum =     _.range(1,1000).reduce(function(memo, num, index){
      if(num % 3 == 0 || num % 5 == 0){
        return memo + num;
      }else{return memo;}
    },0);
    expect(233168).toBe(sum);
  });

  /*********************************************************************************/
   it("should count the ingredient occurrence (imperative)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    for (i = 0; i < products.length; i+=1) {
        for (j = 0; j < products[i].ingredients.length; j+=1) {
            ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1;
        }
    }

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  it("should count the ingredient occurrence (functional)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    /* chain() together map(), flatten() and reduce() */
     _(products).chain()
    .map(function(x){return x.ingredients;})
    .flatten()
    .each(function(x){ingredientCount[x] = (ingredientCount[x] || 0) + 1;})

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  /*********************************************************************************/
  /* UNCOMMENT FOR EXTRA CREDIT */
  /*
  it("should find the largest prime factor of a composite number", function () {

  });

  it("should find the largest palindrome made from the product of two 3 digit numbers", function () {

  });

  it("should find the smallest number divisible by each of the numbers 1 to 20", function () {

  });

  it("should find the difference between the sum of the squares and the square of the sums", function () {

  });

  it("should find the 10001st prime", function () {

  });
  */
});
<|endoftext|>


<commit_before>describe ("View", function() {

    // we create a variable to store our fake 'grove' in the outer scope so that our test
    //  specs can access it
    var mockGrove;

    // we abstract out our 'grove' creation into its own function for readability purposes
    var createGrove = function() {
        mockGrove = document.createElement('div');

        mockGrove.className = "grove";

        document.body.appendChild(mockGrove);
    };

    beforeEach(function() {
        // before each test spec run, we run createGrove to generate the 'grove' DOM element
        createGrove();
    });

    afterEach(function() {
        // after each test spec run, we remove the 'grove' DOM element to create a clean slate
        //  for the next test
        document.body.removeChild(mockGrove);
    });

    describe(".renderTree()", function() {
        var mockTemplate;

        beforeEach(function() {
            //creates a fake orange tree template div
      mockTemplate = document.createElement('div')
      mockTemplate.id = "orange-tree-template"

      // create a fake orange tree div. It's a barebones version of the tree, with
      // no p tags or buttons. You may need to add more complexity to it for future tests
      var orangeTree = document.createElement('div')
      orangeTree.className = "orange-tree"

      // appends the tree div to the template div, just like in orange.html
      mockTemplate.appendChild(orangeTree)
      // appends the template div to the document, in this case
      document.body.appendChild(mockTemplate)
    })

    afterEach(function() {
      // after each test spec run, we remove the 'mockTemplate' DOM elements to create a clean slate
      //  for the next test
      document.body.removeChild(mockTemplate)
    })

    it("should render a tree in the grove", function(){
      var tree = new Tree();
      var view = new View();

      view.renderTree(tree);

      expect(mockGrove.childElementCount).toEqual(1);
    });
  })

});<commit_msg>Finish rewriting view specs<commit_after>describe ("View", function() {

    // we create a variable to store our fake 'grove' in the outer scope so that our test
    //  specs can access it
    var mockGrove;

    // we abstract out our 'grove' creation into its own function for readability purposes
    var createGrove = function() {
        mockGrove = document.createElement('div');

        mockGrove.className = "grove";

        document.body.appendChild(mockGrove);
    };

    beforeEach(function() {
        // before each test spec run, we run createGrove to generate the 'grove' DOM element
        createGrove();
    });

    afterEach(function() {
        // after each test spec run, we remove the 'grove' DOM element to create a clean slate
        //  for the next test
        document.body.removeChild(mockGrove);
    });

    describe(".renderTree()", function() {

        // we create a variable to store our fake 'template' in the outer scope so that our test
        //  specs can access it
        var mockTreeTemplate;

        // we abstract out our 'template' creation into its own function for readability purposes
        var createMockTreeTemplate = function() {
            mockTreeTemplate = document.createElement('div');

            mockTreeTemplate.id = "orange-tree-template";

            // we create a fake orange tree div; it's a barebones version of the tree, with
            //  no p tags or buttons
            // you may need to add more complexity to it for future tests!
            var orangeTree = document.createElement('div');

            orangeTree.className = "orange-tree";

            mockTreeTemplate.appendChild(orangeTree);

            document.body.appendChild(mockTreeTemplate);
        };

        beforeEach(function() {
            createMockTreeTemplate();
        });

        afterEach(function() {
            // after each test spec run, we remove the 'mockTreeTemplate' DOM elements to create a clean slate
            //  for the next test
            document.body.removeChild(mockTreeTemplate)
        });

        it("should render a tree in the grove", function(){
            var tree = new Tree();

            // pass the model (our tree) into the view so the view can render the tree in the UI using
            //  the tree's properties (height, number of oranges, etc.)
            var view = new View({
                model: tree
            });

            view.renderTree();

            expect(mockGrove.childElementCount).toEqual(1);
        });

    });

});<|endoftext|>


<commit_before>var addic7edApi = require('addic7ed-api');
var fs = require('fs');
var Common = require('../common.js');
var Mongoose = require('mongoose');
var Mongo = require('../db/mongo.js');
var ScheduleManager = require('../schedule/scheduleManager.js');
var TvMaze = require('../libs/tvMaze.js');
var Logger = require('../log/logger.js');

exports.addic7edGetSubtitle = function (session, languages, bot, chat, sessionsList) {
    if(session.choosenEpisode.indexOf('-')===-1){
        getSingleEpisodeSubs(session, languages, bot, chat, sessionsList, session.choosenEpisode, true)
    }else{
        var start = +session.choosenEpisode.substr(0, session.choosenEpisode.indexOf('-'));
        var end = +session.choosenEpisode.substr(session.choosenEpisode.indexOf('-') + 1, session.choosenEpisode.length);
        while (start <= end){
            getSingleEpisodeSubs(session, languages, bot, chat, sessionsList, start, start == end),
            start++;
        }
    }
}

function getSingleEpisodeSubs (session, languages = [], bot, chat, sessionsList, episode, sendAmbiguousMessage) {
    //Logger.logEvent("get", languages, session);
    addic7edApi.search(session.choosenSeries.show.name, session.choosenSeason,
        episode, languages).then(function (subtitlesList) {
            var subInfo = subtitlesList[0];
            if (subInfo != undefined) {
                var filename = session.choosenSeries.show.name + '_S' + session.choosenSeason + '_E' + episode + '.srt';
                addic7edApi.download(subInfo, filename).then(function () {
                    fs.exists(filename, function (exists) {
                        if (exists) {
                            console.log('Subtitles file saved.');
                            Common.removeSession(sessionsList, session);
                            bot.sendMessage(chat, Common.buildLinkMessage(subInfo.link));
                            bot.sendDocument(chat, filename).then(function () {
                                fs.unlinkSync(filename);
                            });
                            if (sendAmbiguousMessage && session.choosenSeries.show.name.indexOf("(") > -1 && session.choosenSeries.show.name.indexOf(")") > -1) {
                                bot.sendMessage(chat, Common.ambigousSubtitleMessage);
                            }
                        }
                    });
                });
            }
            else
                bot.sendMessage(chat, Common.subtitleNotFoundInAddic7edMessage);
        });
}

exports.addic7edGetSubtitleAlert = function (alert, job, bot, doneJobInterval) {
    addic7edApi.search(alert.show_name, alert.nextepisode_season, alert.nextepisode_episode, alert.language).then(function (subtitlesList) {
        var subInfo = subtitlesList[0];
        if (subInfo != undefined) {
            var filename = alert.show_name + '_S' + alert.nextepisode_season + '_E' + alert.nextepisode_episode + '.srt';
            addic7edApi.download(subInfo, filename).then(function () {
                fs.exists(filename, function (exists) {
                    if (exists) {
                        console.log('Subtitles file saved.');
                        Mongo.User.find({ alerts: alert._id.toString() }, function (err, users) {
                            users.forEach(function (user) {
                                var userDoc = user._doc;
                                bot.sendMessage(userDoc.chatId, Common.newEpisodeAlertMessage(userDoc.first_name, alert.show_name));
                                bot.sendMessage(userDoc.chatId, Common.buildLinkMessage(subInfo.link));
                                bot.sendDocument(userDoc.chatId, filename).then(function () {
                                    console.log("File sent to user " + userDoc.first_name);
                                });
                                if (Common.isAmbiguousTitle(alert.show_name)) {
                                    bot.sendMessage(userDoc.chatId, Common.ambigousSubtitleMessage);
                                }
                            });
                            job.attrs.data.hasToBeRemoved = true;
                            fs.unlinkSync(filename);
                            doneJobInterval();
                        });
                    }
                });
            });
        } else {
            job.attrs.data.hasToBeRemoved = false;
            doneJobInterval();
        }
    });
}<commit_msg>modified after bigmerge<commit_after>var addic7edApi = require('addic7ed-api');
var fs = require('fs');
var Common = require('../common.js');
var Mongoose = require('mongoose');
var Mongo = require('../db/mongo.js');
var ScheduleManager = require('../schedule/scheduleManager.js');
var TvMaze = require('../libs/tvMaze.js');
var Logger = require('../log/logger.js');

exports.addic7edGetSubtitle = function (session, languages, bot, chat, sessionsList) {
    if(session.choosenEpisode.indexOf('-')===-1){
        getSingleEpisodeSubs(session, languages, bot, chat, sessionsList, session.choosenEpisode, true)
    }else{
        var start = +session.choosenEpisode.substr(0, session.choosenEpisode.indexOf('-'));
        var end = +session.choosenEpisode.substr(session.choosenEpisode.indexOf('-') + 1, session.choosenEpisode.length);
        while (start <= end){
            getSingleEpisodeSubs(session, languages, bot, chat, sessionsList, start, start == end),
            start++;
        }
    }
}

function getSingleEpisodeSubs (session, languages = [], bot, chat, sessionsList, episode, sendAmbiguousMessage) {
    //Logger.logEvent("get", languages, session);
    addic7edApi.search(session.choosenSeries.show.name, session.choosenSeason,
        episode, languages).then(function (subtitlesList) {
            var subInfo = subtitlesList[0];
            if (subInfo != undefined) {
                var filename = session.choosenSeries.show.name + '_S' + session.choosenSeason + '_E' + episode + '.srt';
                addic7edApi.download(subInfo, filename).then(function () {
                    fs.exists(filename, function (exists) {
                        if (exists) {
                            console.log('Subtitles file saved.');
                            Common.removeSession(sessionsList, session);
                            bot.sendMessage(chat, Common.buildLinkMessage(subInfo.link));
                            bot.sendDocument(chat, filename).then(function () {
                                fs.unlinkSync(filename);
                            });
                            if (sendAmbiguousMessage && session.choosenSeries.show.name.indexOf("(") > -1 && session.choosenSeries.show.name.indexOf(")") > -1) {
                                bot.sendMessage(chat, Common.ambigousSubtitleMessage);
                            }
                        }
                    });
                 }).catch(function (err) {
                    console.log("error searching subs - ", err);
                });
            }
            else
                bot.sendMessage(chat, Common.subtitleNotFoundInAddic7edMessage);
         }).catch(function (err) {
            console.log("error downloading subs - ", err);
        });
}

exports.addic7edGetSubtitleAlert = function (alert, job, bot, doneJobInterval) {
    addic7edApi.search(alert.show_name, alert.nextepisode_season, alert.nextepisode_episode, alert.language).then(function (subtitlesList) {
        var subInfo = subtitlesList[0];
        if (subInfo != undefined) {
            var filename = alert.show_name + '_S' + alert.nextepisode_season + '_E' + alert.nextepisode_episode + '.srt';
            addic7edApi.download(subInfo, filename).then(function () {
                fs.exists(filename, function (exists) {
                    if (exists) {
                        console.log('Subtitles file saved.');
                        Mongo.User.find({ alerts: alert._id.toString() }, function (err, users) {
                            users.forEach(function (user) {
                                var userDoc = user._doc;
                                bot.sendMessage(userDoc.chatId, Common.newEpisodeAlertMessage(userDoc.first_name, alert.show_name));
                                bot.sendMessage(userDoc.chatId, Common.buildLinkMessage(subInfo.link));
                                bot.sendDocument(userDoc.chatId, filename).then(function () {
                                    console.log("File sent to user " + userDoc.first_name);
                                });
                                if (Common.isAmbiguousTitle(alert.show_name)) {
                                    bot.sendMessage(userDoc.chatId, Common.ambigousSubtitleMessage);
                                }
                            });
                            job.attrs.data.hasToBeRemoved = true;
                            fs.unlinkSync(filename);
                            doneJobInterval();
                        });
                    }
                });
             }).catch(function (err) {
                console.log("error searching subs - ", err);
            });
        } else {
            job.attrs.data.hasToBeRemoved = false;
            doneJobInterval();
        }
     }).catch(function (err) {
        console.log("error download subs - ", err);
    });
}<|endoftext|>


<commit_before>/* eslint-disable no-console */
/**
 * Why choose inheritance over a HOC?  Multiple advantages for this particular use case.
 * In short, we need identical functionality to setState(), unless there is a prop defined
 * for the state key.  Also:
 *
 * 1. Single Renders
 *    Calling trySetState() in constructor(), componentWillMount(), or componentWillReceiveProps()
 *    does not cause two renders. Consumers and tests do not have to wait two renders to get state.
 *    See www.react.run/4kJFdKoxb/27 for an example of this issue.
 *
 * 2. Simple Testing
 *    Using a HOC means you must either test the undecorated component or test through the decorator.
 *    Testing the undecorated component means you must mock the decorator functionality.
 *    Testing through the HOC means you can not simply shallow render your component.
 *
 * 3. Statics
 *    HOC wrap instances, so statics are no longer accessible.  They can be hoisted, but this is more
 *    looping over properties and storing references.  We rely heavily on statics for testing and sub
 *    components.
 *
 * 4. Instance Methods
 *    Some instances methods may be exposed to users via refs.  Again, these are lost with HOC unless
 *    hoisted and exposed by the HOC.
 */
import _ from 'lodash'
import { Component } from 'react'

const getDefaultPropName = (prop) => `default${prop[0].toUpperCase() + prop.slice(1)}`

export default class AutoControlledComponent extends Component {
  componentWillMount() {
    if (super.componentWillMount) super.componentWillMount()
    const { autoControlledProps } = this.constructor

    // Auto controlled props are copied to state.
    // Set initial state by copying auto controlled props to state.
    // Also look for the default prop for any auto controlled props (foo => defaultFoo)
    // so we can set initial values from defaults.
    this.state = _.transform(autoControlledProps, (res, prop) => {
      const defaultPropName = getDefaultPropName(prop)

      // apply default props if they exist
      res[prop] = this.props[defaultPropName in this.props ? defaultPropName : prop]

      if (!__PROD__) {
        const { name } = this.constructor
        // prevent defaultFoo={} along side foo={}
        if (defaultPropName in this.props && prop in this.props) {
          console.error(
            `${name} prop "${prop}" is auto controlled. Specify either ${defaultPropName} or ${prop}, but not both.`
          )
        }
      }
    }, {})

    if (!__PROD__) {
      const { defaultProps, name, propTypes } = this.constructor
      // require static autoControlledProps
      if (!autoControlledProps) {
        console.error(`Auto controlled ${name} must specify a static autoControlledProps array.`)
      }

      // require propTypes
      _.each(autoControlledProps, (prop) => {
        const defaultProp = getDefaultPropName(prop)
        // regular prop
        if (!_.has(propTypes, defaultProp)) {
          console.error(`${name} is missing "${defaultProp}" propTypes validation for auto controlled prop "${prop}".`)
        }
        // its default prop
        if (!_.has(propTypes, prop)) {
          console.error(`${name} is missing propTypes validation for auto controlled prop "${prop}".`)
        }
      })

      // prevent autoControlledProps in defaultProps
      //
      // When setting state, auto controlled props values always win (so the parent can manage them).
      // It is not reasonable to decipher the difference between props from the parent and defaultProps.
      // Allowing defaultProps results in trySetState always deferring to the defaultProp value.
      // Auto controlled props also listed in defaultProps can never be updated.
      const illegalDefaults = _.intersection(autoControlledProps, _.keys(defaultProps))
      if (!_.isEmpty(illegalDefaults)) {
        console.error([
          'Do not set defaultProps for autoControlledProps,',
          'use trySetState() in constructor() or componentWillMount() instead.',
          `See ${name} props: "${illegalDefaults}".`,
        ].join(' '))
      }

      // prevent listing defaultProps in autoControlledProps
      //
      // Default props are automatically handled.
      // Listing defaults in autoControlledProps would result in allowing defaultDefaultValue props.
      const illegalAutoControlled = _.filter(autoControlledProps, prop => prop.startsWith('default'))
      if (!_.isEmpty(illegalAutoControlled)) {
        console.error([
          'Do not add default props to autoControlledProps.',
          'Default props are automatically handled.',
          `See ${name} autoControlledProps: "${illegalAutoControlled}".`,
        ].join(' '))
      }
    }
  }

  componentWillReceiveProps(nextProps) {
    if (super.componentWillReceiveProps) super.componentWillReceiveProps(nextProps)

    // props always win, update state with all auto controlled prop
    const newState = _.pick(nextProps, this.constructor.autoControlledProps)
    if (!_.isEmpty(newState)) this.setState(newState)
  }

  /**
   * Safely attempt to set state for props that might be controlled by the user.
   * Second argument is a state object that is always passed to setState.
   * @param {object} maybeState State that corresponds to controlled props.
   * @param {object} [state] Actual state, useful when you also need to setState.
   */
  trySetState = (maybeState, state) => {
    // console.debug('trySetState')
    // console.log('maybe:', maybeState, 'state:', state)
    const { autoControlledProps } = this.constructor
    if (!__PROD__) {
      const { name } = this.constructor
      // warn about failed attempts to setState for keys not listed in autoControlledProps
      const illegalKeys = _.difference(_.keys(maybeState), autoControlledProps)
      if (!_.isEmpty(illegalKeys)) {
        console.error([
          `${name} called trySetState() with controlled props: "${illegalKeys}".`,
          'State will not be set.',
          'Only props in static autoControlledProps will be set on state.',
        ].join(' '))
      }
    }

    // pick auto controlled props
    // omit props from parent
    let newState = _.omit(_.pick(maybeState, autoControlledProps), _.keys(this.props))

    if (state) newState = { ...newState, ...state }

    if (!_.isEmpty(newState)) this.setState(newState)
  }
}
<commit_msg>refactor(AutoControlledComponent): use process.env (#232)<commit_after>/* eslint-disable no-console */
/**
 * Why choose inheritance over a HOC?  Multiple advantages for this particular use case.
 * In short, we need identical functionality to setState(), unless there is a prop defined
 * for the state key.  Also:
 *
 * 1. Single Renders
 *    Calling trySetState() in constructor(), componentWillMount(), or componentWillReceiveProps()
 *    does not cause two renders. Consumers and tests do not have to wait two renders to get state.
 *    See www.react.run/4kJFdKoxb/27 for an example of this issue.
 *
 * 2. Simple Testing
 *    Using a HOC means you must either test the undecorated component or test through the decorator.
 *    Testing the undecorated component means you must mock the decorator functionality.
 *    Testing through the HOC means you can not simply shallow render your component.
 *
 * 3. Statics
 *    HOC wrap instances, so statics are no longer accessible.  They can be hoisted, but this is more
 *    looping over properties and storing references.  We rely heavily on statics for testing and sub
 *    components.
 *
 * 4. Instance Methods
 *    Some instances methods may be exposed to users via refs.  Again, these are lost with HOC unless
 *    hoisted and exposed by the HOC.
 */
import _ from 'lodash'
import { Component } from 'react'

const getDefaultPropName = (prop) => `default${prop[0].toUpperCase() + prop.slice(1)}`

export default class AutoControlledComponent extends Component {
  componentWillMount() {
    if (super.componentWillMount) super.componentWillMount()
    const { autoControlledProps } = this.constructor

    // Auto controlled props are copied to state.
    // Set initial state by copying auto controlled props to state.
    // Also look for the default prop for any auto controlled props (foo => defaultFoo)
    // so we can set initial values from defaults.
    this.state = _.transform(autoControlledProps, (res, prop) => {
      const defaultPropName = getDefaultPropName(prop)

      // apply default props if they exist
      res[prop] = this.props[defaultPropName in this.props ? defaultPropName : prop]

      if (process.env.NODE_ENV !== 'production') {
        const { name } = this.constructor
        // prevent defaultFoo={} along side foo={}
        if (defaultPropName in this.props && prop in this.props) {
          console.error(
            `${name} prop "${prop}" is auto controlled. Specify either ${defaultPropName} or ${prop}, but not both.`
          )
        }
      }
    }, {})

    if (process.env.NODE_ENV !== 'production') {
      const { defaultProps, name, propTypes } = this.constructor
      // require static autoControlledProps
      if (!autoControlledProps) {
        console.error(`Auto controlled ${name} must specify a static autoControlledProps array.`)
      }

      // require propTypes
      _.each(autoControlledProps, (prop) => {
        const defaultProp = getDefaultPropName(prop)
        // regular prop
        if (!_.has(propTypes, defaultProp)) {
          console.error(`${name} is missing "${defaultProp}" propTypes validation for auto controlled prop "${prop}".`)
        }
        // its default prop
        if (!_.has(propTypes, prop)) {
          console.error(`${name} is missing propTypes validation for auto controlled prop "${prop}".`)
        }
      })

      // prevent autoControlledProps in defaultProps
      //
      // When setting state, auto controlled props values always win (so the parent can manage them).
      // It is not reasonable to decipher the difference between props from the parent and defaultProps.
      // Allowing defaultProps results in trySetState always deferring to the defaultProp value.
      // Auto controlled props also listed in defaultProps can never be updated.
      const illegalDefaults = _.intersection(autoControlledProps, _.keys(defaultProps))
      if (!_.isEmpty(illegalDefaults)) {
        console.error([
          'Do not set defaultProps for autoControlledProps,',
          'use trySetState() in constructor() or componentWillMount() instead.',
          `See ${name} props: "${illegalDefaults}".`,
        ].join(' '))
      }

      // prevent listing defaultProps in autoControlledProps
      //
      // Default props are automatically handled.
      // Listing defaults in autoControlledProps would result in allowing defaultDefaultValue props.
      const illegalAutoControlled = _.filter(autoControlledProps, prop => prop.startsWith('default'))
      if (!_.isEmpty(illegalAutoControlled)) {
        console.error([
          'Do not add default props to autoControlledProps.',
          'Default props are automatically handled.',
          `See ${name} autoControlledProps: "${illegalAutoControlled}".`,
        ].join(' '))
      }
    }
  }

  componentWillReceiveProps(nextProps) {
    if (super.componentWillReceiveProps) super.componentWillReceiveProps(nextProps)

    // props always win, update state with all auto controlled prop
    const newState = _.pick(nextProps, this.constructor.autoControlledProps)
    if (!_.isEmpty(newState)) this.setState(newState)
  }

  /**
   * Safely attempt to set state for props that might be controlled by the user.
   * Second argument is a state object that is always passed to setState.
   * @param {object} maybeState State that corresponds to controlled props.
   * @param {object} [state] Actual state, useful when you also need to setState.
   */
  trySetState = (maybeState, state) => {
    // console.debug('trySetState')
    // console.log('maybe:', maybeState, 'state:', state)
    const { autoControlledProps } = this.constructor
    if (process.env.NODE_ENV !== 'production') {
      const { name } = this.constructor
      // warn about failed attempts to setState for keys not listed in autoControlledProps
      const illegalKeys = _.difference(_.keys(maybeState), autoControlledProps)
      if (!_.isEmpty(illegalKeys)) {
        console.error([
          `${name} called trySetState() with controlled props: "${illegalKeys}".`,
          'State will not be set.',
          'Only props in static autoControlledProps will be set on state.',
        ].join(' '))
      }
    }

    // pick auto controlled props
    // omit props from parent
    let newState = _.omit(_.pick(maybeState, autoControlledProps), _.keys(this.props))

    if (state) newState = { ...newState, ...state }

    if (!_.isEmpty(newState)) this.setState(newState)
  }
}
<|endoftext|>


<commit_before>/* See license.txt for terms of usage */

"use strict";

const { getToolDefinition, getToolboxWhenReady } = require("./toolbox.js");
const { closeTab } = require("./window.js");
const { setTimeout } = require("sdk/timers");
const { domPanelId } = require("../lib/dom/dom-panel.js");

/**
 * This test checks existence of the DOM panel. It opens a new tab,
 * shows the toolbox and waits till the panel is refreshed.
 */
exports["test DOM panel"] = function(assert, done) {
  getToolboxWhenReady("about:blank", domPanelId).then(({toolbox, tab}) => {
    let tool = getToolDefinition(domPanelId);
    assert.ok(tool, "The DOM tool must exist!");

    toolbox.selectTool(domPanelId).then(panel => {
      assert.ok(panel.id == domPanelId, "DOM panel is loaded!");

      // Wait till the panel is refreshed and asynchronously quit the test.
      panel.once("refreshed", function() {
        setTimeout(function() {
          closeTab(tab);
          done();
        });
      });
    });
  });
};

require("sdk/test").run(exports);
<commit_msg>#287 disable DOM panel test for now<commit_after>/* See license.txt for terms of usage */

"use strict";

const { getToolDefinition, getToolboxWhenReady } = require("./toolbox.js");
const { closeTab } = require("./window.js");
const { setTimeout } = require("sdk/timers");
const { domPanelId } = require("../lib/dom/dom-panel.js");

/**
 * This test checks existence of the DOM panel. It opens a new tab,
 * shows the toolbox and waits till the panel is refreshed.
 */
exports["test DOM panel"] = function(assert, done) {
  getToolboxWhenReady("about:blank", domPanelId).then(({toolbox, tab}) => {
    let tool = getToolDefinition(domPanelId);
    assert.ok(tool, "The DOM tool must exist!");

    closeTab(tab);
    done();

    /*toolbox.selectTool(domPanelId).then(panel => {
      assert.ok(panel.id == domPanelId, "DOM panel is loaded!");

      // Wait till the panel is refreshed and asynchronously quit the test.
      panel.once("refreshed", function() {
        setTimeout(function() {
          closeTab(tab);
          done();
        });
      });
    });*/
  });
};

require("sdk/test").run(exports);
<|endoftext|>


<commit_before>jQuery(function() {

    var loadTemplate = function(basename) {
        var source    = jQuery('#' + basename + '-template').html();
        var template  = Handlebars.compile(source);
        var container = jQuery('#' + basename + 's-container');

        console.log(basename, 'loading...');
        jQuery.get('data/' + basename + 's.json', function(obj) {
            console.log('... loaded ', basename);

            jQuery.each(obj.data, function(ii, item) {
                var rendered = template(item);
                container.append(rendered);
            });
        });
    };

    loadTemplate('stakeholder');
    loadTemplate('topic');
});
<commit_msg>explicitly specifying response dataType to get AJAX working properly on both Apache & simple Ruby server<commit_after>jQuery(function() {

    var loadTemplate = function(basename) {
        var source    = jQuery('#' + basename + '-template').html();
        var template  = Handlebars.compile(source);
        var container = jQuery('#' + basename + 's-container');
        var ajax;

        console.log(basename, 'loading...');
        ajax = jQuery.ajax('data/' + basename + 's.json', {dataType: "json"});
        ajax.done(function(obj) {
            console.log('... loaded ', basename);

            jQuery.each(obj.data, function(ii, item) {
                var rendered = template(item);
                container.append(rendered);
            });
        });
    };

    loadTemplate('stakeholder');
    loadTemplate('topic');
});
<|endoftext|>


<commit_before>import Request from 'superagent';
import Poller from './poller';
import './../../promises';

/* global jest */
jest.mock('superagent');

describe('poller', () => {
  let functions, url;

  beforeEach(() => {
    jest.useFakeTimers();
    const callback = jasmine.createSpy('callback');
    functions = {
      callback
    };
    url = 'foo/bar';
    spyOn(console, 'error');
    spyOn(console, 'warn');

    Request.__setMockResponse({
      status() {
        return 200;
      },
      ok() {
        return true;
      },
      body: {
        message_type: 'success'
      }
    });
  });

  afterEach(() => {
    jest.clearAllMocks();
    jest.clearAllTimers();
  });

  describe('when no url has been provided', () => {
    it('logs a no url error', () => {
      Poller({}, functions, {});
      expect(console.error).toHaveBeenCalledWith( // eslint-disable-line no-console
        'You must provide a url to the poller');
    });

    describe('when no queryOptions object is passed', () => {
      it('logs a no url error', () => {
        Poller(null, functions, {});
        expect(console.error).toHaveBeenCalledWith( // eslint-disable-line no-console
          'You must provide a url to the poller');
      });
    });
  });

  describe('when no callback function is provided and a conditionMet function has been provided', () => {
    it('throws a no callback error', () => {
      Poller({ url }, { conditionMet: () => {} }, {});
      expect(console.error).toHaveBeenCalledWith( // eslint-disable-line no-console
        'You must provide a callback function if you are testing a condition with conditionMet');
    });
  });

  describe('when no callback function is provided', () => {
    it('polls continuously', () => {
      Request.get = jest.fn().mockReturnThis();

      Poller({ url }, {}, {});

      for (let i = 1; i < 10; i++) {
        jest.runTimersToTime(3001);
        expect(Request.get).toBeCalledWith(url);
      }

      expect(Request.get.mock.calls.length).toBe(10);
    });
  });

  describe('default options', () => {
    it('defaults the interval to 3 seconds if none is provided', () => {
      Request.get = jest.fn().mockReturnThis();

      Poller({ url }, functions, {});

      expect(Request.get.mock.calls.length).toBe(1);

      jest.runTimersToTime(1000);

      expect(Request.get.mock.calls.length).toBe(1);

      jest.runTimersToTime(2001);

      expect(Request.get.mock.calls.length).toEqual(2);
    });
  });

  describe('poll', () => {
    describe('when the pollCount exceeds the specified number of retries', () => {
      it('logs a too many requests warning', () => {
        console.warn = jest.fn(); // eslint-disable-line no-console

        Poller({ url }, functions, { interval: 1000, retries: 2 });
        jest.runTimersToTime(1000);

        for (let i = 0; i < 2; i++) {
          jest.runTimersToTime(1000);
        }

        expect(console.warn.mock.calls[0][0]).toBe( // eslint-disable-line no-console
          'The poller has made too many requests - terminating poll');
      });
    });

    describe('when time exceeds the specified endTime', () => {
      it('logs a too many requests warning 2', () => {
        const now = Date.now();
        Date.now = jest.fn();
        Date.now.mockReturnValueOnce(now)
          .mockReturnValueOnce(now)
          .mockReturnValueOnce(now);

        const testInterval = 1000;
        console.warn = jest.fn(); // eslint-disable-line no-console

        let mockDateValue = now;

        Poller({ url }, functions, { interval: testInterval, endTime: 3000 });
        for (let i = 0; i < 4; i++) {
          mockDateValue += (testInterval + i);
          Date.now.mockReturnValueOnce(mockDateValue);
          jest.runTimersToTime(testInterval);
        }
        expect(console.warn.mock.calls[0][0]).toBe( // eslint-disable-line no-console
          'The poller has made too many requests - terminating poll');
      });
    });

    describe('when polling terminates and theres an onMaxRetries function', () => {
      it('calls the onMaxRetries function', () => {
        const onMaxRetriesSpy = jest.fn();
        functions.onMaxRetries = onMaxRetriesSpy;

        Poller({ url }, functions, { interval: 1000, retries: 2 });
        jest.runTimersToTime(1000);

        for (let i = 0; i < 2; i++) {
          jest.runTimersToTime(1000);
        }

        expect(onMaxRetriesSpy).toHaveBeenCalled();
      });
    });

    describe('the request', () => {
      it('makes a get request with the provided params', () => {
        Request.query = jest.fn().mockReturnThis();
        Poller({
          url,
          data: {
            foo: 'bar',
            headers: {
              Accept: 'application/json'
            }
          }
        }, functions, { interval: 1000 });

        expect(Request.query).toBeCalledWith({
          foo: 'bar',
          headers: {
            Accept: 'application/json'
          }
        });
      });
    });

    describe('if there is an error', () => {
      beforeEach(() => {
        Request.__setMockResponse({
          status() {
            return 500;
          },
          ok() {
            return false;
          },
          body: {
            message_type: 'error'
          }
        });

        Request.__setMockError({
          message: 'Unsuccessful HTTP response'
        });
      });

      afterEach(() => {
        Request.__setMockError(undefined);
      });

      describe('if a handleError function is provided', () => {
        it('calls the handleError with the error', (done) => {
          functions.handleError = jest.fn();
          Poller({ url }, functions, { interval: 1000 });
          done();
          expect(functions.handleError).toBeCalled();
        });
      });

      describe('if no custom handleError function is avaliable', () => {
        it('logs the error', (done) => {
          Poller({ url }, functions, { interval: 1000 });
          done();
          expect(console.error).toHaveBeenCalledWith( // eslint-disable-line no-console
            'Unsuccessful HTTP response');
        });
      });
    });

    describe('terminating function', () => {
      beforeEach(() => {
        functions.terminate = jest.fn();
      });

      describe('if a terminating condition function is provided', () => {
        describe('when the terminating condition is met', () => {
          beforeEach(() => {
            functions.terminate.mockReturnValue(true);
            Poller({ url }, functions, { interval: 1000 });
          });

          it('checks the response with terminate function', () => {
            expect(functions.terminate).toHaveBeenCalledWith(jasmine.any(Object));
          });
        });

        describe('if the terminating condition has not been met', () => {
          beforeEach(() => {
            functions.terminate.mockReturnValue(false);
            Poller({ url }, functions, { interval: 1000 });
          });

          it('checks the response with terminate function', () => {
            expect(functions.terminate).toHaveBeenCalledWith(jasmine.any(Object));
          });
        });
      });
    });

    describe('conditionMet function', () => {
      it('calls the conditionMet function with the response', () => {
        functions.conditionMet = jest.fn();
        Poller({ url }, functions, { interval: 1000 });

        expect(functions.conditionMet).toBeCalledWith(jasmine.any(Object));
      });

      describe('when a custom conditionMet function has been provided', () => {
        describe('when the condition has been met', () => {
          it('calls the callback with the response', () => {
            functions.conditionMet = jest.fn().mockReturnValue(true);
            Poller({ url }, functions, { interval: 1000 });
            expect(functions.callback).toBeCalledWith(jasmine.any(Object));
          });
        });

        describe('when the condition has not been met', () => {
          it('does not call the callback', () => {
            functions.conditionMet = jest.fn().mockReturnValue(false);
            Poller({ url }, functions, { interval: 1000 });
            expect(functions.callback).not.toHaveBeenCalled();
          });
        });
      });

      describe('when a custom conditionMet function has not been provided', () => {
        it('never calls the callback', () => {
          Poller({ url }, functions, { interval: 1000 });
          expect(functions.callback).not.toHaveBeenCalled();
        });
      });
    });

    describe('when the promise has not been resolved or rejected', () => {
      it('calls the poll again after the specified interval', () => {
        Request.get = jest.fn().mockReturnThis();

        Poller({ url }, functions, { interval: 1000 });

        expect(Request.get.mock.calls.length).toBe(1);
        jest.runTimersToTime(500);

        expect(Request.get.mock.calls.length).toEqual(1);
        jest.runTimersToTime(501);

        expect(Request.get.mock.calls.length).toEqual(2);
      });
    });
  });

  describe('conditionNotMetCallback', () => {
    describe('when the conditionMet returns true', () => {
      it('does not call the callback with the response', () => {
        functions.conditionMet = jest.fn().mockReturnValue(true);
        functions.conditionNotMetCallback = jest.fn();

        Poller({ url }, functions, { interval: 1000 });

        expect(functions.conditionNotMetCallback).not.toBeCalled();
      });
    });

    describe('when conditionMet returns false', () => {
      it('it calls the condition not met function', () => {
        functions.conditionMet = jest.fn().mockReturnValue(false);
        functions.conditionNotMetCallback = jest.fn();
        Poller({ url }, functions, { interval: 1000 });

        expect(functions.conditionNotMetCallback).toBeCalled();
      });
    });
  });
});
<commit_msg>PR Comments #1791<commit_after>import Request from 'superagent';
import Poller from './poller';
import './../../promises';

/* global jest */
jest.mock('superagent');

describe('poller', () => {
  let functions, url;

  beforeEach(() => {
    jest.useFakeTimers();
    const callback = jasmine.createSpy('callback');
    functions = {
      callback
    };
    url = 'foo/bar';
    spyOn(console, 'error');
    spyOn(console, 'warn');

    Request.__setMockResponse({
      status() {
        return 200;
      },
      ok() {
        return true;
      },
      body: {
        message_type: 'success'
      }
    });
  });

  afterEach(() => {
    jest.clearAllMocks();
    jest.clearAllTimers();
  });

  describe('when no url has been provided', () => {
    it('logs a no url error', () => {
      Poller({}, functions, {});
      expect(console.error).toHaveBeenCalledWith( // eslint-disable-line no-console
        'You must provide a url to the poller');
    });

    describe('when no queryOptions object is passed', () => {
      it('logs a no url error', () => {
        Poller(null, functions, {});
        expect(console.error).toHaveBeenCalledWith( // eslint-disable-line no-console
          'You must provide a url to the poller');
      });
    });
  });

  describe('when no callback function is provided and a conditionMet function has been provided', () => {
    it('throws a no callback error', () => {
      Poller({ url }, { conditionMet: () => {} }, {});
      expect(console.error).toHaveBeenCalledWith( // eslint-disable-line no-console
        'You must provide a callback function if you are testing a condition with conditionMet');
    });
  });

  describe('when no callback function is provided', () => {
    it('polls continuously', () => {
      Request.get = jest.fn().mockReturnThis();

      Poller({ url }, {}, {});

      for (let i = 1; i < 10; i++) {
        jest.runTimersToTime(3001);
        expect(Request.get).toBeCalledWith(url);
      }

      expect(Request.get.mock.calls.length).toBe(10);
    });
  });

  describe('default options', () => {
    it('defaults the interval to 3 seconds if none is provided', () => {
      Request.get = jest.fn().mockReturnThis();

      Poller({ url }, functions, {});

      expect(Request.get.mock.calls.length).toBe(1);

      jest.runTimersToTime(1000);

      expect(Request.get.mock.calls.length).toBe(1);

      jest.runTimersToTime(2001);

      expect(Request.get.mock.calls.length).toEqual(2);
    });
  });

  describe('poll', () => {
    describe('when the pollCount exceeds the specified number of retries', () => {
      it('logs a too many requests warning', () => {
        console.warn = jest.fn(); // eslint-disable-line no-console

        Poller({ url }, functions, { interval: 1000, retries: 2 });
        jest.runTimersToTime(1000);

        for (let i = 0; i < 2; i++) {
          jest.runTimersToTime(1000);
        }

        expect(console.warn.mock.calls[0][0]).toBe( // eslint-disable-line no-console
          'The poller has made too many requests - terminating poll');
      });
    });

    describe('when time exceeds the specified endTime', () => {
      it('logs a too many requests warning 2', () => {
        const now = Date.now();
        Date.now = jest.fn();
        Date.now.mockReturnValueOnce(now)
          .mockReturnValueOnce(now)
          .mockReturnValueOnce(now);

        const testInterval = 1000;
        console.warn = jest.fn(); // eslint-disable-line no-console

        let mockDateValue = now;

        Poller({ url }, functions, { interval: testInterval, endTime: 3000 });
        for (let i = 0; i < 4; i++) {
          mockDateValue += (testInterval + i);
          Date.now.mockReturnValueOnce(mockDateValue);
          jest.runTimersToTime(testInterval);
        }
        expect(console.warn.mock.calls[0][0]).toBe( // eslint-disable-line no-console
          'The poller has made too many requests - terminating poll');
      });
    });

    describe('when polling terminates and theres an onMaxRetries function', () => {
      it('calls the onMaxRetries function', () => {
        const onMaxRetriesSpy = jest.fn();
        functions.onMaxRetries = onMaxRetriesSpy;

        Poller({ url }, functions, { interval: 1000, retries: 2 });

        for (let i = 0; i < 2; i++) {
          expect(onMaxRetriesSpy).not.toHaveBeenCalled();
          jest.runTimersToTime(1000);
        }

        expect(onMaxRetriesSpy).toHaveBeenCalled();
      });
    });

    describe('the request', () => {
      it('makes a get request with the provided params', () => {
        Request.query = jest.fn().mockReturnThis();
        Poller({
          url,
          data: {
            foo: 'bar',
            headers: {
              Accept: 'application/json'
            }
          }
        }, functions, { interval: 1000 });

        expect(Request.query).toBeCalledWith({
          foo: 'bar',
          headers: {
            Accept: 'application/json'
          }
        });
      });
    });

    describe('if there is an error', () => {
      beforeEach(() => {
        Request.__setMockResponse({
          status() {
            return 500;
          },
          ok() {
            return false;
          },
          body: {
            message_type: 'error'
          }
        });

        Request.__setMockError({
          message: 'Unsuccessful HTTP response'
        });
      });

      afterEach(() => {
        Request.__setMockError(undefined);
      });

      describe('if a handleError function is provided', () => {
        it('calls the handleError with the error', (done) => {
          functions.handleError = jest.fn();
          Poller({ url }, functions, { interval: 1000 });
          done();
          expect(functions.handleError).toBeCalled();
        });
      });

      describe('if no custom handleError function is avaliable', () => {
        it('logs the error', (done) => {
          Poller({ url }, functions, { interval: 1000 });
          done();
          expect(console.error).toHaveBeenCalledWith( // eslint-disable-line no-console
            'Unsuccessful HTTP response');
        });
      });
    });

    describe('terminating function', () => {
      beforeEach(() => {
        functions.terminate = jest.fn();
      });

      describe('if a terminating condition function is provided', () => {
        describe('when the terminating condition is met', () => {
          beforeEach(() => {
            functions.terminate.mockReturnValue(true);
            Poller({ url }, functions, { interval: 1000 });
          });

          it('checks the response with terminate function', () => {
            expect(functions.terminate).toHaveBeenCalledWith(jasmine.any(Object));
          });
        });

        describe('if the terminating condition has not been met', () => {
          beforeEach(() => {
            functions.terminate.mockReturnValue(false);
            Poller({ url }, functions, { interval: 1000 });
          });

          it('checks the response with terminate function', () => {
            expect(functions.terminate).toHaveBeenCalledWith(jasmine.any(Object));
          });
        });
      });
    });

    describe('conditionMet function', () => {
      it('calls the conditionMet function with the response', () => {
        functions.conditionMet = jest.fn();
        Poller({ url }, functions, { interval: 1000 });

        expect(functions.conditionMet).toBeCalledWith(jasmine.any(Object));
      });

      describe('when a custom conditionMet function has been provided', () => {
        describe('when the condition has been met', () => {
          it('calls the callback with the response', () => {
            functions.conditionMet = jest.fn().mockReturnValue(true);
            Poller({ url }, functions, { interval: 1000 });
            expect(functions.callback).toBeCalledWith(jasmine.any(Object));
          });
        });

        describe('when the condition has not been met', () => {
          it('does not call the callback', () => {
            functions.conditionMet = jest.fn().mockReturnValue(false);
            Poller({ url }, functions, { interval: 1000 });
            expect(functions.callback).not.toHaveBeenCalled();
          });
        });
      });

      describe('when a custom conditionMet function has not been provided', () => {
        it('never calls the callback', () => {
          Poller({ url }, functions, { interval: 1000 });
          expect(functions.callback).not.toHaveBeenCalled();
        });
      });
    });

    describe('when the promise has not been resolved or rejected', () => {
      it('calls the poll again after the specified interval', () => {
        Request.get = jest.fn().mockReturnThis();

        Poller({ url }, functions, { interval: 1000 });

        expect(Request.get.mock.calls.length).toBe(1);
        jest.runTimersToTime(500);

        expect(Request.get.mock.calls.length).toEqual(1);
        jest.runTimersToTime(501);

        expect(Request.get.mock.calls.length).toEqual(2);
      });
    });
  });

  describe('conditionNotMetCallback', () => {
    describe('when the conditionMet returns true', () => {
      it('does not call the callback with the response', () => {
        functions.conditionMet = jest.fn().mockReturnValue(true);
        functions.conditionNotMetCallback = jest.fn();

        Poller({ url }, functions, { interval: 1000 });

        expect(functions.conditionNotMetCallback).not.toBeCalled();
      });
    });

    describe('when conditionMet returns false', () => {
      it('it calls the condition not met function', () => {
        functions.conditionMet = jest.fn().mockReturnValue(false);
        functions.conditionNotMetCallback = jest.fn();
        Poller({ url }, functions, { interval: 1000 });

        expect(functions.conditionNotMetCallback).toBeCalled();
      });
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

/* Filters */

angular.module('appFilters', [])
    .filter('localDate', function () {
        return function (input) {
            console.log('inside filter', input)
            return moment(new Date(input)).format('MMM Do YYYY HH:mm');
        }
    });<commit_msg>Change date format<commit_after>'use strict';

/* Filters */

angular.module('appFilters', [])
    .filter('localDate', function () {
        return function (input) {
            return moment(new Date(input)).format('MMM D YYYY HH:mm');
        }
    });<|endoftext|>


<commit_before>// configs

var maxConcurrentQueuedRequests = 15 // not queued requests are not limited in running parallel
var queuesByPriority = [
  'architectureGeometries',
  'architectureTexturesLoRes',
  'interiorGeometries',
  'interiorTexturesLoRes',
  'architectureTexturesHiRes',
  'interiorTexturesHiRes'
]

var queueFences = [
  false,
  false,
  true,
  false,
  false
]

// internals
var queues = {}
var queueFences = {}
var queuesChanged = false
var queueInfo = {}
var queuesLength = queuesByPriority.length
var concurrentRequests = 0
var concurrentPerQueue = {}
var loadingQueueData = ''
var loadingQueueAlgorithm     = 'overstep-one-fenced';
var loadingQueuePipelineDepth = maxConcurrentQueuedRequests;
var queueName
for (var i = 0, l = queuesLength; i < l; i++) {
  queueName = queuesByPriority[i]
  queues[queueName] = []
  queueFences[queueName] = queueFences[i]
  queueInfo[queueName] = {requestCount: 0}
  concurrentPerQueue[queueName] = 0
}

// private methods

function startRequest(queueName) {
  // Update queue tracking information
  var info = queueInfo[queueName];
  var time = performance.now() / 1000;
  if (typeof info.timeFirst === 'undefined') {
    info.timeFirst = time;
    info.timeLast  = time;
  } else
    info.timeLast  = time;
  info.requestCount++;
  // Update concurrent request counts
  concurrentPerQueue[queueName] += 1;
  concurrentRequests++;
  //
  queuesChanged = true;
  // Start request
  var queue = queues[queueName];
  var request = queue.shift();
  request.start();
}

function processQueue() {
  var anchorStage = null;
  for (var i = 0; i < queuesLength; i++) {
    var queueName = queuesByPriority[i];
    while (queues[queueName].length > 0 && concurrentRequests < loadingQueuePipelineDepth)
      startRequest(queueName)
    if (anchorStage === null && concurrentPerQueue[queueName] !== 0)
      anchorStage = i;
    if (anchorStage !== null && (queueFences[queueName] || (i - anchorStage > 0)))
      break;
  }
}

// public methods

function enqueue(queueName, url){

  // fallback to first queue
  if (!queues[queueName]) {
    if (queueName) console.error('onknown queue ', queueName)
    queueName = queuesByPriority[0]
  }

  // create promise and add to queue
  return new Promise(function(resolve, reject){
    // has to be asynchronous in order to decouple queue processing from synchronous code
    setTimeout(function(){
      var queue = queues[queueName]
      queue[ queue.length ] = { url: url, start: resolve }
      processQueue()
    },1)
  })

}

function dequeue(queueName, url) {
  var info = queueInfo[queueName];
  if (!info) {
    if (queueName) console.warn('Queue info not found for queue name "'+queueName+'"')
    return
  }
  info.timeLastFinished = performance.now() / 1000;
  concurrentPerQueue[queueName] -= 1
  concurrentRequests -= 1
  queuesChanged = true;
  processQueue()
}

// expose API

var queueManager = {
  enqueue: enqueue,
  dequeue: dequeue,
  info: queueInfo
}

export default queueManager<commit_msg>minor adaptation after migrating code from archilogic editor<commit_after>// configs

var maxConcurrentQueuedRequests = 15 // not queued requests are not limited in running parallel
var queuesByPriority = [
  'architectureGeometries',
  'architectureTexturesLoRes',
  'interiorGeometries',
  'interiorTexturesLoRes',
  'architectureTexturesHiRes',
  'interiorTexturesHiRes'
]

var queueFences = [
  false,
  false,
  true,
  false,
  false
]

// internals

var queues = {}
var queueFences = {}
var queuesChanged = false
var queueInfo = {}
var queuesLength = queuesByPriority.length
var concurrentRequests = 0
var concurrentPerQueue = {}
var queueName
for (var i = 0, l = queuesLength; i < l; i++) {
  queueName = queuesByPriority[i]
  queues[queueName] = []
  queueFences[queueName] = queueFences[i]
  queueInfo[queueName] = {requestCount: 0}
  concurrentPerQueue[queueName] = 0
}

// private methods

function startRequest(queueName) {
  // Update queue tracking information
  var info = queueInfo[queueName];
  var time = performance.now() / 1000;
  if (info.timeFirst) {
    info.timeFirst = time;
    info.timeLast  = time;
  } else
    info.timeLast  = time;
  info.requestCount++;
  // Update concurrent request counts
  concurrentPerQueue[queueName] += 1;
  concurrentRequests++;
  // set flag
  queuesChanged = true;
  // Start request
  var queue = queues[queueName];
  var request = queue.shift();
  request.start();
}

function processQueue() {
  var anchorStage = null;
  for (var i = 0; i < queuesLength; i++) {
    var queueName = queuesByPriority[i];
    while (queues[queueName].length > 0 && concurrentRequests < maxConcurrentQueuedRequests)
      startRequest(queueName)
    if (anchorStage === null && concurrentPerQueue[queueName] !== 0)
      anchorStage = i;
    if (anchorStage !== null && (queueFences[queueName] || (i - anchorStage > 0)))
      break;
  }
}

// public methods

function enqueue(queueName, url){

  // fallback to first queue
  if (!queues[queueName]) {
    if (queueName) console.error('onknown queue ', queueName)
    queueName = queuesByPriority[0]
  }

  // create promise and add to queue
  return new Promise(function(resolve, reject){
    // has to be asynchronous in order to decouple queue processing from synchronous code
    setTimeout(function(){
      var queue = queues[queueName]
      queue[ queue.length ] = { url: url, start: resolve }
      processQueue()
    },1)
  })

}

function dequeue(queueName, url) {
  var info = queueInfo[queueName];
  if (!info) {
    if (queueName) console.warn('Queue info not found for queue name "'+queueName+'"')
    return
  }
  info.timeLastFinished = performance.now() / 1000;
  concurrentPerQueue[queueName] -= 1
  concurrentRequests -= 1
  queuesChanged = true;
  processQueue()
}

// expose API

var queueManager = {
  enqueue: enqueue,
  dequeue: dequeue,
  info: queueInfo
}

export default queueManager<|endoftext|>


<commit_before>// for use with `d3-playbooks-riot-components`

export default ({
  yDomain,
  getColor
}, {getLabel}) => {
  if (!getLabel) getLabel = q => Math.round(q)
  const quantiles = getColor.quantiles()
  const quantileWidth = quantiles[0]
  quantiles.push(yDomain[1])
  return quantiles.map(q => {
    return {
      label: getLabel(q),
      color: getColor(q-quantileWidth/2)
    }
  })
}
<commit_msg>Fix `getLegendItems` quantile width<commit_after>// for use with `d3-playbooks-riot-components`

export default ({
  yDomain,
  getColor
}, {getLabel}) => {
  if (!getLabel) getLabel = q => Math.round(q)
  const quantiles = getColor.quantiles()
  const quantileWidth = quantiles[1] - quantiles[0]
  quantiles.push(yDomain[1])
  return quantiles.map(q => {
    return {
      label: getLabel(q),
      color: getColor(q-quantileWidth/2)
    }
  })
}
<|endoftext|>


<commit_before>'use strict';

const mongoose = require('mongoose');
const sanitizeHtml = require('sanitize-html');
const sanitizeHtmlNoTagsConfig = {
  allowedTags: [],
  allowedAttributes: []
};
const sanitizeHtmlContent = {
  allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img'])
};

const contentItemSchema = mongoose.Schema({
  author: {
    type: String,
    set: (val) => {
      return this.author = sanitizeHtml(val, sanitizeHtmlNoTagsConfig);
    }
  },
  content: {
    type: String,
    set: (val) => {
      return this.content = sanitizeHtml(val, sanitizeHtmlContent);
    }
  },
  description: String,
  image: {
    src: String,
    name: String
  },
  postType: {
    type: String,
    set: (val) => {
      return this.author = sanitizeHtml(val, sanitizeHtmlNoTagsConfig);
    }
  },
  subtitle: {
    type: String,
    set: (val) => {
      return this.author = sanitizeHtml(val, sanitizeHtmlNoTagsConfig);
    }
  },
  title: {
    type: String,
    required: true,
    set: (val) => {
      return this.author = sanitizeHtml(val, sanitizeHtmlNoTagsConfig);
    }
  },
  uniqueTitleKey: {
    type: String,
    default: Date.now().toString()
  },
  createdAt: {
    type: Date,
    default: new Date()
  },
  uniqueTitle: String
});

// Define a pre-save method for contentItemSchema
contentItemSchema.pre('save', function (next) {
  this.uniqueTitle = `${this.title.toLowerCase().toString()
    .replace(/[^a-z0-9+]+/gi, '-')}-${this.uniqueTitleKey}`;
  next();
});

module.exports = mongoose.model('ContentItem', contentItemSchema);
<commit_msg>add native mongoose timestamp<commit_after>'use strict';

const mongoose = require('mongoose');
const sanitizeHtml = require('sanitize-html');
const sanitizeHtmlNoTagsConfig = {
  allowedTags: [],
  allowedAttributes: []
};
const sanitizeHtmlContent = {
  allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img'])
};

const contentItemSchema = mongoose.Schema({
  author: {
    type: String,
    set: (val) => {
      return this.author = sanitizeHtml(val, sanitizeHtmlNoTagsConfig);
    }
  },
  content: {
    type: String,
    set: (val) => {
      return this.content = sanitizeHtml(val, sanitizeHtmlContent);
    }
  },
  description: String,
  image: {
    src: String,
    name: String
  },
  postType: {
    type: String,
    set: (val) => {
      return this.author = sanitizeHtml(val, sanitizeHtmlNoTagsConfig);
    }
  },
  subtitle: {
    type: String,
    set: (val) => {
      return this.author = sanitizeHtml(val, sanitizeHtmlNoTagsConfig);
    }
  },
  title: {
    type: String,
    required: true,
    set: (val) => {
      return this.author = sanitizeHtml(val, sanitizeHtmlNoTagsConfig);
    }
  },
  uniqueTitleKey: {
    type: String,
    default: Date.now().toString()
  },
  uniqueTitle: String
},
  {timestamps: true});

// Define a pre-save method for contentItemSchema
contentItemSchema.pre('save', function (next) {
  this.uniqueTitle = `${this.title.toLowerCase().toString()
    .replace(/[^a-z0-9+]+/gi, '-')}-${this.uniqueTitleKey}`;
  next();
});

module.exports = mongoose.model('ContentItem', contentItemSchema);
<|endoftext|>


<commit_before>module("Plugins");

function pluginRules() {

	if ( ! dominoes.rule("jQuery") ) {
		dominoes
			.rule( "jQuery" , "http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" )
			.rule( "plugin/css" , "../dist/dominoes-css.js" )
			.functor( "cssTest" , function(action) {
				return {
					chain: "jQuery { plugin/css > $css{action} } >|",
					action: action
				}
			});
	}

}

test( "Loading CSS" , function() {

	stop();

	pluginRules();

	dominoes("$cssTest{data/style.php?left=27&wait=1000}" , function() {
		var div = $("
").appendTo($("body"));
		strictEqual( div.css("marginLeft") , "27px" , "Margin left was set to 27px" );
		div.remove();
		start();

	})

});<commit_msg>Made $css auto-replaceable. Added remote CSS test.<commit_after>module("Plugins");

function pluginRules() {

	if ( ! dominoes.rule("jQuery") ) {
		dominoes
			.rule( "jQuery" , "http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" )
			.functor( "css{O}" , function(options) {
				return {
					chain: "../dist/dominoes-css.js > $css{options}",
					options: options
				}
			});
	}

}

test( "Loading CSS (local)" , function() {

	stop();

	pluginRules();

	dominoes("$css{data/style.php?left=27&wait=1000} jQuery >|" , function() {
		var div = $("
").appendTo($("body"));
		strictEqual( div.css("marginLeft") , "27px" , "Margin left was set to 27px" );
		div.remove();
		start();
	});

});

test( "Loading CSS (remote)" , function() {

	stop();

	pluginRules();

	dominoes("$css{http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/ui-lightness/jquery-ui.css} jQuery >|" , function() {
		var div = $("
").appendTo($("body")),
			textIndent = 1 * div.css("textIndent").replace(/px/,"");

		// Opera 16bits capping
		if ( textIndent === -32768 ) {
			strictEqual( textIndent , -32768 , "CSS has been properly applied" );
		} else {
			strictEqual( textIndent , -99999 , "CSS has been properly applied" );
		}

		div.remove();

		start();
	});

});

<|endoftext|>


<commit_before>'use strict';

let periodCriterion = require('../../../../modules/periodcriterion');
let Gettext = require('node-gettext');
let gt = new Gettext();

/**
 * Export leave requests attached to events between two dates
 * @param {apiService} service
 * @param {Date}       from    Interval selected before extraction
 * @param {Date}       to      Interval selected before extraction
 * @return {Promise}           Promised data is the array compatible with xlsx-writestream
 */
exports = module.exports = function(service, from, to) {

    const NAME      = gt.gettext('Name');
    const DEPARTMENT = gt.gettext('Department');
    const CREATEDON = gt.gettext('Created on');
    const DTSTART   = gt.gettext('From');
    const DTEND     = gt.gettext('To');
    const CONSUMED  = gt.gettext('Consumed');
    const QUANTITY  = gt.gettext('Duration');
    const STATUS    = gt.gettext('Status');

    return new Promise((resolve, reject) => {
        var findEvents = service.app.db.models.CalendarEvent.find();
        periodCriterion(findEvents, from, to);
        findEvents.where('request').exists();

        findEvents.exec((err, events) => {

            if (err) {
                return reject(err);
            }

            var find = service.app.db.models.Request.find();
            find.where('status.deleted').in([null, 'waiting']);
            find.where('events').in(events);
            find.populate('events');
            find.populate('absence.distribution');

            find.exec((err, requests) => {

                if (err) {
                    return reject(err);
                }

                let data = [];
                requests.forEach(request => {
                    let row = {};
                    row[NAME]       = request.user.name;
                    row[DEPARTMENT] = request.user.department;
                    row[CREATEDON]  = request.timeCreated;
                    row[DTSTART]    = request.events[0].dtstart;
                    row[DTEND]      = request.events[request.events.length-1].dtend;
                    row[QUANTITY]   = request.getQuantity();
                    row[STATUS]     = request.getDispStatus();
                    row[CONSUMED]   = request.getConsumedQuantity();

                    // consuption details: one column per right for elements

                    request.absence.distribution.forEach(elem => {
                        row[elem.right.name] = elem.consumedQuantity;
                    });

                    data.push(row);
                });
                resolve(data);
            });
        });

    });

};
<commit_msg>right columns, sort results<commit_after>'use strict';

let periodCriterion = require('../../../../modules/periodcriterion');
let Gettext = require('node-gettext');
let gt = new Gettext();

/**
 * Export leave requests attached to events between two dates
 * @param {apiService} service
 * @param {Date}       from    Interval selected before extraction
 * @param {Date}       to      Interval selected before extraction
 * @return {Promise}           Promised data is the array compatible with xlsx-writestream
 */
exports = module.exports = function(service, from, to) {

    const NAME      = gt.gettext('Name');
    const DEPARTMENT = gt.gettext('Department');
    const CREATEDON = gt.gettext('Created on');
    const DTSTART   = gt.gettext('From');
    const DTEND     = gt.gettext('To');
    const CONSUMED  = gt.gettext('Consumed');
    const QUANTITY  = gt.gettext('Duration');
    const STATUS    = gt.gettext('Status');

    return new Promise((resolve, reject) => {
        var findEvents = service.app.db.models.CalendarEvent.find();
        periodCriterion(findEvents, from, to);
        findEvents.where('request').exists();

        findEvents.exec((err, events) => {

            if (err) {
                return reject(err);
            }

            var find = service.app.db.models.Request.find();
            find.where('status.deleted').in([null, 'waiting']);
            find.where('events').in(events);
            find.populate('events');
            find.populate('absence.distribution');

            find.sort("user.name events.dtstart");

            find.exec((err, requests) => {

                if (err) {
                    return reject(err);
                }

                let data = [];
                let allRights = [];

                requests.forEach(request => {
                    let row = {};
                    row[NAME]       = request.user.name;
                    row[DEPARTMENT] = request.user.department;
                    row[CREATEDON]  = request.timeCreated;
                    row[DTSTART]    = request.events[0].dtstart;
                    row[DTEND]      = request.events[request.events.length-1].dtend;
                    row[QUANTITY]   = request.getQuantity();
                    row[STATUS]     = request.getDispStatus();
                    row[CONSUMED]   = request.getConsumedQuantity();

                    // consuption details: one column per right for elements

                    request.absence.distribution.forEach(elem => {
                        row[elem.right.name] = elem.consumedQuantity;
                        if (-1 === allRights.indexOf(elem.right.name)) {
                            allRights.push(elem.right.name);
                        }
                    });

                    data.push(row);
                });

                // add all rights in all rows

                data.map(row => {
                    allRights.forEach(name => {
                        if (undefined === row[name]) {
                            row[name] = 0;
                        }
                    });
                });

                resolve(data);
            });
        });

    });

};
<|endoftext|>