<commit_before>'use strict'

module.exports = function (mongoose, config, db) {
    const utils = require('../lib/utils')();

    function articleResponse(article, owner) {
        const user = article.user;
        return {
            id: article.id,
            created_at: article.created_at,
            title: article.title,
            user_id: article.user.id,
            user: {
                id: user.id,
                name: user.name,
                email: user.email
            },
            keywords: article.keywords,
            content: article.content,
            draft: article.draft,
            category: article.category
        }
    }

    function commentResponse(comment, owner) {
        const user = comment.user;
        return {
            id: comment.id,
            user: {
                id: user.id,
                name: user.name,
                email: user.email
            },
            created_at: comment.created_at,
            content: comment.content,
            ref_id: comment.ref_id,
            hide: comment.hide
        }
    }

    return {
        _checkBlogPermission() {
            return (req, res, next) => {
                if (req.user.isSuperUser()) return next();
                utils.error(res, 403);
            }
        },

        _getArticle(req, res, next) {
            db.Article.findOne({ id: req.params.articleId })
                .populate('user')
                .populate('comments.user').exec((err, article) => {
                    if (err) return utils.error(res, 422, err);
                    if (!article) return utils.error(res, 404);
                    req.article = article;
                    next();
                });
        },

        create(req, res) {
            db.Sequence.getNextSequence("articles", (err, nextArticleId) => {
                if (err) return utils.error(res, 422, err);
                let keywords = req.body.keywords || req.body.title;
                try {
                    if (keywords && keywords.count) keywords = Array.from(keywords);
                    else keywords = undefined;
                } catch (e) {
                    keywords = undefined;
                }
                const article = db.Article({
                    id: nextArticleId,
                    title: req.body.title,
                    user: req.user,
                    content: req.body.content,
                    keywords: keywords,
                    draft: req.body.draft ? req.body.draft : false
                });
                db.Category.setCategory(req.body.category, article, () => article.save(err => err ?
                    db.Sequence.SequenceRollback("articles", utils.error(res, 422, err.message)) :
                    utils.success(res, "update success!")));
            })
        },
        delete(req, res) {
            if (!req.user.isSuperUser() && req.article.user.id != req.user.id) return utils.error(res, 403);
            req.article.remove(err => err ? utils.error(res, 422)
                : utils.success(res, "delete successful"));
        },
        update(req, res) {
            if (!req.user.isSuperUser() && req.article.user.id != req.user.id) return utils.error(res, 403);

            if (req.body.title) req.article.title = req.body.title;
            if (req.body.content) req.article.price = req.body.content;
            if (req.body.keywords) req.article.keywords = req.body.keywords.split(',');
            if (req.body.draft) req.article.draft = req.body.draft;

            req.article.save((err, article) => err ? utils.error(res, 422, err.message)
                : utils.success(res, articleResponse(article)));
        },
        get(req, res) {
            const id = req.params.articleId;
            db.Article.findOne({ id }).populate("user").exec((err, article) => {
                if (err) return utils.error(res, 422, err.message);
                if (!article) return utils.error(res, 404);
                if (article.draft && !(req.user && (req.user.isSuperUser() || req.user.id == article.user.id)))
                    return utils.error(res, 422, err.message);
                utils.responseData(res, article.id, articleResponse(article,
                    req.user && (req.user.isSuperUser() || req.user.id == article.user.id)));
            })
        },
        find(req, res) {
            let query = {};
            let sortBy = null;

            sortBy = {};
            sortBy["order_by"] = "created_at";
            sortBy["order_type"] = "desc";
            if (req.query.title) query["title"] = req.query.title;
            if (req.query.user_id) query["user.id"] = req.query.user_id;
            if (req.query.keywords) query["keywords"] = { $in: req.query.keywords.split(',') }
            if (req.query.category) query["category"] = { $in: req.query.category.split(',') }
            if (req.query.order_type === "asc") sortBy["order_type"] = req.query.order_type;
            if (req.query.draft) query["draft"] = req.query.draft;

            const queryRequest = db.Article.find(query);
            if (sortBy) {
                var sort = {};
                sort[sortBy["order_by"]] = sortBy["order_type"] === "asc" ? "ascending" : "descending";
                queryRequest.sort(sort);
            }

            queryRequest.populate("user").exec((err, dbResponse) => {
                if (err) return utils.error(res, 422, err.message);
                if (!dbResponse) return utils.error(res, 404);
                let ret = dbResponse
                    .filter(article => !article.draft || (req.user && (req.user.isSuperUser() || req.user.id == article.user.id)))
                    .map(article =>
                        articleResponse(article, req.user && (req.user.isSuperUser() || req.user.id == article.user.id)));
                utils.responseData(res, ret.count, ret);
            })
        },

        setupPublic(Router) {
            const articleRouter = new Router();

            articleRouter.param('articleId', utils.requiredParams('articleId'));
            articleRouter.param('commentId', utils.requiredParams('commentId'));
            articleRouter.use('/article/:articleId', this._getArticle);
            articleRouter.use('/article/:articleId/comment/:commentId', this._getArticle);

            articleRouter.get('/article', this.find);
            articleRouter.get('/article/:articleId', this.get);
            articleRouter.get('/article/:articleId/comment', this.Comment.getAll);
            articleRouter.get('/article/:articleId/comment/:commentId', this.Comment.getAll);

            return articleRouter;
        },

        setup(Router) {
            const articleRouter = this.setupPublic(Router);

            articleRouter.post('/article', utils.requiredFields('title category content'), utils.checkSuperUser, this.create);
            articleRouter.route('/article/:articleId').put(this.update).delete(utils.checkSuperUser, this.delete);
            articleRouter.route('/article/:articleId/comment').post(this.Comment.create);
            articleRouter.route('/article/:articleId/comment/:commentId')
                .post(this.Comment.create).delete(this.Comment.delete).put(utils.checkSuperUser, this.Comment.changeHideState);

            return articleRouter;
        },
        Comment: {
            _getComment(req, res, next) {
                let comment = req.article.comments.id(req.params.commentId);
                if (!comment) return utils.error(res, 404);
                req.comment = comment;
                next();
            },

            getAll(req, res) {
                // Only bloggers and commentators can see the hidden comments
                let ret = req.user && (req.user.isSuperUser() || req.article.user.id == req.user.id) ? req.article.comments
                    : req.article.comments.filter(comment => !comment.hide || (req.user && comment.user.id == req.user.id))
                utils.responseData(res, ret.count, ret.map(comment => commentResponse(comment)));
            },

            getSingle(req, res) {
                if (!req.user.isSuperUser()
                    && req.comment.hide
                    && (!req.user || req.article.user.id != req.user.id) // Logged, but not blogger
                    && req.comment.user.id != req.user.id) // Nor is commentator
                    return utils.error(res, 404); // Pretend it does not exist
                utils.responseData(res, "", commentResponse(req.comment));
            },

            create(req, res) {
                if (!req.article.comments) req.article.comments = [];
                if (req.params.commentId
                    && !req.user.isSuperUser()
                    && req.comment.hide
                    && (!req.user || req.article.user.id != req.user.id)
                    && req.comment.user.id != req.user.id)
                    return utils.error(res, 404);
                req.article.comments.push({
                    user: req.user,
                    content: req.body.content,
                    ref_id: req.comment ? req.comment.id : undefined
                });
                req.article.save(err => err ? utils.error(res, 422, err.message)
                    : utils.responseData(res, "post successful"));
            },

            changeHideState(req, res) {
                if (!req.user.isSuperUser() && (!req.user || req.article.user.id != req.user.id))
                    return utils.error(res, 404); // Pretend it does not exist
                req.comment.hide = !!req.params.hide;
                req.comment.save();
            },

            delete(req, res) {
                req.comment.remove();
                req.article.save(err => err ? utils.error(res, 422, err.message)
                    : utils.responseData(res, "delete successful"));
            }
        }
    }
}<commit_msg>debug<commit_after>'use strict'

module.exports = function (mongoose, config, db) {
    const utils = require('../lib/utils')();

    function articleResponse(article, owner) {
        const user = article.user;
        return {
            id: article.id,
            created_at: article.created_at,
            title: article.title,
            user_id: article.user.id,
            user: {
                id: user.id,
                name: user.name,
                email: user.email
            },
            keywords: article.keywords,
            content: article.content,
            draft: article.draft,
            category: article.category
        }
    }

    function commentResponse(comment, owner) {
        const user = comment.user;
        return {
            id: comment.id,
            user: {
                id: user.id,
                name: user.name,
                email: user.email
            },
            created_at: comment.created_at,
            content: comment.content,
            ref_id: comment.ref_id,
            hide: comment.hide
        }
    }

    return {
        _checkBlogPermission() {
            return (req, res, next) => {
                if (req.user.isSuperUser()) return next();
                utils.error(res, 403);
            }
        },

        _getArticle(req, res, next) {
            db.Article.findOne({ id: req.params.articleId })
                .populate('user')
                .populate('comments.user').exec((err, article) => {
                    if (err) return utils.error(res, 422, err);
                    if (!article) return utils.error(res, 404);
                    req.article = article;
                    next();
                });
        },

        create(req, res) {
            db.Sequence.getNextSequence("articles", (err, nextArticleId) => {
                if (err) return utils.error(res, 422, err);
                let keywords = req.body.keywords || req.body.title;
                console.log(keywords);
                try {
                    if (keywords && keywords.count) keywords = Array.from(keywords);
                    else keywords = undefined;
                } catch (e) {
                    keywords = undefined;
                }
                const article = db.Article({
                    id: nextArticleId,
                    title: req.body.title,
                    user: req.user,
                    content: req.body.content,
                    keywords: keywords,
                    draft: req.body.draft ? req.body.draft : false
                });
                db.Category.setCategory(req.body.category, article, () => article.save(err => err ?
                    db.Sequence.SequenceRollback("articles", utils.error(res, 422, err.message)) :
                    utils.success(res, "update success!")));
            })
        },
        delete(req, res) {
            if (!req.user.isSuperUser() && req.article.user.id != req.user.id) return utils.error(res, 403);
            req.article.remove(err => err ? utils.error(res, 422)
                : utils.success(res, "delete successful"));
        },
        update(req, res) {
            if (!req.user.isSuperUser() && req.article.user.id != req.user.id) return utils.error(res, 403);

            if (req.body.title) req.article.title = req.body.title;
            if (req.body.content) req.article.price = req.body.content;
            if (req.body.keywords) req.article.keywords = req.body.keywords.split(',');
            if (req.body.draft) req.article.draft = req.body.draft;

            req.article.save((err, article) => err ? utils.error(res, 422, err.message)
                : utils.success(res, articleResponse(article)));
        },
        get(req, res) {
            const id = req.params.articleId;
            db.Article.findOne({ id }).populate("user").exec((err, article) => {
                if (err) return utils.error(res, 422, err.message);
                if (!article) return utils.error(res, 404);
                if (article.draft && !(req.user && (req.user.isSuperUser() || req.user.id == article.user.id)))
                    return utils.error(res, 422, err.message);
                utils.responseData(res, article.id, articleResponse(article,
                    req.user && (req.user.isSuperUser() || req.user.id == article.user.id)));
            })
        },
        find(req, res) {
            let query = {};
            let sortBy = null;

            sortBy = {};
            sortBy["order_by"] = "created_at";
            sortBy["order_type"] = "desc";
            if (req.query.title) query["title"] = req.query.title;
            if (req.query.user_id) query["user.id"] = req.query.user_id;
            if (req.query.keywords) query["keywords"] = { $in: req.query.keywords.split(',') }
            if (req.query.category) query["category"] = { $in: req.query.category.split(',') }
            if (req.query.order_type === "asc") sortBy["order_type"] = req.query.order_type;
            if (req.query.draft) query["draft"] = req.query.draft;

            const queryRequest = db.Article.find(query);
            if (sortBy) {
                var sort = {};
                sort[sortBy["order_by"]] = sortBy["order_type"] === "asc" ? "ascending" : "descending";
                queryRequest.sort(sort);
            }

            queryRequest.populate("user").exec((err, dbResponse) => {
                if (err) return utils.error(res, 422, err.message);
                if (!dbResponse) return utils.error(res, 404);
                let ret = dbResponse
                    .filter(article => !article.draft || (req.user && (req.user.isSuperUser() || req.user.id == article.user.id)))
                    .map(article =>
                        articleResponse(article, req.user && (req.user.isSuperUser() || req.user.id == article.user.id)));
                utils.responseData(res, ret.count, ret);
            })
        },

        setupPublic(Router) {
            const articleRouter = new Router();

            articleRouter.param('articleId', utils.requiredParams('articleId'));
            articleRouter.param('commentId', utils.requiredParams('commentId'));
            articleRouter.use('/article/:articleId', this._getArticle);
            articleRouter.use('/article/:articleId/comment/:commentId', this._getArticle);

            articleRouter.get('/article', this.find);
            articleRouter.get('/article/:articleId', this.get);
            articleRouter.get('/article/:articleId/comment', this.Comment.getAll);
            articleRouter.get('/article/:articleId/comment/:commentId', this.Comment.getAll);

            return articleRouter;
        },

        setup(Router) {
            const articleRouter = this.setupPublic(Router);

            articleRouter.post('/article', utils.requiredFields('title category content'), utils.checkSuperUser, this.create);
            articleRouter.route('/article/:articleId').put(this.update).delete(utils.checkSuperUser, this.delete);
            articleRouter.route('/article/:articleId/comment').post(this.Comment.create);
            articleRouter.route('/article/:articleId/comment/:commentId')
                .post(this.Comment.create).delete(this.Comment.delete).put(utils.checkSuperUser, this.Comment.changeHideState);

            return articleRouter;
        },
        Comment: {
            _getComment(req, res, next) {
                let comment = req.article.comments.id(req.params.commentId);
                if (!comment) return utils.error(res, 404);
                req.comment = comment;
                next();
            },

            getAll(req, res) {
                // Only bloggers and commentators can see the hidden comments
                let ret = req.user && (req.user.isSuperUser() || req.article.user.id == req.user.id) ? req.article.comments
                    : req.article.comments.filter(comment => !comment.hide || (req.user && comment.user.id == req.user.id))
                utils.responseData(res, ret.count, ret.map(comment => commentResponse(comment)));
            },

            getSingle(req, res) {
                if (!req.user.isSuperUser()
                    && req.comment.hide
                    && (!req.user || req.article.user.id != req.user.id) // Logged, but not blogger
                    && req.comment.user.id != req.user.id) // Nor is commentator
                    return utils.error(res, 404); // Pretend it does not exist
                utils.responseData(res, "", commentResponse(req.comment));
            },

            create(req, res) {
                if (!req.article.comments) req.article.comments = [];
                if (req.params.commentId
                    && !req.user.isSuperUser()
                    && req.comment.hide
                    && (!req.user || req.article.user.id != req.user.id)
                    && req.comment.user.id != req.user.id)
                    return utils.error(res, 404);
                req.article.comments.push({
                    user: req.user,
                    content: req.body.content,
                    ref_id: req.comment ? req.comment.id : undefined
                });
                req.article.save(err => err ? utils.error(res, 422, err.message)
                    : utils.responseData(res, "post successful"));
            },

            changeHideState(req, res) {
                if (!req.user.isSuperUser() && (!req.user || req.article.user.id != req.user.id))
                    return utils.error(res, 404); // Pretend it does not exist
                req.comment.hide = !!req.params.hide;
                req.comment.save();
            },

            delete(req, res) {
                req.comment.remove();
                req.article.save(err => err ? utils.error(res, 422, err.message)
                    : utils.responseData(res, "delete successful"));
            }
        }
    }
}<|endoftext|>


<commit_before>var secrets = require('../config/secrets');
var crypto = require('crypto');
var nodemailer = require("nodemailer");
var smtpTransport = nodemailer.createTransport('SMTP', {
  service: 'Mailgun',
  auth: {
    user: secrets.mailgun.login,
    pass: secrets.mailgun.password
  }
});
var Purchase = require('../models/Purchase');
var User = require('../models/User');

exports.gumroadWebhook = function( req, res ) {
  if (req.user) return res.redirect('/?todo=AccountFoundAndWillBeCreditedThanksPage');
  res.set('Content-Type', 'text/plain');
  return res.send("http://" + req.header('host') + "/signup?email=" + req.body.email + "&name=" + req.body.name);
}

exports.purchase = function( req, res ) {
  Purchase.findOne({ url_hash: req.params.hash }, function(err, purchase) {
    if (err) return next(err);
    if( purchase != null ) {
      console.log( purchase );
      console.log( purchase.claimed );
      if( purchase.claimed ) {
        res.send('This purchased has been redeemed to ' + purchase.email + '. Thanks!');
      }
      else{
        User.findById(req.user.id, function (err, user) {
          if (err) return next(err);
          // Round to tenths
          // Give 10 Tokens
          user.server.tokens = (Math.round(10*user.server.tokens)/10)+10;
          user.save(function (err) {
            if (err) return next(err);
            purchase.claimed = true;
            purchase.save(function(err) {
              if (err) { return err; }
              console.log( 'purchase claimed' );
              req.flash('default', { msg: 'Redeemed tokens to account' + purchase.email + '. Thanks!'});
              res.redirect('/server');
            });
          });
        });
      }
    }
    else {
      res.send( 'Can\'t find it...' );
    }
  });
}

exports.gumroadPurchaseCallback = function( req, res ) {
  console.log( req.body );
  if ( req.body.test ) {
    console.log( ' THIS IS A TEST ' );
  }
  if ( req.body.seller_id === secrets.gumroad.seller_id ) {
    // && req.body.test != 'true' ) { ??

    var hash = crypto.createHash('md5').update(JSON.stringify(req.body)+Math.random()).digest("hex");
    // This is a purchase
    var purchase = new Purchase({
      url_hash: hash,
      seller_id: req.body.seller_id,
      product_id: req.body.product_id,
      product_name: req.body.product_name,
      permalink: req.body.permalink,
      product_permalink: req.body.product_permalink,
      email: req.body.email,
      price: req.body.price,
      currency: req.body.currency,
      order_number: req.body.order_number,
      full_name: req.body.full_name || '',
      test: req.body.test || false
    });

    User.findOne({ email: req.body.email }, function(err, user) {
      if (err) return next(err);
      if( user != null ) {
        console.log(user);
        user.server.tokens = user.server.tokens + 10;
        purchase.claimed = true;
        purchase.save(function(err) {
          if (err) { return err; }
            console.log( 'purchase saved' );
            user.save(function(err) {
              console.log( 'user saved');
              var mailOptions = {
                to: req.body.email,
                from: 'tdy721@gmail.com',
                subject: 'Thanks for your purchase',
                text: 'You bought server tokens! They have been added to your account: http://my.boundstar.com/purchase/' + hash
              };
              smtpTransport.sendMail(mailOptions, function(err) {
                if (err) {
                  req.flash('errors', { msg: err.message });
                  return res.redirect('/server');
                }
                req.flash('success', { msg: 'Email has been sent successfully!' });
                res.redirect('/server');
              });
            });
        });
      }else{
        // EMailed Waiting
        purchase.save(function(err) {
          if (err) { return err; }
            console.log( 'purchase saved' );
            var mailOptions = {
              to: req.body.email,
              from: 'tdy721@gmail.com',
              subject: 'Thanks for your purchase',
              text: 'You bought server tokens! Register, then claim them with this url: http://my.boundstar.com/purchase/' + hash
            };
            smtpTransport.sendMail(mailOptions, function(err) {
              if (err) {
                req.flash('errors', { msg: err.message });
                return res.redirect('/server');
              }
              req.flash('success', { msg: 'Email has been sent successfully!' });
              res.redirect('/server');
            });
        });
      }
    });
  }
  else {
    return res.send("go away, seller_id did not match.");
  }
}
<commit_msg>cleanup<commit_after>var secrets = require('../config/secrets');
var crypto = require('crypto');
var nodemailer = require("nodemailer");
var smtpTransport = nodemailer.createTransport('SMTP', {
  service: 'Mailgun',
  auth: {
    user: secrets.mailgun.login,
    pass: secrets.mailgun.password
  }
});
var Purchase = require('../models/Purchase');
var User = require('../models/User');

exports.gumroadWebhook = function( req, res ) {
  if (req.user) return res.redirect('/?todo=AccountFoundAndWillBeCreditedThanksPage');
  res.set('Content-Type', 'text/plain');
  return res.send("http://" + req.header('host') + "/signup?email=" + req.body.email + "&name=" + req.body.name);
}

exports.purchase = function( req, res ) {
  Purchase.findOne({ url_hash: req.params.hash }, function(err, purchase) {
    if (err) return next(err);
    if( purchase != null ) {
      console.log( purchase );
      console.log( purchase.claimed );
      if( purchase.claimed ) {
        res.send('This purchased has been redeemed to ' + purchase.email + '. Thanks!');
      }
      else{
        User.findById(req.user.id, function (err, user) {
          if (err) return next(err);
          // Round to tenths
          // Give 10 Tokens
          user.server.tokens = (Math.round(10*user.server.tokens)/10)+10;
          user.save(function (err) {
            if (err) return next(err);
            purchase.claimed = true;
            purchase.save(function(err) {
              if (err) { return err; }
              console.log( 'purchase claimed' );
              req.flash('success', { msg: 'Redeemed tokens to account' + purchase.email + '. Thanks!'});
              res.redirect('/server');
            });
          });
        });
      }
    }
    else {
      res.send( 'Can\'t find it...' );
    }
  });
}

exports.gumroadPurchaseCallback = function( req, res ) {
  console.log( req.body );
  if ( req.body.test ) {
    console.log( ' THIS IS A TEST ' );
  }
  if ( req.body.seller_id === secrets.gumroad.seller_id ) {
    // && req.body.test != 'true' ) { ??
    var hash = crypto.createHash('md5').update(JSON.stringify(req.body)+Math.random()).digest("hex");
    var mailOptions = {
      to: req.body.email,
      from: 'tdy721@gmail.com',
      subject: 'Thanks for your purchase',
      text: 'http://my.boundstar.com/purchase/' + hash
    };
    // This is a purchase
    var purchase = new Purchase({
      url_hash: hash,
      seller_id: req.body.seller_id,
      product_id: req.body.product_id,
      product_name: req.body.product_name,
      permalink: req.body.permalink,
      product_permalink: req.body.product_permalink,
      email: req.body.email,
      price: req.body.price,
      currency: req.body.currency,
      order_number: req.body.order_number,
      full_name: req.body.full_name || '',
      test: req.body.test || false
    });

    User.findOne({ email: req.body.email }, function(err, user) {
      if (err) return next(err);
      if( user != null ) {
        console.log(user);
        user.server.tokens = parseFloat(Math.round(10*user.server.tokens)/10)+10;
        purchase.claimed = true;
        purchase.save(function(err) {
          if (err) { return err; }
            console.log( 'purchase saved' );
            user.save(function(err) {
              console.log( 'user saved');
              // 'You bought server tokens! They have been added to your account:'
              smtpTransport.sendMail(mailOptions, function(err) {
                if (err) {
                  req.flash('errors', { msg: err.message });
                  return res.redirect('/server');
                }
                req.flash('success', { msg: 'Email has been sent successfully!' });
                res.redirect('/server');
              });
            });
        });
      }else{
        // EMailed Waiting to be claimed
        purchase.save(function(err) {
          if (err) { return err; }
            console.log( 'purchase saved' );
            var mailOptions = {
              to: req.body.email,
              from: 'tdy721@gmail.com',
              subject: 'Thanks for your purchase',
              text: 'You bought server tokens! Register, then claim them with this url: http://my.boundstar.com/purchase/' + hash
            };
            smtpTransport.sendMail(mailOptions, function(err) {
              if (err) {
                req.flash('errors', { msg: err.message });
                return res.redirect('/server');
              }
              req.flash('success', { msg: 'Email has been sent successfully!' });
              res.redirect('/server');
            });
        });
      }
    });
  }
  else {
    return res.send("go away, seller_id did not match.");
  }
}
<|endoftext|>


<commit_before>
/*      Dependencies
 ---------------------------------------------*/

var express = require('express')
  , async   = require('async')
  , paypal  = require('paypal-rest-sdk');

const returnUrl = SERVER_URI+'#/processPayment';
const cancelUrl = SERVER_URI+'#/cancelPayment';

/**
 |======================================================================================
 |    Payment Module start here...
 |======================================================================================
 */

 var payReq = { intent:'sale', redirect_urls:{ return_url:returnUrl, cancel_url: cancelUrl  }, payer:{ payment_method:'paypal' } };

/*
 |--------------------------------------------------
 | Create Payment through the PayPal
 |--------------------------------------------------
 */
exports.createPayment = function(req, res) {

    var links = new Object();

    payReq.transactions = [{ amount:{ total:'18', currency:'GBP' }, description:'This is the payment transaction description.' }];

    paypal.payment.create(JSON.stringify(payReq), function(err, payment) {

        if(err) return res.status(400).json({
            status: false, message: msg.PAYMENT_FAILED
        });

            payment.links.forEach(function(linkObj){
                links[linkObj.rel] = {
                    href: linkObj.href,
                    method: linkObj.method
                };
            });

        if (links.hasOwnProperty('approval_url')) {
            return res.status(200).json({ status:true, pay_url:links['approval_url'].href });
        } else {
            return res.status(400).json({
                status: false, message: msg.BAD_REQUEST
            });
        }

    });
};

/*
 |--------------------------------------------------
 | Making Payment through the PayPal
 |--------------------------------------------------
 */
exports.executePayment = function (req, res) {

   paypal.payment.execute(req.query.paymentId, { payer_id: req.query.payerId }, function(error, payment) {

        if(error) return res.status(400).json({
           status:false, message: msg.PAYMENT_FAILED
        });

        if (payment.state == 'approved')
            return res.status(200).json({ status:true, message: msg.PAYMENT_SUCCESS });

        return res.status(400).json({ status:true, message: msg.PAYMENT_FAILED});
    });
};

/*
 |--------------------------------------------------
 | Get PayPal Transactions List
 |--------------------------------------------------
 */
exports.getTransactions = function (req, res) {

    paypal.payment.list({ start_index: 1 }, function (error, transactions) {
        if (error)
            return res.status(400).json({ status: false, message: msg.BAD_REQUEST});

        return res.status(200).json( { status: true, count:transactions.payments.length, response: transactions.payments } );
    });
};

/*
 |--------------------------------------------------
 | Get all paypal webhooks notification events
 |--------------------------------------------------
 */
exports.paypalNotifications = function (req, res) {
   console.log(req); res.send("DONE");

};

<commit_msg>Changes -> changes made on payment controller to check webhook events nofications<commit_after>
/*      Dependencies
 ---------------------------------------------*/

var express = require('express')
  , async   = require('async')
  , paypal  = require('paypal-rest-sdk');

const returnUrl = SERVER_URI+'#/processPayment';
const cancelUrl = SERVER_URI+'#/cancelPayment';

/**
 |======================================================================================
 |    Payment Module start here...
 |======================================================================================
 */

 var payReq = { intent:'sale', redirect_urls:{ return_url:returnUrl, cancel_url: cancelUrl  }, payer:{ payment_method:'paypal' } };

/*
 |--------------------------------------------------
 | Create Payment through the PayPal
 |--------------------------------------------------
 */
exports.createPayment = function(req, res) {

    var links = new Object();

    payReq.transactions = [{ amount:{ total:'18', currency:'GBP' }, description:'This is the payment transaction description.' }];

    paypal.payment.create(JSON.stringify(payReq), function(err, payment) {

        if(err) return res.status(400).json({
            status: false, message: msg.PAYMENT_FAILED
        });

            payment.links.forEach(function(linkObj){
                links[linkObj.rel] = {
                    href: linkObj.href,
                    method: linkObj.method
                };
            });

        if (links.hasOwnProperty('approval_url')) {
            return res.status(200).json({ status:true, pay_url:links['approval_url'].href });
        } else {
            return res.status(400).json({
                status: false, message: msg.BAD_REQUEST
            });
        }

    });
};

/*
 |--------------------------------------------------
 | Making Payment through the PayPal
 |--------------------------------------------------
 */
exports.executePayment = function (req, res) {

   paypal.payment.execute(req.query.paymentId, { payer_id: req.query.payerId }, function(error, payment) {

        if(error) return res.status(400).json({
           status:false, message: msg.PAYMENT_FAILED
        });

        if (payment.state == 'approved')
            return res.status(200).json({ status:true, message: msg.PAYMENT_SUCCESS });

        return res.status(400).json({ status:true, message: msg.PAYMENT_FAILED});
    });
};

/*
 |--------------------------------------------------
 | Get PayPal Transactions List
 |--------------------------------------------------
 */
exports.getTransactions = function (req, res) {

    paypal.payment.list({ start_index: 1 }, function (error, transactions) {
        if (error)
            return res.status(400).json({ status: false, message: msg.BAD_REQUEST});

        return res.status(200).json( { status: true, count:transactions.payments.length, response: transactions.payments } );
    });
};

/*
 |--------------------------------------------------
 | Get all paypal webhooks notification events
 |--------------------------------------------------
 */
exports.paypalNotifications = function (req, res) {
    console.log(req.headers);
    var headers     = { 'paypal-auth-algo': req.headers.paypal-auth-algo, 'paypal-cert-url': req.headers.paypal-cert-url, 'paypal-transmission-id': req.headers.paypal-transmission-id, 'paypal-transmission-sig': req.headers.paypal-transmission-sig, 'paypal-transmission-time': req.headers.paypal-transmission-time };

    paypal.notification.webhookEvent.verify(headers, req.body, '73B67500R3338843F', function (error, response) {
        if (error) {
            console.log(error);
            throw error;
        } else {
            console.log(response);

            if (response.verification_status === "SUCCESS") {
                console.log("It was a success.");
            } else {
                console.log("It was a failed verification");
            }
        }
    });
};

<|endoftext|>


<commit_before>'use strict'

import React, {
  Component,
  StyleSheet,
  Navigator,
  Platform,
  View,
  Text,
  BackAndroid,
  TouchableOpacity,
  PixelRatio,
  Image,
  DrawerLayoutAndroid,
} from 'react-native'

import DDPClient from 'ddp-client';

import Login from './app/pages/Login'
import PageTwo from './app/pages/PageTwo'
import PageThree from './app/pages/PageThree'
import PageFour from './app/pages/PageFour'
import AddEarnerProfile from './app/pages/AddEarnerProfile'
const Page = {Login, PageTwo, PageThree, PageFour, AddEarnerProfile}

const Drawer = require('react-native-drawer') // Third party drawer layout that works in iOS, very funky so use with care

let ddpClient = new DDPClient({
  // host: '192.168.1.3', // If using android use your device IP address
  port: '3000',
  // url: <your websocket url>
})

export default class Route extends Component {
	constructor(props) {
		super(props)
		this.state = {
			isDrawerOpen: false,
		}
	}
	_openDrawer() {
		if(Platform.OS === 'ios') {
			this.refs.drawer.open()
		} else {
			this.refs.drawer.openDrawer()
		}
	}
	_closeDrawer() {
		if(Platform.OS === 'ios') {
			this.refs.drawer.close()
		} else {
			this.refs.drawer.closeDrawer()
		}
	}
	toggleDrawerLayout(){
		if(this.state.isDrawerOpen) {
			this._closeDrawer.bind(this)()
		} else {
			this._openDrawer.bind(this)()
		}
	}
	// This gets called when you add new page into navigator stack (ie. navigator.push or navigator.replace)
	renderPage(route, navigator) {
		if(route.className) {
			return React.createElement(Page[route.className], {route, navigator, ddpClient})
		} else {
			route.title = ''
			return React.createElement(Page['PageTwo'], {route, navigator, ddpClient})
		}
	}
	drawerMenuItemPressed(alertPopupMessage) {
		this._closeDrawer()
		alert(alertPopupMessage)
		this.ddpClient.call('addPost')
	}
	renderMenuItems() {
		return (
			<View style={styles.drawerLayoutView}>
				<TouchableOpacity onPress={()=>alert('Do Something!')}>
					<View style={styles.drawerMenuItemView}>
						<Image style={styles.drawerMenuItemImage} source={require('./app/img/navigation/nav_icon_menu.png')} />
						<Text style={styles.drawerMenuItemText}>Do Something!</Text>
					</View>
				</TouchableOpacity>
				<View style={styles.drawerMenuItemSeparator}/>
				<TouchableOpacity onPress={this.drawerMenuItemPressed.bind(this, 'Do Something2!')}>
					<View style={styles.drawerMenuItemView}>
						<Image style={styles.drawerMenuItemImage} source={require('./app/img/navigation/nav_icon_menu.png')} />
						<Text style={styles.drawerMenuItemText}>Do Something2!</Text>
					</View>
				</TouchableOpacity>
				<View style={styles.drawerMenuItemSeparator}/>
				<TouchableOpacity onPress={()=>alert('Do Something3!')}>
					<View style={styles.drawerMenuItemView}>
						<Image style={styles.drawerMenuItemImage} source={require('./app/img/navigation/nav_icon_menu.png')} />
						<Text style={styles.drawerMenuItemText}>Do Something3!</Text>
					</View>
				</TouchableOpacity>
				<View style={styles.drawerMenuItemSeparator}/>
				<TouchableOpacity onPress={()=>this.refs.navigator.push({className: 'AddEarnerProfile', title: 'AddEarnerProfile'})}>
					<View style={styles.drawerMenuItemView}>
						<Image style={styles.drawerMenuItemImage} source={require('./app/img/navigation/nav_icon_menu.png')} />
						<Text style={styles.drawerMenuItemText}>Add Earner Page</Text>
					</View>
				</TouchableOpacity>
				<View style={styles.drawerMenuItemSeparator}/>
			</View>
		)
	}
	componentDidMount() {
		// Override Android back button. Return false if you want to default back to original behaviour, which usually exits the app.
		BackAndroid.addEventListener('hardwareBackPress', ()=>{
			if(this.refs.navigator) {
				if(this.refs.navigator.getCurrentRoutes().length > 1) {
					// Override Android back button to pop() only if you have more than 1 item in navigator stack
					this.refs.navigator.pop()
					return true
				} else {
					return false
				}
			} else {
				return false
			}
		})
	}
	_renderNavigationView() {
		let _this = this // We need to hold onto reference to 'this' as "this" gets overwritten inside the method
		const NavigationBarRouteMapper = {
			LeftButton(route, navigator, index, navState) {
        if(Platform.OS === 'ios' &&  index > 0) {
          return (
            <View style={{flexDirection:"row"}}>
              <View style={styles.navLeftIconView}>
                <TouchableOpacity onPress={navigator.pop} style={styles.navButton}>
                  <Image style={styles.navLeftIcon} source={require('./app/img/navigation/back_bar_icon.png')} />
                </TouchableOpacity>
              </View>
    					<View style={styles.navLeftIconView}>
    						<TouchableOpacity onPress={_this.toggleDrawerLayout.bind(_this)} style={styles.navButton}>
    							<Image style={styles.navLeftIcon} source={require('./app/img/navigation/nav_icon_menu.png')} />
    						</TouchableOpacity>
    					</View>
            </View>
          )
        }
				return (
					<View style={styles.navLeftIconView}>
						<TouchableOpacity onPress={_this.toggleDrawerLayout.bind(_this)} style={styles.navButton}>
							<Image style={styles.navLeftIcon} source={require('./app/img/navigation/nav_icon_menu.png')} />
						</TouchableOpacity>
          </View>
				)
			},
			RightButton(route, navigator, index, navState) {
				// Button on the right side of navigationView
			},
			Title(route, navigator, index, navState) {
				return (
					<View style={styles.navigationTitleView}>
						<Text style={styles.navigationTitleText}>
							{route.title}
						</Text>
					</View>
				)
			},
		}
		return (
			<Navigator initialRoute={{name: 'Login Page', index: 0}}
				ref='navigator'
				renderScene={this.renderPage}
				navigationBar={
					<Navigator.NavigationBar
						style={styles.navigationBar}
						routeMapper={NavigationBarRouteMapper} />
				}
			/>
		)
	}
	render() {
		if(Platform.OS === 'ios') {
			return (
				// Having black backgroundColor to match Android when opening drawerLayout
				<View style={{flex: 1}}>
					<Drawer
						type='overlay' // overlay or static. Make sure to change tweenHandler too.
						ref='drawer'
						content={this.renderMenuItems.bind(this)()}
						tapToClose={true} // Allow user to close drawer by tapping on the right side.
						captureGestures={true} // Disable taps on the buttons when drawer is open.
						openDrawerOffset={0.16} // 16% gap on the right side of drawer
						panOpenMask={-3} // Disable user from opening drawer layout by swiping. This is because of bug that when used with captureGesture={true}, navigation buttons also gets disabled.
						closedDrawerOffset={-3} // Putting -3 to hide the shadow on the left side of the window when drawer is closed.
						styles={{
							drawer: {shadowColor: '#000000', shadowOpacity: 0.8, shadowRadius: 3},
							main: {paddingLeft: 0}
						}}
						/*tweenHandler={Drawer.tweenPresets.parallax}*/
						tweenHandler={(ratio) => ({
							main: { opacity:(2-ratio)/2 }
						})}
						onOpen={()=>this.setState({isDrawerOpen: true})}
						onClose={()=>this.setState({isDrawerOpen: false})} >
						{this._renderNavigationView()}
					</Drawer>
				</View>
			)
		}	else {
			return (
				// Drawer component is really bad in Android (third party), so we are using DrawerLayoutAndroid which is much better
				<DrawerLayoutAndroid
					ref='drawer'
					drawerWidth={300}
					drawerPosition={DrawerLayoutAndroid.positions.Left}
					renderNavigationView={this.renderMenuItems.bind(this)}
					onDrawerOpen={()=>this.setState({isDrawerOpen: true})}
					onDrawerClose={()=>this.setState({isDrawerOpen: false})} >
					{this._renderNavigationView()}
				</DrawerLayoutAndroid>
			)
		}
	}
}

let styles = StyleSheet.create({
	navigationBar: {
		backgroundColor: '#46B7C7',
	},
	navLeftIconView: {
		flex:1,
		justifyContent: 'center',
	},
	navButton: {
		height: 44,
		width: 44,
		alignItems: 'center',
		justifyContent: 'center',
	},
	navLeftIcon: {
		// marginLeft: 10,
	},
	navigationTitleView: {
		flex:1,
		justifyContent: 'center',
	},
	navigationTitleText: {
		color: 'white',
		fontSize: 18,
		fontWeight: '500',
		fontStyle: 'italic',
		alignSelf: 'flex-end',
	},
	drawerLayoutView: {
		flex: 1,
		flexDirection: 'column',
		paddingTop: Platform.OS === 'ios' ? 26 : 16,
		backgroundColor: '#2D3E50',
	},
	drawerMenuItemView: {
		flexDirection: 'row',
		height: 48,
		alignItems: 'center',
	},
	drawerMenuItemSeparator: {
		height: 2 / PixelRatio.get(),
		borderColor: '#899BA5',
		borderBottomWidth: 1 / PixelRatio.get(),
	},
	drawerMenuItemImage: {
		marginLeft: 10,
		marginRight: 8,
		tintColor: '#E7F8FA',
		resizeMode: 'contain',
		height: 24,
		width: 22,
	},
	drawerMenuItemText: {
		color: '#E7F8FA',
	},
})

module.exports = Route
<commit_msg>changed the ip address back to original<commit_after>'use strict'

import React, {
  Component,
  StyleSheet,
  Navigator,
  Platform,
  View,
  Text,
  BackAndroid,
  TouchableOpacity,
  PixelRatio,
  Image,
  DrawerLayoutAndroid,
} from 'react-native'

import DDPClient from 'ddp-client';

import Login from './app/pages/Login'
import PageTwo from './app/pages/PageTwo'
import PageThree from './app/pages/PageThree'
import PageFour from './app/pages/PageFour'
import AddEarnerProfile from './app/pages/AddEarnerProfile'
const Page = {Login, PageTwo, PageThree, PageFour, AddEarnerProfile}

const Drawer = require('react-native-drawer') // Third party drawer layout that works in iOS, very funky so use with care

let ddpClient = new DDPClient({
  host: '172.18.146.36',
  // host: '192.168.1.3', // If using android use your device IP address
  port: '3000',
  // url: <your websocket url>
})

export default class Route extends Component {
	constructor(props) {
		super(props)
		this.state = {
			isDrawerOpen: false,
		}
	}
	_openDrawer() {
		if(Platform.OS === 'ios') {
			this.refs.drawer.open()
		} else {
			this.refs.drawer.openDrawer()
		}
	}
	_closeDrawer() {
		if(Platform.OS === 'ios') {
			this.refs.drawer.close()
		} else {
			this.refs.drawer.closeDrawer()
		}
	}
	toggleDrawerLayout(){
		if(this.state.isDrawerOpen) {
			this._closeDrawer.bind(this)()
		} else {
			this._openDrawer.bind(this)()
		}
	}
	// This gets called when you add new page into navigator stack (ie. navigator.push or navigator.replace)
	renderPage(route, navigator) {
		if(route.className) {
			return React.createElement(Page[route.className], {route, navigator, ddpClient})
		} else {
			route.title = ''
			return React.createElement(Page['PageTwo'], {route, navigator, ddpClient})
		}
	}
	drawerMenuItemPressed(alertPopupMessage) {
		this._closeDrawer()
		alert(alertPopupMessage)
		this.ddpClient.call('addPost')
	}
	renderMenuItems() {
		return (
			<View style={styles.drawerLayoutView}>
				<TouchableOpacity onPress={()=>alert('Do Something!')}>
					<View style={styles.drawerMenuItemView}>
						<Image style={styles.drawerMenuItemImage} source={require('./app/img/navigation/nav_icon_menu.png')} />
						<Text style={styles.drawerMenuItemText}>Do Something!</Text>
					</View>
				</TouchableOpacity>
				<View style={styles.drawerMenuItemSeparator}/>
				<TouchableOpacity onPress={this.drawerMenuItemPressed.bind(this, 'Do Something2!')}>
					<View style={styles.drawerMenuItemView}>
						<Image style={styles.drawerMenuItemImage} source={require('./app/img/navigation/nav_icon_menu.png')} />
						<Text style={styles.drawerMenuItemText}>Do Something2!</Text>
					</View>
				</TouchableOpacity>
				<View style={styles.drawerMenuItemSeparator}/>
				<TouchableOpacity onPress={()=>alert('Do Something3!')}>
					<View style={styles.drawerMenuItemView}>
						<Image style={styles.drawerMenuItemImage} source={require('./app/img/navigation/nav_icon_menu.png')} />
						<Text style={styles.drawerMenuItemText}>Do Something3!</Text>
					</View>
				</TouchableOpacity>
				<View style={styles.drawerMenuItemSeparator}/>
				<TouchableOpacity onPress={()=>this.refs.navigator.push({className: 'AddEarnerProfile', title: 'AddEarnerProfile'})}>
					<View style={styles.drawerMenuItemView}>
						<Image style={styles.drawerMenuItemImage} source={require('./app/img/navigation/nav_icon_menu.png')} />
						<Text style={styles.drawerMenuItemText}>Add Earner Page</Text>
					</View>
				</TouchableOpacity>
				<View style={styles.drawerMenuItemSeparator}/>
			</View>
		)
	}
	componentDidMount() {
		// Override Android back button. Return false if you want to default back to original behaviour, which usually exits the app.
		BackAndroid.addEventListener('hardwareBackPress', ()=>{
			if(this.refs.navigator) {
				if(this.refs.navigator.getCurrentRoutes().length > 1) {
					// Override Android back button to pop() only if you have more than 1 item in navigator stack
					this.refs.navigator.pop()
					return true
				} else {
					return false
				}
			} else {
				return false
			}
		})
	}
	_renderNavigationView() {
		let _this = this // We need to hold onto reference to 'this' as "this" gets overwritten inside the method
		const NavigationBarRouteMapper = {
			LeftButton(route, navigator, index, navState) {
        if(Platform.OS === 'ios' &&  index > 0) {
          return (
            <View style={{flexDirection:"row"}}>
              <View style={styles.navLeftIconView}>
                <TouchableOpacity onPress={navigator.pop} style={styles.navButton}>
                  <Image style={styles.navLeftIcon} source={require('./app/img/navigation/back_bar_icon.png')} />
                </TouchableOpacity>
              </View>
    					<View style={styles.navLeftIconView}>
    						<TouchableOpacity onPress={_this.toggleDrawerLayout.bind(_this)} style={styles.navButton}>
    							<Image style={styles.navLeftIcon} source={require('./app/img/navigation/nav_icon_menu.png')} />
    						</TouchableOpacity>
    					</View>
            </View>
          )
        }
				return (
					<View style={styles.navLeftIconView}>
						<TouchableOpacity onPress={_this.toggleDrawerLayout.bind(_this)} style={styles.navButton}>
							<Image style={styles.navLeftIcon} source={require('./app/img/navigation/nav_icon_menu.png')} />
						</TouchableOpacity>
          </View>
				)
			},
			RightButton(route, navigator, index, navState) {
				// Button on the right side of navigationView
			},
			Title(route, navigator, index, navState) {
				return (
					<View style={styles.navigationTitleView}>
						<Text style={styles.navigationTitleText}>
							{route.title}
						</Text>
					</View>
				)
			},
		}
		return (
			<Navigator initialRoute={{name: 'Login Page', index: 0}}
				ref='navigator'
				renderScene={this.renderPage}
				navigationBar={
					<Navigator.NavigationBar
						style={styles.navigationBar}
						routeMapper={NavigationBarRouteMapper} />
				}
			/>
		)
	}
	render() {
		if(Platform.OS === 'ios') {
			return (
				// Having black backgroundColor to match Android when opening drawerLayout
				<View style={{flex: 1}}>
					<Drawer
						type='overlay' // overlay or static. Make sure to change tweenHandler too.
						ref='drawer'
						content={this.renderMenuItems.bind(this)()}
						tapToClose={true} // Allow user to close drawer by tapping on the right side.
						captureGestures={true} // Disable taps on the buttons when drawer is open.
						openDrawerOffset={0.16} // 16% gap on the right side of drawer
						panOpenMask={-3} // Disable user from opening drawer layout by swiping. This is because of bug that when used with captureGesture={true}, navigation buttons also gets disabled.
						closedDrawerOffset={-3} // Putting -3 to hide the shadow on the left side of the window when drawer is closed.
						styles={{
							drawer: {shadowColor: '#000000', shadowOpacity: 0.8, shadowRadius: 3},
							main: {paddingLeft: 0}
						}}
						/*tweenHandler={Drawer.tweenPresets.parallax}*/
						tweenHandler={(ratio) => ({
							main: { opacity:(2-ratio)/2 }
						})}
						onOpen={()=>this.setState({isDrawerOpen: true})}
						onClose={()=>this.setState({isDrawerOpen: false})} >
						{this._renderNavigationView()}
					</Drawer>
				</View>
			)
		}	else {
			return (
				// Drawer component is really bad in Android (third party), so we are using DrawerLayoutAndroid which is much better
				<DrawerLayoutAndroid
					ref='drawer'
					drawerWidth={300}
					drawerPosition={DrawerLayoutAndroid.positions.Left}
					renderNavigationView={this.renderMenuItems.bind(this)}
					onDrawerOpen={()=>this.setState({isDrawerOpen: true})}
					onDrawerClose={()=>this.setState({isDrawerOpen: false})} >
					{this._renderNavigationView()}
				</DrawerLayoutAndroid>
			)
		}
	}
}

let styles = StyleSheet.create({
	navigationBar: {
		backgroundColor: '#46B7C7',
	},
	navLeftIconView: {
		flex:1,
		justifyContent: 'center',
	},
	navButton: {
		height: 44,
		width: 44,
		alignItems: 'center',
		justifyContent: 'center',
	},
	navLeftIcon: {
		// marginLeft: 10,
	},
	navigationTitleView: {
		flex:1,
		justifyContent: 'center',
	},
	navigationTitleText: {
		color: 'white',
		fontSize: 18,
		fontWeight: '500',
		fontStyle: 'italic',
		alignSelf: 'flex-end',
	},
	drawerLayoutView: {
		flex: 1,
		flexDirection: 'column',
		paddingTop: Platform.OS === 'ios' ? 26 : 16,
		backgroundColor: '#2D3E50',
	},
	drawerMenuItemView: {
		flexDirection: 'row',
		height: 48,
		alignItems: 'center',
	},
	drawerMenuItemSeparator: {
		height: 2 / PixelRatio.get(),
		borderColor: '#899BA5',
		borderBottomWidth: 1 / PixelRatio.get(),
	},
	drawerMenuItemImage: {
		marginLeft: 10,
		marginRight: 8,
		tintColor: '#E7F8FA',
		resizeMode: 'contain',
		height: 24,
		width: 22,
	},
	drawerMenuItemText: {
		color: '#E7F8FA',
	},
})

module.exports = Route
<|endoftext|>


<commit_before>var helpers = require('../helpers.js');
var Link = require('../../models/link.js');

// List links
exports.list = function (req, res) {
	var limit = Number(req.query.limit) || 10;
	var offset = Number(req.query.offset) || 0;
	var sortBy = req.query.sortBy || 'created';
	var sortOrder = Number(req.query.sortOrder) || -1;

	// Restrict limit range
	limit = Math.min(limit, 100);
	limit = Math.max(limit, 0);

	// Format and validate sort
	var sort = {};
	sort[sortBy] = sortOrder;
	// Only accept -1, 1
	if (!(sort[sortBy] in [-1, 1])) {
		sort[sortBy] = -1;
	}

	query = Link.find().sort(sort).skip(offset).limit(limit);
	query.exec(function (err, links) {
		if (err) { console.log(err); }
		res.send(links);
	});
};

// Get link by id
exports.details = function (req, res) {
	var id = req.params.linkId;

	Link.findById(id, function (err, link) {
		if (err) { console.log(err); }
		res.send(link);
	});
};

exports.create = function (req, res) {

	var tag = helpers.generateBase62(6);
	var destination = req.body.destination;

    var link = new Link({
        destination: destination,
        url: 'wrapulous.com', // Eventually we use cool mini domains
        tag: tag
    });

    link.save(function (err, link) {
        if (err) { console.log(err); }
        res.send(link);
    });
};

<commit_msg>query by tag<commit_after>var helpers = require('../helpers.js');
var Link = require('../../models/link.js');

// List links
exports.list = function (req, res) {
	var limit = Number(req.query.limit) || 10;
	var offset = Number(req.query.offset) || 0;
	var sortBy = req.query.sortBy || 'created';
	var sortOrder = Number(req.query.sortOrder) || -1;

	// Restrict limit range
	limit = Math.min(limit, 100);
	limit = Math.max(limit, 0);

	// Format and validate sort
	var sort = {};
	sort[sortBy] = sortOrder;
	// Only accept -1, 1
	if (!(sort[sortBy] in [-1, 1])) {
		sort[sortBy] = -1;
	}

	query = Link.find().sort(sort).skip(offset).limit(limit);
	query.exec(function (err, links) {
		if (err) { console.log(err); }
		res.send(links);
	});
};

// Get link by id
exports.details = function (req, res) {
	var id = req.params.linkId;

	Link.findOne({tag: id}, function (err, link) {
		if (err) { console.log(err); }
		res.send(link);
	});
};

exports.create = function (req, res) {

	var tag = helpers.generateBase62(6);
	var destination = req.body.destination;

    var link = new Link({
        destination: destination,
        url: 'wrpls.com',
        tag: tag
    });

    link.save(function (err, link) {
        if (err) { console.log(err); }
        res.send(link);
    });
};

<|endoftext|>


<commit_before>/**
 * Created by Andrew on 11/6/2014.
 */

// Library for computing the sha1 hash
var crypto = require('crypto');
// Library for synchronously executing a shell command (because child_process.exec is asynchronous which sucks for this application)
var sh = require('execSync');

/**
 * POST /webhook
 * Update the repo
 */

exports.webhook = function(req, res) {

    // JSON payload from Github
    var jsonPayload= req.body;

    // Read the signature header that contains the sha1 hash from Github
    reqGithubHash = req.header('X-Hub-Signature');

    // Define secret (specified on Github) and stringify the payload to use for the SHA1 HMAC Hex Digest function
    var secret = 'Every. Single. Night.';
    var data = JSON.stringify(jsonPayload);

    // Compute the hash using the secret as the key, and the payload as the data to hash
    var computedHash = crypto.createHmac('sha1', secret).update(data).digest('hex');
    computedHash = "sha1=" + computedHash;

    // Compare the two hashes to see if the secrets matched
    if (reqGithubHash == computedHash) {

        // This makes sure that a push to the master branch will update the server (This can obviously be changed)
        if (jsonPayload.ref == "refs/heads/master") {

            // Execute the shell command
            var code = sh.run('cd /var/www && git pull');
            console.log('return code ' + code);

            // Tell Github that everything went peachy
            res.status(200).send("Local repository updated!");
        }
        else {
            // If the branch is not master, tell Github, but still send a 200 status
            res.status(200).send("Local repository not updated! The master branch was not changed.");
        }
    }
    // If the secrets didn't match, then send a '403 Forbidden' response
    else {
        res.status(403).send("Secrets do not match.");
    }
};

/**
 * GET /webhook
 * This is not a GET URL
 * If someone tries to GET this page,
 * Just tell them there's nothing here for them
 */

exports.index = function (req, res) {
    res.status(200).send("This URL is used for webhooks and webhooks only!");
};<commit_msg>OMG WEBHOOK ACTUALLY WORKS (revert commit)<commit_after>/**
 * Created by Andrew on 11/6/2014.
 */

// Library for computing the sha1 hash
var crypto = require('crypto');
// Library for synchronously executing a shell command (because child_process.exec is asynchronous which sucks for this application)
var sh = require('execSync');

/**
 * POST /webhook
 * Update the repo
 */

exports.webhook = function(req, res) {

    // JSON payload sent from Github
    var jsonPayload= req.body;

    // Read the signature header that contains the sha1 hash from Github
    var reqGithubHash = req.header('X-Hub-Signature');

    // Define secret (specified on Github) and stringify the payload to use for the SHA1 HMAC Hex Digest function
    var secret = 'Every. Single. Night.';
    var data = JSON.stringify(jsonPayload);

    // Compute the hash using the secret as the key, and the payload as the data to hash
    var computedHash = crypto.createHmac('sha1', secret).update(data).digest('hex');
    computedHash = "sha1=" + computedHash;

    // Compare the two hashes to see if the secrets matched
    if (reqGithubHash == computedHash) {

        // This makes sure that a push to the master branch will update the server (This can obviously be changed)
        if (jsonPayload.ref == "refs/heads/master") {

            // Execute the shell command
            var code = sh.run('cd /var/www && git pull');
            console.log('return code ' + code);

            // Tell Github that everything went peachy
            res.status(200).send("Local repository updated!");
        }
        else {
            // If the branch is not master, tell Github, but still send a 200 status
            res.status(200).send("Local repository not updated! The master branch was not changed.");
        }
    }
    // If the secrets didn't match, then send a '403 Forbidden' response
    else {
        res.status(403).send("Secrets do not match.");
    }
};

/**
 * GET /webhook
 * This is not a GET URL
 * If someone tries to GET this page,
 * Just tell them there's nothing here for them
 */

exports.index = function (req, res) {
    res.status(200).send("This URL is used for webhooks and webhooks only!");
};<|endoftext|>


<commit_before>/**
 * Created by Andrew on 11/6/2014.
 */

var sha1 = require('sha1');

/**
 * POST /webhook
 * Update the repo
 */

exports.webhook = function(req, res) {
    var jsonPayload = req.body;
    res.status(200).send(jsonPayload);
};

/**
 * GET /webhook
 * Tell people that this is the webhook stuff
 */

exports.index = function (req, res) {
    var jsonResponse = {
        object1: "sometext1",
        object2: "sometext2",
        object3: "sometext3"
    };
    res.json(jsonResponse);
};<commit_msg>testing jsonPayload.ref console.log<commit_after>/**
 * Created by Andrew on 11/6/2014.
 */

var sha1 = require('sha1');

/**
 * POST /webhook
 * Update the repo
 */

exports.webhook = function(req, res) {
    var jsonPayload = req.body;
    console.log(jsonPayload.ref);
    res.status(200).send(jsonPayload);
};

/**
 * GET /webhook
 * Tell people that this is the webhook stuff
 */

exports.index = function (req, res) {
    var jsonResponse = {
        object1: "sometext1",
        object2: "sometext2",
        object3: "sometext3"
    };
    res.json(jsonResponse);
};<|endoftext|>


<commit_before>/*jshint latedef:nofunc */
'use strict';

var poem = require('substance/test/fixtures/collab/poem');
var MessageQueue = require('substance/util/MessageQueue');
var WebSocketServer = require('substance/util/WebSocketServer');
var WebSocket = require('substance/util/WebSocket');
var CollabSession = require('substance/model/CollabSession');
var Icon = require('substance/ui/FontAwesomeIcon');
var StubHub = require('substance/util/StubHub');
var TestStore = require('substance/util/TestStore');
var Component = require('substance/ui/Component');
var SplitPane = require('substance/ui/SplitPane');
var ProseEditor = require('substance/packages/prose-editor/ProseEditor');
var Article = require('substance/packages/prose-editor/ProseArticle');
var $$ = Component.$$;

window.onload = function() {
  var debug = (window.location.hash === '#debug');
  window.app = TwoEditors.static.mount({
    debug: debug
  }, 'body');
};

function TwoEditors() {
  TwoEditors.super.apply(this, arguments);

  var fixture = require('substance/test/fixtures/collab/two-paragraphs');
  // var fixture = poem;

  // Two edited docs, one doc instance on the hub all with the same contents,
  // now we start synchronizing them.
  this.doc1 = new Article();
  this.doc2 = new Article();
  this.store = new TestStore({
    'test': fixture.createChangeset()
  });

  this.messageQueue = new MessageQueue();
  this.wss = new WebSocketServer(this.messageQueue, 'hub');
  this.ws1 = new WebSocket(this.messageQueue, 'user1', 'hub');
  this.ws2 = new WebSocket(this.messageQueue, 'user2', 'hub');

  this.hub = new StubHub(this.wss, this.store);
  this.session1 = new CollabSession(this.doc1, this.ws1, {
    docId: 'test',
    docVersion: 0
  });
  this.session2 = new CollabSession(this.doc2, this.ws2, {
    docId: 'test',
    docVersion: 0
  });

  this._debug = this.props.debug;

  this.handleActions({
    'toggleDebug': this._toggleDebug,
    'processNextMessage': this._processNextMessage,
    'commit': this._onCommit
  });

  // let WebSocket react on message queue
  this.wss.connect();

  // Note: when we connect a client's socket,
  // the server will confirm the connection, which triggers
  // CollabSession._onConnected automatically, which then
  // start to talk the CollabHub prototocol
  // i.e., starting to send ['open', docId, version]
  this.ws1.connect();
  // also estabslish the connection for the second user
  this.ws2.connect();

  if (this._debug) {
    this.session1.stop();
    this.session2.stop();
    // flush initial handshake messages
    this.messageQueue.flush();
  } else {
    this.messageQueue.flush();
    this.messageQueue.start();
  }
}

TwoEditors.Prototype = function() {

  this.render = function() {
    var el = $$('div').addClass('sc-two-editors');
    var statusEl = $$(Status, {
      messageQueue: this.messageQueue,
      debug: this._debug
    }).ref('statusEl').ref('status');

    var leftEditor = $$(ProseEditor, {
      documentSession: this.session1
    }).ref('left').addClass('left-editor');

    var rightEditor = $$(ProseEditor, {
      documentSession: this.session2
    }).ref('right').addClass('right-editor');

    if (this._debug) {
      leftEditor.outlet('tools').append(
        $$(CommitTool, { session: this.session1 })
      );
      rightEditor.outlet('tools').append(
        $$(CommitTool, { session: this.session2 })
      );
    }

    el.append(
      $$(SplitPane, {splitType: 'horizontal', sizeB: 'inherit'}).append(
        $$(SplitPane, {
          splitType: 'vertical',
          sizeA: '50%'
        }).append(
          leftEditor,
          rightEditor
        ),
        statusEl
      )
    );
    return el;
  };

  this._toggleDebug = function() {
    if (!this._debug) {
      this.messageQueue.stop();
      this.session1.stop();
      this.session2.stop();
    } else {
      this.messageQueue.start();
      this.session1.start();
      this.session2.start();
    }
    this._debug = !this._debug;
    this.rerender();
  };

  this._processNextMessage = function() {
    this.messageQueue.tick();
  };

  this._onCommit = function(evt) {
    console.log('Commit');
    evt.stopPropagation();
  };

};

Component.extend(TwoEditors);

function Status() {
  Status.super.apply(this, arguments);
}

Status.Prototype = function() {

  this.didMount = function() {
    this.props.messageQueue.connect(this, {
      'messages:updated': this._onMessagesUpdated
    });
  };

  this.dispose = function() {
    this.props.messageQueue.disconnect(this);
  };

  this.render = function() {
    var statusEl = $$('div').addClass('se-status');

    if (this.props.debug) {
      statusEl.append(
        $$('div').addClass('se-left').append(
          this.props.messageQueue.messages.length+' messages in the air ',
          $$('button').addClass('se-next-message')
            .append($$(Icon, {icon: 'fa-step-forward'})).on('click', this._processNextMessage),
          $$('button').addClass('se-dump-messages')
            .append($$(Icon, {icon: 'fa-tasks'}))
            .attr({ title: 'Dump MessageQueue'})
            .on('click', this._dumpMessageQueue)
        ),
        $$('div').addClass('se-right').append(
          $$('button').addClass('se-debug')
            .append($$(Icon, {icon: 'fa-toggle-off'}), ' Network')
            .on('click', this._toggleDebug)
        )
      );
    } else {
      statusEl.append(
        $$('div').addClass('se-left').append(
          this.props.messageQueue.messages.length+' messages in the air '
        ),
        $$('div').addClass('se-right').append(
          $$('button').addClass('se-debug')
            .append($$(Icon, {icon: 'fa-toggle-on'}), ' Network')
            .on('click', this._toggleDebug)
        )
      );
    }
    return statusEl;
  };

  this._onMessagesUpdated = function(/*messages*/) {
    this.rerender();
  };

  this._toggleDebug = function() {
    this.send('toggleDebug');
  };

  this._processNextMessage = function() {
    this.send('processNextMessage');
  };

  this._dumpMessageQueue = function() {
    // console.log(this.props.messageQueue.messages);
    console.log(JSON.stringify(this.props.messageQueue.messages, null, 2));
  };

};

function CommitTool() {
  CommitTool.super.apply(this, arguments);
}

CommitTool.Prototype = function() {

  this.didMount = function() {
    this.doc = this.props.session.getDocument();
    this.doc.connect(this, {
      'document:changed': this.afterDocumentChange
    }, { priority: -10 });
  };

  this.dispose = function() {
    this.doc.disconnect(this);
  };

  this.render = function() {
    var el = $$('div')
      .attr('title', 'Commit')
      .addClass('se-tool')
      .append(
        $$('button')
          .append($$(Icon, {icon: 'fa-send'}))
          .on('click', this.onClick)
    );
    if (this.state.disabled) {
      el.addClass('sm-disabled');
    }
    return el;
  };

  this.getInitialState = function() {
    return {
      disabled: !this.props.session.nextCommit
    };
  };

  this.afterDocumentChange = function() {
    var newState = {};
    newState.visible = !!this.props._runner;
    newState.disabled = !this.props.session.nextCommit;
    this.setState(newState);
  };

  this.onClick = function() {
    this.props.session.commit();
    this.afterDocumentChange();
  };

};

Component.extend(CommitTool);

Component.extend(Status);
<commit_msg>Use StubCollabSession.<commit_after>/*jshint latedef:nofunc */
'use strict';

var poem = require('substance/test/fixtures/collab/poem');
var MessageQueue = require('substance/util/MessageQueue');
var WebSocketServer = require('substance/util/WebSocketServer');
var WebSocket = require('substance/util/WebSocket');
var CollabSession = require('substance/model/StubCollabSession');
var Icon = require('substance/ui/FontAwesomeIcon');
var StubHub = require('substance/util/StubHub');
var TestStore = require('substance/util/TestStore');
var Component = require('substance/ui/Component');
var SplitPane = require('substance/ui/SplitPane');
var ProseEditor = require('substance/packages/prose-editor/ProseEditor');
var Article = require('substance/packages/prose-editor/ProseArticle');
var $$ = Component.$$;

window.onload = function() {
  var debug = (window.location.hash === '#debug');
  window.app = TwoEditors.static.mount({
    debug: debug
  }, 'body');
};

function TwoEditors() {
  TwoEditors.super.apply(this, arguments);

  var fixture = require('substance/test/fixtures/collab/two-paragraphs');
  // var fixture = poem;

  // Two edited docs, one doc instance on the hub all with the same contents,
  // now we start synchronizing them.
  this.doc1 = new Article();
  this.doc2 = new Article();
  this.store = new TestStore({
    'test': fixture.createChangeset()
  });

  this.messageQueue = new MessageQueue();
  this.wss = new WebSocketServer(this.messageQueue, 'hub');
  this.ws1 = new WebSocket(this.messageQueue, 'user1', 'hub');
  this.ws2 = new WebSocket(this.messageQueue, 'user2', 'hub');

  this.hub = new StubHub(this.wss, this.store);
  this.session1 = new CollabSession(this.doc1, this.ws1, {
    docId: 'test',
    docVersion: 0
  });
  this.session2 = new CollabSession(this.doc2, this.ws2, {
    docId: 'test',
    docVersion: 0
  });

  this._debug = this.props.debug;

  this.handleActions({
    'toggleDebug': this._toggleDebug,
    'processNextMessage': this._processNextMessage,
    'commit': this._onCommit
  });

  // let WebSocket react on message queue
  this.wss.connect();

  // Note: when we connect a client's socket,
  // the server will confirm the connection, which triggers
  // CollabSession._onConnected automatically, which then
  // start to talk the CollabHub prototocol
  // i.e., starting to send ['open', docId, version]
  this.ws1.connect();
  // also estabslish the connection for the second user
  this.ws2.connect();

  if (this._debug) {
    this.session1.stop();
    this.session2.stop();
    // flush initial handshake messages
    this.messageQueue.flush();
  } else {
    this.messageQueue.flush();
    this.messageQueue.start();
  }
}

TwoEditors.Prototype = function() {

  this.render = function() {
    var el = $$('div').addClass('sc-two-editors');
    var statusEl = $$(Status, {
      messageQueue: this.messageQueue,
      debug: this._debug
    }).ref('statusEl').ref('status');

    var leftEditor = $$(ProseEditor, {
      documentSession: this.session1
    }).ref('left').addClass('left-editor');

    var rightEditor = $$(ProseEditor, {
      documentSession: this.session2
    }).ref('right').addClass('right-editor');

    if (this._debug) {
      leftEditor.outlet('tools').append(
        $$(CommitTool, { session: this.session1 })
      );
      rightEditor.outlet('tools').append(
        $$(CommitTool, { session: this.session2 })
      );
    }

    el.append(
      $$(SplitPane, {splitType: 'horizontal', sizeB: 'inherit'}).append(
        $$(SplitPane, {
          splitType: 'vertical',
          sizeA: '50%'
        }).append(
          leftEditor,
          rightEditor
        ),
        statusEl
      )
    );
    return el;
  };

  this._toggleDebug = function() {
    if (!this._debug) {
      this.messageQueue.stop();
      this.session1.stop();
      this.session2.stop();
    } else {
      this.messageQueue.start();
      this.session1.start();
      this.session2.start();
    }
    this._debug = !this._debug;
    this.rerender();
  };

  this._processNextMessage = function() {
    this.messageQueue.tick();
  };

  this._onCommit = function(evt) {
    console.log('Commit');
    evt.stopPropagation();
  };

};

Component.extend(TwoEditors);

function Status() {
  Status.super.apply(this, arguments);
}

Status.Prototype = function() {

  this.didMount = function() {
    this.props.messageQueue.connect(this, {
      'messages:updated': this._onMessagesUpdated
    });
  };

  this.dispose = function() {
    this.props.messageQueue.disconnect(this);
  };

  this.render = function() {
    var statusEl = $$('div').addClass('se-status');

    if (this.props.debug) {
      statusEl.append(
        $$('div').addClass('se-left').append(
          this.props.messageQueue.messages.length+' messages in the air ',
          $$('button').addClass('se-next-message')
            .append($$(Icon, {icon: 'fa-step-forward'})).on('click', this._processNextMessage),
          $$('button').addClass('se-dump-messages')
            .append($$(Icon, {icon: 'fa-tasks'}))
            .attr({ title: 'Dump MessageQueue'})
            .on('click', this._dumpMessageQueue)
        ),
        $$('div').addClass('se-right').append(
          $$('button').addClass('se-debug')
            .append($$(Icon, {icon: 'fa-toggle-off'}), ' Network')
            .on('click', this._toggleDebug)
        )
      );
    } else {
      statusEl.append(
        $$('div').addClass('se-left').append(
          this.props.messageQueue.messages.length+' messages in the air '
        ),
        $$('div').addClass('se-right').append(
          $$('button').addClass('se-debug')
            .append($$(Icon, {icon: 'fa-toggle-on'}), ' Network')
            .on('click', this._toggleDebug)
        )
      );
    }
    return statusEl;
  };

  this._onMessagesUpdated = function(/*messages*/) {
    this.rerender();
  };

  this._toggleDebug = function() {
    this.send('toggleDebug');
  };

  this._processNextMessage = function() {
    this.send('processNextMessage');
  };

  this._dumpMessageQueue = function() {
    // console.log(this.props.messageQueue.messages);
    console.log(JSON.stringify(this.props.messageQueue.messages, null, 2));
  };

};

function CommitTool() {
  CommitTool.super.apply(this, arguments);
}

CommitTool.Prototype = function() {

  this.didMount = function() {
    this.doc = this.props.session.getDocument();
    this.doc.connect(this, {
      'document:changed': this.afterDocumentChange
    }, { priority: -10 });
  };

  this.dispose = function() {
    this.doc.disconnect(this);
  };

  this.render = function() {
    var el = $$('div')
      .attr('title', 'Commit')
      .addClass('se-tool')
      .append(
        $$('button')
          .append($$(Icon, {icon: 'fa-send'}))
          .on('click', this.onClick)
    );
    if (this.state.disabled) {
      el.addClass('sm-disabled');
    }
    return el;
  };

  this.getInitialState = function() {
    return {
      disabled: !this.props.session.nextCommit
    };
  };

  this.afterDocumentChange = function() {
    var newState = {};
    newState.visible = !!this.props._runner;
    newState.disabled = !this.props.session.nextCommit;
    this.setState(newState);
  };

  this.onClick = function() {
    this.props.session.commit();
    this.afterDocumentChange();
  };

};

Component.extend(CommitTool);

Component.extend(Status);
<|endoftext|>


<commit_before>/* global Package Meteor Mongo LocalCollection CollectionHooks _ EJSON */
/* eslint-disable no-proto, no-native-reassign */

// Relevant AOP terminology:
// Aspect: User code that runs before/after (hook)
// Advice: Wrapper code that knows when to call user code (aspects)
// Pointcut: before/after

var advices = {}
var Tracker = Package.tracker && Package.tracker.Tracker || Package.deps.Deps
var publishUserId = Meteor.isServer && new Meteor.EnvironmentVariable()

CollectionHooks = {
  defaults: {
    before: { insert: {}, update: {}, remove: {}, upsert: {}, find: {}, findOne: {}, all: {} },
    after: { insert: {}, update: {}, remove: {}, find: {}, findOne: {}, all: {} },
    all: { insert: {}, update: {}, remove: {}, find: {}, findOne: {}, all: {} }
  },
  directEnv: new Meteor.EnvironmentVariable(),
  directOp: function directOp(func) {
    return this.directEnv.withValue(true, func)
  },
  hookedOp: function hookedOp(func) {
    return this.directEnv.withValue(false, func)
  }
}

CollectionHooks.getUserId = function getUserId() {
  var userId = CollectionHooks.defaultUserId

  if (Meteor.isClient) {
    Tracker.nonreactive(function () {
      userId = Meteor.userId && Meteor.userId()
    })
  }

  if (Meteor.isServer) {
    try {
      // Will throw an error unless within method call.
      // Attempt to recover gracefully by catching:
      userId = Meteor.userId && Meteor.userId()
    } catch (e) { }

    if (!userId) {
      // Get the userId if we are in a publish function.
      userId = publishUserId.get()
    }
  }

  return userId
}

CollectionHooks.extendCollectionInstance = function extendCollectionInstance(self, constructor) {
  // Offer a public API to allow the user to define aspects
  // Example: collection.before.insert(func);
  _.each(['before', 'after'], function (pointcut) {
    _.each(advices, function (advice, method) {
      if (advice === 'upsert' && pointcut === 'after') return

      Meteor._ensure(self, pointcut, method)
      Meteor._ensure(self, '_hookAspects', method)

      self._hookAspects[method][pointcut] = []
      self[pointcut][method] = function (aspect, options) {
        var len = self._hookAspects[method][pointcut].push({
          aspect: aspect,
          options: CollectionHooks.initOptions(options, pointcut, method)
        })

        return {
          replace: function (aspect, options) {
            self._hookAspects[method][pointcut].splice(len - 1, 1, {
              aspect: aspect,
              options: CollectionHooks.initOptions(options, pointcut, method)
            })
          },
          remove: function () {
            self._hookAspects[method][pointcut].splice(len - 1, 1)
          }
        }
      }
    })
  })

  // Offer a publicly accessible object to allow the user to define
  // collection-wide hook options.
  // Example: collection.hookOptions.after.update = {fetchPrevious: false};
  self.hookOptions = EJSON.clone(CollectionHooks.defaults)

  // Wrap mutator methods, letting the defined advice do the work
  _.each(advices, function (advice, method) {
    var collection = Meteor.isClient || method === 'upsert' ? self : self._collection

    // Store a reference to the original mutator method
    var _super = collection[method]

    Meteor._ensure(self, 'direct', method)
    self.direct[method] = function () {
      var args = arguments
      return CollectionHooks.directOp(function () {
        return constructor.prototype[method].apply(self, args)
      })
    }

    collection[method] = function () {
      if (CollectionHooks.directEnv.get() === true) {
        return _super.apply(collection, arguments)
      }

      // NOTE: should we decide to force `update` with `{upsert:true}` to use
      // the `upsert` hooks, this is what will accomplish it. It's important to
      // realize that Meteor won't distinguish between an `update` and an
      // `insert` though, so we'll end up with `after.update` getting called
      // even on an `insert`. That's why we've chosen to disable this for now.
      // if (method === "update" && _.isObject(arguments[2]) && arguments[2].upsert) {
      //   method = "upsert";
      //   advice = CollectionHooks.getAdvice(method);
      // }

      return advice.call(this,
        CollectionHooks.getUserId(),
        _super,
        self,
        method === 'upsert' ? {
          insert: self._hookAspects.insert || {},
          update: self._hookAspects.update || {},
          upsert: self._hookAspects.upsert || {}
        } : self._hookAspects[method] || {},
        function (doc) {
          return (
            _.isFunction(self._transform)
              ? function (d) { return self._transform(d || doc) }
              : function (d) { return d || doc }
          )
        },
        _.toArray(arguments),
        false
      )
    }
  })
}

CollectionHooks.defineAdvice = function defineAdvice(method, advice) {
  advices[method] = advice
}

CollectionHooks.getAdvice = function getAdvice(method) {
  return advices[method]
}

CollectionHooks.initOptions = function initOptions(options, pointcut, method) {
  return CollectionHooks.extendOptions(CollectionHooks.defaults, options, pointcut, method)
}

CollectionHooks.extendOptions = function extendOptions(source, options, pointcut, method) {
  options = _.extend(options || {}, source.all.all)
  options = _.extend(options, source[pointcut].all)
  options = _.extend(options, source.all[method])
  options = _.extend(options, source[pointcut][method])
  return options
}

CollectionHooks.getDocs = function getDocs(collection, selector, options) {
  var findOptions = { transform: null, reactive: false } // added reactive: false

  /*
  // No "fetch" support at this time.
  if (!this._validators.fetchAllFields) {
    findOptions.fields = {};
    _.each(this._validators.fetch, function(fieldName) {
      findOptions.fields[fieldName] = 1;
    });
  }
  */

  // Bit of a magic condition here... only "update" passes options, so this is
  // only relevant to when update calls getDocs:
  if (options) {
    // This was added because in our case, we are potentially iterating over
    // multiple docs. If multi isn't enabled, force a limit (almost like
    // findOne), as the default for update without multi enabled is to affect
    // only the first matched document:
    if (!options.multi) {
      findOptions.limit = 1
    }

    _.extend(findOptions, _.omit(options, 'multi', 'upsert'))
  }

  // Unlike validators, we iterate over multiple docs, so use
  // find instead of findOne:
  return collection.find(selector, findOptions)
}

// This function normalizes the selector (converting it to an Object)
CollectionHooks.normalizeSelector = function (selector) {
  if (typeof selector === 'string' || selector.constructor === Mongo.ObjectID) {
    return {
      _id: selector
    }
  } else {
    return selector
  }
}

// This function contains a snippet of code pulled and modified from:
// ~/.meteor/packages/mongo-livedata/collection.js
// It's contained in these utility functions to make updates easier for us in
// case this code changes.
CollectionHooks.getFields = function getFields(mutator) {
  // compute modified fields
  var fields = []
  // ====ADDED START=======================
  var operators = [
    '$addToSet',
    '$bit',
    '$currentDate',
    '$inc',
    '$max',
    '$min',
    '$pop',
    '$pull',
    '$pullAll',
    '$push',
    '$rename',
    '$set',
    '$unset'
  ]
  // ====ADDED END=========================

  _.each(mutator, function (params, op) {
    // ====ADDED START=======================
    if (_.contains(operators, op)) {
      // ====ADDED END=========================
      _.each(_.keys(params), function (field) {
        // treat dotted fields as if they are replacing their
        // top-level part
        if (field.indexOf('.') !== -1) {
          field = field.substring(0, field.indexOf('.'))
        }

        // record the field we are trying to change
        if (!_.contains(fields, field)) {
          fields.push(field)
        }
      })
      // ====ADDED START=======================
    } else {
      fields.push(op)
    }
    // ====ADDED END=========================
  })

  return fields
}

CollectionHooks.reassignPrototype = function reassignPrototype(instance, constr) {
  var hasSetPrototypeOf = typeof Object.setPrototypeOf === 'function'

  if (!constr) constr = typeof Mongo !== 'undefined' ? Mongo.Collection : Meteor.Collection

  // __proto__ is not available in < IE11
  // Note: Assigning a prototype dynamically has performance implications
  if (hasSetPrototypeOf) {
    Object.setPrototypeOf(instance, constr.prototype)
  } else if (instance.__proto__) {
    instance.__proto__ = constr.prototype
  }
}

CollectionHooks.wrapCollection = function wrapCollection(ns, as) {
  if (!as._CollectionConstructor) as._CollectionConstructor = as.Collection
  if (!as._CollectionPrototype) as._CollectionPrototype = new as.Collection(null)

  var constructor = as._CollectionConstructor
  var proto = as._CollectionPrototype

  ns.Collection = function () {
    var ret = constructor.apply(this, arguments)
    CollectionHooks.extendCollectionInstance(this, constructor)
    return ret
  }

  ns.Collection.prototype = proto
  ns.Collection.prototype.constructor = ns.Collection

  for (var prop in constructor) {
    if (constructor.hasOwnProperty(prop)) {
      ns.Collection[prop] = constructor[prop]
    }
  }
}

CollectionHooks.modify = LocalCollection._modify

if (typeof Mongo !== 'undefined') {
  CollectionHooks.wrapCollection(Meteor, Mongo)
  CollectionHooks.wrapCollection(Mongo, Mongo)
} else {
  CollectionHooks.wrapCollection(Meteor, Meteor)
}

if (Meteor.isServer) {
  var _publish = Meteor.publish
  Meteor.publish = function (name, handler, options) {
    return _publish.call(this, name, function () {
      // This function is called repeatedly in publications
      var ctx = this
      var args = arguments
      return publishUserId.withValue(ctx && ctx.userId, function () {
        return handler.apply(ctx, args)
      })
    }, options)
  }

  // Make the above available for packages with hooks that want to determine
  // whether they are running inside a publish function or not.
  CollectionHooks.isWithinPublish = function isWithinPublish() {
    return publishUserId.get() !== undefined
  }
}
<commit_msg>fix-selector: Fixed bug<commit_after>/* global Package Meteor Mongo LocalCollection CollectionHooks _ EJSON */
/* eslint-disable no-proto, no-native-reassign */

// Relevant AOP terminology:
// Aspect: User code that runs before/after (hook)
// Advice: Wrapper code that knows when to call user code (aspects)
// Pointcut: before/after

var advices = {}
var Tracker = Package.tracker && Package.tracker.Tracker || Package.deps.Deps
var publishUserId = Meteor.isServer && new Meteor.EnvironmentVariable()

CollectionHooks = {
  defaults: {
    before: { insert: {}, update: {}, remove: {}, upsert: {}, find: {}, findOne: {}, all: {} },
    after: { insert: {}, update: {}, remove: {}, find: {}, findOne: {}, all: {} },
    all: { insert: {}, update: {}, remove: {}, find: {}, findOne: {}, all: {} }
  },
  directEnv: new Meteor.EnvironmentVariable(),
  directOp: function directOp(func) {
    return this.directEnv.withValue(true, func)
  },
  hookedOp: function hookedOp(func) {
    return this.directEnv.withValue(false, func)
  }
}

CollectionHooks.getUserId = function getUserId() {
  var userId = CollectionHooks.defaultUserId

  if (Meteor.isClient) {
    Tracker.nonreactive(function () {
      userId = Meteor.userId && Meteor.userId()
    })
  }

  if (Meteor.isServer) {
    try {
      // Will throw an error unless within method call.
      // Attempt to recover gracefully by catching:
      userId = Meteor.userId && Meteor.userId()
    } catch (e) { }

    if (!userId) {
      // Get the userId if we are in a publish function.
      userId = publishUserId.get()
    }
  }

  return userId
}

CollectionHooks.extendCollectionInstance = function extendCollectionInstance(self, constructor) {
  // Offer a public API to allow the user to define aspects
  // Example: collection.before.insert(func);
  _.each(['before', 'after'], function (pointcut) {
    _.each(advices, function (advice, method) {
      if (advice === 'upsert' && pointcut === 'after') return

      Meteor._ensure(self, pointcut, method)
      Meteor._ensure(self, '_hookAspects', method)

      self._hookAspects[method][pointcut] = []
      self[pointcut][method] = function (aspect, options) {
        var len = self._hookAspects[method][pointcut].push({
          aspect: aspect,
          options: CollectionHooks.initOptions(options, pointcut, method)
        })

        return {
          replace: function (aspect, options) {
            self._hookAspects[method][pointcut].splice(len - 1, 1, {
              aspect: aspect,
              options: CollectionHooks.initOptions(options, pointcut, method)
            })
          },
          remove: function () {
            self._hookAspects[method][pointcut].splice(len - 1, 1)
          }
        }
      }
    })
  })

  // Offer a publicly accessible object to allow the user to define
  // collection-wide hook options.
  // Example: collection.hookOptions.after.update = {fetchPrevious: false};
  self.hookOptions = EJSON.clone(CollectionHooks.defaults)

  // Wrap mutator methods, letting the defined advice do the work
  _.each(advices, function (advice, method) {
    var collection = Meteor.isClient || method === 'upsert' ? self : self._collection

    // Store a reference to the original mutator method
    var _super = collection[method]

    Meteor._ensure(self, 'direct', method)
    self.direct[method] = function () {
      var args = arguments
      return CollectionHooks.directOp(function () {
        return constructor.prototype[method].apply(self, args)
      })
    }

    collection[method] = function () {
      if (CollectionHooks.directEnv.get() === true) {
        return _super.apply(collection, arguments)
      }

      // NOTE: should we decide to force `update` with `{upsert:true}` to use
      // the `upsert` hooks, this is what will accomplish it. It's important to
      // realize that Meteor won't distinguish between an `update` and an
      // `insert` though, so we'll end up with `after.update` getting called
      // even on an `insert`. That's why we've chosen to disable this for now.
      // if (method === "update" && _.isObject(arguments[2]) && arguments[2].upsert) {
      //   method = "upsert";
      //   advice = CollectionHooks.getAdvice(method);
      // }

      return advice.call(this,
        CollectionHooks.getUserId(),
        _super,
        self,
        method === 'upsert' ? {
          insert: self._hookAspects.insert || {},
          update: self._hookAspects.update || {},
          upsert: self._hookAspects.upsert || {}
        } : self._hookAspects[method] || {},
        function (doc) {
          return (
            _.isFunction(self._transform)
              ? function (d) { return self._transform(d || doc) }
              : function (d) { return d || doc }
          )
        },
        _.toArray(arguments),
        false
      )
    }
  })
}

CollectionHooks.defineAdvice = function defineAdvice(method, advice) {
  advices[method] = advice
}

CollectionHooks.getAdvice = function getAdvice(method) {
  return advices[method]
}

CollectionHooks.initOptions = function initOptions(options, pointcut, method) {
  return CollectionHooks.extendOptions(CollectionHooks.defaults, options, pointcut, method)
}

CollectionHooks.extendOptions = function extendOptions(source, options, pointcut, method) {
  options = _.extend(options || {}, source.all.all)
  options = _.extend(options, source[pointcut].all)
  options = _.extend(options, source.all[method])
  options = _.extend(options, source[pointcut][method])
  return options
}

CollectionHooks.getDocs = function getDocs(collection, selector, options) {
  var findOptions = { transform: null, reactive: false } // added reactive: false

  /*
  // No "fetch" support at this time.
  if (!this._validators.fetchAllFields) {
    findOptions.fields = {};
    _.each(this._validators.fetch, function(fieldName) {
      findOptions.fields[fieldName] = 1;
    });
  }
  */

  // Bit of a magic condition here... only "update" passes options, so this is
  // only relevant to when update calls getDocs:
  if (options) {
    // This was added because in our case, we are potentially iterating over
    // multiple docs. If multi isn't enabled, force a limit (almost like
    // findOne), as the default for update without multi enabled is to affect
    // only the first matched document:
    if (!options.multi) {
      findOptions.limit = 1
    }

    _.extend(findOptions, _.omit(options, 'multi', 'upsert'))
  }

  // Unlike validators, we iterate over multiple docs, so use
  // find instead of findOne:
  return collection.find(selector, findOptions)
}

// This function normalizes the selector (converting it to an Object)
CollectionHooks.normalizeSelector = function (selector) {
  if (typeof selector === 'string' || (selector && selector.constructor === Mongo.ObjectID)) {
    return {
      _id: selector
    }
  } else {
    return selector
  }
}

// This function contains a snippet of code pulled and modified from:
// ~/.meteor/packages/mongo-livedata/collection.js
// It's contained in these utility functions to make updates easier for us in
// case this code changes.
CollectionHooks.getFields = function getFields(mutator) {
  // compute modified fields
  var fields = []
  // ====ADDED START=======================
  var operators = [
    '$addToSet',
    '$bit',
    '$currentDate',
    '$inc',
    '$max',
    '$min',
    '$pop',
    '$pull',
    '$pullAll',
    '$push',
    '$rename',
    '$set',
    '$unset'
  ]
  // ====ADDED END=========================

  _.each(mutator, function (params, op) {
    // ====ADDED START=======================
    if (_.contains(operators, op)) {
      // ====ADDED END=========================
      _.each(_.keys(params), function (field) {
        // treat dotted fields as if they are replacing their
        // top-level part
        if (field.indexOf('.') !== -1) {
          field = field.substring(0, field.indexOf('.'))
        }

        // record the field we are trying to change
        if (!_.contains(fields, field)) {
          fields.push(field)
        }
      })
      // ====ADDED START=======================
    } else {
      fields.push(op)
    }
    // ====ADDED END=========================
  })

  return fields
}

CollectionHooks.reassignPrototype = function reassignPrototype(instance, constr) {
  var hasSetPrototypeOf = typeof Object.setPrototypeOf === 'function'

  if (!constr) constr = typeof Mongo !== 'undefined' ? Mongo.Collection : Meteor.Collection

  // __proto__ is not available in < IE11
  // Note: Assigning a prototype dynamically has performance implications
  if (hasSetPrototypeOf) {
    Object.setPrototypeOf(instance, constr.prototype)
  } else if (instance.__proto__) {
    instance.__proto__ = constr.prototype
  }
}

CollectionHooks.wrapCollection = function wrapCollection(ns, as) {
  if (!as._CollectionConstructor) as._CollectionConstructor = as.Collection
  if (!as._CollectionPrototype) as._CollectionPrototype = new as.Collection(null)

  var constructor = as._CollectionConstructor
  var proto = as._CollectionPrototype

  ns.Collection = function () {
    var ret = constructor.apply(this, arguments)
    CollectionHooks.extendCollectionInstance(this, constructor)
    return ret
  }

  ns.Collection.prototype = proto
  ns.Collection.prototype.constructor = ns.Collection

  for (var prop in constructor) {
    if (constructor.hasOwnProperty(prop)) {
      ns.Collection[prop] = constructor[prop]
    }
  }
}

CollectionHooks.modify = LocalCollection._modify

if (typeof Mongo !== 'undefined') {
  CollectionHooks.wrapCollection(Meteor, Mongo)
  CollectionHooks.wrapCollection(Mongo, Mongo)
} else {
  CollectionHooks.wrapCollection(Meteor, Meteor)
}

if (Meteor.isServer) {
  var _publish = Meteor.publish
  Meteor.publish = function (name, handler, options) {
    return _publish.call(this, name, function () {
      // This function is called repeatedly in publications
      var ctx = this
      var args = arguments
      return publishUserId.withValue(ctx && ctx.userId, function () {
        return handler.apply(ctx, args)
      })
    }, options)
  }

  // Make the above available for packages with hooks that want to determine
  // whether they are running inside a publish function or not.
  CollectionHooks.isWithinPublish = function isWithinPublish() {
    return publishUserId.get() !== undefined
  }
}
<|endoftext|>


<commit_before>exports.run = (client, msg) => {
  const request = require("superagent");
  const HTMLParser = require("fast-html-parser");
  request
  .get("http://www.fmylife.com/random")
  .end((err, res) => {
    if (err) return msg.reply(err);
    client.funcs.log(err.stack, "error");
    const root = HTMLParser.parse(res.text);
    const article = root.querySelector(".post.article .fmllink");
    return msg.channel.sendMessage(article.childNodes[0].text);
  });
};

exports.conf = {
  enabled: true,
  runIn: ["text", "dm", "group"],
  aliases: [],
  permLevel: 0,
  botPerms: [],
  requiredFuncs: [],
  requiredModules: ["superagent", "fast-html-parser"],
};

exports.help = {
  name: "fml",
  description: "Grabs random 'Fuck My Life' quote from the web.",
  usage: "",
  usageDelim: "",
};
<commit_msg>Update fml.js<commit_after>exports.run = (client, msg) => {
  const request = require("superagent");
  const HTMLParser = require("fast-html-parser");
  request
  .get("http://www.fmylife.com/random")
  .end((err, res) => {
    if (err) return msg.reply(err);
    client.funcs.log(err.stack, "error");
    const root = HTMLParser.parse(res.text);
    const article = root.querySelector('.block a');
    return msg.channel.sendMessage(article.text);
  });
};

exports.conf = {
  enabled: true,
  runIn: ["text", "dm", "group"],
  aliases: [],
  permLevel: 0,
  botPerms: [],
  requiredFuncs: [],
  requiredModules: ["superagent", "fast-html-parser"],
};

exports.help = {
  name: "fml",
  description: "Grabs random 'Fuck My Life' quote from the web.",
  usage: "",
  usageDelim: "",
};
<|endoftext|>