<commit_before>var express = require('express'),
	favicon = require('serve-favicon'),
	fs = require('fs'),
	path = require('path'),
	session = require('express-session'),
	RedisStore = require('connect-redis')(session),
	bodyParser = require('body-parser'),
	oauthserver = require('oauth2-server'),
	methodOverride = require('method-override');

var config,
	app,
	server,
	secureServer,
	oauth,
	log4js,
	logger,
	controllers,
	ssl,
	operator,
	router;

var configure = function(_config, _app, _server, _secureServer, _oauth, _log4js, _logger) {
	config = _config;
	app = _app;
	server = _server;
	secureServer = _secureServer;
	oauth = _oauth;
	log4js = _log4js;
	logger = _logger;
	router = express.Router();
	controllers = require('./Controllers')(config, _log4js);
};

var route = function(type, path, controller, auth) {
	var method;
	if(typeof path != 'string') { return false; }

	switch(type) {
		case 'all':
		case 'get':
		case 'post':
		case 'put':
		case 'delete':
			method = type;
			break;
		case 'del':
			method = 'delete';
		default:
			method = 'get';
			break;
	}

	if(auth) {
		router[method](path, app.oauth.authorise(), controller);
	}
	else {
		router[method](path, controller);
	}

	return true;
}

var start = function() {
	app.use(session({
		store: new RedisStore(configure.redis),
		secret: config.get('server').secret,
		resave: true,
		saveUninitialized: true
	}));

	app.oauth = oauthserver({
		model: oauth,
		grants: ['password', 'refresh_token'],
		debug: false
	});
	operator = app.oauth.grant();
	controllers.oauth2.init(config, oauth, operator);

	app.set('port', config.get('server').port);
	app.set('https', config.get('server').https);
	app.set('view engine', 'jade');

	app.use(log4js.connectLogger(logger.info, { level: log4js.levels.INFO }));
	//app.use(log4js.connectLogger(logger, { level: log4js.levels.INFO, format: ':method :url' }));
	app.use(bodyParser.urlencoded({ extended: false }));
	app.use(bodyParser.json());
	app.use(bodyParser.json({ type: 'application/vnd.api+json' }));
	app.use(controllers.filters.preprocessor);

	app.use(methodOverride('X-HTTP-Method-Override'));
	app.use(express.static(path.join(__dirname, '../public')));
	app.use(favicon(path.join('public/res/favicon.ico')));

	app.use(router);
	app.use(controllers.filters.errResponse);
	app.use(controllers.filters.response);

	//Routes
	router.post('/oauth/token', controllers.oauth2.createToken);
	router.get('/oauth/token/:token', controllers.oauth2.checkToken);
	router.delete('/oauth/token/:token', controllers.oauth2.deleteToken);
	router.get('/oauth/renew/:token', controllers.oauth2.renewToken);

	router.all('/oauth2/*', controllers.oauth2.callback);
	router.get('/public/*', controllers.google.file);
	router.get('/secret/*', app.oauth.authorise(), function (req, res) {
		res.send('Secret area');
	});

	// easyDB
	router.all('/db/', app.oauth.authorise(), controllers.easyDB.route);
	router.all('/db/:table', app.oauth.authorise(), controllers.easyDB.route);
	router.all('/db/:table/:id', app.oauth.authorise(), controllers.easyDB.route);

	// user data
	router.get('/me', controllers.user.data);
	router.post('/login', controllers.user.login);

	// google auth
	router.get('/auth/google', controllers.google.auth);
	router.get('/auth/google/return', passport.authenticate('google', { failureRedirect: '/auth/fail' }), controllers.google.authReturn);

	// facebook auth
	router.get('/auth/facebook', controllers.facebook.auth);
	router.get('/auth/facebook/return', passport.authenticate('facebook', { failureRedirect: '/auth/fail' }), controllers.facebook.authReturn);

	// http
	server.listen(app.get('port'), function () {
		logger.info.info('Server listening at port %d', app.get('port'));
	});

	//https
	if(secureServer) {
		secureServer.listen(app.get('https'), function () {
			logger.info.info('Secure server listening at port %d', app.get('https'));
		});
	}
}

module.exports = {
    configure: configure,
    start: start,
    route: route
}<commit_msg>Debug<commit_after>var express = require('express'),
	favicon = require('serve-favicon'),
	fs = require('fs'),
	path = require('path'),
	session = require('express-session'),
	RedisStore = require('connect-redis')(session),
	bodyParser = require('body-parser'),
	oauthserver = require('oauth2-server'),
	methodOverride = require('method-override');

var config,
	app,
	server,
	secureServer,
	oauth,
	log4js,
	logger,
	controllers,
	ssl,
	operator,
	router;

var configure = function(_config, _app, _server, _secureServer, _oauth, _log4js, _logger) {
	config = _config;
	app = _app;
	server = _server;
	secureServer = _secureServer;
	oauth = _oauth;
	log4js = _log4js;
	logger = _logger;
	router = express.Router();
	controllers = require('./Controllers')(config, _log4js);
};

var route = function(type, path, controller, auth) {
	var method;
	if(typeof path != 'string') { return false; }

	switch(type) {
		case 'all':
		case 'get':
		case 'post':
		case 'put':
		case 'delete':
			method = type;
			break;
		case 'del':
			method = 'delete';
		default:
			method = 'get';
			break;
	}

	if(auth) {
		router[method](path, app.oauth.authorise(), controller);
	}
	else {
		router[method](path, controller);
	}

	return true;
}

var start = function() {
	app.use(session({
		store: new RedisStore(configure.redis),
		secret: config.get('server').secret,
		resave: true,
		saveUninitialized: true
	}));

	app.oauth = oauthserver({
		model: oauth,
		grants: ['password', 'refresh_token'],
		debug: false
	});
	operator = app.oauth.grant();
	controllers.oauth2.init(config, oauth, operator);

	app.set('port', config.get('server').port);
	app.set('https', config.get('server').https);
	app.set('view engine', 'jade');

	app.use(log4js.connectLogger(logger.info, { level: log4js.levels.INFO }));
	//app.use(log4js.connectLogger(logger, { level: log4js.levels.INFO, format: ':method :url' }));
	app.use(bodyParser.urlencoded({ extended: false }));
	app.use(bodyParser.json());
	app.use(bodyParser.json({ type: 'application/vnd.api+json' }));
	app.use(controllers.filters.preprocessor);

	app.use(methodOverride('X-HTTP-Method-Override'));
	app.use(express.static(path.join(__dirname, '../public')));
	app.use(favicon(path.join('public/res/favicon.ico')));

	app.use(router);
	app.use(controllers.filters.errResponse);
	app.use(controllers.filters.response);

	//Routes
	router.post('/oauth/token', controllers.oauth2.createToken);
	router.get('/oauth/token/:token', controllers.oauth2.checkToken);
	router.delete('/oauth/token/:token', controllers.oauth2.deleteToken);
	router.get('/oauth/renew/:token', controllers.oauth2.renewToken);

	router.all('/oauth2/*', controllers.oauth2.callback);
	router.get('/public/*', controllers.google.file);
	router.get('/secret/*', app.oauth.authorise(), function (req, res) {
		res.send('Secret area');
	});

	// easyDB
	router.all('/db/', app.oauth.authorise(), controllers.easyDB.route);
	router.all('/db/:table', app.oauth.authorise(), controllers.easyDB.route);
	router.all('/db/:table/:id', app.oauth.authorise(), controllers.easyDB.route);

	// user data
	router.get('/me', controllers.user.data);
	router.post('/login', controllers.user.login);

	// google auth
	router.get('/auth/google', controllers.google.auth);
	router.get('/auth/google/return', controllers.google.authReturn);

	// facebook auth
	router.get('/auth/facebook', controllers.facebook.auth);
	router.get('/auth/facebook/return', controllers.facebook.authReturn);

	// http
	server.listen(app.get('port'), function () {
		logger.info.info('Server listening at port %d', app.get('port'));
	});

	//https
	if(secureServer) {
		secureServer.listen(app.get('https'), function () {
			logger.info.info('Secure server listening at port %d', app.get('https'));
		});
	}
}

module.exports = {
    configure: configure,
    start: start,
    route: route
}<|endoftext|>


<commit_before>/* call using the following enclosure:
(function(){
  var url = 'https://rawgit.com/jamesona/SEO-Tools/Book-Of-Business/bookmarklets/bobCalendar/loader.js';
  document.head.appendChild(document.createElement('script')).src=url;
})();
*/
(function(){
  // load parser class
  var BobParse = function(){
      this.dates = {};
      this.raw = prompt('Copy all data (Ctrl+A, Ctrl+C) and paste');
      this.parse = this.raw.split("\n").filter(function(str){return (/\S/).test(str);});
      this.parse.shift(); this.parse.shift();
      for (var l=0; l < this.parse.length; l++){
      	this.parse[l] = this.parse[l].split(/\t/);
      }
      for (var i=0;i<this.parse.length;i++) {
      	if (!(this.parse[i][4] in this.dates)) this.dates[this.parse[i][4]] = {};
      	if (!(this.dates[this.parse[i][0]] in this.dates[this.parse[i][4]])) {
      		var date = {};
      		date.start = this.parse[i][1];
      		date.bucket = this.parse[i][2];
      		date.spend = this.parse[i][3];
      		date.due = this.parse[i][4];
      		this.dates[this.parse[i][4]][this.parse[i][0]] = date;
      	}
      }
  };
  // load modal class
  var Modal = function(title, body, callback) {
    this.modalContainer = document.createElement('div');
    this.modalContainer.id = 'modal-container';
    this.modalBox = document.createElement('div');
    this.modalBox.id = 'modal';
    this.modalTitle = document.createElement('h1');
    this.modalTitle.innerHTML = (title !== null && title !== 'undefined' && typeof(title) === 'string') ? title : 'Modal';
    this.modalClose = document.createElement('button');
    this.modalClose.innerHTML = 'X';
    this.modalTitle.appendChild(this.modalClose);
    this.modalBody = document.createElement('div');
    if (typeof(body) === 'object') {
      this.modalBody.innerHTML = body.outerHTML;
    } else if (typeof(body) === 'string'){
      this.modalBody.innerHTML = body;
    }
    this.modalContainer.appendChild(this.modalBox);
    this.modalBox.appendChild(this.modalTitle);
    this.modalBox.appendChild(this.modalBody);
    this.destroy = function(){
      this.modalBox.parentNode.removeChild(this.modalBox);
    };
    this.attach = function(ele){
      var self = this;
      if (ele) {ele.appendChild(this.modalBox);} else {document.body.appendChild(this.modalBox);}
      (function(){
        self.modalClose.addEventListener('click', function(){
          self.destroy();
        });
      })();
    };
    if (callback) callback();
  };
  // load calendar class
  var Calendar = function(month, year, data) {
  	this.current_date = new Date();
  	this.day_labels = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
  	this.month_labels = ['January','February','March','April','May','June','July','August','September','October','November','December'];
  	this.month = (isNaN(month) || month === null) ? this.current_date.getMonth() : month;
  	this.year  = (isNaN(year) || year === null) ? this.current_date.getFullYear() : year;
    this.draw = function(ele){
  		if (this.month > 11) {
  			this.month -= 12;
  			this.year += 1;
  	  } else if (month < 0) {
  			this.month += 12;
  			this.year -= 1;
  		}
  		// get dates
  		var startingDay = new Date(this.year, this.month, 1).getDay(),
  		    endingDate = new Date(this.year, this.month + 1, 0),
  		    monthLength = endingDate.getDate(),
  		    inLastRow = 6 - endingDate.getDay();

  		// generate header
  	  this.table = document.createElement('table');
  		this.head = document.createElement('thead');
  		this.prev = document.createElement('th');
  		this.next = document.createElement('th');
  		this.title = document.createElement('th');
  		this.days = document.createElement('tr');
  		this.body = document.createElement('tbody');
  		this.cells = '';
  		this.table.setAttribute('class', 'calendar');
  		this.table.appendChild(this.head);
  		this.head.appendChild(this.prev);
  		this.prev.innerHTML = "«";
  		this.prev.id = 'prev';
  		this.head.appendChild(this.title);
  		this.head.appendChild(this.next);
  		this.next.innerHTML = "&raquo";
  		this.next.id = 'next';

  		this.table.appendChild(this.days);
  		this.title.innerHTML = this.month_labels[this.month] + " " + this.year;
  		this.title.setAttribute('colspan', '5');
  		this.days.setAttribute('class', 'header');
  		for (var i = 0; i <= 6; i++ ) this.cells += '' + this.day_labels[i] + '	';
  		this.days.innerHTML = this.cells;

  		//generate calendar
  		var html = '
';
  		if ( startingDay ) html += '	';
  		for (var day = 1; day <= monthLength; day++) {
  		html += '
' + day + '
';
  		//if data argument present, append key value for current day
  		if (data) {
  			var today = (this.month+1)+'/'+day+'/'+this.year;
  			if (data[today]) html += '
'+Object.keys(data[today]).length+' Clients
';
  		}
  		html += '	';
  		if ( (day + startingDay) % 7 === 0 && day != monthLength ) html += '

';
  		}
  		if ( inLastRow ) html += '	';
  		html += '
';
  		this.table.innerHTML += html;
      ele.innerHTML = this.table.outerHTML;
  		// save reference to dom node in object
  		this.node = ele;
  	  // save reference to calendar object for enclosure scope
  		var cal = this;
      (function(){
  			// save calendar object reference for listeners
  			var self = this;
        self.prev.addEventListener('click', function(){
  				cal.month--;
          cal.draw(cal.node);
        });
  			self.next.addEventListener('click', function(){
          cal.month++;
  				cal.draw(cal.node);
        });
      })();
  	};
  };
  var date = new Date(), modal = new Modal('Client Calendar'), calendar = new Calendar(date.getMonth(),date.getFullYear(),new BobParse().dates), style = document.createElement('style');
	style.innerHTML = 'body, #modal {width:100%;height:100%;padding:0;margin:0;}';
  style.innerHTML += '#modal {z-index:9;position:fixed;top:0;left:0;background:rgba(0,0,0,.3);pointer-events:none;font-family: sans-serif;background: rgba(0,0,0,0.5);padding-top:5em;}';
  style.innerHTML += '#modal button {float:right;}';
	style.innerHTML += '#modal>div, #modal>h1 {width: 70%;background:rgb(50,50,50);display:inline-block;margin:0;text-align: center;margin-left:15%;border:1px solid rgb(50,50,50);padding:5px;}';
	style.innerHTML += '#modal>h1 {color:#fff;}'
	style.innerHTML += '#modal .calendar{background:#fff;width:100%;height:80%;em;border-collapse:collapse;padding:0px;margin:0;}';
	style.innerHTML += '#modal .calendar td {border:1px solid black;width:14%;vertical-align:top;padding:5px;}';
	style.innerHTML += '#modal .calendar td div {float:right;border:1px solid black;width:1.5em;height:1.5em;margin:-6px;text-align:center;vertical-align:middle;}';
	style.innerHTML += '#modal .calendar td p {font-weight:bold;text-align:center;}';
	modal.attach();
  modal.modalBox.appendChild(style);
  calendar.draw(modal.modalBody);
})();
<commit_msg>Update loader.js<commit_after>/* call using the following enclosure:
(function(){
  var url = 'https://rawgit.com/jamesona/SEO-Tools/Book-Of-Business/bookmarklets/bobCalendar/loader.js';
  document.head.appendChild(document.createElement('script')).src=url;
})();
*/
(function(){
  // load parser class
  var BobParse = function(){
      this.dates = {};
      this.raw = prompt('Copy all data (Ctrl+A, Ctrl+C) and paste');
      this.parse = this.raw.split("\n").filter(function(str){return (/\S/).test(str);});
      this.parse.shift(); this.parse.shift();
      for (var l=0; l < this.parse.length; l++){
      	this.parse[l] = this.parse[l].split(/\t/);
      }
      for (var i=0;i<this.parse.length;i++) {
      	if (!(this.parse[i][4] in this.dates)) this.dates[this.parse[i][4]] = {};
      	if (!(this.dates[this.parse[i][0]] in this.dates[this.parse[i][4]])) {
      		var date = {};
      		date.start = this.parse[i][1];
      		date.bucket = this.parse[i][2];
      		date.spend = this.parse[i][3];
      		date.due = this.parse[i][4];
      		this.dates[this.parse[i][4]][this.parse[i][0]] = date;
      	}
      }
  };
  // load modal class
  var Modal = function(title, body, callback) {
    this.modalContainer = document.createElement('div');
    this.modalContainer.id = 'modal-container';
    this.modalBox = document.createElement('div');
    this.modalBox.id = 'modal';
    this.modalTitle = document.createElement('h1');
    this.modalTitle.innerHTML = (title !== null && title !== 'undefined' && typeof(title) === 'string') ? title : 'Modal';
    this.modalClose = document.createElement('button');
    this.modalClose.innerHTML = 'X';
    this.modalTitle.appendChild(this.modalClose);
    this.modalBody = document.createElement('div');
    if (typeof(body) === 'object') {
      this.modalBody.innerHTML = body.outerHTML;
    } else if (typeof(body) === 'string'){
      this.modalBody.innerHTML = body;
    }
    this.modalContainer.appendChild(this.modalBox);
    this.modalBox.appendChild(this.modalTitle);
    this.modalBox.appendChild(this.modalBody);
    this.destroy = function(){
      this.modalBox.parentNode.removeChild(this.modalBox);
    };
    this.attach = function(ele){
      var self = this;
      if (ele) {ele.appendChild(this.modalBox);} else {document.body.appendChild(this.modalBox);}
      (function(){
        self.modalClose.addEventListener('click', function(){
          self.destroy();
        });
      })();
    };
    if (callback) callback();
  };
  // load calendar class
  var Calendar = function(month, year, data) {
  	this.current_date = new Date();
  	this.day_labels = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
  	this.month_labels = ['January','February','March','April','May','June','July','August','September','October','November','December'];
  	this.month = (isNaN(month) || month === null) ? this.current_date.getMonth() : month;
  	this.year  = (isNaN(year) || year === null) ? this.current_date.getFullYear() : year;
    this.draw = function(ele){
  		if (this.month > 11) {
  			this.month -= 12;
  			this.year += 1;
  	  } else if (month < 0) {
  			this.month += 12;
  			this.year -= 1;
  		}
  		// get dates
  		var startingDay = new Date(this.year, this.month, 1).getDay(),
  		    endingDate = new Date(this.year, this.month + 1, 0),
  		    monthLength = endingDate.getDate(),
  		    inLastRow = 6 - endingDate.getDay();

  		// generate header
  	  this.table = document.createElement('table');
  		this.head = document.createElement('thead');
  		this.prev = document.createElement('th');
  		this.next = document.createElement('th');
  		this.title = document.createElement('th');
  		this.days = document.createElement('tr');
  		this.body = document.createElement('tbody');
  		this.cells = '';
  		this.table.setAttribute('class', 'calendar');
  		this.table.appendChild(this.head);
  		this.head.appendChild(this.prev);
  		this.prev.innerHTML = "«";
  		this.prev.id = 'prev';
  		this.head.appendChild(this.title);
  		this.head.appendChild(this.next);
  		this.next.innerHTML = "&raquo";
  		this.next.id = 'next';

  		this.table.appendChild(this.days);
  		this.title.innerHTML = this.month_labels[this.month] + " " + this.year;
  		this.title.setAttribute('colspan', '5');
  		this.days.setAttribute('class', 'header');
  		for (var i = 0; i <= 6; i++ ) this.cells += '' + this.day_labels[i] + '	';
  		this.days.innerHTML = this.cells;

  		//generate calendar
  		var html = '
';
  		if ( startingDay ) html += '	';
  		for (var day = 1; day <= monthLength; day++) {
  		html += '
' + day + '
';
  		//if data argument present, append key value for current day
  		if (data) {
  			var today = (this.month+1)+'/'+day+'/'+this.year;
  			if (data[today]) html += '
'+Object.keys(data[today]).length+' Clients
';
  		}
  		html += '	';
  		if ( (day + startingDay) % 7 === 0 && day != monthLength ) html += '

';
  		}
  		if ( inLastRow ) html += '	';
  		html += '
';
  		this.table.innerHTML += html;
      ele.innerHTML = this.table.outerHTML;
  		// save reference to dom node in object
  		this.node = ele;
  	  // save reference to calendar object for enclosure scope
  		var cal = this;
      (function(){
  			// save calendar object reference for listeners
  			var self = this;
        self.prev.addEventListener('click', function(){
  				cal.month--;
          cal.draw(cal.node);
        });
  			self.next.addEventListener('click', function(){
          cal.month++;
  				cal.draw(cal.node);
        });
      })();
  	};
  };
  var date = new Date(), modal = new Modal('Client Calendar'), calendar = new Calendar(date.getMonth(),date.getFullYear(),new BobParse().dates), style = document.createElement('style');
	style.innerHTML = 'body, #modal {width:100%;height:100%;padding:0;margin:0;}';
  style.innerHTML += '#modal {z-index:9;position:fixed;top:0;left:0;background:rgba(0,0,0,.3);font-family: sans-serif;background: rgba(0,0,0,0.5);padding-top:5em;}';
  style.innerHTML += '#modal button {float:right;}';
	style.innerHTML += '#modal>div, #modal>h1 {width: 70%;background:rgb(50,50,50);display:inline-block;margin:0;text-align: center;border:1px solid rgb(50,50,50);padding:5px;}';
	style.innerHTML += '#modal>h1 {color:#fff;}'
	style.innerHTML += '#modal .calendar{background:#fff;width:100%;border-collapse:collapse;padding:0px;margin:0;}';
	style.innerHTML += '#modal .calendar th {height: 1.5em;}';
	style.innerHTML += '#modal .calendar td {border:1px solid black;width:14%;vertical-align:top;padding:5px; height:8em;}';
	style.innerHTML += '#modal .calendar td div {float:right;border:1px solid black;width:1.5em;height:1.5em;margin:-6px;text-align:center;vertical-align:middle;}';
	style.innerHTML += '#modal .calendar td p {font-weight:bold;text-align:center;}';
	modal.attach();
  modal.modalBox.appendChild(style);
  calendar.draw(modal.modalBody);
})();
<|endoftext|>


<commit_before>const i18n = require('../../../shared/i18n');
const errors = require('@tryghost/errors');
const models = require('../../models');

module.exports = {
    docName: 'integrations',
    browse: {
        permissions: true,
        options: [
            'include',
            'limit'
        ],
        validation: {
            options: {
                include: {
                    values: ['api_keys', 'webhooks']
                }
            }
        },
        query({options}) {
            return models.Integration.findPage(options);
        }
    },
    read: {
        permissions: true,
        data: [
            'id'
        ],
        options: [
            'include'
        ],
        validation: {
            data: {
                id: {
                    required: true
                }
            },
            options: {
                include: {
                    values: ['api_keys', 'webhooks']
                }
            }
        },
        query({data, options}) {
            return models.Integration.findOne(data, Object.assign(options, {require: true}))
                .catch(models.Integration.NotFoundError, () => {
                    throw new errors.NotFoundError({
                        message: i18n.t('errors.api.resource.resourceNotFound', {
                            resource: 'Integration'
                        })
                    });
                });
        }
    },
    edit: {
        permissions: true,
        data: [
            'name',
            'icon_image',
            'description',
            'webhooks'
        ],
        options: [
            'id',
            'include'
        ],
        validation: {
            options: {
                id: {
                    required: true
                },
                include: {
                    values: ['api_keys', 'webhooks']
                }
            }
        },
        query({data, options}) {
            return models.Integration.edit(data, Object.assign(options, {require: true}))
                .catch(models.Integration.NotFoundError, () => {
                    throw new errors.NotFoundError({
                        message: i18n.t('errors.api.resource.resourceNotFound', {
                            resource: 'Integration'
                        })
                    });
                });
        }
    },
    add: {
        statusCode: 201,
        permissions: true,
        data: [
            'name',
            'icon_image',
            'description',
            'webhooks'
        ],
        options: [
            'include'
        ],
        validation: {
            data: {
                name: {
                    required: true
                }
            },
            options: {
                include: {
                    values: ['api_keys', 'webhooks']
                }
            }
        },
        query({data, options}) {
            const dataWithApiKeys = Object.assign({
                api_keys: [
                    {type: 'content'},
                    {type: 'admin'}
                ]
            }, data);
            return models.Integration.add(dataWithApiKeys, options);
        }
    },
    destroy: {
        statusCode: 204,
        permissions: true,
        options: [
            'id'
        ],
        validation: {
            options: {
                id: {
                    required: true
                }
            }
        },
        query({options}) {
            return models.Integration.destroy(Object.assign(options, {require: true}))
                .catch(models.Integration.NotFoundError, () => {
                    return Promise.reject(new errors.NotFoundError({
                        message: i18n.t('errors.api.resource.resourceNotFound', {
                            resource: 'Integration'
                        })
                    }));
                });
        }
    }
};
<commit_msg>Replaced i18n.t w/ tpl in v2/integrations.js (#13497)<commit_after>const tpl = require('@tryghost/tpl');
const errors = require('@tryghost/errors');
const models = require('../../models');

const messages = {
    resourceNotFound: '{resource} not found.'
};

module.exports = {
    docName: 'integrations',
    browse: {
        permissions: true,
        options: [
            'include',
            'limit'
        ],
        validation: {
            options: {
                include: {
                    values: ['api_keys', 'webhooks']
                }
            }
        },
        query({options}) {
            return models.Integration.findPage(options);
        }
    },
    read: {
        permissions: true,
        data: [
            'id'
        ],
        options: [
            'include'
        ],
        validation: {
            data: {
                id: {
                    required: true
                }
            },
            options: {
                include: {
                    values: ['api_keys', 'webhooks']
                }
            }
        },
        query({data, options}) {
            return models.Integration.findOne(data, Object.assign(options, {require: true}))
                .catch(models.Integration.NotFoundError, () => {
                    throw new errors.NotFoundError({
                        message: tpl(messages.resourceNotFound, {resource: 'Integration'})
                    });
                });
        }
    },
    edit: {
        permissions: true,
        data: [
            'name',
            'icon_image',
            'description',
            'webhooks'
        ],
        options: [
            'id',
            'include'
        ],
        validation: {
            options: {
                id: {
                    required: true
                },
                include: {
                    values: ['api_keys', 'webhooks']
                }
            }
        },
        query({data, options}) {
            return models.Integration.edit(data, Object.assign(options, {require: true}))
                .catch(models.Integration.NotFoundError, () => {
                    throw new errors.NotFoundError({
                        message: tpl(messages.resourceNotFound, {resource: 'Integration'})
                    });
                });
        }
    },
    add: {
        statusCode: 201,
        permissions: true,
        data: [
            'name',
            'icon_image',
            'description',
            'webhooks'
        ],
        options: [
            'include'
        ],
        validation: {
            data: {
                name: {
                    required: true
                }
            },
            options: {
                include: {
                    values: ['api_keys', 'webhooks']
                }
            }
        },
        query({data, options}) {
            const dataWithApiKeys = Object.assign({
                api_keys: [
                    {type: 'content'},
                    {type: 'admin'}
                ]
            }, data);
            return models.Integration.add(dataWithApiKeys, options);
        }
    },
    destroy: {
        statusCode: 204,
        permissions: true,
        options: [
            'id'
        ],
        validation: {
            options: {
                id: {
                    required: true
                }
            }
        },
        query({options}) {
            return models.Integration.destroy(Object.assign(options, {require: true}))
                .catch(models.Integration.NotFoundError, () => {
                    return Promise.reject(new errors.NotFoundError({
                        message: tpl(messages.resourceNotFound, {resource: 'Integration'})
                    }));
                });
        }
    }
};
<|endoftext|>


<commit_before>;

import angular from 'angular';
import Immutable from 'immutable';
import squareImageModule from './square-image';
import chatTextFieldModule from './chat-textfield';
import { attach, is, delay, msStringToDate } from '../utils.js'
import { actionCreators }  from '../actions/actions';
import { labels, relativeTime } from '../won-label-utils';
import {
    selectAllByConnections,
    selectOpenConnectionUri,
    selectOpenConnection,
} from '../selectors';
import { selectTimestamp } from '../won-utils'

const serviceDependencies = ['$ngRedux', '$scope', '$element'];

function genComponentConf() {
    let template = `

                Conversation about "{{ self.connectionData.getIn(['remoteNeed', 'won:hasContent', 'dc:title']) }}"

                Options

                    <won-square-image
                        title="self.connectionData.getIn(['remoteNeed', 'won:hasContent', 'dc:title'])"
                        src="self.connectionData.getIn(['remoteNeed', 'titleImgSrc'])"
                        uri="self.connectionData.getIn(['remoteNeed', '@id'])"
                        ng-show="message.get('hasSenderNeed') != self.connectionData.getIn(['ownNeed', '@id'])">
                    </won-square-image>

                            {{ message.get('hasTextMessage') }}

                                Pending …

                                {{ message.get('humanReadableTimestamp') }}

        <chat-textfield
            class="pm__footer"
            placeholder="::'Your Message'"
            on-input="::self.input(value)"
            on-submit="::self.send()"
            submit-button-label="::'Send'"
            >
        </chat-textfield>
    `;

    class Controller {
        constructor(/* arguments = dependency injections */) {
            attach(this, serviceDependencies, arguments);
            window.pm4dbg = this;
            window.selectOpenConnectionUri4dbg = selectOpenConnectionUri;
            window.selectChatMessages4dbg = selectChatMessages;

            const self = this;

            this.scrollContainerNg().bind('scroll', e => this.onScroll(e));

            // TODO <HACK>

            const loadStuff = () => {
                /*
                 * TODO don't trigger this more than once! When the
                 * events are there, there's no need to dispatch an
                 * action again -- unless paging is involved of course.
                 *
                 * Check during every select?
                 */

                if(self.eventsPending || self.eventsLoaded) return; // only start loading once.

                const state = self.$ngRedux.getState();
                const connectionUri = selectOpenConnectionUri(state);
                const connection = selectOpenConnection(state);

                if(!connectionUri || !connection) return;

                console.log('post-messages.js: testing for selective loading. ', connectionUri, connection);
                console.log('post-messages.js: calling crawlable query soon. ');
                //TODO determine first if component is actually visible (angular calls the constructor long before that)

                //TODO only do self if the events aren't defined!
                //requiringData AC
                self.eventsPending = true; // TODO should be determined in select
                won.getEventsOfConnection(connectionUri, { requesterWebId: connection.get('belongsToNeed') })
                    .then(events => {
                        self.eventsPending = false; // TODO should be determined in select
                        self.eventsLoaded = true;
                        self.$ngRedux.dispatch({
                            type: 'requiredData',
                            payload: {
                                events: Immutable.fromJS(events)
                            }
                        })

                    })
            }

            /*
             * If component has been created
             * after the connection had been loaded
             * we can already start loading events.
             */
            loadStuff();

            //TODO delete unnecessary logging
            //TODO call this when view is visible and the connection has been loaded (sometimes
            // the view is faster, sometimes the connection)
            console.log('post-messages.js: executing constructor.');
            /*
             * for the case that the component
             * is visible before the connection
             * has been loaded: set up a watch.
             */
            const eventWatchDeregister = this.$scope.$watch(
                ({self}) => self.connection && self.connection.get('uri'),
                (newCnctUri, oldCnctUri) => {
                    console.log('post-messages.js: in connection watch', newCnctUri, oldCnctUri);
                    loadStuff();
                });

            // the caching mechanisms should de-dupe the requests.

            // TODO pro-active loading!!!

            // check in every select?
            /*
            use this approach if there's no flags or we need to check
            outside of any component:
            ```
            const ensureLoaded = () => {
                const state = self.$ngRedux.getState();
                const connection = selectOpenConnection(state);
                // pulled the eventsPending check to here, to avoid the expensive subset calculation
                if(!self.eventsPending && !self.eventsLoaded && connection) {
                    var desiredEvents = connection.get('hasEvents');
                    var loadedEvents = state.getIn(['events','events']).keySeq();
                    if(!desiredEvents.isSubset(loadedEvents)) {
                        loadStuff();
                    }
                }
            }
            ```
            */
            // TODO </HACK>

            //this.postmsg = this;
            const selectFromState = state => {

                //TODO seems like rather bad practice to have sideffects here
                //scroll to bottom directly after rendering, if snapped
                delay(0).then(() => {
                    self.updateScrollposition();
                });

                const connectionUri = selectOpenConnectionUri(state);
                const chatMessages = selectChatMessages(state);
                return {
                    connectionUri,
                    connection: selectOpenConnection(state),
                    lastUpdateTime: state.get('lastUpdateTime'),
                    connectionData: selectAllByConnections(state).get(connectionUri),
                    chatMessages: chatMessages && chatMessages.toArray(), //toArray needed as ng-repeat won't work otherwise :|
                    state4dbg: state,
                }
            };

            const disconnect = this.$ngRedux.connect(selectFromState, actionCreators)(this);
            this.$scope.$on('$destroy', disconnect);

            this.snapToBottom();
        }

        snapToBottom() {
            this._snapBottom = true;
            this.scrollToBottom();
        }
        unsnapFromBottom() {
            this._snapBottom = false;
        }
        updateScrollposition() {
            if(this._snapBottom) {
                this.scrollToBottom();
            }
        }
        scrollToBottom() {
            this._programmaticallyScrolling = true;

            this.scrollContainer().scrollTop = this.scrollContainer().scrollHeight;
        }
        onScroll(e) {
            if(!this._programmaticallyScrolling) {
                //only unsnap if the user scrolled themselves
                this.unsnapFromBottom();
            }

            const sc = this.scrollContainer();
            const isAtBottom = sc.scrollTop + sc.offsetHeight >= sc.scrollHeight;
            if(isAtBottom) {
                this.snapToBottom();
            }

            this._programmaticallyScrolling = false
        }
        scrollContainerNg() {
            if(!this._scrollContainer) {
                this._scrollContainer = this.$element.find('.pm__content');
            }
            return this._scrollContainer;
        }
        scrollContainer() {
            return this.scrollContainerNg()[0];
        }

        input(userInput) {
            this.chatMessage = userInput;
        }

        send() {
            const trimmedMsg = this.chatMessage.trim();
            const connectionUri = this.connectionData.getIn(['connection', 'uri']);
            if(trimmedMsg) {
               this.connections__sendChatMessage(trimmedMsg, connectionUri);
            }
        }
    }
    Controller.$inject = serviceDependencies;

    return {
        restrict: 'E',
        controller: Controller,
        controllerAs: 'self',
        bindToController: true, //scope-bindings -> ctrl
        scope: { },
        template: template,
    }
}

export default angular.module('won.owner.components.postMessages', [
    squareImageModule,
    chatTextFieldModule,
])
    .directive('wonPostMessages', genComponentConf)
    .name;

//TODO refactor so that it always returns an array of immutable messages to
// allow ng-repeat without giving up the cheaper digestion
function selectChatMessages(state) {
    const connectionUri = selectOpenConnectionUri(state);
    const connectionData = selectAllByConnections(state).get(connectionUri);
    const ownNeedUri = connectionData && connectionData.getIn(['ownNeed', '@id']);

    if (!connectionData || !connectionData.get('events')) {
        return Immutable.List();

    } else {
        const timestamp = (event) =>
            //msStringToDate(selectTimestamp(event, connectionUri))
            msStringToDate(selectTimestamp(event))

        const chatMessages = connectionData.get('events')

            /* filter for valid chat messages */
            .filter(event => {
                if (event.get('hasTextMessage')) return true;
                else {
                    let remote = event.get('hasCorrespondingRemoteMessage');
                    if(is('String', remote)) {
                        remote = state.getIn(['events', 'events', remote]);
                    }
                    return remote && remote.get('hasTextMessage');
                }
            }).map(event => {
                const remote = event.get('hasCorrespondingRemoteMessage');
                if (event.get('hasTextMessage'))
                    return event;
                else
                    return remote;
            })

            /* sort them so the latest get shown last */
            .sort((event1, event2) =>
                timestamp(event1) - timestamp(event2)
            )
            /*
             * sort so the latest, optimistic/unconfirmed
             * messages are always at the bottom.
             */
            .sort((event1, event2) => {
                const u1 = event1.get('unconfirmed');
                const u2 = event2.get('unconfirmed');

                if(u1 && !u2) {
                  return 1;
                }
                else if (!u1 && u2) {
                    return -1;
                }
                else {
                    return 0;
                }
            })

            /* add a nice relative timestamp */
            .map(event => event.set(
                    'humanReadableTimestamp',
                    relativeTime(
                        state.get('lastUpdateTime'),
                        timestamp(event)
                    )
                )
            );

        return chatMessages;
    }

}
<commit_msg>Debugging paging WIP.<commit_after>;

import angular from 'angular';
import Immutable from 'immutable';
import squareImageModule from './square-image';
import chatTextFieldModule from './chat-textfield';
import {
    attach,
    is,
    delay,
    msStringToDate,
    urisToLookupMap,
} from '../utils.js'
import { actionCreators }  from '../actions/actions';
import {
    labels,
    relativeTime,
} from '../won-label-utils';
import {
    selectAllByConnections,
    selectOpenConnectionUri,
    selectOpenConnection,
} from '../selectors';
import { selectTimestamp } from '../won-utils'

const serviceDependencies = ['$ngRedux', '$scope', '$element'];

function genComponentConf() {
    let template = `

                Conversation about "{{ self.connectionData.getIn(['remoteNeed', 'won:hasContent', 'dc:title']) }}"

                Options

                    <won-square-image
                        title="self.connectionData.getIn(['remoteNeed', 'won:hasContent', 'dc:title'])"
                        src="self.connectionData.getIn(['remoteNeed', 'titleImgSrc'])"
                        uri="self.connectionData.getIn(['remoteNeed', '@id'])"
                        ng-show="message.get('hasSenderNeed') != self.connectionData.getIn(['ownNeed', '@id'])">
                    </won-square-image>

                            {{ message.get('hasTextMessage') }}

                                Pending …

                                {{ message.get('humanReadableTimestamp') }}

        <chat-textfield
            class="pm__footer"
            placeholder="::'Your Message'"
            on-input="::self.input(value)"
            on-submit="::self.send()"
            submit-button-label="::'Send'"
            >
        </chat-textfield>
    `;

    class Controller {
        constructor(/* arguments = dependency injections */) {
            attach(this, serviceDependencies, arguments);
            window.pm4dbg = this;
            window.selectOpenConnectionUri4dbg = selectOpenConnectionUri;
            window.selectChatMessages4dbg = selectChatMessages;

            const self = this;

            this.scrollContainerNg().bind('scroll', e => this.onScroll(e));

            // TODO <HACK>

            const loadStuff = () => {
                /*
                 * TODO don't trigger this more than once! When the
                 * events are there, there's no need to dispatch an
                 * action again -- unless paging is involved of course.
                 *
                 * Check during every select?
                 */

                if(self.eventsPending || self.eventsLoaded) return; // only start loading once.

                const state = self.$ngRedux.getState();
                const connectionUri = selectOpenConnectionUri(state);
                const connection = selectOpenConnection(state);

                if(!connectionUri || !connection) return;

                console.log('post-messages.js: testing for selective loading. ', connectionUri, connection);
                console.log('post-messages.js: calling crawlable query soon. ');
                //TODO determine first if component is actually visible (angular calls the constructor long before that)

                //TODO only do self if the events aren't defined!
                //requiringData AC
                self.eventsPending = true; // TODO should be determined in select
                const requesterWebId = connection.get('belongsToNeed');

                const deletme = () =>
                    store4dbg.node(connection.get('hasEventContainer'), (s,res) => {
                        console.log('store4dbg.node: ', s, res);
                        res.triples.forEach(t => console.log('store4dbg.node.triple: ', t.subject.nominalValue, ' -- ', t.predicate.nominalValue, ' -- ', t.object.nominalValue));
                    })
                won.getNode(connection.get('hasEventContainer'), { requesterWebId, pagingSize: 5, deep: true})

                .then(eventContainer => {
                        console.log('store4dbg.eventContainer: ', eventContainer)
                        deletme();
                }) //TODO deletme; for debug
                /*
                .then(eventContainer =>
                    urisToLookupMap(
                        eventContainer.member,
                        uri => won.getNode(uri, { requesterWebId })
                    )
                )
                //.then(events => {}))
                //won.getEventsOfConnection(connectionUri, { requesterWebId: connection.get('belongsToNeed'), pagingSize: 2 })
                .then(events => {
                    self.eventsPending = false; // TODO should be determined in select
                    self.eventsLoaded = true;
                    self.$ngRedux.dispatch({
                        type: 'requiredData',
                        payload: {
                            events: Immutable.fromJS(events)
                        }
                    });

                });
                */
            }

            /*
             * If component has been created
             * after the connection had been loaded
             * we can already start loading events.
             */
            loadStuff();

            //TODO delete unnecessary logging
            //TODO call this when view is visible and the connection has been loaded (sometimes
            // the view is faster, sometimes the connection)
            console.log('post-messages.js: executing constructor.');
            /*
             * for the case that the component
             * is visible before the connection
             * has been loaded: set up a watch.
             */
            const eventWatchDeregister = this.$scope.$watch(
                ({self}) => self.connection && self.connection.get('uri'),
                (newCnctUri, oldCnctUri) => {
                    console.log('post-messages.js: in connection watch', newCnctUri, oldCnctUri);
                    loadStuff();
                });

            // the caching mechanisms should de-dupe the requests.

            // TODO pro-active loading!!!

            // check in every select?
            /*
            use this approach if there's no flags or we need to check
            outside of any component:
            ```
            const ensureLoaded = () => {
                const state = self.$ngRedux.getState();
                const connection = selectOpenConnection(state);
                // pulled the eventsPending check to here, to avoid the expensive subset calculation
                if(!self.eventsPending && !self.eventsLoaded && connection) {
                    var desiredEvents = connection.get('hasEvents');
                    var loadedEvents = state.getIn(['events','events']).keySeq();
                    if(!desiredEvents.isSubset(loadedEvents)) {
                        loadStuff();
                    }
                }
            }
            ```
            */
            // TODO </HACK>

            //this.postmsg = this;
            const selectFromState = state => {

                //TODO seems like rather bad practice to have sideffects here
                //scroll to bottom directly after rendering, if snapped
                delay(0).then(() => {
                    self.updateScrollposition();
                });

                const connectionUri = selectOpenConnectionUri(state);
                const chatMessages = selectChatMessages(state);
                return {
                    connectionUri,
                    connection: selectOpenConnection(state),
                    lastUpdateTime: state.get('lastUpdateTime'),
                    connectionData: selectAllByConnections(state).get(connectionUri),
                    chatMessages: chatMessages && chatMessages.toArray(), //toArray needed as ng-repeat won't work otherwise :|
                    state4dbg: state,
                }
            };

            const disconnect = this.$ngRedux.connect(selectFromState, actionCreators)(this);
            this.$scope.$on('$destroy', disconnect);

            this.snapToBottom();
        }

        snapToBottom() {
            this._snapBottom = true;
            this.scrollToBottom();
        }
        unsnapFromBottom() {
            this._snapBottom = false;
        }
        updateScrollposition() {
            if(this._snapBottom) {
                this.scrollToBottom();
            }
        }
        scrollToBottom() {
            this._programmaticallyScrolling = true;

            this.scrollContainer().scrollTop = this.scrollContainer().scrollHeight;
        }
        onScroll(e) {
            if(!this._programmaticallyScrolling) {
                //only unsnap if the user scrolled themselves
                this.unsnapFromBottom();
            }

            const sc = this.scrollContainer();
            const isAtBottom = sc.scrollTop + sc.offsetHeight >= sc.scrollHeight;
            if(isAtBottom) {
                this.snapToBottom();
            }

            this._programmaticallyScrolling = false
        }
        scrollContainerNg() {
            if(!this._scrollContainer) {
                this._scrollContainer = this.$element.find('.pm__content');
            }
            return this._scrollContainer;
        }
        scrollContainer() {
            return this.scrollContainerNg()[0];
        }

        input(userInput) {
            this.chatMessage = userInput;
        }

        send() {
            const trimmedMsg = this.chatMessage.trim();
            const connectionUri = this.connectionData.getIn(['connection', 'uri']);
            if(trimmedMsg) {
               this.connections__sendChatMessage(trimmedMsg, connectionUri);
            }
        }
    }
    Controller.$inject = serviceDependencies;

    return {
        restrict: 'E',
        controller: Controller,
        controllerAs: 'self',
        bindToController: true, //scope-bindings -> ctrl
        scope: { },
        template: template,
    }
}

export default angular.module('won.owner.components.postMessages', [
    squareImageModule,
    chatTextFieldModule,
])
    .directive('wonPostMessages', genComponentConf)
    .name;

//TODO refactor so that it always returns an array of immutable messages to
// allow ng-repeat without giving up the cheaper digestion
function selectChatMessages(state) {
    const connectionUri = selectOpenConnectionUri(state);
    const connectionData = selectAllByConnections(state).get(connectionUri);
    const ownNeedUri = connectionData && connectionData.getIn(['ownNeed', '@id']);

    if (!connectionData || !connectionData.get('events')) {
        return Immutable.List();

    } else {
        const timestamp = (event) =>
            //msStringToDate(selectTimestamp(event, connectionUri))
            msStringToDate(selectTimestamp(event))

        const chatMessages = connectionData.get('events')

            /* filter for valid chat messages */
            .filter(event => {
                if (event.get('hasTextMessage')) return true;
                else {
                    let remote = event.get('hasCorrespondingRemoteMessage');
                    if(is('String', remote)) {
                        remote = state.getIn(['events', 'events', remote]);
                    }
                    return remote && remote.get('hasTextMessage');
                }
            }).map(event => {
                const remote = event.get('hasCorrespondingRemoteMessage');
                if (event.get('hasTextMessage'))
                    return event;
                else
                    return remote;
            })

            /* sort them so the latest get shown last */
            .sort((event1, event2) =>
                timestamp(event1) - timestamp(event2)
            )
            /*
             * sort so the latest, optimistic/unconfirmed
             * messages are always at the bottom.
             */
            .sort((event1, event2) => {
                const u1 = event1.get('unconfirmed');
                const u2 = event2.get('unconfirmed');

                if(u1 && !u2) {
                  return 1;
                }
                else if (!u1 && u2) {
                    return -1;
                }
                else {
                    return 0;
                }
            })

            /* add a nice relative timestamp */
            .map(event => event.set(
                    'humanReadableTimestamp',
                    relativeTime(
                        state.get('lastUpdateTime'),
                        timestamp(event)
                    )
                )
            );

        return chatMessages;
    }

}
<|endoftext|>


<commit_before>(function (module) {
    module.controller("FilesAllController", FilesAllController);

    FilesAllController.$inject = ["$scope", "project", "$state", "pubsub", "Restangular", "gridFiles"];

    /* @ngInject */
    function FilesAllController($scope, project, $state, pubsub, Restangular, gridFiles) {
        var ctrl = this;

        ctrl.gridShowingFlag = true;
        ctrl.files = project.files;
        ctrl.files[0].expanded = true;

        pubsub.waitOn($scope, 'files.refresh', function (f) {
            var treeModel = new TreeModel(),
                root = treeModel.parse(project.files[0]);
            var file = root.first({strategy: 'pre'}, function (node) {
                return node.model.data.id === f.id;
            });
            if (file) {
                file.model.data.name = f.name;
                ctrl.gridOptions.api.recomputeAggregates();
                ctrl.gridOptions.api.refreshGroupRows();
                ctrl.gridOptions.api.refreshView();
                ctrl.gridShowingFlag = !ctrl.gridShowingFlag;
            }
        });

        init();

        ///////////////////////////////

        function init() {
            var columnDefs = [
                {
                    headerName: "",
                    field: "name",
                    width: 350,
                    cellRenderer: {
                        renderer: 'group',
                        innerRenderer: function (params) {
                            if (params.data._type == 'directory') {
                                return '' + params.data.name + '';
                            }

                            var icon = "fa-file";
                            switch (params.data.mediatype.mime) {
                            case "application/pdf":
                                icon = "fa-file-pdf-o";
                                break;
                            case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
                                icon = "fa-file-excel-o";
                                break;
                            case "application/vnd.ms-excel":
                                icon = "fa-file-excel-o";
                                break;
                            case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
                                icon = "fa-file-word-o";
                                break;
                            case "application/ms-word":
                                icon = "fa-file-word-o";
                                break;
                            case "application/vnd.ms-powerpoint.presentation.macroEnabled.12":
                                icon = "fa-file-powerpoint-o";
                                break;
                            case "application/vnd.ms-powerpoint":
                                icon = "fa-file-powerpoint-o";
                                break;
                            default:
                                if (isImage(params.data.mediatype.mime)) {
                                    icon = "fa-file-image-o";
                                }
                                break;
                            }
                            return '' +
                                params.data.name + '';
                        }
                    }
                }
            ];

            ctrl.gridOptions = {
                columnDefs: columnDefs,
                rowData: ctrl.files,
                rowClicked: rowClicked,
                rowSelection: 'single',
                rowsAlreadyGrouped: true,
                enableColResize: false,
                enableSorting: false,
                rowHeight: 30,
                angularCompileRows: false,
                icons: {
                    groupExpanded: '',
                    groupContracted: ''
                }
            };

            //$state.go('projects.project.files.all.edit', {file_id: ctrl.files[0].datafile_id, file_type: 'datadir'});
        }

        function rowClicked(params) {
            if (params.data._type == 'directory') {
                handleDirectory(params);
            } else {
                handleFile(params);
            }
        }

        function handleDirectory(params) {
            if (!params.data.childrenLoaded) {
                Restangular.one('v2').one('projects', project.id)
                    .one('directories', params.data.id).get().then(function(files) {
                            var treeModel = new TreeModel(),
                                root = treeModel.parse(project.files[0]);
                            var dir = root.first({strategy: 'pre'}, function (node) {
                                return node.model.data.id === params.data.id;
                            });
                            dir.model.children = gridFiles.toGridChildren(files);
                            dir.model.data.childrenLoaded = true;
                            ctrl.gridOptions.api.onNewRows();
                            ctrl.gridShowingFlag = !ctrl.gridShowingFlag;
                        $state.go('projects.project.files.all.dir', {dir_id: params.data.id});
                });
            } else {
                ctrl.gridShowingFlag = !ctrl.gridShowingFlag;
                $state.go('projects.project.files.all.dir', {dir_id: params.data.id});
            }
        }

        function handleFile(params) {
            $state.go('projects.project.files.all.edit', {file_id: params.data.id});
        }
    }
}(angular.module('materialscommons')));
<commit_msg>Add console.dir to see the data structure layout.<commit_after>(function (module) {
    module.controller("FilesAllController", FilesAllController);

    FilesAllController.$inject = ["$scope", "project", "$state", "pubsub", "Restangular", "gridFiles"];

    /* @ngInject */
    function FilesAllController($scope, project, $state, pubsub, Restangular, gridFiles) {
        var ctrl = this;

        ctrl.gridShowingFlag = true;
        ctrl.files = project.files;
        ctrl.files[0].expanded = true;

        pubsub.waitOn($scope, 'files.refresh', function (f) {
            var treeModel = new TreeModel(),
                root = treeModel.parse(project.files[0]);
            var file = root.first({strategy: 'pre'}, function (node) {
                return node.model.data.id === f.id;
            });
            if (file) {
                file.model.data.name = f.name;
                ctrl.gridOptions.api.recomputeAggregates();
                ctrl.gridOptions.api.refreshGroupRows();
                ctrl.gridOptions.api.refreshView();
                ctrl.gridShowingFlag = !ctrl.gridShowingFlag;
            }
        });

        init();

        ///////////////////////////////

        function init() {
            var columnDefs = [
                {
                    headerName: "",
                    field: "name",
                    width: 350,
                    cellRenderer: {
                        renderer: 'group',
                        innerRenderer: function (params) {
                            if (params.data._type == 'directory') {
                                return '' + params.data.name + '';
                            }

                            var icon = "fa-file";
                            switch (params.data.mediatype.mime) {
                            case "application/pdf":
                                icon = "fa-file-pdf-o";
                                break;
                            case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
                                icon = "fa-file-excel-o";
                                break;
                            case "application/vnd.ms-excel":
                                icon = "fa-file-excel-o";
                                break;
                            case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
                                icon = "fa-file-word-o";
                                break;
                            case "application/ms-word":
                                icon = "fa-file-word-o";
                                break;
                            case "application/vnd.ms-powerpoint.presentation.macroEnabled.12":
                                icon = "fa-file-powerpoint-o";
                                break;
                            case "application/vnd.ms-powerpoint":
                                icon = "fa-file-powerpoint-o";
                                break;
                            default:
                                if (isImage(params.data.mediatype.mime)) {
                                    icon = "fa-file-image-o";
                                }
                                break;
                            }
                            return '' +
                                params.data.name + '';
                        }
                    }
                }
            ];

            ctrl.gridOptions = {
                columnDefs: columnDefs,
                rowData: ctrl.files,
                rowClicked: rowClicked,
                rowSelection: 'single',
                rowsAlreadyGrouped: true,
                enableColResize: false,
                enableSorting: false,
                rowHeight: 30,
                angularCompileRows: false,
                icons: {
                    groupExpanded: '',
                    groupContracted: ''
                }
            };

            console.dir(ctrl.files[0]);
            //$state.go('projects.project.files.all.dir', {dir_id: ctrl.files[0].id});
        }

        function rowClicked(params) {
            if (params.data._type == 'directory') {
                handleDirectory(params);
            } else {
                handleFile(params);
            }
        }

        function handleDirectory(params) {
            if (!params.data.childrenLoaded) {
                Restangular.one('v2').one('projects', project.id)
                    .one('directories', params.data.id).get().then(function(files) {
                            var treeModel = new TreeModel(),
                                root = treeModel.parse(project.files[0]);
                            var dir = root.first({strategy: 'pre'}, function (node) {
                                return node.model.data.id === params.data.id;
                            });
                            dir.model.children = gridFiles.toGridChildren(files);
                            dir.model.data.childrenLoaded = true;
                            ctrl.gridOptions.api.onNewRows();
                            ctrl.gridShowingFlag = !ctrl.gridShowingFlag;
                        $state.go('projects.project.files.all.dir', {dir_id: params.data.id});
                });
            } else {
                ctrl.gridShowingFlag = !ctrl.gridShowingFlag;
                $state.go('projects.project.files.all.dir', {dir_id: params.data.id});
            }
        }

        function handleFile(params) {
            $state.go('projects.project.files.all.edit', {file_id: params.data.id});
        }
    }
}(angular.module('materialscommons')));
<|endoftext|>