<commit_before>import StringManipulator from '../stringManipulation';

import exceptions from '../exceptions';

import constants from '../constants';

import DateTime from '../generated-data/dateTime';

const alasql = require('alasql');

const stringManipulator = new StringManipulator();

const dateTime = new DateTime();

function getFormattedCurrentDateTime() {
  return stringManipulator.stringConcat('"', dateTime.getCurrentDateTime(), '"');
}

export default function sqlCommands() {
  this.linkDatabaseToIndexedDB = function linkDatabaseToIndexedDB() {
    const databaseRequestStr = "CREATE INDEXEDDB DATABASE IF NOT EXISTS lectureNote; " +
                               "ATTACH INDEXEDDB DATABASE lectureNote; " +
                               "USE lectureNote;";
    alasql.promise([databaseRequestStr])
      .then().catch(sqlError => sqlError);
  };

  this.getFullTableData = function getFullTableData(tableName) {
    // ensure working in browsers that support Promise
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT * FROM ', tableName)])
          .then(data => resolve(data))
          .catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };

  this.createTable = function createTable(sqlStatement) {
    alasql.promise([stringManipulator.stringConcat('CREATE TABLE IF NOT EXISTS ', sqlStatement)])
      .then().catch(sqlError => sqlError);
  };

  this.insertContent = function insertContent(tableName, ...content) {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        // concatenate all the values to insert together
        const valuesToInsertIntoTable = content.join(', ');
        alasql.promise([stringManipulator.stringConcat('INSERT INTO ', tableName,
                                                       ' VALUES (', valuesToInsertIntoTable, ')')])
        .then(() => true)
        .catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };

  this.partialSearchFileName = function partialSearchFileName(searchString) {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT * FROM ', constants.ENTITIES_FILE_MANAGER,
                                                       ' WHERE ', constants.HEADER_FILE_MANAGER_FILE_NAME,
                                                       ' LIKE "%', searchString, '%"')])
        .then(data => resolve(data))
        .catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };
  this.getMaxFileId = function getMaxFileId() {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT MAX(', constants.HEADER_FILE_MANAGER_FILE_ID,
                                                       ') FROM ', constants.ENTITIES_FILE_MANAGER)])
        .then((data) => {
          const maxFileId = getDataOutOfAlasql(data);
          if (typeof maxFileId === 'number') {
            resolve(maxFileId);
          } else {
            resolve(-1);
          }
        }).catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };
  this.getMaxFolderId = function getMaxFolderId() {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT MAX(', constants.HEADER_FOLDER_FOLDER_ID,
                                                       ') FROM ', constants.ENTITIES_FOLDER)])
        .then((data) => {
          const maxFolderId = getDataOutOfAlasql(data);
          if (typeof maxFolderId === 'number') {
            resolve(maxFolderId);
          } else {
            resolve(0);
          }
        }).catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };

  this.partialSearchFolderName = function partialSearchFolderName(searchString) {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT * FROM ', constants.ENTITIES_FOLDER,
                                                       ' WHERE ', constants.HEADER_FOLDER_FOLDER_NAME,
                                                       ' LIKE "%', searchString, '%"')])
        .then(data => resolve(data))
        .catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };

  this.loadFilesFromFolder = function loadFilesFromFolder(folderId) {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT * FROM ', constants.ENTITIES_FILE_MANAGER,
                                                       ' WHERE ', constants.HEADER_FILE_MANAGER_FOLDER_ID,
                                                       ' = ', folderId)])
        .then(data => resolve(data))
        .catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };

  this.loadFoldersFromFolder = function loadFoldersFromFolder(folderId) {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT * FROM ', constants.ENTITIES_FOLDER,
                                                       ' WHERE ', constants.HEADER_FOLDER_PARENT_FOLDER_ID,
                                                       ' = ', folderId,
                                                       ' AND ', constants.HEADER_FOLDER_PARENT_FOLDER_ID,
                                                       ' != NULL')])
          .then(data => resolve(data))
          .catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };

  this.loadFile = function loadFile(fileId) {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT ', constants.HEADER_FILE_MANAGER_FILE_MARKDOWN,
                                                       ' FROM ', constants.ENTITIES_FILE_MANAGER,
                                                       ' WHERE ', constants.HEADER_FILE_MANAGER_FILE_ID,
                                                       ' = ', fileId)])
        .then(data => resolve(data))
        .catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };

  this.saveFile = function saveFile(fileId, markdownFile) {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        // save file
        alasql.promise([stringManipulator.stringConcat('UPDATE ', constants.ENTITIES_FILE_MANAGER,
                                                       ' SET ', constants.HEADER_FILE_MANAGER_FILE_MARKDOWN,
                                                       ' = "', markdownFile,
                                                       '" WHERE ', constants.HEADER_FILE_MANAGER_FILE_ID,
                                                       ' = ', fileId)])
          .then().catch(sqlError => sqlError);

        // update last modified datetime
        const currentDateTime = getFormattedCurrentDateTime();
        alasql.promise([stringManipulator.stringConcat('UPDATE ', constants.ENTITIES_FILE_MANAGER,
                                                       ' SET ', constants.HEADER_FILE_MANAGER_LAST_MODIFIED_DATE,
                                                       ' = "', currentDateTime,
                                                       '" WHERE ', constants.HEADER_FILE_MANAGER_FILE_ID,
                                                       ' = ', fileId)])
          .then(() => true).catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };
  };

  this.deleteTable = function deleteTable(tableName) {
    alasql(stringManipulator.stringConcat('DROP TABLE ', tableName), callback());
  };

  this.cleanTable = function cleanTable(tableName) {
    alasql(stringManipulator.stringConcat('DELETE * FROM ', tableName), callback());
  };
}
<commit_msg>Add deleteFile implementation into sqlCommands.js<commit_after>import StringManipulator from '../stringManipulation';

import exceptions from '../exceptions';

import constants from '../constants';

import DateTime from '../generated-data/dateTime';

const alasql = require('alasql');

const stringManipulator = new StringManipulator();

const dateTime = new DateTime();

function getFormattedCurrentDateTime() {
  return stringManipulator.stringConcat('"', dateTime.getCurrentDateTime(), '"');
}

export default function sqlCommands() {
  this.linkDatabaseToIndexedDB = function linkDatabaseToIndexedDB() {
    const databaseRequestStr = "CREATE INDEXEDDB DATABASE IF NOT EXISTS lectureNote; " +
                               "ATTACH INDEXEDDB DATABASE lectureNote; " +
                               "USE lectureNote;";
    alasql.promise([databaseRequestStr])
      .then().catch(sqlError => sqlError);
  };

  this.getFullTableData = function getFullTableData(tableName) {
    // ensure working in browsers that support Promise
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT * FROM ', tableName)])
          .then(data => resolve(data))
          .catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };

  this.createTable = function createTable(sqlStatement) {
    alasql.promise([stringManipulator.stringConcat('CREATE TABLE IF NOT EXISTS ', sqlStatement)])
      .then().catch(sqlError => sqlError);
  };

  this.insertContent = function insertContent(tableName, ...content) {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        // concatenate all the values to insert together
        const valuesToInsertIntoTable = content.join(', ');
        alasql.promise([stringManipulator.stringConcat('INSERT INTO ', tableName,
                                                       ' VALUES (', valuesToInsertIntoTable, ')')])
        .then(() => true)
        .catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };

  this.partialSearchFileName = function partialSearchFileName(searchString) {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT * FROM ', constants.ENTITIES_FILE_MANAGER,
                                                       ' WHERE ', constants.HEADER_FILE_MANAGER_FILE_NAME,
                                                       ' LIKE "%', searchString, '%"')])
        .then(data => resolve(data))
        .catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };
  this.getMaxFileId = function getMaxFileId() {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT MAX(', constants.HEADER_FILE_MANAGER_FILE_ID,
                                                       ') FROM ', constants.ENTITIES_FILE_MANAGER)])
        .then((data) => {
          const maxFileId = getDataOutOfAlasql(data);
          if (typeof maxFileId === 'number') {
            resolve(maxFileId);
          } else {
            resolve(-1);
          }
        }).catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };
  this.getMaxFolderId = function getMaxFolderId() {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT MAX(', constants.HEADER_FOLDER_FOLDER_ID,
                                                       ') FROM ', constants.ENTITIES_FOLDER)])
        .then((data) => {
          const maxFolderId = getDataOutOfAlasql(data);
          if (typeof maxFolderId === 'number') {
            resolve(maxFolderId);
          } else {
            resolve(0);
          }
        }).catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };

  this.partialSearchFolderName = function partialSearchFolderName(searchString) {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT * FROM ', constants.ENTITIES_FOLDER,
                                                       ' WHERE ', constants.HEADER_FOLDER_FOLDER_NAME,
                                                       ' LIKE "%', searchString, '%"')])
        .then(data => resolve(data))
        .catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };

  this.loadFilesFromFolder = function loadFilesFromFolder(folderId) {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT * FROM ', constants.ENTITIES_FILE_MANAGER,
                                                       ' WHERE ', constants.HEADER_FILE_MANAGER_FOLDER_ID,
                                                       ' = ', folderId)])
        .then(data => resolve(data))
        .catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };

  this.loadFoldersFromFolder = function loadFoldersFromFolder(folderId) {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT * FROM ', constants.ENTITIES_FOLDER,
                                                       ' WHERE ', constants.HEADER_FOLDER_PARENT_FOLDER_ID,
                                                       ' = ', folderId,
                                                       ' AND ', constants.HEADER_FOLDER_PARENT_FOLDER_ID,
                                                       ' != NULL')])
          .then(data => resolve(data))
          .catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };

  this.loadFile = function loadFile(fileId) {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('SELECT ', constants.HEADER_FILE_MANAGER_FILE_MARKDOWN,
                                                       ' FROM ', constants.ENTITIES_FILE_MANAGER,
                                                       ' WHERE ', constants.HEADER_FILE_MANAGER_FILE_ID,
                                                       ' = ', fileId)])
        .then(data => resolve(data))
        .catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };

  this.saveFile = function saveFile(fileId, markdownFile) {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        // save file
        alasql.promise([stringManipulator.stringConcat('UPDATE ', constants.ENTITIES_FILE_MANAGER,
                                                       ' SET ', constants.HEADER_FILE_MANAGER_FILE_MARKDOWN,
                                                       ' = "', markdownFile,
                                                       '" WHERE ', constants.HEADER_FILE_MANAGER_FILE_ID,
                                                       ' = ', fileId)])
          .then().catch(sqlError => sqlError);

        // update last modified datetime
        const currentDateTime = getFormattedCurrentDateTime();
        alasql.promise([stringManipulator.stringConcat('UPDATE ', constants.ENTITIES_FILE_MANAGER,
                                                       ' SET ', constants.HEADER_FILE_MANAGER_LAST_MODIFIED_DATE,
                                                       ' = "', currentDateTime,
                                                       '" WHERE ', constants.HEADER_FILE_MANAGER_FILE_ID,
                                                       ' = ', fileId)])
          .then(() => true).catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };

  this.deleteFile = function deleteFile(fileId) {
    if (typeof Promise === 'function') {
      return new Promise((resolve, reject) => {
        alasql.promise([stringManipulator.stringConcat('DELETE FROM ', constants.ENTITIES_FILE_MANAGER,
                                                       ' WHERE ', constants.HEADER_FILE_MANAGER_FILE_ID,
                                                       ' = ', fileId)])
        .then(() => true)
        .catch(sqlError => sqlError);
      });
    } else {
      throw new exceptions.PromiseFunctionNotDefined();
    }
  };
  };

  this.deleteTable = function deleteTable(tableName) {
    alasql(stringManipulator.stringConcat('DROP TABLE ', tableName), callback());
  };

  this.cleanTable = function cleanTable(tableName) {
    alasql(stringManipulator.stringConcat('DELETE * FROM ', tableName), callback());
  };
}
<|endoftext|>


<commit_before>const React = require('react');
const Navigation = require('./../../components/Navigation/Navigation.js');

const Menu = React.createClass({
  contextTypes: {
    router: React.PropTypes.object.isRequired
  },

  getInitialState: function() {
    return {
      activeMenu: 0
    };
  },

  handleAction: function() {
    let path = this.props.route.childRoutes[this.state.activeMenu].path;
    if (path === 'quit') {
      this.props.options.exit();
    }
    if (path === 'back') {
      this.props.actions.toggleMenu('menu', 'Fermeture du menu');
    }
    else {
      this.context.router.push('menu/' + path);
    }
  },

  changeActiveMenu: function(index) {
    this.setState({activeMenu: index});
  },

  read: function(text) {
    this.props.options.tts.speak(text);
  },

  render: function() {
    return (
      <Navigation
        action={this.handleAction}
        read={this.read}
        index={this.state.activeMenu}
        items={this.props.route.childRoutes}
        changeIndex={this.changeActiveMenu}
        read={this.read}
        >
      </Navigation>
    );
  }
});

module.exports = Menu;
<commit_msg>Remove duplicate props<commit_after>const React = require('react');
const Navigation = require('./../../components/Navigation/Navigation.js');

const Menu = React.createClass({
  contextTypes: {
    router: React.PropTypes.object.isRequired
  },

  getInitialState: function() {
    return {
      activeMenu: 0
    };
  },

  handleAction: function() {
    let path = this.props.route.childRoutes[this.state.activeMenu].path;
    if (path === 'quit') {
      this.props.options.exit();
    }
    if (path === 'back') {
      this.props.actions.toggleMenu('menu', 'Fermeture du menu');
    }
    else {
      this.context.router.push('menu/' + path);
    }
  },

  changeActiveMenu: function(index) {
    this.setState({activeMenu: index});
  },

  read: function(text) {
    this.props.options.tts.speak(text);
  },

  render: function() {
    return (
      <Navigation
        action={this.handleAction}
        index={this.state.activeMenu}
        items={this.props.route.childRoutes}
        changeIndex={this.changeActiveMenu}
        read={this.read}
        >
      </Navigation>
    );
  }
});

module.exports = Menu;
<|endoftext|>


<commit_before>/**
 * Using Rails-like standard naming convention for endpoints.
 * GET     /api/sections              ->  index
 * POST    /api/sections              ->  create
 * GET     /api/sections/:id          ->  show
 * PUT     /api/sections/:id          ->  update
 * DELETE  /api/sections/:id          ->  destroy
 */

'use strict';

var _ = require('lodash');
var async = require("async");
var Auth = require('../../auth/auth.service');
import Section from './section.model';
import User from '../user/user.model';

// Takes a Bool flag and Function func, returns a Promise to execute func on
// mongooseObject and responseObject inputs
// call the "done" of func when finished manipulating data.
// @param Function func: func(mongooseObject, responseObject, done)
// Note: The function "func" must return [mongooseObject, responseObject]
function ifFlagManipulate(flag, func){
  return (mongooseObject, responseObject) => {
    if (flag){
      return new Promise((resolve, reject) => {
        func(mongooseObject, responseObject, (newMongooseObject, newResponseObject)=>{
          if (!newResponseObject){
            var err = newMongooseObject;
            reject(err);
          }else{
            resolve([newMongooseObject, newResponseObject]);
          }
        });
      });
    }else{
      return Promise.all([mongooseObject, responseObject]);
    }
  };
}

function handleError(res, statusCode) {
  statusCode = statusCode || 500;
  return function(err) {
    res.status(statusCode).send(err);
  };
}

function responseWithResult(res, statusCode) {
  statusCode = statusCode || 200;
  return function(entity) {
    if (entity) {
      res.status(statusCode).json(entity);
    }
  };
}

function handleEntityNotFound(res) {
  return function(entity) {
    if (!entity) {
      res.status(404).end();
      return null;
    }
    return entity;
  };
}

function saveUpdates(updates) {
  return function(entity) {
    var updated = _.merge(entity, updates);
    return updated.saveAsync()
      .spread(function(updated) {
        return updated;
      });
  };
}

function removeEntity(res) {
  return function(entity) {
    if (entity) {
      return entity.removeAsync()
        .then(function() {
          res.status(204).end();
        });
    }
  };
}

function updateSection(req){
  if(req.body.pendingStudent){
    return updatePendingStudents(req);
  }
  else{
    return saveSectionUpdates(req);
  }
}

function updatePendingStudents(req){
  return (section) =>{
    var pendingStudent = req.body.pendingStudent;
    if(section.pendingStudents.remove(pendingStudent)){
      section.students.push(pendingStudent);
      return section.saveAsync()
        .spread((sect)=>{
          return Section.populate(sect, {path:"pendingStudents"})
        });
    }
  }
}

function checkSectionReq(req) {
  // Check sections numbers
  var sectionNumbers = req.body.sectionNumbers.map(Number);
  if(sectionNumbers){
    sectionNumbers.sort();
    for (var i = 0; i < sectionNumbers.length - 1; i++) {
      if(sectionNumbers[i] < 0){
        throw "Section number must be greater than zero";
      }
      if (sectionNumbers[i + 1] == sectionNumbers[i]) {
        throw "Duplicate section numbers found";
      }
    }
  }
}

function saveSectionUpdates(req) {
  return (section) => {
    checkSectionReq(req);
    section.sectionNumbers = req.body.sectionNumbers.map(Number);
    section.enrollmentPolicy = req.body.enrollmentPolicy;
    section.instructors = req.body.instructors;
    return section.saveAsync()
      .spread(function(updated) {
        return updated;
      });
  }
}

// Gets a list of Sections
// Filter by current user ?onlyUser=me
// Filter by user (id) ?onlyUser=:id
// Filter by current user ?onlyCurrentUser=true

exports.index = function(req, res, next)  {
    var query = Section.find();
    query = exports.getSectionsExtra(query,req.query);

    query.then(responseWithResult(res))
    .catch(handleError(res));
};

// Gets a list of Sections for a user
exports.userSections = function(req, res, next) {
  var userId = req.params.id;
  User.findById(userId)
  .select('-salt -password')
  .execAsync()
  .then((user) => {
    if (!user) {
      return res.status(404).end();
    }
    var profile = user.toJSON();
    return Promise.all([user, profile]);
  })
  .spread(ifFlagManipulate(true, (user,profile,done)=>{
    user.getSectionsAsync(req.query).then((sections) => {
      profile.sections = sections;
      done(user, profile);
    });
  }))
  .spread((user,profile) => {
    return res.json(profile.sections);

  })
  .catch(err => next(err));
};

// Gets a list of Sections for the user
exports.mySections = function(req, res, next) {
  var userId = req.user._id;
  req.params.id = userId;
  exports.userSections(req, res, next);
};

// Gets a single Section from the DB
exports.show = function(req, res) {
  var query = Section.findByIdAsync(req.params.id);

  query = exports.getSectionsExtra(query,req.query);

  query
    .then(handleEntityNotFound(res))
    .then(responseWithResult(res))
    .catch(handleError(res));
};

// Creates a new Section in the DB
exports.create = function(req, res) {
  try{checkSectionReq(req);}
  catch(err) { return handleError(res)(err);}
  Section.createAsync(req.body)
    .then(responseWithResult(res, 201))
    .catch(handleError(res));
};

// Updates an existing Section in the DB
exports.update = function(req, res) {
  if (req.body._id) {
    delete req.body._id;
  }
  Section.findByIdAsync(req.params.id)
    .then(handleEntityNotFound(res))
    .then(updateSection(req))
    .then(responseWithResult(res))
    .catch(handleError(res));
};

// Deletes a Section from the DB
exports.destroy = function(req, res) {
  Section.findByIdAsync(req.params.id)
    .then(handleEntityNotFound(res))
    .then(removeEntity(res))
    .catch(handleError(res));
};

exports.getSectionsExtra = function (query, opts){
  opts = opts || {};

  //FIXME too many endpoints see #113
  if (opts.withSectionsEvent || opts.withSectionEvent){
    query = query.populate('events');
  }
  if (opts.withSectionsCourse || opts.withSectionCourse){
    query = query.populate('course');
  }
  if (opts.withSectionsInstructors || opts.withSectionInstructors){
    query = query.populate('instructors');
  }
  if (opts.withSectionsStudents || opts.withSectionStudents){
    query = query.populate('students');
  }
  if (opts.withSectionsPendingStudents || opts.withSectionPendingStudents){
    query = query.populate('pendingStudents');
  }
  return query;
}
<commit_msg>removed needless ifFlagManipulates call<commit_after>/**
 * Using Rails-like standard naming convention for endpoints.
 * GET     /api/sections              ->  index
 * POST    /api/sections              ->  create
 * GET     /api/sections/:id          ->  show
 * PUT     /api/sections/:id          ->  update
 * DELETE  /api/sections/:id          ->  destroy
 */

'use strict';

var _ = require('lodash');
var async = require("async");
var Auth = require('../../auth/auth.service');
import Section from './section.model';
import User from '../user/user.model';

// Takes a Bool flag and Function func, returns a Promise to execute func on
// mongooseObject and responseObject inputs
// call the "done" of func when finished manipulating data.
// @param Function func: func(mongooseObject, responseObject, done)
// Note: The function "func" must return [mongooseObject, responseObject]
function ifFlagManipulate(flag, func){
  return (mongooseObject, responseObject) => {
    if (flag){
      return new Promise((resolve, reject) => {
        func(mongooseObject, responseObject, (newMongooseObject, newResponseObject)=>{
          if (!newResponseObject){
            var err = newMongooseObject;
            reject(err);
          }else{
            resolve([newMongooseObject, newResponseObject]);
          }
        });
      });
    }else{
      return Promise.all([mongooseObject, responseObject]);
    }
  };
}

function handleError(res, statusCode) {
  statusCode = statusCode || 500;
  return function(err) {
    res.status(statusCode).send(err);
  };
}

function responseWithResult(res, statusCode) {
  statusCode = statusCode || 200;
  return function(entity) {
    if (entity) {
      res.status(statusCode).json(entity);
    }
  };
}

function handleEntityNotFound(res) {
  return function(entity) {
    if (!entity) {
      res.status(404).end();
      return null;
    }
    return entity;
  };
}

function saveUpdates(updates) {
  return function(entity) {
    var updated = _.merge(entity, updates);
    return updated.saveAsync()
      .spread(function(updated) {
        return updated;
      });
  };
}

function removeEntity(res) {
  return function(entity) {
    if (entity) {
      return entity.removeAsync()
        .then(function() {
          res.status(204).end();
        });
    }
  };
}

function updateSection(req){
  if(req.body.pendingStudent){
    return updatePendingStudents(req);
  }
  else{
    return saveSectionUpdates(req);
  }
}

function updatePendingStudents(req){
  return (section) =>{
    var pendingStudent = req.body.pendingStudent;
    if(section.pendingStudents.remove(pendingStudent)){
      section.students.push(pendingStudent);
      return section.saveAsync()
        .spread((sect)=>{
          return Section.populate(sect, {path:"pendingStudents"})
        });
    }
  }
}

function checkSectionReq(req) {
  // Check sections numbers
  var sectionNumbers = req.body.sectionNumbers.map(Number);
  if(sectionNumbers){
    sectionNumbers.sort();
    for (var i = 0; i < sectionNumbers.length - 1; i++) {
      if(sectionNumbers[i] < 0){
        throw "Section number must be greater than zero";
      }
      if (sectionNumbers[i + 1] == sectionNumbers[i]) {
        throw "Duplicate section numbers found";
      }
    }
  }
}

function saveSectionUpdates(req) {
  return (section) => {
    checkSectionReq(req);
    section.sectionNumbers = req.body.sectionNumbers.map(Number);
    section.enrollmentPolicy = req.body.enrollmentPolicy;
    section.instructors = req.body.instructors;
    return section.saveAsync()
      .spread(function(updated) {
        return updated;
      });
  }
}

// Gets a list of Sections
// Filter by current user ?onlyUser=me
// Filter by user (id) ?onlyUser=:id
// Filter by current user ?onlyCurrentUser=true

exports.index = function(req, res, next)  {
    var query = Section.find();
    query = exports.getSectionsExtra(query,req.query);

    query.then(responseWithResult(res))
    .catch(handleError(res));
};

// Gets a list of Sections for a user
exports.userSections = function(req, res, next) {
  var userId = req.params.id;
  User.findById(userId)
  .select('-salt -password')
  .execAsync()
  .then((user) => {
    if (!user) {
      return res.status(404).end();
    }
    var profile = user.toJSON();
    return Promise.all([user, profile]);
  })
  .spread((user,profile,done)=>{
    user.getSectionsAsync(req.query).then((sections) => {
      profile.sections = sections;
      done(user, profile);
    });
  })
  .spread((user,profile) => {
    return res.json(profile.sections);

  })
  .catch(err => next(err));
};

// Gets a list of Sections for the user
exports.mySections = function(req, res, next) {
  var userId = req.user._id;
  req.params.id = userId;
  exports.userSections(req, res, next);
};

// Gets a single Section from the DB
exports.show = function(req, res) {
  var query = Section.findByIdAsync(req.params.id);

  query = exports.getSectionsExtra(query,req.query);

  query
    .then(handleEntityNotFound(res))
    .then(responseWithResult(res))
    .catch(handleError(res));
};

// Creates a new Section in the DB
exports.create = function(req, res) {
  try{checkSectionReq(req);}
  catch(err) { return handleError(res)(err);}
  Section.createAsync(req.body)
    .then(responseWithResult(res, 201))
    .catch(handleError(res));
};

// Updates an existing Section in the DB
exports.update = function(req, res) {
  if (req.body._id) {
    delete req.body._id;
  }
  Section.findByIdAsync(req.params.id)
    .then(handleEntityNotFound(res))
    .then(updateSection(req))
    .then(responseWithResult(res))
    .catch(handleError(res));
};

// Deletes a Section from the DB
exports.destroy = function(req, res) {
  Section.findByIdAsync(req.params.id)
    .then(handleEntityNotFound(res))
    .then(removeEntity(res))
    .catch(handleError(res));
};

exports.getSectionsExtra = function (query, opts){
  opts = opts || {};

  //FIXME too many endpoints see #113
  if (opts.withSectionsEvent || opts.withSectionEvent){
    query = query.populate('events');
  }
  if (opts.withSectionsCourse || opts.withSectionCourse){
    query = query.populate('course');
  }
  if (opts.withSectionsInstructors || opts.withSectionInstructors){
    query = query.populate('instructors');
  }
  if (opts.withSectionsStudents || opts.withSectionStudents){
    query = query.populate('students');
  }
  if (opts.withSectionsPendingStudents || opts.withSectionPendingStudents){
    query = query.populate('pendingStudents');
  }
  return query;
}
<|endoftext|>


<commit_before>const Command = require("../base/slashCommand");

class Poll extends Command {
    constructor(Bot) {
        super(Bot, {
            name: "poll",
            category: "Misc",
            aliases: ["vote"],
            permissions: ["EMBED_LINKS"],
            guildOnly: false,
            options: [
                // Subcommands for create, view, end, cancel, vote
                {
                    name: "create",
                    description: "Create a poll",
                    type: "SUB_COMMAND",
                    options: [
                        {
                            name: "question",
                            required: true,
                            description: "The question you want people to vote on",
                            type: "STRING"
                        },
                        {
                            name: "options",
                            required: true,
                            description: "Options for the poll, separated by a pipe symbol `|`",
                            type: "STRING"
                        },
                        {
                            name: "anonymous",
                            description: "If enabled, current votes will not be shown until the poll is closed. ",
                            type: "BOOLEAN"
                        }
                    ]
                },
                {
                    name: "end",
                    description: "End a poll, and show the final results",
                    type: "SUB_COMMAND",
                    options: []
                },
                {
                    name: "cancel",
                    description: "Cancel a poll, don't bother with the results",
                    type: "SUB_COMMAND",
                    options: []
                },
                {
                    name: "view",
                    description: "View the status of a poll with the current results",
                    type: "SUB_COMMAND",
                    options: [ ]
                },
                {
                    name: "vote",
                    description: "Vote on a poll (your vote will be hidden)",
                    type: "SUB_COMMAND",
                    options: [
                        {
                            name: "option",
                            required: true,
                            description: "The poll option you want to vote for",
                            type: "INTEGER",
                            min_value: 0,
                            max_value: 10,
                        }
                    ]
                }
            ]
        });
    }

    async run(Bot, interaction, options) {
        const action = interaction.options.getSubcommand();

        const restrictedActions = ["cancel", "create", "end"];

        let poll = { // ID = guildID-channelID
            "question": "",
            "options": [],
            "votes": {
                // userID: vote#
            },
            "anon": false
        };

        if (!interaction.guild || !interaction.channel) {
            // This is not available in DMs
            // TODO Lang this
            return super.error(interaction, "Sorry, but this command is not available in DMs. If you are voting with `/poll vote`, it will only show for you.");
        }
        const pollID = `${interaction.guild.id}-${interaction.channel.id}`;

        // If they're just voting on the channel's poll
        const oldPoll = await Bot.database.models.polls.findOne({where: {id: pollID}});
        const oldPolllDv = oldPoll?.dataValues;

        if (oldPolllDv && action === "create") {
            // If they're trying to create a new poll when one exists, tell em
            return super.error(interaction, interaction.language.get("COMMAND_POLL_ALREADY_RUNNING"));
        } else if (!oldPolllDv && action !== "create") {
            // If they're tyring to use a poll that doesn't exist, let them know
            return super.error(interaction, "Sorry, but there is no poll active in this channel.");
        }

        if (oldPolllDv) {
            poll = oldPolllDv.poll;
        }

        // Make sure it's a mod or someone with the appropriate perms trying to create it
        if (restrictedActions.includes(action) && options.level < Bot.constants.GUILD_ADMIN) {
            return super.error(interaction, interaction.language.get("COMMAND_MISSING_PERMS"));
        }

        switch (action) {
            case "create": {
                const optionsString = interaction.options.getString("options");
                poll.question       = interaction.options.getString("question");
                poll.anon           = interaction.options.getBoolean("anonymous");
                poll.options        = optionsString.split("|").map(opt => opt.trim());

                // Make sure the question is kept within a reasonable length (Not sure why I chose 256 at the time)
                if (poll.question.length >= 256) {
                    return super.error(interaction, interaction.language.get("COMMAND_POLL_TITLE_TOO_LONG"));
                }

                // Keep the choices limited to between 2 & 10 options
                if (poll.options.length < 2) {
                    return super.error(interaction, interaction.language.get("COMMAND_POLL_TOO_FEW_OPT"));
                } else if (poll.options.length > 10) {
                    return super.error(interaction, interaction.language.get("COMMAND_POLL_TOO_MANY_OPT"));
                }

                // Create a poll (lvl 3+)
                await Bot.database.models.polls.create({
                    id: pollID,
                    poll: poll
                })
                    .then((thisPoll) => {
                        poll.pollID = thisPoll.dataValues.pollId;
                        return interaction.reply({
                            content: interaction.language.get("COMMAND_POLL_CREATED_SLASH", interaction.user.tag, interaction.guildSettings.prefix),
                            embeds: [{
                                author: {
                                    name: poll.question
                                },
                                description: pollCheck(poll),
                                footer: getFooter(poll)
                            }]
                        });
                    })
                    .catch((err) => {
                        Bot.logger.error("Broke when creating a poll: \n" + err);
                        return super.error(interaction, "Sorry, but something went wrong when saving that poll. Please try again in a bit");
                    });
                break;
            }
            case "cancel": {
                // Cancel the current poll in a channel, need to ask for confirmation, maybe try and use a button here at some point?
                // Delete the current poll
                await Bot.database.models.polls.destroy({where: {id: pollID}})
                    .then(() => {
                        // Then send a message confirming the deletion
                        return super.success(interaction, "> Poll deleted.");
                    })
                    .catch(() => {
                        // Or, if it breaks, tell them that it broke
                        return super.error(interaction, interaction.language.get("COMMAND_POLL_FINAL_ERROR", poll.question));
                    });
                break;
            }
            case "end": {
                // End the current poll in a channel, need to ask for confirmation, maybe try and use a button here at some point?
                // Delete the current poll
                await Bot.database.models.polls.destroy({where: {id: pollID}})
                    .then(() => {
                        // Then send a message showing the final results
                        return interaction.reply({
                            embeds: [{
                                author: {
                                    name: interaction.language.get("COMMAND_POLL_FINAL", "")
                                },
                                description: `**${poll.question}**\n${pollCheck(poll, true)}`
                            }]
                        });
                    })
                    .catch(() => {
                        // Or, if it breaks, tell them that it broke
                        return super.error(interaction, interaction.language.get("COMMAND_POLL_FINAL_ERROR", poll.question));
                    });
                break;
            }
            case "view": {
                // View the current poll in a channel
                return interaction.reply({
                    embeds: [{
                        author: {
                            name: poll.question
                        },
                        description: pollCheck(poll),
                        footer: getFooter(poll)
                    }]
                });
            }
            case "vote": {
                // Vote on the current poll in a channel, and don't show any output for this
                // Doesn't need to be usable in DMs anymore because of the ephemeral reqponses now
                const opt = interaction.options.getInteger("option") - 1;
                if (poll.options.length <= opt || opt < 0) {
                    return super.error(interaction, interaction.language.get("COMMAND_POLL_INVALID_OPTION"), {ephemeral: true});
                } else {
                    let voted = null;
                    if (poll.votes[interaction.user.id] === opt) {
                        // Warn em that they're voting for the same thing they already voted for, so it won't be registered
                        return super.error(interaction, interaction.language.get("COMMAND_POLL_SAME_OPT", poll.options[opt]), {ephemeral: true});
                    } else if (!Number.isNaN(poll.votes[interaction.user.id])) {
                        voted = poll.votes[interaction.user.id];
                    }
                    poll.votes[interaction.user.id] = opt;
                    await Bot.database.models.polls.update({poll: poll}, {where: {id: pollID}})
                        .then(() => {
                            if (voted !== null) {
                                return interaction.reply({
                                    content: interaction.language.get("COMMAND_POLL_CHANGED_OPT", poll.options[voted], poll.options[opt]),
                                    ephemeral: true
                                });
                            } else {
                                return interaction.reply({
                                    content: interaction.language.get("COMMAND_POLL_REGISTERED", poll.options[opt]),
                                    ephemeral: true
                                });
                            }
                        });
                }
                break;
            }
        }

        function pollCheck(poll, showRes=false) {
            const voteCount = {};
            const totalVotes = Object.keys(poll.votes).length || 1;
            poll.options.forEach((opt, ix) => {
                voteCount[ix] = 0;
            });
            Object.keys(poll.votes).forEach(voter => {
                voteCount[poll.votes[voter]] += 1;
            });
            let outString = "";
            Object.keys(voteCount).forEach(opt => {
                const percent = Math.floor((voteCount[opt] / totalVotes) * 30);
                outString += `\`[${parseInt(opt, 10)+1}]\` **${poll.options[opt]}**\n`;
                if (!poll.anon || showRes) {
                    // If the poll is not set to anonymous, or it's told to show the results (for closing the poll)
                    outString += `**\`[${"#".repeat(percent)}${"-".repeat(30-percent)}]\`**(${voteCount[opt]})\n`;
                }
            });
            return outString;
        }

        function getFooter(poll) {
            const footer = {};
            if (interaction.guild) {
                footer.text = Bot.expandSpaces(interaction.language.get("COMMAND_POLL_FOOTER", poll.pollID, interaction.guildSettings.prefix));
            } else {
                footer.text = Bot.expandSpaces(interaction.language.get("COMMAND_POLL_DM_FOOTER", poll.pollID, interaction.guildSettings.prefix));
            }
            return footer;
        }
    }
}

module.exports = Poll;
<commit_msg>Fix polls being able to be created/ ended by anyone<commit_after>const Command = require("../base/slashCommand");

class Poll extends Command {
    constructor(Bot) {
        super(Bot, {
            name: "poll",
            category: "Misc",
            aliases: ["vote"],
            permissions: ["EMBED_LINKS"],
            guildOnly: false,
            options: [
                // Subcommands for create, view, end, cancel, vote
                {
                    name: "create",
                    description: "Create a poll",
                    type: "SUB_COMMAND",
                    options: [
                        {
                            name: "question",
                            required: true,
                            description: "The question you want people to vote on",
                            type: "STRING"
                        },
                        {
                            name: "options",
                            required: true,
                            description: "Options for the poll, separated by a pipe symbol `|`",
                            type: "STRING"
                        },
                        {
                            name: "anonymous",
                            description: "If enabled, current votes will not be shown until the poll is closed. ",
                            type: "BOOLEAN"
                        }
                    ]
                },
                {
                    name: "end",
                    description: "End a poll, and show the final results",
                    type: "SUB_COMMAND",
                    options: []
                },
                {
                    name: "cancel",
                    description: "Cancel a poll, don't bother with the results",
                    type: "SUB_COMMAND",
                    options: []
                },
                {
                    name: "view",
                    description: "View the status of a poll with the current results",
                    type: "SUB_COMMAND",
                    options: [ ]
                },
                {
                    name: "vote",
                    description: "Vote on a poll (your vote will be hidden)",
                    type: "SUB_COMMAND",
                    options: [
                        {
                            name: "option",
                            required: true,
                            description: "The poll option you want to vote for",
                            type: "INTEGER",
                            min_value: 0,
                            max_value: 10,
                        }
                    ]
                }
            ]
        });
    }

    async run(Bot, interaction, options) {
        const action = interaction.options.getSubcommand();

        let poll = { // ID = guildID-channelID
            "question": "",
            "options": [],
            "votes": {
                // userID: vote#
            },
            "anon": false
        };

        if (!interaction.guild || !interaction.channel) {
            // This is not available in DMs
            // TODO Lang this
            return super.error(interaction, "Sorry, but this command is not available in DMs. If you are voting with `/poll vote`, it will only show for you.");
        }
        const pollID = `${interaction.guild.id}-${interaction.channel.id}`;

        // If they're just voting on the channel's poll
        const oldPoll = await Bot.database.models.polls.findOne({where: {id: pollID}});
        const oldPolllDv = oldPoll?.dataValues;

        if (oldPolllDv && action === "create") {
            // If they're trying to create a new poll when one exists, tell em
            return super.error(interaction, interaction.language.get("COMMAND_POLL_ALREADY_RUNNING"));
        } else if (!oldPolllDv && action !== "create") {
            // If they're tyring to use a poll that doesn't exist, let them know
            return super.error(interaction, "Sorry, but there is no poll active in this channel.");
        }

        if (oldPolllDv) {
            poll = oldPolllDv.poll;
        }

        // Make sure it's a mod or someone with the appropriate perms trying to create it
        const restrictedActions = ["cancel", "create", "end"];
        if (restrictedActions.includes(action) && options.level < Bot.constants.permMap.GUILD_ADMIN) {
            return super.error(interaction, interaction.language.get("COMMAND_MISSING_PERMS"));
        }

        switch (action) {
            case "create": {
                const optionsString = interaction.options.getString("options");
                poll.question       = interaction.options.getString("question");
                poll.anon           = interaction.options.getBoolean("anonymous");
                poll.options        = optionsString.split("|").map(opt => opt.trim());

                // Make sure the question is kept within a reasonable length (Not sure why I chose 256 at the time)
                if (poll.question.length >= 256) {
                    return super.error(interaction, interaction.language.get("COMMAND_POLL_TITLE_TOO_LONG"));
                }

                // Keep the choices limited to between 2 & 10 options
                if (poll.options.length < 2) {
                    return super.error(interaction, interaction.language.get("COMMAND_POLL_TOO_FEW_OPT"));
                } else if (poll.options.length > 10) {
                    return super.error(interaction, interaction.language.get("COMMAND_POLL_TOO_MANY_OPT"));
                }

                // Create a poll (lvl 3+)
                await Bot.database.models.polls.create({
                    id: pollID,
                    poll: poll
                })
                    .then((thisPoll) => {
                        poll.pollID = thisPoll.dataValues.pollId;
                        return interaction.reply({
                            content: interaction.language.get("COMMAND_POLL_CREATED_SLASH", interaction.user.tag, interaction.guildSettings.prefix),
                            embeds: [{
                                author: {
                                    name: poll.question
                                },
                                description: pollCheck(poll),
                                footer: getFooter(poll)
                            }]
                        });
                    })
                    .catch((err) => {
                        Bot.logger.error("Broke when creating a poll: \n" + err);
                        return super.error(interaction, "Sorry, but something went wrong when saving that poll. Please try again in a bit");
                    });
                break;
            }
            case "cancel": {
                // Cancel the current poll in a channel, need to ask for confirmation, maybe try and use a button here at some point?
                // Delete the current poll
                await Bot.database.models.polls.destroy({where: {id: pollID}})
                    .then(() => {
                        // Then send a message confirming the deletion
                        return super.success(interaction, "> Poll deleted.");
                    })
                    .catch(() => {
                        // Or, if it breaks, tell them that it broke
                        return super.error(interaction, interaction.language.get("COMMAND_POLL_FINAL_ERROR", poll.question));
                    });
                break;
            }
            case "end": {
                // End the current poll in a channel, need to ask for confirmation, maybe try and use a button here at some point?
                // Delete the current poll
                await Bot.database.models.polls.destroy({where: {id: pollID}})
                    .then(() => {
                        // Then send a message showing the final results
                        return interaction.reply({
                            embeds: [{
                                author: {
                                    name: interaction.language.get("COMMAND_POLL_FINAL", "")
                                },
                                description: `**${poll.question}**\n${pollCheck(poll, true)}`
                            }]
                        });
                    })
                    .catch(() => {
                        // Or, if it breaks, tell them that it broke
                        return super.error(interaction, interaction.language.get("COMMAND_POLL_FINAL_ERROR", poll.question));
                    });
                break;
            }
            case "view": {
                // View the current poll in a channel
                return interaction.reply({
                    embeds: [{
                        author: {
                            name: poll.question
                        },
                        description: pollCheck(poll),
                        footer: getFooter(poll)
                    }]
                });
            }
            case "vote": {
                // Vote on the current poll in a channel, and don't show any output for this
                // Doesn't need to be usable in DMs anymore because of the ephemeral reqponses now
                const opt = interaction.options.getInteger("option") - 1;
                if (poll.options.length <= opt || opt < 0) {
                    return super.error(interaction, interaction.language.get("COMMAND_POLL_INVALID_OPTION"), {ephemeral: true});
                } else {
                    let voted = null;
                    if (poll.votes[interaction.user.id] === opt) {
                        // Warn em that they're voting for the same thing they already voted for, so it won't be registered
                        return super.error(interaction, interaction.language.get("COMMAND_POLL_SAME_OPT", poll.options[opt]), {ephemeral: true});
                    } else if (!Number.isNaN(poll.votes[interaction.user.id])) {
                        voted = poll.votes[interaction.user.id];
                    }
                    poll.votes[interaction.user.id] = opt;
                    await Bot.database.models.polls.update({poll: poll}, {where: {id: pollID}})
                        .then(() => {
                            if (voted !== null) {
                                return interaction.reply({
                                    content: interaction.language.get("COMMAND_POLL_CHANGED_OPT", poll.options[voted], poll.options[opt]),
                                    ephemeral: true
                                });
                            } else {
                                return interaction.reply({
                                    content: interaction.language.get("COMMAND_POLL_REGISTERED", poll.options[opt]),
                                    ephemeral: true
                                });
                            }
                        });
                }
                break;
            }
        }

        function pollCheck(poll, showRes=false) {
            const voteCount = {};
            const totalVotes = Object.keys(poll.votes).length || 1;
            poll.options.forEach((opt, ix) => {
                voteCount[ix] = 0;
            });
            Object.keys(poll.votes).forEach(voter => {
                voteCount[poll.votes[voter]] += 1;
            });
            let outString = "";
            Object.keys(voteCount).forEach(opt => {
                const percent = Math.floor((voteCount[opt] / totalVotes) * 30);
                outString += `\`[${parseInt(opt, 10)+1}]\` **${poll.options[opt]}**\n`;
                if (!poll.anon || showRes) {
                    // If the poll is not set to anonymous, or it's told to show the results (for closing the poll)
                    outString += `**\`[${"#".repeat(percent)}${"-".repeat(30-percent)}]\`**(${voteCount[opt]})\n`;
                }
            });
            return outString;
        }

        function getFooter(poll) {
            const footer = {};
            if (interaction.guild) {
                footer.text = Bot.expandSpaces(interaction.language.get("COMMAND_POLL_FOOTER", poll.pollID, interaction.guildSettings.prefix));
            } else {
                footer.text = Bot.expandSpaces(interaction.language.get("COMMAND_POLL_DM_FOOTER", poll.pollID, interaction.guildSettings.prefix));
            }
            return footer;
        }
    }
}

module.exports = Poll;
<|endoftext|>


<commit_before>'use strict';

const got = require('got');
const path = require('path');
const moment = require('moment');
const pad = require('lodash.padstart');
const _ = require('lodash');
const AWS = require('aws-sdk')
const local = require('kes/src/local');
const metadata = require('../../lib/metadata');
var through2 = require('through2')

const bands = [
  'ANG.txt',
  'B1.TIF',
  'B2.TIF',
  'B3.TIF',
  'B4.TIF',
  'B5.TIF',
  'B6.TIF',
  'B7.TIF',
  'B8.TIF',
  'B9.TIF',
  'B10.TIF',
  'B11.TIF',
  'BQA.TIF',
  'MTL.txt'
];

const s3 = new AWS.S3()

function googleLinks(data) {
  const row = pad(data.row, 3, '0');
  const _path = pad(data.path, 3, '0');
  //const sceneId = data.sceneID;
  const productId = data.LANDSAT_PRODUCT_ID;

  const c1Console = `https://console.cloud.google.com/storage/browser/gcp-public-data-landsat/LC08/${path.join(_path, row, productId)}`;
  const c1Base = `https://storage.googleapis.com/gcp-public-data-landsat/LC08/01/${path.join(_path, row, productId)}`;

  const c1Files = bands.map((b) => `${c1Base}/${productId}_${b}`);

  const c1 = {
    index: c1Console,
    files: c1Files
  };

  return { c1 };
}

//! Check to see if a URL exists
function fileExists(url) {
  var params = {
    Bucket: 'landsat-pds',
    Key: url.slice(36)
  }
  return new Promise(function(resolve, reject) {
    s3.headObject(params, function (err, metadata) {
      if (err && err.code === 'NotFound') {
        reject(url)
      } else {
        resolve(url)
      }
    })
  })
  /*return new Promise(function(resolve, reject) {
    got(url).then(response => {
      resolve(url);
    }).catch(e => {
      reject(url);
    });
  });*/
}

//! iterate over an array synchronously, invoke function on each element
function arrayIterate(values, fn) {
  return new Promise(function(resolve, reject) {
    // Are there any values to check?
    if (values.length === 0) {
      // All were rejected
      reject();
    }
    // Try the first value
    fn(values[0]).then(function(val) {
      // Resolved, we're all done
      //console.log('Resolved ' + val);
      resolve(val);
    }).catch(function() {
      // Rejected, remove the first item from the array and recursively
      // try the next one
      //console.log('Rejected ' + values[0]);
      values.shift();
      arrayIterate(values, fn).then(resolve).catch(reject);
    });
  });
}

function awsLinks(data) {
  const row = pad(data.row, 3, '0');
  const _path = pad(data.path, 3, '0');
  const sceneId = data.sceneID;
  const productId = data.LANDSAT_PRODUCT_ID;

  const c1Base = `https://landsat-pds.s3.amazonaws.com/c1/L8/${path.join(_path, row, productId)}`;
  const c1Files = bands.map((b) => `${c1Base}/${productId}_${b}`);

  const c1 = {
    index: `${c1Base}/index.html`,
    files: c1Files,
    thumbnail: `${c1Base}/${productId}_thumb_large.jpg`
  };

  return new Promise(function(resolve, reject) {
    // AWS doesn't include all C1 scenes, we return the old urls for
    // any scenes that is before May 1 2017
    info = {};
    if (moment(data.acquisitionDate) > moment('2017-04-30')) {
      resolve(c1)
    } else {
      const _sceneId = sceneId.slice(0, -2);
      const rev = sceneId.slice(-2)
      var prefix = `http://landsat-pds.s3.amazonaws.com/L8/${path.join(_path, row, _sceneId)}`;
      var links = _.range(rev, -1, -1).map(r => `${prefix}` + pad(r, 2, '0') + '/index.html');

      arrayIterate(links, fileExists).then(val => {
        prefix = prefix + val.slice(-13, -11);
        const pre = {
          index: `${prefix}/index.html`,
          files: bands.map((b) => `${prefix}_${b}`),
          thumbnail: `${prefix}_thumb_large.jpg`
        };
        resolve(pre);
      }).catch(e => {
        reject(`${prefix} not available`);
      });
    }
  });
}

function transform(data, encoding, next) {
  const numberFields = [
    'cloudCoverFull',
    'path',
    'row',
    'upperLeftCornerLatitude',
    'upperLeftCornerLongitude',
    'upperRightCornerLatitude',
    'upperRightCornerLongitude',
    'lowerLeftCornerLatitude',
    'lowerLeftCornerLongitude',
    'lowerRightCornerLatitude',
    'lowerRightCornerLongitude',
    'sceneCenterLatitude',
    'sceneCenterLongitude',
    'cloudCover',
    'sunElevation',
    'sunAzimuth',
    'receivingStation',
    'imageQuality1',
    //'ROLL_ANGLE',
    //'GEOMETRIC_RMSE_MODEL',
    //'GEOMETRIC_RMSE_MODEL_X',
    //'GEOMETRIC_RMSE_MODEL_Y',
    //'COLLECTION_NUMBER',
    //'CLOUD_COVER_LAND'
  ];

  numberFields.forEach(f => {
    data[f] = parseFloat(data[f]);
  });

  const data_geometry = { // eslint-disable-line camelcase
    type: 'Polygon',
    crs: {
      type: 'name',
      properties: {
        name: 'urn:ogc:def:crs:EPSG:8.9:4326'
      }
    },
    coordinates: [[
      [data.upperRightCornerLongitude, data.upperRightCornerLatitude],
      [data.upperLeftCornerLongitude, data.upperLeftCornerLatitude],
      [data.lowerLeftCornerLongitude, data.lowerLeftCornerLatitude],
      [data.lowerRightCornerLongitude, data.lowerRightCornerLatitude],
      [data.upperRightCornerLongitude, data.upperRightCornerLatitude]
    ]]
  };

  const leftLong = Math.min(data.lowerLeftCornerLongitude, data.upperLeftCornerLongitude)
  const rightLong = Math.max(data.lowerRightCornerLongitude, data.upperRightCornerLongitude)
  if (Math.abs(rightLong - leftLong) > 300) {
    //console.log(`error processing ${data.sceneID}: Geometry crosses Prime Meridian (${JSON.stringify(data_geometry)})`)
    console.log(`error: ${data.sceneID} looks like a bad geometry (${JSON.stringify(data_geometry)})`)
    next()
  } else {
    const google = googleLinks(data);

    const customFields = {
      scene_id: data.sceneID,
      product_id: data.LANDSAT_PRODUCT_ID,
      satellite_name: 'landsat-8',
      cloud_coverage: data.cloudCoverFull,
      date: data.acquisitionDate,
      thumbnail: data.browseURL,
      data_geometry,
      download_links: {
        usgs: `https://earthexplorer.usgs.gov/download/12864/${data.sceneID}/STANDARD/EE`,
        aws_s3: [],
        google: google.c1.files
      },
      aws_thumbnail: null,
      aws_index: null,
      google_index: google.c1.index,
    };

    delete data.cloudCoverFull

    awsLinks(data).then((info) => {
      //console.log('awslinks', info)
      customFields.download_links.aws_s3 = info.files
      customFields.aws_thumbnail = info.thumbnail
      customFields.aws_index = info.index
      record = Object.assign({}, customFields, data)
      this.push(record)
      next()
    }).catch(e => {
      console.log(`error processing ${customFields.scene_id}: ${e}`)
      next()
    })
  }

  //if (thumbnailUrl) {
  //customFields.thumbnail = url.resolve(thumbnailUrl, `${data.LANDSAT_PRODUCT_ID}.jpg`);
  //}
}

function handler (event, context, cb) {
  var _transform = through2({'objectMode': true, 'consume': true}, transform)
  console.log('Landsat handler:', event)
  metadata.update(event, _transform, cb)
}

local.localRun(() => {
  const a = {
    bucket: 'sat-api',
    key: 'test',
    satellite: 'landsat',
    currentFileNum: 11,
    lastFileNum: 11,
    arn: 'arn:aws:states:us-east-1:552819999234:stateMachine:landsat-meta'
  };
  console.log('running locally')

  handler(a, null, (e, r) => {});
});

module.exports.handler = handler;
<commit_msg>add logging of 180th meridian crossing<commit_after>'use strict';

const got = require('got');
const path = require('path');
const moment = require('moment');
const pad = require('lodash.padstart');
const _ = require('lodash');
const AWS = require('aws-sdk')
const local = require('kes/src/local');
const metadata = require('../../lib/metadata');
var through2 = require('through2')

const bands = [
  'ANG.txt',
  'B1.TIF',
  'B2.TIF',
  'B3.TIF',
  'B4.TIF',
  'B5.TIF',
  'B6.TIF',
  'B7.TIF',
  'B8.TIF',
  'B9.TIF',
  'B10.TIF',
  'B11.TIF',
  'BQA.TIF',
  'MTL.txt'
];

const s3 = new AWS.S3()

function googleLinks(data) {
  const row = pad(data.row, 3, '0');
  const _path = pad(data.path, 3, '0');
  //const sceneId = data.sceneID;
  const productId = data.LANDSAT_PRODUCT_ID;

  const c1Console = `https://console.cloud.google.com/storage/browser/gcp-public-data-landsat/LC08/${path.join(_path, row, productId)}`;
  const c1Base = `https://storage.googleapis.com/gcp-public-data-landsat/LC08/01/${path.join(_path, row, productId)}`;

  const c1Files = bands.map((b) => `${c1Base}/${productId}_${b}`);

  const c1 = {
    index: c1Console,
    files: c1Files
  };

  return { c1 };
}

//! Check to see if a URL exists
function fileExists(url) {
  var params = {
    Bucket: 'landsat-pds',
    Key: url.slice(36)
  }
  return new Promise(function(resolve, reject) {
    s3.headObject(params, function (err, metadata) {
      if (err && err.code === 'NotFound') {
        reject(url)
      } else {
        resolve(url)
      }
    })
  })
  /*return new Promise(function(resolve, reject) {
    got(url).then(response => {
      resolve(url);
    }).catch(e => {
      reject(url);
    });
  });*/
}

//! iterate over an array synchronously, invoke function on each element
function arrayIterate(values, fn) {
  return new Promise(function(resolve, reject) {
    // Are there any values to check?
    if (values.length === 0) {
      // All were rejected
      reject();
    }
    // Try the first value
    fn(values[0]).then(function(val) {
      // Resolved, we're all done
      //console.log('Resolved ' + val);
      resolve(val);
    }).catch(function() {
      // Rejected, remove the first item from the array and recursively
      // try the next one
      //console.log('Rejected ' + values[0]);
      values.shift();
      arrayIterate(values, fn).then(resolve).catch(reject);
    });
  });
}

function awsLinks(data) {
  const row = pad(data.row, 3, '0');
  const _path = pad(data.path, 3, '0');
  const sceneId = data.sceneID;
  const productId = data.LANDSAT_PRODUCT_ID;

  const c1Base = `https://landsat-pds.s3.amazonaws.com/c1/L8/${path.join(_path, row, productId)}`;
  const c1Files = bands.map((b) => `${c1Base}/${productId}_${b}`);

  const c1 = {
    index: `${c1Base}/index.html`,
    files: c1Files,
    thumbnail: `${c1Base}/${productId}_thumb_large.jpg`
  };

  return new Promise(function(resolve, reject) {
    // AWS doesn't include all C1 scenes, we return the old urls for
    // any scenes that is before May 1 2017
    info = {};
    if (moment(data.acquisitionDate) > moment('2017-04-30')) {
      resolve(c1)
    } else {
      const _sceneId = sceneId.slice(0, -2);
      const rev = sceneId.slice(-2)
      var prefix = `http://landsat-pds.s3.amazonaws.com/L8/${path.join(_path, row, _sceneId)}`;
      var links = _.range(rev, -1, -1).map(r => `${prefix}` + pad(r, 2, '0') + '/index.html');

      arrayIterate(links, fileExists).then(val => {
        prefix = prefix + val.slice(-13, -11);
        const pre = {
          index: `${prefix}/index.html`,
          files: bands.map((b) => `${prefix}_${b}`),
          thumbnail: `${prefix}_thumb_large.jpg`
        };
        resolve(pre);
      }).catch(e => {
        reject(`${prefix} not available`);
      });
    }
  });
}

function transform(data, encoding, next) {
  const numberFields = [
    'cloudCoverFull',
    'path',
    'row',
    'upperLeftCornerLatitude',
    'upperLeftCornerLongitude',
    'upperRightCornerLatitude',
    'upperRightCornerLongitude',
    'lowerLeftCornerLatitude',
    'lowerLeftCornerLongitude',
    'lowerRightCornerLatitude',
    'lowerRightCornerLongitude',
    'sceneCenterLatitude',
    'sceneCenterLongitude',
    'cloudCover',
    'sunElevation',
    'sunAzimuth',
    'receivingStation',
    'imageQuality1',
    //'ROLL_ANGLE',
    //'GEOMETRIC_RMSE_MODEL',
    //'GEOMETRIC_RMSE_MODEL_X',
    //'GEOMETRIC_RMSE_MODEL_Y',
    //'COLLECTION_NUMBER',
    //'CLOUD_COVER_LAND'
  ];

  numberFields.forEach(f => {
    data[f] = parseFloat(data[f]);
  });

  const data_geometry = { // eslint-disable-line camelcase
    type: 'Polygon',
    crs: {
      type: 'name',
      properties: {
        name: 'urn:ogc:def:crs:EPSG:8.9:4326'
      }
    },
    coordinates: [[
      [data.upperRightCornerLongitude, data.upperRightCornerLatitude],
      [data.upperLeftCornerLongitude, data.upperLeftCornerLatitude],
      [data.lowerLeftCornerLongitude, data.lowerLeftCornerLatitude],
      [data.lowerRightCornerLongitude, data.lowerRightCornerLatitude],
      [data.upperRightCornerLongitude, data.upperRightCornerLatitude]
    ]]
  };

  const leftLong = Math.min(data.lowerLeftCornerLongitude, data.upperLeftCornerLongitude)
  const rightLong = Math.max(data.lowerRightCornerLongitude, data.upperRightCornerLongitude)
  if (Math.abs(rightLong - leftLong) > 300) {
    console.log(`error: ${data.sceneID} crosses 180th Meridian (${JSON.stringify(data_geometry)})`)
    next()
  } else {
    const google = googleLinks(data);

    const customFields = {
      scene_id: data.sceneID,
      product_id: data.LANDSAT_PRODUCT_ID,
      satellite_name: 'landsat-8',
      cloud_coverage: data.cloudCoverFull,
      date: data.acquisitionDate,
      thumbnail: data.browseURL,
      data_geometry,
      download_links: {
        usgs: `https://earthexplorer.usgs.gov/download/12864/${data.sceneID}/STANDARD/EE`,
        aws_s3: [],
        google: google.c1.files
      },
      aws_thumbnail: null,
      aws_index: null,
      google_index: google.c1.index,
    };

    delete data.cloudCoverFull

    awsLinks(data).then((info) => {
      //console.log('awslinks', info)
      customFields.download_links.aws_s3 = info.files
      customFields.aws_thumbnail = info.thumbnail
      customFields.aws_index = info.index
      record = Object.assign({}, customFields, data)
      this.push(record)
      next()
    }).catch(e => {
      console.log(`error processing ${customFields.scene_id}: ${e}`)
      next()
    })
  }

  //if (thumbnailUrl) {
  //customFields.thumbnail = url.resolve(thumbnailUrl, `${data.LANDSAT_PRODUCT_ID}.jpg`);
  //}
}

function handler (event, context, cb) {
  var _transform = through2({'objectMode': true, 'consume': true}, transform)
  console.log('Landsat handler:', event)
  metadata.update(event, _transform, cb)
}

local.localRun(() => {
  const a = {
    bucket: 'sat-api',
    key: 'test',
    satellite: 'landsat',
    currentFileNum: 11,
    lastFileNum: 11,
    arn: 'arn:aws:states:us-east-1:552819999234:stateMachine:landsat-meta'
  };
  console.log('running locally')

  handler(a, null, (e, r) => {});
});

module.exports.handler = handler;
<|endoftext|>


<commit_before>(function ($) {
  $.extend($.summernote.lang, {
    'ko-KR': {
      font: {
        bold: '굵게',
        italic: '기울임꼴',
        underline: '밑줄',
        strikethrough: '취소선',
        clear: '글자 효과 없애기',
        height: '줄간격',
        name: '글꼴',
        size: '글자 크기'
      },
      image: {
        image: '사진',
        insert: '사진 추가',
        resizeFull: '원본 크기로 변경',
        resizeHalf: '50% 크기로 변경',
        resizeQuarter: '25% 크기로 변경',
        floatLeft: '왼쪽 정렬',
        floatRight: '오른쪽 정렬',
        floatNone: '정렬하지 않음',
        shapeRounded: '스타일: 둥근 모서리',
        shapeCircle: '스타일: 원형',
        shapeThumbnail: '스타일: 액자',
        shapeNone: '스타일: 없음',
        dragImageHere: '사진을 이곳으로 끌어오세요',
        selectFromFiles: '파일 선택',
        url: '사진 URL',
        remove: '사진 삭제'
      },
      link: {
        link: '링크',
        insert: '링크 추가',
        unlink: '링크 삭제',
        edit: '수정',
        textToDisplay: '링크에 표시할 내용',
        url: '이동할 URL',
        openInNewWindow: '새창으로 열기'
      },
      video: {
        video: '동영상',
        videoLink: '동영상 링크',
        insert: '동영상 추가',
        url: '동영상 URL',
        providers: '(YouTube, Vimeo, Vine, Instagram, DailyMotion, Youku 사용 가능)'
      },
      table: {
        table: '테이블'
      },
      hr: {
        insert: '구분선 추가'
      },
      style: {
        style: '스타일',
        normal: '본문',
        blockquote: '인용구',
        pre: '코드',
        h1: '제목 1',
        h2: '제목 2',
        h3: '제목 3',
        h4: '제목 4',
        h5: '제목 5',
        h6: '제목 6'
      },
      lists: {
        unordered: '글머리 기호',
        ordered: '번호 매기기'
      },
      options: {
        help: '도움말',
        fullscreen: '전체 화면',
        codeview: '코드 보기'
      },
      paragraph: {
        paragraph: '문단 정렬',
        outdent: '내어쓰기',
        indent: '들여쓰기',
        left: '왼쪽 정렬',
        center: '가운데 정렬',
        right: '오른쪽 정렬',
        justify: '양쪽 정렬'
      },
      color: {
        recent: '마지막으로 사용한 색',
        more: '다른 색 선택',
        background: '배경색',
        foreground: '글자색',
        transparent: '투명',
        setTransparent: '투명',
        reset: '취소',
        resetToDefault: '기본 값으로 변경'
      },
      shortcut: {
        shortcuts: '키보드 단축키',
        close: '닫기',
        textFormatting: '글자 스타일 적용',
        action: '기능',
        paragraphFormatting: '문단 스타일 적용',
        documentStyle: '문서 스타일 적용'
      },
      history: {
        undo: '실행 취소',
        redo: '다시 실행'
      }
    }
  });
})(jQuery);
<commit_msg>Added missing typos (subscript/superscript) in ko-KR Locale.<commit_after>(function ($) {
  $.extend($.summernote.lang, {
    'ko-KR': {
      font: {
        bold: '굵게',
        italic: '기울임꼴',
        underline: '밑줄',
        superscript: '위첨자',
        subscript: '아랫첨자',
        strikethrough: '취소선',
        clear: '글자 효과 없애기',
        height: '줄간격',
        name: '글꼴',
        size: '글자 크기'
      },
      image: {
        image: '사진',
        insert: '사진 추가',
        resizeFull: '원본 크기로 변경',
        resizeHalf: '50% 크기로 변경',
        resizeQuarter: '25% 크기로 변경',
        floatLeft: '왼쪽 정렬',
        floatRight: '오른쪽 정렬',
        floatNone: '정렬하지 않음',
        shapeRounded: '스타일: 둥근 모서리',
        shapeCircle: '스타일: 원형',
        shapeThumbnail: '스타일: 액자',
        shapeNone: '스타일: 없음',
        dragImageHere: '사진을 이곳으로 끌어오세요',
        selectFromFiles: '파일 선택',
        url: '사진 URL',
        remove: '사진 삭제'
      },
      link: {
        link: '링크',
        insert: '링크 추가',
        unlink: '링크 삭제',
        edit: '수정',
        textToDisplay: '링크에 표시할 내용',
        url: '이동할 URL',
        openInNewWindow: '새창으로 열기'
      },
      video: {
        video: '동영상',
        videoLink: '동영상 링크',
        insert: '동영상 추가',
        url: '동영상 URL',
        providers: '(YouTube, Vimeo, Vine, Instagram, DailyMotion, Youku 사용 가능)'
      },
      table: {
        table: '테이블'
      },
      hr: {
        insert: '구분선 추가'
      },
      style: {
        style: '스타일',
        normal: '본문',
        blockquote: '인용구',
        pre: '코드',
        h1: '제목 1',
        h2: '제목 2',
        h3: '제목 3',
        h4: '제목 4',
        h5: '제목 5',
        h6: '제목 6'
      },
      lists: {
        unordered: '글머리 기호',
        ordered: '번호 매기기'
      },
      options: {
        help: '도움말',
        fullscreen: '전체 화면',
        codeview: '코드 보기'
      },
      paragraph: {
        paragraph: '문단 정렬',
        outdent: '내어쓰기',
        indent: '들여쓰기',
        left: '왼쪽 정렬',
        center: '가운데 정렬',
        right: '오른쪽 정렬',
        justify: '양쪽 정렬'
      },
      color: {
        recent: '마지막으로 사용한 색',
        more: '다른 색 선택',
        background: '배경색',
        foreground: '글자색',
        transparent: '투명',
        setTransparent: '투명',
        reset: '취소',
        resetToDefault: '기본 값으로 변경'
      },
      shortcut: {
        shortcuts: '키보드 단축키',
        close: '닫기',
        textFormatting: '글자 스타일 적용',
        action: '기능',
        paragraphFormatting: '문단 스타일 적용',
        documentStyle: '문서 스타일 적용'
      },
      history: {
        undo: '실행 취소',
        redo: '다시 실행'
      }
    }
  });
})(jQuery);
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var async = require('async');
var Handlebars = require('handlebars');
var Mentat = require('mentat');

var ilsapi = require('../lib/ilsapi');

function sendNotice(options, callback) {
  var noticeScope = {};

  var mailOptions = _.defaults({
    from: Mentat.server.settings.app.notices.fromAddress
  }, options.mailOptions);

  async.parallel({
    patron: _getPatron ,
    suggestion: _getSuggestion
  }, _parallelTasksDone);

  function _getPatron(_callback) {
    return ilsapi.getPatron(options.patronId, _callback);
  }

  function _getSuggestion(_callback) {
    return Mentat.models.Suggestion
      .findById(options.suggestionId)
      .nodeify(_callback);
  }

  function _sendEmail(_callback) {
    var subjectPrefix = Mentat.server.settings.app.notices.subjectPrefix;

    mailOptions.to = noticeScope.patron.emailAddress;
    mailOptions.subject = subjectPrefix + noticeScope.patron.patronName;

    var textTemplate = Handlebars.compile(options.template.body); // TODO: errors?
    mailOptions.text = textTemplate(noticeScope);

    // if template requires bibnumber...
    return Mentat.transporter.sendMail(mailOptions, _callback);
  }

  function _deleteSuggestion(_callback) {
    Mentat.models.Suggestion
      .findById(noticeScope.suggestion.id)
      .then(function (template) {
        template
          .destroy()
          .nodeify(_callback);
      })
      .catch(function (err) {
        return _callback(err, null);
      });
  }

  function _sendNoticeDone(err, response) {
    if(err) {
      return callback(err, null);
    }

    Mentat.controllers.EventsController.log({
      event: {
        type: 'notices:sent',
        body: noticeScope.suggestion
      },
      logFields: [ 'title' ]
    });

    return callback(null, 'Sent.');
  }

  function _parallelTasksDone (err, results) {
    if (err) {
      Mentat.server.log(['error'], err);
      return callback(err, null);
    }

    noticeScope.patron = results['patron'];
    if (results['patron'] === null || results['patron'] === undefined) {
      return callback('Patron not found.', null);
    }

    if (!results['patron']['emailAddress']) {
      return callback('No email found for patron.', null);
    }

    if (results['suggestion'] === null || results['suggestion'] === undefined) {
      return callback('Suggestion not found.', null);
    }

    noticeScope.suggestion = results['suggestion'].dataValues;

    async.series([ _sendEmail, _deleteSuggestion ], _sendNoticeDone);
  }
}

module.exports = new Mentat.Controller('Notices', {
  sendNotice: sendNotice
});
<commit_msg>bib result handling<commit_after>'use strict';

var _ = require('lodash');
var async = require('async');
var Handlebars = require('handlebars');
var Mentat = require('mentat');

var ilsapi = require('../lib/ilsapi');

function sendNotice(options, callback) {
  var noticeScope = {};

  var mailOptions = _.defaults({
    from: Mentat.server.settings.app.notices.fromAddress
  }, options.mailOptions);

  if (options.bibNumber) {
      async.parallel({
        patron: _getPatron ,
        suggestion: _getSuggestion,
        bib: _getBib
      }, _parallelTasksDone);
  } else {
    async.parallel({
      patron: _getPatron ,
      suggestion: _getSuggestion,
    }, _parallelTasksDone);
  }

  function _getPatron(_callback) {
    return ilsapi.getPatron(options.patronId, _callback);
  }

  function _getBib(_callback) {
    return ilsapi.getBib(options.bibNumber, _callback);
  }

  function _getSuggestion(_callback) {
    return Mentat.models.Suggestion
      .findById(options.suggestionId)
      .nodeify(_callback);
  }

  function _sendEmail(_callback) {
    var subjectPrefix = Mentat.server.settings.app.notices.subjectPrefix;

    mailOptions.to = noticeScope.patron.emailAddress;
    mailOptions.subject = subjectPrefix + noticeScope.patron.patronName;

    var textTemplate = Handlebars.compile(options.template.body); // TODO: errors?
    mailOptions.text = textTemplate(noticeScope);

    // if template requires bibnumber...
    return Mentat.transporter.sendMail(mailOptions, _callback);
  }

  function _deleteSuggestion(_callback) {
    Mentat.models.Suggestion
      .findById(noticeScope.suggestion.id)
      .then(function (template) {
        template
          .destroy()
          .nodeify(_callback);
      })
      .catch(function (err) {
        return _callback(err, null);
      });
  }

  function _sendNoticeDone(err, response) {
    if(err) {
      return callback(err, null);
    }

    Mentat.controllers.EventsController.log({
      event: {
        type: 'notices:sent',
        body: noticeScope.suggestion
      },
      logFields: [ 'title' ]
    });

    return callback(null, 'Sent.');
  }

  function _parallelTasksDone (err, results) {
    if (err) {
      Mentat.server.log(['error'], err);
      return callback(err, null);
    }

    noticeScope.patron = results['patron'];
    if (results['patron'] === null || results['patron'] === undefined) {
      return callback('Patron not found.', null);
    }

    if (!results['patron']['emailAddress']) {
      return callback('No email found for patron.', null);
    }

    if (results['suggestion'] === null || results['suggestion'] === undefined) {
      return callback('Suggestion not found.', null);
    }

    if (options.bibNumber && results['bib'] === null || results['bib'] === undefined) {
      return callback('Bib record not found.', null);
    }

    noticeScope.suggestion = results['suggestion'].dataValues;
    noticeScope.bib = results['bib'];

    async.series([ _sendEmail, _deleteSuggestion ], _sendNoticeDone);
  }
}

module.exports = new Mentat.Controller('Notices', {
  sendNotice: sendNotice
});
<|endoftext|>


<commit_before><commit_msg>#1834 review notes<commit_after><|endoftext|>


<commit_before>"use strict";

(function () {
CONSOLE = this.CONSOLE = {};
CONSOLE.open = function (object) {
    var here = object.jqueryObjectWest.append("

");
    $('#support-console').append('

')
    var newLayout = $('#support-console').layout({
        togglerLength_open: 0, // HIDE the toggler button

        south: {
            enableCursorHotkey: false,
            closable: false,
            resizable: false,
            spacing_open: 0,
            spacing_closed: 0,
        },
        center: {
            enableCursorHotkey: false,
            closable: false,
            resizable: false,
            spacing_open: 0,
            spacing_closed: 0,
            size:1000,
        }
    });

    $('#console').hide();
    $('#console').addClass('ui-widget-content');

    $('#buttonLayout-').on('change', function (e) {
        if ($(this).is(':checked')) {
            $('#console').show();
            newLayout.sizePane('south','120');
        } else {
            $('#console').hide();
            $('#support-layout').css("height", '100%');
            newLayout.sizePane('south','0');
        }
    });

    newLayout.allowOverflow("south");

    function debug() {
        allMessage();
        $('#message-console').show();
        $('#layout-console').hide();
        $('#mode_console').remove();
        GUI.label('mode_console', "debug", $('#console '));
        $('#content-console').find('div').each(function (index) {
            if (this.id == 'warn') {
                $(this).hide();
            } else if (this.id == 'log') {
                $(this).hide();
            } else if (this.id == 'error') {
                $(this).hide();
            }
        });
    };

    function log() {
        allMessage();
        $('#message-console').show();
        $('#layout-console').hide();
        $('#mode_console').remove();
        GUI.label('mode_console', "log", $('#console '));
        $('#content-console').find('div').each(function (index) {
            if (this.id == 'warn') {
                $(this).hide();
            } else if (this.id == 'debug') {
                $(this).hide();
            } else if (this.id == 'error') {
                $(this).hide();
            }
        });
    };

    function warn() {
        allMessage();
        $('#message-console').show();
        $('#layout-console').hide();
        $('#mode_console').remove();
        GUI.label('mode_console', "warning", $('#console '));
        $('#content-console').find('div').each(function (index) {
            if (this.id == 'debug') {
                $(this).hide();
            } else if (this.id == 'log') {
                $(this).hide();
            } else if (this.id == 'error') {
                $(this).hide();
            }
        });
    };

    function error() {
        allMessage();
        $('#message-console').show();
        $('#layout-console').hide();
        $('#mode_console').remove();
        GUI.label('mode_console', "error", $('#console '));
        $('#content-console').find('div').each(function (index) {
            if (this.id == 'warn') {
                $(this).hide();
            } else if (this.id == 'log') {
                $(this).hide();
            } else if (this.id == 'debug') {
                $(this).hide();
            }
        });
    };

    function allMessage() {
        $('#message-console').show();
        $('#layout-console').hide();
        $('#mode_console').remove();
        GUI.label('mode_console', "all", $('#console '));
        $('#content-console').find('div').each(function (index) {
            if (this.id == 'warn') {
                $(this).show();
            } else if (this.id == 'log') {
                $(this).show();
            } else if (this.id == 'debug') {
                $(this).show();
            } else if (this.id == 'error') {
                $(this).show();
            }
        });
    };

    function script() {
        $('#message-console').hide();
        $('#layout-console').show();
        $('#mode_console').remove();
        GUI.label('mode_console', "script", $('#console '));
        $('#content-console').find('div').each(function (index) {
            if (this.id == 'warn') {
                $(this).hide();
            } else if (this.id == 'log') {
                $(this).hide();
            } else if (this.id == 'debug') {
                $(this).hide();
            } else if (this.id == 'error') {
                $(this).hide();
            }
        });
        $('#layout-console').terminal(function (command, term) {
            if (command !== '') {
                try {
                    var result = window.eval(command);
                    if (result !== undefined) {
                        term.echo(new String(result));
                    }
                } catch (e) {
                    term.error(new String(e));
                    console.error(new String(e));
                }
            } else {
                term.echo('');
            }
        }, {
            greetings: '',
            name: 'js_command',
            width: 400,
            prompt: 'js> '
        });
    };

    var linksTool = ["allMessage();", "debug();", "error();", "log();", "warn();", "script();"];
    var itemTool = ["icon-list", "icon-info-sign", "icon-remove-sign", "icon-ban-circle", "icon-warning-sign ", "icon-comment"];
    GUI.toolBar("toolConsole", $('#console'), itemTool, linksTool, "top", $('#normal-button-bottom'));
    //GUI.label = function(_id,_txt, _parent,_style,_mode)
    GUI.label('title_console', "Console : ", $('#console '));
    GUI.label('mode_console', "all", $('#console '));

    $('#console').append("

")

    CONSOLE.messages();

    return
    };

    CONSOLE.messages=function(){

            //handling errors,warnings,debugs,logs
    //catch error

    window.onerror = function (message, url, linenumber) {
        var content = '
' + GUI.time() + '
';
        if (!url) {
            url = "indefined";
        }
        if (!linenumber) {
            linenumber = "indefined";
        }
        content += '' + message + ' url:' + url + ' line:' + linenumber + '

';
        var $content = $(content);
        $('#message-console').prepend($content);
    };

    //catch debug from console firebug API
    var oldDebug = console.debug;
    console.debug = function (message) {
        var content = '
' + GUI.time() + '
';
        content += '' + message + '

';
        var $content = $(content);
        $('#message-console').prepend($content);
        oldDebug.apply(console, arguments);
    };

    //catch log from console firebug API
    var oldLog = console.log;
    console.log = function (message) {
        var content = '
' + GUI.time() + '
';
        content += '' + message + '

';
        var $content = $(content);
        $('#message-console').prepend($content);
        oldLog.apply(console, arguments);
    };

    //catch error from console firebug API
    var oldError = console.error;
    console.error = function (message) {
        var content = '
' + GUI.time() + '
';
        content += '' + message + '

';
        var $content = $(content);
        $('#message-console').prepend($content);
        oldError.apply(console, arguments);
    };

    //catch warning from console firebug API
    var oldWarn = console.warn;
    console.warn = function (message) {
        var content = '
' + GUI.time() + '
';
        content += '' + message + '

';
        var $content = $(content);
        $('#message-console').prepend($content);
        oldWarn.apply(console, arguments);
    };

    }
}).call(this);<commit_msg>bug script in the console has been fixed<commit_after>"use strict";

(function () {
CONSOLE = this.CONSOLE = {};
CONSOLE.open = function (object) {
    var here = object.jqueryObjectWest.append("

");
    $('#support-console').append('

')
    var newLayout = $('#support-console').layout({
        togglerLength_open: 0, // HIDE the toggler button

        south: {
            enableCursorHotkey: false,
            closable: false,
            resizable: false,
            spacing_open: 0,
            spacing_closed: 0,
        },
        center: {
            enableCursorHotkey: false,
            closable: false,
            resizable: false,
            spacing_open: 0,
            spacing_closed: 0,
            size:1000,
        }
    });

    $('#console').hide();
    $('#console').addClass('ui-widget-content');

    $('#buttonLayout-').on('change', function (e) {
        if ($(this).is(':checked')) {
            $('#console').show();
            newLayout.sizePane('south','120');
        } else {
            $('#console').hide();
            $('#support-layout').css("height", '100%');
            newLayout.sizePane('south','0');
        }
    });

    newLayout.allowOverflow("south");

    function debug() {
        allMessage();
        $('#message-console').show();
        $('#layout-console').hide();
        $('#mode_console').remove();
        GUI.label('mode_console', "debug", $('#console '));
        $('#content-console').find('div').each(function (index) {
            if (this.id == 'warn') {
                $(this).hide();
            } else if (this.id == 'log') {
                $(this).hide();
            } else if (this.id == 'error') {
                $(this).hide();
            }
        });
    };

    function log() {
        allMessage();
        $('#message-console').show();
        $('#layout-console').hide();
        $('#mode_console').remove();
        GUI.label('mode_console', "log", $('#console '));
        $('#content-console').find('div').each(function (index) {
            if (this.id == 'warn') {
                $(this).hide();
            } else if (this.id == 'debug') {
                $(this).hide();
            } else if (this.id == 'error') {
                $(this).hide();
            }
        });
    };

    function warn() {
        allMessage();
        $('#message-console').show();
        $('#layout-console').hide();
        $('#mode_console').remove();
        GUI.label('mode_console', "warning", $('#console '));
        $('#content-console').find('div').each(function (index) {
            if (this.id == 'debug') {
                $(this).hide();
            } else if (this.id == 'log') {
                $(this).hide();
            } else if (this.id == 'error') {
                $(this).hide();
            }
        });
    };

    function error() {
        allMessage();
        $('#message-console').show();
        $('#layout-console').hide();
        $('#mode_console').remove();
        GUI.label('mode_console', "error", $('#console '));
        $('#content-console').find('div').each(function (index) {
            if (this.id == 'warn') {
                $(this).hide();
            } else if (this.id == 'log') {
                $(this).hide();
            } else if (this.id == 'debug') {
                $(this).hide();
            }
        });
    };

    function allMessage() {
        $('#message-console').show();
        $('#layout-console').hide();
        $('#mode_console').remove();
        GUI.label('mode_console', "all", $('#console '));
        $('#content-console').find('div').each(function (index) {
            if (this.id == 'warn') {
                $(this).show();
            } else if (this.id == 'log') {
                $(this).show();
            } else if (this.id == 'debug') {
                $(this).show();
            } else if (this.id == 'error') {
                $(this).show();
            }
        });
    };

    window.scriptGo = function() {
        $('#message-console').hide();
        $('#layout-console').show();
        $('#mode_console').remove();
        GUI.label('mode_console', "script", $('#console '));
        $('#content-console').find('div').each(function (index) {
            if (this.id == 'warn') {
                $(this).hide();
            } else if (this.id == 'log') {
                $(this).hide();
            } else if (this.id == 'debug') {
                $(this).hide();
            } else if (this.id == 'error') {
                $(this).hide();
            }
        });
        $('#layout-console').terminal(function (command, term) {
            if (command !== '') {
                try {
                    var result = window.eval(command);
                    if (result !== undefined) {
                        term.echo(new String(result));
                    }
                } catch (e) {
                    term.error(new String(e));
                    console.error(new String(e));
                }
            } else {
                term.echo('');
            }
        }, {
            greetings: '',
            name: 'js_command',
            width: 400,
            prompt: 'js> '
        });
    };

    var linksTool = ["allMessage();", "debug();", "error();", "log();", "warn();", "window.scriptGo();"];
    var itemTool = ["icon-list", "icon-info-sign", "icon-remove-sign", "icon-ban-circle", "icon-warning-sign ", "icon-comment"];
    GUI.toolBar("toolConsole", $('#console'), itemTool, linksTool, "top", $('#normal-button-bottom'));
    //GUI.label = function(_id,_txt, _parent,_style,_mode)
    GUI.label('title_console', "Console : ", $('#console '));
    GUI.label('mode_console', "all", $('#console '));

    $('#console').append("

")
      //handling errors,warnings,debugs,logs
    //catch error

    window.onerror = function (message, url, linenumber) {
        var content = '
' + GUI.time() + '
';
        if (!url) {
            url = "indefined";
        }
        if (!linenumber) {
            linenumber = "indefined";
        }
        content += '' + message + ' url:' + url + ' line:' + linenumber + '

';
        var $content = $(content);
        $('#message-console').prepend($content);
    };

    //catch debug from console firebug API
    var oldDebug = console.debug;
    console.debug = function (message) {
        var content = '
' + GUI.time() + '
';
        content += '' + message + '

';
        var $content = $(content);
        $('#message-console').prepend($content);
        oldDebug.apply(console, arguments);
    };

    //catch log from console firebug API
    var oldLog = console.log;
    console.log = function (message) {
        var content = '
' + GUI.time() + '
';
        content += '' + message + '

';
        var $content = $(content);
        $('#message-console').prepend($content);
        oldLog.apply(console, arguments);
    };

    //catch error from console firebug API
    var oldError = console.error;
    console.error = function (message) {
        var content = '
' + GUI.time() + '
';
        content += '' + message + '

';
        var $content = $(content);
        $('#message-console').prepend($content);
        oldError.apply(console, arguments);
    };

    //catch warning from console firebug API
    var oldWarn = console.warn;
    console.warn = function (message) {
        var content = '
' + GUI.time() + '
';
        content += '' + message + '

';
        var $content = $(content);
        $('#message-console').prepend($content);
        oldWarn.apply(console, arguments);
    };

    return
    };

}).call(this);<|endoftext|>