<commit_before>var racer = require('racer');
var $ = require('jquery');
var wams = require('wams');

var rndColor = (function() {
   var bg_colour = Math.floor(Math.random() * 16777215).toString(16);
   bg_colour = "#"+("000000" + bg_colour).slice(-6);
   return bg_colour;
}());
var rndName = (function() {
   var sampleNames = [
      'Fe', 'Thomas', 'Kirstie', 'Wynell', 'Mario', 'Aretha', 'Cherryl', 'Ta',
      'Lindy', 'Karina', 'Sacha', 'Latesha', 'Miki', 'Janel', 'Leola', 'Romeo',
      'Roderick', 'Felica', 'Ilona', 'Nila', 'Patrina', 'Wes', 'Henry', 'Elvera',
      'Karrie', 'Jacklyn', 'Alethea', 'Emogene', 'Alphonso', 'Chandra', 'Beryl',
      'Lilly', 'Georgetta', 'Darrin', 'Deane', 'Rocio', 'Charissa', 'Simona',
      'Don', 'Arianne', 'Esther', 'Leonia', 'Karma', 'Rosemarie', 'Carolyn',
      'Miriam', 'Chastity', 'Vesta', 'Christian', 'Lashaun'
   ].sort();

   return sampleNames[Math.floor(Math.random() * sampleNames.length)];
}());

function displayScreenMode(screen) {
   var screenMode = $('#mode');
   screenMode.text(screen.w + 'x' + screen.h +
      (screen.x >= 0 ? '+' + screen.x : "" + screen.x) +
      (screen.y >= 0 ? '+' + screen.y : "" + screen.y) + ':' +
      screen.s
   );
}

function extractColor(data) {
   var needToDelete = false, elem = $('#' + data.attributes.id);

   // object does not exist
   if (!elem.length) {
      needToDelete = true;

      elem = document.createElement(data.tag);
      elem.setAttribute('id', data.attributes.id);

      var body = document.getElementsByTagName('body');
      body[0].appendChild(elem);

      elem = $(elem);
   }

   var color = elem.css('background-color');
   if (needToDelete) {
      elem.remove();
   }
   return color;
}

function showElements(elements) {
   elements.forEach(function (element) {
      var elem = document.createElement(element.tag),
         attr;
      for (attr in element.attributes) {
         if (element.attributes.hasOwnProperty(attr)) {
            elem.setAttribute(attr, element.attributes[attr]);
         }
      }
      elem.innerHTML = element.innerHTML || "";

      var body = document.getElementsByTagName('body')[0];
      body.appendChild(elem);
   });
}

var MAX_CANVAS_HEIGHT = 450,
   MAX_CANVAS_WIDTH = 250,
   MIN_SCALE = 25,
   MAX_SCALE = 500,
   SCALE_DELTA = 5,
   canvas = document.getElementById('minimap'),
   ctx = canvas.getContext('2d'),
   minimapScale;

racer.ready(function(model) {
   var room = 'sharedWorkspace';
   model.subscribe(room, function() {
      window.model = model;
      // model = model.at('sharedWorkspace');

      var id = model.id();
      model.add(room + '.users', {
         id: id,
         color: rndColor,
         name: rndName
      });
      model.add(room + '.screens', {
         id: id,
         w: window.innerWidth,
         h: window.innerHeight,
         x: 0,
         y: 0,
         s: 100
      });
      model.ref('_page.me', room + '.users.' + id);
      model.ref('_page.screen', room + '.screens.' + id);
      model.ref('_page.settings', room + '.settings');

      window.onbeforeunload = function() {
         model.del(room + '.users.' + id);
         model.del(room + '.screens.' + id);
      };

      $(document).ready(function() {
         var userID = $('#userID');
         userID.text( model.get('_page.me.name') );
         userID.css({ background: model.get('_page.me.color') });
         displayScreenMode( model.get('_page.screen') );
         showElements( model.get(room + '.elements') );
      });

      $(window).resize(function() {
         model.set('_page.screen.w', window.innerWidth);
         model.set('_page.screen.h', window.innerHeight);
      });

      function rescaleElements() {
         var scale = model.get('_page.screen.s'),
            elements = model.get(room + '.elements');
         elements.forEach(function(element) {
            var elem = document.getElementById(element.attributes.id);
            if (elem) {
               elem = $(elem);
               elem.css({
                  x: element.x * scale / 100,
                  y: element.y * scale / 100,
                  width: element.w * scale / 100,
                  height: element.h * scale / 100,
                  borderRadius: +elem.css('width') / 2
               });
            }
         });
      }
      function onMouseWheel(ev) {
         var screen = model.get('_page.screen');
         if ((screen.s === MIN_SCALE && ev.wheelDeltaY > 0) ||
            (screen.s > MIN_SCALE && screen.s < MAX_SCALE && ev.whellDeltaY !== 0) ||
            (screen.s === MAX_SCALE && ev.wheelDeltaY < 0))
         {
            var delta = Math.floor(ev.wheelDeltaY / 120);
            model.increment('_page.screen.s', SCALE_DELTA * delta);
            rescaleElements(SCALE_DELTA * delta);
         }
      }
      var html = document.getElementsByTagName('html')[0];
      html.addEventListener('mousewheel', onMouseWheel, false);

      model.on('change', '_page.screen**', function() {
         displayScreenMode( model.get('_page.screen') );
      });

      function drawClients() {
         var id, screen, color,
            screens = model.get(room + '.screens'),
            clients = model.get(room + '.users'),
            drawGap = model.get('_page.settings.minimap.gapBetweenClients');

         for (id in screens) {
            if (screens.hasOwnProperty(id)) {
               screen = screens[id];
               color = clients[id].color;

               ctx.beginPath();
                  ctx.strokeStyle = color;
                  ctx.setLineDash([7, 3]);
                  if (drawGap) {
                     ctx.rect(screen.x * minimapScale + 1,
                        screen.y * minimapScale + 1,
                        screen.w * minimapScale * screen.s / 100 - 2,
                        screen.h * minimapScale * screen.s / 100 - 2);
                  } else {
                     ctx.rect(screen.x * minimapScale,
                        screen.y * minimapScale,
                        screen.w * minimapScale * screen.s / 100,
                        screen.h * minimapScale * screen.s / 100);
                  }
               ctx.stroke();
            }
         }
      }
      function drawBalls() {
         var color, x, y, r,
            elements = model.get(room + '.elements');

         elements.forEach(function(element) {
            color = extractColor(element);

            ctx.beginPath();
               ctx.fillStyle = color;
               x = element.x + element.w / 2;
               y = element.y + element.h / 2;
               r = element.w / 2;
               ctx.arc(x * minimapScale, y * minimapScale, r * minimapScale, 0, 360);
            ctx.fill();
         });
      }
      function drawMinimap() {
         canvas.width = canvas.width;
         canvas.height = canvas.height;
         ctx.translate(0.5, 0.5);
         drawClients(ctx);
         if (model.get('_page.settings.minimap.showElements')) {
            drawBalls(ctx);
         }
      }

      model.on('change', room + '.workspace', function(value, previous, passed) {
         if (!value.w || !value.h) { return; }

         var w, h;

         if (MAX_CANVAS_HEIGHT / MAX_CANVAS_WIDTH < value.h / value.w) {
            minimapScale = MAX_CANVAS_HEIGHT / value.h;
            h = MAX_CANVAS_HEIGHT;
            w = value.w * minimapScale;
         } else {
            minimapScale = MAX_CANVAS_WIDTH / value.w;
            h = value.h * minimapScale;
            w = MAX_CANVAS_WIDTH;
         }

         canvas.width = w;
         canvas.height = h;

         drawMinimap();
      });

      model.on('change', room + '.elements**', function() {
         drawMinimap();
      });
      model.on('change', room + '.minimap**', function() {
         drawMinimap();
      });
   });
});

$('#rst_wrkspc_btn').click(function() {
   model.set('_page.me.screen.x', 0);
   model.set('_page.me.screen.y', 0);
   model.set('_page.me.screen.w', window.innerWidth);
   model.set('_page.me.screen.h', window.innerHeight);
   model.set('_page.me.screen.s', 100);
})

<commit_msg>feat(clone): function to deep clone objects and arrays<commit_after>var racer = require('racer');
var $ = require('jquery');
var wams = require('wams');

var rndColor = (function() {
   var bg_colour = Math.floor(Math.random() * 16777215).toString(16);
   bg_colour = "#"+("000000" + bg_colour).slice(-6);
   return bg_colour;
}());
var rndName = (function() {
   var sampleNames = [
      'Fe', 'Thomas', 'Kirstie', 'Wynell', 'Mario', 'Aretha', 'Cherryl', 'Ta',
      'Lindy', 'Karina', 'Sacha', 'Latesha', 'Miki', 'Janel', 'Leola', 'Romeo',
      'Roderick', 'Felica', 'Ilona', 'Nila', 'Patrina', 'Wes', 'Henry', 'Elvera',
      'Karrie', 'Jacklyn', 'Alethea', 'Emogene', 'Alphonso', 'Chandra', 'Beryl',
      'Lilly', 'Georgetta', 'Darrin', 'Deane', 'Rocio', 'Charissa', 'Simona',
      'Don', 'Arianne', 'Esther', 'Leonia', 'Karma', 'Rosemarie', 'Carolyn',
      'Miriam', 'Chastity', 'Vesta', 'Christian', 'Lashaun'
   ].sort();

   return sampleNames[Math.floor(Math.random() * sampleNames.length)];
}());

function clone(obj) {
   // Handle the 2 simple types, and null or undefined
   if (null == obj || "object" != typeof obj) return obj;

   // Handle Array
   if (obj instanceof Array) {
      var copy = [];
      for (var i = 0, len = obj.length; i < len; i++) {
         copy[i] = clone(obj[i]);
      }
      return copy;
   }

   // Handle Object
   if (obj instanceof Object) {
      var copy = {};
      for (var attr in obj) {
         if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
      }
      return copy;
   }

   throw new Error("Unable to copy obj! Its type isn't supported.");
}

function displayScreenMode(screen) {
   var screenMode = $('#mode');
   screenMode.text(screen.w + 'x' + screen.h +
      (screen.x >= 0 ? '+' + screen.x : "" + screen.x) +
      (screen.y >= 0 ? '+' + screen.y : "" + screen.y) + ':' +
      screen.s
   );
}

function extractColor(data) {
   var needToDelete = false, elem = $('#' + data.attributes.id);

   // object does not exist
   if (!elem.length) {
      needToDelete = true;

      elem = document.createElement(data.tag);
      elem.setAttribute('id', data.attributes.id);

      var body = document.getElementsByTagName('body');
      body[0].appendChild(elem);

      elem = $(elem);
   }

   var color = elem.css('background-color');
   if (needToDelete) {
      elem.remove();
   }
   return color;
}

function showElements(elements) {
   elements.forEach(function (element) {
      var elem = document.createElement(element.tag),
         attr;
      for (attr in element.attributes) {
         if (element.attributes.hasOwnProperty(attr)) {
            elem.setAttribute(attr, element.attributes[attr]);
         }
      }
      elem.innerHTML = element.innerHTML || "";

      var body = document.getElementsByTagName('body')[0];
      body.appendChild(elem);
   });
}

var MAX_CANVAS_HEIGHT = 450,
   MAX_CANVAS_WIDTH = 250,
   MIN_SCALE = 25,
   MAX_SCALE = 500,
   SCALE_DELTA = 5,
   canvas = document.getElementById('minimap'),
   ctx = canvas.getContext('2d'),
   minimapScale;

racer.ready(function(model) {
   var room = 'sharedWorkspace';
   model.subscribe(room, function() {
      window.model = model;
      // model = model.at('sharedWorkspace');

      var id = model.id();
      model.add(room + '.users', {
         id: id,
         color: rndColor,
         name: rndName
      });
      model.add(room + '.screens', {
         id: id,
         w: window.innerWidth,
         h: window.innerHeight,
         x: 0,
         y: 0,
         s: 100
      });
      model.ref('_page.me', room + '.users.' + id);
      model.ref('_page.screen', room + '.screens.' + id);
      model.ref('_page.settings', room + '.settings');

      window.onbeforeunload = function() {
         model.del(room + '.users.' + id);
         model.del(room + '.screens.' + id);
      };

      $(document).ready(function() {
         var userID = $('#userID');
         userID.text( model.get('_page.me.name') );
         userID.css({ background: model.get('_page.me.color') });
         displayScreenMode( model.get('_page.screen') );
         showElements( model.get(room + '.elements') );
      });

      $(window).resize(function() {
         model.set('_page.screen.w', window.innerWidth);
         model.set('_page.screen.h', window.innerHeight);
      });

      function rescaleElements() {
         var scale = model.get('_page.screen.s'),
            elements = model.get(room + '.elements');
         elements.forEach(function(element) {
            var elem = document.getElementById(element.attributes.id);
            if (elem) {
               elem = $(elem);
               elem.css({
                  x: element.x * scale / 100,
                  y: element.y * scale / 100,
                  width: element.w * scale / 100,
                  height: element.h * scale / 100,
                  borderRadius: +elem.css('width') / 2
               });
            }
         });
      }
      function onMouseWheel(ev) {
         var screen = model.get('_page.screen');
         if ((screen.s === MIN_SCALE && ev.wheelDeltaY > 0) ||
            (screen.s > MIN_SCALE && screen.s < MAX_SCALE && ev.whellDeltaY !== 0) ||
            (screen.s === MAX_SCALE && ev.wheelDeltaY < 0))
         {
            var delta = Math.floor(ev.wheelDeltaY / 120);
            model.increment('_page.screen.s', SCALE_DELTA * delta);
            rescaleElements(SCALE_DELTA * delta);
         }
      }
      var html = document.getElementsByTagName('html')[0];
      html.addEventListener('mousewheel', onMouseWheel, false);

      model.on('change', '_page.screen**', function() {
         displayScreenMode( model.get('_page.screen') );
      });

      function drawClients() {
         var id, screen, color,
            screens = model.get(room + '.screens'),
            clients = model.get(room + '.users'),
            drawGap = model.get('_page.settings.minimap.gapBetweenClients');

         for (id in screens) {
            if (screens.hasOwnProperty(id)) {
               screen = screens[id];
               color = clients[id].color;

               ctx.beginPath();
                  ctx.strokeStyle = color;
                  ctx.setLineDash([7, 3]);
                  if (drawGap) {
                     ctx.rect(screen.x * minimapScale + 1,
                        screen.y * minimapScale + 1,
                        screen.w * minimapScale * screen.s / 100 - 2,
                        screen.h * minimapScale * screen.s / 100 - 2);
                  } else {
                     ctx.rect(screen.x * minimapScale,
                        screen.y * minimapScale,
                        screen.w * minimapScale * screen.s / 100,
                        screen.h * minimapScale * screen.s / 100);
                  }
               ctx.stroke();
            }
         }
      }
      function drawBalls() {
         var color, x, y, r,
            elements = model.get(room + '.elements');

         elements.forEach(function(element) {
            color = extractColor(element);

            ctx.beginPath();
               ctx.fillStyle = color;
               x = element.x + element.w / 2;
               y = element.y + element.h / 2;
               r = element.w / 2;
               ctx.arc(x * minimapScale, y * minimapScale, r * minimapScale, 0, 360);
            ctx.fill();
         });
      }
      function drawMinimap() {
         canvas.width = canvas.width;
         canvas.height = canvas.height;
         ctx.translate(0.5, 0.5);
         drawClients(ctx);
         if (model.get('_page.settings.minimap.showElements')) {
            drawBalls(ctx);
         }
      }

      model.on('change', room + '.workspace', function(value, previous, passed) {
         if (!value.w || !value.h) { return; }

         var w, h;

         if (MAX_CANVAS_HEIGHT / MAX_CANVAS_WIDTH < value.h / value.w) {
            minimapScale = MAX_CANVAS_HEIGHT / value.h;
            h = MAX_CANVAS_HEIGHT;
            w = value.w * minimapScale;
         } else {
            minimapScale = MAX_CANVAS_WIDTH / value.w;
            h = value.h * minimapScale;
            w = MAX_CANVAS_WIDTH;
         }

         canvas.width = w;
         canvas.height = h;

         drawMinimap();
      });

      model.on('change', room + '.elements**', function() {
         drawMinimap();
      });
      model.on('change', room + '.minimap**', function() {
         drawMinimap();
      });
   });
});

$('#rst_wrkspc_btn').click(function() {
   model.set('_page.me.screen.x', 0);
   model.set('_page.me.screen.y', 0);
   model.set('_page.me.screen.w', window.innerWidth);
   model.set('_page.me.screen.h', window.innerHeight);
   model.set('_page.me.screen.s', 100);
})

<|endoftext|>


<commit_before>var httpServReqListenerProxy = require("./http-server-request-listener-proxy");
var URL = require("url");
var mori = require("mori");
var faye = require("faye");
var when = require("when");
var when_pipeline = require("when/pipeline");
var rampResources = require("ramp-resources");

var rampSlave = require("./ramp-slave");
var rampSession = require("./ramp-session");
var homeless = require("./homeless");
var moriHashMapToObj = homeless.moriHashMapToObj;

function writeJson(res, data) {
    res.setHeader("Content-Type", "application/json");
    res.end(JSON.stringify(data));
}

function concatBody(req, res) {
    var deferred = when.defer();
    var body = "";
    req.setEncoding("utf8");
    req.on("data", function (chunk) { body += chunk; });
    req.on("end", function () {
        try {
            deferred.resolve(JSON.parse(body));
        } catch (e) { deferred.reject(e); }
    })
    return deferred.promise;
};

function listSlaves(rampServer, req, res) {
    writeJson(res, mori.into_array(
        mori.map(
            rampSlave.toPublicValue,
            mori.get(rampServer, "atoms").activeSlaves)))
};

function performCapture(rampServer, req, res) {
    var slave = rampSlave.createSlave(mori.hash_map(
        "userAgent", req.headers["user-agent"],
        "header", mori.get(rampServer, "header")
    ));

    var atoms = mori.get(rampServer, "atoms");

    atoms.allSlaves = mori.assoc(atoms.allSlaves, mori.get(slave, "id"), slave);
    atoms.loadingSlaves = mori.conj(atoms.loadingSlaves, slave);
    var slaveMaxLoadTime = new Date().getTime() + mori.get(rampServer, "slaveLoadTimeHint")
    atoms.slaveHeartbeats = mori.assoc(atoms.slaveHeartbeats, mori.get(slave, "id"), slaveMaxLoadTime);

    mori.get(rampServer, "resourceMiddleware").mount(
        mori.get(slave, "chainsPath"),
        mori.get(slave, "chainsResourceSet"));

    res.writeHead(302, {"Location": mori.get(slave, "chainsPath")})
    res.end();
};

function createSession(rampServer, req, res) {
    var atoms = mori.get(rampServer, "atoms");

    if (atoms.currentSession) {
        res.writeHead(409);
        res.end("A session is already in progress.");
        return;
    }

    when_pipeline([
        mori.partial(concatBody, req, res),
        function (resourceSetValue) {
            var deferred = when.defer();
            rampResources.deserialize(resourceSetValue).then(
                function (resourceSet) {
                    // For some reason, resolving resourceSet directly breaks
                    // when so it doesn't actually resolve. Wrapping it in an
                    // object seems to help.
                    deferred.resolve({resourceSet: resourceSet});
                },
                deferred.reject
            );
            return deferred.promise;
        },
        function (e) {
            var deferred = when.defer();
            // Same as above. Fails if passing resourceSet directly.
            mori.get(rampServer, "resourceCache").inflate(e.resourceSet).then(function (resourceSet) {
                deferred.resolve({resourceSet: resourceSet});
            }, deferred.reject)
            return deferred.promise;
        },
    ]).then(function (e) {
        var session = rampSession.createSession(e.resourceSet)
        atoms.currentSession = session;
        writeJson(res, rampSession.toPublicValue(session));
    }, function () {
        res.writeHead(500);
        res.end();
    });
}

function initializeSession(rampServer, req, res) {
    var atoms = mori.get(rampServer, "atoms");
    var activeSlaves = atoms.activeSlaves;

    if (mori.is_empty(activeSlaves)) {
        mori.get(rampServer, "atoms").currentSession = null;
        res.writeHead(418);
        res.end("Cannot initialize session, no slaves are captured.");
        return;
    }

    var session = atoms.currentSession = mori.assoc(atoms.currentSession, "slaves", activeSlaves);

    mori.get(rampServer, "resourceMiddleware").mount(
        mori.get(session, "resourcesPath"),
        mori.get(session, "resourceSet"));

    mori.each(activeSlaves, mori.partial(
        rampSlave.initializeSession,
        mori.get(rampServer, "fayeClient"),
        session));

    writeJson(res, {
        session: rampSession.toPublicValue(session),
        slaves: mori.into_array(mori.map(rampSlave.toPublicValue, activeSlaves))
    });
};

function endSession(rampServer, req, res) {
    var session = mori.get(rampServer, "atoms").currentSession;

    if (session) {
        mori.get(rampServer, "resourceMiddleware").unmount(mori.get(session, "resourcesPath"));
        delete mori.get(rampServer, "atoms").currentSession;
        mori.each(mori.get(session, "slaves"), mori.partial(rampSlave.endSession, mori.get(rampServer, "fayeClient")));
        res.writeHead(200)
        res.end();
    } else {
        res.writeHead(404);
        res.end("No session found, cannot end.");
    }
};

function getCurrentSession(rampServer, req, res) {
    var session = mori.get(rampServer, "atoms").currentSession;

    if (session) {
        writeJson(res, rampSession.toPublicValue(session));
    } else {
        res.writeHead(404);
        res.end("No session currently running.");
    }
};

function showSlaveIdle(rampServer, req, res) {
    res.end("Idle...");
}

function listResourceCache(rampServer, req, res) {
    writeJson(res, mori.get(rampServer, "resourceCache").resourceVersions());
};

function purgeResourceCache(rampServer, req, res) {
    mori.get(rampServer, "resourceCache").purgeAll();
    res.end();
};

function respond(rampServer, req, res) {
    var atoms = mori.get(rampServer, "atoms");
    var url = URL.parse(req.url);

    if (req.method === "GET" && url.path === "/slaves") {
        listSlaves(rampServer, req, res);
        return true;
    }

    if (req.method === "GET" && url.path === "/slave_idle") {
        showSlaveIdle(rampServer, req, res);
        return true;
    }

    if (req.method === "GET" && url.path === "/capture") {
        performCapture(rampServer, req, res)
        return true;
    }

    if (req.method === "POST" && url.path === "/sessions") {
        createSession(rampServer, req, res)
        return true;
    }

    if (req.method === "GET" && url.path === "/current_session") {
        getCurrentSession(rampServer, req, res)
        return true;
    }

    if (url.path === "/resources") {
        if (req.method === "GET") {
            listResourceCache(rampServer, req, res);
            return true;
        }

        if (req.method === "DELETE") {
            purgeResourceCache(rampServer, req, res);
            return true;
        }
    }

    if (atoms.currentSession) {
        var match = rampSession.matchPathForSession(atoms.currentSession, url.path);
        if (match) {
            var segment = match[1];

            if (req.method === "POST" && segment === "/initialize") {
                initializeSession(rampServer, req ,res);
                return true;
            }

            if (req.method === "DELETE" && segment === "") {
                endSession(rampServer, req, res);
                return true;
            }
        }
    }

    var match = url.path.match(/^\/slaves\/([^\/]+)\/chains$/);
    if (match) {
        var slaveId = match[1];

        var slave = mori.first(
            mori.filter(
                function (slave) { return mori.get(slave, "id") === slaveId; },
                atoms.loadingSlaves));

        if (slave) {
            // Don't return - continue as normal, but mark as loaded.
            atoms.loadingSlaves = mori.disj(mori.get(rampServer, "atoms").loadingSlaves, slave);
        } else {
            // Slave is already loaded, create a new one.
            performCapture(rampServer, req, res);
            return true;
        }
    }

    if (mori.get(rampServer, "resourceMiddleware").respond(req, res)) return true;
}

function attach(rampServer, httpServer) {
    httpServReqListenerProxy.attach(httpServer, mori.partial(respond, rampServer));
    mori.get(rampServer, "fayeAdapter").attach(httpServer);
}

function removeSlave(rampServer, slave) {
    var atoms = mori.get(rampServer, "atoms");
    atoms.slaveHeartbeats = mori.dissoc(atoms.slaveHeartbeats, mori.get(slave, "id"));
    atoms.allSlaves = mori.dissoc(atoms.allSlaves, mori.get(slave, "id"));
    atoms.activeSlaves = mori.disj(atoms.activeSlaves, slave);
    atoms.loadingSlaves = mori.disj(atoms.loadingSlaves, slave);

    mori.get(rampServer, "resourceMiddleware").unmount(mori.get(slave, "chainsPath"));
};

function checkSlaveTimeouts(rampServer) {
    var atoms = mori.get(rampServer, "atoms");
    var timeout = mori.get(rampServer, "slaveTimeoutHint");

    setTimeout(function () {
        var now = new Date().getTime();

        var deadSlaves = mori.filter(function (heartBeat) {
            var slaveId = mori.get(heartBeat, 0);
            var lastSeen = mori.get(heartBeat, 1);

            return (now - lastSeen) >= timeout;
        }, atoms.slaveHeartbeats);

        mori.each(deadSlaves, function (heartBeat) {
            var slaveId = mori.get(heartBeat, 0);
            var lastSeen = mori.get(heartBeat, 1);

            var slave = mori.get(atoms.allSlaves, slaveId);
            removeSlave(rampServer, slave);
        });

        checkSlaveTimeouts(rampServer);
    }, 500);
};

function onSlaveDisconnect(rampServer, e) {
    var atoms = mori.get(rampServer, "atoms");
    var slave = mori.get(atoms.allSlaves, e.slaveId);
    removeSlave(rampServer, slave);
};

function onSlaveReady(rampServer, e) {
    var atoms = mori.get(rampServer, "atoms");
    var slave = mori.get(atoms.allSlaves, e.slaveId);
    atoms.activeSlaves = mori.conj(atoms.activeSlaves, slave);
};

function onSlaveHeartbeat(rampServer, e) {
    var atoms = mori.get(rampServer, "atoms");
    var slaveId = e.slaveId;

    if (mori.has_key(atoms.allSlaves, slaveId)) {
        atoms.slaveHeartbeats = mori.assoc(atoms.slaveHeartbeats, slaveId, new Date().getTime());
    } else {
        mori.get(rampServer, "fayeClient").publish("/slave/" + slaveId + "/recapture", {});
    }
};

function getActiveSlaves(rampServer) {
    var atoms = mori.get(rampServer, "atoms");
    return mori.into_array(mori.map(rampSlave.toPublicValue, atoms.activeSlaves));
}

module.exports.createRampServer = function (opts) {
    var fayeAdapter = new faye.NodeAdapter({
        mount: "/messaging"
    });
    var atoms = {
        allSlaves: mori.hash_map(),
        slaveHeartbeats: mori.hash_map(),
        activeSlaves:  mori.set(),
        loadingSlaves: mori.set()
    };

    var rampServer = mori.hash_map(
        "atoms", atoms,
        "resourceMiddleware", rampResources.createMiddleware(),
        "resourceCache", rampResources.createCache(),
        "fayeAdapter", fayeAdapter,
        "fayeClient", fayeAdapter.getClient(),
        "slaveTimeoutHint", opts.slaveTimeoutHint || 10000,
        "slaveLoadTimeHint", opts.slaveLoadTimeHint || 10000
    );

    fayeAdapter.getClient().subscribe("/slave_ready", mori.partial(onSlaveReady, rampServer));
    fayeAdapter.getClient().subscribe("/slave_disconnect", mori.partial(onSlaveDisconnect, rampServer));
    fayeAdapter.getClient().subscribe("/slave_heartbeat", mori.partial(onSlaveHeartbeat, rampServer));

    checkSlaveTimeouts(rampServer);

    return {
        getSlaves: mori.partial(getActiveSlaves, rampServer),
        attach: mori.partial(attach, rampServer)
    }
};
<commit_msg>We don't need to check timeouts until we attach.<commit_after>var httpServReqListenerProxy = require("./http-server-request-listener-proxy");
var URL = require("url");
var mori = require("mori");
var faye = require("faye");
var when = require("when");
var when_pipeline = require("when/pipeline");
var rampResources = require("ramp-resources");

var rampSlave = require("./ramp-slave");
var rampSession = require("./ramp-session");
var homeless = require("./homeless");
var moriHashMapToObj = homeless.moriHashMapToObj;

function writeJson(res, data) {
    res.setHeader("Content-Type", "application/json");
    res.end(JSON.stringify(data));
}

function concatBody(req, res) {
    var deferred = when.defer();
    var body = "";
    req.setEncoding("utf8");
    req.on("data", function (chunk) { body += chunk; });
    req.on("end", function () {
        try {
            deferred.resolve(JSON.parse(body));
        } catch (e) { deferred.reject(e); }
    })
    return deferred.promise;
};

function listSlaves(rampServer, req, res) {
    writeJson(res, mori.into_array(
        mori.map(
            rampSlave.toPublicValue,
            mori.get(rampServer, "atoms").activeSlaves)))
};

function performCapture(rampServer, req, res) {
    var slave = rampSlave.createSlave(mori.hash_map(
        "userAgent", req.headers["user-agent"],
        "header", mori.get(rampServer, "header")
    ));

    var atoms = mori.get(rampServer, "atoms");

    atoms.allSlaves = mori.assoc(atoms.allSlaves, mori.get(slave, "id"), slave);
    atoms.loadingSlaves = mori.conj(atoms.loadingSlaves, slave);
    var slaveMaxLoadTime = new Date().getTime() + mori.get(rampServer, "slaveLoadTimeHint")
    atoms.slaveHeartbeats = mori.assoc(atoms.slaveHeartbeats, mori.get(slave, "id"), slaveMaxLoadTime);

    mori.get(rampServer, "resourceMiddleware").mount(
        mori.get(slave, "chainsPath"),
        mori.get(slave, "chainsResourceSet"));

    res.writeHead(302, {"Location": mori.get(slave, "chainsPath")})
    res.end();
};

function createSession(rampServer, req, res) {
    var atoms = mori.get(rampServer, "atoms");

    if (atoms.currentSession) {
        res.writeHead(409);
        res.end("A session is already in progress.");
        return;
    }

    when_pipeline([
        mori.partial(concatBody, req, res),
        function (resourceSetValue) {
            var deferred = when.defer();
            rampResources.deserialize(resourceSetValue).then(
                function (resourceSet) {
                    // For some reason, resolving resourceSet directly breaks
                    // when so it doesn't actually resolve. Wrapping it in an
                    // object seems to help.
                    deferred.resolve({resourceSet: resourceSet});
                },
                deferred.reject
            );
            return deferred.promise;
        },
        function (e) {
            var deferred = when.defer();
            // Same as above. Fails if passing resourceSet directly.
            mori.get(rampServer, "resourceCache").inflate(e.resourceSet).then(function (resourceSet) {
                deferred.resolve({resourceSet: resourceSet});
            }, deferred.reject)
            return deferred.promise;
        },
    ]).then(function (e) {
        var session = rampSession.createSession(e.resourceSet)
        atoms.currentSession = session;
        writeJson(res, rampSession.toPublicValue(session));
    }, function () {
        res.writeHead(500);
        res.end();
    });
}

function initializeSession(rampServer, req, res) {
    var atoms = mori.get(rampServer, "atoms");
    var activeSlaves = atoms.activeSlaves;

    if (mori.is_empty(activeSlaves)) {
        mori.get(rampServer, "atoms").currentSession = null;
        res.writeHead(418);
        res.end("Cannot initialize session, no slaves are captured.");
        return;
    }

    var session = atoms.currentSession = mori.assoc(atoms.currentSession, "slaves", activeSlaves);

    mori.get(rampServer, "resourceMiddleware").mount(
        mori.get(session, "resourcesPath"),
        mori.get(session, "resourceSet"));

    mori.each(activeSlaves, mori.partial(
        rampSlave.initializeSession,
        mori.get(rampServer, "fayeClient"),
        session));

    writeJson(res, {
        session: rampSession.toPublicValue(session),
        slaves: mori.into_array(mori.map(rampSlave.toPublicValue, activeSlaves))
    });
};

function endSession(rampServer, req, res) {
    var session = mori.get(rampServer, "atoms").currentSession;

    if (session) {
        mori.get(rampServer, "resourceMiddleware").unmount(mori.get(session, "resourcesPath"));
        delete mori.get(rampServer, "atoms").currentSession;
        mori.each(mori.get(session, "slaves"), mori.partial(rampSlave.endSession, mori.get(rampServer, "fayeClient")));
        res.writeHead(200)
        res.end();
    } else {
        res.writeHead(404);
        res.end("No session found, cannot end.");
    }
};

function getCurrentSession(rampServer, req, res) {
    var session = mori.get(rampServer, "atoms").currentSession;

    if (session) {
        writeJson(res, rampSession.toPublicValue(session));
    } else {
        res.writeHead(404);
        res.end("No session currently running.");
    }
};

function showSlaveIdle(rampServer, req, res) {
    res.end("Idle...");
}

function listResourceCache(rampServer, req, res) {
    writeJson(res, mori.get(rampServer, "resourceCache").resourceVersions());
};

function purgeResourceCache(rampServer, req, res) {
    mori.get(rampServer, "resourceCache").purgeAll();
    res.end();
};

function respond(rampServer, req, res) {
    var atoms = mori.get(rampServer, "atoms");
    var url = URL.parse(req.url);

    if (req.method === "GET" && url.path === "/slaves") {
        listSlaves(rampServer, req, res);
        return true;
    }

    if (req.method === "GET" && url.path === "/slave_idle") {
        showSlaveIdle(rampServer, req, res);
        return true;
    }

    if (req.method === "GET" && url.path === "/capture") {
        performCapture(rampServer, req, res)
        return true;
    }

    if (req.method === "POST" && url.path === "/sessions") {
        createSession(rampServer, req, res)
        return true;
    }

    if (req.method === "GET" && url.path === "/current_session") {
        getCurrentSession(rampServer, req, res)
        return true;
    }

    if (url.path === "/resources") {
        if (req.method === "GET") {
            listResourceCache(rampServer, req, res);
            return true;
        }

        if (req.method === "DELETE") {
            purgeResourceCache(rampServer, req, res);
            return true;
        }
    }

    if (atoms.currentSession) {
        var match = rampSession.matchPathForSession(atoms.currentSession, url.path);
        if (match) {
            var segment = match[1];

            if (req.method === "POST" && segment === "/initialize") {
                initializeSession(rampServer, req ,res);
                return true;
            }

            if (req.method === "DELETE" && segment === "") {
                endSession(rampServer, req, res);
                return true;
            }
        }
    }

    var match = url.path.match(/^\/slaves\/([^\/]+)\/chains$/);
    if (match) {
        var slaveId = match[1];

        var slave = mori.first(
            mori.filter(
                function (slave) { return mori.get(slave, "id") === slaveId; },
                atoms.loadingSlaves));

        if (slave) {
            // Don't return - continue as normal, but mark as loaded.
            atoms.loadingSlaves = mori.disj(mori.get(rampServer, "atoms").loadingSlaves, slave);
        } else {
            // Slave is already loaded, create a new one.
            performCapture(rampServer, req, res);
            return true;
        }
    }

    if (mori.get(rampServer, "resourceMiddleware").respond(req, res)) return true;
}

function attach(rampServer, httpServer) {
    httpServReqListenerProxy.attach(httpServer, mori.partial(respond, rampServer));
    mori.get(rampServer, "fayeAdapter").attach(httpServer);
    checkSlaveTimeouts(rampServer);
}

function removeSlave(rampServer, slave) {
    var atoms = mori.get(rampServer, "atoms");
    atoms.slaveHeartbeats = mori.dissoc(atoms.slaveHeartbeats, mori.get(slave, "id"));
    atoms.allSlaves = mori.dissoc(atoms.allSlaves, mori.get(slave, "id"));
    atoms.activeSlaves = mori.disj(atoms.activeSlaves, slave);
    atoms.loadingSlaves = mori.disj(atoms.loadingSlaves, slave);

    mori.get(rampServer, "resourceMiddleware").unmount(mori.get(slave, "chainsPath"));
};

function checkSlaveTimeouts(rampServer) {
    var atoms = mori.get(rampServer, "atoms");
    var timeout = mori.get(rampServer, "slaveTimeoutHint");

    setTimeout(function () {
        var now = new Date().getTime();

        var deadSlaves = mori.filter(function (heartBeat) {
            var slaveId = mori.get(heartBeat, 0);
            var lastSeen = mori.get(heartBeat, 1);

            return (now - lastSeen) >= timeout;
        }, atoms.slaveHeartbeats);

        mori.each(deadSlaves, function (heartBeat) {
            var slaveId = mori.get(heartBeat, 0);
            var lastSeen = mori.get(heartBeat, 1);

            var slave = mori.get(atoms.allSlaves, slaveId);
            removeSlave(rampServer, slave);
        });

        checkSlaveTimeouts(rampServer);
    }, 500);
};

function onSlaveDisconnect(rampServer, e) {
    var atoms = mori.get(rampServer, "atoms");
    var slave = mori.get(atoms.allSlaves, e.slaveId);
    removeSlave(rampServer, slave);
};

function onSlaveReady(rampServer, e) {
    var atoms = mori.get(rampServer, "atoms");
    var slave = mori.get(atoms.allSlaves, e.slaveId);
    atoms.activeSlaves = mori.conj(atoms.activeSlaves, slave);
};

function onSlaveHeartbeat(rampServer, e) {
    var atoms = mori.get(rampServer, "atoms");
    var slaveId = e.slaveId;

    if (mori.has_key(atoms.allSlaves, slaveId)) {
        atoms.slaveHeartbeats = mori.assoc(atoms.slaveHeartbeats, slaveId, new Date().getTime());
    } else {
        mori.get(rampServer, "fayeClient").publish("/slave/" + slaveId + "/recapture", {});
    }
};

function getActiveSlaves(rampServer) {
    var atoms = mori.get(rampServer, "atoms");
    return mori.into_array(mori.map(rampSlave.toPublicValue, atoms.activeSlaves));
}

module.exports.createRampServer = function (opts) {
    var fayeAdapter = new faye.NodeAdapter({
        mount: "/messaging"
    });
    var atoms = {
        allSlaves: mori.hash_map(),
        slaveHeartbeats: mori.hash_map(),
        activeSlaves:  mori.set(),
        loadingSlaves: mori.set()
    };

    var rampServer = mori.hash_map(
        "atoms", atoms,
        "resourceMiddleware", rampResources.createMiddleware(),
        "resourceCache", rampResources.createCache(),
        "fayeAdapter", fayeAdapter,
        "fayeClient", fayeAdapter.getClient(),
        "slaveTimeoutHint", opts.slaveTimeoutHint || 10000,
        "slaveLoadTimeHint", opts.slaveLoadTimeHint || 10000
    );

    fayeAdapter.getClient().subscribe("/slave_ready", mori.partial(onSlaveReady, rampServer));
    fayeAdapter.getClient().subscribe("/slave_disconnect", mori.partial(onSlaveDisconnect, rampServer));
    fayeAdapter.getClient().subscribe("/slave_heartbeat", mori.partial(onSlaveHeartbeat, rampServer));

    return {
        getSlaves: mori.partial(getActiveSlaves, rampServer),
        attach: mori.partial(attach, rampServer)
    }
};
<|endoftext|>


<commit_before>'use strict';

var app = require('../..');
var request = require('supertest');

var newSection;

describe('Section API:', function() {

  describe('GET /api/sections', function() {
    var sections;

    beforeEach(function(done) {
      request(app)
        .get('/api/sections')
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) {
            return done(err);
          }
          sections = res.body;
          done();
        });
    });

    it('should respond with JSON array', function() {
      expect(sections).to.be.instanceOf(Array);
    });

  });

  describe('POST /api/sections', function() {
    beforeEach(function(done) {
      request(app)
        .post('/api/sections')
        .send({
          sectionNumbers: [1,2,3]
        })
        .expect(201)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) {
            return done(err);
          }
          newSection = res.body;
          done();
        });
    });

    it('should respond with the newly created section', function() {
      assert.deepEqual(newSection.sectionNumbers, [1,2,3]);
    });

  });

  describe('GET /api/sections/:id', function() {
    var section;

    beforeEach(function(done) {
      request(app)
        .get('/api/sections/' + newSection._id)
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) {
            return done(err);
          }
          section = res.body;
          done();
        });
    });

    afterEach(function() {
      section = {};
    });

    it('should respond with the requested section', function() {
      assert.deepEqual(section.sectionNumbers, [1,2,3]);
    });

  });

  describe('PUT /api/sections/:id', function() {
    var updatedSection

    beforeEach(function(done) {
      request(app)
        .put('/api/sections/' + newSection._id)
        .send({
          sectionNumbers: [1,3,5]
        })
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) {
            return done(err);
          }
          updatedSection = res.body;
          done();
        });
    });

    afterEach(function() {
      updatedSection = {};
    });

    it('should respond with the updated section', function() {
      assert.deepEqual(updatedSection.sectionNumbers, [1,3,5]);
    });

  });

  describe('DELETE /api/sections/:id', function() {

    it('should respond with 204 on successful removal', function(done) {
      request(app)
        .delete('/api/sections/' + newSection._id)
        .expect(204)
        .end(function(err, res) {
          if (err) {
            return done(err);
          }
          done();
        });
    });

    it('should respond with 404 when section does not exist', function(done) {
      request(app)
        .delete('/api/sections/' + newSection._id)
        .expect(404)
        .end(function(err, res) {
          if (err) {
            return done(err);
          }
          done();
        });
    });

  });

});
<commit_msg>fixed old section tests<commit_after>'use strict';

var app = require('../..');
var request = require('supertest');
var auth = require("../../auth/local/test.integration");
var superwith = require("../superwith.integration");

var seed = require('../../config/seed');
var exampleSection = seed.exampleSection;

var newSection;

describe('Section API:', function() {

  describe('GET /api/sections', function() {
    var sections;

    beforeEach(function(done) {
      request(app)
        .get('/api/sections')
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) {
            return done(err);
          }
          sections = res.body;
          done();
        });
    });

    it('should respond with JSON array', function() {
      expect(sections).to.be.instanceOf(Array);
    });

  });

  describe('POST /api/sections', function() {
    beforeEach(function(done) {
      auth.instructor.request(app)
        .post('/api/sections')
        .send({
          sectionNumbers: [1,2,3]
        })
        .expect(201)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) {
            return done(err);
          }
          newSection = res.body;
          done();
        });
    });

    it('should respond with the newly created section', function() {
      assert.deepEqual(newSection.sectionNumbers, [1,2,3]);
    });

  });

  describe('GET /api/sections/:id', function() {
    var section;

    beforeEach(function(done) {
      request(app)
        .get('/api/sections/' + newSection._id)
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) {
            return done(err);
          }
          section = res.body;
          done();
        });
    });

    afterEach(function() {
      section = {};
    });

    it('should respond with the requested section', function() {
      assert.deepEqual(section.sectionNumbers, [1,2,3]);
    });

  });

  describe('PUT /api/sections/:id', function() {
    var updatedSection

    beforeEach(function(done) {
      auth.instructor.request(app)
        .put('/api/sections/' + newSection._id)
        .send({
          sectionNumbers: [1,3,5]
        })
        .expect(200)
        .expect('Content-Type', /json/)
        .end(function(err, res) {
          if (err) {
            return done(err);
          }
          updatedSection = res.body;
          done();
        });
    });

    afterEach(function() {
      updatedSection = {};
    });

    it('should respond with the updated section', function() {
      assert.deepEqual(updatedSection.sectionNumbers, [1,3,5]);
    });

  });

  describe('DELETE /api/sections/:id', function() {

    it('should respond with 204 on successful removal', function(done) {
      auth.instructor.request(app)
        .delete('/api/sections/' + newSection._id)
        .expect(204)
        .end(function(err, res) {
          if (err) {
            return done(err);
          }
          done();
        });
    });

    it('should respond with 404 when section does not exist', function(done) {
      request(app)
        .get('/api/sections/' + newSection._id)
        .expect(404)
        .end(function(err, res) {
          if (err) {
            return done(err);
          }
          done();
        });
    });

  });

});
<|endoftext|>


<commit_before>const logger = require('../../logger');
const { Kommission } = require('../models/kommission');
const { createUserError } = require('../../utils');

/**
 * Return all kommissions of the app.
 *
 * @returns {Promise<Array>} Kommissions
 */
async function getAllKommissions() {

    logger.verbose('Kommission service: get all kommissions');
    return await Kommission.findAll();
}

/**
 * Create a kommission.
 *
 * @param newKommission {Kommission} partial kommission
 * @return {Promise<Kommission|Errors.ValidationError>} The created kommission with its id
 */
async function createKommission(newKommission) {

    logger.verbose('Kommission service: creating a new kommission named %s %s', newKommission.firstName, newKommission.lastName);
    return await newKommission.save();
}

/**
     * Get a kommission by its id.
     *
     * @param kommissionId {number} Kommission id
     * @return {Promise<Kommission>} The wanted kommission.
     */
async function getKommissionById(kommissionId) {

    logger.verbose('Kommission service: get kommission by id %d', kommissionId);

    const kommission = await Kommission.findById(kommissionId);

    if (!kommission) throw createUserError('UnknownKommission', 'This kommission does not exist');

    return kommission.getBarmans();
}

/**
     * Update an kommission.
     * This will copy only the allowed changes from the `updatedKommission`
     * into the current kommission.
     * This means, with this function, you can not change everything like
     * the `createdAt` field or others.
     *
     * @param kommissionId {number} kommission id
     * @param updatedKommission {Kommission} Updated kommission, constructed from the request.
     * @return {Promise<Kommission>} The updated kommission
     */
async function updateKommission(kommissionId, updatedKommission) {

    const currentKommission = await Kommission.findById(kommissionId);

    if (!currentKommission) throw createUserError('UnknownKommission', 'This kommission does not exist');

    logger.verbose('Kommission service: updating kommission named %s %s', currentKommission.firstName, currentKommission.lastName);

    return await currentKommission.update({
        name: updatedKommission.name,
        description: updatedKommission.description,

    });
}

/**
     * Delete an kommission.
     *
     * @param kommissionId {number} kommission id.
     * @return {Promise<Kommission>} The deleted kommission
     */
async function deleteKommission(kommissionId) {

    logger.verbose('Kommission service: deleting kommission with id %d', kommissionId);

    const kommission = await Kommission.findById(kommissionId);

    if (!kommission) throw createUserError('UnknownKommission', 'This kommission does not exist');

    await kommission.destroy();

    return kommission;
}

module.exports = {
    getAllKommissions,
    createKommission,
    updateKommission,
    getKommissionById,
    deleteKommission
};
<commit_msg>nouvelle version KommissionbyID avec un findAll w where<commit_after>const logger = require('../../logger');
const { Kommission } = require('../models/kommission');
const { Barman } = require('../models/barman');
const { createUserError } = require('../../utils');

/**
 * Return all kommissions of the app.
 *
 * @returns {Promise<Array>} Kommissions
 */
async function getAllKommissions() {

    logger.verbose('Kommission service: get all kommissions');
    return await Kommission.findAll();
}

/**
 * Create a kommission.
 *
 * @param newKommission {Kommission} partial kommission
 * @return {Promise<Kommission|Errors.ValidationError>} The created kommission with its id
 */
async function createKommission(newKommission) {

    logger.verbose('Kommission service: creating a new kommission named %s %s', newKommission.firstName, newKommission.lastName);
    return await newKommission.save();
}

/**
     * Get a kommission by its id.
     *
     * @param kommissionId {number} Kommission id
     * @return {Promise<Kommission>} The wanted kommission.
     */
async function getKommissionById(kommissionId) {

    logger.verbose('Kommission service: get kommission by id %d', kommissionId);

    const kommission = await Kommission.findAll({where: {id: kommissionId}, include: [{model: Barman, through: {attributes:['id', 'firstname', 'lastname', 'nickname', 'facebook', 'dateofBirth', 'flow']}}]});

    if (!kommission) throw createUserError('UnknownKommission', 'This kommission does not exist');

    return kommission;
}

/**
     * Update an kommission.
     * This will copy only the allowed changes from the `updatedKommission`
     * into the current kommission.
     * This means, with this function, you can not change everything like
     * the `createdAt` field or others.
     *
     * @param kommissionId {number} kommission id
     * @param updatedKommission {Kommission} Updated kommission, constructed from the request.
     * @return {Promise<Kommission>} The updated kommission
     */
async function updateKommission(kommissionId, updatedKommission) {

    const currentKommission = await Kommission.findById(kommissionId);

    if (!currentKommission) throw createUserError('UnknownKommission', 'This kommission does not exist');

    logger.verbose('Kommission service: updating kommission named %s %s', currentKommission.firstName, currentKommission.lastName);

    return await currentKommission.update({
        name: updatedKommission.name,
        description: updatedKommission.description,

    });
}

/**
     * Delete an kommission.
     *
     * @param kommissionId {number} kommission id.
     * @return {Promise<Kommission>} The deleted kommission
     */
async function deleteKommission(kommissionId) {

    logger.verbose('Kommission service: deleting kommission with id %d', kommissionId);

    const kommission = await Kommission.findById(kommissionId);

    if (!kommission) throw createUserError('UnknownKommission', 'This kommission does not exist');

    await kommission.destroy();

    return kommission;
}

module.exports = {
    getAllKommissions,
    createKommission,
    updateKommission,
    getKommissionById,
    deleteKommission
};
<|endoftext|>


<commit_before>// Retrive data for all steps of all files
// (map db data into meta objects for our needs)

'use strict';

var aFrom                         = require('es5-ext/array/from')
  , forEach                       = require('es5-ext/object/for-each')
  , capitalize                    = require('es5-ext/string/#/capitalize')
  , Set                           = require('es6-set')
  , Map                           = require('es6-map')
  , deferred                      = require('deferred')
  , memoize                       = require('memoizee')
  , unserializeValue              = require('dbjs/_setup/unserialize/value')
  , resolveProcessingStepFullPath = require('../../utils/resolve-processing-step-full-path')
  , toDateInTz                    = require('../../utils/to-date-in-time-zone')
  , timeZone                      = require('../../db').timeZone;

var re = new RegExp('^([0-9a-z]+)\\/processingSteps\\/map\\/([a-zA-Z0-9]+' +
	'(?:\\/steps\\/map\\/[a-zA-Z0-9]+)*)\\/([a-z0-9A-Z\\/]+)$');

module.exports = exports = memoize(function (driver, processingStepsMeta) {
	var storageStepsMap = new Map(), stepShortPathMap = new Map()
	  , serviceFullShortNameMap = new Map();

	var result = { steps: Object.create(null), businessProcesses: Object.create(null) };

	forEach(processingStepsMeta, function (meta, stepShortPath) {
		var stepPath = resolveProcessingStepFullPath(stepShortPath);
		stepShortPathMap.set(stepPath, stepShortPath);
		meta._services.forEach(function (serviceName) {
			var serviceFullName = 'businessProcess' + capitalize.call(serviceName)
			  , storage = driver.getStorage(serviceFullName);
			serviceFullShortNameMap.set(serviceFullName, serviceName);
			if (!storageStepsMap.has(storage)) storageStepsMap.set(storage, new Set());
			storageStepsMap.get(storage).add(stepPath);

		});

		result.steps[stepShortPath] = Object.create(null);
	});

	return deferred.map(aFrom(storageStepsMap), function (data) {
		var storage = data[0], stepPaths = data[1]
		  , serviceName = serviceFullShortNameMap.get(storage.name);

		var initStepDataset = function (stepPath, businessProcessId) {
			var stepShortPath = stepShortPathMap.get(stepPath);
			if (!result.steps[stepShortPath][businessProcessId]) {
				result.steps[stepShortPath][businessProcessId] = {
					stepFullPath: 'processingSteps/map/' + stepPath,
					serviceName: serviceName
				};
			}
			return result.steps[stepShortPath][businessProcessId];
		};
		var initBpDataset = function (businessProcessId) {
			if (!result.businessProcesses[businessProcessId]) {
				result.businessProcesses[businessProcessId] = { serviceName: serviceName };
			}
			return result.businessProcesses[businessProcessId];
		};

		// Listen for new records
		stepPaths.forEach(function (stepPath) {
			// Status
			forEach(exports.stepMetaMap, function (meta, stepKeyPath) {
				storage.on('key:processingSteps/map/' + stepPath + '/' + stepKeyPath, function (event) {
					if (event.type !== (meta.type || 'direct')) return;
					if (!meta.validate(event.data)) meta.delete(initStepDataset(stepPath, event.ownerId));
					else meta.set(initStepDataset(stepPath, event.ownerId), event.data);
				});
			});
		});
		forEach(exports.businessProcessMetaMap, function (meta, keyPath) {
			storage.on('key:' + keyPath, function (event) {
				if (event.type !== (meta.type || 'direct')) return;
				if (!meta.validate(event.data)) meta.delete(initBpDataset(event.ownerId));
				else meta.set(initBpDataset(event.ownerId), event.data);
			});
		});

		// Get current records
		return deferred(
			storage.search(function (id, record) {
				var index = id.indexOf('/'), stepPath, stepKeyPath, meta;
				if (index === -1) return;
				var businessProcessId = id.slice(0, index)
				  , keyPath = id.slice(index + 1);
				meta = exports.businessProcessMetaMap[keyPath];
				if (meta) {
					if (meta.type && (meta.type !== 'direct')) return;
					if (!meta.validate(record)) return;
					meta.set(initBpDataset(businessProcessId), record);
				}
				var match = id.match(re);
				if (!match) return;
				stepPath = match[2];
				if (!stepPaths.has(stepPath)) return;
				stepKeyPath = match[3];
				meta = exports.stepsMetaMap[stepKeyPath];
				if (!meta) return;
				if (meta.type && (meta.type !== 'direct')) return;
				if (!meta.validate(record)) return;
				meta.set(initStepDataset(stepPath, businessProcessId), record);
			}),
			deferred.map(Object.keys(exports.businessProcessMetaMap), function (keyPath) {
				var meta = exports.businessProcessMetaMap[keyPath];
				if (meta.type !== 'computed') return;
				return storage.searchComputed({ keyPath: keyPath }, function (id, record) {
					if (!meta.validate(record)) return;
					meta.set(initBpDataset(id.split('/', 1)[0]), record);
				});
			}),
			deferred.map(aFrom(stepPaths), function (stepPath) {
				return deferred.map(Object.keys(exports.stepsMetaMap), function (stepPropKeyPath) {
					var meta = exports.stepsMetaMap[stepPropKeyPath];
					if (meta.type !== 'computed') return;
					var keyPath = 'processingSteps/map/' + stepPath + '/' + stepPropKeyPath;
					return storage.searchComputed({ keyPath: keyPath }, function (id, record) {
						if (!meta.validate(record)) return;
						meta.set(initStepDataset(stepPath, id.split('/', 1)[0]), record);
					});
				});
			})
		);
	})(result);

}, { length: 0 });

// Map of all properties to be mapped to result with corresponding instructions
exports.stepsMetaMap = {
	status: {
		validate: function (record) {
			return ((record.value === '3approved') || (record.value === '3rejected'));
		},
		set: function (data, record) {
			data.processingDate = toDateInTz(new Date(record.stamp / 1000), timeZone);
		},
		delete: function (data) { delete data.processingDate; }
	},
	processor: {
		validate: function (record) { return (record.value[0] === '7'); },
		set: function (data, record) { data.processor = record.value.slice(1); },
		delete: function (data) { delete data.processor; }
	},
	correctionTime: {
		validate: function (record) { return (record.value[0] === '2'); },
		set: function (data, record) { data.correctionTime = unserializeValue(record.value); },
		delete: function (data) { delete data.correctionTime; }
	},
	processingTime: {
		validate: function (record) { return (record.value[0] === '2'); },
		set: function (data, record) { data.processingTime = unserializeValue(record.value); },
		delete: function (data) { delete data.processingTime; }
	},
	isReady: {
		type: 'computed',
		validate: function (record) { return (record.value === '11'); },
		set: function (data, record) {
			data.pendingDate = toDateInTz(new Date(record.stamp / 1000), timeZone);
		},
		delete: function (data) { delete data.pendingDate; }
	}
};

exports.businessProcessMetaMap = {
	isApproved: {
		validate: function (record) { return (record.value === '11'); },
		set: function (data, record) {
			data.approvedDateTime = new Date(record.stamp / 1000);
			data.approvedDate = toDateInTz(data.approvedDateTime, timeZone);
		},
		delete: function (data) {
			delete data.approvedDateTime;
			delete data.approvedDate;
		}
	},
	isSubmitted: {
		validate: function (record) { return (record.value === '11'); },
		set: function (data, record) {
			data.submissionDateTime = new Date(record.stamp / 1000);
		},
		delete: function (data) { delete data.submissionDateTime; }
	}
};
<commit_msg>Fix metaMap references<commit_after>// Retrive data for all steps of all files
// (map db data into meta objects for our needs)

'use strict';

var aFrom                         = require('es5-ext/array/from')
  , forEach                       = require('es5-ext/object/for-each')
  , capitalize                    = require('es5-ext/string/#/capitalize')
  , Set                           = require('es6-set')
  , Map                           = require('es6-map')
  , deferred                      = require('deferred')
  , memoize                       = require('memoizee')
  , unserializeValue              = require('dbjs/_setup/unserialize/value')
  , resolveProcessingStepFullPath = require('../../utils/resolve-processing-step-full-path')
  , toDateInTz                    = require('../../utils/to-date-in-time-zone')
  , timeZone                      = require('../../db').timeZone;

var re = new RegExp('^([0-9a-z]+)\\/processingSteps\\/map\\/([a-zA-Z0-9]+' +
	'(?:\\/steps\\/map\\/[a-zA-Z0-9]+)*)\\/([a-z0-9A-Z\\/]+)$');

module.exports = exports = memoize(function (driver, processingStepsMeta) {
	var storageStepsMap = new Map(), stepShortPathMap = new Map()
	  , serviceFullShortNameMap = new Map();

	var result = { steps: Object.create(null), businessProcesses: Object.create(null) };

	forEach(processingStepsMeta, function (meta, stepShortPath) {
		var stepPath = resolveProcessingStepFullPath(stepShortPath);
		stepShortPathMap.set(stepPath, stepShortPath);
		meta._services.forEach(function (serviceName) {
			var serviceFullName = 'businessProcess' + capitalize.call(serviceName)
			  , storage = driver.getStorage(serviceFullName);
			serviceFullShortNameMap.set(serviceFullName, serviceName);
			if (!storageStepsMap.has(storage)) storageStepsMap.set(storage, new Set());
			storageStepsMap.get(storage).add(stepPath);

		});

		result.steps[stepShortPath] = Object.create(null);
	});

	return deferred.map(aFrom(storageStepsMap), function (data) {
		var storage = data[0], stepPaths = data[1]
		  , serviceName = serviceFullShortNameMap.get(storage.name);

		var initStepDataset = function (stepPath, businessProcessId) {
			var stepShortPath = stepShortPathMap.get(stepPath);
			if (!result.steps[stepShortPath][businessProcessId]) {
				result.steps[stepShortPath][businessProcessId] = {
					stepFullPath: 'processingSteps/map/' + stepPath,
					serviceName: serviceName
				};
			}
			return result.steps[stepShortPath][businessProcessId];
		};
		var initBpDataset = function (businessProcessId) {
			if (!result.businessProcesses[businessProcessId]) {
				result.businessProcesses[businessProcessId] = { serviceName: serviceName };
			}
			return result.businessProcesses[businessProcessId];
		};

		// Listen for new records
		stepPaths.forEach(function (stepPath) {
			// Status
			forEach(exports.stepMetaMap, function (meta, stepKeyPath) {
				storage.on('key:processingSteps/map/' + stepPath + '/' + stepKeyPath, function (event) {
					if (event.type !== (meta.type || 'direct')) return;
					if (!meta.validate(event.data)) meta.delete(initStepDataset(stepPath, event.ownerId));
					else meta.set(initStepDataset(stepPath, event.ownerId), event.data);
				});
			});
		});
		forEach(exports.businessProcessMetaMap, function (meta, keyPath) {
			storage.on('key:' + keyPath, function (event) {
				if (event.type !== (meta.type || 'direct')) return;
				if (!meta.validate(event.data)) meta.delete(initBpDataset(event.ownerId));
				else meta.set(initBpDataset(event.ownerId), event.data);
			});
		});

		// Get current records
		return deferred(
			storage.search(function (id, record) {
				var index = id.indexOf('/'), stepPath, stepKeyPath, meta;
				if (index === -1) return;
				var businessProcessId = id.slice(0, index)
				  , keyPath = id.slice(index + 1);
				meta = exports.businessProcessMetaMap[keyPath];
				if (meta) {
					if (meta.type && (meta.type !== 'direct')) return;
					if (!meta.validate(record)) return;
					meta.set(initBpDataset(businessProcessId), record);
				}
				var match = id.match(re);
				if (!match) return;
				stepPath = match[2];
				if (!stepPaths.has(stepPath)) return;
				stepKeyPath = match[3];
				meta = exports.stepMetaMap[stepKeyPath];
				if (!meta) return;
				if (meta.type && (meta.type !== 'direct')) return;
				if (!meta.validate(record)) return;
				meta.set(initStepDataset(stepPath, businessProcessId), record);
			}),
			deferred.map(Object.keys(exports.businessProcessMetaMap), function (keyPath) {
				var meta = exports.businessProcessMetaMap[keyPath];
				if (meta.type !== 'computed') return;
				return storage.searchComputed({ keyPath: keyPath }, function (id, record) {
					if (!meta.validate(record)) return;
					meta.set(initBpDataset(id.split('/', 1)[0]), record);
				});
			}),
			deferred.map(aFrom(stepPaths), function (stepPath) {
				return deferred.map(Object.keys(exports.stepMetaMap), function (stepPropKeyPath) {
					var meta = exports.stepMetaMap[stepPropKeyPath];
					if (meta.type !== 'computed') return;
					var keyPath = 'processingSteps/map/' + stepPath + '/' + stepPropKeyPath;
					return storage.searchComputed({ keyPath: keyPath }, function (id, record) {
						if (!meta.validate(record)) return;
						meta.set(initStepDataset(stepPath, id.split('/', 1)[0]), record);
					});
				});
			})
		);
	})(result);

}, { length: 0 });

// Map of all properties to be mapped to result with corresponding instructions
exports.stepMetaMap = {
	status: {
		validate: function (record) {
			return ((record.value === '3approved') || (record.value === '3rejected'));
		},
		set: function (data, record) {
			data.processingDate = toDateInTz(new Date(record.stamp / 1000), timeZone);
		},
		delete: function (data) { delete data.processingDate; }
	},
	processor: {
		validate: function (record) { return (record.value[0] === '7'); },
		set: function (data, record) { data.processor = record.value.slice(1); },
		delete: function (data) { delete data.processor; }
	},
	correctionTime: {
		validate: function (record) { return (record.value[0] === '2'); },
		set: function (data, record) { data.correctionTime = unserializeValue(record.value); },
		delete: function (data) { delete data.correctionTime; }
	},
	processingTime: {
		validate: function (record) { return (record.value[0] === '2'); },
		set: function (data, record) { data.processingTime = unserializeValue(record.value); },
		delete: function (data) { delete data.processingTime; }
	},
	isReady: {
		type: 'computed',
		validate: function (record) { return (record.value === '11'); },
		set: function (data, record) {
			data.pendingDate = toDateInTz(new Date(record.stamp / 1000), timeZone);
		},
		delete: function (data) { delete data.pendingDate; }
	}
};

exports.businessProcessMetaMap = {
	isApproved: {
		validate: function (record) { return (record.value === '11'); },
		set: function (data, record) {
			data.approvedDateTime = new Date(record.stamp / 1000);
			data.approvedDate = toDateInTz(data.approvedDateTime, timeZone);
		},
		delete: function (data) {
			delete data.approvedDateTime;
			delete data.approvedDate;
		}
	},
	isSubmitted: {
		validate: function (record) { return (record.value === '11'); },
		set: function (data, record) {
			data.submissionDateTime = new Date(record.stamp / 1000);
		},
		delete: function (data) { delete data.submissionDateTime; }
	}
};
<|endoftext|>


<commit_before>/**
 * Uses Mongoose Models for db operations.
 */
import Shipment from '../models/shipment';
import sanitizeHtml from 'sanitize-html';

export default {
    getShipments: function (req, res) {
        const rq = req.query,
              query = {};
        if (rq.company) query.company = rq.company;
        if (rq.dept) query.dept = rq.dept;

        if (rq.year && !rq.month) {
            query.date = {
                "$gte": new Date(rq.year, 0, 1),
                "$lt": new Date(rq.year, 12, 1)
            }
        } else if (rq.year && rq.month) {
            query.date = {
                "$gte": new Date(rq.year, rq.month, 1),
                "$lt": new Date(rq.year, Number(rq.month) + 1, 1)
            }
        }

        Shipment.find(query, {__v: 0, dateAdded: 0})
            .sort('-refPage refPageSeq dateAdded')
            .exec((err, docs) => {
                if (err) {
                    return res.status(500).send(err);
                }
                res.json(docs);
            });
    },

    shipmentsPDF: function (req, res) {
        const WASTE_WATER = "廢水";
        if (!("company" in req.query && "start" in req.query && "end" in req.query)) {
            res.status(400).send({error: "'start' and 'end' dates are required."});
        }
        const company = req.query.company,
              start = new Date(req.query.start),
              end = new Date(req.query.end + " 23:59");
        if (!company) {
            res.status(400).send({error: "Error in company name."});
        }
        if (isNaN(start.getDate()) || isNaN(end.getDate())) {
            res.status(400).send({error: "Malformed dates. Check format is YYYY/MM/DD."});
        }

        const query = {
            company: company,
            date: {
                "$gte": start,
                "$lte": end
            }
        };
        if ("unit" in req.query && req.query.unit === WASTE_WATER) {
            query.unit = req.query.unit;
        }

        const monthReportSort = { refPage: 1, refPageSeq: 1, dateAdded: 1 };
        const wasteWaterSort = { date: 1 };

        // TODO: Could embed a secondary query to aggregate product totals.
        Shipment.find(query, {_id: 0, __v: 0, dateAdded: 0, note: 0})
            .sort(query.unit ? wasteWaterSort : monthReportSort)
            .exec((err, shipments) => {
                if (err) {
                    return res.status(500).send(err);
                }
                res.json({
                    company,
                    start,
                    end,
                    shipments
                });
            });
    },

    /**
     * Server side code.
     * Adds `shipment` records to Mongo database.
     * @returns {object}   Response object with error or save confirmation.
     */
    addShipments: function (req, res) {
        let shipments = req.body.shipments;

        function validateShipment(s) {
            if (!s.date || !s.product || !s.pn || !s.amount
                || !s.company || !s.dept || !s.unit || !s.refPage) {
                return false;
            }
            return true;
        }

        shipments = shipments.map(s => {
            if (validateShipment(s)) {
                return {
                    product: s.product ? sanitizeHtml(s.product) : undefined,
                    pn: s.pn ? sanitizeHtml(s.pn) : undefined,
                    note: s.note ? sanitizeHtml(s.note) : "",
                    company: s.company ? sanitizeHtml(s.company) : undefined,
                    dept: s.dept ? sanitizeHtml(s.dept) : undefined,
                    unit: s.unit ? sanitizeHtml(s.unit) : undefined,
                    refPage: s.refPage,
                    refPageSeq: s.refPageSeq,
                    amount: s.amount,
                    date: s.date,
                };
            }
            // 403 Forbidden
            return false;
        });

        if (shipments.every(each => !!each)) {
            Shipment.insertMany(shipments, (err, recs) => {
                if (err) {
                    return res.status(500).send(err);
                }
                return res.json(recs);
            });
        } else res.status(403).end();
    },

    deleteShipment: function (req, res) {
        const { _id } = req.body;
        Shipment.findById(_id).exec((err, shipment) => {
            if (err) {
                return res.status(500).send(err);
            }

            shipment.remove(() => {
                res.status(204).end();
            });
        });
    },

    updateSpecReport: function (req, res) {
        const { id, report } = req.body;

        Shipment.findById(id).exec((err, shipment) => {
            if (err) {
                return res.status(500).send(err);
            }
            console.log("report");
            console.dir(report);
            shipment.testReport = report;
            shipment.save((err, doc) => {
                if (err) {
                    return res.status(500).send(err);
                }
                res.json(doc);
            })
        });
    },

    specReports: function (req, res) {
        const { pn } = req.query;
        if (!pn) {
            res.status(400).end();
        }

        Shipment.aggregate([
            { $match: {
                pn: pn,
                "testReport.tests.0": {$exists: true}
            } },
//            { $sample : { size: 5 } },  // Available in version 3.2+
            { $limit : { size: 8 } },
            { $project: {
                product: 1,
                pn: 1,
                testReport: 1,
                tests: "$testReport.tests",
                _id: 0,
            } },
            { $unwind: "$tests" },
            { $group: {
                _id: "$pn",
                pn: {$first: "$pn"},
                companyHeader: {$last: "$testReport.companyHeader"},
                lotAmount: {$first: "$testReport.lotAmount"},
                sampler: {$last: "$testReport.sampler"},
                inspector: {$first: "$testReport.inspector"},
                reporter: {$last: "$testReport.reporter"},
                shelfLife: {$first: "$testReport.shelfLife"},
                result: {$last: "$testReport.result"},

                tests: {$addToSet: "$tests"},
            } },
        ]).exec((err, docs) => {
            if (err) return res.send(err);

//            console.log('reports');
//            console.dir(docs);
//            if (docs.length > 0) console.dir(docs[0].tests);

            res.json(docs.length > 0 ? docs[0] : null);
        });
    },
}
<commit_msg>Fixed limit<commit_after>/**
 * Uses Mongoose Models for db operations.
 */
import Shipment from '../models/shipment';
import sanitizeHtml from 'sanitize-html';

export default {
    getShipments: function (req, res) {
        const rq = req.query,
              query = {};
        if (rq.company) query.company = rq.company;
        if (rq.dept) query.dept = rq.dept;

        if (rq.year && !rq.month) {
            query.date = {
                "$gte": new Date(rq.year, 0, 1),
                "$lt": new Date(rq.year, 12, 1)
            }
        } else if (rq.year && rq.month) {
            query.date = {
                "$gte": new Date(rq.year, rq.month, 1),
                "$lt": new Date(rq.year, Number(rq.month) + 1, 1)
            }
        }

        Shipment.find(query, {__v: 0, dateAdded: 0})
            .sort('-refPage refPageSeq dateAdded')
            .exec((err, docs) => {
                if (err) {
                    return res.status(500).send(err);
                }
                res.json(docs);
            });
    },

    shipmentsPDF: function (req, res) {
        const WASTE_WATER = "廢水";
        if (!("company" in req.query && "start" in req.query && "end" in req.query)) {
            res.status(400).send({error: "'start' and 'end' dates are required."});
        }
        const company = req.query.company,
              start = new Date(req.query.start),
              end = new Date(req.query.end + " 23:59");
        if (!company) {
            res.status(400).send({error: "Error in company name."});
        }
        if (isNaN(start.getDate()) || isNaN(end.getDate())) {
            res.status(400).send({error: "Malformed dates. Check format is YYYY/MM/DD."});
        }

        const query = {
            company: company,
            date: {
                "$gte": start,
                "$lte": end
            }
        };
        if ("unit" in req.query && req.query.unit === WASTE_WATER) {
            query.unit = req.query.unit;
        }

        const monthReportSort = { refPage: 1, refPageSeq: 1, dateAdded: 1 };
        const wasteWaterSort = { date: 1 };

        // TODO: Could embed a secondary query to aggregate product totals.
        Shipment.find(query, {_id: 0, __v: 0, dateAdded: 0, note: 0})
            .sort(query.unit ? wasteWaterSort : monthReportSort)
            .exec((err, shipments) => {
                if (err) {
                    return res.status(500).send(err);
                }
                res.json({
                    company,
                    start,
                    end,
                    shipments
                });
            });
    },

    /**
     * Server side code.
     * Adds `shipment` records to Mongo database.
     * @returns {object}   Response object with error or save confirmation.
     */
    addShipments: function (req, res) {
        let shipments = req.body.shipments;

        function validateShipment(s) {
            if (!s.date || !s.product || !s.pn || !s.amount
                || !s.company || !s.dept || !s.unit || !s.refPage) {
                return false;
            }
            return true;
        }

        shipments = shipments.map(s => {
            if (validateShipment(s)) {
                return {
                    product: s.product ? sanitizeHtml(s.product) : undefined,
                    pn: s.pn ? sanitizeHtml(s.pn) : undefined,
                    note: s.note ? sanitizeHtml(s.note) : "",
                    company: s.company ? sanitizeHtml(s.company) : undefined,
                    dept: s.dept ? sanitizeHtml(s.dept) : undefined,
                    unit: s.unit ? sanitizeHtml(s.unit) : undefined,
                    refPage: s.refPage,
                    refPageSeq: s.refPageSeq,
                    amount: s.amount,
                    date: s.date,
                };
            }
            // 403 Forbidden
            return false;
        });

        if (shipments.every(each => !!each)) {
            Shipment.insertMany(shipments, (err, recs) => {
                if (err) {
                    return res.status(500).send(err);
                }
                return res.json(recs);
            });
        } else res.status(403).end();
    },

    deleteShipment: function (req, res) {
        const { _id } = req.body;
        Shipment.findById(_id).exec((err, shipment) => {
            if (err) {
                return res.status(500).send(err);
            }

            shipment.remove(() => {
                res.status(204).end();
            });
        });
    },

    updateSpecReport: function (req, res) {
        const { id, report } = req.body;

        Shipment.findById(id).exec((err, shipment) => {
            if (err) {
                return res.status(500).send(err);
            }
            console.log("report");
            console.dir(report);
            shipment.testReport = report;
            shipment.save((err, doc) => {
                if (err) {
                    return res.status(500).send(err);
                }
                res.json(doc);
            })
        });
    },

    specReports: function (req, res) {
        const { pn } = req.query;
        if (!pn) {
            res.status(400).end();
        }

        Shipment.aggregate([
            { $match: {
                pn: pn,
                "testReport.tests.0": {$exists: true}
            } },
//            { $sample : { size: 5 } },  // Available in version 3.2+
            { $limit : 8 },
            { $project: {
                product: 1,
                pn: 1,
                testReport: 1,
                tests: "$testReport.tests",
                _id: 0,
            } },
            { $unwind: "$tests" },
            { $group: {
                _id: "$pn",
                pn: {$first: "$pn"},
                companyHeader: {$last: "$testReport.companyHeader"},
                lotAmount: {$first: "$testReport.lotAmount"},
                sampler: {$last: "$testReport.sampler"},
                inspector: {$first: "$testReport.inspector"},
                reporter: {$last: "$testReport.reporter"},
                shelfLife: {$first: "$testReport.shelfLife"},
                result: {$last: "$testReport.result"},

                tests: {$addToSet: "$tests"},
            } },
        ]).exec((err, docs) => {
            if (err) return res.send(err);

//            console.log('reports');
//            console.dir(docs);
//            if (docs.length > 0) console.dir(docs[0].tests);

            res.json(docs.length > 0 ? docs[0] : null);
        });
    },
}
<|endoftext|>


<commit_before>const DrawCard = require('../../drawcard.js');
const AbilityDsl = require('../../abilitydsl');

class KitsukiJusai extends DrawCard {
    setupCardAbilities() {
        this.reaction({
            title: 'Set your opponent\'s dial to equal yours',
            when: {
                onHonorDialsRevealed: (event, context) =>
                    context.player.opponent &&
                    context.player.honorBid === context.player.opponent.honorBid &&
                    context.player.opponent.fate > 0
            },
            gameAction: AbilityDsl.actions.selectRing(context => ({
                activePromptTitle: 'Choose an unclaimed ring to move fate to',
                ringCondition: ring => ring.isUnclaimed() && ring !== context.ring,
                message: '{0} moves a fate from {1}\'s fate pool to the {2}',
                messageArgs: ring => [context.player, context.player.opponent, ring],
                gameAction: AbilityDsl.actions.placeFateOnRing({ origin: context.player.opponent })
            })),
            effect: 'move 1 fate from {1}\'s fate pool to an unclaimed ring',
            effectArgs: context => [context.player.opponent]
        });
    }
}

KitsukiJusai.id = 'kitsuki-jusai';

module.exports = KitsukiJusai;
<commit_msg>Removed context.ring<commit_after>const DrawCard = require('../../drawcard.js');
const AbilityDsl = require('../../abilitydsl');

class KitsukiJusai extends DrawCard {
    setupCardAbilities() {
        this.reaction({
            title: 'Set your opponent\'s dial to equal yours',
            when: {
                onHonorDialsRevealed: (event, context) =>
                    context.player.opponent &&
                    context.player.honorBid === context.player.opponent.honorBid &&
                    context.player.opponent.fate > 0
            },
            gameAction: AbilityDsl.actions.selectRing(context => ({
                activePromptTitle: 'Choose an unclaimed ring to move fate to',
                ringCondition: ring => ring.isUnclaimed(),
                message: '{0} moves a fate from {1}\'s fate pool to the {2}',
                messageArgs: ring => [context.player, context.player.opponent, ring],
                gameAction: AbilityDsl.actions.placeFateOnRing({ origin: context.player.opponent })
            })),
            effect: 'move 1 fate from {1}\'s fate pool to an unclaimed ring',
            effectArgs: context => [context.player.opponent]
        });
    }
}

KitsukiJusai.id = 'kitsuki-jusai';

module.exports = KitsukiJusai;
<|endoftext|>


<commit_before>const DrawCard = require('../../../drawcard.js');

class TheWall extends DrawCard {
    constructor(owner, cardData) {
        super(owner, cardData);

        this.registerEvents(['onCardPlayed', 'onEndChallengePhase']);
    }

    play(player) {
        super.play(player);

        player.cardsInPlay.each(card => {
            if(card.getFaction() === this.getFaction() && card.getType() === 'character') {
                card.strengthModifier++;
            }
        });
    }

    onCardPlayed(e, player, cardId) {
        if(!this.inPlay || this.owner !== player) {
            return;
        }

        var card = player.findCardInPlayByUuid(cardId);
        if(!card) {
            return;
        }

        if(card.getFaction() === this.getFaction() && card.getType() === 'character') {
            card.strengthModifier++;
        }
    }

    onUnopposedWin(winner) {
        if(this.owner !== winner && !this.kneeled) {
            this.game.addMessage('{0} is forced to kneel {1} because they lost an unopposed challenge', this.owner, this);
            this.kneeled = true;
        }
    }

    onEndChallengePhase() {
        if(!this.inPlay || this.kneeled) {
            return;
        }

        this.game.promptWithMenu(this.owner, this, {
            activePrompt: {
                menuTitle: 'Kneel ' + this.name + '?',
                buttons: [
                    { text: 'Yes', command: 'menuButton', method: 'kneel' },
                    { text: 'No', command: 'menuButton', method: 'cancel' }
                ]
            },
            waitingPromptTitle: 'Waiting for opponent to use ' + this.name
        });

        this.game.pipeline.continue();
    }

    kneel(player) {
        if(!this.inPlay || this.isBlank() || this.owner !== player) {
            return false;
        }

        this.game.addMessage('{0} kneels {1} to gain 2 power for their faction', player, this);

        this.game.addPower(player, 2);

        return true;
    }

    cancel(player) {
        if(!this.inPlay || this.isBlank() || this.owner !== player) {
            return false;
        }

        this.game.addMessage('{0} declines to trigger {1}', player, this);
        return true;
    }

    leavesPlay() {
        super.leavesPlay();

        this.owner.cardsInPlay.each(card => {
            if(card.getFaction() === this.getFaction() && card.getType() === 'character') {
                card.strengthModifier--;
            }
        });
    }
}

TheWall.code = '01137';

module.exports = TheWall;
<commit_msg>fix infinite loop in the wall<commit_after>const DrawCard = require('../../../drawcard.js');

class TheWall extends DrawCard {
    constructor(owner, cardData) {
        super(owner, cardData);

        this.registerEvents(['onCardPlayed', 'onEndChallengePhase']);
    }

    play(player) {
        super.play(player);

        player.cardsInPlay.each(card => {
            if(card.getFaction() === this.getFaction() && card.getType() === 'character') {
                card.strengthModifier++;
            }
        });
    }

    onCardPlayed(e, player, cardId) {
        if(!this.inPlay || this.owner !== player) {
            return;
        }

        var card = player.findCardInPlayByUuid(cardId);
        if(!card) {
            return;
        }

        if(card.getFaction() === this.getFaction() && card.getType() === 'character') {
            card.strengthModifier++;
        }
    }

    onUnopposedWin(winner) {
        if(this.owner !== winner && !this.kneeled) {
            this.game.addMessage('{0} is forced to kneel {1} because they lost an unopposed challenge', this.owner, this);
            this.kneeled = true;
        }
    }

    onEndChallengePhase() {
        if(!this.inPlay || this.kneeled) {
            return;
        }

        this.game.promptWithMenu(this.owner, this, {
            activePrompt: {
                menuTitle: 'Kneel ' + this.name + '?',
                buttons: [
                    { text: 'Yes', command: 'menuButton', method: 'kneel' },
                    { text: 'No', command: 'menuButton', method: 'cancel' }
                ]
            },
            waitingPromptTitle: 'Waiting for opponent to use ' + this.name
        });
    }

    kneel(player) {
        if(!this.inPlay || this.isBlank() || this.owner !== player) {
            return false;
        }

        this.game.addMessage('{0} kneels {1} to gain 2 power for their faction', player, this);

        this.game.addPower(player, 2);

        return true;
    }

    cancel(player) {
        if(!this.inPlay || this.isBlank() || this.owner !== player) {
            return false;
        }

        this.game.addMessage('{0} declines to trigger {1}', player, this);
        return true;
    }

    leavesPlay() {
        super.leavesPlay();

        this.owner.cardsInPlay.each(card => {
            if(card.getFaction() === this.getFaction() && card.getType() === 'character') {
                card.strengthModifier--;
            }
        });
    }
}

TheWall.code = '01137';

module.exports = TheWall;
<|endoftext|>