<commit_before>var spies = require('./spy');
var chmodSpy = spies.chmodSpy;
var statSpy = spies.statSpy;

var vfs = require('../');

var path = require('path');
var fs = require('graceful-fs');

var bufEqual = require('buffer-equal');
var through = require('through2');
var File = require('vinyl');

var should = require('should');
require('mocha');

var dataWrap = function(fn) {
  return function(data, enc, cb) {
    fn(data);
    cb();
  };
};

describe('source stream', function() {

  it('should explode on invalid glob (empty)', function(done) {
    var stream;
    try {
      stream = vfs.src();
    } catch (err) {
      should.exist(err);
      should.not.exist(stream);
      done();
    }
  });

  it('should explode on invalid glob (number)', function(done) {
    var stream;
    try {
      stream = vfs.src(123);
    } catch (err) {
      should.exist(err);
      should.not.exist(stream);
      done();
    }
  });

  it('should not explode on invalid glob (empty array)', function(done) {
    var stream = vfs.src([]);
    stream.once('data', done);
    stream.once('end', function(){
      done();
    });
  });

  it('should pass through writes', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');
    var expectedContent = fs.readFileSync(expectedPath);

    var expectedFile = new File({
      base: __dirname,
      cwd: __dirname,
      path: expectedPath,
      contents: expectedContent
    });

    var stream = vfs.src('./fixtures/noexist.coffee');
    stream.on('data', function(file){
      file.should.equal(expectedFile);
      bufEqual(file.contents, expectedContent).should.equal(true);
      done();
    });
    stream.write(expectedFile);
  });

  it('should strip BOM from UTF-8-encoded files', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/bom-utf8.txt');
    var expectedContent = fs.readFileSync(expectedPath)
      // U+FEFF takes up 3 bytes in UTF-8: http://mothereff.in/utf-8#%EF%BB%BF
      .slice(3);

    var onEnd = function(){
      buffered.length.should.equal(1);
      should.exist(buffered[0].stat);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isBuffer().should.equal(true);
      bufEqual(buffered[0].contents, expectedContent).should.equal(true);
      done();
    };

    var stream = vfs.src('./fixtures/bom-utf8.txt', {cwd: __dirname});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should not strip anything that looks like a UTF-8-encoded BOM from UTF-16-BE-encoded files', function(done) {
    // Note: this goes for any non-UTF-8 encoding, but testing for UTF-16-BE
    // and UTF-16-LE is enough to demonstrate this is done properly.
    var expectedPath = path.join(__dirname, './fixtures/bom-utf16be.txt');
    var expectedContent = fs.readFileSync(expectedPath);

    var onEnd = function(){
      buffered.length.should.equal(1);
      should.exist(buffered[0].stat);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isBuffer().should.equal(true);
      bufEqual(buffered[0].contents, expectedContent).should.equal(true);
      done();
    };

    var stream = vfs.src('./fixtures/bom-utf16be.txt', {cwd: __dirname});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should not strip anything that looks like a UTF-8-encoded BOM from UTF-16-LE-encoded files', function(done) {
    // Note: this goes for any non-UTF-8 encoding, but testing for UTF-16-BE
    // and UTF-16-LE is enough to demonstrate this is done properly.
    var expectedPath = path.join(__dirname, './fixtures/bom-utf16le.txt');
    var expectedContent = fs.readFileSync(expectedPath);

    var onEnd = function(){
      buffered.length.should.equal(1);
      should.exist(buffered[0].stat);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isBuffer().should.equal(true);
      bufEqual(buffered[0].contents, expectedContent).should.equal(true);
      done();
    };

    var stream = vfs.src('./fixtures/bom-utf16le.txt', {cwd: __dirname});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should glob a file with default settings', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');
    var expectedContent = fs.readFileSync(expectedPath);

    var onEnd = function(){
      buffered.length.should.equal(1);
      should.exist(buffered[0].stat);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isBuffer().should.equal(true);
      bufEqual(buffered[0].contents, expectedContent).should.equal(true);
      done();
    };

    var stream = vfs.src('./fixtures/*.coffee', {cwd: __dirname});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should glob a file with default settings and relative cwd', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');
    var expectedContent = fs.readFileSync(expectedPath);

    var onEnd = function(){
      buffered.length.should.equal(1);
      should.exist(buffered[0].stat);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isBuffer().should.equal(true);
      bufEqual(buffered[0].contents, expectedContent).should.equal(true);
      done();
    };

    var stream = vfs.src('./fixtures/*.coffee', {cwd: path.relative(process.cwd(), __dirname)});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should glob a directory with default settings', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/wow');

    var onEnd = function(){
      buffered.length.should.equal(1);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isNull().should.equal(true);
      buffered[0].isDirectory().should.equal(true);
      done();
    };

    var stream = vfs.src('./fixtures/wow/', {cwd: __dirname});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should glob a file with with no contents', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');
    var expectedContent = fs.readFileSync(expectedPath);

    var onEnd = function(){
      buffered.length.should.equal(1);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isNull().should.equal(true);
      should.not.exist(buffered[0].contents);
      done();
    };

    var stream = vfs.src('./fixtures/*.coffee', {cwd: __dirname, read: false});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should glob a file changed after since', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');
    var expectedContent = fs.readFileSync(expectedPath);
    var lastUpdateDate = new Date(+fs.statSync(expectedPath).mtime - 1000);

    var onEnd = function(){
      buffered.length.should.equal(1);
      should.exist(buffered[0].stat);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isBuffer().should.equal(true);
      bufEqual(buffered[0].contents, expectedContent).should.equal(true);
      done();
    };

    var stream = vfs.src('./fixtures/*.coffee', {cwd: __dirname, since: lastUpdateDate});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should not glob a file changed before since', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');
    var lastUpdateDate = new Date(+fs.statSync(expectedPath).mtime + 1000);

    var onEnd = function(){
      buffered.length.should.equal(0);
      done();
    };

    var stream = vfs.src('./fixtures/*.coffee', {cwd: __dirname, since: lastUpdateDate});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should glob a file with streaming contents', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');
    var expectedContent = fs.readFileSync(expectedPath);

    var onEnd = function(){
      buffered.length.should.equal(1);
      should.exist(buffered[0].stat);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isStream().should.equal(true);

      var contentBuffer = new Buffer([]);
      var contentBufferStream = through(dataWrap(function(data){
        contentBuffer = Buffer.concat([contentBuffer, data]);
      }));
      buffered[0].contents.pipe(contentBufferStream);
      buffered[0].contents.once('end', function(){
        bufEqual(contentBuffer, expectedContent);
        done();
      });
    };

    var stream = vfs.src('./fixtures/*.coffee', {cwd: __dirname, buffer: false});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should pass files through', function(done) {
    var expectedPaths = [
      path.join(__dirname, './fixtures/test.coffee'),
      path.join(__dirname, './fixtures/wow/suchempty')
    ];
    var expectedContents = expectedPaths.map(function(path/* more args here so can't pass function directly */) {
      return fs.readFileSync(path);
    });

    var onEnd = function(){
      buffered.length.should.equal(2);
      buffered.forEach(function(file) {
        should.exist(file.stat);
        file.isBuffer().should.equal(true);

        expectedPaths.some(function(expectedPath) {
          return file.path === expectedPath;
        }).should.equal(true);

        expectedContents.some(function(expectedContent) {
          return bufEqual(file.contents, expectedContent);
        }).should.equal(true);
      });
      done();
    };

    var stream1 = vfs.src('./fixtures/*.coffee', {cwd: __dirname});
    var stream2 = vfs.src('./fixtures/wow/*', {cwd: __dirname, passthrough: true});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream1.pipe(stream2).pipe(bufferStream);
  });

  it('should pass files through (empty glob array in passthrough stream)', function(done) {
    var expectedPaths = [
      path.join(__dirname, './fixtures/test.coffee'),
      path.join(__dirname, './fixtures/wow/suchempty')
    ];
    var expectedContents = expectedPaths.map(function(path/* more args here so can't pass function directly */) {
      return fs.readFileSync(path);
    });

    var onEnd = function(){
      buffered.length.should.equal(2);
      buffered.forEach(function(file) {
        should.exist(file.stat);
        file.isBuffer().should.equal(true);

        expectedPaths.some(function(expectedPath) {
          return file.path === expectedPath;
        }).should.equal(true);

        expectedContents.some(function(expectedContent) {
          return bufEqual(file.contents, expectedContent);
        }).should.equal(true);
      });
      done();
    };

    var stream1 = vfs.src(['./fixtures/*.coffee', './fixtures/wow/*'], {cwd: __dirname});
    var stream2 = vfs.src([], {cwd: __dirname, passthrough: true});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream1.pipe(stream2).pipe(bufferStream);
  });

  it('should pass files through (empty glob array in source stream)', function(done) {
    var expectedPaths = [
      path.join(__dirname, './fixtures/test.coffee'),
      path.join(__dirname, './fixtures/wow/suchempty')
    ];
    var expectedContents = expectedPaths.map(function(path/* more args here so can't pass function directly */) {
      return fs.readFileSync(path);
    });

    var onEnd = function(){
      buffered.length.should.equal(2);
      buffered.forEach(function(file) {
        should.exist(file.stat);
        file.isBuffer().should.equal(true);

        expectedPaths.some(function(expectedPath) {
          return file.path === expectedPath;
        }).should.equal(true);

        expectedContents.some(function(expectedContent) {
          return bufEqual(file.contents, expectedContent);
        }).should.equal(true);
      });
      done();
    };

    var stream1 = vfs.src([], {cwd: __dirname});
    var stream2 = vfs.src(['./fixtures/*.coffee', './fixtures/wow/*'], {cwd: __dirname, passthrough: true});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream1.pipe(stream2).pipe(bufferStream);
  });

  it('should still end when passing through empty streams', function(done) {
    var onEnd = function(){
      buffered.length.should.equal(0);
      done();
    };

    var stream1 = vfs.src([], {cwd: __dirname});
    var stream2 = vfs.src([], {cwd: __dirname, passthrough: true});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream1.pipe(stream2).pipe(bufferStream);
  });

  it('should follow file symlinks', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');

    var stream = vfs.src('./fixtures/test-symlink', {cwd: __dirname});
    stream.on('data', function(file){
      file.path.should.equal(expectedPath);
      done();
    });
  });

  it('should follow dir symlinks', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/wow');

    var stream = vfs.src('./fixtures/test-symlink-dir', {cwd: __dirname});
    stream.on('data', function(file){
      file.path.should.equal(expectedPath);
      done();
    });
  });

});
<commit_msg>Update: Cleanup some `src()` tests<commit_after>var vfs = require('../');

var path = require('path');
var fs = require('graceful-fs');

var bufEqual = require('buffer-equal');
var through = require('through2');
var File = require('vinyl');

var should = require('should');
require('mocha');

var dataWrap = function(fn) {
  return function(data, enc, cb) {
    fn(data);
    cb();
  };
};

describe('source stream', function() {

  it('should explode on invalid glob (empty)', function(done) {
    var stream;
    try {
      stream = vfs.src();
    } catch (err) {
      should.exist(err);
      should.not.exist(stream);
      done();
    }
  });

  it('should explode on invalid glob (number)', function(done) {
    var stream;
    try {
      stream = vfs.src(123);
    } catch (err) {
      should.exist(err);
      should.not.exist(stream);
      done();
    }
  });

  it('should not explode on invalid glob (empty array)', function(done) {
    var stream = vfs.src([]);
    stream.once('data', done);
    stream.once('end', function(){
      done();
    });
  });

  it('should error on file not existing', function(done) {
    var stream = vfs.src('./fixtures/noexist.coffee');
    stream.on('error', function(err){
      should.exist(err);
      done();
    });
  });

  it('should pass through writes', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');
    var expectedContent = fs.readFileSync(expectedPath);
    var files = [];
    var expectedFile = new File({
      base: __dirname,
      cwd: __dirname,
      path: expectedPath,
      contents: expectedContent,
      stat: fs.lstatSync(expectedPath)
    });

    var stream = vfs.src(expectedPath, {cwd: __dirname, base: __dirname});
    stream.on('data', function(file){
      files.push(file);
    });
    stream.once('end', function(){
      files.length.should.equal(2);
      files[0].should.eql(expectedFile);
      bufEqual(files[0].contents, expectedContent).should.equal(true);
      files[1].should.eql(expectedFile);
      bufEqual(files[1].contents, expectedContent).should.equal(true);
      done();
    });
    stream.write(expectedFile);
  });

  it('should strip BOM from UTF-8-encoded files', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/bom-utf8.txt');
    var expectedContent = fs.readFileSync(expectedPath)
      // U+FEFF takes up 3 bytes in UTF-8: http://mothereff.in/utf-8#%EF%BB%BF
      .slice(3);

    var onEnd = function(){
      buffered.length.should.equal(1);
      should.exist(buffered[0].stat);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isBuffer().should.equal(true);
      bufEqual(buffered[0].contents, expectedContent).should.equal(true);
      done();
    };

    var stream = vfs.src('./fixtures/bom-utf8.txt', {cwd: __dirname});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should not strip anything that looks like a UTF-8-encoded BOM from UTF-16-BE-encoded files', function(done) {
    // Note: this goes for any non-UTF-8 encoding, but testing for UTF-16-BE
    // and UTF-16-LE is enough to demonstrate this is done properly.
    var expectedPath = path.join(__dirname, './fixtures/bom-utf16be.txt');
    var expectedContent = fs.readFileSync(expectedPath);

    var onEnd = function(){
      buffered.length.should.equal(1);
      should.exist(buffered[0].stat);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isBuffer().should.equal(true);
      bufEqual(buffered[0].contents, expectedContent).should.equal(true);
      done();
    };

    var stream = vfs.src('./fixtures/bom-utf16be.txt', {cwd: __dirname});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should not strip anything that looks like a UTF-8-encoded BOM from UTF-16-LE-encoded files', function(done) {
    // Note: this goes for any non-UTF-8 encoding, but testing for UTF-16-BE
    // and UTF-16-LE is enough to demonstrate this is done properly.
    var expectedPath = path.join(__dirname, './fixtures/bom-utf16le.txt');
    var expectedContent = fs.readFileSync(expectedPath);

    var onEnd = function(){
      buffered.length.should.equal(1);
      should.exist(buffered[0].stat);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isBuffer().should.equal(true);
      bufEqual(buffered[0].contents, expectedContent).should.equal(true);
      done();
    };

    var stream = vfs.src('./fixtures/bom-utf16le.txt', {cwd: __dirname});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should glob a file with default settings', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');
    var expectedContent = fs.readFileSync(expectedPath);

    var onEnd = function(){
      buffered.length.should.equal(1);
      should.exist(buffered[0].stat);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isBuffer().should.equal(true);
      bufEqual(buffered[0].contents, expectedContent).should.equal(true);
      done();
    };

    var stream = vfs.src('./fixtures/*.coffee', {cwd: __dirname});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should glob a file with default settings and relative cwd', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');
    var expectedContent = fs.readFileSync(expectedPath);

    var onEnd = function(){
      buffered.length.should.equal(1);
      should.exist(buffered[0].stat);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isBuffer().should.equal(true);
      bufEqual(buffered[0].contents, expectedContent).should.equal(true);
      done();
    };

    var stream = vfs.src('./fixtures/*.coffee', {cwd: path.relative(process.cwd(), __dirname)});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should glob a directory with default settings', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/wow');

    var onEnd = function(){
      buffered.length.should.equal(1);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isNull().should.equal(true);
      buffered[0].isDirectory().should.equal(true);
      done();
    };

    var stream = vfs.src('./fixtures/wow/', {cwd: __dirname});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should glob a file with with no contents', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');
    var expectedContent = fs.readFileSync(expectedPath);

    var onEnd = function(){
      buffered.length.should.equal(1);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isNull().should.equal(true);
      should.not.exist(buffered[0].contents);
      done();
    };

    var stream = vfs.src('./fixtures/*.coffee', {cwd: __dirname, read: false});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should glob a file changed after since', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');
    var expectedContent = fs.readFileSync(expectedPath);
    var lastUpdateDate = new Date(+fs.statSync(expectedPath).mtime - 1000);

    var onEnd = function(){
      buffered.length.should.equal(1);
      should.exist(buffered[0].stat);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isBuffer().should.equal(true);
      bufEqual(buffered[0].contents, expectedContent).should.equal(true);
      done();
    };

    var stream = vfs.src('./fixtures/*.coffee', {cwd: __dirname, since: lastUpdateDate});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should not glob a file changed before since', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');
    var lastUpdateDate = new Date(+fs.statSync(expectedPath).mtime + 1000);

    var onEnd = function(){
      buffered.length.should.equal(0);
      done();
    };

    var stream = vfs.src('./fixtures/*.coffee', {cwd: __dirname, since: lastUpdateDate});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should glob a file with streaming contents', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');
    var expectedContent = fs.readFileSync(expectedPath);

    var onEnd = function(){
      buffered.length.should.equal(1);
      should.exist(buffered[0].stat);
      buffered[0].path.should.equal(expectedPath);
      buffered[0].isStream().should.equal(true);

      var contentBuffer = new Buffer([]);
      var contentBufferStream = through(dataWrap(function(data){
        contentBuffer = Buffer.concat([contentBuffer, data]);
      }));
      buffered[0].contents.pipe(contentBufferStream);
      buffered[0].contents.once('end', function(){
        bufEqual(contentBuffer, expectedContent);
        done();
      });
    };

    var stream = vfs.src('./fixtures/*.coffee', {cwd: __dirname, buffer: false});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream.pipe(bufferStream);
  });

  it('should pass files through', function(done) {
    var expectedPaths = [
      path.join(__dirname, './fixtures/test.coffee'),
      path.join(__dirname, './fixtures/wow/suchempty')
    ];
    var expectedContents = expectedPaths.map(function(path/* more args here so can't pass function directly */) {
      return fs.readFileSync(path);
    });

    var onEnd = function(){
      buffered.length.should.equal(2);
      buffered.forEach(function(file) {
        should.exist(file.stat);
        file.isBuffer().should.equal(true);

        expectedPaths.some(function(expectedPath) {
          return file.path === expectedPath;
        }).should.equal(true);

        expectedContents.some(function(expectedContent) {
          return bufEqual(file.contents, expectedContent);
        }).should.equal(true);
      });
      done();
    };

    var stream1 = vfs.src('./fixtures/*.coffee', {cwd: __dirname});
    var stream2 = vfs.src('./fixtures/wow/*', {cwd: __dirname, passthrough: true});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream1.pipe(stream2).pipe(bufferStream);
  });

  it('should pass files through (empty glob array in passthrough stream)', function(done) {
    var expectedPaths = [
      path.join(__dirname, './fixtures/test.coffee'),
      path.join(__dirname, './fixtures/wow/suchempty')
    ];
    var expectedContents = expectedPaths.map(function(path/* more args here so can't pass function directly */) {
      return fs.readFileSync(path);
    });

    var onEnd = function(){
      buffered.length.should.equal(2);
      buffered.forEach(function(file) {
        should.exist(file.stat);
        file.isBuffer().should.equal(true);

        expectedPaths.some(function(expectedPath) {
          return file.path === expectedPath;
        }).should.equal(true);

        expectedContents.some(function(expectedContent) {
          return bufEqual(file.contents, expectedContent);
        }).should.equal(true);
      });
      done();
    };

    var stream1 = vfs.src(['./fixtures/*.coffee', './fixtures/wow/*'], {cwd: __dirname});
    var stream2 = vfs.src([], {cwd: __dirname, passthrough: true});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream1.pipe(stream2).pipe(bufferStream);
  });

  it('should pass files through (empty glob array in source stream)', function(done) {
    var expectedPaths = [
      path.join(__dirname, './fixtures/test.coffee'),
      path.join(__dirname, './fixtures/wow/suchempty')
    ];
    var expectedContents = expectedPaths.map(function(path/* more args here so can't pass function directly */) {
      return fs.readFileSync(path);
    });

    var onEnd = function(){
      buffered.length.should.equal(2);
      buffered.forEach(function(file) {
        should.exist(file.stat);
        file.isBuffer().should.equal(true);

        expectedPaths.some(function(expectedPath) {
          return file.path === expectedPath;
        }).should.equal(true);

        expectedContents.some(function(expectedContent) {
          return bufEqual(file.contents, expectedContent);
        }).should.equal(true);
      });
      done();
    };

    var stream1 = vfs.src([], {cwd: __dirname});
    var stream2 = vfs.src(['./fixtures/*.coffee', './fixtures/wow/*'], {cwd: __dirname, passthrough: true});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream1.pipe(stream2).pipe(bufferStream);
  });

  it('should still end when passing through empty streams', function(done) {
    var onEnd = function(){
      buffered.length.should.equal(0);
      done();
    };

    var stream1 = vfs.src([], {cwd: __dirname});
    var stream2 = vfs.src([], {cwd: __dirname, passthrough: true});

    var buffered = [];
    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
    stream1.pipe(stream2).pipe(bufferStream);
  });

  it('should follow file symlinks', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/test.coffee');

    var stream = vfs.src('./fixtures/test-symlink', {cwd: __dirname});
    stream.on('data', function(file){
      file.path.should.equal(expectedPath);
      done();
    });
  });

  it('should follow dir symlinks', function(done) {
    var expectedPath = path.join(__dirname, './fixtures/wow');

    var stream = vfs.src('./fixtures/test-symlink-dir', {cwd: __dirname});
    stream.on('data', function(file){
      file.path.should.equal(expectedPath);
      done();
    });
  });

});
<|endoftext|>


<commit_before>var Dissolve = require("../index");

describe("tap", function() {
  it("should emit data 2 times then end", function(done) {
    var reader = Dissolve().uint8("x").tap(function() {
      this.emit("data", this.vars.x);

      this.uint8("y").tap(function() {
        this.emit("data", this.vars.y);

        this.tap(function() {
          this.emit("done");
        });
      });
    });

    var counter = 0;

    reader.on("data", function() {
      counter++;
    });

    reader.on("done", function() {
      if (counter !== 2) {
        return done(Error("invalid counter value"));
      } else {
        return done();
      }
    });

    reader.write(Buffer([0x01, 0x01]));
  });
});
<commit_msg>added named tap job test<commit_after>var Dissolve = require("../index");

describe("tap", function() {
  it("should emit data 2 times then end", function(done) {
    var reader = Dissolve().uint8("x").tap(function() {
      this.emit("data", this.vars.x);

      this.uint8("y").tap(function() {
        this.emit("data", this.vars.y);

        this.tap(function() {
          this.emit("done");
        });
      });
    });

    var counter = 0;

    reader.on("data", function() {
      counter++;
    });

    reader.on("done", function() {
      if (counter !== 2) {
        return done(Error("invalid counter value"));
      } else {
        return done();
      }
    });

    reader.write(Buffer([0x01, 0x01]));
  });

  it("should populate child objects correctly", function(done) {
    var reader = Dissolve().tap("a", function() {
      this.uint8("x").tap("b", function() {
        this.uint8("y").tap(function() {
          this.emit("data", this.vars);
        });
      });
    });

    reader.on("data", function(e) {
      if (typeof e !== "object" || e === null) {
        return done(Error("invalid payload for data event"));
      }

      if (typeof e.a !== "object" || e.a === null || typeof e.a.b !== "object" || e.a.b === null) {
        return done(Error("child object(s) not set correctly"));
      }

      if (typeof e.a.x !== "number" || typeof e.a.b.y !== "number") {
        return done(Error("child object(s) not set correctly"));
      }

      return done();
    });

    reader.write(Buffer([0x01, 0x01]));
  });
});
<|endoftext|>


<commit_before>'use strict';

const execSync = require('child_process').execSync;
const pkg = require('../package');
const fs = require('fs');
const semver = require('semver');

module.exports = function(grunt) {
  grunt.registerTask('changelog', 'Add the changes since the last release to the changelog', releaseType => {
    const curVersion = pkg.version;
    const nextVersion = semver.inc(curVersion, releaseType);
    if (!nextVersion) {
      grunt.fail.fatal('Invalid release type: ' + releaseType);
    }

    const repoUrl = pkg.repository.url.slice(0, -4); // Slice off '.git'
    const getCommitLog = `git --no-pager log v${curVersion}... --pretty=format:"+ %s ([view](${repoUrl}/commit/%H))"`;
    const commitLog = execSync(getCommitLog).toString();
    const changes = commitLog.replace(/^\+ Merge.*[\r\n]*/gm, ''); // Filter out merge commits
    const date = new Date().toISOString().slice(0, 10);
    const versionHeader = '## ' + nextVersion + ' (' + date + ')\n';

    var changelog = fs.readFileSync('CHANGELOG.md', 'utf8');
    if (changelog.indexOf(versionHeader, 13) >= 0) {
      grunt.log.warn('Changelog already updated.');
      return;
    }
    changelog = '# CHANGELOG\n\n' +
                versionHeader + changes + '\n' +
                changelog.replace(/^# CHANGELOG\s+/, '\n');

    fs.writeFileSync('CHANGELOG.md', changelog);
    grunt.log.ok('Added changes to the changelog.');
  });
};
<commit_msg>Update changelog task to use short commit hash for link<commit_after>'use strict';

const execSync = require('child_process').execSync;
const pkg = require('../package');
const fs = require('fs');
const semver = require('semver');

module.exports = function(grunt) {
  grunt.registerTask('changelog', 'Add the changes since the last release to the changelog', releaseType => {
    const curVersion = pkg.version;
    const nextVersion = semver.inc(curVersion, releaseType);
    if (!nextVersion) {
      grunt.fail.fatal('Invalid release type: ' + releaseType);
    }

    const repoUrl = pkg.repository.url.slice(0, -4); // Slice off '.git'
    const getCommitLog = `git --no-pager log v${curVersion}... --pretty=format:"+ %s ([\`%h\`](${repoUrl}/commit/%H))"`;
    const commitLog = execSync(getCommitLog).toString();
    const changes = commitLog.replace(/^\+ Merge.*[\r\n]*/gm, ''); // Filter out merge commits
    const date = new Date().toISOString().slice(0, 10);
    const versionHeader = '## ' + nextVersion + ' (' + date + ')\n';

    var changelog = fs.readFileSync('CHANGELOG.md', 'utf8');
    if (changelog.indexOf(versionHeader, 13) >= 0) {
      grunt.log.warn('Changelog already updated.');
      return;
    }
    changelog = '# CHANGELOG\n\n' +
                versionHeader + changes + '\n' +
                changelog.replace(/^# CHANGELOG\s+/, '\n');

    fs.writeFileSync('CHANGELOG.md', changelog);
    grunt.log.ok('Added changes to the changelog.');
  });
};
<|endoftext|>


<commit_before>var base        = require('taskcluster-base');
var debug       = require('debug')('hooks:routes:v1');
var Promise     = require('promise');
var taskcluster = require('taskcluster-client');
var nextDate    = require('../hooks/nextdate');
var _           = require('lodash');

var api = new base.API({
  title:         "Hooks API Documentation",
  description:   [
    "Hooks are a mechanism for creating tasks in response to events.",
    "",
    "Hooks are identified with a `hookGroupId` and a `hookId`.",
    "",
    "When an event occurs, the resulting task is automatically created.  The",
    "task is created using the role `hook-id:<hookGroupId>/<hookId>`, which",
    "must have scopes to make the creteTask call, including satisfying all",
    "scopes in `task.scopes`.",
    "",
    "Hooks can have a 'schedule' indicating specific times that new tasks should",
    "be created.  Each schedule is in a simple cron format, per ",
    "https://www.npmjs.com/package/cron-parser.  For example:",
    " * `[\"0 0 1 * * *\"]` -- daily at 1:00 UTC",
    " * `[\"0 0 9,21 * * 1-5\", \"0 0 12 * * 0,6\"]` -- weekdays at 9:00 and 21:00 UTC, weekends at noon",
  ].join('\n'),
  schemaPrefix:  'http://schemas.taskcluster.net/hooks/v1/'
});

// Export api
module.exports = api;

/** Get hook groups **/
api.declare({
  method:       'get',
  route:        '/hooks',
  name:         'listHookGroups',
  idempotent:   true,
  output:       'list-hook-groups-response.json',
  title:        'List hook groups',
  description: [
    "This endpoint will return a list of all hook groups with at least one hook.",
  ].join('\n')
}, async function(req, res) {
  var groups = new Set();
  await this.Hook.scan({},{
    handler: (item) => {
      groups.add(item.hookGroupId);
    }
  });
  return res.reply({groups: Array.from(groups)});
});

/** Get hooks in a given group **/
api.declare({
  method:       'get',
  route:        '/hooks/:hookGroupId',
  name:         'listHooks',
  idempotent:   true,
  output:       'list-hooks-response.json',
  title:        'List hooks in a given group',
  description: [
    "This endpoint will return a list of all the hook definitions within a",
    "given hook group."
  ].join('\n')
}, async function(req, res) {
  var hooks = [];
  await this.Hook.query({
    hookGroupId: req.params.hookGroupId
  }, {
    handler: async (hook) => {
      hooks.push(await hook.definition());
    }
  });
  if (hooks.length == 0) {
    return res.status(404).json({
      message: "No such group"
    });
  }
  return res.reply({hooks: hooks});
});

/** Get hook definition **/
api.declare({
  method:       'get',
  route:        '/hooks/:hookGroupId/:hookId',
  name:         'hook',
  idempotent:   true,
  output:       'hook-definition.json',
  title:        'Get hook definition',
  description: [
    "This endpoint will return the hook defintion for the given `hookGroupId`",
    "and hookId."
  ].join('\n')
}, async function(req, res) {
  let hook = await this.Hook.load({
    hookGroupId: req.params.hookGroupId,
    hookId:      req.params.hookId
  }, true);

  // Handle the case where the hook doesn't exist
  if (!hook) {
    return res.status(404).json({
      message: "Hook not found"
    });
  }

  // Reply with the hook definition
  let definition = await hook.definition();
  return res.reply(definition);
});

/** Get next scheduled hook date */
api.declare({
  method:       'get',
  route:        '/hooks/:hookGroupId/:hookId/schedule',
  name:         'getHookSchedule',
  output:       'hook-schedule.json',
  title:        'Get hook schedule',
  description: [
    "This endpoint will return the schedule and next scheduled creation time",
    "for the given hook."
  ].join('\n')
}, async function(req, res) {
  let hook = await this.Hook.load({
    hookGroupId: req.params.hookGroupId,
    hookId:      req.params.hookId
  }, true);

  // Handle the case where the hook doesn't exist
  if (!hook) {
    return res.status(404).json({
      message: "Hook not found"
    });
  }

  // Return a schedule only if a schedule is defined
  if (hook.schedule.length > 0) {
    return res.reply({
      schedule: hook.schedule,
      nextScheduledDate: hook.nextScheduledDate.toJSON()
    });
  }
  return res.reply({});
});

/** Create a hook **/
api.declare({
  method:       'put',
  route:        '/hooks/:hookGroupId/:hookId',
  name:         'createHook',
  deferAuth:    true,
  idempotent:   true,
  scopes:       [["hooks:modify-hook:<hookGroupId>/<hookId>"]],
  input:        'create-hook-request.json',
  output:       'hook-definition.json',
  title:        'Create a hook',
  description: [
    "This endpoint will create a new hook.",
    "",
    "The caller's credentials need not satisfy `hook.task.scopes`. Instead,",
    "the role for the hook must satisfy these scopes as well as the necessary",
    "scopes to add the task to the queue.",
  ].join('\n')
}, async function(req, res) {
  var hookGroupId = req.params.hookGroupId;
  var hookId    = req.params.hookId;
  var hookDef   = req.body;

  hookDef = _.defaults({}, hookDef, {
    hookGroupId,
    hookId,
    schedule: [],
    expires: ''
  });

  if (!req.satisfies({hookGroupId, hookId})) {
    return;
  }

  // Try to create a Hook entity
  try {
    var hook = await this.Hook.create(
      _.defaults({}, hookDef, {
        bindings:           [], // TODO
        accessToken:        taskcluster.slugid(),
        nextTaskId:         taskcluster.slugid(),
        nextScheduledDate:  nextDate(hookDef.schedule)
      }));
  }
  catch (err) {
    if (!err || err.code !== 'EntityAlreadyExists') {
      throw err;
    }
    let existingHook = await this.Hook.load({
        hookGroupId: req.params.hookGroupId,
        hookId:      req.params.hookId
    }, true);
    if (!_.isEqual(hookDef, await existingHook.definition())) {
      return res.status(409).json({
        message: "hook `" + hookGroupId + "/" + hookId + "` already exists."
      });
    }
  }

  // Reply with the hook definition
  return res.reply(hookDef);
});

/** Update hook definition**/
api.declare({
  method:       'patch',
  route:        '/hooks/:hookGroupId/:hookId',
  name:         'updateHook',
  deferAuth:    true,
  idempotent:   true,
  scopes:       [["hooks:modify-hook:<hookGroupId>/<hookId>"]],
  input:        'create-hook-request.json',
  output:       'hook-definition.json',
  title:        'Update a hook',
  description: [
    "This endpoint will update an existing hook.  All fields except",
    "`hookGroupId` and `hookId` can be modified.",
  ].join('\n')
}, async function(req, res) {
  var hookGroupId = req.params.hookGroupId;
  var hookId = req.params.hookId;
  var hookDef = req.body;

  if (!req.satisfies({hookGroupId, hookId})) {
    return;
  }

  var hook = await this.Hook.load({
    hookGroupId: hookGroupId,
    hookId:      hookId
  }, true);

  if (!hook) {
    return res.status(404).json({
      message: "Hook not found. " +
        "Use PUT instead of PATCH to create a resource."
    });
  }

  // Attempt to modify properties of the hook
  var schedule = hookDef.schedule ? hookDef.schedule : [];
  await hook.modify((hook) => {
    hook.metadata          = hookDef.metadata;
    hook.task              = hookDef.task;
    hook.deadline          = hookDef.deadline;
    hook.expires           = hookDef.expires ? hookDef.expires : '';
    hook.schedule          = schedule;
    hook.nextScheduledDate = nextDate(schedule);
  });

  let definition = await hook.definition();
  return res.reply(definition);
});

/** Delete hook definition**/
api.declare({
  method:       'delete',
  route:        '/hooks/:hookGroupId/:hookId',
  name:         'removeHook',
  idempotent:   true,
  deferAuth:    true,
  scopes:       [["hooks:modify-hook:<hookGroupId>/<hookId>"]],
  title:        'Delete a hook',
  description: [
    "This endpoint will remove a hook definition."
  ].join('\n')
}, async function(req, res) {
  var hookGroupId = req.params.hookGroupId;
  var hookId = req.params.hookId;

  if (!req.satisfies({hookGroupId, hookId})) {
    return;
  }

  // Remove the resource if it exists
  let hook = await this.Hook.load({
    hookGroupId: hookGroupId,
    hookId:      hookId
  }, true);

  if (!hook) {
    return res.status(404).json({
      message: "Resource does not exist."
    });
  }

  await hook.remove();

  return res.status(200).json({});
});

// XXX disabled for the first draft of this service
if (0) {

/** Get secret token for a trigger **/
api.declare({
  method:       'get',
  route:        '/hooks/:hookGroupId/:hookId/token',
  name:         'getTriggerToken',
  deferAuth:    true,
  scopes:       [["hooks:get-trigger-token:<hookGroupId>/<hookId>"]],
  input:        undefined,
  output:       'trigger-token-response.json',
  title:        'Get a trigger token',
  description: [
    "Retrieve a unique secret token for triggering the specified hook. This",
    "token can be deactivated with resetTriggerToken."
  ].join('\n')
}, async function(req, res) {
  var hookGroupId = req.params.hookGroupId;
  var hookId    = req.params.hookId;
  if (!req.satisfies({hookGroupId, hookId})) {
    return;
  }

  let hook = await this.Hook.load({
    hookGroupId: req.params.hookGroupId,
    hookId:      req.params.hookId
  }, true);

  if (!hook) {
    return res.status(404).json({
      message: "Hook not found"
    });
  }

  return res.reply({
    token: hook.accessToken
  });
});

/** Reset a trigger token **/
api.declare({
  method:       'post',
  route:        '/hooks/:hookGroupId/:hookId/token',
  name:         'resetTriggerToken',
  deferAuth:    true,
  scopes:       [["hooks:reset-trigger-token:<hookGroupId>/<hookId>"]],
  input:        undefined,
  output:       'trigger-token-response.json',
  title:        'Reset a trigger token',
  description: [
    "Reset the token for triggering a given hook. This invalidates token that",
    "may have been issued via getTriggerToken with a new token."
  ].join('\n')
}, async function(req, res) {
  var hookGroupId = req.params.hookGroupId;
  var hookId    = req.params.hookId;
  if (!req.satisfies({hookGroupId, hookId})) {
    return;
  }

  let hook = await this.Hook.load({
    hookGroupId: req.params.hookGroupId,
    hookId:      req.params.hookId
  }, true);

  if (!hook) {
    return res.status(404).json({
      message: "Hook not found"
    });
  }

  await hook.modify((hook) => {
    hook.accessToken = taskcluster.slugid();
  });

  return res.reply({
    token: hook.accessToken
  });
});

/** Trigger hook from a webhook with a token **/
api.declare({
  method:       'post',
  route:        '/hooks/:hookGroupId/:hookId/trigger/:token',
  name:         'triggerHookWithToken',
  input:        'trigger-payload.json',
  output:       'task-status.json',
  title:        'Trigger a hook with a token',
  description: [
    "This endpoint triggers a defined hook with a valid token."
  ].join('\n')
}, async function(req, res) {
  var payload = req.body;

  var hook = await this.Hook.load({
    hookGroupId: req.params.hookGroupId,
    hookId:      req.params.hookId
  }, true);

  // Return a 404 if the hook entity doesn't exist
  if (!hook) {
    return res.status(404).json({
      message: "Hook not found"
    });
  }

  // Return 401 if the token doesn't exist or doesn't match
  if (req.params.token !== hook.accessToken) {
    return res.status(401).json({
      message: "Invalid token"
    });
  }

  let resp = await this.taskcreator.fire(hook, payload);
  return res.reply(resp);
});

/** Trigger a hook for debugging **/
api.declare({
  method:       'post',
  route:        '/hooks/:hookGroupId/:hookId/trigger',
  name:         'triggerHook',
  deferAuth:    true,
  scopes:       [["hooks:trigger-hook:<hookGroupId>/<hookId>"]],
  input:        'trigger-payload.json',
  output:       'task-status.json',
  title:        'Trigger a hook',
  description: [
    "Trigger a hook, given that you have the correct scoping for it"
  ].join('\n')
}, async function(req, res) {
  var hookGroupId = req.params.hookGroupId;
  var hookId    = req.params.hookId;
  if (!req.satisfies({hookGroupId, hookId})) {
    return;
  }

  var payload = req.body;

  var hook = await this.Hook.load({
    hookGroupId: req.params.hookGroupId,
    hookId:      req.params.hookId
  }, true);

  // Return a 404 if the hook entity doesn't exist
  if (!hook) {
    return res.status(404).json({
      message: "Hook not found"
    });
  }

  let resp = await this.taskcreator.fire(hook, payload);
  return res.reply(resp);
});
}
<commit_msg>make removing idempotent<commit_after>var base        = require('taskcluster-base');
var debug       = require('debug')('hooks:routes:v1');
var Promise     = require('promise');
var taskcluster = require('taskcluster-client');
var nextDate    = require('../hooks/nextdate');
var _           = require('lodash');

var api = new base.API({
  title:         "Hooks API Documentation",
  description:   [
    "Hooks are a mechanism for creating tasks in response to events.",
    "",
    "Hooks are identified with a `hookGroupId` and a `hookId`.",
    "",
    "When an event occurs, the resulting task is automatically created.  The",
    "task is created using the role `hook-id:<hookGroupId>/<hookId>`, which",
    "must have scopes to make the creteTask call, including satisfying all",
    "scopes in `task.scopes`.",
    "",
    "Hooks can have a 'schedule' indicating specific times that new tasks should",
    "be created.  Each schedule is in a simple cron format, per ",
    "https://www.npmjs.com/package/cron-parser.  For example:",
    " * `[\"0 0 1 * * *\"]` -- daily at 1:00 UTC",
    " * `[\"0 0 9,21 * * 1-5\", \"0 0 12 * * 0,6\"]` -- weekdays at 9:00 and 21:00 UTC, weekends at noon",
  ].join('\n'),
  schemaPrefix:  'http://schemas.taskcluster.net/hooks/v1/'
});

// Export api
module.exports = api;

/** Get hook groups **/
api.declare({
  method:       'get',
  route:        '/hooks',
  name:         'listHookGroups',
  idempotent:   true,
  output:       'list-hook-groups-response.json',
  title:        'List hook groups',
  description: [
    "This endpoint will return a list of all hook groups with at least one hook.",
  ].join('\n')
}, async function(req, res) {
  var groups = new Set();
  await this.Hook.scan({},{
    handler: (item) => {
      groups.add(item.hookGroupId);
    }
  });
  return res.reply({groups: Array.from(groups)});
});

/** Get hooks in a given group **/
api.declare({
  method:       'get',
  route:        '/hooks/:hookGroupId',
  name:         'listHooks',
  idempotent:   true,
  output:       'list-hooks-response.json',
  title:        'List hooks in a given group',
  description: [
    "This endpoint will return a list of all the hook definitions within a",
    "given hook group."
  ].join('\n')
}, async function(req, res) {
  var hooks = [];
  await this.Hook.query({
    hookGroupId: req.params.hookGroupId
  }, {
    handler: async (hook) => {
      hooks.push(await hook.definition());
    }
  });
  if (hooks.length == 0) {
    return res.status(404).json({
      message: "No such group"
    });
  }
  return res.reply({hooks: hooks});
});

/** Get hook definition **/
api.declare({
  method:       'get',
  route:        '/hooks/:hookGroupId/:hookId',
  name:         'hook',
  idempotent:   true,
  output:       'hook-definition.json',
  title:        'Get hook definition',
  description: [
    "This endpoint will return the hook defintion for the given `hookGroupId`",
    "and hookId."
  ].join('\n')
}, async function(req, res) {
  let hook = await this.Hook.load({
    hookGroupId: req.params.hookGroupId,
    hookId:      req.params.hookId
  }, true);

  // Handle the case where the hook doesn't exist
  if (!hook) {
    return res.status(404).json({
      message: "Hook not found"
    });
  }

  // Reply with the hook definition
  let definition = await hook.definition();
  return res.reply(definition);
});

/** Get next scheduled hook date */
api.declare({
  method:       'get',
  route:        '/hooks/:hookGroupId/:hookId/schedule',
  name:         'getHookSchedule',
  output:       'hook-schedule.json',
  title:        'Get hook schedule',
  description: [
    "This endpoint will return the schedule and next scheduled creation time",
    "for the given hook."
  ].join('\n')
}, async function(req, res) {
  let hook = await this.Hook.load({
    hookGroupId: req.params.hookGroupId,
    hookId:      req.params.hookId
  }, true);

  // Handle the case where the hook doesn't exist
  if (!hook) {
    return res.status(404).json({
      message: "Hook not found"
    });
  }

  // Return a schedule only if a schedule is defined
  if (hook.schedule.length > 0) {
    return res.reply({
      schedule: hook.schedule,
      nextScheduledDate: hook.nextScheduledDate.toJSON()
    });
  }
  return res.reply({});
});

/** Create a hook **/
api.declare({
  method:       'put',
  route:        '/hooks/:hookGroupId/:hookId',
  name:         'createHook',
  deferAuth:    true,
  idempotent:   true,
  scopes:       [["hooks:modify-hook:<hookGroupId>/<hookId>"]],
  input:        'create-hook-request.json',
  output:       'hook-definition.json',
  title:        'Create a hook',
  description: [
    "This endpoint will create a new hook.",
    "",
    "The caller's credentials need not satisfy `hook.task.scopes`. Instead,",
    "the role for the hook must satisfy these scopes as well as the necessary",
    "scopes to add the task to the queue.",
  ].join('\n')
}, async function(req, res) {
  var hookGroupId = req.params.hookGroupId;
  var hookId    = req.params.hookId;
  var hookDef   = req.body;

  hookDef = _.defaults({}, hookDef, {
    hookGroupId,
    hookId,
    schedule: [],
    expires: ''
  });

  if (!req.satisfies({hookGroupId, hookId})) {
    return;
  }

  // Try to create a Hook entity
  try {
    var hook = await this.Hook.create(
      _.defaults({}, hookDef, {
        bindings:           [], // TODO
        accessToken:        taskcluster.slugid(),
        nextTaskId:         taskcluster.slugid(),
        nextScheduledDate:  nextDate(hookDef.schedule)
      }));
  }
  catch (err) {
    if (!err || err.code !== 'EntityAlreadyExists') {
      throw err;
    }
    let existingHook = await this.Hook.load({
        hookGroupId: req.params.hookGroupId,
        hookId:      req.params.hookId
    }, true);
    if (!_.isEqual(hookDef, await existingHook.definition())) {
      return res.status(409).json({
        message: "hook `" + hookGroupId + "/" + hookId + "` already exists."
      });
    }
  }

  // Reply with the hook definition
  return res.reply(hookDef);
});

/** Update hook definition**/
api.declare({
  method:       'patch',
  route:        '/hooks/:hookGroupId/:hookId',
  name:         'updateHook',
  deferAuth:    true,
  idempotent:   true,
  scopes:       [["hooks:modify-hook:<hookGroupId>/<hookId>"]],
  input:        'create-hook-request.json',
  output:       'hook-definition.json',
  title:        'Update a hook',
  description: [
    "This endpoint will update an existing hook.  All fields except",
    "`hookGroupId` and `hookId` can be modified.",
  ].join('\n')
}, async function(req, res) {
  var hookGroupId = req.params.hookGroupId;
  var hookId = req.params.hookId;
  var hookDef = req.body;

  if (!req.satisfies({hookGroupId, hookId})) {
    return;
  }

  var hook = await this.Hook.load({
    hookGroupId: hookGroupId,
    hookId:      hookId
  }, true);

  if (!hook) {
    return res.status(404).json({
      message: "Hook not found. " +
        "Use PUT instead of PATCH to create a resource."
    });
  }

  // Attempt to modify properties of the hook
  var schedule = hookDef.schedule ? hookDef.schedule : [];
  await hook.modify((hook) => {
    hook.metadata          = hookDef.metadata;
    hook.task              = hookDef.task;
    hook.deadline          = hookDef.deadline;
    hook.expires           = hookDef.expires ? hookDef.expires : '';
    hook.schedule          = schedule;
    hook.nextScheduledDate = nextDate(schedule);
  });

  let definition = await hook.definition();
  return res.reply(definition);
});

/** Delete hook definition**/
api.declare({
  method:       'delete',
  route:        '/hooks/:hookGroupId/:hookId',
  name:         'removeHook',
  idempotent:   true,
  deferAuth:    true,
  scopes:       [["hooks:modify-hook:<hookGroupId>/<hookId>"]],
  title:        'Delete a hook',
  description: [
    "This endpoint will remove a hook definition."
  ].join('\n')
}, async function(req, res) {
  var hookGroupId = req.params.hookGroupId;
  var hookId = req.params.hookId;

  if (!req.satisfies({hookGroupId, hookId})) {
    return;
  }

  // Remove the resource if it exists
  let hook = await this.Hook.remove({
    hookGroupId: hookGroupId,
    hookId:      hookId
  }, true);

  return res.status(200).json({});
});

// XXX disabled for the first draft of this service
if (0) {

/** Get secret token for a trigger **/
api.declare({
  method:       'get',
  route:        '/hooks/:hookGroupId/:hookId/token',
  name:         'getTriggerToken',
  deferAuth:    true,
  scopes:       [["hooks:get-trigger-token:<hookGroupId>/<hookId>"]],
  input:        undefined,
  output:       'trigger-token-response.json',
  title:        'Get a trigger token',
  description: [
    "Retrieve a unique secret token for triggering the specified hook. This",
    "token can be deactivated with resetTriggerToken."
  ].join('\n')
}, async function(req, res) {
  var hookGroupId = req.params.hookGroupId;
  var hookId    = req.params.hookId;
  if (!req.satisfies({hookGroupId, hookId})) {
    return;
  }

  let hook = await this.Hook.load({
    hookGroupId: req.params.hookGroupId,
    hookId:      req.params.hookId
  }, true);

  if (!hook) {
    return res.status(404).json({
      message: "Hook not found"
    });
  }

  return res.reply({
    token: hook.accessToken
  });
});

/** Reset a trigger token **/
api.declare({
  method:       'post',
  route:        '/hooks/:hookGroupId/:hookId/token',
  name:         'resetTriggerToken',
  deferAuth:    true,
  scopes:       [["hooks:reset-trigger-token:<hookGroupId>/<hookId>"]],
  input:        undefined,
  output:       'trigger-token-response.json',
  title:        'Reset a trigger token',
  description: [
    "Reset the token for triggering a given hook. This invalidates token that",
    "may have been issued via getTriggerToken with a new token."
  ].join('\n')
}, async function(req, res) {
  var hookGroupId = req.params.hookGroupId;
  var hookId    = req.params.hookId;
  if (!req.satisfies({hookGroupId, hookId})) {
    return;
  }

  let hook = await this.Hook.load({
    hookGroupId: req.params.hookGroupId,
    hookId:      req.params.hookId
  }, true);

  if (!hook) {
    return res.status(404).json({
      message: "Hook not found"
    });
  }

  await hook.modify((hook) => {
    hook.accessToken = taskcluster.slugid();
  });

  return res.reply({
    token: hook.accessToken
  });
});

/** Trigger hook from a webhook with a token **/
api.declare({
  method:       'post',
  route:        '/hooks/:hookGroupId/:hookId/trigger/:token',
  name:         'triggerHookWithToken',
  input:        'trigger-payload.json',
  output:       'task-status.json',
  title:        'Trigger a hook with a token',
  description: [
    "This endpoint triggers a defined hook with a valid token."
  ].join('\n')
}, async function(req, res) {
  var payload = req.body;

  var hook = await this.Hook.load({
    hookGroupId: req.params.hookGroupId,
    hookId:      req.params.hookId
  }, true);

  // Return a 404 if the hook entity doesn't exist
  if (!hook) {
    return res.status(404).json({
      message: "Hook not found"
    });
  }

  // Return 401 if the token doesn't exist or doesn't match
  if (req.params.token !== hook.accessToken) {
    return res.status(401).json({
      message: "Invalid token"
    });
  }

  let resp = await this.taskcreator.fire(hook, payload);
  return res.reply(resp);
});

/** Trigger a hook for debugging **/
api.declare({
  method:       'post',
  route:        '/hooks/:hookGroupId/:hookId/trigger',
  name:         'triggerHook',
  deferAuth:    true,
  scopes:       [["hooks:trigger-hook:<hookGroupId>/<hookId>"]],
  input:        'trigger-payload.json',
  output:       'task-status.json',
  title:        'Trigger a hook',
  description: [
    "Trigger a hook, given that you have the correct scoping for it"
  ].join('\n')
}, async function(req, res) {
  var hookGroupId = req.params.hookGroupId;
  var hookId    = req.params.hookId;
  if (!req.satisfies({hookGroupId, hookId})) {
    return;
  }

  var payload = req.body;

  var hook = await this.Hook.load({
    hookGroupId: req.params.hookGroupId,
    hookId:      req.params.hookId
  }, true);

  // Return a 404 if the hook entity doesn't exist
  if (!hook) {
    return res.status(404).json({
      message: "Hook not found"
    });
  }

  let resp = await this.taskcreator.fire(hook, payload);
  return res.reply(resp);
});
}
<|endoftext|>


<commit_before><commit_msg>Update delete_post.js<commit_after>function deletePost(post_id, user_id, csrf_token) {
    $.ajax( {
        type: 'post',
        url: '/delete.php',
        data: {
            type: 2, // refer to /delete.php for information about this POST data.
            topic_id: post_id,
            user_id: user_id,
            csrf_token: csrf_token
        },
        success: function(html) {
            if(html == 'true') {
                // Later make it remove the comment from the page WITHOUT reloading?
            } else {
                alert(html);
            }
        }

    });
}
<|endoftext|>


<commit_before>/*jslint esversion: 6, node: true, nomen: true, unparam: true */
// TODO: enhance readability using res.format() https://expressjs.com/en/4x/api.html#res.format

'use strict';

var debug = require('debug')('myBus:rv2');
var express = require('express');
var router = express.Router();
var passport = require('passport');
var http_auth = require('../module/http_auth.js');
var sqlEscape = require('../module/sqlEscape.js');

// initial DB object
var mysql = require('promise-mysql');
var sql_config = require('../sql_config');
var db = mysql.createPool(sql_config.db);

router.get('/route', (req, res) => {
    debug(JSON.stringify(req.query));
    if (req.query.route) {
        var query = `SELECT * FROM \`Bus_stop\` WHERE \`route\`=${Number(req.query.route)}`;
        db.query(query).then((rows, field)=>{
            res.send(JSON.stringify(rows));
        }, (err)=>{
            throw err;
        });
    } else {
        var err = new Error('Too few arguments');
        err.status = 400;
        throw err;
    }
});

router.get('/bus', (req, res) => {
    res.set("Connection", "close");
    res.send('this is bus');
});

router.post('/register', (req, res) => {
    http_auth.register(req.body.uuid, req.body.password, req.body.phone).then((user) => {
        res.send(JSON.stringify(user));
    }, (err) => {
        res.status(err.code);
        res.json({
            description: err.message
        });
    });
});

router.get('/busArrival', (req, res) => {
    if (req.query.route === undefined) {
        res.status(400);
        res.json({
            description: 'Too few arguments (missing route)'
        });
    } else {
        var query = `SELECT * FROM \`Bus_arrival\` WHERE \`route\` = ${req.query.route} `;
        if (req.query.is_reverse !== undefined) {
            query += `AND \`is_reverse\` = ${sqlEscape.escapeBoolean(req.query.is_reverse)}`;
        }
        db.query(query).then((rows) => {
            if (rows.length === 0) {
                res.send(JSON.stringify(null));
            } else {
                res.send(JSON.stringify(rows));
            }
        });
    }
});

router.get('/lineStatus', (req, res) => {
    var query = '';

    if (req.query.verbose === undefined || sqlEscape.escapeBoolean(req.query.verbose) === true) {
        query += 'SELECT * ';
    } else {
        query += 'SELECT `closestStop` ';
    }

    query += 'FROM `Bus_status` ';

    if (req.query.route && req.query.is_reverse) {
        query += `WHERE \`route\` = ${db.escape(req.query.route)} AND \`is_reverse\` = ${sqlEscape.escapeBoolean(req.query.is_reverse)} `;
    } else {
        res.status(400);
        res.json({
            description: 'Too few arguments'
        });
    }

    if (req.query.sn) {
        query += `ORDER BY ABS(closestStop-${req.query.sn})`;
    }

    debug(query);
    res.set("Connection", "close");
    db.query(query).then((rows) => {
        if (rows.length === 0) {
            res.send(JSON.stringify(null));
        } else if (req.query.sn === undefined) {
            res.send(JSON.stringify(rows));
        } else {
            res.send(JSON.stringify(rows[0].closestStop));
        }
    });
});

router.post('/reservation',
    passport.authenticate('standard', {session: false}), (req, res) => {
    // INSERT INTO `Reservation_List`(`UUID`, `route`, `is_reverse`, `from_sn`, `to_sn`) VALUES ('B397A7F7',160,false,1,3)
    try {
        sqlEscape.escapeParam(req.body,
            'UID', null,
            'route', {type: 'number'},
            //'is_reverse', {optional: true},     // actually not needed anymore
            'from_sn', {type: 'number'},
            'to_sn', {type: 'number'}
        );
    } catch (err) {
        res.status(406);
        res.json({
            description: err.message
        });
        return;
    }

    if (req.user.UUID !== req.body.UID.substring(1, req.body.UID.length-1) &&
        http_auth.permissionLevel[req.user.permission] < http_auth.permissionLevel.arduino) {
        console.log('out');
        res.status(401);
        res.json({
            description: `you are not ${req.body.UID}`
        });
        return;
    }

    var query = `INSERT INTO \`Reservation_List\`(\`UID\`, \`route\`, \`is_reverse\`, \`from_sn\`, \`to_sn\`) ` +
                `VALUES (${req.body.UID},${req.body.route},${(req.body.from_sn<req.body.to_sn)},${req.body.from_sn},${req.body.to_sn})`;
    db.query(query).then((rows, field) => {
        res.json({description: "Register OK"});
    }, (err) => {
        if (err.code.includes('ER_DUP_ENTRY')) {
            debug(`Reservation with id ${req.body.UID} already exist, update`);
            //UPDATE `Reservation_List` SET `route`=160,`is_reverse`=true,`from_sn`=5,`to_sn`=3 WHERE `UID`='b397a7f7'
            query = `UPDATE \`Reservation_List\` SET \`route\`=${req.body.route},\`is_reverse\`=${(req.body.from_sn<req.body.to_sn)},\`from_sn\`=${req.body.from_sn},\`to_sn\`=${req.body.to_sn} WHERE \`UID\`=${req.body.UID}`;
            db.query(query).then(() => {
                res.json({description: "Register UPDATE OK"});
            });
        } else if (err.code.includes('ER_NO_REFERENCED_ROW')) {
            res.status(400);
            res.json({
                description: 'Error you are not registered yet'
            });
        } else {
            res.status(500);
            res.json({description: 'Unknown Error'});
        }
    });
});

router.post('/environment', (req, res) => {
    // INSERT INTO `Weather` (`route`, `sn`, `is_reverse`, `humidity`, `temperature`, `timestamp`) VALUES ('160', '2', '0', '50', '32', CURRENT_TIMESTAMP);
    // UPDATE `Weather` SET `route`='160',`sn`='2',`is_reverse`='true',`humidity`='50',`temperature`='32',`timestamp`=NOW() WHERE `route`='160' AND `sn`='2' AND `is_reverse`='true'
    var query = '';

    if (req.body.route === undefined || req.body.sn === undefined || req.body.is_reverse === undefined) {
        res.status(400);
        res.json({
            description: 'Too few arguments (route, sn, is_reverse are required)'
        });
        return;
    }

    query = `UPDATE \`Weather\` SET ` +
            `${req.body.humidity ? `\`humidity\`='${req.body.humidity}',` : ''}` +
            `${req.body.temp ? `\`temperature\`='${req.body.temp}',` : ''}` +
            `\`timestamp\`=CURRENT_TIMESTAMP ` +
            `WHERE \`route\`='${req.body.route}' AND \`sn\`='${req.body.sn}' AND \`is_reverse\`='${sqlEscape.escapeBoolean(req.body.sn)}'`;

    db.query(query).then((result) => {
        if (result.affectedRows <= 0) {
            query = `INSERT INTO \`Weather\` (\`route\`, \`sn\`, \`is_reverse\`, \`timestamp\`, ` +
                    `${req.body.humidity ? '`humidity`, ': ''}` +
                    `${req.body.tempe ? '`temperature`, ': ''}` +
                    `) VALUES ('${req.body.route}', '${req.body.sn}', '${req.body.is_reverse}', CURRENT_TIMESTAMP, ` +
                    `${req.body.humidity ? `'${req.body.humidity}', ` : ''}` +
                    `${req.body.temp ? `'${req.body.temp}'` : ''}` +
                    `)`;

            return db.query(query).then(() => {
                res.send('OK');
            });
        } else {
            res.send('OK');
        }
    });
});

router.get('/account/:uuid',
    passport.authenticate('standard',{session: false}),
    (req, res) => {
        if (req.params.uuid.toUpperCase() === req.user.UUID.toUpperCase()) {
            res.send(JSON.stringify(req.user));
        } else {
            debug(`User ${req.user.UUID} try to access ${req.params.uuid}'s account info'`);
            res.status(401);
            res.send('{"description":"Unauthorized"}');
        }

    }
);

module.exports = router;
<commit_msg>add DELETE /reservation<commit_after>/*jslint esversion: 6, node: true, nomen: true, unparam: true */
// TODO: enhance readability using res.format() https://expressjs.com/en/4x/api.html#res.format

'use strict';

var debug = require('debug')('myBus:rv2');
var express = require('express');
var router = express.Router();
var passport = require('passport');
var http_auth = require('../module/http_auth.js');
var sqlEscape = require('../module/sqlEscape.js');

// initial DB object
var mysql = require('promise-mysql');
var sql_config = require('../sql_config');
var db = mysql.createPool(sql_config.db);

router.get('/route', (req, res) => {
    debug(JSON.stringify(req.query));
    if (req.query.route) {
        var query = `SELECT * FROM \`Bus_stop\` WHERE \`route\`=${Number(req.query.route)}`;
        db.query(query).then((rows, field)=>{
            res.send(JSON.stringify(rows));
        }, (err)=>{
            throw err;
        });
    } else {
        var err = new Error('Too few arguments');
        err.status = 400;
        throw err;
    }
});

router.get('/bus', (req, res) => {
    res.set("Connection", "close");
    res.send('this is bus');
});

router.post('/register', (req, res) => {
    http_auth.register(req.body.uuid, req.body.password, req.body.phone).then((user) => {
        res.send(JSON.stringify(user));
    }, (err) => {
        res.status(err.code);
        res.json({
            description: err.message
        });
    });
});

router.get('/busArrival', (req, res) => {
    if (req.query.route === undefined) {
        res.status(400);
        res.json({
            description: 'Too few arguments (missing route)'
        });
    } else {
        var query = `SELECT * FROM \`Bus_arrival\` WHERE \`route\` = ${req.query.route} `;
        if (req.query.is_reverse !== undefined) {
            query += `AND \`is_reverse\` = ${sqlEscape.escapeBoolean(req.query.is_reverse)}`;
        }
        db.query(query).then((rows) => {
            if (rows.length === 0) {
                res.send(JSON.stringify(null));
            } else {
                res.send(JSON.stringify(rows));
            }
        });
    }
});

router.get('/lineStatus', (req, res) => {
    var query = '';

    if (req.query.verbose === undefined || sqlEscape.escapeBoolean(req.query.verbose) === true) {
        query += 'SELECT * ';
    } else {
        query += 'SELECT `closestStop` ';
    }

    query += 'FROM `Bus_status` ';

    if (req.query.route && req.query.is_reverse) {
        query += `WHERE \`route\` = ${db.escape(req.query.route)} AND \`is_reverse\` = ${sqlEscape.escapeBoolean(req.query.is_reverse)} `;
    } else {
        res.status(400);
        res.json({
            description: 'Too few arguments'
        });
    }

    if (req.query.sn) {
        query += `ORDER BY ABS(closestStop-${req.query.sn})`;
    }

    debug(query);
    res.set("Connection", "close");
    db.query(query).then((rows) => {
        if (rows.length === 0) {
            res.send(JSON.stringify(null));
        } else if (req.query.sn === undefined) {
            res.send(JSON.stringify(rows));
        } else {
            res.send(JSON.stringify(rows[0].closestStop));
        }
    });
});

router.post('/reservation',
    passport.authenticate('standard', {session: false}), (req, res) => {
    // INSERT INTO `Reservation_List`(`UUID`, `route`, `is_reverse`, `from_sn`, `to_sn`) VALUES ('B397A7F7',160,false,1,3)
    try {
        sqlEscape.escapeParam(req.body,
            'UID', null,
            'route', {type: 'number'},
            //'is_reverse', {optional: true},     // actually not needed anymore
            'from_sn', {type: 'number'},
            'to_sn', {type: 'number'}
        );
    } catch (err) {
        res.status(406);
        res.json({
            description: err.message
        });
        return;
    }

    if (req.user.UUID !== req.body.UID.substring(1, req.body.UID.length-1) &&
        http_auth.permissionLevel[req.user.permission] < http_auth.permissionLevel.arduino) {
        console.log('out');
        res.status(401);
        res.json({
            description: `you are not ${req.body.UID}`
        });
        return;
    }

    var query = `INSERT INTO \`Reservation_List\`(\`UID\`, \`route\`, \`is_reverse\`, \`from_sn\`, \`to_sn\`) ` +
                `VALUES (${req.body.UID},${req.body.route},${(req.body.from_sn<req.body.to_sn)},${req.body.from_sn},${req.body.to_sn})`;
    db.query(query).then((rows, field) => {
        res.json({description: "Register OK"});
    }, (err) => {
        if (err.code.includes('ER_DUP_ENTRY')) {
            debug(`Reservation with id ${req.body.UID} already exist, update`);
            //UPDATE `Reservation_List` SET `route`=160,`is_reverse`=true,`from_sn`=5,`to_sn`=3 WHERE `UID`='b397a7f7'
            query = `UPDATE \`Reservation_List\` SET \`route\`=${req.body.route},\`is_reverse\`=${(req.body.from_sn<req.body.to_sn)},\`from_sn\`=${req.body.from_sn},\`to_sn\`=${req.body.to_sn} WHERE \`UID\`=${req.body.UID}`;
            db.query(query).then(() => {
                res.json({description: "Register UPDATE OK"});
            });
        } else if (err.code.includes('ER_NO_REFERENCED_ROW')) {
            res.status(400);
            res.json({
                description: 'Error you are not registered yet'
            });
        } else {
            res.status(500);
            res.json({description: 'Unknown Error'});
        }
    });
});

router.delete('/reservation', (req, res) => {
    // DELETE FROM `Reservation_List` WHERE `Reservation_List`.`UID` = 'b397a7f7'
    passport.authenticate('standard', {session: false}, (req, res) => {
        try {
            sqlEscape.escapeParam(req.query,
                'UID', null
            );
        } catch (err) {
            res.status(406);
            res.json({
                description: err.message
            });
            return;
        }
    });

    db.query(`DELETE FROM \`Reservation_List\` WHERE \`Reservation_List\`.\`UID\` = '${req.query.UID}'`)
        .then( (result, err) => {
            if (result.affectedRows > 0) {
                res.status(200);
                res.json({
                    description: `Delete ${result.affectedRows} reservation`
                });
            } else {
                res.status(404);
                res.json({
                    description: 'You have NOT make any reservation yet'
                });
            }
        });
});
router.post('/environment', (req, res) => {
    // INSERT INTO `Weather` (`route`, `sn`, `is_reverse`, `humidity`, `temperature`, `timestamp`) VALUES ('160', '2', '0', '50', '32', CURRENT_TIMESTAMP);
    // UPDATE `Weather` SET `route`='160',`sn`='2',`is_reverse`='true',`humidity`='50',`temperature`='32',`timestamp`=NOW() WHERE `route`='160' AND `sn`='2' AND `is_reverse`='true'
    var query = '';

    if (req.body.route === undefined || req.body.sn === undefined || req.body.is_reverse === undefined) {
        res.status(400);
        res.json({
            description: 'Too few arguments (route, sn, is_reverse are required)'
        });
        return;
    }

    query = `UPDATE \`Weather\` SET ` +
            `${req.body.humidity ? `\`humidity\`='${req.body.humidity}',` : ''}` +
            `${req.body.temp ? `\`temperature\`='${req.body.temp}',` : ''}` +
            `\`timestamp\`=CURRENT_TIMESTAMP ` +
            `WHERE \`route\`='${req.body.route}' AND \`sn\`='${req.body.sn}' AND \`is_reverse\`='${sqlEscape.escapeBoolean(req.body.sn)}'`;

    db.query(query).then((result) => {
        if (result.affectedRows <= 0) {
            query = `INSERT INTO \`Weather\` (\`route\`, \`sn\`, \`is_reverse\`, \`timestamp\`, ` +
                    `${req.body.humidity ? '`humidity`, ': ''}` +
                    `${req.body.tempe ? '`temperature`, ': ''}` +
                    `) VALUES ('${req.body.route}', '${req.body.sn}', '${req.body.is_reverse}', CURRENT_TIMESTAMP, ` +
                    `${req.body.humidity ? `'${req.body.humidity}', ` : ''}` +
                    `${req.body.temp ? `'${req.body.temp}'` : ''}` +
                    `)`;

            return db.query(query).then(() => {
                res.send('OK');
            });
        } else {
            res.send('OK');
        }
    });
});

router.get('/account/:uuid',
    passport.authenticate('standard',{session: false}),
    (req, res) => {
        if (req.params.uuid.toUpperCase() === req.user.UUID.toUpperCase()) {
            res.send(JSON.stringify(req.user));
        } else {
            debug(`User ${req.user.UUID} try to access ${req.params.uuid}'s account info'`);
            res.status(401);
            res.send('{"description":"Unauthorized"}');
        }

    }
);

module.exports = router;
<|endoftext|>


<commit_before>/*!
 * URI.js - Mutating URLs
 * jQuery Plugin
 *
 * Version: 1.7.2
 *
 * Author: Rodney Rehm
 * Web: http://medialize.github.com/URI.js/jquery-uri-plugin.html
 *
 * Licensed under
 *   MIT License http://www.opensource.org/licenses/mit-license
 *   GPL v3 http://opensource.org/licenses/GPL-3.0
 *
 */

(function($, undefined){

var URI = typeof module !== "undefined" && module.exports
    ? require('./URIjs')
    : window.URI;

function escapeRegEx(string) {
    // https://github.com/medialize/URI.js/commit/85ac21783c11f8ccab06106dba9735a31a86924d#commitcomment-821963
    return string.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
}

function getUriProperty(elem) {
    var property;

    $.each(['href', 'src', 'action'], function(k, v) {
        if (v in elem) {
            property = v;
            return false;
        }

        return true;
    });

    // compensate ambiguous <input>
    if (elem.nodeName.toLowerCase() === 'input' && elem.type !== 'image') {
        return undefined;
    }

    return property;
}

var pseudo = /^([a-zA-Z]+)\s*([\^\$*]?=|:)\s*(['"]?)(.+)\3|^\s*([a-zA-Z0-9]+)\s*$/,
    comparable = {},
    // https://developer.mozilla.org/en/CSS/Attribute_selectors
    compare = {
        // equals
        '=': function(value, target) {
            return value === target;
        },
        // ~= translates to value.match((?:^|\s)target(?:\s|$)) which is useless for URIs
        // |= translates to value.match((?:\b)target(?:-|\s|$)) which is useless for URIs
        // begins with
        '^=': function(value, target, property) {
            return !!(value + "").match(new RegExp('^' + escapeRegEx(target), 'i'));
        },
        // ends with
        '$=': function(value, target, property) {
            return !!(value + "").match(new RegExp(escapeRegEx(target) + '$', 'i'));
        },
        // contains
        '*=': function(value, target, property) {
            if (property == 'directory') {
                // add trailing slash so /dir/ will match the deep-end as well
                value += '/';
            }

            return !!(value + "").match(new RegExp(escapeRegEx(target), 'i'));
        },
        'equals:': function(uri, target) {
            return uri.equals(target);
        },
        'is:': function(uri, target) {
            return uri.is(target);
        }
    },
    generateAccessor = function(property) {
        return {
            get: function(elem) {
                return $(elem).uri()[property]();
            },
            set: function(elem, value) {
                $(elem).uri()[property](value);
                return value;
            }
        };
    };

// populate lookup table and register $.attr('uri:accessor') handlers
$.each('authority directory domain filename fragment hash host hostname href password path pathname port protocol query scheme search subdomain suffix tld username'.split(" "), function(k, v) {
    comparable[v] = true;
    $.attrHooks['uri:' + v] = generateAccessor(v);
});

// general URI accessor
$.fn.uri = function(uri) {
    var $this = this.first(),
        elem = $this.get(0),
        property = getUriProperty(elem);

    if (!property) {
        throw new Error('Element "' + elem.nodeName + '" does not have either property: href, src, action');
    }

    if (uri !== undefined) {
        var old = $this.data('uri');
        if (old) {
            return old.href(uri);
        }

        if (!(uri instanceof URI)) {
            uri = URI(uri);
        }
    } else {
        uri = $this.data('uri');
        if (uri) {
            return uri;
        } else {
    		uri = URI($this.attr(property));
        }
    }

    uri._dom_element = elem;
    uri._dom_attribute = property;
    uri.normalize();
    $this.data('uri', uri);
    return uri;
};

// overwrite URI.build() to update associated DOM element if necessary
URI.prototype.build = function(deferBuild) {
    if (this._dom_element) {
        // cannot defer building when hooked into a DOM element
        this._string = URI.build(this._parts);
        this._deferred_build = false;
        this._dom_element.setAttribute(this._dom_attribute, this._string);
        this._dom_element[this._dom_attribute] = this._string;
    } else if (deferBuild === true) {
        this._deferred_build = true;
    } else if (deferBuild === undefined || this._deferred_build) {
        this._string = URI.build(this._parts);
        this._deferred_build = false;
    }

    return this;
};

// :uri() pseudo-selector for $.find(), $.filter() $.is(), et al.
$.expr.filters.uri = function(elem, index, matches) {
    // documentation on this is scarce, look into
    //  - https://github.com/jquery/sizzle/wiki/Sizzle-Home
    //  - https://github.com/jquery/sizzle/blob/master/sizzle.js#L626

    // skip anything without src|href|action and bad :uri() syntax
    if (!getUriProperty(elem) || !matches[3]) {
        return false;
    }

    var t = matches[3].match(pseudo),
        property,
        uri;

    if (!t || (!t[5] && t[2] !== ':' && !compare[t[2]])) {
        // abort because the given selector cannot be executed
        // filers seem to fail silently
        return false;
    }

    uri = $(elem).uri();

    if (t[5]) {
        return uri.is(t[5]);
    } else if (t[2] === ':') {
        property = t[1].toLowerCase() + ':';
        if (!compare[property]) {
            // filers seem to fail silently
            return false;
        }

        return compare[property](uri, t[4]);
    } else {
        property = t[1].toLowerCase();
        if (!comparable[property]) {
            // filers seem to fail silently
            return false;
        }

        return compare[t[2]](uri[property](), t[4], property);
    }

    return false;
};

// pipe $.attr('src') and $.attr('href') through URI.js
var _attrHooks = {
    get: function(elem) {
        return $(elem).uri();
    },
    set: function(elem, value) {
        return $(elem).uri().href(value).toString();
    }
};
$.each(['src', 'href', 'action', 'uri'], function(k, v) {
    $.attrHooks[v] = {
        set: _attrHooks.set
    };
});
$.attrHooks.uri.get = _attrHooks.get;

})(jQuery);<commit_msg>Fixing Issue #48 - IE9 reports img.href instead of img.src<commit_after>/*!
 * URI.js - Mutating URLs
 * jQuery Plugin
 *
 * Version: 1.7.2
 *
 * Author: Rodney Rehm
 * Web: http://medialize.github.com/URI.js/jquery-uri-plugin.html
 *
 * Licensed under
 *   MIT License http://www.opensource.org/licenses/mit-license
 *   GPL v3 http://opensource.org/licenses/GPL-3.0
 *
 */

(function($, undefined){

var URI = typeof module !== "undefined" && module.exports
    ? require('./URIjs')
    : window.URI;

function escapeRegEx(string) {
    // https://github.com/medialize/URI.js/commit/85ac21783c11f8ccab06106dba9735a31a86924d#commitcomment-821963
    return string.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
}

function getUriProperty(elem) {
    var property;

    // Note: IE9 will report img.href, so check img.src first (Issue #48)
    $.each(['src', 'href', 'action'], function(k, v) {
        if (v in elem ) {
            property = v;
            return false;
        }

        return true;
    });

    // compensate ambiguous <input>
    if (elem.nodeName.toLowerCase() === 'input' && elem.type !== 'image') {
        return undefined;
    }

    return property;
}

var pseudo = /^([a-zA-Z]+)\s*([\^\$*]?=|:)\s*(['"]?)(.+)\3|^\s*([a-zA-Z0-9]+)\s*$/,
    comparable = {},
    // https://developer.mozilla.org/en/CSS/Attribute_selectors
    compare = {
        // equals
        '=': function(value, target) {
            return value === target;
        },
        // ~= translates to value.match((?:^|\s)target(?:\s|$)) which is useless for URIs
        // |= translates to value.match((?:\b)target(?:-|\s|$)) which is useless for URIs
        // begins with
        '^=': function(value, target, property) {
            return !!(value + "").match(new RegExp('^' + escapeRegEx(target), 'i'));
        },
        // ends with
        '$=': function(value, target, property) {
            return !!(value + "").match(new RegExp(escapeRegEx(target) + '$', 'i'));
        },
        // contains
        '*=': function(value, target, property) {
            if (property == 'directory') {
                // add trailing slash so /dir/ will match the deep-end as well
                value += '/';
            }

            return !!(value + "").match(new RegExp(escapeRegEx(target), 'i'));
        },
        'equals:': function(uri, target) {
            return uri.equals(target);
        },
        'is:': function(uri, target) {
            return uri.is(target);
        }
    },
    generateAccessor = function(property) {
        return {
            get: function(elem) {
                return $(elem).uri()[property]();
            },
            set: function(elem, value) {
                $(elem).uri()[property](value);
                return value;
            }
        };
    };

// populate lookup table and register $.attr('uri:accessor') handlers
$.each('authority directory domain filename fragment hash host hostname href password path pathname port protocol query scheme search subdomain suffix tld username'.split(" "), function(k, v) {
    comparable[v] = true;
    $.attrHooks['uri:' + v] = generateAccessor(v);
});

// general URI accessor
$.fn.uri = function(uri) {
    var $this = this.first(),
        elem = $this.get(0),
        property = getUriProperty(elem);

    if (!property) {
        throw new Error('Element "' + elem.nodeName + '" does not have either property: href, src, action');
    }

    if (uri !== undefined) {
        var old = $this.data('uri');
        if (old) {
            return old.href(uri);
        }

        if (!(uri instanceof URI)) {
            uri = URI(uri);
        }
    } else {
        uri = $this.data('uri');
        if (uri) {
            return uri;
        } else {
    		uri = URI($this.attr(property));
        }
    }

    uri._dom_element = elem;
    uri._dom_attribute = property;
    uri.normalize();
    $this.data('uri', uri);
    return uri;
};

// overwrite URI.build() to update associated DOM element if necessary
URI.prototype.build = function(deferBuild) {
    if (this._dom_element) {
        // cannot defer building when hooked into a DOM element
        this._string = URI.build(this._parts);
        this._deferred_build = false;
        this._dom_element.setAttribute(this._dom_attribute, this._string);
        this._dom_element[this._dom_attribute] = this._string;
    } else if (deferBuild === true) {
        this._deferred_build = true;
    } else if (deferBuild === undefined || this._deferred_build) {
        this._string = URI.build(this._parts);
        this._deferred_build = false;
    }

    return this;
};

// :uri() pseudo-selector for $.find(), $.filter() $.is(), et al.
$.expr.filters.uri = function(elem, index, matches) {
    // documentation on this is scarce, look into
    //  - https://github.com/jquery/sizzle/wiki/Sizzle-Home
    //  - https://github.com/jquery/sizzle/blob/master/sizzle.js#L626

    // skip anything without src|href|action and bad :uri() syntax
    if (!getUriProperty(elem) || !matches[3]) {
        return false;
    }

    var t = matches[3].match(pseudo),
        property,
        uri;

    if (!t || (!t[5] && t[2] !== ':' && !compare[t[2]])) {
        // abort because the given selector cannot be executed
        // filers seem to fail silently
        return false;
    }

    uri = $(elem).uri();

    if (t[5]) {
        return uri.is(t[5]);
    } else if (t[2] === ':') {
        property = t[1].toLowerCase() + ':';
        if (!compare[property]) {
            // filers seem to fail silently
            return false;
        }

        return compare[property](uri, t[4]);
    } else {
        property = t[1].toLowerCase();
        if (!comparable[property]) {
            // filers seem to fail silently
            return false;
        }

        return compare[t[2]](uri[property](), t[4], property);
    }

    return false;
};

// pipe $.attr('src') and $.attr('href') through URI.js
var _attrHooks = {
    get: function(elem) {
        return $(elem).uri();
    },
    set: function(elem, value) {
        return $(elem).uri().href(value).toString();
    }
};
$.each(['src', 'href', 'action', 'uri'], function(k, v) {
    $.attrHooks[v] = {
        set: _attrHooks.set
    };
});
$.attrHooks.uri.get = _attrHooks.get;

})(jQuery);<|endoftext|>