<commit_before>var express = require('express')
  , router  = express.Router()
  , log     = require('magic-log')
  , view    = require('magic-view')
;

router.get('/', function(req, res, next) {
  log.info('magic-router', '/ route called');
  view.render.page(req, res, next);
});

router.get('/:page', function(req, res, next) {
  log.info('magic-router', '/:page route called', req.params.page);
  view.render.page(req, res, next);
});

module.exports = router;
<commit_msg>router is now simplified<commit_after>var express = require('express')
  , router  = express.Router()
  , log     = require('magic-log')
  , view    = require('magic-view')
;

router.get('/', view.render.page);
router.get('/:page', view.render.page);

module.exports = router;
<|endoftext|>


<commit_before>beforeEach(function () {
	this.addMatchers({
		// Expects that property is synchronous
		toHold: function () {
			var actual = this.actual;
			var notText = this.isNot ? " not" : "";
			/* global window */
			var quiet = window && !(/verbose=true/).test(window.location.search);

			var r = jsc.check(actual, { quiet: quiet });

			var counterExampleText = r === true ? "" : "Counter example found: " + JSON.stringify(r.counterexample);

			this.message = function() {
				return "Expected property to " + notText + " to not hold." + counterExampleText;
			};

			return r === true;
		},
	});
});<commit_msg>Fix jasmine helper<commit_after>beforeEach(function () {
	this.addMatchers({
		// Expects that property is synchronous
		toHold: function () {
			var actual = this.actual;
			var notText = this.isNot ? " not" : "";
			/* global window */
			var quiet = window && !(/verbose=true/).test(window.location.search);

			var r = jsc.check(actual, { quiet: quiet });

			var counterExampleText = r === true ? "" : "Counterexample found: " + r.counterexamplestr;

			this.message = function() {
				return "Expected property to" + notText + " hold. " + counterExampleText;
			};

			return r === true;
		},
	});
});<|endoftext|>


<commit_before>module.exports = function(app) {
app.get('/', function(request, response) {
  response.sendFile(__dirname + '/site.htm');
});

app.get('/signin', function(request, response) {
  response.sendFile(__dirname + '/signin.html');
});

app.get('/workoutentry', function(request, response) {
  response.sendFile(__dirname + '/workoutentry.htm');
});
}<commit_msg>editing routes.js<commit_after>module.exports = function(app) {
app.get('/', function(request, response) {
  response.sendFile(__dirname + '/site.htm');
});

app.get('/signin', function(request, response) {
  response.sendFile(__dirname + '/signin.html');
});

app.get('/workoutentry', function(request, response) {
  response.sendFile(__dirname + '/workoutentry.htm');
});

};<|endoftext|>


<commit_before>'use strict';

function ensureAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    return next();
  }
  res.set('X-Auth-Required', 'true');
  res.redirect('/login/?returnUrl='+ encodeURIComponent(req.originalUrl));
}

function ensureAdmin(req, res, next) {
  if (req.user.canPlayRoleOf('admin')) {
    return next();
  }
  res.redirect('/');
}

function ensureAccount(req, res, next) {
  if (req.user.canPlayRoleOf('account')) {
    if (req.app.get('require-account-verification')) {
      if (req.user.roles.account.isVerified !== 'yes' && !/^\/account\/verification\//.test(req.url)) {
        return res.redirect('/account/verification/');
      }
    }
    return next();
  }
  res.redirect('/');
}

exports = module.exports = function(app, passport) {
  // CORS
  app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
    res.header("Access-Control-Allow-Headers", "Content-Type");
    next();
  });

  //front end
  app.get('/', require('./views/index').init);
  app.get('/about/', require('./views/about/index').init);
  app.get('/contact/', require('./views/contact/index').init);
  app.post('/contact/', require('./views/contact/index').sendMessage);

  //CUSTOM
  app.get('/pages/', require('./views/pages/index').find);
  app.post('/pages/', require('./views/pages/index').create);
  app.get('/pages/:id/', require('./views/pages/index').read);
  app.get('/pages/:id/deals/', require('./views/pages/index').deals);
	app.get('/pages/:id/preview/', require('./views/pages/index').preview);

  //app.get('/deals/', require('./views/deals/index').find);
  app.post('/deals/', require('./views/deals/index').create);
  app.get('/deals/:id/', require('./views/deals/index').read);
  app.put('/deals/:id/', require('./views/deals/index').update);

  //sign up
  app.get('/signup/', require('./views/signup/index').init);
  app.post('/signup/', require('./views/signup/index').signup);

  //social sign up
  app.post('/signup/social/', require('./views/signup/index').signupSocial);
  app.get('/signup/twitter/', passport.authenticate('twitter', { callbackURL: '/signup/twitter/callback/' }));
  app.get('/signup/twitter/callback/', require('./views/signup/index').signupTwitter);
  app.get('/signup/github/', passport.authenticate('github', { callbackURL: '/signup/github/callback/' }));
  app.get('/signup/github/callback/', require('./views/signup/index').signupGitHub);
  app.get('/signup/facebook/', passport.authenticate('facebook', { callbackURL: '/signup/facebook/callback/' }));
  app.get('/signup/facebook/callback/', require('./views/signup/index').signupFacebook);

  //login/out
  app.get('/login/', require('./views/login/index').init);
  app.post('/login/', require('./views/login/index').login);
  app.get('/login/forgot/', require('./views/login/forgot/index').init);
  app.post('/login/forgot/', require('./views/login/forgot/index').send);
  app.get('/login/reset/', require('./views/login/reset/index').init);
  app.get('/login/reset/:token/', require('./views/login/reset/index').init);
  app.put('/login/reset/:token/', require('./views/login/reset/index').set);
  app.get('/logout/', require('./views/logout/index').init);

  //social login
  app.get('/login/twitter/', passport.authenticate('twitter', { callbackURL: '/login/twitter/callback/' }));
  app.get('/login/twitter/callback/', require('./views/login/index').loginTwitter);
  app.get('/login/github/', passport.authenticate('github', { callbackURL: '/login/github/callback/' }));
  app.get('/login/github/callback/', require('./views/login/index').loginGitHub);
  app.get('/login/facebook/', passport.authenticate('facebook', { callbackURL: '/login/facebook/callback/' }));
  app.get('/login/facebook/callback/', require('./views/login/index').loginFacebook);

  //admin
  app.all('/admin*', ensureAuthenticated);
  app.all('/admin*', ensureAdmin);
  app.get('/admin/', require('./views/admin/index').init);

  //admin > users
  app.get('/admin/users/', require('./views/admin/users/index').find);
  app.post('/admin/users/', require('./views/admin/users/index').create);
  app.get('/admin/users/:id/', require('./views/admin/users/index').read);
  app.put('/admin/users/:id/', require('./views/admin/users/index').update);
  app.put('/admin/users/:id/password/', require('./views/admin/users/index').password);
  app.put('/admin/users/:id/role-admin/', require('./views/admin/users/index').linkAdmin);
  app.delete('/admin/users/:id/role-admin/', require('./views/admin/users/index').unlinkAdmin);
  app.put('/admin/users/:id/role-account/', require('./views/admin/users/index').linkAccount);
  app.delete('/admin/users/:id/role-account/', require('./views/admin/users/index').unlinkAccount);
  app.delete('/admin/users/:id/', require('./views/admin/users/index').delete);

  //admin > administrators
  app.get('/admin/administrators/', require('./views/admin/administrators/index').find);
  app.post('/admin/administrators/', require('./views/admin/administrators/index').create);
  app.get('/admin/administrators/:id/', require('./views/admin/administrators/index').read);
  app.put('/admin/administrators/:id/', require('./views/admin/administrators/index').update);
  app.put('/admin/administrators/:id/permissions/', require('./views/admin/administrators/index').permissions);
  app.put('/admin/administrators/:id/groups/', require('./views/admin/administrators/index').groups);
  app.put('/admin/administrators/:id/user/', require('./views/admin/administrators/index').linkUser);
  app.delete('/admin/administrators/:id/user/', require('./views/admin/administrators/index').unlinkUser);
  app.delete('/admin/administrators/:id/', require('./views/admin/administrators/index').delete);

  //admin > admin groups
  app.get('/admin/admin-groups/', require('./views/admin/admin-groups/index').find);
  app.post('/admin/admin-groups/', require('./views/admin/admin-groups/index').create);
  app.get('/admin/admin-groups/:id/', require('./views/admin/admin-groups/index').read);
  app.put('/admin/admin-groups/:id/', require('./views/admin/admin-groups/index').update);
  app.put('/admin/admin-groups/:id/permissions/', require('./views/admin/admin-groups/index').permissions);
  app.delete('/admin/admin-groups/:id/', require('./views/admin/admin-groups/index').delete);

  //admin > accounts
  app.get('/admin/accounts/', require('./views/admin/accounts/index').find);
  app.post('/admin/accounts/', require('./views/admin/accounts/index').create);
  app.get('/admin/accounts/:id/', require('./views/admin/accounts/index').read);
  app.put('/admin/accounts/:id/', require('./views/admin/accounts/index').update);
  app.put('/admin/accounts/:id/user/', require('./views/admin/accounts/index').linkUser);
  app.delete('/admin/accounts/:id/user/', require('./views/admin/accounts/index').unlinkUser);
  app.post('/admin/accounts/:id/notes/', require('./views/admin/accounts/index').newNote);
  app.post('/admin/accounts/:id/status/', require('./views/admin/accounts/index').newStatus);
  app.delete('/admin/accounts/:id/', require('./views/admin/accounts/index').delete);

  //admin > statuses
  app.get('/admin/statuses/', require('./views/admin/statuses/index').find);
  app.post('/admin/statuses/', require('./views/admin/statuses/index').create);
  app.get('/admin/statuses/:id/', require('./views/admin/statuses/index').read);
  app.put('/admin/statuses/:id/', require('./views/admin/statuses/index').update);
  app.delete('/admin/statuses/:id/', require('./views/admin/statuses/index').delete);

  //admin > categories
  app.get('/admin/categories/', require('./views/admin/categories/index').find);
  app.post('/admin/categories/', require('./views/admin/categories/index').create);
  app.get('/admin/categories/:id/', require('./views/admin/categories/index').read);
  app.put('/admin/categories/:id/', require('./views/admin/categories/index').update);
  app.delete('/admin/categories/:id/', require('./views/admin/categories/index').delete);

  //admin > search
  app.get('/admin/search/', require('./views/admin/search/index').find);

  //account
  app.all('/account*', ensureAuthenticated);
  app.all('/account*', ensureAccount);
  app.get('/account/', require('./views/account/index').init);

  //account > verification
  app.get('/account/verification/', require('./views/account/verification/index').init);
  app.post('/account/verification/', require('./views/account/verification/index').resendVerification);
  app.get('/account/verification/:token/', require('./views/account/verification/index').verify);

  //account > settings
  app.get('/account/settings/', require('./views/account/settings/index').init);
  app.put('/account/settings/', require('./views/account/settings/index').update);
  app.put('/account/settings/identity/', require('./views/account/settings/index').identity);
  app.put('/account/settings/password/', require('./views/account/settings/index').password);

  //account > settings > social
  app.get('/account/settings/twitter/', passport.authenticate('twitter', { callbackURL: '/account/settings/twitter/callback/' }));
  app.get('/account/settings/twitter/callback/', require('./views/account/settings/index').connectTwitter);
  app.get('/account/settings/twitter/disconnect/', require('./views/account/settings/index').disconnectTwitter);
  app.get('/account/settings/github/', passport.authenticate('github', { callbackURL: '/account/settings/github/callback/' }));
  app.get('/account/settings/github/callback/', require('./views/account/settings/index').connectGitHub);
  app.get('/account/settings/github/disconnect/', require('./views/account/settings/index').disconnectGitHub);
  app.get('/account/settings/facebook/', passport.authenticate('facebook', { callbackURL: '/account/settings/facebook/callback/' }));
  app.get('/account/settings/facebook/callback/', require('./views/account/settings/index').connectFacebook);
  app.get('/account/settings/facebook/disconnect/', require('./views/account/settings/index').disconnectFacebook);

  //route not found
  app.all('*', require('./views/http/index').http404);
};
<commit_msg>'cors'<commit_after>'use strict';

function ensureAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    return next();
  }
  res.set('X-Auth-Required', 'true');
  res.redirect('/login/?returnUrl='+ encodeURIComponent(req.originalUrl));
}

function ensureAdmin(req, res, next) {
  if (req.user.canPlayRoleOf('admin')) {
    return next();
  }
  res.redirect('/');
}

function ensureAccount(req, res, next) {
  if (req.user.canPlayRoleOf('account')) {
    if (req.app.get('require-account-verification')) {
      if (req.user.roles.account.isVerified !== 'yes' && !/^\/account\/verification\//.test(req.url)) {
        return res.redirect('/account/verification/');
      }
    }
    return next();
  }
  res.redirect('/');
}

exports = module.exports = function(app, passport) {
  // CORS
  app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
    res.header("Access-Control-Allow-Headers", "Content-Type, X-Requested-With");
    next();
  });

  //front end
  app.get('/', require('./views/index').init);
  app.get('/about/', require('./views/about/index').init);
  app.get('/contact/', require('./views/contact/index').init);
  app.post('/contact/', require('./views/contact/index').sendMessage);

  //CUSTOM
  app.get('/pages/', require('./views/pages/index').find);
  app.post('/pages/', require('./views/pages/index').create);
  app.get('/pages/:id/', require('./views/pages/index').read);
  app.get('/pages/:id/deals/', require('./views/pages/index').deals);
	app.get('/pages/:id/preview/', require('./views/pages/index').preview);

  //app.get('/deals/', require('./views/deals/index').find);
  app.post('/deals/', require('./views/deals/index').create);
  app.get('/deals/:id/', require('./views/deals/index').read);
  app.put('/deals/:id/', require('./views/deals/index').update);

  //sign up
  app.get('/signup/', require('./views/signup/index').init);
  app.post('/signup/', require('./views/signup/index').signup);

  //social sign up
  app.post('/signup/social/', require('./views/signup/index').signupSocial);
  app.get('/signup/twitter/', passport.authenticate('twitter', { callbackURL: '/signup/twitter/callback/' }));
  app.get('/signup/twitter/callback/', require('./views/signup/index').signupTwitter);
  app.get('/signup/github/', passport.authenticate('github', { callbackURL: '/signup/github/callback/' }));
  app.get('/signup/github/callback/', require('./views/signup/index').signupGitHub);
  app.get('/signup/facebook/', passport.authenticate('facebook', { callbackURL: '/signup/facebook/callback/' }));
  app.get('/signup/facebook/callback/', require('./views/signup/index').signupFacebook);

  //login/out
  app.get('/login/', require('./views/login/index').init);
  app.post('/login/', require('./views/login/index').login);
  app.get('/login/forgot/', require('./views/login/forgot/index').init);
  app.post('/login/forgot/', require('./views/login/forgot/index').send);
  app.get('/login/reset/', require('./views/login/reset/index').init);
  app.get('/login/reset/:token/', require('./views/login/reset/index').init);
  app.put('/login/reset/:token/', require('./views/login/reset/index').set);
  app.get('/logout/', require('./views/logout/index').init);

  //social login
  app.get('/login/twitter/', passport.authenticate('twitter', { callbackURL: '/login/twitter/callback/' }));
  app.get('/login/twitter/callback/', require('./views/login/index').loginTwitter);
  app.get('/login/github/', passport.authenticate('github', { callbackURL: '/login/github/callback/' }));
  app.get('/login/github/callback/', require('./views/login/index').loginGitHub);
  app.get('/login/facebook/', passport.authenticate('facebook', { callbackURL: '/login/facebook/callback/' }));
  app.get('/login/facebook/callback/', require('./views/login/index').loginFacebook);

  //admin
  app.all('/admin*', ensureAuthenticated);
  app.all('/admin*', ensureAdmin);
  app.get('/admin/', require('./views/admin/index').init);

  //admin > users
  app.get('/admin/users/', require('./views/admin/users/index').find);
  app.post('/admin/users/', require('./views/admin/users/index').create);
  app.get('/admin/users/:id/', require('./views/admin/users/index').read);
  app.put('/admin/users/:id/', require('./views/admin/users/index').update);
  app.put('/admin/users/:id/password/', require('./views/admin/users/index').password);
  app.put('/admin/users/:id/role-admin/', require('./views/admin/users/index').linkAdmin);
  app.delete('/admin/users/:id/role-admin/', require('./views/admin/users/index').unlinkAdmin);
  app.put('/admin/users/:id/role-account/', require('./views/admin/users/index').linkAccount);
  app.delete('/admin/users/:id/role-account/', require('./views/admin/users/index').unlinkAccount);
  app.delete('/admin/users/:id/', require('./views/admin/users/index').delete);

  //admin > administrators
  app.get('/admin/administrators/', require('./views/admin/administrators/index').find);
  app.post('/admin/administrators/', require('./views/admin/administrators/index').create);
  app.get('/admin/administrators/:id/', require('./views/admin/administrators/index').read);
  app.put('/admin/administrators/:id/', require('./views/admin/administrators/index').update);
  app.put('/admin/administrators/:id/permissions/', require('./views/admin/administrators/index').permissions);
  app.put('/admin/administrators/:id/groups/', require('./views/admin/administrators/index').groups);
  app.put('/admin/administrators/:id/user/', require('./views/admin/administrators/index').linkUser);
  app.delete('/admin/administrators/:id/user/', require('./views/admin/administrators/index').unlinkUser);
  app.delete('/admin/administrators/:id/', require('./views/admin/administrators/index').delete);

  //admin > admin groups
  app.get('/admin/admin-groups/', require('./views/admin/admin-groups/index').find);
  app.post('/admin/admin-groups/', require('./views/admin/admin-groups/index').create);
  app.get('/admin/admin-groups/:id/', require('./views/admin/admin-groups/index').read);
  app.put('/admin/admin-groups/:id/', require('./views/admin/admin-groups/index').update);
  app.put('/admin/admin-groups/:id/permissions/', require('./views/admin/admin-groups/index').permissions);
  app.delete('/admin/admin-groups/:id/', require('./views/admin/admin-groups/index').delete);

  //admin > accounts
  app.get('/admin/accounts/', require('./views/admin/accounts/index').find);
  app.post('/admin/accounts/', require('./views/admin/accounts/index').create);
  app.get('/admin/accounts/:id/', require('./views/admin/accounts/index').read);
  app.put('/admin/accounts/:id/', require('./views/admin/accounts/index').update);
  app.put('/admin/accounts/:id/user/', require('./views/admin/accounts/index').linkUser);
  app.delete('/admin/accounts/:id/user/', require('./views/admin/accounts/index').unlinkUser);
  app.post('/admin/accounts/:id/notes/', require('./views/admin/accounts/index').newNote);
  app.post('/admin/accounts/:id/status/', require('./views/admin/accounts/index').newStatus);
  app.delete('/admin/accounts/:id/', require('./views/admin/accounts/index').delete);

  //admin > statuses
  app.get('/admin/statuses/', require('./views/admin/statuses/index').find);
  app.post('/admin/statuses/', require('./views/admin/statuses/index').create);
  app.get('/admin/statuses/:id/', require('./views/admin/statuses/index').read);
  app.put('/admin/statuses/:id/', require('./views/admin/statuses/index').update);
  app.delete('/admin/statuses/:id/', require('./views/admin/statuses/index').delete);

  //admin > categories
  app.get('/admin/categories/', require('./views/admin/categories/index').find);
  app.post('/admin/categories/', require('./views/admin/categories/index').create);
  app.get('/admin/categories/:id/', require('./views/admin/categories/index').read);
  app.put('/admin/categories/:id/', require('./views/admin/categories/index').update);
  app.delete('/admin/categories/:id/', require('./views/admin/categories/index').delete);

  //admin > search
  app.get('/admin/search/', require('./views/admin/search/index').find);

  //account
  app.all('/account*', ensureAuthenticated);
  app.all('/account*', ensureAccount);
  app.get('/account/', require('./views/account/index').init);

  //account > verification
  app.get('/account/verification/', require('./views/account/verification/index').init);
  app.post('/account/verification/', require('./views/account/verification/index').resendVerification);
  app.get('/account/verification/:token/', require('./views/account/verification/index').verify);

  //account > settings
  app.get('/account/settings/', require('./views/account/settings/index').init);
  app.put('/account/settings/', require('./views/account/settings/index').update);
  app.put('/account/settings/identity/', require('./views/account/settings/index').identity);
  app.put('/account/settings/password/', require('./views/account/settings/index').password);

  //account > settings > social
  app.get('/account/settings/twitter/', passport.authenticate('twitter', { callbackURL: '/account/settings/twitter/callback/' }));
  app.get('/account/settings/twitter/callback/', require('./views/account/settings/index').connectTwitter);
  app.get('/account/settings/twitter/disconnect/', require('./views/account/settings/index').disconnectTwitter);
  app.get('/account/settings/github/', passport.authenticate('github', { callbackURL: '/account/settings/github/callback/' }));
  app.get('/account/settings/github/callback/', require('./views/account/settings/index').connectGitHub);
  app.get('/account/settings/github/disconnect/', require('./views/account/settings/index').disconnectGitHub);
  app.get('/account/settings/facebook/', passport.authenticate('facebook', { callbackURL: '/account/settings/facebook/callback/' }));
  app.get('/account/settings/facebook/callback/', require('./views/account/settings/index').connectFacebook);
  app.get('/account/settings/facebook/disconnect/', require('./views/account/settings/index').disconnectFacebook);

  //route not found
  app.all('*', require('./views/http/index').http404);
};
<|endoftext|>


<commit_before>import FactoryGuy from 'ember-data-factory-guy';
import faker from 'faker';

FactoryGuy.define('file', {
    default: {
        name: () => 'foo.txt',//faker.lorem.word() + '.txt',
        kind: 'file',
        path: '/1234567890',  // Faker.system.filePath may not yet be implemented
        size: () => faker.random.number(),
        provider: 'osfstorage',
        materializedPath: () => '/' + 'foo.png',//faker.lorem.word() + '.png',
        lastTouched: null,

        dateModified: () => faker.date.recent(1),
        dateCreated: () => faker.date.past(1),

        isProvider: false,
        checkout: false,

        links: {
            upload: '/this/is/an/upload/url',
            download: '/this/is/a/download/url',
            move: '/this/is/a/move/url',
            delete: '/this/is/a/delete/url',
            new_folder: '/this/is/a/new_folder/url'
        }
    },
    traits: {
        // Folder specific
        isFolder: {
            kind: 'folder',
            materializedPath: () => '/' + 'foo',//faker.lorem.word(),
            files: () => FactoryGuy.hasMany('file', 3)
        },
        // File specific
        hasVersions: {
            kind: 'file',
            versions: () => FactoryGuy.hasMany('file-version', 3)
        },
        hasComments: {
            kind: 'file',
            comments: () => FactoryGuy.hasMany('comment', 3)
        }
    }
});
<commit_msg>Undo hacky faker workaround<commit_after>import FactoryGuy from 'ember-data-factory-guy';
import faker from 'faker';

FactoryGuy.define('file', {
    default: {
        name: () => faker.lorem.words(1) + '.txt',
        kind: 'file',
        path: '/1234567890',  // Faker.system.filePath may not yet be implemented
        size: () => faker.random.number(),
        provider: 'osfstorage',
        materializedPath: () => '/' + faker.lorem.words(1) + '.png',
        lastTouched: null,

        dateModified: () => faker.date.recent(1),
        dateCreated: () => faker.date.past(1),

        isProvider: false,
        checkout: false,

        links: {
            upload: '/this/is/an/upload/url',
            download: '/this/is/a/download/url',
            move: '/this/is/a/move/url',
            delete: '/this/is/a/delete/url',
            new_folder: '/this/is/a/new_folder/url'
        }
    },
    traits: {
        // Folder specific
        isFolder: {
            kind: 'folder',
            materializedPath: () => '/' + faker.lorem.words(1),
            files: () => FactoryGuy.hasMany('file', 3)
        },
        // File specific
        hasVersions: {
            kind: 'file',
            versions: () => FactoryGuy.hasMany('file-version', 3)
        },
        hasComments: {
            kind: 'file',
            comments: () => FactoryGuy.hasMany('comment', 3)
        }
    }
});
<|endoftext|>


<commit_before>'use strict';

var Poll = require('../models/polls.js');
var User = require('../models/users.js');
var choicearray2 = [[]];

function PollHandler () {

	/*this.getPolls = function (req, res) {
		Poll
			.findOne({ 'poll.id': id }, { '_id': false })
			.exec(function (err, result) {
				if (err) { throw err; }

				res.json(result);
			});
	};*/

	this.addPoll = function (req, res) {
		//var id = 1;
		process.nextTick(function (err, poll) {
				if (err) {
					return err;
				} else {
					var newPoll = new Poll();

					//newPoll.poll.id = id;
					newPoll.poll.question = req.body.question;
					//newPoll.poll.creator  = displayName;
					var choicearray = req.body.choices.split(",");
					for (var i=0; i<choicearray.length; i++) {
						for (var j=0; j<2; j++) {
							choicearray2[i]["Choice"] = choicearray[i];
							choicearray2[i]["Count"] = 0;
						}
					}
					newPoll.poll.choices = choicearray2;
					//User.polls = req.body.question;
					//newPoll.poll.choices.count = 1;
					//id++;

					newPoll.save(function (err) {
						if (err) {
							throw err;
						}
						User.findOne({ polls: newPoll.poll.question })
							.populate('creator', 'displayName') // only return the Persons name
							.exec(function (err, story) {
							if (err) {
								throw err;
							}
								});
						return newPoll;
					});
}
});
};
}

module.exports = PollHandler;
<commit_msg>saving polls<commit_after>'use strict';

var Poll = require('../models/polls.js');
var User = require('../models/users.js');
var choicearray2 = [];

function PollHandler () {

	/*this.getPolls = function (req, res) {
		Poll
			.findOne({ 'poll.id': id }, { '_id': false })
			.exec(function (err, result) {
				if (err) { throw err; }

				res.json(result);
			});
	};*/

	this.addPoll = function (req, res) {
		//var id = 1;
		process.nextTick(function (err, poll) {
				if (err) {
					return err;
				} else {
					var newPoll = new Poll();

					//newPoll.poll.id = id;
					newPoll.poll.question = req.body.question;
					//newPoll.poll.creator  = displayName;
					var choicearray = req.body.choices.split(",");
					for (var i=0; i<choicearray.length; i++) {
							var newchoice = {choice: choicearray[i], count: 0};
							choicearray2.push(newchoice);
					}
					newPoll.poll.choices = choicearray2;
					//User.polls = req.body.question;
					//newPoll.poll.choices.count = 1;
					//id++;

					newPoll.save(function (err) {
						if (err) {
							throw err;
						}
						User.findOne({ polls: newPoll.poll.question })
							.populate('creator', 'displayName') // only return the Persons name
							.exec(function (err, story) {
							if (err) {
								throw err;
							}
								});
						return newPoll;
					});
}
});
};
}

module.exports = PollHandler;
<|endoftext|>


<commit_before>import Ember from 'ember';
import {parseDateString} from 'ghost/utils/date-formatting';
import SettingsMenuMixin from 'ghost/mixins/settings-menu-controller';
import boundOneWay from 'ghost/utils/bound-one-way';
import isNumber from 'ghost/utils/isNumber';

const {
    $,
    ArrayProxy,
    Controller,
    Handlebars,
    PromiseProxyMixin,
    RSVP,
    computed,
    guidFor,
    inject: {service, controller},
    isArray,
    isBlank,
    observer,
    run
} = Ember;

export default Controller.extend(SettingsMenuMixin, {
    debounceId: null,
    lastPromise: null,
    selectedAuthor: null,
    uploaderReference: null,

    application: controller(),
    config: service(),
    ghostPaths: service(),
    notifications: service(),
    session: service(),
    slugGenerator: service(),

    initializeSelectedAuthor: observer('model', function () {
        return this.get('model.author').then((author) => {
            this.set('selectedAuthor', author);
            return author;
        });
    }),

    authors: computed(function () {
        // Loaded asynchronously, so must use promise proxies.
        let deferred = {};

        deferred.promise = this.store.query('user', {limit: 'all'}).then((users) => {
            return users.rejectBy('id', 'me').sortBy('name');
        }).then((users) => {
            return users.filter((user) => {
                return user.get('active');
            });
        });

        return ArrayProxy
            .extend(PromiseProxyMixin)
            .create(deferred);
    }),

    slugValue: boundOneWay('model.slug'),

    // Requests slug from title
    generateAndSetSlug(destination) {
        let title = this.get('model.titleScratch');
        let afterSave = this.get('lastPromise');
        let promise;

        // Only set an "untitled" slug once per post
        if (title === '(Untitled)' && this.get('model.slug')) {
            return;
        }

        promise = RSVP.resolve(afterSave).then(() => {
            return this.get('slugGenerator').generateSlug('post', title).then((slug) => {
                if (!isBlank(slug)) {
                    this.set(destination, slug);
                }
            }).catch(() => {
                // Nothing to do (would be nice to log this somewhere though),
                // but a rejected promise needs to be handled here so that a resolved
                // promise is returned.
            });
        });

        this.set('lastPromise', promise);
    },

    metaTitleScratch: boundOneWay('model.metaTitle'),
    metaDescriptionScratch: boundOneWay('model.metaDescription'),

    seoTitle: computed('model.titleScratch', 'metaTitleScratch', function () {
        let metaTitle = this.get('metaTitleScratch') || '';

        metaTitle = metaTitle.length > 0 ? metaTitle : this.get('model.titleScratch');

        if (metaTitle.length > 70) {
            metaTitle = metaTitle.substring(0, 70).trim();
            metaTitle = Handlebars.Utils.escapeExpression(metaTitle);
            metaTitle = Ember.String.htmlSafe(`${metaTitle}…`);
        }

        return metaTitle;
    }),

    seoDescription: computed('model.scratch', 'metaDescriptionScratch', function () {
        let metaDescription = this.get('metaDescriptionScratch') || '';
        let html = '';
        let el, placeholder;

        if (metaDescription.length > 0) {
            placeholder = metaDescription;
        } else {
            el = $('.rendered-markdown');

            // Get rendered markdown
            if (el !== undefined && el.length > 0) {
                html = el.clone();
                html.find('.js-drop-zone').remove();
                html = html[0].innerHTML;
            }

            // Strip HTML
            placeholder = $('<div />', {html}).text();
            // Replace new lines and trim
            placeholder = placeholder.replace(/\n+/g, ' ').trim();
        }

        if (placeholder.length > 156) {
            // Limit to 156 characters
            placeholder = placeholder.substring(0, 156).trim();
            placeholder = Handlebars.Utils.escapeExpression(placeholder);
            placeholder = Ember.String.htmlSafe(`${placeholder}…`);
        }

        return placeholder;
    }),

    seoURL: computed('model.slug', 'config.blogUrl', function () {
        let blogUrl = this.get('config.blogUrl');
        let seoSlug = this.get('model.slug') ? this.get('model.slug') : '';
        let seoURL = `${blogUrl}/${seoSlug}`;

        // only append a slash to the URL if the slug exists
        if (seoSlug) {
            seoURL += '/';
        }

        if (seoURL.length > 70) {
            seoURL = seoURL.substring(0, 70).trim();
            seoURL = Ember.String.htmlSafe(`${seoURL}…`);
        }

        return seoURL;
    }),

    // observe titleScratch, keeping the post's slug in sync
    // with it until saved for the first time.
    addTitleObserver: observer('model', function () {
        if (this.get('model.isNew') || this.get('model.title') === '(Untitled)') {
            this.addObserver('model.titleScratch', this, 'titleObserver');
        }
    }),

    titleObserver() {
        let title = this.get('model.title');
        let debounceId;

        // generate a slug if a post is new and doesn't have a title yet or
        // if the title is still '(Untitled)' and the slug is unaltered.
        if ((this.get('model.isNew') && !title) || title === '(Untitled)') {
            debounceId = run.debounce(this, 'generateAndSetSlug', 'model.slug', 700);
        }

        this.set('debounceId', debounceId);
    },

    // live-query of all tags for tag input autocomplete
    availableTags: computed(function () {
        return this.get('store').filter('tag', {limit: 'all'}, () => {
            return true;
        });
    }),

    showErrors(errors) {
        errors = isArray(errors) ? errors : [errors];
        this.get('notifications').showErrors(errors);
    },

    actions: {
        discardEnter() {
            return false;
        },

        togglePage() {
            this.toggleProperty('model.page');

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch((errors) => {
                this.showErrors(errors);
                this.get('model').rollbackAttributes();
            });
        },

        toggleFeatured() {
            this.toggleProperty('model.featured');

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save(this.get('saveOptions')).catch((errors) => {
                this.showErrors(errors);
                this.get('model').rollbackAttributes();
            });
        },

        /**
         * triggered by user manually changing slug
         */
        updateSlug(newSlug) {
            let slug = this.get('model.slug');

            newSlug = newSlug || slug;
            newSlug = newSlug && newSlug.trim();

            // Ignore unchanged slugs or candidate slugs that are empty
            if (!newSlug || slug === newSlug) {
                // reset the input to its previous state
                this.set('slugValue', slug);

                return;
            }

            this.get('slugGenerator').generateSlug('post', newSlug).then((serverSlug) => {
                // If after getting the sanitized and unique slug back from the API
                // we end up with a slug that matches the existing slug, abort the change
                if (serverSlug === slug) {
                    return;
                }

                // Because the server transforms the candidate slug by stripping
                // certain characters and appending a number onto the end of slugs
                // to enforce uniqueness, there are cases where we can get back a
                // candidate slug that is a duplicate of the original except for
                // the trailing incrementor (e.g., this-is-a-slug and this-is-a-slug-2)

                // get the last token out of the slug candidate and see if it's a number
                let slugTokens = serverSlug.split('-');
                let check = Number(slugTokens.pop());

                // if the candidate slug is the same as the existing slug except
                // for the incrementor then the existing slug should be used
                if (isNumber(check) && check > 0) {
                    if (slug === slugTokens.join('-') && serverSlug !== newSlug) {
                        this.set('slugValue', slug);

                        return;
                    }
                }

                this.set('model.slug', serverSlug);

                if (this.hasObserverFor('model.titleScratch')) {
                    this.removeObserver('model.titleScratch', this, 'titleObserver');
                }

                // If this is a new post.  Don't save the model.  Defer the save
                // to the user pressing the save button
                if (this.get('model.isNew')) {
                    return;
                }

                return this.get('model').save();
            }).catch((errors) => {
                this.showErrors(errors);
                this.get('model').rollbackAttributes();
            });
        },

        /**
         * Parse user's set published date.
         * Action sent by post settings menu view.
         * (#1351)
         */
        setPublishedAt(userInput) {
            let newPublishedAt = parseDateString(userInput);
            let publishedAt = moment(this.get('model.publishedAt'));
            let errMessage = '';

            if (!userInput) {
                // Clear out the publishedAt field for a draft
                if (this.get('model.isDraft')) {
                    this.set('model.publishedAt', null);
                }

                return;
            }

            // Validate new Published date
            if (!newPublishedAt.isValid()) {
                errMessage = 'Published Date must be a valid date with format: ' +
                    'DD MMM YY @ HH:mm (e.g. 6 Dec 14 @ 15:00)';
            }
            if (newPublishedAt.diff(new Date(), 'h') > 0) {
                errMessage = 'Published Date cannot currently be in the future.';
            }

            // If errors, notify and exit.
            if (errMessage) {
                this.get('model.errors').add('post-setting-date', errMessage);
                return;
            }

            // Do nothing if the user didn't actually change the date
            if (publishedAt && publishedAt.isSame(newPublishedAt)) {
                return;
            }

            // Validation complete
            this.set('model.publishedAt', newPublishedAt);

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch((errors) => {
                this.showErrors(errors);
                this.get('model').rollbackAttributes();
            });
        },

        setMetaTitle(metaTitle) {
            let property = 'metaTitle';
            let model = this.get('model');
            let currentTitle = model.get(property) || '';

            // Only update if the title has changed
            if (currentTitle === metaTitle) {
                return;
            }

            model.set(property, metaTitle);

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (model.get('isNew')) {
                return;
            }

            model.save();
        },

        setMetaDescription(metaDescription) {
            let property = 'metaDescription';
            let model = this.get('model');
            let currentDescription = model.get(property) || '';

            // Only update if the description has changed
            if (currentDescription === metaDescription) {
                return;
            }

            model.set(property, metaDescription);

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (model.get('isNew')) {
                return;
            }

            model.save();
        },

        setCoverImage(image) {
            this.set('model.image', image);

            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch((errors) => {
                this.showErrors(errors);
                this.get('model').rollbackAttributes();
            });
        },

        clearCoverImage() {
            this.set('model.image', '');

            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch((errors) => {
                this.showErrors(errors);
                this.get('model').rollbackAttributes();
            });
        },

        resetUploader() {
            let uploader = this.get('uploaderReference');

            if (uploader && uploader[0]) {
                uploader[0].uploaderUi.reset();
            }
        },

        resetPubDate() {
            this.set('publishedAtValue', '');
        },

        closeNavMenu() {
            this.get('application').send('closeNavMenu');
        },

        changeAuthor(newAuthor) {
            let author = this.get('model.author');
            let model = this.get('model');

            // return if nothing changed
            if (newAuthor.get('id') === author.get('id')) {
                return;
            }

            model.set('author', newAuthor);

            // if this is a new post (never been saved before), don't try to save it
            if (this.get('model.isNew')) {
                return;
            }

            model.save().catch((errors) => {
                this.showErrors(errors);
                this.set('selectedAuthor', author);
                model.rollbackAttributes();
            });
        },

        addTag(tagName, index) {
            let currentTags = this.get('model.tags');
            let currentTagNames = currentTags.map((tag) => {
                return tag.get('name').toLowerCase();
            });
            let availableTagNames,
                tagToAdd;

            tagName = tagName.trim();

            // abort if tag is already selected
            if (currentTagNames.contains(tagName.toLowerCase())) {
                return;
            }

            this.get('availableTags').then((availableTags) => {
                availableTagNames = availableTags.map((tag) => {
                    return tag.get('name').toLowerCase();
                });

                // find existing tag or create new
                if (availableTagNames.contains(tagName.toLowerCase())) {
                    tagToAdd = availableTags.find((tag) => {
                        return tag.get('name').toLowerCase() === tagName.toLowerCase();
                    });
                } else {
                    tagToAdd = this.get('store').createRecord('tag', {
                        name: tagName
                    });

                    // we need to set a UUID so that selectize has a unique value
                    // it will be ignored when sent to the server
                    tagToAdd.set('uuid', guidFor(tagToAdd));
                }

                // push tag onto post relationship
                if (tagToAdd) {
                    this.get('model.tags').insertAt(index, tagToAdd);
                }
            });
        },

        removeTag(tag) {
            this.get('model.tags').removeObject(tag);

            if (tag.get('isNew')) {
                tag.destroyRecord();
            }
        }
    }
});
<commit_msg>Fixed bugs regarding the published date input field validation. refs #5777<commit_after>import Ember from 'ember';
import {parseDateString} from 'ghost/utils/date-formatting';
import SettingsMenuMixin from 'ghost/mixins/settings-menu-controller';
import boundOneWay from 'ghost/utils/bound-one-way';
import isNumber from 'ghost/utils/isNumber';

const {
    $,
    ArrayProxy,
    Controller,
    Handlebars,
    PromiseProxyMixin,
    RSVP,
    computed,
    guidFor,
    inject: {service, controller},
    isArray,
    isBlank,
    observer,
    run
} = Ember;

export default Controller.extend(SettingsMenuMixin, {
    debounceId: null,
    lastPromise: null,
    selectedAuthor: null,
    uploaderReference: null,

    application: controller(),
    config: service(),
    ghostPaths: service(),
    notifications: service(),
    session: service(),
    slugGenerator: service(),

    initializeSelectedAuthor: observer('model', function () {
        return this.get('model.author').then((author) => {
            this.set('selectedAuthor', author);
            return author;
        });
    }),

    authors: computed(function () {
        // Loaded asynchronously, so must use promise proxies.
        let deferred = {};

        deferred.promise = this.store.query('user', {limit: 'all'}).then((users) => {
            return users.rejectBy('id', 'me').sortBy('name');
        }).then((users) => {
            return users.filter((user) => {
                return user.get('active');
            });
        });

        return ArrayProxy
            .extend(PromiseProxyMixin)
            .create(deferred);
    }),

    slugValue: boundOneWay('model.slug'),

    // Requests slug from title
    generateAndSetSlug(destination) {
        let title = this.get('model.titleScratch');
        let afterSave = this.get('lastPromise');
        let promise;

        // Only set an "untitled" slug once per post
        if (title === '(Untitled)' && this.get('model.slug')) {
            return;
        }

        promise = RSVP.resolve(afterSave).then(() => {
            return this.get('slugGenerator').generateSlug('post', title).then((slug) => {
                if (!isBlank(slug)) {
                    this.set(destination, slug);
                }
            }).catch(() => {
                // Nothing to do (would be nice to log this somewhere though),
                // but a rejected promise needs to be handled here so that a resolved
                // promise is returned.
            });
        });

        this.set('lastPromise', promise);
    },

    metaTitleScratch: boundOneWay('model.metaTitle'),
    metaDescriptionScratch: boundOneWay('model.metaDescription'),

    seoTitle: computed('model.titleScratch', 'metaTitleScratch', function () {
        let metaTitle = this.get('metaTitleScratch') || '';

        metaTitle = metaTitle.length > 0 ? metaTitle : this.get('model.titleScratch');

        if (metaTitle.length > 70) {
            metaTitle = metaTitle.substring(0, 70).trim();
            metaTitle = Handlebars.Utils.escapeExpression(metaTitle);
            metaTitle = Ember.String.htmlSafe(`${metaTitle}…`);
        }

        return metaTitle;
    }),

    seoDescription: computed('model.scratch', 'metaDescriptionScratch', function () {
        let metaDescription = this.get('metaDescriptionScratch') || '';
        let html = '';
        let el, placeholder;

        if (metaDescription.length > 0) {
            placeholder = metaDescription;
        } else {
            el = $('.rendered-markdown');

            // Get rendered markdown
            if (el !== undefined && el.length > 0) {
                html = el.clone();
                html.find('.js-drop-zone').remove();
                html = html[0].innerHTML;
            }

            // Strip HTML
            placeholder = $('<div />', {html}).text();
            // Replace new lines and trim
            placeholder = placeholder.replace(/\n+/g, ' ').trim();
        }

        if (placeholder.length > 156) {
            // Limit to 156 characters
            placeholder = placeholder.substring(0, 156).trim();
            placeholder = Handlebars.Utils.escapeExpression(placeholder);
            placeholder = Ember.String.htmlSafe(`${placeholder}…`);
        }

        return placeholder;
    }),

    seoURL: computed('model.slug', 'config.blogUrl', function () {
        let blogUrl = this.get('config.blogUrl');
        let seoSlug = this.get('model.slug') ? this.get('model.slug') : '';
        let seoURL = `${blogUrl}/${seoSlug}`;

        // only append a slash to the URL if the slug exists
        if (seoSlug) {
            seoURL += '/';
        }

        if (seoURL.length > 70) {
            seoURL = seoURL.substring(0, 70).trim();
            seoURL = Ember.String.htmlSafe(`${seoURL}…`);
        }

        return seoURL;
    }),

    // observe titleScratch, keeping the post's slug in sync
    // with it until saved for the first time.
    addTitleObserver: observer('model', function () {
        if (this.get('model.isNew') || this.get('model.title') === '(Untitled)') {
            this.addObserver('model.titleScratch', this, 'titleObserver');
        }
    }),

    titleObserver() {
        let title = this.get('model.title');
        let debounceId;

        // generate a slug if a post is new and doesn't have a title yet or
        // if the title is still '(Untitled)' and the slug is unaltered.
        if ((this.get('model.isNew') && !title) || title === '(Untitled)') {
            debounceId = run.debounce(this, 'generateAndSetSlug', 'model.slug', 700);
        }

        this.set('debounceId', debounceId);
    },

    // live-query of all tags for tag input autocomplete
    availableTags: computed(function () {
        return this.get('store').filter('tag', {limit: 'all'}, () => {
            return true;
        });
    }),

    showErrors(errors) {
        errors = isArray(errors) ? errors : [errors];
        this.get('notifications').showErrors(errors);
    },

    actions: {
        discardEnter() {
            return false;
        },

        togglePage() {
            this.toggleProperty('model.page');

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch((errors) => {
                this.showErrors(errors);
                this.get('model').rollbackAttributes();
            });
        },

        toggleFeatured() {
            this.toggleProperty('model.featured');

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save(this.get('saveOptions')).catch((errors) => {
                this.showErrors(errors);
                this.get('model').rollbackAttributes();
            });
        },

        /**
         * triggered by user manually changing slug
         */
        updateSlug(newSlug) {
            let slug = this.get('model.slug');

            newSlug = newSlug || slug;
            newSlug = newSlug && newSlug.trim();

            // Ignore unchanged slugs or candidate slugs that are empty
            if (!newSlug || slug === newSlug) {
                // reset the input to its previous state
                this.set('slugValue', slug);

                return;
            }

            this.get('slugGenerator').generateSlug('post', newSlug).then((serverSlug) => {
                // If after getting the sanitized and unique slug back from the API
                // we end up with a slug that matches the existing slug, abort the change
                if (serverSlug === slug) {
                    return;
                }

                // Because the server transforms the candidate slug by stripping
                // certain characters and appending a number onto the end of slugs
                // to enforce uniqueness, there are cases where we can get back a
                // candidate slug that is a duplicate of the original except for
                // the trailing incrementor (e.g., this-is-a-slug and this-is-a-slug-2)

                // get the last token out of the slug candidate and see if it's a number
                let slugTokens = serverSlug.split('-');
                let check = Number(slugTokens.pop());

                // if the candidate slug is the same as the existing slug except
                // for the incrementor then the existing slug should be used
                if (isNumber(check) && check > 0) {
                    if (slug === slugTokens.join('-') && serverSlug !== newSlug) {
                        this.set('slugValue', slug);

                        return;
                    }
                }

                this.set('model.slug', serverSlug);

                if (this.hasObserverFor('model.titleScratch')) {
                    this.removeObserver('model.titleScratch', this, 'titleObserver');
                }

                // If this is a new post.  Don't save the model.  Defer the save
                // to the user pressing the save button
                if (this.get('model.isNew')) {
                    return;
                }

                return this.get('model').save();
            }).catch((errors) => {
                this.showErrors(errors);
                this.get('model').rollbackAttributes();
            });
        },

        /**
         * Parse user's set published date.
         * Action sent by post settings menu view.
         * (#1351)
         */
        setPublishedAt(userInput) {
            if (!userInput) {
                // Clear out the publishedAt field for a draft
                if (this.get('model.isDraft')) {
                    this.set('model.publishedAt', null);
                }

                return;
            }

            let newPublishedAt = parseDateString(userInput);
            let publishedAt = moment(this.get('model.publishedAt'));
            let errMessage = '';

            // Clear previous errors
            this.get('model.errors').remove('post-setting-date');

            // Validate new Published date
            if (!newPublishedAt.isValid()) {
                errMessage = 'Published Date must be a valid date with format: ' +
                    'DD MMM YY @ HH:mm (e.g. 6 Dec 14 @ 15:00)';
            } else if (newPublishedAt.diff(new Date(), 'h') > 0) {
                errMessage = 'Published Date cannot currently be in the future.';
            }

            // If errors, notify and exit.
            if (errMessage) {
                this.get('model.errors').add('post-setting-date', errMessage);
                return;
            }

            // Validation complete, update the view
            this.set('model.publishedAt', newPublishedAt);

            // Don't save the date if the user didn't actually changed the date
            if (publishedAt && publishedAt.isSame(newPublishedAt)) {
                return;
            }

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch((errors) => {
                this.showErrors(errors);
                this.get('model').rollbackAttributes();
            });
        },

        setMetaTitle(metaTitle) {
            let property = 'metaTitle';
            let model = this.get('model');
            let currentTitle = model.get(property) || '';

            // Only update if the title has changed
            if (currentTitle === metaTitle) {
                return;
            }

            model.set(property, metaTitle);

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (model.get('isNew')) {
                return;
            }

            model.save();
        },

        setMetaDescription(metaDescription) {
            let property = 'metaDescription';
            let model = this.get('model');
            let currentDescription = model.get(property) || '';

            // Only update if the description has changed
            if (currentDescription === metaDescription) {
                return;
            }

            model.set(property, metaDescription);

            // If this is a new post.  Don't save the model.  Defer the save
            // to the user pressing the save button
            if (model.get('isNew')) {
                return;
            }

            model.save();
        },

        setCoverImage(image) {
            this.set('model.image', image);

            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch((errors) => {
                this.showErrors(errors);
                this.get('model').rollbackAttributes();
            });
        },

        clearCoverImage() {
            this.set('model.image', '');

            if (this.get('model.isNew')) {
                return;
            }

            this.get('model').save().catch((errors) => {
                this.showErrors(errors);
                this.get('model').rollbackAttributes();
            });
        },

        resetUploader() {
            let uploader = this.get('uploaderReference');

            if (uploader && uploader[0]) {
                uploader[0].uploaderUi.reset();
            }
        },

        resetPubDate() {
            this.set('publishedAtValue', '');
        },

        closeNavMenu() {
            this.get('application').send('closeNavMenu');
        },

        changeAuthor(newAuthor) {
            let author = this.get('model.author');
            let model = this.get('model');

            // return if nothing changed
            if (newAuthor.get('id') === author.get('id')) {
                return;
            }

            model.set('author', newAuthor);

            // if this is a new post (never been saved before), don't try to save it
            if (this.get('model.isNew')) {
                return;
            }

            model.save().catch((errors) => {
                this.showErrors(errors);
                this.set('selectedAuthor', author);
                model.rollbackAttributes();
            });
        },

        addTag(tagName, index) {
            let currentTags = this.get('model.tags');
            let currentTagNames = currentTags.map((tag) => {
                return tag.get('name').toLowerCase();
            });
            let availableTagNames,
                tagToAdd;

            tagName = tagName.trim();

            // abort if tag is already selected
            if (currentTagNames.contains(tagName.toLowerCase())) {
                return;
            }

            this.get('availableTags').then((availableTags) => {
                availableTagNames = availableTags.map((tag) => {
                    return tag.get('name').toLowerCase();
                });

                // find existing tag or create new
                if (availableTagNames.contains(tagName.toLowerCase())) {
                    tagToAdd = availableTags.find((tag) => {
                        return tag.get('name').toLowerCase() === tagName.toLowerCase();
                    });
                } else {
                    tagToAdd = this.get('store').createRecord('tag', {
                        name: tagName
                    });

                    // we need to set a UUID so that selectize has a unique value
                    // it will be ignored when sent to the server
                    tagToAdd.set('uuid', guidFor(tagToAdd));
                }

                // push tag onto post relationship
                if (tagToAdd) {
                    this.get('model.tags').insertAt(index, tagToAdd);
                }
            });
        },

        removeTag(tag) {
            this.get('model.tags').removeObject(tag);

            if (tag.get('isNew')) {
                tag.destroyRecord();
            }
        }
    }
});
<|endoftext|>


<commit_before>uuid = require("node-uuid");
redis = require("redis");
EventEmitter = require("events").EventEmitter;

function Thoonk(host, port) {
    if(!host) { host = "127.0.0.1"; }
    if(!port) { port = 6379; }
    EventEmitter.call(this);
    this.lredis = redis.createClient(port, host);
    this.lredis.subscribe("newfeed", "delfeed", "conffeed");
    this.mredis = redis.createClient(port, host);
    this.bredis = redis.createClient(port, host);

    this.instance = uuid();

    //map message events to this.handle_message using event_handler to apply instance scope
    this.lredis.on("message", this.handle_message.bind(this));

    this.feeds = {};

    this.mredis.on("error", function(error) {
        console.log("Error " + error);
    });
    //TODO: on disconnect, reconn
}

//extend Thoonk with EventEmitter
Thoonk.super_ = EventEmitter;
Thoonk.prototype = Object.create(EventEmitter.prototype, {
    constructor: {
        value: Thoonk,
        enumerable: false,
    }
});

//map the event to the subscription callback
Thoonk.prototype.handle_message  = function(channel, msg) {
    if(channel == "newfeed") {
        //feed, instance
        var args = msg.split('\x00');
        if(args[1] != this.instance) {
            //this.feeds[args[0]] = null;
            this.update_config(args[0]);
        }
    } else if (channel == "delfeed") {
        //feed instance
        var args = msg.split('\x00');
        if(args[1] != this.instance) {
            delete this.feeds[args[0]];
        }
    } else if (channel == "conffeed") {
        //feed instance
        var args = msg.split('\x00');
        if(args[1] != this.instance) {
            //this.feeds[args[0]] = null;
            this.update_config(args[0]);
        }
    } else if (channel.substring(0, 13) == 'feed.publish:') {
        //id, event
        var args = msg.split('\x00');

        //chans[1] is the feed name
        var chans = channel.split(":");

        //publish: id, payload
        this.emit('publish', args[0], args[1]);
    } else if (channel.substring(0, 13) == 'feed.retract:') {
        //retract: id
        this.emit('retract', args[0]);
    }
}

//create a feed
Thoonk.prototype.create = function(name, config) {
    this.mredis.sadd("feeds", name, function(err, result) {
        //if we added it, configure it
        if(result != 0) {
            this.set_config(name, config, true);
         } else {
            this.emit("ready:" + name);
         }
    }.bind(this));
}

//update the config
Thoonk.prototype.set_config = function(feed, config, _newfeed) {
    this.mredis.set("feed.config:" + feed, JSON.stringify(config));
    this.feeds[feed] = config;
    this.emit("ready:" + feed);
    if(!_newfeed) {
        this.mredis.publish("conffeed", feed + "\x00" + this.instance);
    }
}

Thoonk.prototype.update_config = function(feed, callback) {
    this.mredis.get("feed.config:" + feed, function(err, reply) {
        this.feeds[feed] = JSON.parse(reply);
        if(callback) {
           callback(this.feeds[feed]);
        }
    }.bind(this));
}

Thoonk.prototype.exists = function(feed, exists_callback, doesnt_callback) {
    if(this.feeds.hasOwnProperty(feed)) { return true; }
    var obj = this;
    this.mredis.sismember("feeds", feed, function(error, reply) {
        if(reply) {
            if(!this.feeds.hasOwnProperty(feed)) { this.update_config(feed); }
            exists_callback(reply);
        } else {
            doesnt_callback(reply);
        }
    }.bind(this));
}

Thoonk.prototype.feed = function(name, config) {
    var feed = new Feed(this, name, config);
    return feed;
}

Thoonk.prototype.queue = function(name, config) {
    var queue = new Queue(this, name, config);
    return queue;
}

Thoonk.prototype.job = function(name, config) {
    var job = new Job(this, name, config);
    return job;
}

Thoonk.prototype.quit = function() {
    this.mredis.quit();
    this.lredis.quit();
    this.bredis.quit();
}

function Feed(thoonk, name, config) {
    EventEmitter.call(this);
    this.thoonk = thoonk;
    this.mredis = this.thoonk.mredis; //I'm lazy
    this.lredis = this.thoonk.lredis;
    this.bredis = this.thoonk.bredis;
    this.name = name;
    this.subscribed = false;
    this.thoonk.once("ready:" + name, this.ready.bind(this));
    this.thoonk.exists(name,
        //exists
        function(reply) {
            if(!config) {
                this.update_config(this.name, this.ready.bind(this));
            } else {
                this.thoonk.set_config(this.name, config);
            }
        }.bind(this),
        //doesn't
        function(reply) {
            this.thoonk.create(name, config);
        }.bind(this)
    );
}

function feed_ready() {
    this.emit("ready");
}

function feed_publish(item, id) {
    var m = this.mredis.multi();
    var id = id;
    var item = item;
    if(id == null) {
        id = uuid()
        //if we're generating a new id
        this.mredis.hset("feed.items:" + this.name, id, item)
        this.mredis.lpush("feed.ids:" + this.name, id, function(err,reply) { this.published(item, id); }.bind(this))
    } else {
        this.mredis.send_command("hexists", ["feed.items:" + this.name, id], function(err,reply) {
            if(!reply) {
                //if the id doesn't already exist
                this.mredis.hset("feed.items:" + this.name, id, item)
                this.mredis.lpush("feed.ids:" + this.name, id, function(err,reply) { this.published(item, id); }.bind(this))
            }
        }.bind(this));
    }
    //if we're updating an existing id
    this.mredis.hset("feed.items:" + this.name, id, item, function(err,reply) { this.published(item, id); }.bind(this))
}

function feed_published(item, id) {
    this.mredis.publish("feed.publish:" + this.name, id + "\x00" + item);
}

function feed_retract(id) {
    this.mredis.multi()
        .lrem("feed.ids:" + this.name, id, 1)
        .hdel("feed.items:" + this.name, id)
        .exec(function(err, replies) {
            var error = false;
            replies.forEach(function(reply, idx) {
                if(!reply) {
                    error = true;
                    console.log("Could not delete " + id + "from " + this.name);
                }
            });
            if(!error) {
                this.mredis.publish("feed.retract:" + this.name, id, id);
            }
        });
}

function feed_get_ids(callback) {
    return this.mredis.lrange("feed.ids:" + this.name, 0, -1, callback);
}

function feed_get_item(id, callback) {
    return this.mredis.hget("feed.items:" + this.name, id, callback);
}

function feed_subscribe(publish_callback, retract_callback) {
    if(!this.subscribed) {
        this.lredis.subscribe("feed.publish:" + this.name);
        this.lredis.subscribe("feed.retract:" + this.name);
        this.subscribed = true;
    }
    this.on('publish', publish_callback);
    this.on('retract', retract_callback);
}

//extend Feed with EventEmitter
Feed.super_ = EventEmitter;
Feed.prototype = Object.create(EventEmitter.prototype, {
    constructor: {
        value: Feed,
        enumerable: false,
    }
});

Feed.prototype.publish = feed_publish;
Feed.prototype.published = feed_published;
Feed.prototype.retract = feed_retract;
Feed.prototype.get_ids = feed_get_ids;
Feed.prototype.get_item = feed_get_item;
Feed.prototype.subscribe = feed_subscribe;
Feed.prototype.ready = feed_ready;

function Queue(thoonk, name, config) {
    Feed.call(this, thoonk, name, config);
}

function queue_publish(item) {
    id = uuid()
    this.mredis.multi()
    .hset("feed.items:" + this.name, id, item)
    .lpush("feed.ids:" + this.name, id)
    .exec(function(err, replies) {
        //TODO error handler
    });
}

function queue_get(timeout, callback, timeout_callback) {
    var callback = callback;
    if(!timeout) { var timeout = 0 };
    this.bredis.brpop("feed.ids:" + this.name, timeout, function(err, result) {
        if(!err) {
            var id = result[1];
            this.mredis.hget("feed.items:" + this.name, id, function(err, result) {
                callback(result, id);
                this.mredis.hdel("feed.items:" + this.name, result);
            }.bind(this));
        } else {
            timeout_callback()
        }
    }.bind(this));
}

Queue.super_ = Feed;
Queue.prototype = Object.create(Feed.prototype, {
    constructor: {
        value: Queue,
        enumerable: false,
    }
});

Queue.prototype.publish = queue_publish;
Queue.prototype.put = queue_publish;
Queue.prototype.get = queue_get;

function Job(thoonk, name, config) {
    Queue.call(this, thoonk, name, config);
}

Job.super_ = Queue;
Job.prototype = Object.create(Queue.prototype, {
    constructor: {
        value: Job,
        enumerable: false,
    }
});

function job_get(timeout, callback, timeout_callback) {
    if(!timeout) { var timeout = 0; }
    this.bredis.brpop("feed.ids:" + this.name, timeout, function(err, result) {
        if(!err) {
            var d = new Date()
            var id = result[1];
            this.mredis.hset("feed.running:" + this.name, id, d.getTime());
            this.mredis.hget("feed.items:" + this.name, id, function(err, result) {
                callback(result, id);
            }.bind(this));
        } else {
            timeout_callback();
        }
    }.bind(this));
}

function job_finish(id, setresult, callback, error_callback) {
    var id = id;
    this.mredis.hdel("feed.running:" + this.name, id, function(err, result) {
        if(!err) {
            if(setresult !== null && setresult !== undefined) {
                this.mredis.hget("feed.items:" + this.name, id, function(err, result) {
                    if(!err) {
                        this.mredis.lpush("feed.jobfinished:" + this.name + "\x00" + id, setresult);
                    }
                });
            }
            this.mredis.hdel("feed.items:" + this.name, id, function(err, result) {
                if(err) {
                    if(error_callback) {
                        error_callback(id);
                    }
                } else {
                    if(callback) {
                        callback(id);
                    }
                }
            }.bind(this));
        } else {
            error_callback(id);
        }
    }.bind(this));
}

function job_get_result(id, timeout, callback, timeout_callback) {
    this.mredis.blpop("feed.jobfinished:" + this.name + "\x00" + id, timeout, function(err, result) {
        if(err) {
            timeout_callback(id);
        } else {
            callback(result);
        }
    }.bind(this));
}

function job_cancel(id) {
    this.mredis.hdel("feed.running:" + this.name, id, function(err, result) {
        if(!err) {
            this.mredis.rpush("feed.ids:" + this.name, id);
        }
    });
}

function job_stall(id) {
    this.mredis.hdel("feed.running:" + this.name, id, function(err, result) {
        if(!err) {
            this.mredis.rpush("feed.stalled:" + this.name, id);
        }
    });
}

function job_retry(id) {
    this.mredis.lrem("feed.stalled:" + this.name, 1, id, function(err, result) {
        if(!err) {
            this.mredis.rpush("feed.ids:" + this.name, id);
        }
    });
}

Job.prototype.get = job_get;
Job.prototype.finish = job_finish;
Job.prototype.get_result = job_get_result;
Job.prototype.cancel = job_cancel;
Job.prototype.stall = job_stall;
Job.prototype.retry = job_retry;

exports.Thoonk = Thoonk;
exports.Feed = Feed;
exports.Queue = Queue;
exports.Job = Job;
<commit_msg>some feed compatibility fixes<commit_after>uuid = require("node-uuid");
redis = require("redis");
EventEmitter = require("events").EventEmitter;

function Thoonk(host, port) {
    if(!host) { host = "127.0.0.1"; }
    if(!port) { port = 6379; }
    EventEmitter.call(this);
    this.lredis = redis.createClient(port, host);
    this.lredis.subscribe("newfeed", "delfeed", "conffeed");
    this.mredis = redis.createClient(port, host);
    this.bredis = redis.createClient(port, host);

    this.instance = uuid();

    //map message events to this.handle_message using event_handler to apply instance scope
    this.lredis.on("message", this.handle_message.bind(this));

    this.feeds = {};

    this.mredis.on("error", function(error) {
        console.log("Error " + error);
    });
    //TODO: on disconnect, reconn
}

//extend Thoonk with EventEmitter
Thoonk.super_ = EventEmitter;
Thoonk.prototype = Object.create(EventEmitter.prototype, {
    constructor: {
        value: Thoonk,
        enumerable: false,
    }
});

//map the event to the subscription callback
Thoonk.prototype.handle_message  = function(channel, msg) {
    if(channel == "newfeed") {
        //feed, instance
        var args = msg.split('\x00');
        if(args[1] != this.instance) {
            //this.feeds[args[0]] = null;
            this.update_config(args[0]);
        }
    } else if (channel == "delfeed") {
        //feed instance
        var args = msg.split('\x00');
        if(args[1] != this.instance) {
            delete this.feeds[args[0]];
        }
    } else if (channel == "conffeed") {
        //feed instance
        var args = msg.split('\x00');
        if(args[1] != this.instance) {
            //this.feeds[args[0]] = null;
            this.update_config(args[0]);
        }
    } else if (channel.substring(0, 13) == 'feed.publish:') {
        //id, event
        var args = msg.split('\x00');

        //chans[1] is the feed name
        var chans = channel.split(":");

        //publish: id, payload
        this.emit('publish', args[0], args[1]);
    } else if (channel.substring(0, 13) == 'feed.retract:') {
        //retract: id
        this.emit('retract', args[0]);
    }
}

//create a feed
Thoonk.prototype.create = function(name, config) {
    this.mredis.sadd("feeds", name, function(err, result) {
        //if we added it, configure it
        if(result != 0) {
            this.set_config(name, config, true);
         } else {
            this.emit("ready:" + name);
         }
    }.bind(this));
}

//update the config
Thoonk.prototype.set_config = function(feed, config, _newfeed) {
    if(!config.hasOwnProperty('type')) {
        config['type'] = 'feed';
    }
    this.mredis.set("feed.config:" + feed, JSON.stringify(config));
    this.feeds[feed] = config;
    this.emit("ready:" + feed);
    if(!_newfeed) {
        this.mredis.publish("conffeed", feed + "\x00" + this.instance);
    }
}

//(re)load the config from redis
Thoonk.prototype.update_config = function(feed, callback) {
    this.mredis.get("feed.config:" + feed, function(err, reply) {
        this.feeds[feed] = JSON.parse(reply);
        if(callback) {
           callback(this.feeds[feed]);
        }
    }.bind(this));
}

//does the feed exist
Thoonk.prototype.exists = function(feed, exists_callback, doesnt_callback) {
    if(this.feeds.hasOwnProperty(feed)) { return true; }
    var obj = this;
    this.mredis.sismember("feeds", feed, function(error, reply) {
        if(reply) {
            if(!this.feeds.hasOwnProperty(feed)) { this.update_config(feed); }
            exists_callback(reply);
        } else {
            doesnt_callback(reply);
        }
    }.bind(this));
}

//generator for the Feed class
Thoonk.prototype.feed = function(name, config) {
    var feed = new Feed(this, name, config);
    return feed;
}

//generator for the Queue class
Thoonk.prototype.queue = function(name, config) {
    var queue = new Queue(this, name, config);
    return queue;
}

//generator for the Job class
Thoonk.prototype.job = function(name, config) {
    var job = new Job(this, name, config);
    return job;
}

//cleanly disconnect from all redis connections
Thoonk.prototype.quit = function() {
    this.mredis.quit();
    this.lredis.quit();
    this.bredis.quit();
}

//Feed object
function Feed(thoonk, name, config, type) {
    EventEmitter.call(this);
    this.thoonk = thoonk;

    //local references
    this.mredis = this.thoonk.mredis;
    this.lredis = this.thoonk.lredis;
    this.bredis = this.thoonk.bredis;

    this.name = name;
    this.subscribed = false;
    this.thoonk.once("ready:" + name, this.ready.bind(this));
    this.thoonk.exists(name,
        //exists
        function(reply) {
            if(!config) {
                this.update_config(this.name, this.ready.bind(this));
            } else {
                if(!type) { type = 'feed' }
                if(!config.hasOwnProperty('type')) { config.type = type; }
                this.thoonk.set_config(this.name, config);
            }
        }.bind(this),
        //doesn't
        function(reply) {
            this.thoonk.create(name, config);
        }.bind(this)
    );
}

function feed_ready() {
    this.emit("ready");
}

function feed_publish(item, id) {
    var m = this.mredis.multi();
    var id = id;
    var item = item;
    if(id == null) {
        id = uuid()
        //if we're generating a new id
        this.mredis.hset("feed.items:" + this.name, id, item)
        this.mredis.lpush("feed.ids:" + this.name, id, function(err,reply) { this.published(item, id); }.bind(this))
    } else {
        this.mredis.send_command("hexists", ["feed.items:" + this.name, id], function(err,reply) {
            if(!reply) {
                //if the id doesn't already exist
                this.mredis.hset("feed.items:" + this.name, id, item)
                this.mredis.lpush("feed.ids:" + this.name, id, function(err,reply) { this.published(item, id); }.bind(this))
            }
        }.bind(this));
    }
    //if we're updating an existing id
    this.mredis.hset("feed.items:" + this.name, id, item, function(err,reply) { this.published(item, id); }.bind(this))
}

function feed_published(item, id) {
    this.mredis.publish("feed.publish:" + this.name, id + "\x00" + item);
}

function feed_retract(id) {
    this.mredis.multi()
        .lrem("feed.ids:" + this.name, id, 1)
        .hdel("feed.items:" + this.name, id)
        .exec(function(err, replies) {
            var error = false;
            replies.forEach(function(reply, idx) {
                if(!reply) {
                    error = true;
                    console.log("Could not delete " + id + "from " + this.name);
                }
            });
            if(!error) {
                this.mredis.publish("feed.retract:" + this.name, id, id);
            }
        });
}

function feed_get_ids(callback) {
    return this.mredis.lrange("feed.ids:" + this.name, 0, -1, callback);
}

function feed_get_item(id, callback) {
    return this.mredis.hget("feed.items:" + this.name, id, callback);
}

function feed_subscribe(publish_callback, retract_callback) {
    if(!this.subscribed) {
        this.lredis.subscribe("feed.publish:" + this.name);
        this.lredis.subscribe("feed.retract:" + this.name);
        this.subscribed = true;
    }
    this.on('publish', publish_callback);
    this.on('retract', retract_callback);
}

//extend Feed with EventEmitter
Feed.super_ = EventEmitter;
Feed.prototype = Object.create(EventEmitter.prototype, {
    constructor: {
        value: Feed,
        enumerable: false,
    }
});

Feed.prototype.publish = feed_publish;
Feed.prototype.published = feed_published;
Feed.prototype.retract = feed_retract;
Feed.prototype.get_ids = feed_get_ids;
Feed.prototype.get_item = feed_get_item;
Feed.prototype.subscribe = feed_subscribe;
Feed.prototype.ready = feed_ready;

function Queue(thoonk, name, config) {
    Feed.call(this, thoonk, name, config, 'queue');
}

function queue_publish(item) {
    id = uuid()
    this.mredis.multi()
    .hset("feed.items:" + this.name, id, item)
    .lpush("feed.ids:" + this.name, id)
    .exec(function(err, replies) {
        //TODO error handler
    });
}

function queue_get(timeout, callback, timeout_callback) {
    var callback = callback;
    if(!timeout) { var timeout = 0 };
    this.bredis.brpop("feed.ids:" + this.name, timeout, function(err, result) {
        if(!err) {
            var id = result[1];
            this.mredis.hget("feed.items:" + this.name, id, function(err, result) {
                callback(result, id);
                this.mredis.hdel("feed.items:" + this.name, result);
            }.bind(this));
        } else {
            timeout_callback()
        }
    }.bind(this));
}

Queue.super_ = Feed;
Queue.prototype = Object.create(Feed.prototype, {
    constructor: {
        value: Queue,
        enumerable: false,
    }
});

Queue.prototype.publish = queue_publish;
Queue.prototype.put = queue_publish;
Queue.prototype.get = queue_get;

function Job(thoonk, name, config) {
    Feed.call(this, thoonk, name, config, 'job');
}

Job.super_ = Queue;
Job.prototype = Object.create(Queue.prototype, {
    constructor: {
        value: Job,
        enumerable: false,
    }
});

function job_get(timeout, callback, timeout_callback) {
    if(!timeout) { var timeout = 0; }
    this.bredis.brpop("feed.ids:" + this.name, timeout, function(err, result) {
        if(!err) {
            var d = new Date()
            var id = result[1];
            this.mredis.hset("feed.running:" + this.name, id, d.getTime());
            this.mredis.hget("feed.items:" + this.name, id, function(err, result) {
                callback(result, id);
            }.bind(this));
        } else {
            timeout_callback();
        }
    }.bind(this));
}

function job_finish(id, setresult, callback, error_callback) {
    var id = id;
    this.mredis.hdel("feed.running:" + this.name, id, function(err, result) {
        if(!err) {
            if(setresult !== null && setresult !== undefined) {
                this.mredis.hget("feed.items:" + this.name, id, function(err, result) {
                    if(!err) {
                        this.mredis.lpush("feed.jobfinished:" + this.name + "\x00" + id, setresult);
                    }
                });
            }
            this.mredis.hdel("feed.items:" + this.name, id, function(err, result) {
                if(err) {
                    if(error_callback) {
                        error_callback(id);
                    }
                } else {
                    if(callback) {
                        callback(id);
                    }
                }
            }.bind(this));
        } else {
            error_callback(id);
        }
    }.bind(this));
}

function job_get_result(id, timeout, callback, timeout_callback) {
    this.mredis.blpop("feed.jobfinished:" + this.name + "\x00" + id, timeout, function(err, result) {
        if(err) {
            timeout_callback(id);
        } else {
            callback(result);
        }
    }.bind(this));
}

function job_cancel(id) {
    this.mredis.hdel("feed.running:" + this.name, id, function(err, result) {
        if(!err) {
            this.mredis.rpush("feed.ids:" + this.name, id);
        }
    });
}

function job_stall(id) {
    this.mredis.hdel("feed.running:" + this.name, id, function(err, result) {
        if(!err) {
            this.mredis.rpush("feed.stalled:" + this.name, id);
        }
    });
}

function job_retry(id) {
    this.mredis.lrem("feed.stalled:" + this.name, 1, id, function(err, result) {
        if(!err) {
            this.mredis.rpush("feed.ids:" + this.name, id);
        }
    });
}

Job.prototype.get = job_get;
Job.prototype.finish = job_finish;
Job.prototype.get_result = job_get_result;
Job.prototype.cancel = job_cancel;
Job.prototype.stall = job_stall;
Job.prototype.retry = job_retry;

exports.Thoonk = Thoonk;
exports.Feed = Feed;
exports.Queue = Queue;
exports.Job = Job;
<|endoftext|>


<commit_before>var redis = require('redis'),
    fs = require('fs'),
    path = require('path'),
    EventEmitter = require("events").EventEmitter,
    uuid = require('node-uuid');

var Thoonk = function() {
    EventEmitter.call(this);

    this.redis = redis.createClient();
    this.lredis = redis.createClient();
    this.ready = false;

    this.lredis.on('message', function(channel, msg) {
        msg = msg.toString();
        this.emit(channel, channel, msg);
    }.bind(this));

    this.lredis.on('subscribe', function(channel) {
        this.emit('subscribed.' + channel);
    }.bind(this));

    this.scripts = {};
    this.shas = {};

    this.instance = uuid();

    this.subscriptions = {};

    this.objects = {};
};

Thoonk.prototype = Object.create(EventEmitter.prototype);
Thoonk.prototype.constructor = Thoonk;

(function() {
    //continue extending Thoonk

    this.quit = function() {
        this.redis.quit();
        this.lredis.quit();
    };

    this.registerType = function(objname, theobject, callback) {
        this.objects[objname] = function(name) {
            return new theobject(name, this);
        }.bind(this);
        var dir = theobject.prototype.scriptdir;
        this.scripts[theobject.prototype.objtype] = {};
        this.shas[theobject.prototype.objtype] = {}
        var curdir = fs.readdirSync(dir);
        curdir = curdir.filter(function(fname) { return fname.substr(-4) == '.lua'; });
        curdir.forEach(function(filename, fidx, curdir) {
            var last = (fidx + 1 == curdir.length);
            if(path.extname(filename) == '.lua') {
                var verbname = path.basename(filename).slice(0,-4);
                this.scripts[theobject.prototype.objtype][verbname] = fs.readFileSync(dir + '/' + filename).toString();
                this.redis.send_command('SCRIPT', ['LOAD', this.scripts[theobject.prototype.objtype][verbname]], function(err, reply) {
                    if(err) { console.log(verbname, err); }
                    this.shas[theobject.prototype.objtype][verbname] = reply.toString();
                    if(last) {
                        if(callback) {
                            callback(false);
                        }
                        this.emit('loaded.' + objname);
                    }
                }.bind(this));
            }
        }.bind(this));
    };

    this.create = function() {
    };

    this._runscript = function(objtype, scriptname, feedname, args, callback) {
        args = [this.shas[objtype][scriptname], '0', feedname].concat(args);
        this.redis.send_command('EVALSHA', args, callback);
    };

    this.feed = function(name, config) {
        return new Feed(name);
    };

}).call(Thoonk.prototype);

var ThoonkBaseObject = function(name, thoonk) {
    EventEmitter.call(this);
    this.thoonk = thoonk;
    this.redis = this.thoonk.redis;
    this.name = name;
    //TODO: create feed if it doesn't exist
};

ThoonkBaseObject.prototype = Object.create(EventEmitter.prototype);
ThoonkBaseObject.constructor = ThoonkBaseObject;

(function() {

    this._build_event = function(eventtype) {
        return 'event.' + this.objtype + '.' + eventtype + ':' + this.name
    };

    this.handle_event = function(channel, msg) {
        //override this function in your object
    };

    this.init_subscribe = function(functions) {
        if(!this.thoonk.subscriptions.hasOwnProperty(this.name)) {
            this.thoonk.once('subscribed.' + this._build_event(this.subscribables[this.subscribables.length - 1]), function() {
                this.emit('subscribe_ready');
            }.bind(this));
            this.thoonk.subscriptions[this.name] = this.subscribables;
            for(var subscribable in this.subscribables) {
                this.thoonk.lredis.subscribe(this._build_event(this.subscribables[subscribable]));
            }
        }
        if(!this.subinitted) {
            for(var subscribable in this.subscribables) {
                this.thoonk.on(this._build_event(this.subscribables[subscribable]), this.handle_event.bind(this));
            }
            this.subinitted = true;
        }
    };

    this.runscript = function(scriptname, args, callback) {
        this.thoonk._runscript(this.objtype, scriptname, this.name, args, function(err, results) {
            console.log(scriptname);
            if(err) {
                console.log(scriptname, err);
            } else {
                if(callback) {
                    callback.apply(this, results);
                }
            };
        }.bind(this));
    };

}).call(ThoonkBaseObject.prototype);

exports.Thoonk = Thoonk;
exports.ThoonkBaseObject = ThoonkBaseObject;
<commit_msg>removed a debuging console log<commit_after>var redis = require('redis'),
    fs = require('fs'),
    path = require('path'),
    EventEmitter = require("events").EventEmitter,
    uuid = require('node-uuid');

var Thoonk = function() {
    EventEmitter.call(this);

    this.redis = redis.createClient();
    this.lredis = redis.createClient();
    this.ready = false;

    this.lredis.on('message', function(channel, msg) {
        msg = msg.toString();
        this.emit(channel, channel, msg);
    }.bind(this));

    this.lredis.on('subscribe', function(channel) {
        this.emit('subscribed.' + channel);
    }.bind(this));

    this.scripts = {};
    this.shas = {};

    this.instance = uuid();

    this.subscriptions = {};

    this.objects = {};
};

Thoonk.prototype = Object.create(EventEmitter.prototype);
Thoonk.prototype.constructor = Thoonk;

(function() {
    //continue extending Thoonk

    this.quit = function() {
        this.redis.quit();
        this.lredis.quit();
    };

    this.registerType = function(objname, theobject, callback) {
        this.objects[objname] = function(name) {
            return new theobject(name, this);
        }.bind(this);
        var dir = theobject.prototype.scriptdir;
        this.scripts[theobject.prototype.objtype] = {};
        this.shas[theobject.prototype.objtype] = {}
        var curdir = fs.readdirSync(dir);
        curdir = curdir.filter(function(fname) { return fname.substr(-4) == '.lua'; });
        curdir.forEach(function(filename, fidx, curdir) {
            var last = (fidx + 1 == curdir.length);
            if(path.extname(filename) == '.lua') {
                var verbname = path.basename(filename).slice(0,-4);
                this.scripts[theobject.prototype.objtype][verbname] = fs.readFileSync(dir + '/' + filename).toString();
                this.redis.send_command('SCRIPT', ['LOAD', this.scripts[theobject.prototype.objtype][verbname]], function(err, reply) {
                    if(err) { console.log(verbname, err); }
                    this.shas[theobject.prototype.objtype][verbname] = reply.toString();
                    if(last) {
                        if(callback) {
                            callback(false);
                        }
                        this.emit('loaded.' + objname);
                    }
                }.bind(this));
            }
        }.bind(this));
    };

    this.create = function() {
    };

    this._runscript = function(objtype, scriptname, feedname, args, callback) {
        args = [this.shas[objtype][scriptname], '0', feedname].concat(args);
        this.redis.send_command('EVALSHA', args, callback);
    };

    this.feed = function(name, config) {
        return new Feed(name);
    };

}).call(Thoonk.prototype);

var ThoonkBaseObject = function(name, thoonk) {
    EventEmitter.call(this);
    this.thoonk = thoonk;
    this.redis = this.thoonk.redis;
    this.name = name;
    //TODO: create feed if it doesn't exist
};

ThoonkBaseObject.prototype = Object.create(EventEmitter.prototype);
ThoonkBaseObject.constructor = ThoonkBaseObject;

(function() {

    this._build_event = function(eventtype) {
        return 'event.' + this.objtype + '.' + eventtype + ':' + this.name
    };

    this.handle_event = function(channel, msg) {
        //override this function in your object
    };

    this.init_subscribe = function(functions) {
        if(!this.thoonk.subscriptions.hasOwnProperty(this.name)) {
            this.thoonk.once('subscribed.' + this._build_event(this.subscribables[this.subscribables.length - 1]), function() {
                this.emit('subscribe_ready');
            }.bind(this));
            this.thoonk.subscriptions[this.name] = this.subscribables;
            for(var subscribable in this.subscribables) {
                this.thoonk.lredis.subscribe(this._build_event(this.subscribables[subscribable]));
            }
        }
        if(!this.subinitted) {
            for(var subscribable in this.subscribables) {
                this.thoonk.on(this._build_event(this.subscribables[subscribable]), this.handle_event.bind(this));
            }
            this.subinitted = true;
        }
    };

    this.runscript = function(scriptname, args, callback) {
        this.thoonk._runscript(this.objtype, scriptname, this.name, args, function(err, results) {
            if(err) {
                console.log(scriptname, err);
            } else {
                if(callback) {
                    callback.apply(this, results);
                }
            };
        }.bind(this));
    };

}).call(ThoonkBaseObject.prototype);

exports.Thoonk = Thoonk;
exports.ThoonkBaseObject = ThoonkBaseObject;
<|endoftext|>