<commit_before>let express = require('express');
let OAuth = require('oauth').OAuth;

/* Twitter for Windows Phone keys are used as a backfill
 * in case the environment variables are not present.
 */
let consumer_key = process.env.TWITTER_CONSUMER_KEY;
let consumer_secret = process.env.TWITTER_CONSUMER_SECRET;
let callback_url = process.env.TWITTER_CALLBACK_URL || (
  'https://amptweet.herokuapp.com/auth/twitter/callback');

let router = express.Router();

let TwitterAuth = new OAuth(
  'https://api.twitter.com/oauth/request_token',
  'https://api.twitter.com/oauth/access_token',
  consumer_key,
  consumer_secret,
  '1.0',
  callback_url,
  'HMAC-SHA1'
);

/* Listen for GET on /auth/twitter/redirect */
router.get('/twitter/redirect', function(req, res) {
  TwitterAuth.getOAuthRequestToken(function (error, oAuthToken, oAuthTokenSecret, results) {
    TwitterAuth.authURL = 'https://twitter.com/' + 'oauth/authenticate?oauth_token=' + oAuthToken;
    res.status(302) // HTTP Redirect - 302 Found
      .append("Location", TwitterAuth.authURL);
    res.end();
  });
});

router.all('/twitter/callback', function(req, res) {
  res.send(req.body);
  res.end();
});

module.exports = router;
<commit_msg>i'm going to cry<commit_after>let express = require('express');
let OAuth = require('oauth').OAuth;

/* Twitter for Windows Phone keys are used as a backfill
 * in case the environment variables are not present.
 */
let consumer_key = process.env.TWITTER_CONSUMER_KEY;
let consumer_secret = process.env.TWITTER_CONSUMER_SECRET;
let callback_url = 'https://amptweet.herokuapp.com/auth/twitter/callback';

let router = express.Router();

let TwitterAuth = new OAuth(
  'https://api.twitter.com/oauth/request_token',
  'https://api.twitter.com/oauth/access_token',
  consumer_key,
  consumer_secret,
  '1.0A',
  callback_url,
  'HMAC-SHA1'
);

/* Listen for GET on /auth/twitter/redirect */
router.get('/twitter/redirect', function(req, res) {
  TwitterAuth.getOAuthRequestToken(function (error, oAuthToken, oAuthTokenSecret, results) {
    TwitterAuth.authURL = 'https://twitter.com/' + 'oauth/authenticate?oauth_token=' + oAuthToken;
    res.status(302) // HTTP Redirect - 302 Found
      .append("Location", TwitterAuth.authURL);
    res.end();
  });
});

router.all('/twitter/callback', function(req, res) {
  res.send(req.body);
  res.end();
});

module.exports = router;
<|endoftext|>


<commit_before>// Dependencies
var hljs   = require('highlight.js');   // Syntax colouring
var marked   = require('marked');       // Markdown compilation
var mongoose = require('mongoose');
var html_md  = require('html-md');
var RSS      = require('rss');
var emailjs  = require('emailjs');
var grav     = require('gravatar');

var Articles = require('../lib/post');
var Post     = Articles.Post;
var Draft    = Articles.Draft;
var Comment  = require('../lib/comment').Comment;

// options => website, route, username, description, dbport
exports.Blog = function (options) {

    // Setup the markdown compiler
    marked.setOptions({
        gfm         : true,
        tables      : true,
        breaks      : false,
        pedantic    : false,
        sanitize    : true,
        smartLists  : true,
        smartypants : false,
        langPrefix  : 'lang-',
        highlight: function (code, lang) {
            // TODO: support lang since it's provided
            return hljs.highlightAuto(code).value;
        }
    });

    console.log('connecting to: ' + 'mongodb://localhost:' + options.dbport + '/' + options.db);
    mongoose.connect('mongodb://localhost:' + options.dbport + '/' + options.db);
    var db = mongoose.connection;

    // Initialize the rss feed
    //var feed = new RSS({
    //    title       : options.username + '\'s Blog',
    //    description : options.description,
    //    feed_url    : options.website + options.route + 'rss/',
    //    site_url    : options.website,
    //    author      : options.username,
    //    language    : 'English'
    //});

    // Create a new provider
    //var _Provider = require('../lib/articles').provider;
    //var provider  = new _Provider('localhost', options.dbport);

    //function addToRss (feed, article) {
    //    feed.item({
    //        title       : article.title,
    //        description : 'New blog post at ' + options.website,
    //        url         : options.website + '/blog/id/' + article._id,
    //        guid        : '' + article._id,
    //        date        : article['created-at']
    //    });

    //    return feed;
    //}

    // Initialize the RSS feed upon startup
    //setTimeout(function () {
    //    provider.findAll(function (error, docs) {
    //        if (error) return;
    //        else docs.forEach(function (article) {
    //            addToRss(feed, article);
    //        });
    //    });
    //}, 1000);

    // Serve all articles
    function articles (req, res) {
        Post.find({}, function (err, posts) {
            if (err)
                return res.status(500).end();

            res.send(posts);
        });
        //provider.findAll(function (error, docs) {
        //    if (error) {
        //        res.status(500).end();
        //    } else {
        //        res.send(docs);
        //    }
        //});
    }

    /*
     * Given a list of comments, add a gravatar attribute to
     * the comment with the gravatar image for the user associated
     * with the comment.
     */
    function resolveGravatars (comments) {
        return comments.map(resolveGravatar);
    }

    function resolveGravatar (comment) {
        if (comment instanceof Array)
            return resolveGravatars(comment);

        comment.gravatar = grav.url(comment.email, {s: '40', r: 'pg', d: 'retro'});
        return comment;
    }

    function single (req, res) {
        Post.findOne({ _id: req.params.id }, function (err, post) {
            if (err || post === null)
                return res.status(500).end();

            // Add a flag to render comments
            post.full     = true;
            post.comments = resolveGravatar(post.comments);

            // Render the view
            res.render(options.route + 'article', {
                article: post,
                recent: []
            });
        });
        //provider.findById(req.params.id, function (error, doc) {
        //    if (error || doc === null) {
        //        res.status(500).end();
        //    } else {
        //        doc.full = true; // Flag to add comments
        //        doc.comments = resolveGravatar(doc.comments);
        //        res.render(options.route + 'article', {
        //            article: doc,
        //            recent: []
        //        });
        //    }
        //});
    }

    function comment (req, res) {

        var com = new Comment({
            body  : req.param('content'),
            email : req.param('email'),
            user  : req.param('user')
        });

        Post.findOne({ _id: req.param('id') }, function (err, post) {

            if (err || post === null)
                return res.status(500).end();

            // Add the comment to the post
            post.comments.push(com.toObject());

            // Update the post in the database
            post.save(function (err) {
                if (err)
                    return res.status(500).end();

                res.redirect('/blog/id/' + req.param('_id'));
            });
        });

        // Update the article with the new body
        //provider.comment({
        //    user    : req.param('name') || 'Anonymous',
        //    email   : req.param('email'),
        //    content : req.param('content'),
        //    notify  : req.param('notify') || 'off',
        //    _id     : req.param('_id')
        //}, function (error, docs) {
        //    if (error) res.status(500).end();
        //    else {

        //        // TODO: Email all users with the 'notify' flag set
        //        // TODO: Add 'reply to' mechanism to reply to comments
        //        //       and restrict the above emails being sent

        //        // Direct the user to the updated page
        //        res.redirect('/blog/id/' + req.param('_id'));
        //    }
        //});
    }

    // TODO
    //function notify () {}

    function commentReply (req, res) {
    //    provider.replyTo(req.param('parent_id'), {
    //        user    : req.param('name') || 'Anonymous',
    //        email   : req.param('email'),
    //        content : req.param('content'),
    //        notify  : req.param('notify') || 'off',
    //        _id     : req.param('_id')
    //    }, function (error, article) {
    //        if (error) res.status(500).end();
    //        else {

    //            // Notify the parent of the reply if necessary
    //            if (req.param('notify') === 'on') {
    //                var parents = article.comments.filter(function (article) {
    //                    return article._id === req.param('parent_id');
    //                });

    //                if (parents.length > 0) {
    //                    var email = parents[0].email;
    //                    notify(email, req.param('name'), req.param('content'));
    //                }
    //            }

    //            // Redirect to the article
    //            res.redirect('/blog/id/' + req.param('_id'));
    //        }
    //    });
    }

    function recent (callback) {
        Post.find({}, function (err, posts) {
            if (err || posts === null)
                return callback([]);
            callback(sortByDate(posts).slice(0, 3));
        });
        //provider.findAll(function (error, docs) {
        //    if (error) callback([]);
        //    else callback(docs.sort(function (a1, a2) {
        //        return a1.date < a2.date;
        //    }).slice(0,3)); // Take the first 3
        //});
    }

    function sortByDate (items) {
        return items.sort(function (p1, p2) {
            return p1.date < p2.date;
        });
    }

    function all (req, res) {
        Post.find({}, function (err, posts) {
            if (err || posts === null)
                return res.status(500).end();

            res.render(options.route + 'blog', {
                recent   : [],
                articles : sortByDate(posts)
                    .filter(function (p) {
                        return p.body;
                    })
                    .map(function (article) {
                        article.body = article.body.split('
')[0] + '
' +
                            article.body.split('
')[1] + '
';

                        return article;
                    })
            });
        });

        //provider.findAll(function (error, docs) {
        //    recent(function (recent) {
        //        if (error) {
        //            res.status(500).end();
        //        } else {
        //            res.render(options.route + 'blog', {
        //                articles: docs.sort(function (a1, a2) {
        //                    return a1.date < a2.date;
        //                }).filter(function (article) {
        //                    return article.body;
        //                }).map(function (article) {
        //                    article.body = article.body.split('
')[0] + '
' +
        //                        article.body.split('
')[1] + '
';
        //                    return article;
        //                }),
        //                recent: recent
        //            });
        //        }
        //    });
        //});
    }

    function edit (req, res) {

        Post.findOne({ _id: req.params.id }, function (err, post) {
            if (err || post === null)
                return res.status(500).end();

            post.isDraft = 'false';
            post.draftID = '';

            res.render(options.route + 'edit', {
                article: post,
                recent: []
            });
        });

        //provider.findById(req.params.id, function (error, doc) {
        //    if (error || doc === null) {
        //        res.status(500).end();
        //    } else {
        //        res.render(options.route + 'edit', {
        //            article: {
        //                body       : doc.body,
        //                github     : doc.github,
        //                date       : doc.created_at,
        //                title      : doc.title,
        //                _id        : doc._id
        //            },
        //            recent: []
        //        });
        //    }
        //});
    }

    function editDraft (req, res) {

        Draft.findOne({ _id: req.params.id }, function (err, draft) {
            if (err || draft === null)
                return res.status(500).end();

            var article     = draft;
            article.isDraft = 'true';

            res.render(options.route + 'edit', {
                article: article,
                recent: []
            });
        });

        //provider.findDraftById(req.params.id, function (error, doc) {
        //    if (error || doc === null) {
        //        res.status(500).end();
        //    } else {
        //        res.render(options.route + 'edit', {
        //            article: doc,
        //            recent: []
        //        });
        //    }
        //});
    }

    function update (req, res) {

        //if (req.session.user === undefined)
        //    return res.status(401).send('Unauthorized');

        //// Update the article with the new body
        //provider.update({
        //    title  : req.param('title'),
        //    body   : req.param('body'),
        //    github : req.param('github') || '',
        //    _id    : req.param('_id')
        //}, function (error, docs) {
        //    if (error)
        //        res.status(500).end();
        //    else
        //        res.redirect('/blog/id/' + req.param('_id'));
        //});
    }

    function create (req, res) {
        if (req.session.user === undefined)
            return res.status(401).send('Unauthorized');

        res.render(options.route + 'edit', {
            article:{
                body     : '',
                markdown : '',
                _id      : '',
                isDraft  : 'false',
                title    : '',
                github   : ''
            },
            recent: []
        });
    }

    function admin (req, res) {
        if (req.session.user === undefined)
            return res.status(401).send('Unauthorized');

        Draft.find({}, function (err, drafts) {
            if (err)
                return res.status(501).end();

            res.render(options.route + 'admin', {
                drafts: drafts,
                recent: []
            });
        });

        //provider.findDrafts(function (error, drafts) {
        //    if (error) return res.status(501).end();

        //    res.render(options.route + 'admin', {
        //        drafts: drafts,
        //        recent: []
        //    });
        //});
    }

    function save (req, res) {

        // Check whether a draft already exists with the same name
        Draft.findOne({ _id: req.param('draftID') }, function (err, draft) {

            if (err || draft === null) {
                draft = new Draft();
            }

            draft.title    = req.param('title');
            draft.body     = '';
            draft.markdown = req.param('markdown');
            draft.github   = req.param('github');

            draft.save(function (err) {
                if (err)
                    return res.status(501).end();

                res.redirect('/blog/admin');
            });
        });

        // If authorized, save the article
        //provider.save({
        //    title    : req.param('title'),
        //    github   : req.param('github') || '',
        //    markdown : req.param('markdown')
        //}, function (error, docs) {
        //    if (error) {
        //        res.status(500).end();
        //    } else {
        //        // Redirect to the blog
        //        res.redirect('/blog/admin');
        //    }
        //});
    }

    function publish (req, res) {

        // If a draft already exists, remove it
        if (req.param('isDraft') === 'true') {
            Draft.findOne({ _id: req.param('draftID') }, function(err, draft) {
                if (!err && draft !== null)
                    draft.remove();
            });
        }
        // Otherwise, if the post has been published, remove the old one
        else if (req.param('draftID') !== ''){
            Post.findOne({ _id: req.param('draftID') }, function (err, post) {
                if (!err && post !== null) {
                    post.remove();
                }
            });
        }

        // Save the article as a post
        var post = new Post({
            title    : req.param('title'),
            github   : req.param('github'),
            markdown : req.param('markdown'),
            body     : marked(req.param('markdown'))
        });

        post.save(function (err) {
            if (err)
                return res.status(501).end();

            res.redirect('/blog');
        });

        //provider.publish({
        //    title    : req.param('title'),
        //    github   : req.param('github') || '',
        //    created  : req.param('created') !== '' ? new Date(req.param('created')) : new Date(),
        //    markdown : req.param('markdown')
        //}, function (error, docs) {
        //    if (error) {
        //        res.status(500).end();
        //    } else {

        //        // Add the article to rss
        //        addToRss(feed, docs[0]);

        //        // Redirect to the blog
        //        res.redirect('/blog');
        //    }
        //});
    }

    function author (req, res) {
        if (req.session.user === undefined)
            return res.status(401).send('Unauthorized');

        if (req.param('save'))
            save(req, res);
        else if (req.param('publish'))
            publish(req, res);
        else
            res.status(401).send('Unauthorized');
    }

    function rss (req, res) {
        //res.send(feed.xml('  '));
    }

    return {
        articles     : articles,
        single       : single,
        comment      : comment,
        commentReply : commentReply,
        recent       : recent,
        all          : all,
        edit         : edit,
        editDraft    : editDraft,
        update       : update,
        create       : create,
        admin        : admin,
        author       : author,
        rss          : rss
    };
};

<commit_msg>Removing console log<commit_after>// Dependencies
var hljs   = require('highlight.js');   // Syntax colouring
var marked   = require('marked');       // Markdown compilation
var mongoose = require('mongoose');
var html_md  = require('html-md');
var RSS      = require('rss');
var emailjs  = require('emailjs');
var grav     = require('gravatar');

var Articles = require('../lib/post');
var Post     = Articles.Post;
var Draft    = Articles.Draft;
var Comment  = require('../lib/comment').Comment;

// options => website, route, username, description, dbport
exports.Blog = function (options) {

    // Setup the markdown compiler
    marked.setOptions({
        gfm         : true,
        tables      : true,
        breaks      : false,
        pedantic    : false,
        sanitize    : true,
        smartLists  : true,
        smartypants : false,
        langPrefix  : 'lang-',
        highlight: function (code, lang) {
            // TODO: support lang since it's provided
            return hljs.highlightAuto(code).value;
        }
    });

    mongoose.connect('mongodb://localhost:' + options.dbport + '/' + options.db);
    var db = mongoose.connection;

    // Initialize the rss feed
    //var feed = new RSS({
    //    title       : options.username + '\'s Blog',
    //    description : options.description,
    //    feed_url    : options.website + options.route + 'rss/',
    //    site_url    : options.website,
    //    author      : options.username,
    //    language    : 'English'
    //});

    // Create a new provider
    //var _Provider = require('../lib/articles').provider;
    //var provider  = new _Provider('localhost', options.dbport);

    //function addToRss (feed, article) {
    //    feed.item({
    //        title       : article.title,
    //        description : 'New blog post at ' + options.website,
    //        url         : options.website + '/blog/id/' + article._id,
    //        guid        : '' + article._id,
    //        date        : article['created-at']
    //    });

    //    return feed;
    //}

    // Initialize the RSS feed upon startup
    //setTimeout(function () {
    //    provider.findAll(function (error, docs) {
    //        if (error) return;
    //        else docs.forEach(function (article) {
    //            addToRss(feed, article);
    //        });
    //    });
    //}, 1000);

    // Serve all articles
    function articles (req, res) {
        Post.find({}, function (err, posts) {
            if (err)
                return res.status(500).end();

            res.send(posts);
        });
        //provider.findAll(function (error, docs) {
        //    if (error) {
        //        res.status(500).end();
        //    } else {
        //        res.send(docs);
        //    }
        //});
    }

    /*
     * Given a list of comments, add a gravatar attribute to
     * the comment with the gravatar image for the user associated
     * with the comment.
     */
    function resolveGravatars (comments) {
        return comments.map(resolveGravatar);
    }

    function resolveGravatar (comment) {
        if (comment instanceof Array)
            return resolveGravatars(comment);

        comment.gravatar = grav.url(comment.email, {s: '40', r: 'pg', d: 'retro'});
        return comment;
    }

    function single (req, res) {
        Post.findOne({ _id: req.params.id }, function (err, post) {
            if (err || post === null)
                return res.status(500).end();

            // Add a flag to render comments
            post.full     = true;
            post.comments = resolveGravatar(post.comments);

            // Render the view
            res.render(options.route + 'article', {
                article: post,
                recent: []
            });
        });
        //provider.findById(req.params.id, function (error, doc) {
        //    if (error || doc === null) {
        //        res.status(500).end();
        //    } else {
        //        doc.full = true; // Flag to add comments
        //        doc.comments = resolveGravatar(doc.comments);
        //        res.render(options.route + 'article', {
        //            article: doc,
        //            recent: []
        //        });
        //    }
        //});
    }

    function comment (req, res) {

        var com = new Comment({
            body  : req.param('content'),
            email : req.param('email'),
            user  : req.param('user')
        });

        Post.findOne({ _id: req.param('id') }, function (err, post) {

            if (err || post === null)
                return res.status(500).end();

            // Add the comment to the post
            post.comments.push(com.toObject());

            // Update the post in the database
            post.save(function (err) {
                if (err)
                    return res.status(500).end();

                res.redirect('/blog/id/' + req.param('_id'));
            });
        });

        // Update the article with the new body
        //provider.comment({
        //    user    : req.param('name') || 'Anonymous',
        //    email   : req.param('email'),
        //    content : req.param('content'),
        //    notify  : req.param('notify') || 'off',
        //    _id     : req.param('_id')
        //}, function (error, docs) {
        //    if (error) res.status(500).end();
        //    else {

        //        // TODO: Email all users with the 'notify' flag set
        //        // TODO: Add 'reply to' mechanism to reply to comments
        //        //       and restrict the above emails being sent

        //        // Direct the user to the updated page
        //        res.redirect('/blog/id/' + req.param('_id'));
        //    }
        //});
    }

    // TODO
    //function notify () {}

    function commentReply (req, res) {
    //    provider.replyTo(req.param('parent_id'), {
    //        user    : req.param('name') || 'Anonymous',
    //        email   : req.param('email'),
    //        content : req.param('content'),
    //        notify  : req.param('notify') || 'off',
    //        _id     : req.param('_id')
    //    }, function (error, article) {
    //        if (error) res.status(500).end();
    //        else {

    //            // Notify the parent of the reply if necessary
    //            if (req.param('notify') === 'on') {
    //                var parents = article.comments.filter(function (article) {
    //                    return article._id === req.param('parent_id');
    //                });

    //                if (parents.length > 0) {
    //                    var email = parents[0].email;
    //                    notify(email, req.param('name'), req.param('content'));
    //                }
    //            }

    //            // Redirect to the article
    //            res.redirect('/blog/id/' + req.param('_id'));
    //        }
    //    });
    }

    function recent (callback) {
        Post.find({}, function (err, posts) {
            if (err || posts === null)
                return callback([]);
            callback(sortByDate(posts).slice(0, 3));
        });
        //provider.findAll(function (error, docs) {
        //    if (error) callback([]);
        //    else callback(docs.sort(function (a1, a2) {
        //        return a1.date < a2.date;
        //    }).slice(0,3)); // Take the first 3
        //});
    }

    function sortByDate (items) {
        return items.sort(function (p1, p2) {
            return p1.date < p2.date;
        });
    }

    function all (req, res) {
        Post.find({}, function (err, posts) {
            if (err || posts === null)
                return res.status(500).end();

            res.render(options.route + 'blog', {
                recent   : [],
                articles : sortByDate(posts)
                    .filter(function (p) {
                        return p.body;
                    })
                    .map(function (article) {
                        article.body = article.body.split('
')[0] + '
' +
                            article.body.split('
')[1] + '
';

                        return article;
                    })
            });
        });

        //provider.findAll(function (error, docs) {
        //    recent(function (recent) {
        //        if (error) {
        //            res.status(500).end();
        //        } else {
        //            res.render(options.route + 'blog', {
        //                articles: docs.sort(function (a1, a2) {
        //                    return a1.date < a2.date;
        //                }).filter(function (article) {
        //                    return article.body;
        //                }).map(function (article) {
        //                    article.body = article.body.split('
')[0] + '
' +
        //                        article.body.split('
')[1] + '
';
        //                    return article;
        //                }),
        //                recent: recent
        //            });
        //        }
        //    });
        //});
    }

    function edit (req, res) {

        Post.findOne({ _id: req.params.id }, function (err, post) {
            if (err || post === null)
                return res.status(500).end();

            post.isDraft = 'false';
            post.draftID = '';

            res.render(options.route + 'edit', {
                article: post,
                recent: []
            });
        });

        //provider.findById(req.params.id, function (error, doc) {
        //    if (error || doc === null) {
        //        res.status(500).end();
        //    } else {
        //        res.render(options.route + 'edit', {
        //            article: {
        //                body       : doc.body,
        //                github     : doc.github,
        //                date       : doc.created_at,
        //                title      : doc.title,
        //                _id        : doc._id
        //            },
        //            recent: []
        //        });
        //    }
        //});
    }

    function editDraft (req, res) {

        Draft.findOne({ _id: req.params.id }, function (err, draft) {
            if (err || draft === null)
                return res.status(500).end();

            var article     = draft;
            article.isDraft = 'true';

            res.render(options.route + 'edit', {
                article: article,
                recent: []
            });
        });

        //provider.findDraftById(req.params.id, function (error, doc) {
        //    if (error || doc === null) {
        //        res.status(500).end();
        //    } else {
        //        res.render(options.route + 'edit', {
        //            article: doc,
        //            recent: []
        //        });
        //    }
        //});
    }

    function update (req, res) {

        //if (req.session.user === undefined)
        //    return res.status(401).send('Unauthorized');

        //// Update the article with the new body
        //provider.update({
        //    title  : req.param('title'),
        //    body   : req.param('body'),
        //    github : req.param('github') || '',
        //    _id    : req.param('_id')
        //}, function (error, docs) {
        //    if (error)
        //        res.status(500).end();
        //    else
        //        res.redirect('/blog/id/' + req.param('_id'));
        //});
    }

    function create (req, res) {
        if (req.session.user === undefined)
            return res.status(401).send('Unauthorized');

        res.render(options.route + 'edit', {
            article:{
                body     : '',
                markdown : '',
                _id      : '',
                isDraft  : 'false',
                title    : '',
                github   : ''
            },
            recent: []
        });
    }

    function admin (req, res) {
        if (req.session.user === undefined)
            return res.status(401).send('Unauthorized');

        Draft.find({}, function (err, drafts) {
            if (err)
                return res.status(501).end();

            res.render(options.route + 'admin', {
                drafts: drafts,
                recent: []
            });
        });

        //provider.findDrafts(function (error, drafts) {
        //    if (error) return res.status(501).end();

        //    res.render(options.route + 'admin', {
        //        drafts: drafts,
        //        recent: []
        //    });
        //});
    }

    function save (req, res) {

        // Check whether a draft already exists with the same name
        Draft.findOne({ _id: req.param('draftID') }, function (err, draft) {

            if (err || draft === null) {
                draft = new Draft();
            }

            draft.title    = req.param('title');
            draft.body     = '';
            draft.markdown = req.param('markdown');
            draft.github   = req.param('github');

            draft.save(function (err) {
                if (err)
                    return res.status(501).end();

                res.redirect('/blog/admin');
            });
        });

        // If authorized, save the article
        //provider.save({
        //    title    : req.param('title'),
        //    github   : req.param('github') || '',
        //    markdown : req.param('markdown')
        //}, function (error, docs) {
        //    if (error) {
        //        res.status(500).end();
        //    } else {
        //        // Redirect to the blog
        //        res.redirect('/blog/admin');
        //    }
        //});
    }

    function publish (req, res) {

        // If a draft already exists, remove it
        if (req.param('isDraft') === 'true') {
            Draft.findOne({ _id: req.param('draftID') }, function(err, draft) {
                if (!err && draft !== null)
                    draft.remove();
            });
        }
        // Otherwise, if the post has been published, remove the old one
        else if (req.param('draftID') !== ''){
            Post.findOne({ _id: req.param('draftID') }, function (err, post) {
                if (!err && post !== null) {
                    post.remove();
                }
            });
        }

        // Save the article as a post
        var post = new Post({
            title    : req.param('title'),
            github   : req.param('github'),
            markdown : req.param('markdown'),
            body     : marked(req.param('markdown'))
        });

        post.save(function (err) {
            if (err)
                return res.status(501).end();

            res.redirect('/blog');
        });

        //provider.publish({
        //    title    : req.param('title'),
        //    github   : req.param('github') || '',
        //    created  : req.param('created') !== '' ? new Date(req.param('created')) : new Date(),
        //    markdown : req.param('markdown')
        //}, function (error, docs) {
        //    if (error) {
        //        res.status(500).end();
        //    } else {

        //        // Add the article to rss
        //        addToRss(feed, docs[0]);

        //        // Redirect to the blog
        //        res.redirect('/blog');
        //    }
        //});
    }

    function author (req, res) {
        if (req.session.user === undefined)
            return res.status(401).send('Unauthorized');

        if (req.param('save'))
            save(req, res);
        else if (req.param('publish'))
            publish(req, res);
        else
            res.status(401).send('Unauthorized');
    }

    function rss (req, res) {
        //res.send(feed.xml('  '));
    }

    return {
        articles     : articles,
        single       : single,
        comment      : comment,
        commentReply : commentReply,
        recent       : recent,
        all          : all,
        edit         : edit,
        editDraft    : editDraft,
        update       : update,
        create       : create,
        admin        : admin,
        author       : author,
        rss          : rss
    };
};

<|endoftext|>


<commit_before>/**********************************************************************
  Dependencies
**********************************************************************/
var express = require('express');
var router = express.Router();
var request = require("request");
var utils = require("../helpers/utils")
var redisCache = require('redis').createClient(process.env.REDIS_URL);

/**********************************************************************
  Feed Display (GET)
**********************************************************************/
router.get('/',

  function ajaxRequest(req, res, next) {

    // user has typed in something
    if(req.query.url){
      if(req.query.url.indexOf("http") == -1){
        req.query.url = "http://" + req.query.url
      }

      request(req.query.url.trim(), function(err, requestResponse, rawData) {

        // we have a response!
        if(requestResponse && requestResponse.headers){

          var feedType = null

          // check what mimetype we have
          utils.mimeTypes.forEach(function(m){
            if (requestResponse.headers["content-type"].indexOf(m.mimetype) > -1){
              feedType = m.feedtype;
            }
          })

          if(feedType == "json"){

            var parsedJson;

            res.locals.feedType = "json"

            try {
              parsedJson = JSON.parse(rawData);
            } catch(e) {
              req.flash("error", "Error while parsing the JSON feed.")
              return res.redirect("/");
            }

            if(parsedJson.hasOwnProperty('err')){
              req.flash("error", "There was an error while preparing the feed to be displayed.")
              return res.redirect("/");
            }
            else{
              // feed is ready to be displayed!
              parsedJson["fetched_at"] = new Date();
              if(!parsedJson.feed_url){
                parsedJson.feed_url = req.query.url.toLowerCase().trim()
              }
              res.locals.data = parsedJson;

              // push data to the redis cache (expires after 72 hours)
              redisCache.setex(encodeURIComponent(req.query.url.toLowerCase().trim()), 60*60*72, JSON.stringify(parsedJson), function(){
                return next();
              })
            }
          }

          else if(feedType == "xml"){

            res.locals.feedType = "xml"

            // we need convert the rss/atom feed to json first
            request("https://feed2json.org/convert?url="+encodeURIComponent(req.query.url.trim()), function(err, converterRequestResponse, converterRawData) {

              // we have a response from feed2json!
              if(converterRequestResponse && converterRequestResponse.headers){

                var convertedFeedType = null

                // check what mimetype we have
                utils.mimeTypes.forEach(function(m){
                  if (converterRequestResponse.headers["content-type"].indexOf(m.mimetype) > -1){
                    convertedFeedType = m.feedtype;
                  }
                })

                if(convertedFeedType == "json"){
                  var parsedConvertedJson;

                  try {
                    parsedConvertedJson = JSON.parse(converterRawData);
                  } catch(e) {
                    req.flash("error", "Error while parsing the converted feed.")
                    return res.redirect("/");
                  }

                  if(parsedConvertedJson.hasOwnProperty('err')){
                    req.flash("error", "There was an error while preparing the feed to be displayed.")
                    return res.redirect("/");
                  }
                  else{
                    // feed is ready to be displayed!
                    parsedConvertedJson["fetched_at"] = new Date();
                    if(!parsedConvertedJson.feed_url){
                      parsedConvertedJson.feed_url = req.query.url.toLowerCase().trim()
                    }
                    res.locals.data = parsedConvertedJson;

                    // push data to the redis cache (expires after 72 hours)
                    redisCache.setex(encodeURIComponent(req.query.url.toLowerCase().trim()), 60*60*72, JSON.stringify(parsedConvertedJson), function(){
                      return next();
                    })
                  }
                }
                else{
                  // converted data is not json
                  req.flash("error", "Error while converting the feed to JSON. Please try again.")
                  return res.redirect("/");
                }
              }
              else{
                // bad response from converter
                req.flash("error", "Invalid response from the feed converter. Please try again.")
                return res.redirect("/");
              }
            });
          }
          else{
            // not json, nor xml
            req.flash("error", "Unexpected MIME type. Please make sure you are entering a JSON, RSS, or Atom feed URL.")
            return res.redirect("/");
          }
        }

        else{
          // we don't have a valid response
          req.flash("error", "Invalid response from this URL. Please try again.")
          return res.redirect("/");
        }
      });
    }

    // no user input
    else{
      return res.redirect("/");
    }
  },

  function render(req, res, next) {
    return res.render("feed")
  }

);

/**********************************************************************
  Exports
**********************************************************************/
module.exports = router;<commit_msg>fixed 'no mimetype in header' bug<commit_after>/**********************************************************************
  Dependencies
**********************************************************************/
var express = require('express');
var router = express.Router();
var request = require("request");
var utils = require("../helpers/utils")
var redisCache = require('redis').createClient(process.env.REDIS_URL);

/**********************************************************************
  Feed Display (GET)
**********************************************************************/
router.get('/',

  function ajaxRequest(req, res, next) {

    // user has typed in something
    if(req.query.url){
      if(req.query.url.indexOf("http") == -1){
        req.query.url = "http://" + req.query.url
      }

      request(req.query.url.trim(), function(err, requestResponse, rawData) {

        // we have a response!
        if(requestResponse && requestResponse.headers){

          var feedType = null

          // check what mimetype we have
          utils.mimeTypes.forEach(function(m){
            if (requestResponse.headers["content-type"] && requestResponse.headers["content-type"].indexOf(m.mimetype) > -1){
              feedType = m.feedtype;
            }
          })

          if(feedType == "json"){

            var parsedJson;

            res.locals.feedType = "json"

            try {
              parsedJson = JSON.parse(rawData);
            } catch(e) {
              req.flash("error", "Error while parsing the JSON feed.")
              return res.redirect("/");
            }

            if(parsedJson.hasOwnProperty('err')){
              req.flash("error", "There was an error while preparing the feed to be displayed.")
              return res.redirect("/");
            }
            else{
              // feed is ready to be displayed!
              parsedJson["fetched_at"] = new Date();
              if(!parsedJson.feed_url){
                parsedJson.feed_url = req.query.url.toLowerCase().trim()
              }
              res.locals.data = parsedJson;

              // push data to the redis cache (expires after 72 hours)
              redisCache.setex(encodeURIComponent(req.query.url.toLowerCase().trim()), 60*60*72, JSON.stringify(parsedJson), function(){
                return next();
              })
            }
          }

          else if(feedType == "xml"){

            res.locals.feedType = "xml"

            // we need convert the rss/atom feed to json first
            request("https://feed2json.org/convert?url="+encodeURIComponent(req.query.url.trim()), function(err, converterRequestResponse, converterRawData) {

              // we have a response from feed2json!
              if(converterRequestResponse && converterRequestResponse.headers){

                var convertedFeedType = null

                // check what mimetype we have
                utils.mimeTypes.forEach(function(m){
                  if (converterRequestResponse.headers["content-type"].indexOf(m.mimetype) > -1){
                    convertedFeedType = m.feedtype;
                  }
                })

                if(convertedFeedType == "json"){
                  var parsedConvertedJson;

                  try {
                    parsedConvertedJson = JSON.parse(converterRawData);
                  } catch(e) {
                    req.flash("error", "Error while parsing the converted feed.")
                    return res.redirect("/");
                  }

                  if(parsedConvertedJson.hasOwnProperty('err')){
                    req.flash("error", "There was an error while preparing the feed to be displayed.")
                    return res.redirect("/");
                  }
                  else{
                    // feed is ready to be displayed!
                    parsedConvertedJson["fetched_at"] = new Date();
                    if(!parsedConvertedJson.feed_url){
                      parsedConvertedJson.feed_url = req.query.url.toLowerCase().trim()
                    }
                    res.locals.data = parsedConvertedJson;

                    // push data to the redis cache (expires after 72 hours)
                    redisCache.setex(encodeURIComponent(req.query.url.toLowerCase().trim()), 60*60*72, JSON.stringify(parsedConvertedJson), function(){
                      return next();
                    })
                  }
                }
                else{
                  // converted data is not json
                  req.flash("error", "Error while converting the feed to JSON. Please try again.")
                  return res.redirect("/");
                }
              }
              else{
                // bad response from converter
                req.flash("error", "Invalid response from the feed converter. Please try again.")
                return res.redirect("/");
              }
            });
          }
          else{
            // not json, nor xml
            req.flash("error", "Unexpected MIME type. Please make sure you are entering a JSON, RSS, or Atom feed URL.")
            return res.redirect("/");
          }
        }

        else{
          // we don't have a valid response
          req.flash("error", "Invalid response from this URL. Please try again.")
          return res.redirect("/");
        }
      });
    }

    // no user input
    else{
      return res.redirect("/");
    }
  },

  function render(req, res, next) {
    return res.render("feed")
  }

);

/**********************************************************************
  Exports
**********************************************************************/
module.exports = router;
<|endoftext|>


<commit_before><commit_msg>Alphabetaize institution names<commit_after><|endoftext|>


<commit_before>var data = require('../data.json');
exports.view = function(req, res){
//	console.log(data);
	console.log(req.query.selected);
	var eventid = req.query.selected.split('+')[0];
	var ideaname = req.query.selected.split('+')[1];
	console.log("eventid: " + eventid);
	console.log("ideaname: " + ideaname);
	var e = data[eventid];
	var idealist = e.idea;
	console.log(idealist);
	for (i in idealist){
		console.log(idealist[i]);
		var idea = idealist[i];
		console.log(idea.name == ideaname);
		if (idea.name == ideaname){
			res.render('idea', eventid, idea);
			break;
		}
	}
			console.log("HERE");
};<commit_msg>working idea pages (need to fix cancel still)<commit_after>var data = require('../data.json');
exports.view = function(req, res){
//	console.log(data);
	console.log(req.query.selected);
	var eventid = req.query.selected.split('+')[0];
	var ideaname = req.query.selected.split('+')[1];
	console.log("eventid: " + eventid);
	console.log("ideaname: " + ideaname);
	var e = data[eventid];
	var idealist = e.idea;
	console.log(idealist);
	for (i in idealist){
		console.log(idealist[i]);
		var idea = idealist[i];
		console.log(idea.name == ideaname);
		if (idea.name == ideaname){
			res.render('idea', idea);
			break;
		}
	}
			console.log("HERE");
};<|endoftext|>


<commit_before>var https = require('https');
var fs = require('fs');
var url = require('url');
var child_process = require('child_process');
var spawn = child_process.spawn;
var exec = child_process.exec;

var apiHost = "api.github.com";
var apiEndpoint = "/repos/timelapseplus/VIEW/";
var baseInstallPath = "/home/view/";

var kernelVersion = "#51 PREEMPT Thu Jan 5 13:15:18 EST 2017";
var uBootVersion = "U-Boot SPL 2016.01 TL+ VIEW -00446-g12f229e-dirty (Dec 23 2016 - 17:47:10)";

var libgphoto2Version = "2.5.12.1";

var getLibGPhoto2Version = "/usr/local/bin/gphoto2 --version | grep \"libgphoto2 \"";
var installLibGPhoto2 = "/usr/bin/test -e /home/view/current/lib/libgphoto2_2.5.12-2-1_armhf.deb && dpkg -i /home/view/current/lib/libgphoto2_2.5.12-2-1_armhf.deb";

var getKernelVersion = "uname -v";
var doKernelUpdate = "/usr/bin/test -e /home/view/current/boot/zImage && /usr/bin/test -e /home/view/current/boot/sun5i-a13-timelapseplus-view.dtb && mount /dev/mmcblk0p1 /boot && cp /home/view/current/boot/zImage /boot/ && cp /home/view/current/boot/sun5i-a13-timelapseplus-view.dtb /boot/ && /bin/sync && umount /boot";

var getUBootVersion = "/bin/dd if=/dev/mmcblk0 bs=1024 count=32 | /usr/bin/strings | /bin/grep \"U-Boot SPL\"";
var doUBootUpdate = "/usr/bin/test -e /home/view/current/boot/u-boot-sunxi-with-spl.bin && /bin/dd if=/home/view/current/boot/u-boot-sunxi-with-spl.bin of=/dev/mmcblk0 bs=1024 seek=8";

var installIcons = "/usr/bin/test -e /home/view/current/fonts/icons.ttf && cp -u /home/view/current/fonts/icons.ttf /usr/share/fonts/truetype/";

function checkLibGPhotoUpdate(callback) {
	exec(getLibGPhoto2Version, function(err, stdout, stderr) {
		if(!err && stdout) {
			var parts = stdout.match(/([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/);
			if(parts && parts.length > 1 ) {
				var version = parts[1].trim();
				exports.libgphoto2Version = version;
				if(version != libgphoto2Version) {
					console.log("libgphoto2 update required (current version = " + version + ")");
					callback(null, true);
				} else {
					console.log("libgphoto2 is up to date");
					callback(null, false);
				}
			} else {
				callback("error getting version");
			}
		} else {
			callback("error getting version");
		}
	});
}

function installLibGPhoto(callback) {
	exports.updatingLibGphoto = true;
	exec(installLibGPhoto2, function(err) {
		exports.updatingLibGphoto = false;
		callback(err);
	});
}

function apiRequest(method, callback) {
	var req = https.request({method:'get', host:apiHost, path: apiEndpoint+method, headers: {'user-agent': 'VIEW-app'}}, function(res) {
		//console.log(`STATUS: ${res.statusCode}`);
		//console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
		res.setEncoding('utf8');
		var data = "";
		res.on('data', function(chunk) {
			data += chunk;
			//console.log(`BODY: ${chunk}`);
		});
		res.on('end', function() {
			var doc = JSON.parse(data);
			//console.log(doc);
			if(callback) callback(null, doc);
		});

	});
	req.end();
	req.on('error', function(err) {
		if(callback) callback(err);
	});
}

function download(href, path, callback) {
	var options = url.parse(href);
	options.headers = {'user-agent': 'VIEW-app'};
	options.method = "GET";
	//options.auth = username+':'+accessToken;

	var req = https.get(options, function(res) {
		//console.log(`STATUS: ${res.statusCode}`);
		//console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
		if(res.statusCode == 302 && res.headers.location) {
			download(res.headers.location, path, callback);
			return;
		}
		var fd = fs.openSync(path, 'w');
		if(!fd) callback("error creating " + path);
		res.on('data', function(chunk) {
			var bytes = 0;
			if(fd) bytes = fs.writeSync(fd, chunk, 0, chunk.length);
			//console.log("Writing " + bytes + " bytes to file ", fd, chunk.length);
		});
		res.on('end', function() {
			if(fd) {
				fs.closeSync(fd);
				callback(null, path);
			}
		});

	});
	req.end();
	req.on('error', function(err) {
		callback(err);
	});
}

function extract(zipPath, destFolder, callback) {
	var unzip = spawn('unzip', ['-q', zipPath, '-d', destFolder + '_zip_extract']);
	console.log("extracting...");
	unzip.once('close', function(code) {
		fs.readdir(destFolder + '_zip_extract', function(err, files) {
			console.log(err, files);
			if(files && files.length > 0) {
				fs.rename(destFolder + '_zip_extract' + '/' + files[0], destFolder, function(){
					fs.rmdir(destFolder + '_zip_extract');
					console.log("done extracting");
					callback(err, destFolder);
				});
			} else {
				callback(err, destFolder);
			}
		});
	});
}

function checkKernel(callback) {
	exec(getKernelVersion, function(err, stdout, stderr) {
		if(!err && stdout) {
			var currentKernel = stdout.trim();
			if(currentKernel == kernelVersion) {
				callback(null, false);
			} else {
				console.log("Current KERNEL:", currentKernel)
				callback(null, true);
			}
		} else {
			callback(err, false);
		}
	});
}

exports.updatingKernel = false;
function updateKernel(callback) {
	checkKernel(function(err1, needUpdate) {
		if(needUpdate) {
			console.log("KERNEL UPDATE REQUIRED");
			exports.updatingKernel = true;
			exec(doKernelUpdate, function(err, stdout, stderr) {
				exports.updatingKernel = false;
				if(err) {
					if(callback) callback(err);
					console.log("KERNEL UPDATE FAILED", err, stdout, stderr);
				} else {
					console.log("KERNEL UPDATE SUCCESS, running call back for reboot", err, stdout, stderr);
					if(callback) callback(false, true);
				}
			});
		} else {
			if(callback) callback(false);
			console.log("KERNEL UP TO DATE");
		}
	});
}

function checkUBoot(callback) {
	exec(getUBootVersion, function(err, stdout, stderr) {
		if(!err && stdout) {
			var currentUBoot = stdout.trim();
			if(currentUBoot == uBootVersion) {
				callback(null, false);
			} else {
				console.log("Current U-BOOT:", currentUBoot)
				callback(null, true);
			}
		} else {
			callback(err, false);
		}
	});
}

function updateUBoot(callback) {
	checkUBoot(function(err1, needUpdate) {
		if(needUpdate) {
			console.log("U-BOOT UPDATE REQUIRED");
			exec(doUBootUpdate, function(err, stdout, stderr) {
				if(err) {
					console.log("U-BOOT UPDATE FAILED", err, stdout, stderr);
				}
				if(callback) callback(err);
			});
		} else {
			if(callback) callback(false);
			console.log("U-BOOT UP TO DATE");
		}
	});
}

exports.version = "";
var installs = fs.readdirSync(baseInstallPath);
var current = "";
if(installs.indexOf('current') !== -1) {
	current = fs.readlinkSync(baseInstallPath + 'current');
	current = current.match(/[^\/]+$/)[0];
	console.log("current version:", current);
	exports.version = current;
}

exports.getCurrentVersion = function() {
	return current;
}

exports.developerMode = false;
var cachedVersions = null;
exports.getVersions = function(callback){
	if(cachedVersions) {
		callback(null, cachedVersions);
	} else {
		apiRequest('releases', function(err, res) {
			if(!err && res) {
				var installs = fs.readdirSync(baseInstallPath);
				var current = "";
				console.log(installs);
				if(installs.indexOf('current') !== -1) {
					current = fs.readlinkSync(baseInstallPath + 'current');
					current = current.match(/[^\/]+$/)[0];
					console.log("current version:", current);
				}
				var list = [];
				for(var i = 0; i < res.length; i++) {
					if(!res[i].prerelease || exports.developerMode) list.push({
						version: res[i].tag_name,
						description: res[i].name,
						notes: res[i].body,
						url: res[i].zipball_url,
						pre: res[i].prerelease,
						date: res[i].published_at,
						installed: installs.indexOf(res[i].tag_name) !== -1,
						current: res[i].tag_name == current
					});
				}
				cachedVersions = list;
				setTimeout(function(){
					cachedVersions = null; // clear cache after 5 minutes
				}, 1000*60*5);
				callback(null, list);
			} else {
				callback(err);
			}
		});
	}
};

exports.installing = false;
exports.installStatus = null;
exports.installVersion = function(versionInfo, callback, statusCallback) {
	exports.installing = true;
	var updateStatus = function(status) {
		console.log("INSTALL:", status);
		exports.installStatus = status;
		if(statusCallback) statusCallback(status);
	}
	if(versionInfo.version && versionInfo.url) {
		updateStatus('downloading...');
		download(versionInfo.url, baseInstallPath + "tmp.zip", function(err, info){
			if(err) {
				updateStatus('download failed.');
				exports.installing = false;
				callback(err);
			} else {
				updateStatus('extracting...');
				extract(baseInstallPath + "tmp.zip", baseInstallPath + versionInfo.version, function(err) {
					if(err) {
						updateStatus('extract failed.');
						exports.installing = false;
						callback(err);
					} else {
						fs.unlink(baseInstallPath + "tmp.zip");
						fs.writeFile(baseInstallPath + versionInfo.version + "/version.json", JSON.stringify(versionInfo), function(){
							updateStatus('done.');
							exports.installing = false;
							callback();
						});
					}
				});
			}
		});
	} else {
		callback("invalid version object");
	}
}

exports.setVersion = function(versionInfo, callback) {
	var installs = fs.readdirSync(baseInstallPath);
	console.log(installs);
	if(installs.indexOf('current') !== -1) {
		fs.unlinkSync(baseInstallPath + 'current');
	}
	fs.symlink(baseInstallPath + versionInfo.version, baseInstallPath + 'current', function(err) {
		callback && callback(err);
		console.log(err);
	});
}

exports.installIcons = function(callback) {
	exec(installIcons, callback);
}

exports.download = download;
exports.extract = extract;
exports.apiRequest = apiRequest;

exports.checkLibGPhotoUpdate = checkLibGPhotoUpdate;
exports.installLibGPhoto = installLibGPhoto;

exports.updateKernel = updateKernel;
exports.updateUBoot = updateUBoot;

<commit_msg>libgphoto2 update<commit_after>var https = require('https');
var fs = require('fs');
var url = require('url');
var child_process = require('child_process');
var spawn = child_process.spawn;
var exec = child_process.exec;

var apiHost = "api.github.com";
var apiEndpoint = "/repos/timelapseplus/VIEW/";
var baseInstallPath = "/home/view/";

var kernelVersion = "#51 PREEMPT Thu Jan 5 13:15:18 EST 2017";
var uBootVersion = "U-Boot SPL 2016.01 TL+ VIEW -00446-g12f229e-dirty (Dec 23 2016 - 17:47:10)";

var libgphoto2Version = "2.5.13.1";

var getLibGPhoto2Version = "/usr/local/bin/gphoto2 --version | grep \"libgphoto2 \"";
var installLibGPhoto2 = "/usr/bin/test -e /home/view/current/lib/libgphoto2_2.5.13.1-1_armhf.deb && dpkg -i /home/view/current/lib/libgphoto2_2.5.13.1-1_armhf.deb";

var getKernelVersion = "uname -v";
var doKernelUpdate = "/usr/bin/test -e /home/view/current/boot/zImage && /usr/bin/test -e /home/view/current/boot/sun5i-a13-timelapseplus-view.dtb && mount /dev/mmcblk0p1 /boot && cp /home/view/current/boot/zImage /boot/ && cp /home/view/current/boot/sun5i-a13-timelapseplus-view.dtb /boot/ && /bin/sync && umount /boot";

var getUBootVersion = "/bin/dd if=/dev/mmcblk0 bs=1024 count=32 | /usr/bin/strings | /bin/grep \"U-Boot SPL\"";
var doUBootUpdate = "/usr/bin/test -e /home/view/current/boot/u-boot-sunxi-with-spl.bin && /bin/dd if=/home/view/current/boot/u-boot-sunxi-with-spl.bin of=/dev/mmcblk0 bs=1024 seek=8";

var installIcons = "/usr/bin/test -e /home/view/current/fonts/icons.ttf && cp -u /home/view/current/fonts/icons.ttf /usr/share/fonts/truetype/";

function checkLibGPhotoUpdate(callback) {
	exec(getLibGPhoto2Version, function(err, stdout, stderr) {
		if(!err && stdout) {
			var parts = stdout.match(/([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/);
			if(parts && parts.length > 1 ) {
				var version = parts[1].trim();
				exports.libgphoto2Version = version;
				if(version != libgphoto2Version) {
					console.log("libgphoto2 update required (current version = " + version + ")");
					callback(null, true);
				} else {
					console.log("libgphoto2 is up to date");
					callback(null, false);
				}
			} else {
				callback("error getting version");
			}
		} else {
			callback("error getting version");
		}
	});
}

function installLibGPhoto(callback) {
	exports.updatingLibGphoto = true;
	exec(installLibGPhoto2, function(err) {
		exports.updatingLibGphoto = false;
		callback(err);
	});
}

function apiRequest(method, callback) {
	var req = https.request({method:'get', host:apiHost, path: apiEndpoint+method, headers: {'user-agent': 'VIEW-app'}}, function(res) {
		//console.log(`STATUS: ${res.statusCode}`);
		//console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
		res.setEncoding('utf8');
		var data = "";
		res.on('data', function(chunk) {
			data += chunk;
			//console.log(`BODY: ${chunk}`);
		});
		res.on('end', function() {
			var doc = JSON.parse(data);
			//console.log(doc);
			if(callback) callback(null, doc);
		});

	});
	req.end();
	req.on('error', function(err) {
		if(callback) callback(err);
	});
}

function download(href, path, callback) {
	var options = url.parse(href);
	options.headers = {'user-agent': 'VIEW-app'};
	options.method = "GET";
	//options.auth = username+':'+accessToken;

	var req = https.get(options, function(res) {
		//console.log(`STATUS: ${res.statusCode}`);
		//console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
		if(res.statusCode == 302 && res.headers.location) {
			download(res.headers.location, path, callback);
			return;
		}
		var fd = fs.openSync(path, 'w');
		if(!fd) callback("error creating " + path);
		res.on('data', function(chunk) {
			var bytes = 0;
			if(fd) bytes = fs.writeSync(fd, chunk, 0, chunk.length);
			//console.log("Writing " + bytes + " bytes to file ", fd, chunk.length);
		});
		res.on('end', function() {
			if(fd) {
				fs.closeSync(fd);
				callback(null, path);
			}
		});

	});
	req.end();
	req.on('error', function(err) {
		callback(err);
	});
}

function extract(zipPath, destFolder, callback) {
	var unzip = spawn('unzip', ['-q', zipPath, '-d', destFolder + '_zip_extract']);
	console.log("extracting...");
	unzip.once('close', function(code) {
		fs.readdir(destFolder + '_zip_extract', function(err, files) {
			console.log(err, files);
			if(files && files.length > 0) {
				fs.rename(destFolder + '_zip_extract' + '/' + files[0], destFolder, function(){
					fs.rmdir(destFolder + '_zip_extract');
					console.log("done extracting");
					callback(err, destFolder);
				});
			} else {
				callback(err, destFolder);
			}
		});
	});
}

function checkKernel(callback) {
	exec(getKernelVersion, function(err, stdout, stderr) {
		if(!err && stdout) {
			var currentKernel = stdout.trim();
			if(currentKernel == kernelVersion) {
				callback(null, false);
			} else {
				console.log("Current KERNEL:", currentKernel)
				callback(null, true);
			}
		} else {
			callback(err, false);
		}
	});
}

exports.updatingKernel = false;
function updateKernel(callback) {
	checkKernel(function(err1, needUpdate) {
		if(needUpdate) {
			console.log("KERNEL UPDATE REQUIRED");
			exports.updatingKernel = true;
			exec(doKernelUpdate, function(err, stdout, stderr) {
				exports.updatingKernel = false;
				if(err) {
					if(callback) callback(err);
					console.log("KERNEL UPDATE FAILED", err, stdout, stderr);
				} else {
					console.log("KERNEL UPDATE SUCCESS, running call back for reboot", err, stdout, stderr);
					if(callback) callback(false, true);
				}
			});
		} else {
			if(callback) callback(false);
			console.log("KERNEL UP TO DATE");
		}
	});
}

function checkUBoot(callback) {
	exec(getUBootVersion, function(err, stdout, stderr) {
		if(!err && stdout) {
			var currentUBoot = stdout.trim();
			if(currentUBoot == uBootVersion) {
				callback(null, false);
			} else {
				console.log("Current U-BOOT:", currentUBoot)
				callback(null, true);
			}
		} else {
			callback(err, false);
		}
	});
}

function updateUBoot(callback) {
	checkUBoot(function(err1, needUpdate) {
		if(needUpdate) {
			console.log("U-BOOT UPDATE REQUIRED");
			exec(doUBootUpdate, function(err, stdout, stderr) {
				if(err) {
					console.log("U-BOOT UPDATE FAILED", err, stdout, stderr);
				}
				if(callback) callback(err);
			});
		} else {
			if(callback) callback(false);
			console.log("U-BOOT UP TO DATE");
		}
	});
}

exports.version = "";
var installs = fs.readdirSync(baseInstallPath);
var current = "";
if(installs.indexOf('current') !== -1) {
	current = fs.readlinkSync(baseInstallPath + 'current');
	current = current.match(/[^\/]+$/)[0];
	console.log("current version:", current);
	exports.version = current;
}

exports.getCurrentVersion = function() {
	return current;
}

exports.developerMode = false;
var cachedVersions = null;
exports.getVersions = function(callback){
	if(cachedVersions) {
		callback(null, cachedVersions);
	} else {
		apiRequest('releases', function(err, res) {
			if(!err && res) {
				var installs = fs.readdirSync(baseInstallPath);
				var current = "";
				console.log(installs);
				if(installs.indexOf('current') !== -1) {
					current = fs.readlinkSync(baseInstallPath + 'current');
					current = current.match(/[^\/]+$/)[0];
					console.log("current version:", current);
				}
				var list = [];
				for(var i = 0; i < res.length; i++) {
					if(!res[i].prerelease || exports.developerMode) list.push({
						version: res[i].tag_name,
						description: res[i].name,
						notes: res[i].body,
						url: res[i].zipball_url,
						pre: res[i].prerelease,
						date: res[i].published_at,
						installed: installs.indexOf(res[i].tag_name) !== -1,
						current: res[i].tag_name == current
					});
				}
				cachedVersions = list;
				setTimeout(function(){
					cachedVersions = null; // clear cache after 5 minutes
				}, 1000*60*5);
				callback(null, list);
			} else {
				callback(err);
			}
		});
	}
};

exports.installing = false;
exports.installStatus = null;
exports.installVersion = function(versionInfo, callback, statusCallback) {
	exports.installing = true;
	var updateStatus = function(status) {
		console.log("INSTALL:", status);
		exports.installStatus = status;
		if(statusCallback) statusCallback(status);
	}
	if(versionInfo.version && versionInfo.url) {
		updateStatus('downloading...');
		download(versionInfo.url, baseInstallPath + "tmp.zip", function(err, info){
			if(err) {
				updateStatus('download failed.');
				exports.installing = false;
				callback(err);
			} else {
				updateStatus('extracting...');
				extract(baseInstallPath + "tmp.zip", baseInstallPath + versionInfo.version, function(err) {
					if(err) {
						updateStatus('extract failed.');
						exports.installing = false;
						callback(err);
					} else {
						fs.unlink(baseInstallPath + "tmp.zip");
						fs.writeFile(baseInstallPath + versionInfo.version + "/version.json", JSON.stringify(versionInfo), function(){
							updateStatus('done.');
							exports.installing = false;
							callback();
						});
					}
				});
			}
		});
	} else {
		callback("invalid version object");
	}
}

exports.setVersion = function(versionInfo, callback) {
	var installs = fs.readdirSync(baseInstallPath);
	console.log(installs);
	if(installs.indexOf('current') !== -1) {
		fs.unlinkSync(baseInstallPath + 'current');
	}
	fs.symlink(baseInstallPath + versionInfo.version, baseInstallPath + 'current', function(err) {
		callback && callback(err);
		console.log(err);
	});
}

exports.installIcons = function(callback) {
	exec(installIcons, callback);
}

exports.download = download;
exports.extract = extract;
exports.apiRequest = apiRequest;

exports.checkLibGPhotoUpdate = checkLibGPhotoUpdate;
exports.installLibGPhoto = installLibGPhoto;

exports.updateKernel = updateKernel;
exports.updateUBoot = updateUBoot;

<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var mysql      = require('mysql');
var db = require('./db'); // database utilities
var request = require('request');
var async = require('async');

// ******************************************************************************** item
function module_context(req, res, next)
{
  // *** PARAMETERS (SQL)
  this.objFormParameters = {
    table_name: "item_detail",
    primary_key: ["id"],
    autoincrement_column: "id",
    fields:[
      {name:"id",label:"#",type:"String",required:false,validation:null},
      {name:"isbn13",label:req.i18n.__("Numéro ISBN"),type:"String",required:false,validation:null,maximum_length:13},
      {name:"title",label:req.i18n.__("Titre"),type:"String",required:true,validation:null,maximum_length:255},
      {name:"author",label:req.i18n.__("Auteur"),type:"String",required:true,validation:null,maximum_length:255},
      {name:"description",label:req.i18n.__("Description (Synopsis)"),type:"String",required:false,validation:null,maximum_length:65535},
    ]
  };
  // To search we only have ONE field named "search" and a special SQL table with full text indexes
  this.objSearchParameters = {
    table_name: this.objFormParameters.table_name+"_search",
    primary_key: this.objFormParameters.primary_key,
    autoincrement_column: this.objFormParameters.autoincrement_column,
    fields:[
      {
        name:"search",label:req.i18n.__("Titre, Auteur, Description"),type:"String",required:true,validation:null,maximum_length:255,
        match_fields:[
          "title",
          "description"
        ]
      },
    ]
  };
  // *** PARAMETERS (MENU)
  this.objMenu = [{text:req.i18n.__("Gérer"),link:"/manage/"},{text:req.i18n.__("Livres"),link:"/item/"}];
  this.objMainMenu = {text:req.i18n.__("Menu principal"),link:"/"};
}

// GET menu
router.get('/', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  res.render('item/index', { title: req.app.locals.title, subtitle: null, menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu) });

});
// Get list
router.get('/list', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  db.list_record(req, res, next, objMyContext.objFormParameters, null /* objSQLOptions */, function(err, result, fields) {
    if (err) throw err;
    // Display records with "list" template
    res.render('item/list', { title: req.app.locals.title, subtitle: req.i18n.__("Liste"), menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objFormParameters, records:result });
  });

});

// ************************************************************************************* NEW
// GET new (form)
router.get('/new', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  res.render('item/new', {req:req, title: req.app.locals.title, subtitle: null, menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objFormParameters, message:{text:"Veuillez remplir le formulaire",type:"info"}, action:"new"});

});
// POST new (form validation then insert new record in database)
router.post('/new', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  if (req.body["_CANCEL"] != null)
  {
    // Cancel insert : Redirect to menu
    res.redirect('./');
  } // if (req.body["_CANCEL"] != null)
  else if (req.body["_OK"] != null)
  {
    db.insert_record(req, res, next, objMyContext.objFormParameters, function(err, result, fields, objSQLConnection) {
      if (err)
      {
        if (objSQLConnection)
        {
          objSQLConnection.end();
        }
        db.handle_error(err, res, "item/new", { title: req.app.locals.title, subtitle: null, menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objFormParameters, message:{text:"Ce livre est déjà dans l'inventaire ("+err+")",type:"error"}, action:"new" });
      }
      else
      {
        // Always add at least ONE exemplary of the book (item => item_detail)
        db.runsql("INSERT INTO item(item_detail_id) VALUES(LAST_INSERT_ID());" /* strSQL */, function(err, rows, fields) {
          if (err) throw err;
          if (objSQLConnection)
          {
            objSQLConnection.end();
          }
          // Redirect to list
          res.redirect('list'); // TODO res.redirect('view') compute parameters
        }, objSQLConnection);

      }
    });
  } // else if (req.body["_CANCEL"] != null)
  else
  {
    // Neither _OK nor _CANCEL: error!
    throw new Error("ERROR: Invalid form state (must be _OK or _CANCEL)");
  }

});

// ************************************************************************************* UPDATE
// POST update (form validation then update all fields in database)
router.post('/update', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  if (req.body["_CANCEL"] != null)
  {
    // Cancel : Redirect to menu
    res.redirect('./');
  } // if (req.body["_CANCEL"] != null)
  else if (req.body["_OK"] != null)
  {
    db.update_record(req, res, next, objMyContext.objFormParameters, function(err, result, fields, objSQLConnection) {
      if (err)
      {
        db.handle_error(err, res, "item/update", { title: req.app.locals.title, subtitle: null, menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objFormParameters, message:"Impossible de modifier ce livre ("+err+")" });
      }
      else
      {
        // Redirect to list
        res.redirect('list');

      }
    });
  } // else if (req.body["_CANCEL"] != null)
  else
  {
    // Neither _OK nor _CANCEL: error!
    throw new Error("ERROR: Invalid form state (must be _OK or _CANCEL)");
  }

});

// ************************************************************************************* DELETE
// POST delete (form validation then delete record in database)
router.post('/delete', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  if (req.body["_CANCEL"] != null)
  {
    // Cancel : Redirect to menu
    res.redirect('./');
  } // if (req.body["_CANCEL"] != null)
  else if (req.body["_OK"] != null)
  {
    db.delete_record(req, res, next, objMyContext.objFormParameters, function(err, result, fields, objSQLConnection) {
      if (err)
      {
        db.handle_error(err, res, "item/delete", { title: req.app.locals.title, subtitle: null, menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objFormParameters, message:"Impossible d'effacer ce livre ("+err+")" });
      }
      else
      {
        // Redirect to list
        res.redirect('list');

      }
    });
  } // else if (req.body["_CANCEL"] != null)
  else
  {
    // Neither _OK nor _CANCEL: error!
    throw new Error("ERROR: Invalid form state (must be _OK or _CANCEL)");
  }

});

// ************************************************************************************* VIEW
// GET view
router.get('/view', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  db.view_record(req, res, next, objMyContext.objFormParameters, function(err, result, fields) {
    if (err) throw err;
    // Display first record with "view" template
    res.render('item/view', { title: req.app.locals.title, subtitle: "Fiche", menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objFormParameters, record:result[0], message:null });
  });

});

// ************************************************************************************* WEB SERVICES
// GET web service (fetch isbn information)
router.get('/webservice', function(req, objLocalWebServiceResult, next) {

  var objMyContext = new module_context(req, objLocalWebServiceResult, next);
  var objWebServiceResult = {status:"KO"};

  // Must be something in the body
  if (!req.body)
  {
    console.log("ERROR: Web Service called with an empty body");
    return objLocalWebServiceResult.sendStatus(400);
  }

  // DEBUG
  console.log("req.query.isbn=%s\n",req.query.isbn);

  var strISBN = req.query.isbn;
  // ISBN must not be empty
  if (strISBN == null || strISBN == "")
  {
    console.log("ERROR: Web Service called with an empty isbn parameter");
    return objLocalWebServiceResult.sendStatus(400);
  }

  const urls= [
    "http://xisbn.worldcat.org/webservices/xid/isbn/"+encodeURIComponent(strISBN)+"?method=getMetadata&format=json&fl="+encodeURIComponent('*'),
    "https://www.googleapis.com/books/v1/volumes?q=isbn:"+encodeURIComponent(strISBN)
  ];
  async.map(urls, function (url, callback) {
    // DEBUG
    console.log("Calling Web Service "+url);
    const options = {
      url :  url,
      json : true
    };
    request(options,
      function(err, res, body) {
        // DEBUG
        console.log("Body = %j",body);
        callback(err, body);
      }
    );
  }, function (err, res) {

    // Handle errors gracefully
    if (err)
    {
      objLocalWebServiceResult.status = "KO";
      objLocalWebServiceResult.message = err;
      objLocalWebServiceResult.json(objWebServiceResult);
    }

    // DEBUG
    console.log("res=%j\n",res);

    if (res && res.length > 0)
    {
      // Response is ok : build a custom object for replying (with only the first item)
      for (var intResult in res)
      {
        // DEBUG
        console.log("res[intResult]=%j\n",res[intResult]);

        if (res[intResult].stat)
        {
          // Worldcat result
          if (res[intResult].stat == "ok" && res[intResult].list && res[intResult].list.length >0)
          {
            var objResultItem = res[intResult].list[0]; // TODO Handle multiple results? (let the user pick one?)
            if (objResultItem.author)
            {
              var strNewValue = objResultItem.author; // TODO Handle multiple authors?
              // WARNING: don't overwrite result from another Web Service, unless this result is longuer (ok, it's a silly way to finding the most appropriate answer)
              if (objWebServiceResult.authors == null || objWebServiceResult.authors.length < strNewValue.length)
              {
                objWebServiceResult.authors = strNewValue;
              }
            }
            if (objResultItem.title)
            {
              objWebServiceResult.title = objResultItem.title;
            }
            if (objResultItem.isbn && objResultItem.isbn.length > 0 && objResultItem.isbn[0])
            {
              objWebServiceResult.isbn = objResultItem.isbn[0]; // TODO Handle multiple ISBN?
            }
            // TODO handle description? publisher? language? hyperlink to more information on google?
            objWebServiceResult.status = "OK";
          }
          else
          {
            // Worldcat error : ignore it
          }
        }
        else if (res[intResult].kind)
        {
          // Google result
          if (res[intResult].totalItems > 0 && res[intResult].items.length && res[intResult].items[0].volumeInfo)
          {
            var objResultItem = res[intResult].items[0].volumeInfo; // TODO Handle multiple results? (let the user pick one?)
            if (objResultItem.authors)
            {
              var strNewValue = objResultItem.authors.join(", ");
              // WARNING: don't overwrite result from another Web Service, unless this result is longuer (ok, it's a silly way to finding the most appropriate answer)
              if (objWebServiceResult.authors == null || objWebServiceResult.authors.length < strNewValue.length)
              {
                objWebServiceResult.authors = strNewValue;
              }
            }
            if (objResultItem.title)
            {
              objWebServiceResult.title = objResultItem.title;
            }
            if (objResultItem.description)
            {
              objWebServiceResult.description = objResultItem.description;
            }
            if (objResultItem.industryIdentifiers && objResultItem.industryIdentifiers.length > 0)
            {
              for (var intID in objResultItem.industryIdentifiers)
              {
                if (objResultItem.industryIdentifiers[intID].type == "ISBN_13")
                {
                  objWebServiceResult.isbn = objResultItem.industryIdentifiers[intID].identifier;
                }
              }
            }
            // TODO handle publisher? language? hyperlink to more information on google?
            objWebServiceResult.status = "OK";
          }
          else
          {
            // Google error : ignore it
          }
        }
        else
        {
          // Unknown format - fatal error
          objWebServiceResult.message = "Unknown format: can't find book with isbn \""+strISBN+"\"";
        }

      } // for (var intResult in res)

      // If no web service returned a result, set a generic error message
      if (objWebServiceResult.status == "KO")
      {
        objWebServiceResult.message = "Unknown error: can't find book with isbn \""+strISBN+"\"";
      }

      // DEBUG
      console.log("objWebServiceResult=%j", objWebServiceResult);

      // Return final result
      objLocalWebServiceResult.json(objWebServiceResult);

    } // if (res && res.length > 0)
  });

});

// ************************************************************************************* SEARCH
// GET search (form)
router.get('/search', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  res.render('item/new', {req:req, title: req.app.locals.title, subtitle: "Recherche", menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objSearchParameters, message:{text:"Veuillez remplir le formulaire",type:"info"}, action:"search"});

});
// POST search (form validation then search records in database)
router.post('/search', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  if (req.body["_CANCEL"] != null)
  {
    // Cancel insert : Redirect to menu
    res.redirect('./');
  } // if (req.body["_CANCEL"] != null)
  else if (req.body["_OK"] != null)
  {
    db.search_record(req, res, next, objMyContext.objSearchParameters, null /* objSQLOptions */, function(err, result, fields) {
      if (err) throw err;
      // Display records with "list" template
      res.render('item/list', { title: req.app.locals.title, subtitle: "Liste", menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objFormParameters, records:result });
    });
  } // else if (req.body["_CANCEL"] != null)
  else
  {
    // Neither _OK nor _CANCEL: error!
    throw new Error("ERROR: Invalid form state (must be _OK or _CANCEL)");
  }

});

module.exports = router;
<commit_msg>enhanced I18N support (missing strings)<commit_after>var express = require('express');
var router = express.Router();
var mysql      = require('mysql');
var db = require('./db'); // database utilities
var request = require('request');
var async = require('async');

// ******************************************************************************** item
function module_context(req, res, next)
{
  // *** PARAMETERS (SQL)
  this.objFormParameters = {
    table_name: "item_detail",
    primary_key: ["id"],
    autoincrement_column: "id",
    fields:[
      {name:"id",label:"#",type:"String",required:false,validation:null},
      {name:"isbn13",label:req.i18n.__("Numéro ISBN"),type:"String",required:false,validation:null,maximum_length:13},
      {name:"title",label:req.i18n.__("Titre"),type:"String",required:true,validation:null,maximum_length:255},
      {name:"author",label:req.i18n.__("Auteur"),type:"String",required:true,validation:null,maximum_length:255},
      {name:"description",label:req.i18n.__("Description (Synopsis)"),type:"String",required:false,validation:null,maximum_length:65535},
    ]
  };
  // To search we only have ONE field named "search" and a special SQL table with full text indexes
  this.objSearchParameters = {
    table_name: this.objFormParameters.table_name+"_search",
    primary_key: this.objFormParameters.primary_key,
    autoincrement_column: this.objFormParameters.autoincrement_column,
    fields:[
      {
        name:"search",label:req.i18n.__("Titre, Auteur, Description"),type:"String",required:true,validation:null,maximum_length:255,
        match_fields:[
          "title",
          "description"
        ]
      },
    ]
  };
  // *** PARAMETERS (MENU)
  this.objMenu = [{text:req.i18n.__("Gérer"),link:"/manage/"},{text:req.i18n.__("Livres"),link:"/item/"}];
  this.objMainMenu = {text:req.i18n.__("Menu principal"),link:"/"};
}

// GET menu
router.get('/', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  res.render('item/index', { title: req.app.locals.title, subtitle: null, menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu) });

});
// Get list
router.get('/list', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  db.list_record(req, res, next, objMyContext.objFormParameters, null /* objSQLOptions */, function(err, result, fields) {
    if (err) throw err;
    // Display records with "list" template
    res.render('item/list', { title: req.app.locals.title, subtitle: req.i18n.__("Liste"), menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objFormParameters, records:result });
  });

});

// ************************************************************************************* NEW
// GET new (form)
router.get('/new', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  res.render('item/new', {req:req, title: req.app.locals.title, subtitle: null, menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objFormParameters, message:{text:"Veuillez remplir le formulaire",type:"info"}, action:"new"});

});
// POST new (form validation then insert new record in database)
router.post('/new', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  if (req.body["_CANCEL"] != null)
  {
    // Cancel insert : Redirect to menu
    res.redirect('./');
  } // if (req.body["_CANCEL"] != null)
  else if (req.body["_OK"] != null)
  {
    db.insert_record(req, res, next, objMyContext.objFormParameters, function(err, result, fields, objSQLConnection) {
      if (err)
      {
        if (objSQLConnection)
        {
          objSQLConnection.end();
        }
        db.handle_error(err, res, "item/new", { title: req.app.locals.title, subtitle: null, menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objFormParameters, message:{text:"Ce livre est déjà dans l'inventaire ("+err+")",type:"error"}, action:"new" });
      }
      else
      {
        // Always add at least ONE exemplary of the book (item => item_detail)
        db.runsql("INSERT INTO item(item_detail_id) VALUES(LAST_INSERT_ID());" /* strSQL */, function(err, rows, fields) {
          if (err) throw err;
          if (objSQLConnection)
          {
            objSQLConnection.end();
          }
          // Redirect to list
          res.redirect('list'); // TODO res.redirect('view') compute parameters
        }, objSQLConnection);

      }
    });
  } // else if (req.body["_CANCEL"] != null)
  else
  {
    // Neither _OK nor _CANCEL: error!
    throw new Error("ERROR: Invalid form state (must be _OK or _CANCEL)");
  }

});

// ************************************************************************************* UPDATE
// POST update (form validation then update all fields in database)
router.post('/update', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  if (req.body["_CANCEL"] != null)
  {
    // Cancel : Redirect to menu
    res.redirect('./');
  } // if (req.body["_CANCEL"] != null)
  else if (req.body["_OK"] != null)
  {
    db.update_record(req, res, next, objMyContext.objFormParameters, function(err, result, fields, objSQLConnection) {
      if (err)
      {
        db.handle_error(err, res, "item/update", { title: req.app.locals.title, subtitle: null, menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objFormParameters, message:"Impossible de modifier ce livre ("+err+")" });
      }
      else
      {
        // Redirect to list
        res.redirect('list');

      }
    });
  } // else if (req.body["_CANCEL"] != null)
  else
  {
    // Neither _OK nor _CANCEL: error!
    throw new Error("ERROR: Invalid form state (must be _OK or _CANCEL)");
  }

});

// ************************************************************************************* DELETE
// POST delete (form validation then delete record in database)
router.post('/delete', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  if (req.body["_CANCEL"] != null)
  {
    // Cancel : Redirect to menu
    res.redirect('./');
  } // if (req.body["_CANCEL"] != null)
  else if (req.body["_OK"] != null)
  {
    db.delete_record(req, res, next, objMyContext.objFormParameters, function(err, result, fields, objSQLConnection) {
      if (err)
      {
        db.handle_error(err, res, "item/delete", { title: req.app.locals.title, subtitle: null, menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objFormParameters, message:"Impossible d'effacer ce livre ("+err+")" });
      }
      else
      {
        // Redirect to list
        res.redirect('list');

      }
    });
  } // else if (req.body["_CANCEL"] != null)
  else
  {
    // Neither _OK nor _CANCEL: error!
    throw new Error("ERROR: Invalid form state (must be _OK or _CANCEL)");
  }

});

// ************************************************************************************* VIEW
// GET view
router.get('/view', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  db.view_record(req, res, next, objMyContext.objFormParameters, function(err, result, fields) {
    if (err) throw err;
    // Display first record with "view" template
    res.render('item/view', { title: req.app.locals.title, subtitle: req.i18n.__("Fiche"), menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objFormParameters, record:result[0], message:null });
  });

});

// ************************************************************************************* WEB SERVICES
// GET web service (fetch isbn information)
router.get('/webservice', function(req, objLocalWebServiceResult, next) {

  var objMyContext = new module_context(req, objLocalWebServiceResult, next);
  var objWebServiceResult = {status:"KO"};

  // Must be something in the body
  if (!req.body)
  {
    console.log("ERROR: Web Service called with an empty body");
    return objLocalWebServiceResult.sendStatus(400);
  }

  // DEBUG
  console.log("req.query.isbn=%s\n",req.query.isbn);

  var strISBN = req.query.isbn;
  // ISBN must not be empty
  if (strISBN == null || strISBN == "")
  {
    console.log("ERROR: Web Service called with an empty isbn parameter");
    return objLocalWebServiceResult.sendStatus(400);
  }

  const urls= [
    "http://xisbn.worldcat.org/webservices/xid/isbn/"+encodeURIComponent(strISBN)+"?method=getMetadata&format=json&fl="+encodeURIComponent('*'),
    "https://www.googleapis.com/books/v1/volumes?q=isbn:"+encodeURIComponent(strISBN)
  ];
  async.map(urls, function (url, callback) {
    // DEBUG
    console.log("Calling Web Service "+url);
    const options = {
      url :  url,
      json : true
    };
    request(options,
      function(err, res, body) {
        // DEBUG
        console.log("Body = %j",body);
        callback(err, body);
      }
    );
  }, function (err, res) {

    // Handle errors gracefully
    if (err)
    {
      objLocalWebServiceResult.status = "KO";
      objLocalWebServiceResult.message = err;
      objLocalWebServiceResult.json(objWebServiceResult);
    }

    // DEBUG
    console.log("res=%j\n",res);

    if (res && res.length > 0)
    {
      // Response is ok : build a custom object for replying (with only the first item)
      for (var intResult in res)
      {
        // DEBUG
        console.log("res[intResult]=%j\n",res[intResult]);

        if (res[intResult].stat)
        {
          // Worldcat result
          if (res[intResult].stat == "ok" && res[intResult].list && res[intResult].list.length >0)
          {
            var objResultItem = res[intResult].list[0]; // TODO Handle multiple results? (let the user pick one?)
            if (objResultItem.author)
            {
              var strNewValue = objResultItem.author; // TODO Handle multiple authors?
              // WARNING: don't overwrite result from another Web Service, unless this result is longuer (ok, it's a silly way to finding the most appropriate answer)
              if (objWebServiceResult.authors == null || objWebServiceResult.authors.length < strNewValue.length)
              {
                objWebServiceResult.authors = strNewValue;
              }
            }
            if (objResultItem.title)
            {
              objWebServiceResult.title = objResultItem.title;
            }
            if (objResultItem.isbn && objResultItem.isbn.length > 0 && objResultItem.isbn[0])
            {
              objWebServiceResult.isbn = objResultItem.isbn[0]; // TODO Handle multiple ISBN?
            }
            // TODO handle description? publisher? language? hyperlink to more information on google?
            objWebServiceResult.status = "OK";
          }
          else
          {
            // Worldcat error : ignore it
          }
        }
        else if (res[intResult].kind)
        {
          // Google result
          if (res[intResult].totalItems > 0 && res[intResult].items.length && res[intResult].items[0].volumeInfo)
          {
            var objResultItem = res[intResult].items[0].volumeInfo; // TODO Handle multiple results? (let the user pick one?)
            if (objResultItem.authors)
            {
              var strNewValue = objResultItem.authors.join(", ");
              // WARNING: don't overwrite result from another Web Service, unless this result is longuer (ok, it's a silly way to finding the most appropriate answer)
              if (objWebServiceResult.authors == null || objWebServiceResult.authors.length < strNewValue.length)
              {
                objWebServiceResult.authors = strNewValue;
              }
            }
            if (objResultItem.title)
            {
              objWebServiceResult.title = objResultItem.title;
            }
            if (objResultItem.description)
            {
              objWebServiceResult.description = objResultItem.description;
            }
            if (objResultItem.industryIdentifiers && objResultItem.industryIdentifiers.length > 0)
            {
              for (var intID in objResultItem.industryIdentifiers)
              {
                if (objResultItem.industryIdentifiers[intID].type == "ISBN_13")
                {
                  objWebServiceResult.isbn = objResultItem.industryIdentifiers[intID].identifier;
                }
              }
            }
            // TODO handle publisher? language? hyperlink to more information on google?
            objWebServiceResult.status = "OK";
          }
          else
          {
            // Google error : ignore it
          }
        }
        else
        {
          // Unknown format - fatal error
          objWebServiceResult.message = "Unknown format: can't find book with isbn \""+strISBN+"\"";
        }

      } // for (var intResult in res)

      // If no web service returned a result, set a generic error message
      if (objWebServiceResult.status == "KO")
      {
        objWebServiceResult.message = "Unknown error: can't find book with isbn \""+strISBN+"\"";
      }

      // DEBUG
      console.log("objWebServiceResult=%j", objWebServiceResult);

      // Return final result
      objLocalWebServiceResult.json(objWebServiceResult);

    } // if (res && res.length > 0)
  });

});

// ************************************************************************************* SEARCH
// GET search (form)
router.get('/search', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  res.render('item/new', {req:req, title: req.app.locals.title, subtitle: req.i18n.__("Recherche"), menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objSearchParameters, message:{text:"Veuillez remplir le formulaire",type:"info"}, action:"search"});

});
// POST search (form validation then search records in database)
router.post('/search', function(req, res, next) {

  var objMyContext = new module_context(req, res, next);
  if (req.body["_CANCEL"] != null)
  {
    // Cancel insert : Redirect to menu
    res.redirect('./');
  } // if (req.body["_CANCEL"] != null)
  else if (req.body["_OK"] != null)
  {
    db.search_record(req, res, next, objMyContext.objSearchParameters, null /* objSQLOptions */, function(err, result, fields) {
      if (err) throw err;
      // Display records with "list" template
      res.render('item/list', { title: req.app.locals.title, subtitle: req.i18n.__("Liste"), menus:[objMyContext.objMainMenu].concat(objMyContext.objMenu), form:objMyContext.objFormParameters, records:result });
    });
  } // else if (req.body["_CANCEL"] != null)
  else
  {
    // Neither _OK nor _CANCEL: error!
    throw new Error("ERROR: Invalid form state (must be _OK or _CANCEL)");
  }

});

module.exports = router;
<|endoftext|>