<commit_before>const Router = require('express').Router;
const router = Router();
const User = require('../models/user');
<<<<<<< HEAD
// const Rule = require('../models/rule');
=======
>>>>>>> fdaa321dfb1e94eb768cb7d10042ba6ba0f309e2

router
    .get('/users', (req, res, next) => {
        User.find({ role: 'user' })
            .lean()
            .select('name email role status')
            .select('-_id')
            .then(users => res.send(users))
            .catch(next);
    })

    .get('/users/:email', (req, res, next) => {
        User.findOne({ email: req.params.email })
            .lean()
            .select('name email role status')
            .select('-_id')
            .then(user => res.send(user))
            .catch(next);
    })

    .patch('/users/:email', (req, res, next) => {
        User.findOneAndUpdate(
            { email: req.params.email },
            { $set: req.body },
            { new: true, runValidators: true }
        )
            .lean()
            .select('name email role status')
            .select('-_id')
            .then(user => res.send(user))
            .catch(next);
    })

    .delete('/users/:email', (req, res, next) => {
        User.remove({ email: req.params.email })
            .then(result => res.send({ removed: !!result }))
            .catch(next);
    });
<<<<<<< HEAD

    // .get('/rules', (req, res, next) => {
    //     Rule.find()
    //         .lean()
    //         .select('name active description')
    //         .select('-_id')
    //         .then(rule => res.send(rule))
    //         .catch(next);
    // })

    // .patch('/rules/:name', (req, res, next) => {
    //     Rule.findOneAndUpdate(
    //         { name: req.params.name },
    //         { $set: req.body },
    //         { new: true, runValidators: true }
    //     )
    //         .lean()
    //         .select('name active description')
    //         .select('-_id')
    //         .then(rule => res.send(rule))
    //         .catch(next);
    // });
=======
>>>>>>> fdaa321dfb1e94eb768cb7d10042ba6ba0f309e2

module.exports = router;
<commit_msg>Resolve merge conflict in routes/admin.js<commit_after>const Router = require('express').Router;
const router = Router();
const User = require('../models/user');

router
    .get('/users', (req, res, next) => {
        User.find({ role: 'user' })
            .lean()
            .select('name email role status')
            .select('-_id')
            .then(users => res.send(users))
            .catch(next);
    })

    .get('/users/:email', (req, res, next) => {
        User.findOne({ email: req.params.email })
            .lean()
            .select('name email role status')
            .select('-_id')
            .then(user => res.send(user))
            .catch(next);
    })

    .patch('/users/:email', (req, res, next) => {
        User.findOneAndUpdate(
            { email: req.params.email },
            { $set: req.body },
            { new: true, runValidators: true }
        )
            .lean()
            .select('name email role status')
            .select('-_id')
            .then(user => res.send(user))
            .catch(next);
    })

    .delete('/users/:email', (req, res, next) => {
        User.remove({ email: req.params.email })
            .then(result => res.send({ removed: !!result }))
            .catch(next);
    });
<<<<<<< HEAD

    // .get('/rules', (req, res, next) => {
    //     Rule.find()
    //         .lean()
    //         .select('name active description')
    //         .select('-_id')
    //         .then(rule => res.send(rule))
    //         .catch(next);
    // })

    // .patch('/rules/:name', (req, res, next) => {
    //     Rule.findOneAndUpdate(
    //         { name: req.params.name },
    //         { $set: req.body },
    //         { new: true, runValidators: true }
    //     )
    //         .lean()
    //         .select('name active description')
    //         .select('-_id')
    //         .then(rule => res.send(rule))
    //         .catch(next);
    // });
=======
>>>>>>> fdaa321dfb1e94eb768cb7d10042ba6ba0f309e2

module.exports = router;
<|endoftext|>


<commit_before>var User = require('../model/user');
var Group = require('../model/group');
var Message = require('../model/message');
var async = require('async');
var ObjectId = require('mongoose').Types.ObjectId;
var io = require('../socket/socket');
var GroupSetting = require('../model/groupSetting');

exports.getGroups = function(req, res, next) {
  var usr = req.user;

  GroupSetting.find({'user': usr._id}, function(err, gses) {

    Group.find( { 'members' : usr._id }, '_id members leftMembers name lastMessage')
      .populate('members', 'username')
      .populate('leftMembers', 'username')
      .populate('lastMessage')
      .exec(function(err, groups) {
	if (err) return next(500);

	///
	/// Sort groups so the most recent messages move up to the top
	///
	groups.sort(function(a, b) {
	  var first;
	  if (a.lastMessage) {
	    first = a.lastMessage.sent;
	  } else {
	    return 1;
	  }
	  var second;
	  if (b.lastMessage) {
	    second = b.lastMessage.sent;
	  } else {
	    return -1;
	  }

          return ((first < second) ? 1 : ((first > second) ? -1 : 0));
	});

	///
	/// For each group - find the group setting object associated with it
	/// and if it exists, add the unread count to this group
	///
	groups.forEach(function(g) {
	  var index = gses.indexOfEquals(g._id, 'group');
	  if (index > -1) {
	    g.unread = gses[index].unread;
	  } else {
	    g.unread = 0;
	  }
	});

	res.json(groups);
      });
  });
};

exports.createGroup = function(req, res, next) {
  var usr = req.user;

  console.log('BODY: ' + JSON.stringify(req.body, null, 4));

  var members = req.body.members;
  if (!members || !(members instanceof Array) || members.length == 0) {
    return next('The "members" value must be a valid array of length 1!');
  }

  var message = req.body.text;
  if (!message) {
    return next('You must send a message with the new group!');
  }

  var cb = function(err, group) {
    if (err) return next(err);
    res.send(201, group);
  };

  var name = req.body.name;

  for (var i = 0; i < members.length; i++) {
    members[i] = members[i].toLowerCase();
  }

  User.find({'username': { $in: members } }, function(err, users) {
    if (err || users.length == 0) {
      return next('No users were found with those usernames!');
    }

    console.log('Found Users: ' + JSON.stringify(users, null, 4));

    var otherMembers = [];
    users.forEach(function(user) {
      if (!user._id.equals(usr._id)) {
	otherMembers.push(user);
      }
    });

    if (otherMembers.length === 0) {
      return next('You can\'t make a group with only yourself!');
    }

    newGroup(name, otherMembers, message, usr, cb);
  });

};

function newGroup(groupName, members, message, creator, cb) {

  members.push(creator);

  Group.newGroup({'name': groupName, 'members': members}, function(err, group) {
    if (err) return cb(err);

    var aMessage = new Message({'from' : creator._id,
				'group': group._id,
				'text' : message,
				'sent' : new Date()
			       });

    aMessage.save(function(err) {
      group.messages.push(aMessage._id);
      group.save();

      ///
      /// Emit a new message to socket users
      ///
      var usersNotOn = [];
      members.forEach(function(user) {
	if ( !user._id.equals(creator._id) ) { //Don't emit to creator
	  var didSend = io.emitNewGroup(user._id, group);
	  if (!didSend) {
	    usersNotOn.push(user);
	  }
	}
      });

      var text = creator.username + '@' + group.name + ': ' + message;
      usersNotOn.forEach(function(user) {
	user.push(group, text, null, false);
      });

      cb(null, group);
    });

  });
};

// PUT /group/:id/leave
exports.leaveGroup = function(req, res, next) {

  var idParam = req.params.id.toString();
  var groupId = new ObjectId(idParam);
  var user = req.user;

  // To leave a group, we must:
  // put them in the leftMembers array in the group
  // remove them from the members array in the group
  // add the group to leftGroups in the profile
  // remove the group from groups in the profile

  Group.findOne( { _id : groupId }, function(err, group) {
    if (!group) {
      return next(404);
    }

    var index = group.members.indexOfEquals(user._id);
    if (index === -1) {
      return next(404);
    }

    async.parallel([
      function(callback) {
	// update group
	group.members.splice(index, 1);
	group.leftMembers.push(user._id);
	group.save(function(err) {
	  callback(err);
	});
      },
      function(callback){
	// Update profile
	var groupIndex = user.groups.indexOfEquals(groupId);
	console.log('Index2: ' + groupIndex);
	if (groupIndex > -1) {
	  user.groups.splice(groupIndex, 1);
	  user.leftGroups.push(groupId);
	  user.save(function(err) {
	    callback(err);
	  });
	} else {
	  callback();
	}
      },
      function(callback) {
	// send a message to the group notifying them that the person left
	var aMessage = new Message({'from' : null,
				    'group': group._id,
				    'text' : user.username + ' has left the group.',
				    'sent' : new Date(),
				    'type' : 'system'
				   });
	aMessage.save();
	io.messageToGroup(group._id, 'member_left', aMessage);
	callback();
      }
    ],
    // optional callback
    function(err, results) {
      if (err) return next(err);

      res.json(200, {});
    });
  });
};

exports.changeSettings = function(req, res, next) {
  console.log('HERE');
  var name = req.body.name;
  var idParam = req.params.id.toString();
  var groupId = new ObjectId(idParam);
  var user = req.user;

  if (!user.hasGroup(groupId)) {
    return next(404);
  }

  Group.findOne( { _id : groupId }, function(err, group) {
    if (err || !group) return next(404);

    group.name = name;
    group.save(function(err) {

      var aMessage = new Message({'from' : null,
				  'group': group._id,
				  'text' : 'Group is now called ' + name,
				  'sent' : new Date(),
				  'type' : 'system'
				 });
      aMessage.save();
      io.messageToGroup(group._id, 'group_name', aMessage);

      res.send(200, {});
    });
  });
};

exports.add = function(req, res, next) {
  console.log('Invite Body: ' + JSON.stringify(req.body, null, 4));

  var idParam = req.params.id.toString();
  var invites = req.body.invitees;
  var groupId = new ObjectId(idParam);

  if ( !(invites instanceof Array) ) {
    return next('invitees must be an Array!');
  }

  if (invites.length == 0 ) {
    return res.json(200, {});
  }

  Group.findOne( { _id : groupId }, function(err, group) {
    if (err || !group) return next(404);

    console.log('Found Group: ' + JSON.stringify(group, null, 4));
    async.each(invites, function(username, cb) {
      User.findOne( { 'username': username.toLowerCase() }, function (err, usr) {

	if (!usr) {
	  return cb();
	}

	///
	/// Don't add to the group if the user has left the group
	///
	var index = usr.leftGroups.indexOfEquals(group._id);
	var index2 = usr.groups.indexOfEquals(group._id);

	if (index !== -1 || index2 !== -1) {
	  return cb('A user who left cannot be readded!');
	}

	///
	/// Each member in the group gets a GroupSetting object
	///
	var setting = new GroupSetting({
	  'user': usr._id,
	  'group': group._id
	});

	setting.save(function(err) {
	  console.log('Error: '+ err);
	});
	usr.groupSettings.push(setting._id);

	///
	/// Don't invite, just add straight to group
	///
	group.members.push(usr._id);

	group.save(function (err) {
	  if (err) return cb(err);

	  usr.groups.push(group._id);
	  usr.save( function (err) {
	    if (err) return cb(err);

	    var aMessage = new Message({'from' : null,
					'group': group._id,
					'text' : usr.username + ' has joined the group.',
					'sent' : new Date(),
					'type' : 'system'
				       });
	    aMessage.save();
	    io.messageToGroup(group._id, 'member_joined', aMessage);
	    var didSend = io.emitNewGroup(usr._id, group);
	    if (!didSend) {
	      usr.push(null, 'You have been added to the group: ' + group.name, null, false);
	    }
	    cb();
	  });
	});
      });
    }, function(err) {
      if (err) return next(err);

      res.send(200, {});
    });
  });
};
<commit_msg>Fixing a small bug in which the JSON returned when creating a new group was unexpected.<commit_after>var User = require('../model/user');
var Group = require('../model/group');
var Message = require('../model/message');
var async = require('async');
var ObjectId = require('mongoose').Types.ObjectId;
var io = require('../socket/socket');
var GroupSetting = require('../model/groupSetting');

exports.getGroups = function(req, res, next) {
  var usr = req.user;

  GroupSetting.find({'user': usr._id}, function(err, gses) {

    Group.find( { 'members' : usr._id }, '_id members leftMembers name lastMessage')
      .populate('members', 'username')
      .populate('leftMembers', 'username')
      .populate('lastMessage')
      .exec(function(err, groups) {
	if (err) return next(500);

	///
	/// Sort groups so the most recent messages move up to the top
	///
	groups.sort(function(a, b) {
	  var first;
	  if (a.lastMessage) {
	    first = a.lastMessage.sent;
	  } else {
	    return 1;
	  }
	  var second;
	  if (b.lastMessage) {
	    second = b.lastMessage.sent;
	  } else {
	    return -1;
	  }

          return ((first < second) ? 1 : ((first > second) ? -1 : 0));
	});

	///
	/// For each group - find the group setting object associated with it
	/// and if it exists, add the unread count to this group
	///
	groups.forEach(function(g) {
	  var index = gses.indexOfEquals(g._id, 'group');
	  if (index > -1) {
	    g.unread = gses[index].unread;
	  } else {
	    g.unread = 0;
	  }
	});

	res.json(groups);
      });
  });
};

exports.createGroup = function(req, res, next) {
  var usr = req.user;

  console.log('BODY: ' + JSON.stringify(req.body, null, 4));

  var members = req.body.members;
  if (!members || !(members instanceof Array) || members.length == 0) {
    return next('The "members" value must be a valid array of length 1!');
  }

  var message = req.body.text;
  if (!message) {
    return next('You must send a message with the new group!');
  }

  var cb = function(err, group) {
    if (err) return next(err);

    Group.findOne( { '_id' : group._id }, '_id members leftMembers name lastMessage')
      .populate('members', 'username')
      .populate('leftMembers', 'username')
      .populate('lastMessage')
      .exec(function(err, madeGroup) {
	res.send(201, madeGroup);
      });
  };

  var name = req.body.name;

  for (var i = 0; i < members.length; i++) {
    members[i] = members[i].toLowerCase();
  }

  User.find({'username': { $in: members } }, function(err, users) {
    if (err || users.length == 0) {
      return next('No users were found with those usernames!');
    }

    console.log('Found Users: ' + JSON.stringify(users, null, 4));

    var otherMembers = [];
    users.forEach(function(user) {
      if (!user._id.equals(usr._id)) {
	otherMembers.push(user);
      }
    });

    if (otherMembers.length === 0) {
      return next('You can\'t make a group with only yourself!');
    }

    newGroup(name, otherMembers, message, usr, cb);
  });

};

function newGroup(groupName, members, message, creator, cb) {

  members.push(creator);

  Group.newGroup({'name': groupName, 'members': members}, function(err, group) {
    if (err) return cb(err);

    var aMessage = new Message({'from' : creator._id,
				'group': group._id,
				'text' : message,
				'sent' : new Date()
			       });

    aMessage.save(function(err) {
      group.messages.push(aMessage._id);
      group.lastMessage = aMessage;
      group.save();

      ///
      /// Emit a new message to socket users
      ///
      var usersNotOn = [];
      members.forEach(function(user) {
	if ( !user._id.equals(creator._id) ) { //Don't emit to creator
	  var didSend = io.emitNewGroup(user._id, group);
	  if (!didSend) {
	    usersNotOn.push(user);
	  }
	}
      });

      var text = creator.username + '@' + group.name + ': ' + message;
      usersNotOn.forEach(function(user) {
	user.push(group, text, null, false);
      });

      cb(null, group);
    });

  });
};

// PUT /group/:id/leave
exports.leaveGroup = function(req, res, next) {

  var idParam = req.params.id.toString();
  var groupId = new ObjectId(idParam);
  var user = req.user;

  // To leave a group, we must:
  // put them in the leftMembers array in the group
  // remove them from the members array in the group
  // add the group to leftGroups in the profile
  // remove the group from groups in the profile

  Group.findOne( { _id : groupId }, function(err, group) {
    if (!group) {
      return next(404);
    }

    var index = group.members.indexOfEquals(user._id);
    if (index === -1) {
      return next(404);
    }

    async.parallel([
      function(callback) {
	// update group
	group.members.splice(index, 1);
	group.leftMembers.push(user._id);
	group.save(function(err) {
	  callback(err);
	});
      },
      function(callback){
	// Update profile
	var groupIndex = user.groups.indexOfEquals(groupId);
	console.log('Index2: ' + groupIndex);
	if (groupIndex > -1) {
	  user.groups.splice(groupIndex, 1);
	  user.leftGroups.push(groupId);
	  user.save(function(err) {
	    callback(err);
	  });
	} else {
	  callback();
	}
      },
      function(callback) {
	// send a message to the group notifying them that the person left
	var aMessage = new Message({'from' : null,
				    'group': group._id,
				    'text' : user.username + ' has left the group.',
				    'sent' : new Date(),
				    'type' : 'system'
				   });
	aMessage.save();
	io.messageToGroup(group._id, 'member_left', aMessage);
	callback();
      }
    ],
    // optional callback
    function(err, results) {
      if (err) return next(err);

      res.json(200, {});
    });
  });
};

exports.changeSettings = function(req, res, next) {
  console.log('HERE');
  var name = req.body.name;
  var idParam = req.params.id.toString();
  var groupId = new ObjectId(idParam);
  var user = req.user;

  if (!user.hasGroup(groupId)) {
    return next(404);
  }

  Group.findOne( { _id : groupId }, function(err, group) {
    if (err || !group) return next(404);

    group.name = name;
    group.save(function(err) {

      var aMessage = new Message({'from' : null,
				  'group': group._id,
				  'text' : 'Group is now called ' + name,
				  'sent' : new Date(),
				  'type' : 'system'
				 });
      aMessage.save();
      io.messageToGroup(group._id, 'group_name', aMessage);

      res.send(200, {});
    });
  });
};

exports.add = function(req, res, next) {
  console.log('Invite Body: ' + JSON.stringify(req.body, null, 4));

  var idParam = req.params.id.toString();
  var invites = req.body.invitees;
  var groupId = new ObjectId(idParam);

  if ( !(invites instanceof Array) ) {
    return next('invitees must be an Array!');
  }

  if (invites.length == 0 ) {
    return res.json(200, {});
  }

  Group.findOne( { _id : groupId }, function(err, group) {
    if (err || !group) return next(404);

    console.log('Found Group: ' + JSON.stringify(group, null, 4));
    async.each(invites, function(username, cb) {
      User.findOne( { 'username': username.toLowerCase() }, function (err, usr) {

	if (!usr) {
	  return cb();
	}

	///
	/// Don't add to the group if the user has left the group
	///
	var index = usr.leftGroups.indexOfEquals(group._id);
	var index2 = usr.groups.indexOfEquals(group._id);

	if (index !== -1 || index2 !== -1) {
	  return cb('A user who left cannot be readded!');
	}

	///
	/// Each member in the group gets a GroupSetting object
	///
	var setting = new GroupSetting({
	  'user': usr._id,
	  'group': group._id
	});

	setting.save(function(err) {
	  console.log('Error: '+ err);
	});
	usr.groupSettings.push(setting._id);

	///
	/// Don't invite, just add straight to group
	///
	group.members.push(usr._id);

	group.save(function (err) {
	  if (err) return cb(err);

	  usr.groups.push(group._id);
	  usr.save( function (err) {
	    if (err) return cb(err);

	    var aMessage = new Message({'from' : null,
					'group': group._id,
					'text' : usr.username + ' has joined the group.',
					'sent' : new Date(),
					'type' : 'system'
				       });
	    aMessage.save();
	    io.messageToGroup(group._id, 'member_joined', aMessage);
	    var didSend = io.emitNewGroup(usr._id, group);
	    if (!didSend) {
	      usr.push(null, 'You have been added to the group: ' + group.name, null, false);
	    }
	    cb();
	  });
	});
      });
    }, function(err) {
      if (err) return next(err);

      res.send(200, {});
    });
  });
};
<|endoftext|>


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

/* GET home page. */
router.get('/', homeController.index)
router.get('/tweets', homeController.getTweets);

module.exports = router;
<commit_msg>Added robots.txt<commit_after>var express = require('express');
var router = express.Router();
var homeController = require('../controllers/homeController');

/* GET home page. */
router.get('/', homeController.index)
router.get('/tweets', homeController.getTweets);
router.get('/robots.txt', function(req, res, next) {
	res.type('text/plain');
	res.send("User-agent: *\nAllow: /");
});

module.exports = router;
<|endoftext|>


<commit_before>module.exports = function(crowi, app) {
  const controllers = crowi.controllers
  const middlewares = crowi.middlewares
  const form = require('../form')

  const routes = {
    Admin: require('./admin')(crowi, app, form),
    API: require('./API')(crowi, app, form),
    Login: require('./login')(crowi, app, form),
    Me: require('./me')(crowi, app, form),
  }

  var multer = require('multer')
  var uploads = multer({ dest: crowi.tmpDir + 'uploads' })
  var page = controllers.Page
  var login = controllers.Login
  var logout = controllers.Logout
  var me = controllers.Me
  var installer = controllers.Installer
  var user = controllers.User
  var attachment = controllers.Attachment
  var comment = controllers.Comment
  var search = controllers.Search
  var share = controllers.Share
  var shareAccess = controllers.ShareAccess
  var notification = controllers.Notification
  var backlink = controllers.Backlink
  var slack = controllers.Slack
  var loginRequired = middlewares.LoginRequired
  var fileAccessRightOrLoginRequired = middlewares.FileAccessRightOrLoginRequired
  var encodeSpace = middlewares.EncodeSpace
  var accessTokenParser = middlewares.AccessTokenParser
  var csrf = middlewares.CsrfVerify
  var applicationNotInstalled = middlewares.ApplicationNotInstalled
  var applicationInstalled = middlewares.ApplicationInstalled

  app.use(routes.Admin)
  app.use(routes.Login)
  app.use(routes.Me)
  app.use('/_api', routes.API)

  app.get('/', loginRequired, page.pageListShow)

  app.get('/installer', applicationNotInstalled, installer.index)
  app.post('/installer/createAdmin', applicationNotInstalled, form.register, csrf, installer.createAdmin)
  // app.post('/installer/user'         , applicationNotInstalled , installer.createFirstUser);

  app.post('/register', form.register, csrf, login.register)
  app.get('/register', applicationInstalled, login.register)
  app.get('/google/callback', login.googleCallback)
  app.get('/github/callback', login.githubCallback)
  app.get('/logout', logout.logout)

  app.get('/:id([0-9a-z]{24})', loginRequired, page.api.redirector)
  app.get('/_r/:id([0-9a-z]{24})', loginRequired, page.api.redirector) // alias
  app.get('/files/:id([0-9a-z]{24})', fileAccessRightOrLoginRequired, attachment.api.redirector)

  app.get('/_notifications', accessTokenParser, loginRequired, notification.notificationPage)

  app.get('/_search', loginRequired, search.searchPage)
  app.get('/_api/search', accessTokenParser, loginRequired, search.api.search)

  app.get('/_share/:uuid([0-9a-z-]{36})', share.pageShow)

  app.get('/_api/check_username', user.api.checkUsername)
  app.post('/_api/me/picture/upload', loginRequired, uploads.single('userPicture'), me.api.uploadPicture)
  app.get('/_api/user/bookmarks', loginRequired, user.api.bookmarks)
  app.get('/_api/user/recentlyViewed', loginRequired, user.api.getRecentlyViewedPages)

  app.get('/user/:username([^/]+)/bookmarks', loginRequired, page.userBookmarkList)
  app.get('/user/:username([^/]+)/recent-create', loginRequired, page.userRecentCreatedList)

  // HTTP RPC Styled API (に徐々に移行していいこうと思う)
  app.get('/_api/users.list', accessTokenParser, loginRequired, user.api.list)
  app.get('/_api/comments.get', accessTokenParser, loginRequired, comment.api.get)
  app.post('/_api/comments.add', form.comment, accessTokenParser, loginRequired, csrf, comment.api.add)
  app.post('/_api/likes.add', accessTokenParser, loginRequired, csrf, page.api.like)
  app.post('/_api/likes.remove', accessTokenParser, loginRequired, csrf, page.api.unlike)

  app.get('/_api/backlink.list', accessTokenParser, loginRequired, backlink.api.list)

  // app.get('/_api/revision/:id'     , user.useUserData()         , revision.api.get);
  // app.get('/_api/r/:revisionId'    , user.useUserData()         , page.api.get);

  app.get('/_api/shares/accesses.list', accessTokenParser, loginRequired, shareAccess.api.list)

  app.post('/_api/slack/event', slack.api.handleEvent)

  app.post('/_/edit', form.revision, loginRequired, csrf, page.pageEdit)
  app.get('/trash/$', loginRequired, page.deletedPageListShow)
  app.get('/trash/*/$', loginRequired, page.deletedPageListShow)
  app.get('/*/$', loginRequired, encodeSpace, page.pageListShow)
  app.get('/user/:username([^/]+)', loginRequired, page.userPageShow)
  app.get('/*', loginRequired, encodeSpace, page.pageShow)
}
<commit_msg>Use const and destructuring assignment<commit_after>module.exports = function(crowi, app) {
  const controllers = crowi.controllers
  const middlewares = crowi.middlewares
  const form = require('../form')

  const routes = {
    Admin: require('./admin')(crowi, app, form),
    API: require('./API')(crowi, app, form),
    Login: require('./login')(crowi, app, form),
    Me: require('./me')(crowi, app, form),
  }

  var multer = require('multer')
  var uploads = multer({ dest: crowi.tmpDir + 'uploads' })

  const {
    Page: page,
    Login: login,
    Logout: logout,
    Me: me,
    Installer: installer,
    User: user,
    Attachment: attachment,
    Comment: comment,
    Search: search,
    Share: share,
    ShareAccess: shareAccess,
    Notification: notification,
    Backlink: backlink,
    Slack: slack,
  } = controllers

  const {
    LoginRequired: loginRequired,
    FileAccessRightOrLoginRequired: fileAccessRightOrLoginRequired,
    EncodeSpace: encodeSpace,
    AccessTokenParser: accessTokenParser,
    CsrfVerify: csrf,
    ApplicationNotInstalled: applicationNotInstalled,
    ApplicationInstalled: applicationInstalled,
  } = middlewares

  app.use(routes.Admin)
  app.use(routes.Login)
  app.use(routes.Me)
  app.use('/_api', routes.API)

  app.get('/', loginRequired, page.pageListShow)

  app.get('/installer', applicationNotInstalled, installer.index)
  app.post('/installer/createAdmin', applicationNotInstalled, form.register, csrf, installer.createAdmin)
  // app.post('/installer/user'         , applicationNotInstalled , installer.createFirstUser);

  app.post('/register', form.register, csrf, login.register)
  app.get('/register', applicationInstalled, login.register)
  app.get('/google/callback', login.googleCallback)
  app.get('/github/callback', login.githubCallback)
  app.get('/logout', logout.logout)

  app.get('/:id([0-9a-z]{24})', loginRequired, page.api.redirector)
  app.get('/_r/:id([0-9a-z]{24})', loginRequired, page.api.redirector) // alias
  app.get('/files/:id([0-9a-z]{24})', fileAccessRightOrLoginRequired, attachment.api.redirector)

  app.get('/_notifications', accessTokenParser, loginRequired, notification.notificationPage)

  app.get('/_search', loginRequired, search.searchPage)
  app.get('/_api/search', accessTokenParser, loginRequired, search.api.search)

  app.get('/_share/:uuid([0-9a-z-]{36})', share.pageShow)

  app.get('/_api/check_username', user.api.checkUsername)
  app.post('/_api/me/picture/upload', loginRequired, uploads.single('userPicture'), me.api.uploadPicture)
  app.get('/_api/user/bookmarks', loginRequired, user.api.bookmarks)
  app.get('/_api/user/recentlyViewed', loginRequired, user.api.getRecentlyViewedPages)

  app.get('/user/:username([^/]+)/bookmarks', loginRequired, page.userBookmarkList)
  app.get('/user/:username([^/]+)/recent-create', loginRequired, page.userRecentCreatedList)

  // HTTP RPC Styled API (に徐々に移行していいこうと思う)
  app.get('/_api/users.list', accessTokenParser, loginRequired, user.api.list)
  app.get('/_api/comments.get', accessTokenParser, loginRequired, comment.api.get)
  app.post('/_api/comments.add', form.comment, accessTokenParser, loginRequired, csrf, comment.api.add)
  app.post('/_api/likes.add', accessTokenParser, loginRequired, csrf, page.api.like)
  app.post('/_api/likes.remove', accessTokenParser, loginRequired, csrf, page.api.unlike)

  app.get('/_api/backlink.list', accessTokenParser, loginRequired, backlink.api.list)

  // app.get('/_api/revision/:id'     , user.useUserData()         , revision.api.get);
  // app.get('/_api/r/:revisionId'    , user.useUserData()         , page.api.get);

  app.get('/_api/shares/accesses.list', accessTokenParser, loginRequired, shareAccess.api.list)

  app.post('/_api/slack/event', slack.api.handleEvent)

  app.post('/_/edit', form.revision, loginRequired, csrf, page.pageEdit)
  app.get('/trash/$', loginRequired, page.deletedPageListShow)
  app.get('/trash/*/$', loginRequired, page.deletedPageListShow)
  app.get('/*/$', loginRequired, encodeSpace, page.pageListShow)
  app.get('/user/:username([^/]+)', loginRequired, page.userPageShow)
  app.get('/*', loginRequired, encodeSpace, page.pageShow)
}
<|endoftext|>


<commit_before>'use strict';

var User = require('../models/User'),
    Pomodoro = require('../models/Pomodoro'),
    utils = require('../utils'),
    Q = require('q');

module.exports = {
  '/user': {
    '/prefs': {
      get: [ ensureUserSession, getUserPrefs ],
      post: [ ensureUserSession, saveUserPrefs ]
    },
    '/pomodoro':  {
      get: [ ensureUserSession, getAllPomodoroHistory ],
      post: [ ensureUserSession, savePomodoro ],
      '/sync': {
        post: [ ensureUserSession, syncPomodori ]
      },
      '/month': {
        '/:interval': {
          get: [ ensureUserSession, getPomodoroHistoryForMonth ]
        }
      },
      '/between': {
        '/:date1/:date2': {
          get: [ ensureUserSession, getPomodoroHistoryForRange ]
        }
      }
    }
  }
};

function ensureUserSession () {
  // `next()` is usually the first param, unless the route
  // is capturing params, where ea. captured param appears
  // as the prior arguments...
  var args = Array.prototype.slice.call(arguments),
      next = args.pop();

  if (this.req.isAuthenticated()) return next();

  utils.writeJSON(this.res, "User isn't signed in", 403);
  return false;
}

function saveUserPrefs () {
  var res = this.res,
      user = this.req.user;

  user.set('preferences', this.req.body.prefs);
  user.save().then(function () {
    utils.writeJSON(res);
  }, function (err) {
    utils.writeJSON(res, err, 400);
  });
}

function getUserPrefs () {
  var res = this.res;

  User.findById(this.req.user.id).then(function (result) {
    utils.writeJSON(res, result.preferences);
  }, function (err) {
    utils.writeJSON(res, err, 400);
  });
}

function getAllPomodoroHistory () {
  var res = this.res;

  Pomodoro.getAllForUser(this.req.user).then(function (result) {
    utils.writeJSON(res, result);
  }, function (err) {
    utils.writeJSON(res, err, 400);
  });
}

function getPomodoroHistory (req, res, interval) {
  Pomodoro.getInDateRangeForUser(interval, req.user).then(function (result) {
    utils.writeJSON(res, result);
  }, function (err) {
    utils.writeJSON(res, err, 400);
  });
}

/**
 * @param  {string} yearAndMonth YYYY-MM OR YYYY-M
 */
function getPomodoroHistoryForMonth (yearAndMonth) {
  getPomodoroHistory(this.req, this.res, { start: yearAndMonth });
}

/**
 * date1 must be less than date2.
 * @param  {string} date1 YYYY-MM OR YYYY-M (inclusive)
 * @param  {string} date2 YYYY-MM OR YYYY-M (exclusive)
 */
function getPomodoroHistoryForRange (date1, date2) {
  getPomodoroHistory(this.req, this.res, {
    start: date1,
    end:   date2
  });
}

function savePomodoro () {
  var req = this.req,
      res = this.res,
      session = new Pomodoro({
        notes:    req.body.notes || null,
        duration: req.body.duration,
        date:     req.body.date,
        time:     req.body.time
      });

  session.save(this.req.user).then(function (saved) {
    utils.writeJSON(res, saved);
  }, function (err) {
    utils.writeJSON(res, err, 400);
  });
}

function syncPomodori () {
  var req = this.req,
      res = this.res,
      promises = [];

  req.body.pomodori.forEach(function (pomInfo) {
    var pomodoro = new Pomodoro({
      notes:    pomInfo.notes || null,
      duration: pomInfo.duration,
      date:     pomInfo.date,
      time:     pomInfo.time
    });

    promises.push(Pomodoro.findOneForUser(pomodoro, req.user).then(function (found) {
      if (!found) {
        return pomodoro.save(req.user);
      }
    }));
  });

  Q.all(promises).then(function (results) {
    utils.writeJSON(res, results);
  }, function (err) {
    utils.writeJSON(res, err, 400);
  });
}
<commit_msg>Don't send back unnecessary user info on each pomodoro session<commit_after>'use strict';

var User = require('../models/User'),
    Pomodoro = require('../models/Pomodoro'),
    utils = require('../utils'),
    Q = require('q');

module.exports = {
  '/user': {
    '/prefs': {
      get: [ ensureUserSession, getUserPrefs ],
      post: [ ensureUserSession, saveUserPrefs ]
    },
    '/pomodoro':  {
      get: [ ensureUserSession, getAllPomodoroHistory ],
      post: [ ensureUserSession, savePomodoro ],
      '/sync': {
        post: [ ensureUserSession, syncPomodori ]
      },
      '/month': {
        '/:interval': {
          get: [ ensureUserSession, getPomodoroHistoryForMonth ]
        }
      },
      '/between': {
        '/:date1/:date2': {
          get: [ ensureUserSession, getPomodoroHistoryForRange ]
        }
      }
    }
  }
};

function ensureUserSession () {
  // `next()` is usually the first param, unless the route
  // is capturing params, where ea. captured param appears
  // as the prior arguments...
  var args = Array.prototype.slice.call(arguments),
      next = args.pop();

  if (this.req.isAuthenticated()) return next();

  utils.writeJSON(this.res, "User isn't signed in", 403);
  return false;
}

function parePomodori (results) {
  if (!results) return results;

  return results.map(function (pomodoro) {
    return {
      id:       pomodoro.id,
      date:     pomodoro.date,
      duration: pomodoro.duration,
      notes:    pomodoro.notes,
      time:     pomodoro.time
    };
  });
}

function getPomodoroHistory (req, res, interval) {
  Pomodoro.getInDateRangeForUser(interval, req.user).then(function (result) {
    utils.writeJSON(res, parePomodori(result));
  }, function (err) {
    utils.writeJSON(res, err, 400);
  });
}

// POST /user/prefs
function saveUserPrefs () {
  var res = this.res,
      user = this.req.user;

  user.set('preferences', this.req.body.prefs);
  user.save().then(function () {
    utils.writeJSON(res);
  }, function (err) {
    utils.writeJSON(res, err, 400);
  });
}

// GET /user/prefs
function getUserPrefs () {
  var res = this.res;

  User.findById(this.req.user.id).then(function (result) {
    utils.writeJSON(res, result.preferences);
  }, function (err) {
    utils.writeJSON(res, err, 400);
  });
}

// GET /user/pomodoro
function getAllPomodoroHistory () {
  var res = this.res;

  Pomodoro.getAllForUser(this.req.user).then(function (result) {
    utils.writeJSON(res, parePomodori(result));
  }, function (err) {
    utils.writeJSON(res, err, 400);
  });
}

/**
 * GET /user/pomodoro/month/:interval
 * @param  {string} yearAndMonth YYYY-MM OR YYYY-M
 */
function getPomodoroHistoryForMonth (yearAndMonth) {
  getPomodoroHistory(this.req, this.res, { start: yearAndMonth });
}

/**
 * GET /user/pomodoro/between/:date1/:date2
 * date1 must be less than date2.
 * @param  {string} date1 YYYY-MM OR YYYY-M (inclusive)
 * @param  {string} date2 YYYY-MM OR YYYY-M (exclusive)
 */
function getPomodoroHistoryForRange (date1, date2) {
  getPomodoroHistory(this.req, this.res, {
    start: date1,
    end:   date2
  });
}

// POST /user/pomodoro
function savePomodoro () {
  var req = this.req,
      res = this.res,
      session = new Pomodoro({
        notes:    req.body.notes || null,
        duration: req.body.duration,
        date:     req.body.date,
        time:     req.body.time
      });

  session.save(this.req.user).then(function (saved) {
    utils.writeJSON(res, saved);
  }, function (err) {
    utils.writeJSON(res, err, 400);
  });
}

// POST /user/pomodoro/sync
function syncPomodori () {
  var req = this.req,
      res = this.res,
      promises = [];

  req.body.pomodori.forEach(function (pomInfo) {
    var pomodoro = new Pomodoro({
      notes:    pomInfo.notes || null,
      duration: pomInfo.duration,
      date:     pomInfo.date,
      time:     pomInfo.time
    });

    promises.push(Pomodoro.findOneForUser(pomodoro, req.user).then(function (found) {
      if (!found) {
        return pomodoro.save(req.user);
      }
    }));
  });

  Q.all(promises).then(function (results) {
    utils.writeJSON(res, parePomodori(results));
  }, function (err) {
    utils.writeJSON(res, err, 400);
  });
}
<|endoftext|>


<commit_before>const _ = require('lodash');
const inflection = require('inflection');
const traverse = require('traverse');

/*!
 * @param ctx
 * @returns {string}
 */
function getPathFromContext(ctx) {
  let path = ctx.path.join('.');

  // check if we specifically set type
  const lastElement = ctx.path[ctx.path.length - 1];
  if (lastElement) {
    const lev = lastElement.toLowerCase();
    if (lev === 'type') {
      path = ctx.path.slice(0, ctx.path.length - 1).join('.');
    }
  }

  // check if in array
  const reg = new RegExp('^\\d+$');
  const lastPath = path.substring(path.lastIndexOf('.') + 1);
  if (lastPath && reg.test(lastPath)) {
    path = path.substring(0, path.lastIndexOf('.'));
  }

  return path;
}

let Model;

/*!
 *
 * @param descriptor
 * @returns {Array}
 */
exports.getRefs = function (descriptor) {
  if (!Model) {
    Model = require('./model').Model;
  }

  let refs = [];
  traverse(descriptor).forEach(function (obj) {
    const ctx = this;
    if (obj && (obj.modelName && Model.isPrototypeOf(obj.type || obj)) ||
      (obj.type === Model && obj.modelName)) {
      const path = getPathFromContext(ctx);

      refs.push({
        path,
        ref: obj.modelName
      });
    }
  });

  refs = _.compact(refs);

  return refs;
};

/*!
 *
 * @param descriptor
 * @returns {Array}
 */
exports.getIndexes = function (descriptor) {
  if (!Model) {
    Model = require('./model').Model;
  }

  let inds = [];

  traverse(descriptor).forEach(function (obj) {
    const ctx = this;
    if (obj && obj.index === true && (obj.type || obj.Type)) {
      const t = obj.type || obj.Type;
      if ((t === String || t === Number) ||
        (t.modelName && Model.isPrototypeOf(t)) ||
        (t === Model && t.modelName)) {
        const path = getPathFromContext(ctx);

        let name = obj.indexName;
        if (!name) {
          name = ctx.key;
          const reg = new RegExp('^\\d+$');
          if (reg.test(name)) {
            name = ctx.path[ctx.path.length - 2];
          }
          name = inflection.singularize(name);
        }

        let indexType = obj.indexType ? obj.indexType.toLowerCase() : 'single';
        if (indexType !== 'single' && indexType !== 'array') {
          indexType = 'single';
        }

        inds.push({ path, name, indexType });
      }
    }
  });

  inds = _.compact(inds);
  return inds;
};
<commit_msg>fix checking for index type when using deferred model<commit_after>const _ = require('lodash');
const inflection = require('inflection');
const traverse = require('traverse');

/*!
 * @param ctx
 * @returns {string}
 */
function getPathFromContext(ctx) {
  let path = ctx.path.join('.');

  // check if we specifically set type
  const lastElement = ctx.path[ctx.path.length - 1];
  if (lastElement) {
    const lev = lastElement.toLowerCase();
    if (lev === 'type') {
      path = ctx.path.slice(0, ctx.path.length - 1).join('.');
    }
  }

  // check if in array
  const reg = new RegExp('^\\d+$');
  const lastPath = path.substring(path.lastIndexOf('.') + 1);
  if (lastPath && reg.test(lastPath)) {
    path = path.substring(0, path.lastIndexOf('.'));
  }

  return path;
}

let Model;

/*!
 *
 * @param descriptor
 * @returns {Array}
 */
exports.getRefs = function (descriptor) {
  if (!Model) {
    Model = require('./model').Model;
  }

  let refs = [];
  traverse(descriptor).forEach(function (obj) {
    const ctx = this;
    if (obj && (obj.modelName && Model.isPrototypeOf(obj.type || obj)) ||
      (obj.type === Model && obj.modelName)) {
      const path = getPathFromContext(ctx);

      refs.push({
        path,
        ref: obj.modelName
      });
    }
  });

  refs = _.compact(refs);

  return refs;
};

/*!
 *
 * @param descriptor
 * @returns {Array}
 */
exports.getIndexes = function (descriptor) {
  if (!Model) {
    Model = require('./model').Model;
  }

  let inds = [];

  traverse(descriptor).forEach(function (obj) {
    const ctx = this;
    if (obj && obj.index === true && (obj.type || obj.Type)) {
      const t = obj.type || obj.Type;
      if ((t === String || t === Number) ||
        (Model.isPrototypeOf(t) && t.modelName) ||
        (obj.modelName && Model.isPrototypeOf(t)) ||
        (obj.modelName && t === Model)) {
        const path = getPathFromContext(ctx);

        let name = obj.indexName;
        if (!name) {
          name = ctx.key;
          const reg = new RegExp('^\\d+$');
          if (reg.test(name)) {
            name = ctx.path[ctx.path.length - 2];
          }
          name = inflection.singularize(name);
        }

        let indexType = obj.indexType ? obj.indexType.toLowerCase() : 'single';
        if (indexType !== 'single' && indexType !== 'array') {
          indexType = 'single';
        }

        inds.push({ path, name, indexType });
      }
    }
  });

  inds = _.compact(inds);
  return inds;
};
<|endoftext|>


<commit_before>const Boom = require( 'boom' ),
    Log = require( '../methods/log.js' ),
    Roles = require( '../../models.js' )
    .Roles;

module.exports = function checkRole( request, reply ) {

    let auth = request.route.settings.plugins.poetryAuth;

    process.nextTick( () => {

        // No auth check needed
        if ( !auth )
            return reply.continue();

        // Not logged on
        if ( !request.session.isAuthenticated || !request.session.user )
            return reply( Boom.unauthorized() );

        // SUPER case
        if ( request.session.user.role == 'SUPER' )
            return reply.continue();

        // ADMIN case
        if ( request.session.user.role == '*' )
            return roles( {
                name: "ADMIN",
                permissions: request.session.team.permissions
            } );

        // USER case
        let id;
        try {
            id = ObjectID( request.session.user.role );
        } catch ( err ) {
            Log.error( 'Wrong role for ', request.session.user );
            return reply( Boom.unauthorized() );
        }
        Roles.findOne( {
                _id: id,
                team: request.session.team._id
            } )
            .then( roles );

    } );

    function roles( role ) {

        if ( !role ) {
            Log.warn( 'Unknown role !', request.route.method, request.route.path );
            return reply( Boom.forbidden() );
        }

        // Special handwritten auths
        if ( Array.isArray( auth ) ) {
            let res = auth.some( tag => check(
                `API.${tag}.${ request.route.settings.description }`,
                role
            ) );

            if ( res === true )
                return reply.continue();
            if ( res === false )
                return reply( Boom.forbidden() );
        }

        if ( request.route.settings.tags ) {

            // For descripted routes
            if ( request.route.settings.description ) {

                let res = request.route.settings.tags.some( tag => check(
                    `API.${tag}.${ request.route.settings.description }`,
                    role
                ) );

                if ( res === true )
                    return reply.continue();
                if ( res === false )
                    return reply( Boom.forbidden( 'Desc' ) );
            }

            // For tagged routes
            let res = request.route.settings.tags.some( tag => check(
                `API.${tag}`,
                role.permissions
            ) );

            if ( res === true )
                return reply.continue();
            if ( res === false )
                return reply( Boom.forbidden( 'GlobalTag' ) );

        }

        // FORBIDDEN
        Log.silly( 'No permission found', request.route.method, request.route.path );
        return reply( Boom.forbidden( 'Fallback' ) );

    }

};

// Get nested value with dot notation
function check( path, object ) {
    Log.silly( 'Checking role', path, object );

    path = path.split( '.' );

    if ( object === true || object === false )
        return object;

    if ( !object ) return undefined;
    if ( !object[ path[ 0 ] ] ) return undefined;

    // It's the targeted value
    if ( path.length == 1 )
        return object[ path[ 0 ] ];

    // Deep inspect sub object
    return check( path.slice( 1 )
        .join( '.' ), object[ path[ 0 ] ] );

}
<commit_msg>console log<commit_after>const Boom = require( 'boom' ),
    Log = require( '../methods/log.js' ),
    Roles = require( '../../models.js' )
    .Roles;

module.exports = function checkRole( request, reply ) {

    let auth = request.route.settings.plugins.poetryAuth;

    process.nextTick( () => {

        // No auth check needed
        if ( !auth )
            return reply.continue();

        // Not logged on
        if ( !request.session.isAuthenticated || !request.session.user )
            return reply( Boom.unauthorized() );

        // SUPER case
        if ( request.session.user.role == 'SUPER' )
            return reply.continue();

        // ADMIN case
        if ( request.session.user.role == '*' )
            return roles( {
                name: "ADMIN",
                permissions: request.session.team.permissions
            } );

        // USER case
        let id;
        try {
            id = ObjectID( request.session.user.role );
        } catch ( err ) {
            Log.error( 'Wrong role for ', request.session.user );
            return reply( Boom.unauthorized() );
        }
        Roles.findOne( {
                _id: id,
                team: request.session.team._id
            } )
            .then( roles );

    } );

    function roles( role ) {

        if ( !role ) {
            Log.warn( 'Unknown role !', request.route.method, request.route.path );
            return reply( Boom.forbidden() );
        }

        // Special handwritten auths
        if ( Array.isArray( auth ) ) {
            let res = auth.some( tag => check(
                `API.${tag}.${ request.route.settings.description }`,
                role
            ) );

            if ( res === true )
                return reply.continue();
            if ( res === false )
                return reply( Boom.forbidden() );
        }

        if ( request.route.settings.tags ) {

            // For descripted routes
            if ( request.route.settings.description ) {

                let res = request.route.settings.tags.some( tag => check(
                    `API.${tag}.${ request.route.settings.description }`,
                    role
                ) );

                if ( res === true )
                    return reply.continue();
                if ( res === false )
                    return reply( Boom.forbidden( 'Desc' ) );
            }

            // For tagged routes
            let res = request.route.settings.tags.some( tag => check(
                `API.${tag}`,
                role.permissions
            ) );

            if ( res === true )
                return reply.continue();
            if ( res === false )
                return reply( Boom.forbidden( 'GlobalTag' ) );

        }

        // FORBIDDEN
        Log.silly( 'No permission found', request.route.method, request.route.path );
        return reply( Boom.forbidden( 'Fallback' ) );

    }

};

// Get nested value with dot notation
function check( path, object ) {
    Log.silly( 'Checking role', path, object );

    path = path.split( '.' );

    if ( object === true || object === false ) {
        console.log( 'OBJECT' );
        return object;
    }

    if ( !object ) {
        console.log( '1' );
        return undefined;
    }
    if ( !object[ path[ 0 ] ] ) {
        console.log( '2' );
        return undefined;
    }

    // It's the targeted value
    if ( path.length == 1 ) {
        console.log( 'targeted' );
        return object[ path[ 0 ] ];
    }
    console.log( 'SUB' );
    // Deep inspect sub object
    return check( path.slice( 1 )
        .join( '.' ), object[ path[ 0 ] ] );

}
<|endoftext|>


<commit_before>/* global log */

'use strict'

var clone = require('lodash/clone')
var defaults = require('lodash/defaults')
var SparqlHttpClient = require('sparql-http-client')

SparqlHttpClient.fetch = require('node-fetch')

function authBasicHeader (user, password) {
  return 'Basic ' + new Buffer(user + ':' + password).toString('base64')
}

function sparqlProxy (options) {
  var queryOptions = {}

  if (options.authentication) {
    queryOptions.headers = {
      Authorization: authBasicHeader(options.authentication.user, options.authentication.password)
    }
  }

  var queryOperation = options.queryOperation || 'postQueryDirect'
  var client = new SparqlHttpClient({endpointUrl: options.endpointUrl})

  return function (req, res, next) {
    var query

    if (req.method === 'GET') {
      query = req.query.query
    } else if (req.method === 'POST') {
      query = req.body.query || req.body
    } else {
      return next()
    }

    log.info({script: __filename}, 'handle SPARQL request for endpoint: ' + options.endpointUrl)
    log.debug({script: __filename}, 'SPARQL query:' + query)

    // merge configuration query options with request query options
    var currentQueryOptions = defaults(clone(queryOptions), {accept: req.headers.accept})

    return client[queryOperation](query, currentQueryOptions).then(function (result) {
      result.headers.forEach(function (value, name) {
        res.setHeader(name, value)
      })

      result.body.pipe(res)
    }).catch(next)
  }
}

module.exports = sparqlProxy
<commit_msg>bypass middleware if no options are given<commit_after>/* global log */

'use strict'

var clone = require('lodash/clone')
var defaults = require('lodash/defaults')
var SparqlHttpClient = require('sparql-http-client')

SparqlHttpClient.fetch = require('node-fetch')

function authBasicHeader (user, password) {
  return 'Basic ' + new Buffer(user + ':' + password).toString('base64')
}

function sparqlProxy (options) {
  if (options) {
    var queryOptions = {}

    if (options.authentication) {
      queryOptions.headers = {
        Authorization: authBasicHeader(options.authentication.user, options.authentication.password)
      }
    }

    var queryOperation = options.queryOperation || 'postQueryDirect'
    var client = new SparqlHttpClient({endpointUrl: options.endpointUrl})
  }

  return function (req, res, next) {
    if (!options) {
      return next()
    }

    var query

    if (req.method === 'GET') {
      query = req.query.query
    } else if (req.method === 'POST') {
      query = req.body.query || req.body
    } else {
      return next()
    }

    log.info({script: __filename}, 'handle SPARQL request for endpoint: ' + options.endpointUrl)
    log.debug({script: __filename}, 'SPARQL query:' + query)

    // merge configuration query options with request query options
    var currentQueryOptions = defaults(clone(queryOptions), {accept: req.headers.accept})

    return client[queryOperation](query, currentQueryOptions).then(function (result) {
      result.headers.forEach(function (value, name) {
        res.setHeader(name, value)
      })

      result.body.pipe(res)
    }).catch(next)
  }
}

module.exports = sparqlProxy
<|endoftext|>


<commit_before>'use babel';

/* @flow */
import Promise from 'bluebird';
import { existsSync, readFile, unlink } from 'fs';
import { basename, dirname, join, resolve as pathResolve } from 'path';
import { EOL, tmpdir } from 'os';
import { BufferedProcess } from 'atom';
import { parse as babylonParse } from 'jest-editor-support';
import { parse as typescriptParse } from 'jest-test-typescript-parser';
import type { TextEditor } from 'atom';

const ERROR_TEXT = 'Error: ';
let shouldUpdateSnapshot = false;
let isSnapshotNotificationActive = false;

type assertionResult = {
  status: 'passed'|'failed'|'skipped'|'unknown',
  title: string,
  name: string,
  failureMessages: Array<string>
};

type itBlock = {
  file: string,
  name: string,
  start:{
    line: number,
    column: number
  },
  end:{
    line: number,
    column: number
  }
};

type TestState = 'passed'|'failed'|'skipped'|'unknown';

type message = {
  state: TestState,
  title: string,
  error: { name: string, message: string },
  duration?: number,
  lineNumber: number,
  filePath: string,
};

const readFileAsync = Promise.promisify(readFile);
const unlinkAsync = Promise.promisify(unlink);

export function convertPathToPattern(path :string) :string {
  return path.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
}

export function removeBadArgs(args :?Array<string>) {
  if (!args) {
    return [];
  }

  const prohibitedArgs = ['--json', '--outputFile', '--watch', '--watchAll', '--watchman'];
  const clearArgs = [];
  args.forEach((arg) => {
    const index = prohibitedArgs.indexOf(arg);
    if (index === -1) {
      clearArgs.push(arg);
    }
  });
  return clearArgs;
}

export function getJestError(result :assertionResult) :string {
  let errorMessage = '';
  if (result && result.failureMessages && result.failureMessages.length > 0) {
    const content = result.failureMessages[0];
    const messageMatch = content.match(/(^(.|\n)*?(?=\n\s*at\s.*\:\d*\:\d*))/);
    errorMessage = messageMatch ? messageMatch[0] : 'Error';
    if (errorMessage.startsWith(ERROR_TEXT)) {
      errorMessage = errorMessage.substr(ERROR_TEXT.length);
    }
  }
  return errorMessage;
}

export function getFormattedTesterMessage(state :TestState,
  title :string,
  errorMessage :string,
  duration :number,
  lineNumber :number,
  filePath :string) :message {
  return {
    state,
    title,
    error: {
      name: '',
      message: errorMessage,
    },
    duration,
    lineNumber,
    filePath,
  };
}

export function getMessagesFromAssertionResults(textEditor :TextEditor,
  assertionResults :Array<assertionResult>,
  duration :number) :Promise<Array<message>> {
  const filePath = textEditor.getPath();
  return Promise.reduce(assertionResults, (messages, testResult) =>
    new Promise((resolve) => {
      textEditor.scan(new RegExp(testResult.title.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&')),
      (scanResult) => {
        if (testResult.status === 'pending') {
          testResult.status = 'skipped';
        }
        const errorMessage = getJestError(testResult);
        const state = testResult.status;
        const title = testResult.title;
        const lineNumber = scanResult.row;
        messages.push(getFormattedTesterMessage(state, title, errorMessage, duration, lineNumber, filePath));
      });
      resolve(messages);
    }), []);
}

export function getMessagesFromTestLocations(textEditor :TextEditor,
  testLocations :?Array<itBlock>,
  assertionResults :Array<assertionResult>,
  duration :number) :Promise<Array<message>> {
  const filePath = textEditor.getPath();
  return Promise.reduce(testLocations, (messages, testLocation) => {
    const testResult = assertionResults.find(ar => ar.title === testLocation.name);
    if (assertionResults && assertionResults.length > 0 && testResult) {
      if (testResult.status === 'pending') {
        testResult.status = 'skipped';
      }
      const errorMessage = getJestError(testResult);
      const state = testResult.status;
      const title = testResult.title || '';
      const lineNumber = testLocation.start.line - 1;
      messages.push(getFormattedTesterMessage(state, title, errorMessage, duration, lineNumber, filePath));
    } else {
      const state = 'unknown';
      const title = testLocation.name || '';
      const lineNumber = testLocation.start.line - 1;
      const errorMessage = '';
      messages.push(getFormattedTesterMessage(state, title, errorMessage, duration, lineNumber, filePath));
    }
    return messages;
  }, []);
}

export function getMessagesFromTestResults(testResults :Array<Object>) {
  return Promise.map(testResults, testResult =>
    Promise.map(testResult.assertionResults, (result) => {
      if (result.status === 'pending') {
        result.status = 'skipped';
      }
      const errorMessage = getJestError(result);
      const state = result.status;
      const title = result.title;
      const lineNumber = 0;
      const duration = (testResult.endTime || 0) - (testResult.startTime || 0);
      return getFormattedTesterMessage(state, title, errorMessage, duration, lineNumber, testResult.name);
    }))
    .reduce((messages, result) => result.concat(messages), []);
}

export async function parseReporterOutput(data :string,
  filePath :string,
  textEditor :TextEditor,
  testLocations :?Array<itBlock>,
  output : string) :Promise<{messages: Array<message>, output: string}> {
  let messages = [];
  let dataJSON;
  try {
    dataJSON = await JSON.parse(data);
  } catch (error) {
    atom.notifications.addError('Tester Jest: Could not parse data to JSON.');
  }
  let duration = 0;
  if (dataJSON && dataJSON.testResults && dataJSON.testResults.length > 0) {
    duration = (dataJSON.testResults[0].endTime || 0) - (dataJSON.testResults[0].startTime || 0);
    if (filePath && textEditor) {
      const assertionResults = dataJSON.testResults[0].assertionResults;
      if (testLocations && testLocations.length > 0) {
        messages = await getMessagesFromTestLocations(textEditor, testLocations, assertionResults, duration);
      } else if (assertionResults) {
        messages = await getMessagesFromAssertionResults(textEditor, assertionResults, duration);
      }
    } else {
      // Project test
      messages = await getMessagesFromTestResults(dataJSON.testResults);
    }
  }
  if (!messages.length) {
    messages.push(getFormattedTesterMessage('unknown', 'No results', output, duration, 0, filePath));
  }
  return { messages, output };
}

export async function getTestLocations(filePath :string) :Promise<?Array<itBlock>> {
  if (!filePath) {
    return Promise.resolve(null);
  }
  const isTypeScript = filePath.match(/.(ts|tsx)$/);
  const parser = isTypeScript ? typescriptParse : babylonParse;
  try {
    const parseResults :{itBlocks:Array<itBlock>} = await parser(filePath);
    return parseResults.itBlocks;
  } catch (e) {
    console.warn('Tester Jest: Failed to parse with babel.', e);
  }
}

export function run(textEditor :?TextEditor, additionalArgs :?string) {
  return new Promise((resolve) => {
    let processOutput = `\u001b[1mTester Jest\u001b[0m${EOL}`;
    const filePath = textEditor ? textEditor.getPath() : '';
    const projectPath = filePath ? atom.project.relativizePath(filePath)[0] : atom.project.getPaths()[0];

    let cwd = projectPath;
    if (!(cwd)) {
      cwd = dirname(filePath);
    }
    const jsonOutputFilePath = join(tmpdir(),
      `tester-jest_${filePath ? basename(filePath) : basename(projectPath)}.json`);

    const userConfigArgs = removeBadArgs(atom.config.get('tester-jest.args'));
    const additionalArgsArray = (additionalArgs && additionalArgs.trim()) ?
      removeBadArgs(additionalArgs.trim().split(' ')) : [];

    const belowEighteen = atom.config.get('tester-jest.jestMajorVersion') < 18;
    const outputArg = belowEighteen ? '--jsonOutputFile' : '--outputFile';
    const defaultArgs = ['--json', outputArg, jsonOutputFilePath];
    if (filePath) {
      defaultArgs.push(convertPathToPattern(filePath));
    }
    if (shouldUpdateSnapshot) {
      defaultArgs.push('--updateSnapshot');
    }
    let args = userConfigArgs.concat(additionalArgsArray, defaultArgs);
    const env = Object.create(process.env);
    // Jest NODE_ENV default is 'test'
    // https://github.com/facebook/jest/blob/master/packages/jest-cli/bin/jest.js#L13
    env.NODE_ENV = atom.config.get('tester-jest.nodeEnv');
    // To use our own commands in create-react, we need to tell the command that
    // we're in a CI environment, or it will always append --watch
    env.CI = atom.config.get('tester-jest.ciEnv');
    // set NODE_PATH otherwise will set atom own path
    // https://github.com/atom/atom/blob/master/src/initialize-application-window.coffee#L71
    env.NODE_PATH = cwd;
    const options = { cwd, env };
    let jestBinary = atom.config.get('tester-jest.binaryPath');
    let command = '';
    if (jestBinary) {
      const runtimeExecutable = jestBinary;
      const parameters = runtimeExecutable.split(' ');
      command = parameters.shift();
      args = parameters.concat(args);
    } else {
      const jestBinaryProject = pathResolve(cwd, './node_modules/.bin/jest');
      jestBinary = existsSync(jestBinaryProject) ? jestBinaryProject : 'jest';
      command = jestBinary;
    }
    processOutput += `\u001b[1mcommand:\u001b[0m ${command} ${args.join(' ')}${EOL}`;
    processOutput += `\u001b[1mcwd:\u001b[0m ${cwd}${EOL}`;
    const stdout = (data) => {
      if (!data.startsWith('Test results written to:')) {
        processOutput += data;
      }
    };
    const stderr = data => processOutput += data;
    const exit = async () => {
      this.bufferedProcess = null;
      shouldUpdateSnapshot = false;
      try {
        const testLocations = await getTestLocations(filePath);
        const jestJsonResults = await readFileAsync(jsonOutputFilePath, 'utf8');
        await unlinkAsync(jsonOutputFilePath);
        resolve(await parseReporterOutput(jestJsonResults, filePath, textEditor, testLocations, processOutput));
        if (!isSnapshotNotificationActive &&
          processOutput.includes('Inspect your code changes or re-run with `-u` to update them.')) {
          isSnapshotNotificationActive = true;
          const notification = atom.notifications.addInfo('Tester Jest', {
            detail: 'Do you want update the snapshot?',
            icon: 'beaker',
            dismissable: true,
            buttons: [
              {
                text: 'Yes',
                onDidClick: () => {
                  shouldUpdateSnapshot = true;
                  atom.commands.dispatch(atom.views.getView(atom.workspace.getActivePaneItem()), 'tester:test-last');
                  isSnapshotNotificationActive = false;
                  notification.dismiss();
                },
              },
              {
                text: 'No',
                onDidClick: () => {
                  shouldUpdateSnapshot = false;
                  isSnapshotNotificationActive = false;
                  notification.dismiss();
                },
              },
            ],
          });
        }
      } catch (error) {
        processOutput += error.toString();
        resolve({
          messages: getFormattedTesterMessage('unknown', 'No results', error, 0, 0, filePath),
          output: processOutput,
        });
      }
    };
    this.bufferedProcess = new BufferedProcess({ command, args, options, stdout, stderr, exit });

    this.bufferedProcess.onWillThrowError(() => {
      const error = 'Tester is unable to locate the jest command. Please ensure process.env.PATH can access jest.';
      atom.notifications.addError(error);
    });
  });
}

export function stop() {
  if (this.bufferedProcess) {
    this.bufferedProcess.kill();
    this.bufferedProcess = null;
  }
}
<commit_msg>only windows<commit_after>'use babel';

/* @flow */
import Promise from 'bluebird';
import { existsSync, readFile, unlink } from 'fs';
import { basename, dirname, join, resolve as pathResolve } from 'path';
import { EOL, tmpdir } from 'os';
import { BufferedProcess } from 'atom';
import { parse as babylonParse } from 'jest-editor-support';
import { parse as typescriptParse } from 'jest-test-typescript-parser';
import type { TextEditor } from 'atom';

const ERROR_TEXT = 'Error: ';
let shouldUpdateSnapshot = false;
let isSnapshotNotificationActive = false;

type assertionResult = {
  status: 'passed'|'failed'|'skipped'|'unknown',
  title: string,
  name: string,
  failureMessages: Array<string>
};

type itBlock = {
  file: string,
  name: string,
  start:{
    line: number,
    column: number
  },
  end:{
    line: number,
    column: number
  }
};

type TestState = 'passed'|'failed'|'skipped'|'unknown';

type message = {
  state: TestState,
  title: string,
  error: { name: string, message: string },
  duration?: number,
  lineNumber: number,
  filePath: string,
};

const readFileAsync = Promise.promisify(readFile);
const unlinkAsync = Promise.promisify(unlink);

export function convertPathToPattern(path :string) :string {
  if (process.platform.match(/^win/)) {
    return path.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
  }
  return path;
}

export function removeBadArgs(args :?Array<string>) {
  if (!args) {
    return [];
  }

  const prohibitedArgs = ['--json', '--outputFile', '--watch', '--watchAll', '--watchman'];
  const clearArgs = [];
  args.forEach((arg) => {
    const index = prohibitedArgs.indexOf(arg);
    if (index === -1) {
      clearArgs.push(arg);
    }
  });
  return clearArgs;
}

export function getJestError(result :assertionResult) :string {
  let errorMessage = '';
  if (result && result.failureMessages && result.failureMessages.length > 0) {
    const content = result.failureMessages[0];
    const messageMatch = content.match(/(^(.|\n)*?(?=\n\s*at\s.*\:\d*\:\d*))/);
    errorMessage = messageMatch ? messageMatch[0] : 'Error';
    if (errorMessage.startsWith(ERROR_TEXT)) {
      errorMessage = errorMessage.substr(ERROR_TEXT.length);
    }
  }
  return errorMessage;
}

export function getFormattedTesterMessage(state :TestState,
  title :string,
  errorMessage :string,
  duration :number,
  lineNumber :number,
  filePath :string) :message {
  return {
    state,
    title,
    error: {
      name: '',
      message: errorMessage,
    },
    duration,
    lineNumber,
    filePath,
  };
}

export function getMessagesFromAssertionResults(textEditor :TextEditor,
  assertionResults :Array<assertionResult>,
  duration :number) :Promise<Array<message>> {
  const filePath = textEditor.getPath();
  return Promise.reduce(assertionResults, (messages, testResult) =>
    new Promise((resolve) => {
      textEditor.scan(new RegExp(testResult.title.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&')),
      (scanResult) => {
        if (testResult.status === 'pending') {
          testResult.status = 'skipped';
        }
        const errorMessage = getJestError(testResult);
        const state = testResult.status;
        const title = testResult.title;
        const lineNumber = scanResult.row;
        messages.push(getFormattedTesterMessage(state, title, errorMessage, duration, lineNumber, filePath));
      });
      resolve(messages);
    }), []);
}

export function getMessagesFromTestLocations(textEditor :TextEditor,
  testLocations :?Array<itBlock>,
  assertionResults :Array<assertionResult>,
  duration :number) :Promise<Array<message>> {
  const filePath = textEditor.getPath();
  return Promise.reduce(testLocations, (messages, testLocation) => {
    const testResult = assertionResults.find(ar => ar.title === testLocation.name);
    if (assertionResults && assertionResults.length > 0 && testResult) {
      if (testResult.status === 'pending') {
        testResult.status = 'skipped';
      }
      const errorMessage = getJestError(testResult);
      const state = testResult.status;
      const title = testResult.title || '';
      const lineNumber = testLocation.start.line - 1;
      messages.push(getFormattedTesterMessage(state, title, errorMessage, duration, lineNumber, filePath));
    } else {
      const state = 'unknown';
      const title = testLocation.name || '';
      const lineNumber = testLocation.start.line - 1;
      const errorMessage = '';
      messages.push(getFormattedTesterMessage(state, title, errorMessage, duration, lineNumber, filePath));
    }
    return messages;
  }, []);
}

export function getMessagesFromTestResults(testResults :Array<Object>) {
  return Promise.map(testResults, testResult =>
    Promise.map(testResult.assertionResults, (result) => {
      if (result.status === 'pending') {
        result.status = 'skipped';
      }
      const errorMessage = getJestError(result);
      const state = result.status;
      const title = result.title;
      const lineNumber = 0;
      const duration = (testResult.endTime || 0) - (testResult.startTime || 0);
      return getFormattedTesterMessage(state, title, errorMessage, duration, lineNumber, testResult.name);
    }))
    .reduce((messages, result) => result.concat(messages), []);
}

export async function parseReporterOutput(data :string,
  filePath :string,
  textEditor :TextEditor,
  testLocations :?Array<itBlock>,
  output : string) :Promise<{messages: Array<message>, output: string}> {
  let messages = [];
  let dataJSON;
  try {
    dataJSON = await JSON.parse(data);
  } catch (error) {
    atom.notifications.addError('Tester Jest: Could not parse data to JSON.');
  }
  let duration = 0;
  if (dataJSON && dataJSON.testResults && dataJSON.testResults.length > 0) {
    duration = (dataJSON.testResults[0].endTime || 0) - (dataJSON.testResults[0].startTime || 0);
    if (filePath && textEditor) {
      const assertionResults = dataJSON.testResults[0].assertionResults;
      if (testLocations && testLocations.length > 0) {
        messages = await getMessagesFromTestLocations(textEditor, testLocations, assertionResults, duration);
      } else if (assertionResults) {
        messages = await getMessagesFromAssertionResults(textEditor, assertionResults, duration);
      }
    } else {
      // Project test
      messages = await getMessagesFromTestResults(dataJSON.testResults);
    }
  }
  if (!messages.length) {
    messages.push(getFormattedTesterMessage('unknown', 'No results', output, duration, 0, filePath));
  }
  return { messages, output };
}

export async function getTestLocations(filePath :string) :Promise<?Array<itBlock>> {
  if (!filePath) {
    return Promise.resolve(null);
  }
  const isTypeScript = filePath.match(/.(ts|tsx)$/);
  const parser = isTypeScript ? typescriptParse : babylonParse;
  try {
    const parseResults :{itBlocks:Array<itBlock>} = await parser(filePath);
    return parseResults.itBlocks;
  } catch (e) {
    console.warn('Tester Jest: Failed to parse with babel.', e);
  }
}

export function run(textEditor :?TextEditor, additionalArgs :?string) {
  return new Promise((resolve) => {
    let processOutput = `\u001b[1mTester Jest\u001b[0m${EOL}`;
    const filePath = textEditor ? textEditor.getPath() : '';
    const projectPath = filePath ? atom.project.relativizePath(filePath)[0] : atom.project.getPaths()[0];

    let cwd = projectPath;
    if (!(cwd)) {
      cwd = dirname(filePath);
    }
    const jsonOutputFilePath = join(tmpdir(),
      `tester-jest_${filePath ? basename(filePath) : basename(projectPath)}.json`);

    const userConfigArgs = removeBadArgs(atom.config.get('tester-jest.args'));
    const additionalArgsArray = (additionalArgs && additionalArgs.trim()) ?
      removeBadArgs(additionalArgs.trim().split(' ')) : [];

    const belowEighteen = atom.config.get('tester-jest.jestMajorVersion') < 18;
    const outputArg = belowEighteen ? '--jsonOutputFile' : '--outputFile';
    const defaultArgs = ['--json', outputArg, jsonOutputFilePath];
    if (filePath) {
      defaultArgs.push(convertPathToPattern(filePath));
    }
    if (shouldUpdateSnapshot) {
      defaultArgs.push('--updateSnapshot');
    }
    let args = userConfigArgs.concat(additionalArgsArray, defaultArgs);
    const env = Object.create(process.env);
    // Jest NODE_ENV default is 'test'
    // https://github.com/facebook/jest/blob/master/packages/jest-cli/bin/jest.js#L13
    env.NODE_ENV = atom.config.get('tester-jest.nodeEnv');
    // To use our own commands in create-react, we need to tell the command that
    // we're in a CI environment, or it will always append --watch
    env.CI = atom.config.get('tester-jest.ciEnv');
    // set NODE_PATH otherwise will set atom own path
    // https://github.com/atom/atom/blob/master/src/initialize-application-window.coffee#L71
    env.NODE_PATH = cwd;
    const options = { cwd, env };
    let jestBinary = atom.config.get('tester-jest.binaryPath');
    let command = '';
    if (jestBinary) {
      const runtimeExecutable = jestBinary;
      const parameters = runtimeExecutable.split(' ');
      command = parameters.shift();
      args = parameters.concat(args);
    } else {
      const jestBinaryProject = pathResolve(cwd, './node_modules/.bin/jest');
      jestBinary = existsSync(jestBinaryProject) ? jestBinaryProject : 'jest';
      command = jestBinary;
    }
    processOutput += `\u001b[1mcommand:\u001b[0m ${command} ${args.join(' ')}${EOL}`;
    processOutput += `\u001b[1mcwd:\u001b[0m ${cwd}${EOL}`;
    const stdout = (data) => {
      if (!data.startsWith('Test results written to:')) {
        processOutput += data;
      }
    };
    const stderr = data => processOutput += data;
    const exit = async () => {
      this.bufferedProcess = null;
      shouldUpdateSnapshot = false;
      try {
        const testLocations = await getTestLocations(filePath);
        const jestJsonResults = await readFileAsync(jsonOutputFilePath, 'utf8');
        await unlinkAsync(jsonOutputFilePath);
        resolve(await parseReporterOutput(jestJsonResults, filePath, textEditor, testLocations, processOutput));
        if (!isSnapshotNotificationActive &&
          processOutput.includes('Inspect your code changes or re-run with `-u` to update them.')) {
          isSnapshotNotificationActive = true;
          const notification = atom.notifications.addInfo('Tester Jest', {
            detail: 'Do you want update the snapshot?',
            icon: 'beaker',
            dismissable: true,
            buttons: [
              {
                text: 'Yes',
                onDidClick: () => {
                  shouldUpdateSnapshot = true;
                  atom.commands.dispatch(atom.views.getView(atom.workspace.getActivePaneItem()), 'tester:test-last');
                  isSnapshotNotificationActive = false;
                  notification.dismiss();
                },
              },
              {
                text: 'No',
                onDidClick: () => {
                  shouldUpdateSnapshot = false;
                  isSnapshotNotificationActive = false;
                  notification.dismiss();
                },
              },
            ],
          });
        }
      } catch (error) {
        processOutput += error.toString();
        resolve({
          messages: getFormattedTesterMessage('unknown', 'No results', error, 0, 0, filePath),
          output: processOutput,
        });
      }
    };
    this.bufferedProcess = new BufferedProcess({ command, args, options, stdout, stderr, exit });

    this.bufferedProcess.onWillThrowError(() => {
      const error = 'Tester is unable to locate the jest command. Please ensure process.env.PATH can access jest.';
      atom.notifications.addError(error);
    });
  });
}

export function stop() {
  if (this.bufferedProcess) {
    this.bufferedProcess.kill();
    this.bufferedProcess = null;
  }
}
<|endoftext|>