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

var UserActivity = require('../models/UserActivity');
var moment = require('moment');
var util = require('util');

router.get('/cal', function(req, res, next) {
  res.json(['2015-06-02', '2015-06-04', '2015-06-09']);
});

router.get('/news', function(req, res) {
  res.json([
      {
        content: '헬스 휘트니스 옷장과 화장대 내 무단 보관된 사물은 내일 폐기합니다.',
        date: '2015-05-18'
      },
      {
        content: '기간 연장은 입원치료등 서류 제출시 가능하며, 여행등은 해당되지 않습니다.',
        date: '2015-05-15'
      },
      {
        content: '회원들께서는 휘트니스 이용수칙을 잘 지켜주시기 바랍니다. 감사합니다.',
        date: '2015-05-08'
      },
      {
        content: '재등록하셔서 다시 운동하는 모습으로 뵙기를 바랍니다. ^^',
        date: '2015-05-04'
      }
    ]);
});

router.get('/profile', function(req, res) {
  res.json({
    name: '구재성',
    image: '/images/flat-avatar.png'
  })
});

router.get('/today', function(req, res) {
  var dummy = {
    time: 50,
    timeBase: 60,
    distance: 4,
    distanceBase: 5,
    calory: 1000,
    caloryBase: 1500,
    goal: 'distance'
  };

  UserActivity.find({ datetime: { $gt: moment().startOf('d').toDate() } }, function(err, activities) {
    if (err) res.status(500).json(err);
    else {
      activities.forEach(function(activity) {
        dummy.time += activity.time;
        dummy.distance += activity.distance;
        dummy.calory += activity.calory;
      });

      res.json(dummy);
    }
  });
});

router.get('/activity', function(req, res) {
  res.json([
      {
        name: 'Walking / Running',
        type: 'aerobic',
        id: 0
      },
      {
        name: 'Biking',
        type: 'aerobic',
        id: 1
      },
      {
        name: 'Aerobics',
        type: 'aerobic',
        id: 2
      },
      {
        name: 'Yoga',
        type: 'aerobic',
        id: 3
      }
    ]);
});

router.get('/body', function(req, res) {
  res.json([
      {
        name: 'Weight',
        unit: 'kg',
        id: 0
      },
      {
        name: 'Lean Body Mass',
        unit: 'kg',
        id: 1
      },
      {
        name: 'Body Fat Percent',
        unit: '%',
        id: 2
      },
      {
        name: 'Body Mass Index',
        unit: 'BMI',
        id: 3
      },
      {
        name: 'Height',
        unit: 'cm',
        id: 4
      }
    ]);
});

// date must be sorted by ascending
router.get('/activity/data', function(req, res) {
  var dummy = [
    {
      date: '2015-06-01',
      activity_id: 0,
      distance: 5,
      time: 40,
      calory: 1000
    },
    {
      date: '2015-06-01',
      activity_id: 1,
      distance: 5,
      time: 20,
      calory: 500
    },
    {
      date: '2015-06-01',
      activity_id: 0,
      distance: 2,
      time: 10,
      calory: 200
    },
    {
      date: '2015-06-02',
      activity_id: 0,
      distance: 3,
      time: 20,
      calory: 400
    },
    {
      date: '2015-06-02',
      activity_id: 3,
      distance: 2,
      time: 10,
      calory: 300
    },
    {
      date: '2015-06-05',
      activity_id: 3,
      distance: 6,
      time: 10,
      calory: 300
    },
    {
      date: '2015-06-08',
      activity_id: 2,
      distance: 1,
      time: 3,
      calory: 120
    },
    {
      date: '2015-06-15',
      activity_id: 0,
      distance: 15,
      time: 50,
      calory: 1000
    }
  ];

  var query = UserActivity.find();
  query.sort('datetime');
  query.exec(function(err, activities) {
    if (err) res.status(500).json(err);
    else {
      activities.forEach(function(activityModel) {
        var activity = activityModel.toJSON();
        activity.date = moment(activity.datetime).format('YYYY-MM-DD');
        dummy.push(activity);
      });
      res.json(dummy);
    }
  });
});

router.get('/body/data', function(req, res) {
  res.json([
    {
      date: '2015-06-01',
      body_id: 4,
      value: 161
    },
    {
      date: '2015-06-02',
      body_id: 4,
      value: 162
    },
    {
      date: '2015-06-15',
      body_id: 4,
      value: 163
    },
    {
      date: '2015-06-01',
      body_id: 0,
      value: 60
    },
    {
      date: '2015-06-02',
      body_id: 0,
      value: 59
    },
    {
      date: '2015-06-03',
      body_id: 0,
      value: 61
    },
    {
      date: '2015-06-04',
      body_id: 0,
      value: 63
    }
  ]);
});

router.post('/activity', function(req, res) {
  // TODO validate request data
  // TODO check if duplicate

  req.body.datetime = moment(req.body.datetime).toDate();

  new UserActivity(req.body).save(function(err) {
    if (err) {
      res.json(500, err);
    } else {
      res.sendStatus(204);
    }
  });
});

module.exports = router;
<commit_msg>calendar data from db<commit_after>var express = require('express');
var router = express.Router();

var UserActivity = require('../models/UserActivity');
var moment = require('moment');
var util = require('util');

router.get('/cal', function(req, res, next) {
  var dummy = ['2015-06-01', '2015-06-02', '2015-06-05', '2015-06-08', '2015-06-15'];

  UserActivity.find().lean().exec(function(err, result) {
    if (err) res.status(500).json(err);
    else {
      result.forEach(function(activity) {
        dummy.push(moment(activity.datetime).format('YYYY-MM-DD'));
      });
      res.json(dummy);
    }
  });
});

router.get('/news', function(req, res) {
  res.json([
      {
        content: '헬스 휘트니스 옷장과 화장대 내 무단 보관된 사물은 내일 폐기합니다.',
        date: '2015-05-18'
      },
      {
        content: '기간 연장은 입원치료등 서류 제출시 가능하며, 여행등은 해당되지 않습니다.',
        date: '2015-05-15'
      },
      {
        content: '회원들께서는 휘트니스 이용수칙을 잘 지켜주시기 바랍니다. 감사합니다.',
        date: '2015-05-08'
      },
      {
        content: '재등록하셔서 다시 운동하는 모습으로 뵙기를 바랍니다. ^^',
        date: '2015-05-04'
      }
    ]);
});

router.get('/profile', function(req, res) {
  res.json({
    name: '구재성',
    image: '/images/flat-avatar.png'
  })
});

router.get('/today', function(req, res) {
  var dummy = {
    time: 50,
    timeBase: 60,
    distance: 4,
    distanceBase: 5,
    calory: 1000,
    caloryBase: 1500,
    goal: 'distance'
  };

  UserActivity.find({ datetime: { $gt: moment().startOf('d').toDate() } }, function(err, activities) {
    if (err) res.status(500).json(err);
    else {
      activities.forEach(function(activity) {
        dummy.time += activity.time;
        dummy.distance += activity.distance;
        dummy.calory += activity.calory;
      });

      res.json(dummy);
    }
  });
});

router.get('/activity', function(req, res) {
  res.json([
      {
        name: 'Walking / Running',
        type: 'aerobic',
        id: 0
      },
      {
        name: 'Biking',
        type: 'aerobic',
        id: 1
      },
      {
        name: 'Aerobics',
        type: 'aerobic',
        id: 2
      },
      {
        name: 'Yoga',
        type: 'aerobic',
        id: 3
      }
    ]);
});

router.get('/body', function(req, res) {
  res.json([
      {
        name: 'Weight',
        unit: 'kg',
        id: 0
      },
      {
        name: 'Lean Body Mass',
        unit: 'kg',
        id: 1
      },
      {
        name: 'Body Fat Percent',
        unit: '%',
        id: 2
      },
      {
        name: 'Body Mass Index',
        unit: 'BMI',
        id: 3
      },
      {
        name: 'Height',
        unit: 'cm',
        id: 4
      }
    ]);
});

// date must be sorted by ascending
router.get('/activity/data', function(req, res) {
  var dummy = [
    {
      date: '2015-06-01',
      activity_id: 0,
      distance: 5,
      time: 40,
      calory: 1000
    },
    {
      date: '2015-06-01',
      activity_id: 1,
      distance: 5,
      time: 20,
      calory: 500
    },
    {
      date: '2015-06-01',
      activity_id: 0,
      distance: 2,
      time: 10,
      calory: 200
    },
    {
      date: '2015-06-02',
      activity_id: 0,
      distance: 3,
      time: 20,
      calory: 400
    },
    {
      date: '2015-06-02',
      activity_id: 3,
      distance: 2,
      time: 10,
      calory: 300
    },
    {
      date: '2015-06-05',
      activity_id: 3,
      distance: 6,
      time: 10,
      calory: 300
    },
    {
      date: '2015-06-08',
      activity_id: 2,
      distance: 1,
      time: 3,
      calory: 120
    },
    {
      date: '2015-06-15',
      activity_id: 0,
      distance: 15,
      time: 50,
      calory: 1000
    }
  ];

  var query = UserActivity.find();
  query.sort('datetime');
  query.exec(function(err, activities) {
    if (err) res.status(500).json(err);
    else {
      activities.forEach(function(activityModel) {
        var activity = activityModel.toJSON();
        activity.date = moment(activity.datetime).format('YYYY-MM-DD');
        dummy.push(activity);
      });
      res.json(dummy);
    }
  });
});

router.get('/body/data', function(req, res) {
  res.json([
    {
      date: '2015-06-01',
      body_id: 4,
      value: 161
    },
    {
      date: '2015-06-02',
      body_id: 4,
      value: 162
    },
    {
      date: '2015-06-15',
      body_id: 4,
      value: 163
    },
    {
      date: '2015-06-01',
      body_id: 0,
      value: 60
    },
    {
      date: '2015-06-02',
      body_id: 0,
      value: 59
    },
    {
      date: '2015-06-03',
      body_id: 0,
      value: 61
    },
    {
      date: '2015-06-04',
      body_id: 0,
      value: 63
    }
  ]);
});

router.post('/activity', function(req, res) {
  // TODO validate request data
  // TODO check if duplicate

  req.body.datetime = moment(req.body.datetime).toDate();

  new UserActivity(req.body).save(function(err) {
    if (err) {
      res.json(500, err);
    } else {
      res.sendStatus(204);
    }
  });
});

module.exports = router;
<|endoftext|>


<commit_before>var util = require('util'),
  redis = require('redis'),
  async = require('async'),
  RedisShard = require('redis-shard');

module.exports = function RedisManager(config) {

  var self = {};
  var clients = [];
  var masterAddr;
  var hasSlaveNode = false;

  if (config) {
    if (typeof config === 'string' || config instanceof String) {
      masterAddr = config;

    } else {

      if (config.address) {
        if (config.address.master) {
          masterAddr = config.address.master;
        } else {
          masterAddr = config.address;
        }

        hasSlaveNode = config.address && config.address.slave;
      }

    }
  }

  if(!masterAddr) masterAddr = "127.0.0.1:6379";

  var client = redis.createClient(masterAddr.split(':')[1], masterAddr.split(':')[0]);
  clients.push(client);

  var shardedClient;

  if (hasSlaveNode) {
    var options = {servers: config.address.slave};
    shardedClient = new RedisShard(options);
    clients.push(shardedClient);
  }

  var WRITES = [
    "del", "publish", "subscribe", "hset", "hdel", "set", "expire", "hmset", "sadd", "smembers", "hsetnx", "incr", "decr", "hincrby"
  ];

  WRITES.forEach(function (command) {
    self[command] = function () {
      client[command].apply(client, arguments);
    };
  });

  var READS = [
    "hget", "hgetall", "get", "hlen", "hscan", "hexists", "mget", "exists"
  ];

  READS.forEach(function (command) {
    self[command] = function () {
      if (shardedClient) {
        shardedClient[command].apply(client, arguments);
      } else {
        client[command].apply(client, arguments);
      }
    };
  });

  self.on = function (event, listener) {
    clients.forEach(function (c) {
      c.on(event, function () {
        // append server as last arg passed to listener
        var args = Array.prototype.slice.call(arguments);
        listener.apply(undefined, args);
      });
    });
  };

  // Note: listener will fire once per shard, not once per cluster
  self.once = function (event, listener) {

    async.parallel(
      [
        function (callback) {
          client.once(event, function () {
            callback(undefined, 'one');
          });
        },
        function (callback) {
          if (hasSlaveNode) {
            var connected = 0;
            shardedClient.once(event, function () {
              connected++;
              if (connected == config.address.slave.length) {
                callback(undefined, 'two');
              }
            });
          } else {
            callback(undefined, 'two');
          }
        }
      ],
      function (err, results) {
        var args = Array.prototype.slice.call(arguments).concat("result");
        listener.apply(undefined, args);
      }
    );
  };

  return self;
};
<commit_msg>add redis commands<commit_after>var util = require('util'),
  redis = require('redis'),
  async = require('async'),
  RedisShard = require('redis-shard');

module.exports = function RedisManager(config) {

  var self = {};
  var clients = [];
  var masterAddr;
  var hasSlaveNode = false;

  if (config) {
    if (typeof config === 'string' || config instanceof String) {
      masterAddr = config;

    } else {

      if (config.address) {
        if (config.address.master) {
          masterAddr = config.address.master;
        } else {
          masterAddr = config.address;
        }

        hasSlaveNode = config.address && config.address.slave;
      }

    }
  }

  if(!masterAddr) masterAddr = "127.0.0.1:6379";

  var client = redis.createClient(masterAddr.split(':')[1], masterAddr.split(':')[0]);
  clients.push(client);

  var shardedClient;

  if (hasSlaveNode) {
    var options = {servers: config.address.slave};
    shardedClient = new RedisShard(options);
    clients.push(shardedClient);
  }

  var WRITES = [
    "del", "publish", "subscribe", "hset", "hdel", "set", "expire", "hmset", "sadd", "smembers", "hsetnx", "incr", "decr", "hincrby", "lpush", "lrem"
  ];

  WRITES.forEach(function (command) {
    self[command] = function () {
      client[command].apply(client, arguments);
    };
  });

  var READS = [
    "hget", "hgetall", "get", "hlen", "hscan", "hexists", "mget", "exists", "rpop", "llen"
  ];

  READS.forEach(function (command) {
    self[command] = function () {
      if (shardedClient) {
        shardedClient[command].apply(client, arguments);
      } else {
        client[command].apply(client, arguments);
      }
    };
  });

  self.on = function (event, listener) {
    clients.forEach(function (c) {
      c.on(event, function () {
        // append server as last arg passed to listener
        var args = Array.prototype.slice.call(arguments);
        listener.apply(undefined, args);
      });
    });
  };

  // Note: listener will fire once per shard, not once per cluster
  self.once = function (event, listener) {

    async.parallel(
      [
        function (callback) {
          client.once(event, function () {
            callback(undefined, 'one');
          });
        },
        function (callback) {
          if (hasSlaveNode) {
            var connected = 0;
            shardedClient.once(event, function () {
              connected++;
              if (connected == config.address.slave.length) {
                callback(undefined, 'two');
              }
            });
          } else {
            callback(undefined, 'two');
          }
        }
      ],
      function (err, results) {
        var args = Array.prototype.slice.call(arguments).concat("result");
        listener.apply(undefined, args);
      }
    );
  };

  return self;
};
<|endoftext|>


<commit_before>'use strict'

const { Router } = require('express')
const router = Router()

const session = require('../controllers/session')

router.post('/register', session.register)

module.exports = router<commit_msg>added login route to routes index.js<commit_after>'use strict'

const { Router } = require('express')
const router = Router()

const session = require('../controllers/session')

router.post('/register', session.register)

router.post('/login', session.login)

module.exports = router<|endoftext|>


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

// This is returned as the module
var indexRoute = {
    changePage: null,
    router: router
}

router.route('/')
    .get(function (req, res) {
        res.render('main/index', {
            pageId: "Home",
            pageTitle: "Home Control",
            pageDescription: "Home Control's landing page.",
            pageCss: ['main'],
            pageScripts: ['dummyScript'],
            useBootstrap: true
        });
    });

router.route('/switcher')
    .get(isLoggedIn, function (req, res) {

        if (!req.cookies.deviceName) {
            res.redirect('/device');
        }

        res.render('main/switcher', {
            pageId: "Switcher",
            pageTitle: "Home Control Switcher",
            pageDescription: "Home Control's switcher page.",
            pageCss: ['main'],
            pageScripts: ['switcher'],
            useBootstrap: true,
            useSocket: true,
            userID: req.session.passport.user
        });
    });

router.route('/viewer')
    .get(isLoggedIn, function (req, res) {

        if (!req.cookies.deviceName) {
            res.redirect('/device');
            return;
        }

        res.render('main/viewer', {
            pageId: "Viewer",
            pageTitle: "Home Control",
            pageDescription: "Home Control's viewing page.",
            pageCss: ['main'],
            pageScripts: ['viewer'],
            useBootstrap: true,
            useSocket: true,
            userID: req.session.passport.user
        });
    });

router.post('/switch', function(req, res) {
    let action = req.body.result.action;

    // Show page intent
    if (action === 'show_page') {
        let page = req.body.result.parameters.page;
        let devices = req.body.result.parameters.devices;
        indexRoute.changePage(page, devices);
        let speech = "Showing " + page;
        if (devices) {
            speech += " on ";
            devices.forEach(function(device, index) {
                if (index === devices.length - 1 && devices.length !== 1) {
                    speech += ", and " + device;
                } else {
                    speech += ", " + device;
                }
            });
        }
        res.json({
            "speech": speech,
            "displayText": speech,
            "source": "home.carlschriever.com",
            "data": {
                "google": {
                    "expect_user_response": false,
                }
            }
        });
    } else if (action === 'show_weather') {
        let location = req.body.result.parameters.location || 'Atlanta';
        indexRoute.changePage('weather/' + location);
        res.json({
            "speech": "Showing weather for " + location,
            "displayText": "Showing weather for " + location,
            "source": "home.carlschriever.com",
            "data": {
                "google": {
                    "expect_user_response": false,
                }
            }
        });
    } else if (action === 'activate_button') {
        let button = req.body.result.parameters.button_id;
        res.json({
            "speech": "Pressing " + button,
            "displayText": "Pressing " + button,
            "source": "home.carlschriever.com",
            "data": {
                "google": {
                    "expect_user_response": false,
                }
            }
        });
    } else if (action === 'show_cheat_sheet') {
        let page = 'cheatsheet/' + req.body.result.parameters.cheatsheet;
        let devices = req.body.result.parameters.devices;
        indexRoute.changePage(page, devices);
        let speech = "Showing " + page;
        if (devices) {
            speech += " on ";
            devices.forEach(function(device, index) {
                if (index === devices.length - 1 && devices.length !== 1) {
                    speech += ", and " + device;
                } else {
                    speech += ", " + device;
                }
            });
        }
        res.json({
            "speech": speech,
            "displayText": speech,
            "source": "home.carlschriever.com",
            "data": {
                "google": {
                    "expect_user_response": false,
                }
            }
        });
    }
});

function isLoggedIn(req, res, next) {
    if (req.isAuthenticated()) {
        return next();
    }
    res.redirect('/user/login');
}

module.exports = function(changePage) {
    indexRoute.changePage = changePage;

    return indexRoute;
};<commit_msg>Fixed speech for multiple devices<commit_after>var express = require('express');
var router = express.Router();
var path = require('path')

// This is returned as the module
var indexRoute = {
    changePage: null,
    router: router
}

router.route('/')
    .get(function (req, res) {
        res.render('main/index', {
            pageId: "Home",
            pageTitle: "Home Control",
            pageDescription: "Home Control's landing page.",
            pageCss: ['main'],
            pageScripts: ['dummyScript'],
            useBootstrap: true
        });
    });

router.route('/switcher')
    .get(isLoggedIn, function (req, res) {

        if (!req.cookies.deviceName) {
            res.redirect('/device');
        }

        res.render('main/switcher', {
            pageId: "Switcher",
            pageTitle: "Home Control Switcher",
            pageDescription: "Home Control's switcher page.",
            pageCss: ['main'],
            pageScripts: ['switcher'],
            useBootstrap: true,
            useSocket: true,
            userID: req.session.passport.user
        });
    });

router.route('/viewer')
    .get(isLoggedIn, function (req, res) {

        if (!req.cookies.deviceName) {
            res.redirect('/device');
            return;
        }

        res.render('main/viewer', {
            pageId: "Viewer",
            pageTitle: "Home Control",
            pageDescription: "Home Control's viewing page.",
            pageCss: ['main'],
            pageScripts: ['viewer'],
            useBootstrap: true,
            useSocket: true,
            userID: req.session.passport.user
        });
    });

router.post('/switch', function(req, res) {
    let action = req.body.result.action;

    // Show page intent
    if (action === 'show_page') {
        let page = req.body.result.parameters.page;
        let devices = req.body.result.parameters.devices;
        indexRoute.changePage(page, devices);
        let speech = "Showing " + page;
        if (devices) {
            speech +=  listDevices(devices);
        }
        res.json({
            "speech": speech,
            "displayText": speech,
            "source": "home.carlschriever.com",
            "data": {
                "google": {
                    "expect_user_response": false,
                }
            }
        });
    } else if (action === 'show_weather') {
        let location = req.body.result.parameters.location || 'Atlanta';
        indexRoute.changePage('weather/' + location);
        res.json({
            "speech": "Showing weather for " + location,
            "displayText": "Showing weather for " + location,
            "source": "home.carlschriever.com",
            "data": {
                "google": {
                    "expect_user_response": false,
                }
            }
        });
    } else if (action === 'activate_button') {
        let button = req.body.result.parameters.button_id;
        res.json({
            "speech": "Pressing " + button,
            "displayText": "Pressing " + button,
            "source": "home.carlschriever.com",
            "data": {
                "google": {
                    "expect_user_response": false,
                }
            }
        });
    } else if (action === 'show_cheat_sheet') {
        let page = 'cheatsheet/' + req.body.result.parameters.cheatsheet;
        let devices = req.body.result.parameters.devices;
        indexRoute.changePage(page, devices);
        let speech = "Showing " + page;
        if (devices) {
            speech +=  listDevices(devices);
        }
        res.json({
            "speech": speech,
            "displayText": speech,
            "source": "home.carlschriever.com",
            "data": {
                "google": {
                    "expect_user_response": false,
                }
            }
        });
    }
});

function isLoggedIn(req, res, next) {
    if (req.isAuthenticated()) {
        return next();
    }
    res.redirect('/user/login');
}

function listDevice() {
    let speech = " on ";
    devices.forEach(function(device, index) {
        if (index == 0) {
            speech += " " + device;
        } else if (index === devices.length - 1 && devices.length !== 1) {
            speech += ", and " + device;
        } else {
            speech += ", " + device;
        }
    });
    return speech;
}

module.exports = function(changePage) {
    indexRoute.changePage = changePage;

    return indexRoute;
};<|endoftext|>


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

// module.exports = function(app, passport) {
//   app.post('/login', passport.authenticate('local', {
//     successReturnToOrRedirect: './',
//     failureRedirect: '../login'
//   }));
// };

module.exports = function(app, protect){
  app.get('/login$', function(req, res, next){
    // handled by express.static after this
    return res.redirect('./login/');
  });

  app.post('/login', function(req, res, next) {
    passport.authenticate('local', function(err, user, info) {
      console.log({ err, user, info });
      if (err) { return next(err); }
      if (!user) {
        if (/json/.test(req.headers.accept)) {
          res.json({ status: 'no user' });
          return;
        }
        return res.redirect('./login');
      }
      req.logIn(user, function(err) {
        if (err) { return next(err); }

        if (/json/.test(req.headers.accept)) {
          res.json({ status: 'logged in' });
          return;
        }

        return res.redirect('./');
      });
    })(req, res, next);
  });
};
<commit_msg>Revert "troubleshooting auth"<commit_after>var passport = require('passport');

// module.exports = function(app, passport) {
//   app.post('/login', passport.authenticate('local', {
//     successReturnToOrRedirect: './',
//     failureRedirect: '../login'
//   }));
// };

module.exports = function(app, protect){
  app.get('/login$', function(req, res, next){
    // handled by express.static after this
    return res.redirect('./login/');
  });

  app.post('/login', function(req, res, next) {
    passport.authenticate('local', function(err, user, info) {
      if (err) { return next(err); }
      if (!user) {
        if (/json/.test(req.headers.accept)) {
          res.json({ status: 'no user' });
          return;
        }
        return res.redirect('./login');
      }
      req.logIn(user, function(err) {
        if (err) { return next(err); }

        if (/json/.test(req.headers.accept)) {
          res.json({ status: 'logged in' });
          return;
        }

        return res.redirect('./');
      });
    })(req, res, next);
  });
};
<|endoftext|>


<commit_before>/*
 * ChanChan Orion REST API
 */

var utils = require('../utils');
var orion_url = "orion"; // To be changed to PEP for auth

// Return the list of available entities in Orion
exports.contexts = function(req, res) {
    // TODO: Check auth
    // Is it possible to get all contexts from the API?
    // Right now we get all contexts from a type
    contextType = "Room";

    return_get = function(res, buffer) {
        res.send(buffer);
    };

    var options = {
        host: orion_url,
        port: 10026,
        path: '/NGSI10/contextEntityTypes/'+contextType,
        method: 'GET',
        headers: {
            accept: 'application/json'
        }
    };

    utils.do_get(options, return_get, res);
};

//Create a new Context subscription in CKAN for an organization
exports.subscribe_context = function(req, res) {
  return_post = function(res, buffer, headers) {
      res.send(buffer);
  };

  var cygnus_ckan_url = "http://localhost";
  var org_id = req.params.org_id;
  var context_id = req.params.context_id;
  var org_port;

    if (org_id == "org_a" || org_id == "organization_a") {
      org_port = "5001";
  } else if (org_id == "org_b" || org_id == "organizatiob_b") {
      org_port = "5002";
  } else {
      res.status(404);
      res.send(err.message || "Org " + org_id + " not found.");
      return;
  }

  post_data = {
      "entities": [
           {
               "type": context_id,
               "isPattern": "false",
               "id": "FirstEntity"
           }
       ],
       "attributes": [
           "temperature"
       ],
       "reference": cygnus_ckan_url + ":" + org_port +"/notify",
       "duration": "P1M",
       "notifyConditions": [
           {
               "type": "ONCHANGE",
               "condValues": [
                   "pressure"
               ]
           }
       ],
       "throttling": "PT1S"
  };

  post_data = JSON.stringify(post_data);

  headers = {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'Content-Length': Buffer.byteLength(post_data)
  };

  var options = {
      host: orion_url,
      port: 10026,
      path: '/NGSI10/subscribeContext',
      method: 'POST',
      headers: headers
  };

  utils.do_post(options, post_data, return_post, res);
};

// Update entities data (temperature)
exports.update_context_temperature = function(req, res) {
  return_post = function(res, buffer, headers) {
      res.send(buffer);
  };

  var org_id = req.params.org_id;
  var context_id = req.params.context_id;
  var temperature_id = req.params.temperature_id;

    post_data = {
        "contextElements": [
                {
                    "type": org_id,
                    "isPattern": "false",
                    "id": context_id,
                    "attributes": [
                    {
                        "name": "temperature",
                        "type": "centigrade",
                        "value": temperature_id
                    },
                    {
                        "name": "pressure",
                        "type": "mmHg",
                        "value": "720"
                    }
                    ]
                }
            ],
            "updateAction": "APPEND"
    };

  post_data = JSON.stringify(post_data);

  headers = {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'Content-Length': Buffer.byteLength(post_data)
  };

  var options = {
      host: orion_url,
      port: 10026,
      path: '/NGSI10/updateContext',
      method: 'POST',
      headers: headers
  };

  utils.do_post(options, post_data, return_post, res);
};

function get_orion_items(type, restaurant_name_regexp, res) {
    return_post = function(res, buffer, headers) {
        res.send(buffer);
    };

    var name = restaurant_name_regexp;
    var orion_url = "orion";
    var orion_port = 10026;
    var orion_res_limit = 1000; // Max orion items to avoid pagination

    post_data = {
          "entities": [
           {
               "type": type,
               "isPattern": "true",
               "id": ".*"+name+".*"
           }]
    };

    if (name === undefined) {
        // Get all restaurants
        post_data.entities[0].id=".*";
    }

    post_data = JSON.stringify(post_data);

    headers = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Content-Length': Buffer.byteLength(post_data)
    };

    var options = {
        host: orion_url,
        port: orion_port,
        path: '/NGSI10/queryContext?limit='+orion_res_limit,
        method: 'POST',
        headers: headers
    };

    utils.do_post(options, post_data, return_post, res);
}

// Find the restaurants given a name
exports.get_restaurants = function(req, res) {
    get_orion_items("restaurant", req.params.name, res);
};

// Find the reviews given a restaurant name regexp
exports.get_reviews = function(req, res) {
    get_orion_items("review", req.params.name, res);
};

// Find the reservations given a restaurant name regexp
exports.get_reservations = function(req, res) {
    get_orion_items("reservation", req.params.name, res);
};

// Update entities in orion
exports.update_entities = function(req, res) {
  return_post = function(res, buffer, headers) {
      res.send(buffer);
  };

  var org_id = req.params.org_id;
  var post_data = JSON.stringify(req.body);

  headers = {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'Content-Length': Buffer.byteLength(post_data)
  };

  var options = {
      host: orion_url,
      port: 10026,
      path: '/NGSI10/updateContext',
      method: 'POST',
      headers: headers
  };

  utils.do_post(options, post_data, return_post, res);
};
<commit_msg>Decode encoded characters from orion response.<commit_after>/*
 * ChanChan Orion REST API
 */

var utils = require('../utils');
var orion_url = "orion"; // To be changed to PEP for auth

// Return the list of available entities in Orion
exports.contexts = function(req, res) {
    // TODO: Check auth
    // Is it possible to get all contexts from the API?
    // Right now we get all contexts from a type
    contextType = "Room";

    return_get = function(res, buffer) {
        res.send(buffer);
    };

    var options = {
        host: orion_url,
        port: 10026,
        path: '/NGSI10/contextEntityTypes/'+contextType,
        method: 'GET',
        headers: {
            accept: 'application/json'
        }
    };

    utils.do_get(options, return_get, res);
};

//Create a new Context subscription in CKAN for an organization
exports.subscribe_context = function(req, res) {
  return_post = function(res, buffer, headers) {
      res.send(buffer);
  };

  var cygnus_ckan_url = "http://localhost";
  var org_id = req.params.org_id;
  var context_id = req.params.context_id;
  var org_port;

    if (org_id == "org_a" || org_id == "organization_a") {
      org_port = "5001";
  } else if (org_id == "org_b" || org_id == "organizatiob_b") {
      org_port = "5002";
  } else {
      res.status(404);
      res.send(err.message || "Org " + org_id + " not found.");
      return;
  }

  post_data = {
      "entities": [
           {
               "type": context_id,
               "isPattern": "false",
               "id": "FirstEntity"
           }
       ],
       "attributes": [
           "temperature"
       ],
       "reference": cygnus_ckan_url + ":" + org_port +"/notify",
       "duration": "P1M",
       "notifyConditions": [
           {
               "type": "ONCHANGE",
               "condValues": [
                   "pressure"
               ]
           }
       ],
       "throttling": "PT1S"
  };

  post_data = JSON.stringify(post_data);

  headers = {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'Content-Length': Buffer.byteLength(post_data)
  };

  var options = {
      host: orion_url,
      port: 10026,
      path: '/NGSI10/subscribeContext',
      method: 'POST',
      headers: headers
  };

  utils.do_post(options, post_data, return_post, res);
};

// Update entities data (temperature)
exports.update_context_temperature = function(req, res) {
  return_post = function(res, buffer, headers) {
      res.send(buffer);
  };

  var org_id = req.params.org_id;
  var context_id = req.params.context_id;
  var temperature_id = req.params.temperature_id;

    post_data = {
        "contextElements": [
                {
                    "type": org_id,
                    "isPattern": "false",
                    "id": context_id,
                    "attributes": [
                    {
                        "name": "temperature",
                        "type": "centigrade",
                        "value": temperature_id
                    },
                    {
                        "name": "pressure",
                        "type": "mmHg",
                        "value": "720"
                    }
                    ]
                }
            ],
            "updateAction": "APPEND"
    };

  post_data = JSON.stringify(post_data);

  headers = {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'Content-Length': Buffer.byteLength(post_data)
  };

  var options = {
      host: orion_url,
      port: 10026,
      path: '/NGSI10/updateContext',
      method: 'POST',
      headers: headers
  };

  utils.do_post(options, post_data, return_post, res);
};

function get_orion_items(type, restaurant_name_regexp, res) {
    return_post = function(res, buffer, headers) {
        res.send(unescape(buffer));
    };

    var name = restaurant_name_regexp;
    var orion_url = "orion";
    var orion_port = 10026;
    var orion_res_limit = 1000; // Max orion items to avoid pagination

    post_data = {
          "entities": [
           {
               "type": type,
               "isPattern": "true",
               "id": ".*"+name+".*"
           }]
    };

    if (name === undefined) {
        // Get all restaurants
        post_data.entities[0].id=".*";
    }

    post_data = JSON.stringify(post_data);

    headers = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Content-Length': Buffer.byteLength(post_data)
    };

    var options = {
        host: orion_url,
        port: orion_port,
        path: '/NGSI10/queryContext?limit='+orion_res_limit,
        method: 'POST',
        headers: headers
    };

    utils.do_post(options, post_data, return_post, res);
}

// Find the restaurants given a name
exports.get_restaurants = function(req, res) {
    get_orion_items("restaurant", req.params.name, res);
};

// Find the reviews given a restaurant name regexp
exports.get_reviews = function(req, res) {
    get_orion_items("review", req.params.name, res);
};

// Find the reservations given a restaurant name regexp
exports.get_reservations = function(req, res) {
    get_orion_items("reservation", req.params.name, res);
};

// Update entities in orion
exports.update_entities = function(req, res) {
  return_post = function(res, buffer, headers) {
      res.send(buffer);
  };

  var org_id = req.params.org_id;
  var post_data = JSON.stringify(req.body);

  headers = {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'Content-Length': Buffer.byteLength(post_data)
  };

  var options = {
      host: orion_url,
      port: 10026,
      path: '/NGSI10/updateContext',
      method: 'POST',
      headers: headers
  };

  utils.do_post(options, post_data, return_post, res);
};
<|endoftext|>


<commit_before>const config = require("./config").root();
const path = require("path");
const fs = require("fs");
const child_process = require("child_process");
const rimraf = require("rimraf");

// Convert to milliseconds:
let keepTime = config.exportKeepTime * 60 * 1000;

function exportPath(deviceId) {
  if (deviceId.search(/^[a-z0-9\-]+$/i) == -1) {
    reject(new Error("Bad deviceId"));
  }
  return path.join(config.exportBase, "export---" + deviceId);
}

function removeExportPath(dir) {
  return new Promise((resolve, reject) => {
    rimraf(dir, (error) => {
      if (error && error.code != "ENOENT") {
        reject(error);
      } else {
        resolve();
      }
    });
  });
}

function launchWget(deviceId) {
  return new Promise((resolve, reject) => {
    let dir = exportPath(deviceId);
    let script = path.join(__dirname, "export-shots.sh");
    let start = Date.now();
    let subprocess = child_process.spawn(
      script,
      {
        env: {
          BASE_DIR: dir,
          AUTH: require("./dbschema").getTextKeys()[0],
          DEVICE_ID: deviceId,
          PORT: config.port,
          CONTENT_PORT: config.contentPort,
        }
      }
    );
    subprocess.on("close", function (code) {
      console.info("Exported to", dir, "in", (Date.now() - start) + "ms", "exit code:", code);
    });
    subprocess.on("error", function (e) {
      console.warn("Error launching wget:", e);
    });
    resolve();
    // FIXME: I don't think an exception here will reject
    // Also maybe this is all synchronous
  });
}

function getWgetStatus(deviceId) {
  return new Promise((resolve, reject) => {
    let dir = exportPath(deviceId);
    let result = {errors: []};
    let steps = 3;
    function resolveIfDone() {
      if (steps <= 0) {
        resolve(result);
      }
    }
    fs.readFile(path.join(dir, "wget-process.pid"), {encoding: "UTF-8"}, (error, data) => {
      if (error && error.code == "ENOENT") {
        // File doesn't exist
        result.running = false;
      } else if (error) {
        result.errors.push(["Error loading process PID:", error]);
      } else {
        result.running = true;
      }
      steps--;
      resolveIfDone();
    });
    fs.readFile(path.join(dir, "script-exit-code.txt"), {encoding: "UTF-8"}, (error, data) => {
      if (error && error.code == "ENOENT") {
        // Do nothing
      } else if (error) {
        result.errors.push(["Error loading exit code:", error]);
      } else {
        let code = parseInt(data, 10);
        if (code) {
          result.success = false;
        } else {
          result.success = true;
        }
      }
      steps--;
      resolveIfDone();
    });
    fs.stat(path.join(dir, "pageshot-export.zip"), (error, stat) => {
      if (error && error.code == "ENOENT") {
        result.zip = false;
      } else if (error) {
        result.errors.push(["Error checking zip file:", error]);
      } else {
        result.zip = {
          size: stat.size,
          mtime: stat.mtime.getTime(),
          keepTime: keepTime
        };
      }
      steps--;
      resolveIfDone();
    });
  });
}

exports.cleanExports = function () {
  let start = Date.now();
  fs.readdir(config.exportBase, (error, files) => {
    if (error && error.code == "ENOENT") {
      console.info("EXPORT: Could not clean exports, directory", config.exportBase, "does not exist");
      return;
    }
    if (error) {
      console.warn("EXPORT: Error listing", config.exportBase, ":", error);
      return;
    }
    let toCheck = files.filter((file) => file.startsWith("export--"));
    let count = toCheck.length;
    let deletedCount = 0;
    let errorCount = 0;
    function oneDone(deleted, errored) {
      count--;
      if (deleted) {
        deletedCount++;
      }
      if (errored) {
        errorCount++;
      }
      if (count <= 0) {
        console.info("EXPORT: finished cleanup run;", toCheck.length, "checked;", deletedCount, "deleted;", errorCount, "had errors; total time:", (Date.now() - start) + "ms");
      }
    }
    for (let dir of toCheck) {
      let fullDir = path.join(config.exportBase, dir);
      let file = path.join(fullDir, "pageshot-export.zip");
      fs.stat(file, (error, stat) => {
        if (error && error.code == "ENOENT") {
          fs.stat(fullDir, (error, stat) => {
            if (error && error.code == "ENOENT") {
              console.info("EXPORT: directory", fullDir, "disappeared during cleanup");
              oneDone(false, false);
              return;
            } else if (error) {
              console.warn("EXPORT: could not stat directory", fullDir, ":", error);
              oneDone(false, true);
              return;
            }
            if (stat.mtime.getTime() + keepTime < Date.now()) {
              rimraf(fullDir, (error) => {
                if (error) {
                  oneDone(false, true);
                  console.warn("EXPORT: failed to remove unfinished export", fullDir, ":", error);
                } else {
                  oneDone(true, false);
                  console.info("EXPORT: removed unfinished export", fullDir);
                }
              });
            }
          });
          return;
        } else if (error) {
          oneDone(false, true);
          console.warn("EXPORT: Error doing stat on", file, ":", error);
          return;
        }
        if (stat.mtime.getTime() + keepTime < Date.now()) {
          rimraf(fullDir, (error) => {
            if (error) {
              oneDone(false, true);
              console.warn("EXPORT: failed to remove outdated export", fullDir, ":", error);
            } else {
              oneDone(true, false);
              console.info("EXPORT: removed outdated export:", fullDir);
            }
          });
        } else {
          oneDone(false, false);
        }
      });
    }
  });
};

exports.setup = function (app) {

  app.get("/export", function (req, res) {
    if (! req.deviceId) {
      res.type("txt").status(403).send("You must have the addon installed to export your shots");
      return;
    }
    require("./views/export").render(req, res);
  });

  app.post("/export", function (req, res) {
    if (! req.deviceId) {
      res.type("txt").status(403).send("You must have the addon installed to export your shots");
      return;
    }
    launchWget(req.deviceId).then(() => {
      res.redirect("/export/status?started=" + encodeURIComponent(Date.now()));
    }).catch((e) => {
      require("./server").errorResponse(res, "Failed to launch export", e);
    });
  });

  app.get("/export/status", function (req, res) {
    if (! req.deviceId) {
      res.type("txt").status(403).send("You must have the addon installed to export your shots");
      return;
    }
    let started = parseInt(req.query.started, 10);
    getWgetStatus(req.deviceId).then((status) => {
      if ((! status.running) && ((! started) || (started + 10000 < Date.now()))) {
        res.redirect("/export");
        return;
      }
      if (started && status.zip) {
        res.redirect("/export/status");
        return;
      }
      req.wgetStatus = status;
      req.keepTime = keepTime;
      require("./views/export").renderStatus(req, res);
    }).catch((e) => {
      require("./server").errorResponse(res, "Failed to get status", e);
    });
  });

  app.get("/export/download/pageshot-export.zip", function (req, res) {
    if (! req.deviceId) {
      res.type("txt").status(403).send("You must have the addon installed to download your shots");
      return;
    }
    let dir = exportPath(req.deviceId);
    let fn = path.join(dir, "pageshot-export.zip");
    res.sendFile(fn);
  });

  app.post("/export/remove", function (req, res) {
    if (! req.deviceId) {
      res.type("txt").status(403).send("You must have the addon installed");
    }
    let dir = exportPath(req.deviceId);
    removeExportPath(dir).then(() => {
      res.redirect("/export?deleted");
    }).catch((e) => {
      require("./server").errorResponse(res, "Failed to remove directory", e);
    });
  });

};
<commit_msg>Implement analytics for the export button<commit_after>const config = require("./config").root();
const path = require("path");
const fs = require("fs");
const child_process = require("child_process");
const rimraf = require("rimraf");
const ua = require("universal-analytics");

// Convert to milliseconds:
let keepTime = config.exportKeepTime * 60 * 1000;

function exportPath(deviceId) {
  if (deviceId.search(/^[a-z0-9\-]+$/i) == -1) {
    reject(new Error("Bad deviceId"));
  }
  return path.join(config.exportBase, "export---" + deviceId);
}

function removeExportPath(dir) {
  return new Promise((resolve, reject) => {
    rimraf(dir, (error) => {
      if (error && error.code != "ENOENT") {
        reject(error);
      } else {
        resolve();
      }
    });
  });
}

function launchWget(deviceId) {
  return new Promise((resolve, reject) => {
    let dir = exportPath(deviceId);
    let script = path.join(__dirname, "export-shots.sh");
    let start = Date.now();
    let subprocess = child_process.spawn(
      script,
      {
        env: {
          BASE_DIR: dir,
          AUTH: require("./dbschema").getTextKeys()[0],
          DEVICE_ID: deviceId,
          PORT: config.port,
          CONTENT_PORT: config.contentPort,
        }
      }
    );
    subprocess.on("close", function (code) {
      console.info("Exported to", dir, "in", (Date.now() - start) + "ms", "exit code:", code);
    });
    subprocess.on("error", function (e) {
      console.warn("Error launching wget:", e);
    });
    resolve();
    // FIXME: I don't think an exception here will reject
    // Also maybe this is all synchronous
  });
}

function getWgetStatus(deviceId) {
  return new Promise((resolve, reject) => {
    let dir = exportPath(deviceId);
    let result = {errors: []};
    let steps = 3;
    function resolveIfDone() {
      if (steps <= 0) {
        resolve(result);
      }
    }
    fs.readFile(path.join(dir, "wget-process.pid"), {encoding: "UTF-8"}, (error, data) => {
      if (error && error.code == "ENOENT") {
        // File doesn't exist
        result.running = false;
      } else if (error) {
        result.errors.push(["Error loading process PID:", error]);
      } else {
        result.running = true;
      }
      steps--;
      resolveIfDone();
    });
    fs.readFile(path.join(dir, "script-exit-code.txt"), {encoding: "UTF-8"}, (error, data) => {
      if (error && error.code == "ENOENT") {
        // Do nothing
      } else if (error) {
        result.errors.push(["Error loading exit code:", error]);
      } else {
        let code = parseInt(data, 10);
        if (code) {
          result.success = false;
        } else {
          result.success = true;
        }
      }
      steps--;
      resolveIfDone();
    });
    fs.stat(path.join(dir, "pageshot-export.zip"), (error, stat) => {
      if (error && error.code == "ENOENT") {
        result.zip = false;
      } else if (error) {
        result.errors.push(["Error checking zip file:", error]);
      } else {
        result.zip = {
          size: stat.size,
          mtime: stat.mtime.getTime(),
          keepTime: keepTime
        };
      }
      steps--;
      resolveIfDone();
    });
  });
}

exports.cleanExports = function () {
  let start = Date.now();
  fs.readdir(config.exportBase, (error, files) => {
    if (error && error.code == "ENOENT") {
      console.info("EXPORT: Could not clean exports, directory", config.exportBase, "does not exist");
      return;
    }
    if (error) {
      console.warn("EXPORT: Error listing", config.exportBase, ":", error);
      return;
    }
    let toCheck = files.filter((file) => file.startsWith("export--"));
    let count = toCheck.length;
    let deletedCount = 0;
    let errorCount = 0;
    function oneDone(deleted, errored) {
      count--;
      if (deleted) {
        deletedCount++;
      }
      if (errored) {
        errorCount++;
      }
      if (count <= 0) {
        console.info("EXPORT: finished cleanup run;", toCheck.length, "checked;", deletedCount, "deleted;", errorCount, "had errors; total time:", (Date.now() - start) + "ms");
      }
    }
    for (let dir of toCheck) {
      let fullDir = path.join(config.exportBase, dir);
      let file = path.join(fullDir, "pageshot-export.zip");
      fs.stat(file, (error, stat) => {
        if (error && error.code == "ENOENT") {
          fs.stat(fullDir, (error, stat) => {
            if (error && error.code == "ENOENT") {
              console.info("EXPORT: directory", fullDir, "disappeared during cleanup");
              oneDone(false, false);
              return;
            } else if (error) {
              console.warn("EXPORT: could not stat directory", fullDir, ":", error);
              oneDone(false, true);
              return;
            }
            if (stat.mtime.getTime() + keepTime < Date.now()) {
              rimraf(fullDir, (error) => {
                if (error) {
                  oneDone(false, true);
                  console.warn("EXPORT: failed to remove unfinished export", fullDir, ":", error);
                } else {
                  oneDone(true, false);
                  console.info("EXPORT: removed unfinished export", fullDir);
                }
              });
            }
          });
          return;
        } else if (error) {
          oneDone(false, true);
          console.warn("EXPORT: Error doing stat on", file, ":", error);
          return;
        }
        if (stat.mtime.getTime() + keepTime < Date.now()) {
          rimraf(fullDir, (error) => {
            if (error) {
              oneDone(false, true);
              console.warn("EXPORT: failed to remove outdated export", fullDir, ":", error);
            } else {
              oneDone(true, false);
              console.info("EXPORT: removed outdated export:", fullDir);
            }
          });
        } else {
          oneDone(false, false);
        }
      });
    }
  });
};

exports.setup = function (app) {

  app.get("/export", function (req, res) {
    if (! req.deviceId) {
      res.type("txt").status(403).send("You must have the addon installed to export your shots");
      return;
    }
    require("./views/export").render(req, res);
  });

  app.post("/export", function (req, res) {
    if (! req.deviceId) {
      res.type("txt").status(403).send("You must have the addon installed to export your shots");
      return;
    }
    let userAnalytics = ua(config.gaId, req.deviceId, {strictCidFormat: false});
    userAnalytics.event("click", "export");
    launchWget(req.deviceId).then(() => {
      res.redirect("/export/status?started=" + encodeURIComponent(Date.now()));
    }).catch((e) => {
      require("./server").errorResponse(res, "Failed to launch export", e);
    });
  });

  app.get("/export/status", function (req, res) {
    if (! req.deviceId) {
      res.type("txt").status(403).send("You must have the addon installed to export your shots");
      return;
    }
    let started = parseInt(req.query.started, 10);
    getWgetStatus(req.deviceId).then((status) => {
      if ((! status.running) && ((! started) || (started + 10000 < Date.now()))) {
        res.redirect("/export");
        return;
      }
      if (started && status.zip) {
        res.redirect("/export/status");
        return;
      }
      req.wgetStatus = status;
      req.keepTime = keepTime;
      require("./views/export").renderStatus(req, res);
    }).catch((e) => {
      require("./server").errorResponse(res, "Failed to get status", e);
    });
  });

  app.get("/export/download/pageshot-export.zip", function (req, res) {
    if (! req.deviceId) {
      res.type("txt").status(403).send("You must have the addon installed to download your shots");
      return;
    }
    let dir = exportPath(req.deviceId);
    let fn = path.join(dir, "pageshot-export.zip");
    res.sendFile(fn);
  });

  app.post("/export/remove", function (req, res) {
    if (! req.deviceId) {
      res.type("txt").status(403).send("You must have the addon installed");
    }
    let dir = exportPath(req.deviceId);
    removeExportPath(dir).then(() => {
      res.redirect("/export?deleted");
    }).catch((e) => {
      require("./server").errorResponse(res, "Failed to remove directory", e);
    });
  });

};
<|endoftext|>


<commit_before>'use strict';

const error = require('./error');
const logger = require('./logger');
const Group = require('./permissions/group').Group;
const Collection = require('./collection').Collection;
const version_field = require('./endpoint/writes').version_field;

const r = require('rethinkdb');

// These are exported for use by the CLI. They accept 'R' as a parameter because of
// https://github.com/rethinkdb/rethinkdb/issues/3263
const create_collection_reql = (R, internal_db, user_db, collection) => {
  const do_create = (table) =>
    R.db(user_db).tableCreate(table).do(() =>
      R.db(internal_db)
        .table('collections')
        .get(collection)
        .replace((old_row) =>
          R.branch(old_row.eq(null),
                   { id: collection, table },
                   old_row),
          { returnChanges: 'always' })('changes')(0)
        .do((res) =>
          R.branch(R.or(res.hasFields('error'),
                        res('new_val')('table').ne(table)),
                   R.db(user_db).tableDrop(table).do(() => res),
                   res)));

  return R.uuid().split('-')(-1)
           .do((id) => R.expr(collection).add('_').add(id)).do((table) =>
             R.db(internal_db).table('collections').get(collection).do((row) =>
               R.branch(row.eq(null),
                        do_create(table),
                        { old_val: row, new_val: row })));
};

const initialize_metadata_reql = (R, internal_db, user_db) =>
  R.expr([ user_db, internal_db ])
    .forEach((db) => R.branch(R.dbList().contains(db), [], R.dbCreate(db)))
    .do(() =>
      R.expr([ 'collections', 'users_auth', 'users', 'groups' ])
        .forEach((table) => R.branch(R.db(internal_db).tableList().contains(table),
                                     [], R.db(internal_db).tableCreate(table))));

class Metadata {
  constructor(project_name,
              conn,
              clients,
              auto_create_collection,
              auto_create_index) {
    this._db = project_name;
    this._internal_db = `${this._db}_internal`;
    this._conn = conn;
    this._clients = clients;
    this._auto_create_collection = auto_create_collection;
    this._auto_create_index = auto_create_index;
    this._closed = false;
    this._ready = false;
    this._collections = new Map();
    this._groups = new Map();
    this._collection_feed = null;
    this._group_feed = null;
    this._index_feed = null;

    const make_feeds = () => {
      logger.debug('running metadata sync');
      const groups_ready =
        r.db(this._internal_db)
          .table('groups')
          .changes({ squash: true,
                     includeInitial: true,
                     includeStates: true,
                     includeTypes: true })
          .run(this._conn).then((res) => {
            if (this._closed) {
              res.close();
              throw new Error('This metadata instance has been closed.');
            }
            return new Promise((resolve, reject) => {
              this._group_feed = res;
              this._group_feed.eachAsync((change) => {
                if (change.type === 'state') {
                  if (change.state === 'ready') {
                    logger.info('Groups metadata synced.');
                    resolve();
                  }
                } else if (change.type === 'initial' ||
                           change.type === 'add' ||
                           change.type === 'change') {
                  const group = new Group(change.new_val);
                  this._groups.set(group.name, group);
                  this._clients.forEach((c) => c.group_changed(group.name));
                } else if (change.type === 'uninitial' ||
                           change.type === 'remove') {
                  const group = this._groups.delete(change.old_val.id);
                  if (group) {
                    this._clients.forEach((c) => c.group_changed(group.name));
                  }
                }
              }).catch(reject);
            });
          });
      const collections_ready =
        r.db(this._internal_db)
          .table('collections')
          .changes({ squash: true,
                     includeInitial: true,
                     includeStates: true,
                     includeTypes: true })
          .run(this._conn).then((res) => {
            if (this._closed) {
              res.close();
              throw new Error('This metadata instance has been closed.');
            }
            return new Promise((resolve, reject) => {
              this._collection_feed = res;
              this._collection_feed.eachAsync((change) => {
                if (change.type === 'state') {
                  if (change.state === 'ready') {
                    logger.info('Collections metadata synced.');
                    resolve();
                  }
                } else if (change.type === 'initial' ||
                           change.type === 'add' ||
                           change.type === 'change') {
                  // Ignore special collections
                  if (change.new_val.id !== 'users') {
                    const collection = new Collection(change.new_val, this._db, this._conn);
                    this._collections.set(collection.name, collection);
                  }
                } else if (change.type === 'uninitial' ||
                           change.type === 'remove') {
                  // Ignore special collections
                  if (change.old_val.id !== 'users') {
                    this._collections.delete(change.old_val.id);
                  }
                }
              }).catch(reject);
            });
          });
      const indexes_ready =
        r.db('rethinkdb')
          .table('table_config')
          .filter({ db: this._db })
          .pluck('name', 'indexes')
          .changes({ squash: true,
                     includeInitial: true,
                     includeStates: true,
                     includeTypes: true })
          .run(this._conn).then((res) => {
            if (this._closed) {
              res.close();
              throw new Error('This metadata instance has been closed.');
            }
            return new Promise((resolve, reject) => {
              this._index_feed = res;
              this._index_feed.eachAsync((change) => {
                if (change.type === 'state') {
                  if (change.state === 'ready') {
                    logger.info('Index metadata synced.');
                    resolve();
                  }
                } else if (change.type === 'initial' ||
                           change.type === 'add' ||
                           change.type === 'change') {
                  const table = change.new_val.name;
                  this._collections.forEach((c) => {
                    if (c.table === table) {
                      c.update_indexes(change.new_val.indexes, this._conn);
                    }
                  });
                }
              }).catch(reject);
            });
          });
      return Promise.all([ groups_ready, collections_ready, indexes_ready ]);
    };

    if (this._auto_create_collection) {
      this._ready_promise =
        initialize_metadata_reql(r, this._internal_db, this._db).run(this._conn).then(make_feeds);
    } else {
      this._ready_promise =
        r.expr([ this._db, this._internal_db ])
         .concatMap((db) => r.branch(r.dbList().contains(db), [], [ db ]))
         .run(this._conn).then((missing_dbs) => {
           logger.debug('checking for internal db/tables');
           if (missing_dbs.length > 0) {
             let err_msg;
             if (missing_dbs.length === 1) {
               err_msg = `The database ${missing_dbs[0]} does not exist.`;
             } else {
               err_msg = `The databases ${missing_dbs.join(' and ')} do not exist.`;
             }
             throw new Error(err_msg + 'Run `hz set-schema` to initialize the database, ' +
                             'then start the Horizon server.');
           } else {
             return make_feeds();
           }
         });
    }

    this._ready_promise = this._ready_promise.then(() => {
      logger.debug('adding admin user');
      // Ensure that the admin user and group exists
      return Promise.all([
        r.db(this._internal_db).table('users').get('admin')
          .replace((old_row) =>
            r.branch(old_row.eq(null),
                     { id: 'admin', groups: [ 'admin' ] },
                     old_row),
            { returnChanges: 'always' })('changes')(0)
          .do((res) =>
            r.branch(res('new_val').eq(null),
                     r.error(res('error')),
                     res('new_val'))).run(this._conn),
        r.db(this._internal_db).table('groups').get('admin')
          .replace((old_row) =>
            r.branch(old_row.eq(null),
              {
                id: 'admin',
                rules: { carte_blanche: { template: 'any()' } },
                [version_field]: 0,
              },
              old_row),
            { returnChanges: 'always' })('changes')(0)
          .do((res) =>
            r.branch(res('new_val').eq(null),
                     r.error(res('error')),
                     res('new_val'))).run(this._conn),
      ]);
    }).then(() => {
      logger.debug('redirecting users table');
      // Redirect the 'users' table to the one in the internal db
      this._collections.set('users', new Collection({ id: 'users', table: 'users' },
                                                    this._internal_db, this._conn));
    }).then(() => {
      logger.debug('metadata sync complete');
      this._ready = true;
      return this;
    });

    this._ready_promise.catch(() => {
      this.close();
    });
  }

  close() {
    this._closed = true;
    this._ready = false;
    if (this._group_feed) {
      this._group_feed.close().catch(() => { });
    }
    if (this._collection_feed) {
      this._collection_feed.close().catch(() => { });
    }
    if (this._index_feed) {
      this._index_feed.close().catch(() => { });
    }
  }

  is_ready() {
    return this._ready;
  }

  ready() {
    return this._ready_promise;
  }

  collection(name) {
    const res = this._collections.get(name);
    if (res === undefined) { throw new error.CollectionMissing(name); }
    if (res.promise) { throw new error.CollectionNotReady(res); }
    return res;
  }

  handle_error(err, done) {
    logger.debug(`Handling error: ${err.message}`);
    try {
      if (this._auto_create_collection) {
        if (err instanceof error.CollectionMissing) {
          logger.warn(`Auto-creating collection (dev mode): ${err.name}`);
          return this.create_collection(err.name, done);
        } else if (err instanceof error.CollectionNotReady) {
          return err.collection.on_ready(done);
        }
      }
      if (this._auto_create_index) {
        if (err instanceof error.IndexMissing) {
          logger.warn(`Auto-creating index on collection "${err.collection.name}" ` +
                      `(dev mode): ${JSON.stringify(err.fields)}`);
          return err.collection.create_index(err.fields, this._conn, done);
        } else if (err instanceof error.IndexNotReady) {
          return err.index.on_ready(done);
        }
      }
      done(err);
    } catch (new_err) {
      logger.debug(`Error when handling error: ${new_err.message}`);
      done(new_err);
    }
  }

  create_collection(name, done) {
    error.check(this._collections.get(name) === undefined,
                `Collection "${name}" already exists.`);

    create_collection_reql(r, this._internal_db, this._db, name)
      .run(this._conn)
      .then((res) => {
        error.check(!res.error, `Collection creation failed (dev mode): "${name}", ${res.error}`);
        logger.warn(`Collection created (dev mode): "${name}"`);
        this._collections.set(name, new Collection(res.new_val, this._db, this._conn));
        done();
      }).catch(done);
  }

  get_user_feed(id, cb) {
    r.db(this._internal_db)
      .table('users')
      .get(id)
      .changes({ includeInitial: true, squash: true })
      .run(this._conn)
      .then((cursor) =>
        cursor.eachAsync((change) => {
          if (!change.new_val) {
            throw new Error('User account has been deleted.');
          }
          return cb(change);
        }).then(() => {
          throw new Error('User account feed has been lost.');
        }, (err) => {
          throw new Error(`User account feed errored: ${err}`);
        })
      );
  }

  get_group(group_name) {
    return this._groups.get(group_name);
  }

  connection() {
    return this._conn;
  }
}

module.exports = { Metadata, create_collection_reql, initialize_metadata_reql };
<commit_msg>Handling remaining .close() exceptions<commit_after>'use strict';

const error = require('./error');
const logger = require('./logger');
const Group = require('./permissions/group').Group;
const Collection = require('./collection').Collection;
const version_field = require('./endpoint/writes').version_field;

const r = require('rethinkdb');

// These are exported for use by the CLI. They accept 'R' as a parameter because of
// https://github.com/rethinkdb/rethinkdb/issues/3263
const create_collection_reql = (R, internal_db, user_db, collection) => {
  const do_create = (table) =>
    R.db(user_db).tableCreate(table).do(() =>
      R.db(internal_db)
        .table('collections')
        .get(collection)
        .replace((old_row) =>
          R.branch(old_row.eq(null),
                   { id: collection, table },
                   old_row),
          { returnChanges: 'always' })('changes')(0)
        .do((res) =>
          R.branch(R.or(res.hasFields('error'),
                        res('new_val')('table').ne(table)),
                   R.db(user_db).tableDrop(table).do(() => res),
                   res)));

  return R.uuid().split('-')(-1)
           .do((id) => R.expr(collection).add('_').add(id)).do((table) =>
             R.db(internal_db).table('collections').get(collection).do((row) =>
               R.branch(row.eq(null),
                        do_create(table),
                        { old_val: row, new_val: row })));
};

const initialize_metadata_reql = (R, internal_db, user_db) =>
  R.expr([ user_db, internal_db ])
    .forEach((db) => R.branch(R.dbList().contains(db), [], R.dbCreate(db)))
    .do(() =>
      R.expr([ 'collections', 'users_auth', 'users', 'groups' ])
        .forEach((table) => R.branch(R.db(internal_db).tableList().contains(table),
                                     [], R.db(internal_db).tableCreate(table))));

class Metadata {
  constructor(project_name,
              conn,
              clients,
              auto_create_collection,
              auto_create_index) {
    this._db = project_name;
    this._internal_db = `${this._db}_internal`;
    this._conn = conn;
    this._clients = clients;
    this._auto_create_collection = auto_create_collection;
    this._auto_create_index = auto_create_index;
    this._closed = false;
    this._ready = false;
    this._collections = new Map();
    this._groups = new Map();
    this._collection_feed = null;
    this._group_feed = null;
    this._index_feed = null;

    const make_feeds = () => {
      logger.debug('running metadata sync');
      const groups_ready =
        r.db(this._internal_db)
          .table('groups')
          .changes({ squash: true,
                     includeInitial: true,
                     includeStates: true,
                     includeTypes: true })
          .run(this._conn).then((res) => {
            if (this._closed) {
              res.close().catch(() => { });
              throw new Error('This metadata instance has been closed.');
            }
            return new Promise((resolve, reject) => {
              this._group_feed = res;
              this._group_feed.eachAsync((change) => {
                if (change.type === 'state') {
                  if (change.state === 'ready') {
                    logger.info('Groups metadata synced.');
                    resolve();
                  }
                } else if (change.type === 'initial' ||
                           change.type === 'add' ||
                           change.type === 'change') {
                  const group = new Group(change.new_val);
                  this._groups.set(group.name, group);
                  this._clients.forEach((c) => c.group_changed(group.name));
                } else if (change.type === 'uninitial' ||
                           change.type === 'remove') {
                  const group = this._groups.delete(change.old_val.id);
                  if (group) {
                    this._clients.forEach((c) => c.group_changed(group.name));
                  }
                }
              }).catch(reject);
            });
          });
      const collections_ready =
        r.db(this._internal_db)
          .table('collections')
          .changes({ squash: true,
                     includeInitial: true,
                     includeStates: true,
                     includeTypes: true })
          .run(this._conn).then((res) => {
            if (this._closed) {
              res.close().catch(() => { });
              throw new Error('This metadata instance has been closed.');
            }
            return new Promise((resolve, reject) => {
              this._collection_feed = res;
              this._collection_feed.eachAsync((change) => {
                if (change.type === 'state') {
                  if (change.state === 'ready') {
                    logger.info('Collections metadata synced.');
                    resolve();
                  }
                } else if (change.type === 'initial' ||
                           change.type === 'add' ||
                           change.type === 'change') {
                  // Ignore special collections
                  if (change.new_val.id !== 'users') {
                    const collection = new Collection(change.new_val, this._db, this._conn);
                    this._collections.set(collection.name, collection);
                  }
                } else if (change.type === 'uninitial' ||
                           change.type === 'remove') {
                  // Ignore special collections
                  if (change.old_val.id !== 'users') {
                    this._collections.delete(change.old_val.id);
                  }
                }
              }).catch(reject);
            });
          });
      const indexes_ready =
        r.db('rethinkdb')
          .table('table_config')
          .filter({ db: this._db })
          .pluck('name', 'indexes')
          .changes({ squash: true,
                     includeInitial: true,
                     includeStates: true,
                     includeTypes: true })
          .run(this._conn).then((res) => {
            if (this._closed) {
              res.close().catch(() => { });
              throw new Error('This metadata instance has been closed.');
            }
            return new Promise((resolve, reject) => {
              this._index_feed = res;
              this._index_feed.eachAsync((change) => {
                if (change.type === 'state') {
                  if (change.state === 'ready') {
                    logger.info('Index metadata synced.');
                    resolve();
                  }
                } else if (change.type === 'initial' ||
                           change.type === 'add' ||
                           change.type === 'change') {
                  const table = change.new_val.name;
                  this._collections.forEach((c) => {
                    if (c.table === table) {
                      c.update_indexes(change.new_val.indexes, this._conn);
                    }
                  });
                }
              }).catch(reject);
            });
          });
      return Promise.all([ groups_ready, collections_ready, indexes_ready ]);
    };

    if (this._auto_create_collection) {
      this._ready_promise =
        initialize_metadata_reql(r, this._internal_db, this._db).run(this._conn).then(make_feeds);
    } else {
      this._ready_promise =
        r.expr([ this._db, this._internal_db ])
         .concatMap((db) => r.branch(r.dbList().contains(db), [], [ db ]))
         .run(this._conn).then((missing_dbs) => {
           logger.debug('checking for internal db/tables');
           if (missing_dbs.length > 0) {
             let err_msg;
             if (missing_dbs.length === 1) {
               err_msg = `The database ${missing_dbs[0]} does not exist.`;
             } else {
               err_msg = `The databases ${missing_dbs.join(' and ')} do not exist.`;
             }
             throw new Error(err_msg + 'Run `hz set-schema` to initialize the database, ' +
                             'then start the Horizon server.');
           } else {
             return make_feeds();
           }
         });
    }

    this._ready_promise = this._ready_promise.then(() => {
      logger.debug('adding admin user');
      // Ensure that the admin user and group exists
      return Promise.all([
        r.db(this._internal_db).table('users').get('admin')
          .replace((old_row) =>
            r.branch(old_row.eq(null),
                     { id: 'admin', groups: [ 'admin' ] },
                     old_row),
            { returnChanges: 'always' })('changes')(0)
          .do((res) =>
            r.branch(res('new_val').eq(null),
                     r.error(res('error')),
                     res('new_val'))).run(this._conn),
        r.db(this._internal_db).table('groups').get('admin')
          .replace((old_row) =>
            r.branch(old_row.eq(null),
              {
                id: 'admin',
                rules: { carte_blanche: { template: 'any()' } },
                [version_field]: 0,
              },
              old_row),
            { returnChanges: 'always' })('changes')(0)
          .do((res) =>
            r.branch(res('new_val').eq(null),
                     r.error(res('error')),
                     res('new_val'))).run(this._conn),
      ]);
    }).then(() => {
      logger.debug('redirecting users table');
      // Redirect the 'users' table to the one in the internal db
      this._collections.set('users', new Collection({ id: 'users', table: 'users' },
                                                    this._internal_db, this._conn));
    }).then(() => {
      logger.debug('metadata sync complete');
      this._ready = true;
      return this;
    });

    this._ready_promise.catch(() => {
      this.close();
    });
  }

  close() {
    this._closed = true;
    this._ready = false;
    if (this._group_feed) {
      this._group_feed.close().catch(() => { });
    }
    if (this._collection_feed) {
      this._collection_feed.close().catch(() => { });
    }
    if (this._index_feed) {
      this._index_feed.close().catch(() => { });
    }
  }

  is_ready() {
    return this._ready;
  }

  ready() {
    return this._ready_promise;
  }

  collection(name) {
    const res = this._collections.get(name);
    if (res === undefined) { throw new error.CollectionMissing(name); }
    if (res.promise) { throw new error.CollectionNotReady(res); }
    return res;
  }

  handle_error(err, done) {
    logger.debug(`Handling error: ${err.message}`);
    try {
      if (this._auto_create_collection) {
        if (err instanceof error.CollectionMissing) {
          logger.warn(`Auto-creating collection (dev mode): ${err.name}`);
          return this.create_collection(err.name, done);
        } else if (err instanceof error.CollectionNotReady) {
          return err.collection.on_ready(done);
        }
      }
      if (this._auto_create_index) {
        if (err instanceof error.IndexMissing) {
          logger.warn(`Auto-creating index on collection "${err.collection.name}" ` +
                      `(dev mode): ${JSON.stringify(err.fields)}`);
          return err.collection.create_index(err.fields, this._conn, done);
        } else if (err instanceof error.IndexNotReady) {
          return err.index.on_ready(done);
        }
      }
      done(err);
    } catch (new_err) {
      logger.debug(`Error when handling error: ${new_err.message}`);
      done(new_err);
    }
  }

  create_collection(name, done) {
    error.check(this._collections.get(name) === undefined,
                `Collection "${name}" already exists.`);

    create_collection_reql(r, this._internal_db, this._db, name)
      .run(this._conn)
      .then((res) => {
        error.check(!res.error, `Collection creation failed (dev mode): "${name}", ${res.error}`);
        logger.warn(`Collection created (dev mode): "${name}"`);
        this._collections.set(name, new Collection(res.new_val, this._db, this._conn));
        done();
      }).catch(done);
  }

  get_user_feed(id, cb) {
    r.db(this._internal_db)
      .table('users')
      .get(id)
      .changes({ includeInitial: true, squash: true })
      .run(this._conn)
      .then((cursor) =>
        cursor.eachAsync((change) => {
          if (!change.new_val) {
            throw new Error('User account has been deleted.');
          }
          return cb(change);
        }).then(() => {
          throw new Error('User account feed has been lost.');
        }, (err) => {
          throw new Error(`User account feed errored: ${err}`);
        })
      );
  }

  get_group(group_name) {
    return this._groups.get(group_name);
  }

  connection() {
    return this._conn;
  }
}

module.exports = { Metadata, create_collection_reql, initialize_metadata_reql };
<|endoftext|>


<commit_before>export function JFrogIFrameDownload(JFrogNotifications, $timeout) {
	'ngInject';
    return function(url,defaultErrorMessage) {
        let iframe=$('<iframe style="display: none">');
        iframe.load((event)=>{
            let responseObjStr, response,defaultMessage;
            try {
                responseObjStr = $(event.target).contents().find('pre').text();
            }
            catch(e) { //workaround for ie .contents() ACCESS DENIED error
                defaultMessage = defaultErrorMessage || 'Something went wrong.';
            }

            if (responseObjStr) {
                try {
                    response = JSON.parse(JSON.parse(responseObjStr).errors[0].message).error;
                }
                catch(e) {
                    //Do nothing
                }
            }

            if (defaultMessage || response) {
                let message = defaultMessage || response;
                $timeout(()=>{
                    JFrogNotifications.create({error: message});
                    if (iframe.parent().length) iframe.remove();
                });
            }
        });

        iframe.ready(() => {
            $timeout(()=>{
                if (iframe.parent().length) iframe.remove();
            },15000);
        });

        iframe.attr('src', url).appendTo('body');
    }
}<commit_msg>JFrogIFrameDownload - Update jquery api (.load is deprecated)<commit_after>export function JFrogIFrameDownload(JFrogNotifications, $timeout) {
	'ngInject';
    return function(url,defaultErrorMessage) {
        let iframe=$('<iframe style="display: none">');
        iframe.on('load', (event)=>{
            let responseObjStr, response,defaultMessage;
            try {
                responseObjStr = $(event.target).contents().find('pre').text();
            }
            catch(e) { //workaround for ie .contents() ACCESS DENIED error
                defaultMessage = defaultErrorMessage || 'Something went wrong.';
            }

            if (responseObjStr) {
                try {
                    response = JSON.parse(JSON.parse(responseObjStr).errors[0].message).error;
                }
                catch(e) {
                    //Do nothing
                }
            }

            if (defaultMessage || response) {
                let message = defaultMessage || response;
                $timeout(()=>{
                    JFrogNotifications.create({error: message});
                    if (iframe.parent().length) iframe.remove();
                });
            }
        });

        iframe.ready(() => {
            $timeout(()=>{
                if (iframe.parent().length) iframe.remove();
            },15000);
        });

        iframe.attr('src', url).appendTo('body');
    }
}<|endoftext|>