<commit_before>var express = require('express');
var router = express.Router();
var Promise = require('bluebird');

var BeamServer = require('./model/BeamServer');
var beamServer = new BeamServer();

var Promise = require('bluebird');

router.post('/rpc/registration', function(req, res) {
    // get post information
    var url = req.body.url;
    var name = req.body.name;
    if (url === undefined || name === undefined) {
        res.send(400).end();
        return;
    }

    // connect and assume everything is good
    try {
        beamServer.connect(name, url);
    } catch (e) {
        console.log('Error on connecting to the host');
        console.log(e.toString());
        var code = parseInt(e.message);

        // throw the error if it isn't a simple status code
        if (typeof code !== 'number' && !isNan(code)) {
            throw e;
        }

        // send the response
        res.send(code).end();
        return;
    }

    // if connected to RPC ok, send a 201
    res.send(201).end();
});

// returns a list of all rpc servers
router.get('/rpc', function(req, res) {
    res.send(200, Object.keys(beamServer.clients)).end();
});

router.get('/:name', function(req, res) {
    var name = req.params.name;

    var client = beamServer.clients[name];
    if (client === undefined) {
        res.send(404).end();
    }

    // send the functions associated with that client
    res.send(200, client.functions).end();
});

router.get('/:name/:function', function(req, res) {
    var name = req.params.name;
    var fn = req.params.function;

    // attempt to get the client
    var client = beamServer.clients[name];
    if (client === undefined) {
        res.send(404).end();
    }

    try {
        client.call(fn, [])
        .then(function(result) {
            res.send(200, result);
        });
    } catch (e) {
        console.log(e);
        res.send(500).end();
    }
});

router.get('/test', function(req, res) {
    var client = beamServer.connect('tcp://10.16.22.181:4242');

    client.call('hello', ['colin'])
        .then(function(callRes) {
            console.log('call success!');
            res.send(200, JSON.stringify(callRes)).end();
        })
        .error(function(e) {
            console.log('there was an error');
            console.log(e);
            res.send(500).end();
        });
});

module.exports = router;
<commit_msg>better error handling;<commit_after>var express = require('express');
var router = express.Router();
var Promise = require('bluebird');

var BeamServer = require('./model/BeamServer');
var beamServer = new BeamServer();

var Promise = require('bluebird');

router.post('/rpc/registration', function(req, res) {
    // get post information
    var url = req.body.url;
    var name = req.body.name;
    if (url === undefined || name === undefined) {
        res.send(400).end();
        return;
    }

    // connect and assume everything is good
    try {
        beamServer.connect(name, url);
    } catch (e) {
        console.log('Error while connecting to the host');
        console.log(e.toString());
        var code = parseInt(e.message);

        // throw the error if it isn't a simple status code
        if (typeof code !== 'number' && !isNan(code)) {
            throw e;
        }

        // send bad gateway if can't connect to client or the '_functions'
        // doesn't exist
        if (e.name === 'NotConnected' || e.name === 'FuncNotFound') {
            res.send(502).end();
            return;
        }

        // send the response
        res.send(code).end();
        return;
    }

    // if connected to RPC ok, send a 201
    res.send(201).end();
});

// returns a list of all rpc servers
router.get('/rpc', function(req, res) {
    res.send(200, Object.keys(beamServer.clients)).end();
});

router.get('/:name', function(req, res) {
    var name = req.params.name;

    var client = beamServer.clients[name];
    if (client === undefined) {
        res.send(404).end();
    }

    // send the functions associated with that client
    res.send(200, client.functions).end();
});

router.get('/:name/:function', function(req, res) {
    var name = req.params.name;
    var fn = req.params.function;

    // attempt to get the client
    var client = beamServer.clients[name];
    if (client === undefined) {
        res.send(404).end();
    }

    try {
        client.call(fn, [])
        .then(function(result) {
            res.send(200, result);
        });
    } catch (e) {
        console.log(e);
        res.send(500).end();
    }
});

router.get('/test', function(req, res) {
    var client = beamServer.connect('tcp://10.16.22.181:4242');

    client.call('hello', ['colin'])
        .then(function(callRes) {
            console.log('call success!');
            res.send(200, JSON.stringify(callRes)).end();
        })
        .error(function(e) {
            console.log('there was an error');
            console.log(e);
            res.send(500).end();
        });
});

module.exports = router;
<|endoftext|>


<commit_before>// Implement your server in this file.
// We should be able to run your server with node src/server.js

// Imports the express Node module.
var express = require('express');
// Creates an Express server.
var app = express();
var bodyParser = require('body-parser');
// Support receiving JSON in HTTP request bodies
app.use(bodyParser.json());
app.use(bodyParser.text());
app.use(express.static('../client/build'));

//import database functions
var database = require('./database.js');
var readDocument = database.readDocument;
var addDocument = database.addDocument;
var writeDocument = database.writeDocument;
var deleteDocument = database.deleteDocument;

//schemas
var statusUpdateSchema = require('./schemas/statusUpdate.json');
var commentSchema = require('./schemas/comment.json');
var userInfoSchema = require('./schemas/userInfo.json');
var emailChangeSchema = require('./schemas/emailChange.json');
var activitySchema = require('./schemas/activity.json');
var validate = require('express-jsonschema').validate;

//get post feed data
function getPostFeedItemSync(feedItemId){
  var postFeedItem = readDocument("postFeedItems",feedItemId);
  postFeedItem.likeCounter = postFeedItem.likeCounter.map((id)=>readDocument('users', id));
  postFeedItem.contents.author = readDocument('users', postFeedItem.contents.author);

  postFeedItem.comments.forEach((comment)=>{
    comment.author = readDocument('users', comment.author);
  });

  return postFeedItem;
}

function getPostFeedData(user){
  var userData = readDocument('users',user);
  var feedData = readDocument('postFeeds',userData.post);
  feedData.contents = feedData.contents.map(getPostFeedItemSync);
  return feedData;
}

app.get('/user/:userId/feed',function(req,res){
  var userId = parseInt(req.params.userId,10);
  // var fromUser = getUserIdFromToken(req.get('Authorization'));
  // if(userId === fromUser){
    res.send(getPostFeedData(userId));
  // }
  // else{
    // res.status(401).end();
  // }
});

function postStatus(user, text){
  var time = new Date().getTime();

  var post = {
    "likeCounter":[],
    "type": "general",
    "contents": {
      "author": user,
      "postDate": time,
      "text": text,
      "img": null
    },
    "comments":[]
  };

  post = addDocument('postFeedItems',post);

  var userData = readDocument('users',user);
  var postFeedData = readDocument('postFeeds',userData.post);

  postFeedData.contents.unshift(post._id);

  writeDocument('postFeeds', postFeedData);

  return post;
}

//create post
app.post('/postItem', validate({ body: statusUpdateSchema }),function(req,res){
  var body = req.body;
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  if(fromUser === body.userId){
    var newPost = postStatus(body.userId,body.text);
    res.status(201);
    res.send(newPost);
  }
  else{
    res.status(401).end();
  }
});

//like post
app.put('/postItem/:postItemId/likelist/:userId',function(req,res){
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  var postItemId = parseInt(req.params.postItemId,10);
  var userId = parseInt(req.params.userId,10);
  if(userId === fromUser){
    var postFeedItem = readDocument('postFeedItems',postItemId);
    if(postFeedItem.likeCounter.indexOf(userId)===-1){
      postFeedItem.likeCounter.push(userId);
      writeDocument('postFeedItems',postFeedItem);
    }
    res.status(201);
    res.send(postFeedItem.likeCounter.map((id)=>readDocument('users',id)));
  }
  else{
    res.status(401).end();
  }
});

//unlike post
app.delete('/postItem/:postItemId/likelist/:userId',function(req,res){
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  var postItemId = parseInt(req.params.postItemId,10);
  var userId = parseInt(req.params.userId,10);
  if(userId === fromUser){
    var postFeedItem = readDocument('postFeedItems',postItemId);
    var index = postFeedItem.likeCounter.indexOf(userId);
    if(index!==-1){
      postFeedItem.likeCounter.splice(index,1);
      writeDocument('postFeedItems',postFeedItem);
    }
    res.status(201);
    res.send(postFeedItem.likeCounter.map((id)=>readDocument('users',id)));
  }
  else{
    res.status(401).end();
  }

});

//get user data
app.get('/user/:userId',function(req,res){
  // var fromUser = getUserIdFromToken(req.get('Authorization'));
  var userId = parseInt(req.params.userId,10);
  // if(fromUser === userId){
    var userData = readDocument('users',userId);
    userData.friends = userData.friends.map((id)=>readDocument('users',id));
    res.status(201);
    res.send(userData);
  // }
  // else{
    // res.status(401).end();
  // }
});

//post comments
app.post('/postItem/:postItemId/commentThread/comment',validate({body:commentSchema}),
function(req,res){
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  var body = req.body;
  var postItemId = parseInt(req.params.postItemId);
  var userId = body.author;
  if(fromUser === userId){
    var postFeedItem = readDocument('postFeedItems',postItemId);
    postFeedItem.comments.push({
      "author": userId,
      "text": body.text,
      "postDate": (new Date()).getTime()
    });
    writeDocument('postFeedItems',postFeedItem);
    res.status(201);
    res.send(getPostFeedItemSync(postItemId));
  }
  else{
    res.status(401).end();
  }
});

//change user info
app.put('/settings/user/:userId',validate({body:userInfoSchema}),function(req,res){
  var data = req.body;
  var moment = require('moment');
  var userId = parseInt(req.params.userId);
  var fromUser = getUserIdFromToken(req.get('Authorization'));

  if(fromUser == userId){
    var userData = readDocument('users',userId);
    userData.lastname = data.lastname;
    userData.firstname = data.firstname;
    userData.nickname = data.nickname;
    userData.description = data.description;
    userData.location = data.location;
    userData.birthday = moment(data.birthday).valueOf();

    writeDocument('users', userData);
    res.status(201);
    res.send(userData);
  }
  else{
    res.status(401).end();
  }
});

function getActivityFeedItemSync(activityId){
  var activityItem = readDocument('activityItems', activityId);
  activityItem.author = readDocument('users', activityItem.author);
  activityItem.participants = activityItem.participants.map((id) => readDocument('users', id));
  activityItem.likeCounter = activityItem.likeCounter.map((id) => readDocument('users', id));
  activityItem.comments.forEach((comment) => {
    comment.author = readDocument('users', comment.author);
  });

  return activityItem;
}

function getActivityFeedData(user){
  var userData = readDocument('users',user);
  var activityData = readDocument('activities', userData.activity);
  activityData.contents = activityData.contents.map(getActivityFeedItemSync);
  return activityData;
}

app.put('/settings/emailChange/user/:userId',validate({body:emailChangeSchema}),function(req,res){
  var data = req.body;
  var userId = parseInt(req.params.userId);
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  if(fromUser === userId){
    var userData = readDocument('users',userId);
    if(userData.email === data.oldEmail){
      userData.email = data.newEmail;
      writeDocument('users', userData);
      res.send(false);
    }
    else{
      res.send(true);
    }
  }
  else{
    res.statsus(401).end();
  }
});

// get activity Feed data
app.get('/user/:userid/activity', function(req, res) {
  var userId = parseInt(req.params.userid,10);
  // var fromUser = getUserIdFromToken(req.get('Authorization'));
  // if(userId === fromUser){
    res.send(getActivityFeedData(userId));
  // }
  // else{
    // res.status(401).end();
  // }
});

//get activity detail
app.get('/activityItem/:activityId',function(req,res){
  var activityId = parseInt(req.params.activityId);
  var activityData = getActivityFeedItemSync(activityId);
  res.status(201);
  res.send(activityData);
});

//like activity
app.put('/activityItem/:activityId/likelist/:userId',function(req, res){
  var activityId = parseInt(req.params.activityId, 10);
  var userId = parseInt(req.params.userId, 10);
  var activityItem = readDocument('activityItems', activityId);
  if(activityItem.likeCounter.indexOf(userId) === -1){
    activityItem.likeCounter.push(userId);
    writeDocument('activityItems', activityItem);
  }
  res.status(201);
  res.send(activityItem.likeCounter.map((id) => readDocument('users', id)));
});

//unlike activity
app.delete('/activityItem/:activityId/likelist/:userId', function(req, res){
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  var activityId = parseInt(req.params.activityId, 10);
  var userId = parseInt(req.params.userId, 10);
  var activityItem = readDocument('activityItems', activityId);
  var index = activityItem.likeCounter.indexOf(userId);
  if(index !== -1){
    activityItem.likeCounter.splice(index, 1);
    writeDocument('activityItems', activityItem);
  }
  res.status(201);
  res.send(activityItem.likeCounter.map((id) => readDocument('users', id)));

});

function getNotificationDataSync(notificationId){
  var notification = readDocument('notificationItems',notificationId);
  if(notification.type === "FR"){
    notification.sender = readDocument("users",notification.sender);
  }
  else{
    notification.author = readDocument("users",notification.author);
  }

  return notification;
}

//get notification
app.get('/user/:userId/notification',function(req,res){
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  var userId = parseInt(req.params.userId);
  if(fromUser === userId){
    var userData = readDocument('users',userId);
    var notificationData = readDocument('notifications',userData.notification);
    notificationData.contents = notificationData.contents.map(getNotificationDataSync);
    res.status(201);
    res.send(notificationData);
  }
  else{
    res.status(401).end();
  }
});

function deleteNotification(id, user){
  var userData = readDocument('users',user);
  var notificationData = readDocument('notifications',userData.notification);
  var index = notificationData.contents.indexOf(id);
  if(index !== -1)
    notificationData.contents.splice(index,1);

  writeDocument("notifications",notificationData);
  deleteDocument("notificationItems",id);
  return notificationData;
}

//acceptRequest
app.put('/notification/:notificationId/:userId',function(req,res){
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  var userId = parseInt(req.params.userId);
  var notificationId = parseInt(req.params.notificationId);
  if(fromUser === userId){
    var userData = readDocument('users',userId);
    var notificationItem = readDocument('notificationItems',notificationId);
    userData.friends.push(notificationItem.sender);
    writeDocument("users",userData);
    res.status(201);
    res.send(deleteNotification(notificationId,userId));
  }
  else{
    res.status(401).end();
  }
});

//deleteNotification
app.delete('/notification/:notificationId/:userId',function(req,res){
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  var userId = parseInt(req.params.userId);
  var notificationId = parseInt(req.params.notificationId);
  if(fromUser === userId){
    res.status(201);
    res.send(deleteNotification(notificationId,userId));
  }
  else{
    res.status(401).end();
  }
});

/**
* Get the user ID from a token. Returns -1 (an invalid ID)
* if it fails.
*/
function getUserIdFromToken(authorizationLine) {
  try {
    // Cut off "Bearer " from the header value.
    var token = authorizationLine.slice(7);
    // Convert the base64 string to a UTF-8 string.
    var regularString = new Buffer(token, 'base64').toString('utf8');
    // Convert the UTF-8 string into a JavaScript object.
    var tokenObj = JSON.parse(regularString);
    var id = tokenObj['id'];
    // Check that id is a number.
    if (typeof id === 'number') {
      return id;
    } else {
      // Not a number. Return -1, an invalid ID.
      return -1;
    }
  } catch (e) {
    // Return an invalid ID.
    return -1;
  }
}

// Reset database.
app.post('/resetdb', function(req, res) {
  console.log("Resetting database...");
  // This is a debug route, so don't do any validation.
  database.resetDatabase();
  // res.send() sends an empty response with status code 200
  res.send();
});

/**
* Translate JSON Schema Validation failures into error 400s.
*/
app.use(function(err, req, res, next) {
  if (err.name === 'JsonSchemaValidation') {
    // Set a bad request http response status
    res.status(400).end();
  } else {
    // It's some other sort of error; pass it to next error middleware handler
    next(err);
  }
});

// Starts the server on port 3000!
app.listen(3000, function () {
  console.log('app listening on port 3000!');
});
<commit_msg>fix minor issue<commit_after>// Implement your server in this file.
// We should be able to run your server with node src/server.js

// Imports the express Node module.
var express = require('express');
// Creates an Express server.
var app = express();
var bodyParser = require('body-parser');
// Support receiving JSON in HTTP request bodies
app.use(bodyParser.json());
app.use(bodyParser.text());
app.use(express.static('../client/build'));

//import database functions
var database = require('./database.js');
var readDocument = database.readDocument;
var addDocument = database.addDocument;
var writeDocument = database.writeDocument;
var deleteDocument = database.deleteDocument;

//schemas
var statusUpdateSchema = require('./schemas/statusUpdate.json');
var commentSchema = require('./schemas/comment.json');
var userInfoSchema = require('./schemas/userInfo.json');
var emailChangeSchema = require('./schemas/emailChange.json');
var activitySchema = require('./schemas/activity.json');
var validate = require('express-jsonschema').validate;

//get post feed data
function getPostFeedItemSync(feedItemId){
  var postFeedItem = readDocument("postFeedItems",feedItemId);
  postFeedItem.likeCounter = postFeedItem.likeCounter.map((id)=>readDocument('users', id));
  postFeedItem.contents.author = readDocument('users', postFeedItem.contents.author);

  postFeedItem.comments.forEach((comment)=>{
    comment.author = readDocument('users', comment.author);
  });

  return postFeedItem;
}

function getPostFeedData(user){
  var userData = readDocument('users',user);
  var feedData = readDocument('postFeeds',userData.post);
  feedData.contents = feedData.contents.map(getPostFeedItemSync);
  return feedData;
}

app.get('/user/:userId/feed',function(req,res){
  var userId = parseInt(req.params.userId,10);
  // var fromUser = getUserIdFromToken(req.get('Authorization'));
  // if(userId === fromUser){
    res.send(getPostFeedData(userId));
  // }
  // else{
    // res.status(401).end();
  // }
});

function postStatus(user, text){
  var time = new Date().getTime();

  var post = {
    "likeCounter":[],
    "type": "general",
    "contents": {
      "author": user,
      "postDate": time,
      "text": text,
      "img": null
    },
    "comments":[]
  };

  post = addDocument('postFeedItems',post);

  var userData = readDocument('users',user);
  var postFeedData = readDocument('postFeeds',userData.post);

  postFeedData.contents.unshift(post._id);

  writeDocument('postFeeds', postFeedData);

  return post;
}

//create post
app.post('/postItem', validate({ body: statusUpdateSchema }),function(req,res){
  var body = req.body;
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  if(fromUser === body.userId){
    var newPost = postStatus(body.userId,body.text);
    res.status(201);
    res.send(newPost);
  }
  else{
    res.status(401).end();
  }
});

//like post
app.put('/postItem/:postItemId/likelist/:userId',function(req,res){
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  var postItemId = parseInt(req.params.postItemId,10);
  var userId = parseInt(req.params.userId,10);
  if(userId === fromUser){
    var postFeedItem = readDocument('postFeedItems',postItemId);
    if(postFeedItem.likeCounter.indexOf(userId)===-1){
      postFeedItem.likeCounter.push(userId);
      writeDocument('postFeedItems',postFeedItem);
    }
    res.status(201);
    res.send(postFeedItem.likeCounter.map((id)=>readDocument('users',id)));
  }
  else{
    res.status(401).end();
  }
});

//unlike post
app.delete('/postItem/:postItemId/likelist/:userId',function(req,res){
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  var postItemId = parseInt(req.params.postItemId,10);
  var userId = parseInt(req.params.userId,10);
  if(userId === fromUser){
    var postFeedItem = readDocument('postFeedItems',postItemId);
    var index = postFeedItem.likeCounter.indexOf(userId);
    if(index!==-1){
      postFeedItem.likeCounter.splice(index,1);
      writeDocument('postFeedItems',postFeedItem);
    }
    res.status(201);
    res.send(postFeedItem.likeCounter.map((id)=>readDocument('users',id)));
  }
  else{
    res.status(401).end();
  }

});

//get user data
app.get('/user/:userId',function(req,res){
  // var fromUser = getUserIdFromToken(req.get('Authorization'));
  var userId = parseInt(req.params.userId,10);
  // if(fromUser === userId){
    var userData = readDocument('users',userId);
    userData.friends = userData.friends.map((id)=>readDocument('users',id));
    res.status(201);
    res.send(userData);
  // }
  // else{
    // res.status(401).end();
  // }
});

//post comments
app.post('/postItem/:postItemId/commentThread/comment',validate({body:commentSchema}),
function(req,res){
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  var body = req.body;
  var postItemId = parseInt(req.params.postItemId);
  var userId = body.author;
  if(fromUser === userId){
    var postFeedItem = readDocument('postFeedItems',postItemId);
    postFeedItem.comments.push({
      "author": userId,
      "text": body.text,
      "postDate": (new Date()).getTime()
    });
    writeDocument('postFeedItems',postFeedItem);
    res.status(201);
    res.send(getPostFeedItemSync(postItemId));
  }
  else{
    res.status(401).end();
  }
});

//change user info
app.put('/settings/user/:userId',validate({body:userInfoSchema}),function(req,res){
  var data = req.body;
  var moment = require('moment');
  var userId = parseInt(req.params.userId);
  var fromUser = getUserIdFromToken(req.get('Authorization'));

  if(fromUser == userId){
    var userData = readDocument('users',userId);
    userData.lastname = data.lastname;
    userData.firstname = data.firstname;
    userData.nickname = data.nickname;
    userData.description = data.description;
    userData.location = data.location;
    userData.birthday = moment(data.birthday).valueOf();

    writeDocument('users', userData);
    res.status(201);
    res.send(userData);
  }
  else{
    res.status(401).end();
  }
});

function getActivityFeedItemSync(activityId){
  var activityItem = readDocument('activityItems', activityId);
  activityItem.author = readDocument('users', activityItem.author);
  activityItem.participants = activityItem.participants.map((id) => readDocument('users', id));
  activityItem.likeCounter = activityItem.likeCounter.map((id) => readDocument('users', id));
  activityItem.comments.forEach((comment) => {
    comment.author = readDocument('users', comment.author);
  });

  return activityItem;
}

function getActivityFeedData(user){
  var userData = readDocument('users',user);
  var activityData = readDocument('activities', userData.activity);
  activityData.contents = activityData.contents.map(getActivityFeedItemSync);
  return activityData;
}

app.put('/settings/emailChange/user/:userId',validate({body:emailChangeSchema}),function(req,res){
  var data = req.body;
  var userId = parseInt(req.params.userId);
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  if(fromUser === userId){
    var userData = readDocument('users',userId);
    if(userData.email === data.oldEmail){
      userData.email = data.newEmail;
      writeDocument('users', userData);
      res.send(false);
    }
    else{
      res.send(true);
    }
  }
  else{
    res.statsus(401).end();
  }
});

// get activity Feed data
app.get('/user/:userid/activity', function(req, res) {
  var userId = parseInt(req.params.userid,10);
  // var fromUser = getUserIdFromToken(req.get('Authorization'));
  // if(userId === fromUser){
    res.send(getActivityFeedData(userId));
  // }
  // else{
    // res.status(401).end();
  // }
});

//get activity detail
app.get('/activityItem/:activityId',function(req,res){
  var activityId = parseInt(req.params.activityId);
  var activityData = getActivityFeedItemSync(activityId);
  res.status(201);
  res.send(activityData);
});

//like activity
app.put('/activityItem/:activityId/likelist/:userId',function(req, res){
  var activityId = parseInt(req.params.activityId, 10);
  var userId = parseInt(req.params.userId, 10);
  var activityItem = readDocument('activityItems', activityId);
  if(activityItem.likeCounter.indexOf(userId) === -1){
    activityItem.likeCounter.push(userId);
    writeDocument('activityItems', activityItem);
  }
  res.status(201);
  res.send(activityItem.likeCounter.map((id) => readDocument('users', id)));
});

//unlike activity
app.delete('/activityItem/:activityId/likelist/:userId', function(req, res){
  var activityId = parseInt(req.params.activityId, 10);
  var userId = parseInt(req.params.userId, 10);
  var activityItem = readDocument('activityItems', activityId);
  var index = activityItem.likeCounter.indexOf(userId);
  if(index !== -1){
    activityItem.likeCounter.splice(index, 1);
    writeDocument('activityItems', activityItem);
  }
  res.status(201);
  res.send(activityItem.likeCounter.map((id) => readDocument('users', id)));

});

function getNotificationDataSync(notificationId){
  var notification = readDocument('notificationItems',notificationId);
  if(notification.type === "FR"){
    notification.sender = readDocument("users",notification.sender);
  }
  else{
    notification.author = readDocument("users",notification.author);
  }

  return notification;
}

//get notification
app.get('/user/:userId/notification',function(req,res){
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  var userId = parseInt(req.params.userId);
  if(fromUser === userId){
    var userData = readDocument('users',userId);
    var notificationData = readDocument('notifications',userData.notification);
    notificationData.contents = notificationData.contents.map(getNotificationDataSync);
    res.status(201);
    res.send(notificationData);
  }
  else{
    res.status(401).end();
  }
});

function deleteNotification(id, user){
  var userData = readDocument('users',user);
  var notificationData = readDocument('notifications',userData.notification);
  var index = notificationData.contents.indexOf(id);
  if(index !== -1)
    notificationData.contents.splice(index,1);

  writeDocument("notifications",notificationData);
  deleteDocument("notificationItems",id);
  return notificationData;
}

//acceptRequest
app.put('/notification/:notificationId/:userId',function(req,res){
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  var userId = parseInt(req.params.userId);
  var notificationId = parseInt(req.params.notificationId);
  if(fromUser === userId){
    var userData = readDocument('users',userId);
    var notificationItem = readDocument('notificationItems',notificationId);
    userData.friends.push(notificationItem.sender);
    writeDocument("users",userData);
    res.status(201);
    res.send(deleteNotification(notificationId,userId));
  }
  else{
    res.status(401).end();
  }
});

//deleteNotification
app.delete('/notification/:notificationId/:userId',function(req,res){
  var fromUser = getUserIdFromToken(req.get('Authorization'));
  var userId = parseInt(req.params.userId);
  var notificationId = parseInt(req.params.notificationId);
  if(fromUser === userId){
    res.status(201);
    res.send(deleteNotification(notificationId,userId));
  }
  else{
    res.status(401).end();
  }
});

/**
* Get the user ID from a token. Returns -1 (an invalid ID)
* if it fails.
*/
function getUserIdFromToken(authorizationLine) {
  try {
    // Cut off "Bearer " from the header value.
    var token = authorizationLine.slice(7);
    // Convert the base64 string to a UTF-8 string.
    var regularString = new Buffer(token, 'base64').toString('utf8');
    // Convert the UTF-8 string into a JavaScript object.
    var tokenObj = JSON.parse(regularString);
    var id = tokenObj['id'];
    // Check that id is a number.
    if (typeof id === 'number') {
      return id;
    } else {
      // Not a number. Return -1, an invalid ID.
      return -1;
    }
  } catch (e) {
    // Return an invalid ID.
    return -1;
  }
}

// Reset database.
app.post('/resetdb', function(req, res) {
  console.log("Resetting database...");
  // This is a debug route, so don't do any validation.
  database.resetDatabase();
  // res.send() sends an empty response with status code 200
  res.send();
});

/**
* Translate JSON Schema Validation failures into error 400s.
*/
app.use(function(err, req, res, next) {
  if (err.name === 'JsonSchemaValidation') {
    // Set a bad request http response status
    res.status(400).end();
  } else {
    // It's some other sort of error; pass it to next error middleware handler
    next(err);
  }
});

// Starts the server on port 3000!
app.listen(3000, function () {
  console.log('app listening on port 3000!');
});
<|endoftext|>


<commit_before>// Save a reference to the global object (`window` in the browser, `global`
// on the server).
var root = this;

// The top-level namespace. All public Backbone classes and modules will
// be attached to this. Exported for both CommonJS and the browser.
var Media, server = false;
var PageableCollection = false;
if (typeof exports !== 'undefined') {
    Media = exports;
    server = true;
    var uuid = require('node-uuid');
    PageableCollection = require("backbone-pageable");
} else {
    Media = root.Media = {};
    var uuid = root.uuid;
    PageableCollection = root.Backbone.PageableCollection;
}

// Require Underscore, Backbone & BackboneIO, if we're on the server, and it's not already present.
var _ = root._;
if (!_ && (typeof require !== 'undefined')) _ = require('underscore');

var Backbone = root.Backbone || false;
var BackboneIO = root.BackboneIO;
if ((typeof require !== 'undefined')){
    Backbone = require('backbone');
    Backbone.Memento = function() {};
}

// Require moment
var moment = root.moment || false;
if(typeof require !== 'undefined') {
    moment = require('moment');
}

if ((typeof require !== 'undefined')) require('backbone-relational');

var leadingZero = function (num) {
    return (num < 10) ? "0"+num : num;
}

var toMilliseconds = function (time) {
    if (!time) {
        console.log ("No time");
        return 0;
    }

    var t = time.match(/(\d{2}):(\d{2}):(\d{2})\.(\d*)/);
    t.shift();
    var d = moment.duration ({
        hours:        t[0],
        minutes:      t[1],
        seconds:      t[2],
        milliseconds: t[3]*10
    });

    return d.asMilliseconds();
};

var prettyTime =  function (m) {
    var d = moment.duration(m);
    var p = leadingZero(d.hours())   + ':'
        + leadingZero(d.minutes()) + ':'
        + leadingZero(d.seconds()) + '.'
        + leadingZero(d.milliseconds()/10);
    return p;
};

var arrayDuration = function (a) {
    return  _.reduce(a, function (m, n) {
        return m + toMilliseconds (n);}, 0);
};

var Pageable = {
    state: {
        firstPage: 0,
        currentPage: 0,
        pageSize: 10,
        query: {}
    },
    queryParams: {
        query: function() { return this.state.query; },
    },
};

var Media = {};

Media.Transform = Backbone.RelationalModel.extend({
    urlRoot: 'transform',
    idAttribute: '_id',
    relations: [{
        type: Backbone.HasOne,
        key: 'piece',
        relatedModel:'Media.Piece',
        includeInJSON: '_id',
        reverseRelation: {
            key: 'transform',
            includeInJSON: '_id',
            type: Backbone.HasOne
        }
    },
    {
        type: Backbone.HasOne,
        key: 'playlist',
        relatedModel:'Media.Playlist',
        includeInJSON: '_id',
        reverseRelation: {
            key: 'transform',
            includeInJSON: '_id',
            type: Backbone.HasOne
        }
    },
    {
        type: Backbone.HasOne,
        key: 'occurrence',
        relatedModel:'Media.Occurrence',
        includeInJSON: '_id',
        reverseRelation: {
            key: 'transform',
            includeInJSON: '_id',
            type: Backbone.HasOne
        }
    }],
    defaults: {
        trim: {
            timein:  0,
            timeout: 0,
        },
        overlay: [],
        starts: 0,
        ends: 0,
    },
});

var TransformCollection = {
    model: Media.Transform,
    url: 'transform',
    backend: 'transformbackend',
    initialize: function () {
        if (!server) {
            this.bindBackend();
            this.bind('backend', function(method, model) {
                console.log ('got from backend:', method, model);
            });
        }
        console.log ('creating new Media.TransformCollection');
        Backbone.Collection.prototype.initialize.call (this);
    },
};

Media.TransformCollection = Backbone.Collection.extend(TransformCollection);
Media.TransformCollectionPageable = PageableCollection.extend(_.extend(TransformCollection, Pageable));

Media.Model = Backbone.RelationalModel.extend({
    urlRoot: 'media',
    backend: 'mediabackend',
    idAttribute: '_id',
    initialize: function () {
        console.log ('creating new Media.Model');
    },

    validate: function (attrs) {
        console.log ("checking -> ", attrs);
        if (attrs.file && ! attrs.file.length) {
            console.log ('NO file');
            return new Error("file must be defined");
        }
        if (attrs.stat       &&
            (! attrs.stat.mtime ||
             ! attrs.stat.size  ||
             attrs.stat.size <= 4000)) {
            console.log ('NO or BAD stat');
            return new Error("stat must be defined");
        }
    },
    defaults: {
        _id: '',
        stat: {},
        file: "None",
        name: "",
        audio: "None",
        video: "None",
        template: 'mediaview',
        checksum: "",
        durationraw: "",
        notes: ""
    }
});

var Collection = {
    model: Media.Model,
    url: 'media',
    backend: 'mediabackend',
    initialize: function () {
        if (!server) {
            this.bindBackend();
            this.bind('backend', function(method, model) {
                console.log ('got from backend:', method, model);
            });
        }
        console.log ('creating new Media.Collection');
        Backbone.Collection.prototype.initialize.call (this);
    },
    pretty_duration: function () {
        return prettyTime(arrayDuration(this.pluck('durationraw')));
    },
};

Media.Collection = Backbone.Collection.extend(Collection);
Media.CollectionPageable = PageableCollection.extend(_.extend(Collection, Pageable));

Media.Piece = Media.Model.extend({
    urlRoot: 'piece',
    backend: 'piecebackend',
    idAttribute: '_id',
    initialize: function () {
        console.log ('creating new Media.Piece');
    },
});

var PieceCollection = {
    url: 'piece',
    model: Media.Piece,
    backend: 'piecebackend',
    initialize: function () {
        if (!server) {
            this.bindBackend();
            this.bind('backend', function(method, model) {
                console.log ('got from backend:', method, model);
            });
        }
        console.log ('creating new Media.PieceCollection');
        Backbone.Collection.prototype.initialize.call (this);
    },
};

Media.PieceCollection = Backbone.Collection.extend(PieceCollection);
Media.PieceCollectionPageable = PageableCollection.extend(_.extend(PieceCollection, Pageable));

Media.Playlist = Backbone.RelationalModel.extend({
    urlRoot: 'list',
    backend: 'listbackend', // Makes HasOne relation from Media.Occurrence work.
    idAttribute: '_id',
    relations: [{
        type: Backbone.HasMany,
        key: 'pieces',
        relatedModel: 'Media.Piece',
        collectionType: 'Media.PieceCollection',
        includeInJSON: '_id',
        reverseRelation: {
            key: 'parentPlaylist',
            includeInJSON: '_id',
            type: Backbone.HasOne,
        }
    }],
    initialize: function () {
        var self = this;
        var pieces = this.get('pieces');

        pieces.bind('relational:change relational:add relational:reset relational:remove', function(){
            self.update_duration(self);
        }, this);

        console.log ('creating new Media.Playlist');
        Backbone.RelationalModel.prototype.initialize.call (this);
    },
    update_duration: _.debounce(function (self) {
        self.update_duration_nowait(self.get('pieces'));
    }, 100),
    update_duration_nowait: function(pieces) {
        pieces = pieces || this.get('pieces');
        var durations = pieces.pluck('durationraw');
        var total_duration = arrayDuration(durations);
        var all_ok = _.every(durations);
        console.log("UpdateDuration ~ durationraws:", durations, "total: ", total_duration, " all ok: ", all_ok);
        if (!all_ok) {
            return;
        }
        this.set("duration", total_duration);
    },
    pretty_duration: function () {
        return prettyTime (this.get('duration'));
    },
    defaults: {
        name: null,
        fixed: false,
        duration: 0,
        pos: 0,
    }
});

var Universe = {
    url: 'list',
    model: Media.Playlist,
    backend: 'listbackend',
    comparator: '_id',
    initialize: function () {
        if (!server) {
            this.bindBackend();
            this.bind('backend', function(method, model) {
                console.log ('got from backend:', method, model);
            });
        }
        console.log ('creating new Media.Universe');
        Backbone.Collection.prototype.initialize.call (this);
    },
};

Media.Universe = Backbone.Collection.extend(Universe);
Media.UniversePageable = PageableCollection.extend(_.extend(Universe, Pageable));

Media.Occurrence = Backbone.RelationalModel.extend({
    urlRoot: 'occur',
    idAttribute: '_id',
    relations: [{
        includeInJSON: '_id',
        type: Backbone.HasOne,
        key: 'playlist',
        relatedModel: 'Media.Playlist',
        reverseRelation: {
            key: 'occurrences',
            collectionType: 'Media.Schedule',
            includeInJSON: '_id',
            type: Backbone.HasMany
        }
    }],
    initialize: function () {
        console.log ('creating new Media.Occurrence', this);
        this.overlapsWith = [];
    },
    getOverlappingEvents: function() {
        return this.collection.getOverlappingEvents(this);
    },
    validate: function(attrs, options) {
        // Do not validate when fetching from the server
        if (options.parse) return;
        // Only save model if it's not overlapping with anything
        var self = this;
        overlapping = this.getOverlappingEvents();
        if (overlapping.length) {
            overlapping.forEach(function(oc) {
                oc.overlapsWith.push(self);
            });
            this.collection.trigger('overlap', true);
            return overlapping
        } else {
            // When this event is no longer overlapping, the other events could be valid.
            //   validationError would be unset after this function returns, but I need if before
            //   I call checkOverlap. Could be improved.

            delete this.validationError;
            // Prevent infinite loops by first emptying the list
            var overlapsWith = _.clone(this.overlapsWith);
            this.overlapsWith = [];

            overlapsWith.forEach(function(oc) {
                oc.save();
            });

            if(this.collection) {
                this.collection.checkOverlap();
            }
        }
    },

    defaults: {
        event: null,
    },
});

var Schedule = {
    url: 'occur',
    model: Media.Occurrence,
    backend: 'schedbackend',
    initialize: function () {
        if (!server) {
            this.bindBackend();
            this.bind('backend', function(method, model) {
                console.log ('got from backend:', method, model);
            });
        }
        this.on('add remove', this.checkOverlap);
        console.log ('creating new Media.Schedule');

        this.start_memento();
        this.on('add remove', this.checkOverlap)

        Backbone.Collection.prototype.initialize.call (this);
    },
    start_memento: function() {
        this.memento = new Backbone.Memento(this);
    },
    comparator: "start",
    getInvalid: function() {
        return this.filter(function(oc) {
            return oc.validationError
        });
    },
    checkOverlap: function() {
        var elems = this.getInvalid();
        this.trigger('overlap', elems.length);
    },
    getOverlappingEvents: function(oc) {
        // Get all events that overlap with this one
        return this.filter(function(elem) {
            return (elem.get('_id') != oc.get('_id') &&
                    elem.get('start') < oc.get('end') &&
                    elem.get('end') > oc.get('start'));
        });
    },
    simulateOverlap: function(occurrence, save) {
        var self = this;

        function pusherMapper(pusher) {
            return function(elem) {
                return {
                    pusher: pusher,
                    elem: elem,
                };
            };
        };

        // Processing queue
        var queue = self.getOverlappingEvents(occurrence).map(pusherMapper(occurrence));

        var target;
        while (target = queue.pop()) {
            // Adjust target time
            var duration = target.elem.get("end") - target.elem.get("start");
            target.elem.set({
                start: target.pusher.get("end"),
                end: target.pusher.get("end") + duration,
            });

            if (save) {
                target.elem.save();
            }

            // Check new overlaps and process them first
            var new_overlaps = self.getOverlappingEvents(target.elem).map(pusherMapper(target.elem));
            queue = queue.concat(new_overlaps);
        }
    },
};

Media.Schedule = Backbone.Collection.extend(Schedule);
Media.SchedulePageable = PageableCollection.extend(_.extend(Schedule, Pageable));

Media.Transform.setup();
Media.Model.setup();
Media.Piece.setup();
Media.Playlist.setup();
Media.Occurrence.setup();

if(server) {
    module.exports = Media;
    Backbone.Relational.store.addModelScope({ "Media": Media });
}
else root.Media = Media;
<commit_msg>Adding typeahead prop to collections<commit_after>// Save a reference to the global object (`window` in the browser, `global`
// on the server).
var root = this;

// The top-level namespace. All public Backbone classes and modules will
// be attached to this. Exported for both CommonJS and the browser.
var Media, server = false;
var PageableCollection = false;
if (typeof exports !== 'undefined') {
    Media = exports;
    server = true;
    var uuid = require('node-uuid');
    PageableCollection = require("backbone-pageable");
} else {
    Media = root.Media = {};
    var uuid = root.uuid;
    PageableCollection = root.Backbone.PageableCollection;
}

// Require Underscore, Backbone & BackboneIO, if we're on the server, and it's not already present.
var _ = root._;
if (!_ && (typeof require !== 'undefined')) _ = require('underscore');

var Backbone = root.Backbone || false;
var BackboneIO = root.BackboneIO;
if ((typeof require !== 'undefined')){
    Backbone = require('backbone');
    Backbone.Memento = function() {};
}

// Require moment
var moment = root.moment || false;
if(typeof require !== 'undefined') {
    moment = require('moment');
}

if ((typeof require !== 'undefined')) require('backbone-relational');

var leadingZero = function (num) {
    return (num < 10) ? "0"+num : num;
}

var toMilliseconds = function (time) {
    if (!time) {
        console.log ("No time");
        return 0;
    }

    var t = time.match(/(\d{2}):(\d{2}):(\d{2})\.(\d*)/);
    t.shift();
    var d = moment.duration ({
        hours:        t[0],
        minutes:      t[1],
        seconds:      t[2],
        milliseconds: t[3]*10
    });

    return d.asMilliseconds();
};

var prettyTime =  function (m) {
    var d = moment.duration(m);
    var p = leadingZero(d.hours())   + ':'
        + leadingZero(d.minutes()) + ':'
        + leadingZero(d.seconds()) + '.'
        + leadingZero(d.milliseconds()/10);
    return p;
};

var arrayDuration = function (a) {
    return  _.reduce(a, function (m, n) {
        return m + toMilliseconds (n);}, 0);
};

var Pageable = {
    state: {
        firstPage: 0,
        currentPage: 0,
        pageSize: 10,
        query: {}
    },
    queryParams: {
        query: function() { return this.state.query; },
    },
};

var Media = {};

Media.Transform = Backbone.RelationalModel.extend({
    urlRoot: 'transform',
    idAttribute: '_id',
    relations: [{
        type: Backbone.HasOne,
        key: 'piece',
        relatedModel:'Media.Piece',
        includeInJSON: '_id',
        reverseRelation: {
            key: 'transform',
            includeInJSON: '_id',
            type: Backbone.HasOne
        }
    },
    {
        type: Backbone.HasOne,
        key: 'playlist',
        relatedModel:'Media.Playlist',
        includeInJSON: '_id',
        reverseRelation: {
            key: 'transform',
            includeInJSON: '_id',
            type: Backbone.HasOne
        }
    },
    {
        type: Backbone.HasOne,
        key: 'occurrence',
        relatedModel:'Media.Occurrence',
        includeInJSON: '_id',
        reverseRelation: {
            key: 'transform',
            includeInJSON: '_id',
            type: Backbone.HasOne
        }
    }],
    defaults: {
        trim: {
            timein:  0,
            timeout: 0,
        },
        overlay: [],
        starts: 0,
        ends: 0,
    },
});

var TransformCollection = {
    model: Media.Transform,
    url: 'transform',
    backend: 'transformbackend',
    initialize: function () {
        if (!server) {
            this.bindBackend();
            this.bind('backend', function(method, model) {
                console.log ('got from backend:', method, model);
            });
        }
        console.log ('creating new Media.TransformCollection');
        Backbone.Collection.prototype.initialize.call (this);
    },
};

Media.TransformCollection = Backbone.Collection.extend(TransformCollection);
Media.TransformCollectionPageable = PageableCollection.extend(_.extend(TransformCollection, Pageable));

Media.Model = Backbone.RelationalModel.extend({
    urlRoot: 'media',
    backend: 'mediabackend',
    idAttribute: '_id',
    initialize: function () {
        console.log ('creating new Media.Model');
    },

    validate: function (attrs) {
        console.log ("checking -> ", attrs);
        if (attrs.file && ! attrs.file.length) {
            console.log ('NO file');
            return new Error("file must be defined");
        }
        if (attrs.stat       &&
            (! attrs.stat.mtime ||
             ! attrs.stat.size  ||
             attrs.stat.size <= 4000)) {
            console.log ('NO or BAD stat');
            return new Error("stat must be defined");
        }
    },
    defaults: {
        _id: '',
        stat: {},
        file: "None",
        name: "",
        audio: "None",
        video: "None",
        template: 'mediaview',
        checksum: "",
        durationraw: "",
        notes: ""
    }
});

var Collection = {
    model: Media.Model,
    url: 'media',
    backend: 'mediabackend',
    typeahead: 'stat.name',
    initialize: function () {
        if (!server) {
            this.bindBackend();
            this.bind('backend', function(method, model) {
                console.log ('got from backend:', method, model);
            });
        }
        console.log ('creating new Media.Collection');
        Backbone.Collection.prototype.initialize.call (this);
    },
    pretty_duration: function () {
        return prettyTime(arrayDuration(this.pluck('durationraw')));
    },
};

Media.Collection = Backbone.Collection.extend(Collection);
Media.CollectionPageable = PageableCollection.extend(_.extend(Collection, Pageable));

Media.Piece = Media.Model.extend({
    urlRoot: 'piece',
    backend: 'piecebackend',
    idAttribute: '_id',
    initialize: function () {
        console.log ('creating new Media.Piece');
    },
});

var PieceCollection = {
    url: 'piece',
    model: Media.Piece,
    backend: 'piecebackend',
    initialize: function () {
        if (!server) {
            this.bindBackend();
            this.bind('backend', function(method, model) {
                console.log ('got from backend:', method, model);
            });
        }
        console.log ('creating new Media.PieceCollection');
        Backbone.Collection.prototype.initialize.call (this);
    },
};

Media.PieceCollection = Backbone.Collection.extend(PieceCollection);
Media.PieceCollectionPageable = PageableCollection.extend(_.extend(PieceCollection, Pageable));

Media.Playlist = Backbone.RelationalModel.extend({
    urlRoot: 'list',
    backend: 'listbackend', // Makes HasOne relation from Media.Occurrence work.
    idAttribute: '_id',
    relations: [{
        type: Backbone.HasMany,
        key: 'pieces',
        relatedModel: 'Media.Piece',
        collectionType: 'Media.PieceCollection',
        includeInJSON: '_id',
        reverseRelation: {
            key: 'parentPlaylist',
            includeInJSON: '_id',
            type: Backbone.HasOne,
        }
    }],
    initialize: function () {
        var self = this;
        var pieces = this.get('pieces');

        pieces.bind('relational:change relational:add relational:reset relational:remove', function(){
            self.update_duration(self);
        }, this);

        console.log ('creating new Media.Playlist');
        Backbone.RelationalModel.prototype.initialize.call (this);
    },
    update_duration: _.debounce(function (self) {
        self.update_duration_nowait(self.get('pieces'));
    }, 100),
    update_duration_nowait: function(pieces) {
        pieces = pieces || this.get('pieces');
        var durations = pieces.pluck('durationraw');
        var total_duration = arrayDuration(durations);
        var all_ok = _.every(durations);
        console.log("UpdateDuration ~ durationraws:", durations, "total: ", total_duration, " all ok: ", all_ok);
        if (!all_ok) {
            return;
        }
        this.set("duration", total_duration);
    },
    pretty_duration: function () {
        return prettyTime (this.get('duration'));
    },
    defaults: {
        name: null,
        fixed: false,
        duration: 0,
        pos: 0,
    }
});

var Universe = {
    url: 'list',
    model: Media.Playlist,
    backend: 'listbackend',
    typeahead: 'name',
    comparator: '_id',
    initialize: function () {
        if (!server) {
            this.bindBackend();
            this.bind('backend', function(method, model) {
                console.log ('got from backend:', method, model);
            });
        }
        console.log ('creating new Media.Universe');
        Backbone.Collection.prototype.initialize.call (this);
    },
};

Media.Universe = Backbone.Collection.extend(Universe);
Media.UniversePageable = PageableCollection.extend(_.extend(Universe, Pageable));

Media.Occurrence = Backbone.RelationalModel.extend({
    urlRoot: 'occur',
    idAttribute: '_id',
    relations: [{
        includeInJSON: '_id',
        type: Backbone.HasOne,
        key: 'playlist',
        relatedModel: 'Media.Playlist',
        reverseRelation: {
            key: 'occurrences',
            collectionType: 'Media.Schedule',
            includeInJSON: '_id',
            type: Backbone.HasMany
        }
    }],
    initialize: function () {
        console.log ('creating new Media.Occurrence', this);
        this.overlapsWith = [];
    },
    getOverlappingEvents: function() {
        return this.collection.getOverlappingEvents(this);
    },
    validate: function(attrs, options) {
        // Do not validate when fetching from the server
        if (options.parse) return;
        // Only save model if it's not overlapping with anything
        var self = this;
        overlapping = this.getOverlappingEvents();
        if (overlapping.length) {
            overlapping.forEach(function(oc) {
                oc.overlapsWith.push(self);
            });
            this.collection.trigger('overlap', true);
            return overlapping
        } else {
            // When this event is no longer overlapping, the other events could be valid.
            //   validationError would be unset after this function returns, but I need if before
            //   I call checkOverlap. Could be improved.

            delete this.validationError;
            // Prevent infinite loops by first emptying the list
            var overlapsWith = _.clone(this.overlapsWith);
            this.overlapsWith = [];

            overlapsWith.forEach(function(oc) {
                oc.save();
            });

            if(this.collection) {
                this.collection.checkOverlap();
            }
        }
    },

    defaults: {
        event: null,
    },
});

var Schedule = {
    url: 'occur',
    model: Media.Occurrence,
    backend: 'schedbackend',
    typeahead: 'title',
    initialize: function () {
        if (!server) {
            this.bindBackend();
            this.bind('backend', function(method, model) {
                console.log ('got from backend:', method, model);
            });
        }
        this.on('add remove', this.checkOverlap);
        console.log ('creating new Media.Schedule');

        this.start_memento();
        this.on('add remove', this.checkOverlap)

        Backbone.Collection.prototype.initialize.call (this);
    },
    start_memento: function() {
        this.memento = new Backbone.Memento(this);
    },
    comparator: "start",
    getInvalid: function() {
        return this.filter(function(oc) {
            return oc.validationError
        });
    },
    checkOverlap: function() {
        var elems = this.getInvalid();
        this.trigger('overlap', elems.length);
    },
    getOverlappingEvents: function(oc) {
        // Get all events that overlap with this one
        return this.filter(function(elem) {
            return (elem.get('_id') != oc.get('_id') &&
                    elem.get('start') < oc.get('end') &&
                    elem.get('end') > oc.get('start'));
        });
    },
    simulateOverlap: function(occurrence, save) {
        var self = this;

        function pusherMapper(pusher) {
            return function(elem) {
                return {
                    pusher: pusher,
                    elem: elem,
                };
            };
        };

        // Processing queue
        var queue = self.getOverlappingEvents(occurrence).map(pusherMapper(occurrence));

        var target;
        while (target = queue.pop()) {
            // Adjust target time
            var duration = target.elem.get("end") - target.elem.get("start");
            target.elem.set({
                start: target.pusher.get("end"),
                end: target.pusher.get("end") + duration,
            });

            if (save) {
                target.elem.save();
            }

            // Check new overlaps and process them first
            var new_overlaps = self.getOverlappingEvents(target.elem).map(pusherMapper(target.elem));
            queue = queue.concat(new_overlaps);
        }
    },
};

Media.Schedule = Backbone.Collection.extend(Schedule);
Media.SchedulePageable = PageableCollection.extend(_.extend(Schedule, Pageable));

Media.Transform.setup();
Media.Model.setup();
Media.Piece.setup();
Media.Playlist.setup();
Media.Occurrence.setup();

if(server) {
    module.exports = Media;
    Backbone.Relational.store.addModelScope({ "Media": Media });
}
else root.Media = Media;
<|endoftext|>


<commit_before>import Server from 'socket.io';

export default function startServer(store)
{
    const io = new Server().attach(8090);

    store.subscribe(
        () => io.emit('state', store.getState().toJS())
    );

    io.on('connection', (socket) => {
        socket.emit('state', store.getState().toJS());
        socket.on('action', store.disspatch.bind(store));
    });
}
<commit_msg>Bugfix<commit_after>import Server from 'socket.io';

export default function startServer(store)
{
    const io = new Server().attach(8090);

    store.subscribe(
        () => io.emit('state', store.getState().toJS())
    );

    io.on('connection', (socket) => {
        socket.emit('state', store.getState().toJS());
        socket.on('action', store.dispatch.bind(store));
    });
}
<|endoftext|>


<commit_before>var _ = require('underscore');
var Model = require('../core/model');
var WindshaftFiltersBoundingBoxFilter = require('../windshaft/filters/bounding-box');

/**
 * Default dataview model
 */
module.exports = Model.extend({
  defaults: {
    url: '',
    data: [],
    sync_on_data_change: true,
    sync_on_bbox_change: true,
    enabled: true
  },

  url: function () {
    var params = [];
    if (this.get('boundingBox')) {
      params.push('bbox=' + this.get('boundingBox'));
    }
    return this.get('url') + '?' + params.join('&');
  },

  initialize: function (attrs, opts) {
    attrs = attrs || {};
    opts = opts || {};

    if (!opts.map) {
      throw new Error('map is required');
    }
    if (!opts.windshaftMap) {
      throw new Error('windshaftMap is required');
    }

    if (!attrs.id) {
      this.set('id', this.defaults.type + '-' + this.cid);
    }

    this.layer = opts.layer;
    this._map = opts.map;
    this._windshaftMap = opts.windshaftMap;

    // filter is optional, so have to guard before using it
    this.filter = opts.filter;
    if (this.filter) {
      this.filter.set('dataviewId', this.id);
    }

    this._initBinds();
    this._updateBoundingBox();
  },

  _initBinds: function () {
    this.listenTo(this._windshaftMap, 'instanceCreated', this._onNewWindshaftMapInstance);
    this.listenTo(this.layer, 'change:visible', this._onLayerVisibilityChanged);

    this.listenToOnce(this, 'change:url', function () {
      this.fetch({
        success: this._onChangeBinds.bind(this)
      });
    });

    // Retrigger an event when the filter changes
    if (this.filter) {
      this.listenTo(this.filter, 'change', this._onFilterChanged);
    }
  },

  /**
   * @private
   */
  _onFilterChanged: function () {
    this._reloadMap();
  },

  /**
   * @protected
   */
  _reloadMap: function () {
    this._map.reload({
      sourceLayerId: this.layer.get('id')
    });
  },

  _onNewWindshaftMapInstance: function (windshaftMapInstance, sourceLayerId) {
    var url = windshaftMapInstance.getDataviewURL({
      dataviewId: this.get('id'),
      protocol: 'http'
    });

    if (url) {
      var silent = (sourceLayerId && sourceLayerId !== this.layer.get('id'));

      // TODO: Instead of setting the url here, we could invoke fetch directly
      this.set('url', url, { silent: silent });
    }
  },

  /**
   * Enable/disable the dataview depending on the layer visibility.
   * @private
   * @param  {LayerModel} model the layer model which visible property has changed.
   * @param  {Boolean} value New value for visible.
   * @returns {void}
   */
  _onLayerVisibilityChanged: function (model, value) {
    this.set({enabled: value});
  },

  _onMapBoundsChanged: function () {
    this._updateBoundingBox();
  },

  _updateBoundingBox: function () {
    var boundingBoxFilter = new WindshaftFiltersBoundingBoxFilter(this._map.getViewBounds());
    this.set('boundingBox', boundingBoxFilter.toString());
  },

  _onChangeBinds: function () {
    var BOUNDING_BOX_FILTER_WAIT = 500;
    this.listenTo(this._map, 'change:center change:zoom', _.debounce(this._onMapBoundsChanged.bind(this), BOUNDING_BOX_FILTER_WAIT));

    this.on('change:url', function () {
      if (this._shouldFetchOnURLChange()) {
        this.fetch();
      }
    }, this);
    this.on('change:boundingBox', function () {
      if (this._shouldFetchOnBoundingBoxChange()) {
        this.fetch();
      }
    }, this);

    this.on('change:enabled', function (mdl, isEnabled) {
      if (isEnabled) {
        if (mdl.changedAttributes(this._previousAttrs)) {
          this.fetch();
        }
      } else {
        this._previousAttrs = {
          url: this.get('url'),
          boundingBox: this.get('boundingBox')
        };
      }
    }, this);
  },

  _shouldFetchOnURLChange: function () {
    return this.get('sync_on_data_change') && this.get('enabled');
  },

  _shouldFetchOnBoundingBoxChange: function () {
    return this.get('enabled') && this.get('sync_on_bbox_change');
  },

  refresh: function () {
    this.fetch();
  },

  update: function (attrs) {
    attrs = _.pick(attrs, this.constructor.ATTRS_NAMES);
    this.set(attrs);
  },

  getData: function () {
    return this.get('data');
  },

  getPreviousData: function () {
    return this.previous('data');
  },

  fetch: function (opts) {
    opts = opts || {};
    this.trigger('loading', this);
    return Model.prototype.fetch.call(this, _.extend(opts, {
      error: function () {
        this.trigger('error');
      }.bind(this)
    }));
  },

  toJSON: function () {
    throw new Error('toJSON should be defined for each dataview');
  },

  remove: function () {
    if (this.filter) {
      this.filter.remove();
    }
    this.trigger('destroy', this);
    this.stopListening();
  }
},

  // Class props
  {
    ATTRS_NAMES: [
      'id',
      'sync_on_data_change',
      'sync_on_bbox_change',
      'enabled'
    ]
  }
);
<commit_msg>Moved static var<commit_after>var _ = require('underscore');
var Model = require('../core/model');
var WindshaftFiltersBoundingBoxFilter = require('../windshaft/filters/bounding-box');
var BOUNDING_BOX_FILTER_WAIT = 500;

/**
 * Default dataview model
 */
module.exports = Model.extend({
  defaults: {
    url: '',
    data: [],
    sync_on_data_change: true,
    sync_on_bbox_change: true,
    enabled: true
  },

  url: function () {
    var params = [];
    if (this.get('boundingBox')) {
      params.push('bbox=' + this.get('boundingBox'));
    }
    return this.get('url') + '?' + params.join('&');
  },

  initialize: function (attrs, opts) {
    attrs = attrs || {};
    opts = opts || {};

    if (!opts.map) {
      throw new Error('map is required');
    }
    if (!opts.windshaftMap) {
      throw new Error('windshaftMap is required');
    }

    if (!attrs.id) {
      this.set('id', this.defaults.type + '-' + this.cid);
    }

    this.layer = opts.layer;
    this._map = opts.map;
    this._windshaftMap = opts.windshaftMap;

    // filter is optional, so have to guard before using it
    this.filter = opts.filter;
    if (this.filter) {
      this.filter.set('dataviewId', this.id);
    }

    this._initBinds();
    this._updateBoundingBox();
  },

  _initBinds: function () {
    this.listenTo(this._windshaftMap, 'instanceCreated', this._onNewWindshaftMapInstance);
    this.listenTo(this.layer, 'change:visible', this._onLayerVisibilityChanged);

    this.listenToOnce(this, 'change:url', function () {
      this.fetch({
        success: this._onChangeBinds.bind(this)
      });
    });

    // Retrigger an event when the filter changes
    if (this.filter) {
      this.listenTo(this.filter, 'change', this._onFilterChanged);
    }
  },

  /**
   * @private
   */
  _onFilterChanged: function () {
    this._reloadMap();
  },

  /**
   * @protected
   */
  _reloadMap: function () {
    this._map.reload({
      sourceLayerId: this.layer.get('id')
    });
  },

  _onNewWindshaftMapInstance: function (windshaftMapInstance, sourceLayerId) {
    var url = windshaftMapInstance.getDataviewURL({
      dataviewId: this.get('id'),
      protocol: 'http'
    });

    if (url) {
      var silent = (sourceLayerId && sourceLayerId !== this.layer.get('id'));

      // TODO: Instead of setting the url here, we could invoke fetch directly
      this.set('url', url, { silent: silent });
    }
  },

  /**
   * Enable/disable the dataview depending on the layer visibility.
   * @private
   * @param  {LayerModel} model the layer model which visible property has changed.
   * @param  {Boolean} value New value for visible.
   * @returns {void}
   */
  _onLayerVisibilityChanged: function (model, value) {
    this.set({enabled: value});
  },

  _onMapBoundsChanged: function () {
    this._updateBoundingBox();
  },

  _updateBoundingBox: function () {
    var boundingBoxFilter = new WindshaftFiltersBoundingBoxFilter(this._map.getViewBounds());
    this.set('boundingBox', boundingBoxFilter.toString());
  },

  _onChangeBinds: function () {
    this.listenTo(this._map, 'change:center change:zoom', _.debounce(this._onMapBoundsChanged.bind(this), BOUNDING_BOX_FILTER_WAIT));

    this.on('change:url', function () {
      if (this._shouldFetchOnURLChange()) {
        this.fetch();
      }
    }, this);
    this.on('change:boundingBox', function () {
      if (this._shouldFetchOnBoundingBoxChange()) {
        this.fetch();
      }
    }, this);

    this.on('change:enabled', function (mdl, isEnabled) {
      if (isEnabled) {
        if (mdl.changedAttributes(this._previousAttrs)) {
          this.fetch();
        }
      } else {
        this._previousAttrs = {
          url: this.get('url'),
          boundingBox: this.get('boundingBox')
        };
      }
    }, this);
  },

  _shouldFetchOnURLChange: function () {
    return this.get('sync_on_data_change') && this.get('enabled');
  },

  _shouldFetchOnBoundingBoxChange: function () {
    return this.get('enabled') && this.get('sync_on_bbox_change');
  },

  refresh: function () {
    this.fetch();
  },

  update: function (attrs) {
    attrs = _.pick(attrs, this.constructor.ATTRS_NAMES);
    this.set(attrs);
  },

  getData: function () {
    return this.get('data');
  },

  getPreviousData: function () {
    return this.previous('data');
  },

  fetch: function (opts) {
    opts = opts || {};
    this.trigger('loading', this);
    return Model.prototype.fetch.call(this, _.extend(opts, {
      error: function () {
        this.trigger('error');
      }.bind(this)
    }));
  },

  toJSON: function () {
    throw new Error('toJSON should be defined for each dataview');
  },

  remove: function () {
    if (this.filter) {
      this.filter.remove();
    }
    this.trigger('destroy', this);
    this.stopListening();
  }
},

  // Class props
  {
    ATTRS_NAMES: [
      'id',
      'sync_on_data_change',
      'sync_on_bbox_change',
      'enabled'
    ]
  }
);
<|endoftext|>


<commit_before>var _ = require('underscore');
var Model = require('../core/model');
var BackboneAbortSync = require('../util/backbone-abort-sync');
var WindshaftFiltersBoundingBoxFilter = require('../windshaft/filters/bounding-box');
var BOUNDING_BOX_FILTER_WAIT = 500;

var UNFETCHED_STATUS = 'unfeteched';
var FETCHING_STATUS = 'fetching';
var FETCHED_STATUS = 'fetched';
var FETCH_ERROR_STATUS = 'error';

/**
 * Default dataview model
 */
module.exports = Model.extend({
  defaults: {
    url: '',
    data: [],
    sync_on_data_change: true,
    sync_on_bbox_change: true,
    enabled: true,
    status: UNFETCHED_STATUS
  },

  url: function () {
    var params = _.union(
      [ this._getBoundingBoxFilterParam() ],
      this._getDataviewSpecificURLParams()
    );

    if (this.get('apiKey')) {
      params.push('api_key=' + this.get('apiKey'));
    } else if (this.get('authToken')) {
      var authToken = this.get('authToken');
      if (authToken instanceof Array) {
        _.each(authToken, function (token) {
          params.push('auth_token[]=' + token);
        });
      } else {
        params.push('auth_token=' + authToken);
      }
    }
    return this.get('url') + '?' + params.join('&');
  },

  _getBoundingBoxFilterParam: function () {
    var result = '';
    var boundingBoxFilter;

    if (this.syncsOnBoundingBoxChanges()) {
      boundingBoxFilter = new WindshaftFiltersBoundingBoxFilter(this._getMapViewBounds());
      result = 'bbox=' + boundingBoxFilter.toString();
    }

    return result;
  },

  _getMapViewBounds: function () {
    return this._map.getViewBounds();
  },

  /**
   * Subclasses might override this method to define extra params that will be appended
   * to the dataview's URL.
   * @return {Array} An array of strings in the form of "key=value".
   */
  _getDataviewSpecificURLParams: function () {
    return [];
  },

  initialize: function (attrs, opts) {
    attrs = attrs || {};
    opts = opts || {};

    if (!opts.map) throw new Error('map is required');
    if (!opts.vis) throw new Error('vis is required');
    if (!opts.analysisCollection) throw new Error('analysisCollection is required');
    if (!attrs.source) throw new Error('source is a required attr');

    if (!attrs.id) {
      this.set('id', this.defaults.type + '-' + this.cid);
    }

    this.layer = opts.layer;
    this._map = opts.map;
    this._vis = opts.vis;
    this._analysisCollection = opts.analysisCollection;

    this.sync = BackboneAbortSync.bind(this);

    // filter is optional, so have to guard before using it
    this.filter = opts.filter;
    if (this.filter) {
      this.filter.set('dataviewId', this.id);
    }

    this._initBinds();
    this._setupAnalysisStatusEvents();
  },

  _initBinds: function () {
    this.listenTo(this.layer, 'change:visible', this._onLayerVisibilityChanged);
    this.listenTo(this.layer, 'change:source', this._setupAnalysisStatusEvents);
    this.on('change:source', this._setupAnalysisStatusEvents, this);

    this.listenToOnce(this, 'change:url', function () {
      if (this.syncsOnBoundingBoxChanges() && !this._getMapViewBounds()) {
        // wait until map gets bounds from view
        this._map.on('change:view_bounds_ne', function () {
          this._initialFetch();
        }, this);
      } else {
        this._initialFetch();
      }
    });

    if (this.filter) {
      this.listenTo(this.filter, 'change', this._onFilterChanged);
    }
  },

  _onChangeBinds: function () {
    this.on('change:sync_on_bbox_change', function () {
      this.refresh();
    }, this);

    this.listenTo(this._map, 'change:center change:zoom', _.debounce(this._onMapBoundsChanged.bind(this), BOUNDING_BOX_FILTER_WAIT));

    this.on('change:url', function (model, value, opts) {
      if (this.syncsOnDataChanges()) {
        this._newDataAvailable = true;
      }
      if (this._shouldFetchOnURLChange(opts && _.pick(opts, ['forceFetch', 'sourceId']))) {
        this.fetch();
      }
    }, this);

    this.on('change:enabled', function (mdl, isEnabled) {
      if (isEnabled && this._newDataAvailable) {
        this.fetch();
        this._newDataAvailable = false;
      }
    }, this);
  },

  _onMapBoundsChanged: function () {
    if (this._shouldFetchOnBoundingBoxChange()) {
      this.fetch();
    }

    if (this.syncsOnBoundingBoxChanges()) {
      this._newDataAvailable = true;
    }
  },

  _initialFetch: function () {
    this.fetch({
      success: this._onChangeBinds.bind(this)
    });
  },

  _setupAnalysisStatusEvents: function () {
    this._removeExistingAnalysisBindings();
    this._analysis = this.getSource();
    if (this._analysis) {
      this._analysis.on('change:status', this._onAnalysisStatusChange, this);
    }
  },

  _removeExistingAnalysisBindings: function () {
    if (!this._analysis) return;
    this._analysis.off('change:status', this._onAnalysisStatusChange, this);
  },

  _onAnalysisStatusChange: function (analysis, status) {
    if (analysis.isLoading()) {
      this._triggerLoading();
    } else if (analysis.isFailed()) {
      this._triggerError(analysis.get('error'));
    }
    // loaded will be triggered through the default behavior, so not necessary to react on that status here
  },

  _triggerLoading: function () {
    this.trigger('loading', this);
  },

  _triggerError: function (error) {
    this.trigger('error', this, error);
  },

  /**
   * @protected
   */
  _onFilterChanged: function (filter) {
    this._reloadVis();
  },

  _reloadVis: function (opts) {
    opts = opts || {};
    this._vis.reload(
      _.extend(
        opts, {
          sourceId: this.getSourceId()
        }
      )
    );
  },

  _reloadVisAndForceFetch: function () {
    this._reloadVis({
      forceFetch: true
    });
  },

  /**
   * Enable/disable the dataview depending on the layer visibility.
   * @private
   * @param  {LayerModel} model the layer model which visible property has changed.
   * @param  {Boolean} value New value for visible.
   * @returns {void}
   */
  _onLayerVisibilityChanged: function (model, value) {
    this.set({enabled: value});
  },

  _shouldFetchOnURLChange: function (options) {
    options = options || {};
    var sourceId = options.sourceId;
    var forceFetch = options.forceFetch;

    if (forceFetch) {
      return true;
    }

    return this.isEnabled() &&
      this.syncsOnDataChanges() &&
        this._sourceAffectsMyOwnSource(sourceId);
  },

  _sourceAffectsMyOwnSource: function (sourceId) {
    if (!sourceId) {
      return true;
    }
    var sourceAnalysis = this.getSource();
    return sourceAnalysis && sourceAnalysis.findAnalysisById(sourceId);
  },

  _shouldFetchOnBoundingBoxChange: function () {
    return this.isEnabled() &&
      this.syncsOnBoundingBoxChanges();
  },

  refresh: function () {
    this.fetch();
  },

  update: function (attrs) {
    attrs = _.pick(attrs, this.constructor.ATTRS_NAMES);
    this.set(attrs);
  },

  getData: function () {
    return this.get('data');
  },

  getPreviousData: function () {
    return this.previous('data');
  },

  fetch: function (opts) {
    opts = opts || {};
    this.set('status', FETCHING_STATUS);

    this._triggerLoading();

    if (opts.success) {
      var successCallback = opts && opts.success;
    }

    return Model.prototype.fetch.call(this, _.extend(opts, {
      success: function () {
        this.set('status', FETCHED_STATUS);
        successCallback && successCallback(arguments);
        this.trigger('loaded', this);
      }.bind(this),
      error: function (mdl, err) {
        this.set('status', FETCH_ERROR_STATUS);
        if (!err || (err && err.statusText !== 'abort')) {
          this._triggerError(err);
        }
      }.bind(this)
    }));
  },

  toJSON: function () {
    throw new Error('toJSON should be defined for each dataview');
  },

  getSourceType: function () {
    var sourceAnalysis = this.getSource();
    return sourceAnalysis && sourceAnalysis.get('type');
  },

  getLayerName: function () {
    return this.layer && this.layer.get('layer_name');
  },

  getSource: function () {
    var sourceId = this.getSourceId();
    return sourceId && this._analysisCollection.get(sourceId);
  },

  getSourceId: function () {
    return this.has('source') && this.get('source').id;
  },

  isFiltered: function () {
    var isFiltered = false;
    if (this.filter) {
      isFiltered = !this.filter.isEmpty();
    }
    return isFiltered;
  },

  remove: function () {
    this._removeExistingAnalysisBindings();
    this.trigger('destroy', this);
    this.stopListening();
  },

  isFetched: function () {
    return this.get('status') === FETCHED_STATUS;
  },

  isUnavailable: function () {
    return this.get('status') === FETCH_ERROR_STATUS;
  },

  isEnabled: function () {
    return this.get('enabled');
  },

  syncsOnDataChanges: function () {
    return this.get('sync_on_data_change');
  },

  syncsOnBoundingBoxChanges: function () {
    return this.get('sync_on_bbox_change');
  }
},

  // Class props
{
  ATTRS_NAMES: [
    'id',
    'sync_on_data_change',
    'sync_on_bbox_change',
    'enabled',
    'source'
  ]
}
);
<commit_msg>Add tracking code<commit_after>var _ = require('underscore');
var Model = require('../core/model');
var BackboneAbortSync = require('../util/backbone-abort-sync');
var WindshaftFiltersBoundingBoxFilter = require('../windshaft/filters/bounding-box');
var BOUNDING_BOX_FILTER_WAIT = 500;

var UNFETCHED_STATUS = 'unfeteched';
var FETCHING_STATUS = 'fetching';
var FETCHED_STATUS = 'fetched';
var FETCH_ERROR_STATUS = 'error';

var track = function (error) {
  if (window.trackJs) {
    window.trackJs.track(error);
  }
};

/**
 * Default dataview model
 */
module.exports = Model.extend({
  defaults: {
    url: '',
    data: [],
    sync_on_data_change: true,
    sync_on_bbox_change: true,
    enabled: true,
    status: UNFETCHED_STATUS
  },

  url: function () {
    var params = _.union(
      [ this._getBoundingBoxFilterParam() ],
      this._getDataviewSpecificURLParams()
    );

    if (this.get('apiKey')) {
      params.push('api_key=' + this.get('apiKey'));
    } else if (this.get('authToken')) {
      var authToken = this.get('authToken');
      if (authToken instanceof Array) {
        _.each(authToken, function (token) {
          params.push('auth_token[]=' + token);
        });
      } else {
        params.push('auth_token=' + authToken);
      }
    }
    return this.get('url') + '?' + params.join('&');
  },

  _getBoundingBoxFilterParam: function () {
    var result = '';
    var boundingBoxFilter;

    if (this.syncsOnBoundingBoxChanges()) {
      boundingBoxFilter = new WindshaftFiltersBoundingBoxFilter(this._getMapViewBounds());
      result = 'bbox=' + boundingBoxFilter.toString();
    }

    return result;
  },

  _getMapViewBounds: function () {
    return this._map.getViewBounds();
  },

  /**
   * Subclasses might override this method to define extra params that will be appended
   * to the dataview's URL.
   * @return {Array} An array of strings in the form of "key=value".
   */
  _getDataviewSpecificURLParams: function () {
    return [];
  },

  initialize: function (attrs, opts) {
    attrs = attrs || {};
    opts = opts || {};

    if (!opts.map) throw new Error('map is required');
    if (!opts.vis) throw new Error('vis is required');
    if (!opts.analysisCollection) throw new Error('analysisCollection is required');
    if (!attrs.source) throw new Error('source is a required attr');

    if (!attrs.id) {
      this.set('id', this.defaults.type + '-' + this.cid);
    }

    this.layer = opts.layer;
    this._map = opts.map;
    this._vis = opts.vis;
    this._analysisCollection = opts.analysisCollection;

    this.sync = BackboneAbortSync.bind(this);

    // filter is optional, so have to guard before using it
    this.filter = opts.filter;
    if (this.filter) {
      this.filter.set('dataviewId', this.id);
    }

    this._initBinds();
    this._setupAnalysisStatusEvents();
  },

  _initBinds: function () {
    this.listenTo(this.layer, 'change:visible', this._onLayerVisibilityChanged);
    this.listenTo(this.layer, 'change:source', this._onLayerSourceChanged);
    this.on('change:source', this._onSourceChanged, this);

    this.listenToOnce(this, 'change:url', function () {
      if (this.syncsOnBoundingBoxChanges() && !this._getMapViewBounds()) {
        // wait until map gets bounds from view
        this._map.on('change:view_bounds_ne', function () {
          this._initialFetch();
        }, this);
      } else {
        this._initialFetch();
      }
    });

    if (this.filter) {
      this.listenTo(this.filter, 'change', this._onFilterChanged);
    }
  },

  _onChangeBinds: function () {
    this.on('change:sync_on_bbox_change', function () {
      this.refresh();
    }, this);

    this.listenTo(this._map, 'change:center change:zoom', _.debounce(this._onMapBoundsChanged.bind(this), BOUNDING_BOX_FILTER_WAIT));

    this.on('change:url', function (model, value, opts) {
      if (this.syncsOnDataChanges()) {
        this._newDataAvailable = true;
      }
      if (this._shouldFetchOnURLChange(opts && _.pick(opts, ['forceFetch', 'sourceId']))) {
        this.fetch();
      }
    }, this);

    this.on('change:enabled', function (mdl, isEnabled) {
      if (isEnabled && this._newDataAvailable) {
        this.fetch();
        this._newDataAvailable = false;
      }
    }, this);
  },

  _onMapBoundsChanged: function () {
    if (this._shouldFetchOnBoundingBoxChange()) {
      this.fetch();
    }

    if (this.syncsOnBoundingBoxChanges()) {
      this._newDataAvailable = true;
    }
  },

  _initialFetch: function () {
    this.fetch({
      success: this._onChangeBinds.bind(this)
    });
  },

  _onLayerSourceChanged: function () {
    this._setupAnalysisStatusEvents();
  },

  _onSourceChanged: function (model) {
    var changedKeys = model && model.changed
      ? _.keys(model.changed)
      : '';
    track(new Error('[SOURCE] _onSourceChanged [' + changedKeys + ']'));
    this._setupAnalysisStatusEvents();
  },

  _setupAnalysisStatusEvents: function () {
    this._removeExistingAnalysisBindings();
    this._analysis = this.getSource();
    if (this._analysis) {
      this._analysis.on('change:status', this._onAnalysisStatusChange, this);
    }
  },

  _removeExistingAnalysisBindings: function () {
    if (!this._analysis) return;
    this._analysis.off('change:status', this._onAnalysisStatusChange, this);
  },

  _onAnalysisStatusChange: function (analysis, status) {
    if (analysis.isLoading()) {
      this._triggerLoading();
    } else if (analysis.isFailed()) {
      this._triggerError(analysis.get('error'));
    }
    // loaded will be triggered through the default behavior, so not necessary to react on that status here
  },

  _triggerLoading: function () {
    this.trigger('loading', this);
  },

  _triggerError: function (error) {
    this.trigger('error', this, error);
  },

  /**
   * @protected
   */
  _onFilterChanged: function (filter) {
    this._reloadVis();
  },

  _reloadVis: function (opts) {
    opts = opts || {};
    this._vis.reload(
      _.extend(
        opts, {
          sourceId: this.getSourceId()
        }
      )
    );
  },

  _reloadVisAndForceFetch: function () {
    this._reloadVis({
      forceFetch: true
    });
  },

  /**
   * Enable/disable the dataview depending on the layer visibility.
   * @private
   * @param  {LayerModel} model the layer model which visible property has changed.
   * @param  {Boolean} value New value for visible.
   * @returns {void}
   */
  _onLayerVisibilityChanged: function (model, value) {
    this.set({enabled: value});
  },

  _shouldFetchOnURLChange: function (options) {
    options = options || {};
    var sourceId = options.sourceId;
    var forceFetch = options.forceFetch;

    if (forceFetch) {
      return true;
    }

    return this.isEnabled() &&
      this.syncsOnDataChanges() &&
        this._sourceAffectsMyOwnSource(sourceId);
  },

  _sourceAffectsMyOwnSource: function (sourceId) {
    if (!sourceId) {
      return true;
    }
    var sourceAnalysis = this.getSource();
    return sourceAnalysis && sourceAnalysis.findAnalysisById(sourceId);
  },

  _shouldFetchOnBoundingBoxChange: function () {
    return this.isEnabled() &&
      this.syncsOnBoundingBoxChanges();
  },

  refresh: function () {
    this.fetch();
  },

  update: function (attrs) {
    if (_.has(attrs, 'source')) {
      var message = '[SOURCE] Source present in UPDATE attrs. ' + JSON.stringify(attrs.source);
      track(new Error(message));
    }
    attrs = _.pick(attrs, this.constructor.ATTRS_NAMES);
    this.set(attrs);
  },

  getData: function () {
    return this.get('data');
  },

  getPreviousData: function () {
    return this.previous('data');
  },

  fetch: function (opts) {
    opts = opts || {};
    this.set('status', FETCHING_STATUS);

    this._triggerLoading();

    if (opts.success) {
      var successCallback = opts && opts.success;
    }

    return Model.prototype.fetch.call(this, _.extend(opts, {
      success: function () {
        this.set('status', FETCHED_STATUS);
        successCallback && successCallback(arguments);
        this.trigger('loaded', this);
      }.bind(this),
      error: function (mdl, err) {
        this.set('status', FETCH_ERROR_STATUS);
        if (!err || (err && err.statusText !== 'abort')) {
          this._triggerError(err);
        }
      }.bind(this)
    }));
  },

  toJSON: function () {
    throw new Error('toJSON should be defined for each dataview');
  },

  getSourceType: function () {
    var sourceAnalysis = this.getSource();
    return sourceAnalysis && sourceAnalysis.get('type');
  },

  getLayerName: function () {
    return this.layer && this.layer.get('layer_name');
  },

  getSource: function () {
    var sourceId = this.getSourceId();
    return sourceId && this._analysisCollection.get(sourceId);
  },

  getSourceId: function () {
    return this.has('source') && this.get('source').id;
  },

  isFiltered: function () {
    var isFiltered = false;
    if (this.filter) {
      isFiltered = !this.filter.isEmpty();
    }
    return isFiltered;
  },

  remove: function () {
    this._removeExistingAnalysisBindings();
    this.trigger('destroy', this);
    this.stopListening();
  },

  isFetched: function () {
    return this.get('status') === FETCHED_STATUS;
  },

  isUnavailable: function () {
    return this.get('status') === FETCH_ERROR_STATUS;
  },

  isEnabled: function () {
    return this.get('enabled');
  },

  syncsOnDataChanges: function () {
    return this.get('sync_on_data_change');
  },

  syncsOnBoundingBoxChanges: function () {
    return this.get('sync_on_bbox_change');
  }
},

  // Class props
{
  ATTRS_NAMES: [
    'id',
    'sync_on_data_change',
    'sync_on_bbox_change',
    'enabled',
    'source'
  ]
}
);
<|endoftext|>


<commit_before>'use strict';

var compact       = require('es5-ext/array/#/compact')
  , assign        = require('es5-ext/object/assign')
  , normalizeOpts = require('es5-ext/object/normalize-options')
  , callable      = require('es5-ext/object/valid-callable')
  , compileTpl    = require('es6-template-strings/compile')
  , resolveTpl    = require('es6-template-strings/resolve-to-array')
  , mano          = require('mano')
  , tryRequire    = require('mano/lib/utils/try-require').bind(require)
  , resolve       = require('path').resolve
  , setupTriggers = require('./_setup-triggers')

  , forEach = Array.prototype.forEach, create = Object.create
  , nextTick = process.nextTick
  , configure;

exports = module.exports = [];

configure = function (conf) {
	conf = normalizeOpts(conf);
	conf.text = compileTpl(conf.text);
	if (conf.resolveUser != null) callable(conf.resolveUser);
	conf.variables = Object(conf.variables);
	exports.push(conf);
};

mano.apps.forEach(function (app) {
	var conf = tryRequire(resolve(app.root, 'server/status-log'));
	if (!conf) return;
	forEach.call(conf, configure);
});

exports.forEach(function (conf) {
	var defaultContext = {};
	if (conf.variables) assign(defaultContext, conf.variables);
	setupTriggers(conf, function (target) {
		nextTick(function () {
			var text, businessProcess, context = create(defaultContext), prop, statusLog
			  , official = null;
			if (conf.resolveUser) businessProcess = conf.resolveUser(target);
			else businessProcess = target;
			context.target = target;
			context.user = context.businessProcess = businessProcess;
			if (conf.resolveGetters) {
				for (prop in context) {
					if (typeof context[prop] === 'function') context[prop] = context[prop]();
				}
			}
			text = compact.call(resolveTpl(conf.text, context)).join('');
			statusLog = businessProcess.statusLog.map.newUniq();
			if (conf.official) {
				official = businessProcess.resolveSKeyPath(conf.official);
				if (official) official = official.value;
			}
			statusLog.setProperties({
				label: conf.label,
				official: official,
				time: new Date(Date.now() +
						(conf.timeShift ? (conf.timeShift * 100) : 0)),
				text: text
			});
		});
	});
});
<commit_msg>Fix official set<commit_after>'use strict';

var compact       = require('es5-ext/array/#/compact')
  , assign        = require('es5-ext/object/assign')
  , normalizeOpts = require('es5-ext/object/normalize-options')
  , callable      = require('es5-ext/object/valid-callable')
  , compileTpl    = require('es6-template-strings/compile')
  , resolveTpl    = require('es6-template-strings/resolve-to-array')
  , mano          = require('mano')
  , tryRequire    = require('mano/lib/utils/try-require').bind(require)
  , resolve       = require('path').resolve
  , setupTriggers = require('./_setup-triggers')

  , forEach = Array.prototype.forEach, create = Object.create
  , nextTick = process.nextTick
  , configure;

exports = module.exports = [];

configure = function (conf) {
	conf = normalizeOpts(conf);
	conf.text = compileTpl(conf.text);
	if (conf.resolveUser != null) callable(conf.resolveUser);
	conf.variables = Object(conf.variables);
	exports.push(conf);
};

mano.apps.forEach(function (app) {
	var conf = tryRequire(resolve(app.root, 'server/status-log'));
	if (!conf) return;
	forEach.call(conf, configure);
});

exports.forEach(function (conf) {
	var defaultContext = {};
	if (conf.variables) assign(defaultContext, conf.variables);
	setupTriggers(conf, function (target) {
		nextTick(function () {
			var text, businessProcess, context = create(defaultContext), prop, statusLog
			  , official = null;
			if (conf.resolveUser) businessProcess = conf.resolveUser(target);
			else businessProcess = target;
			context.target = target;
			context.user = context.businessProcess = businessProcess;
			if (conf.resolveGetters) {
				for (prop in context) {
					if (typeof context[prop] === 'function') context[prop] = context[prop]();
				}
			}
			text = compact.call(resolveTpl(conf.text, context)).join('');
			statusLog = businessProcess.statusLog.map.newUniq();
			if (conf.official) {
				official = businessProcess.resolveSKeyPath(conf.official);
				if (official) official = official.value;
			}
			statusLog.setProperties({
				label: conf.label,
				time: new Date(Date.now() +
						(conf.timeShift ? (conf.timeShift * 100) : 0)),
				text: text
			});
			if (official) statusLog.official = official;
		});
	});
});
<|endoftext|>


<commit_before>var fs = require('fs');

var Logger = {
    className: 'Logger',

    /**
     * Syntax:
     * [Time]: [Message]
     */
    log: function(){
        fs.appendFileSync(this.logFile, this.createText(arguments) + "\r\n");
        //console.log.apply(console, arr);
    },

    logArray: function(className, arr){
        fs.appendFileSync(this.logFile, this.createText([className, ':'], arr) + "\r\n");
    },

    createText: function(params, params2){
        params2 = params2 || [];

        var result = ['[', this.getTime(), '] :'];
        for(var i=0; i<params.length; i++){
            result.push(params[i]);
        }
        for(i=0; i<params2.length; i++){
            result.push(params2[i]);
        }
        return result.join(' ');
    },

    sysLog: function(){
        var arr = ['[', this.getTime(), '] :'];
        for(var i =0; i < arguments.length; i++){
            arr.push(arguments[i]);
        }
        console.log.apply(console, arr);
    },

    init: function(){
        var file = this.getFile();
        this.sysLog('Init log file :', file);

        this.logFile = file;

        if(!fs.existsSync(file)){
            console.log(process.cwd());
            console.log(__filename);
            console.log(__dirname);
            var fd = fs.openSync("/app/server/." + file, "a+");
            fs.closeSync(fd);
        }
    },

    getFile: function(index){
        var logName = this.getLogName();
        index = index || 0;
        var fileName = this.getFormattedLogName(logName, index);

        if(!fs.existsSync(fileName)){
            return fileName;
        }

        var stat = fs.statSync(fileName);
        if(stat.size < 1024 * 1024 * 10){
            return fileName;
        }

        return this.getFile(index + 1);
    },

    /**
     * Syntax: dd/mm/YYYY hh:mm:ss
     * @returns {string}
     */
    getTime: function(){
        var d = new Date();
        return d.getDate() + '/' + d.getMonth() + '/' + d.getFullYear() + ' '
            + d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds();
    },

    getFormattedLogName: function(logName, index){
        if(index < 1){
            return 'log/' + logName + '.log';
        }
        return 'log/' + logName + '-' + index + '.log';
    },

    getLogName: function(){
        var d = new Date();

        return d.getDate() + '-' + d.getMonth() + '-' + d.getFullYear();
    }
};

var compile = require('./compile.js');
module.exports = compile.singleton(Logger, null, true);
<commit_msg>fix crashing<commit_after>var fs = require('fs');

var Logger = {
    className: 'Logger',

    /**
     * Syntax:
     * [Time]: [Message]
     */
    log: function(){
        fs.appendFileSync(this.logFile, this.createText(arguments) + "\r\n");
        //console.log.apply(console, arr);
    },

    logArray: function(className, arr){
        fs.appendFileSync(this.logFile, this.createText([className, ':'], arr) + "\r\n");
    },

    createText: function(params, params2){
        params2 = params2 || [];

        var result = ['[', this.getTime(), '] :'];
        for(var i=0; i<params.length; i++){
            result.push(params[i]);
        }
        for(i=0; i<params2.length; i++){
            result.push(params2[i]);
        }
        return result.join(' ');
    },

    sysLog: function(){
        var arr = ['[', this.getTime(), '] :'];
        for(var i =0; i < arguments.length; i++){
            arr.push(arguments[i]);
        }
        console.log.apply(console, arr);
    },

    init: function(){
        var file = this.getFile();
        this.sysLog('Init log file :', file);

        this.logFile = file;

        if(!fs.existsSync(file)){
            console.log(process.cwd());
            console.log(__filename);
            console.log(__dirname);
            var fd = fs.openSync(file.replace('log/', 'tmp/'), "a+");
            fs.closeSync(fd);
        }
    },

    getFile: function(index){
        var logName = this.getLogName();
        index = index || 0;
        var fileName = this.getFormattedLogName(logName, index);

        if(!fs.existsSync(fileName)){
            return fileName;
        }

        var stat = fs.statSync(fileName);
        if(stat.size < 1024 * 1024 * 10){
            return fileName;
        }

        return this.getFile(index + 1);
    },

    /**
     * Syntax: dd/mm/YYYY hh:mm:ss
     * @returns {string}
     */
    getTime: function(){
        var d = new Date();
        return d.getDate() + '/' + d.getMonth() + '/' + d.getFullYear() + ' '
            + d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds();
    },

    getFormattedLogName: function(logName, index){
        if(index < 1){
            return 'log/' + logName + '.log';
        }
        return 'log/' + logName + '-' + index + '.log';
    },

    getLogName: function(){
        var d = new Date();

        return d.getDate() + '-' + d.getMonth() + '-' + d.getFullYear();
    }
};

var compile = require('./compile.js');
module.exports = compile.singleton(Logger, null, true);
<|endoftext|>