<commit_before>"use strict";

var cheerio = require('cheerio');
var request = require('request');
var Iconv  = require('iconv').Iconv;
var debug = require('debug')('OSMBC:model:htmltitle');

function linkFrom(url,page) {
  if (url.substring(0,page.length+7)==("http://"+page)) return true;
  if (url.substring(0,page.length+8)==("https://"+page)) return true;
  return false;
}

function retrieveForum(body,url) {
  if (linkFrom(url,"forum.openstreetmap.org")) {
    let c = cheerio.load(body);
    let title = c("title").text().replace(" / OpenStreetMap Forum","");
    return title;
  }
  return null;
}

function retrieveOsmBlog(body,url) {
  if (linkFrom(url,"www.openstreetmap.org")) {
    let c = cheerio.load(body);
    let title = c("title").text().replace("OpenStreetMap | ","");
    return title;
  }
  return null;
}

function retrieveTwitter(body,url) {
  if (linkFrom(url,"twitter.com")) {
    let c = cheerio.load(body);
    let title = c('meta[property="og:description"]').attr("content");
    //
    title=title.replace(/(https?:\/\/[^[\] \n\r"”“]*)/gi, '<..>');
    return title;
  }
  return null;
}

function retrieveTitle(body) {
  let c = cheerio.load(body);
  let title = c('title').text();
  return title;
}

// Team wished only to grap title, not description.
/*
function retrieveDescription(body) {
  let c = cheerio.load(body);
  let title = c('meta[property="og:description"]').attr("content");
  if (typeof(title)=="undefined") title = null;
  return title;
}*/

var converterList = [retrieveForum,retrieveTwitter,retrieveOsmBlog,retrieveTitle];

function getTitle(url,callback) {
  debug("getTitle");
  request( { method: "GET", url: url, followAllRedirects: true,encoding:null },
    function (error, response,body) {
      if (error) return callback(null,"Page not Found");
      console.dir(response.headers);

      // try to get charset from Headers (version 1)
      var fromcharset = response.headers['content-encoding'];

      // if not exist, try to get charset from Headers (version 2)
      if (!fromcharset) {
        let ct = response.headers['content-type'];
        if (ct) {
          let r = ct.match(/.*?charset=([^"']+)/);
          if (r)fromcharset = r[1];
        }
      }
      // if not exist, try to parse html page for charset in text
      if (!fromcharset) {
        let r = body.toString('utf-8').match((/<meta.*?charset=([^"']+)/));
        if (r) fromcharset = r[1];
      }

      // nothing given, to use parser set incoming & outcoming charset equal
      if (!fromcharset) fromcharset = "UTF-8";
      var utf8body = null;
      try {
        var iconv = new Iconv(fromcharset,'UTF-8');
        utf8body = iconv.convert(body).toString('UTF-8');
      } catch (err) {
        // There is a convert error, ognore it and convert with UTF-8
        utf8body = body.toString('UTF-8');
      }

      let r = null;
      for (let i=0;i<converterList.length;i++) {
        r = converterList[i](utf8body,url);
        if (r) break;
      }
      // remove all linebreaks
      r = r.replace(/(\r\n|\n|\r)/gm," ");
      return callback(null,r);
    }
  );
}

module.exports.getTitle = getTitle;

module.exports.fortestonly = {};
module.exports.fortestonly.linkFrom = linkFrom;

<commit_msg>Avoid an error, if twitter url does not exist in collect screen. Close #523<commit_after>"use strict";

var cheerio = require('cheerio');
var request = require('request');
var Iconv  = require('iconv').Iconv;
var debug = require('debug')('OSMBC:model:htmltitle');

function linkFrom(url,page) {
  if (url.substring(0,page.length+7)==("http://"+page)) return true;
  if (url.substring(0,page.length+8)==("https://"+page)) return true;
  return false;
}

function retrieveForum(body,url) {
  if (linkFrom(url,"forum.openstreetmap.org")) {
    let c = cheerio.load(body);
    let title = c("title").text().replace(" / OpenStreetMap Forum","");
    return title;
  }
  return null;
}

function retrieveOsmBlog(body,url) {
  if (linkFrom(url,"www.openstreetmap.org")) {
    let c = cheerio.load(body);
    let title = c("title").text().replace("OpenStreetMap | ","");
    return title;
  }
  return null;
}

function retrieveTwitter(body,url) {
  if (linkFrom(url,"twitter.com")) {
    let c = cheerio.load(body);
    let title = c('meta[property="og:description"]').attr("content");

    // Only replace Twitter Url, if it exists.
    if (title) title=title.replace(/(https?:\/\/[^[\] \n\r"”“]*)/gi, '<..>');
    return title;
  }
  return null;
}

function retrieveTitle(body) {
  let c = cheerio.load(body);
  let title = c('title').text();
  return title;
}

// Team wished only to grap title, not description.
/*
function retrieveDescription(body) {
  let c = cheerio.load(body);
  let title = c('meta[property="og:description"]').attr("content");
  if (typeof(title)=="undefined") title = null;
  return title;
}*/

var converterList = [retrieveForum,retrieveTwitter,retrieveOsmBlog,retrieveTitle];

function getTitle(url,callback) {
  debug("getTitle");
  request( { method: "GET", url: url, followAllRedirects: true,encoding:null },
    function (error, response,body) {
      if (error) return callback(null,"Page not Found");

      // try to get charset from Headers (version 1)
      var fromcharset = response.headers['content-encoding'];

      // if not exist, try to get charset from Headers (version 2)
      if (!fromcharset) {
        let ct = response.headers['content-type'];
        if (ct) {
          let r = ct.match(/.*?charset=([^"']+)/);
          if (r)fromcharset = r[1];
        }
      }
      // if not exist, try to parse html page for charset in text
      if (!fromcharset) {
        let r = body.toString('utf-8').match((/<meta.*?charset=([^"']+)/));
        if (r) fromcharset = r[1];
      }

      // nothing given, to use parser set incoming & outcoming charset equal
      if (!fromcharset) fromcharset = "UTF-8";
      var utf8body = null;
      try {
        var iconv = new Iconv(fromcharset,'UTF-8');
        utf8body = iconv.convert(body).toString('UTF-8');
      } catch (err) {
        // There is a convert error, ognore it and convert with UTF-8
        utf8body = body.toString('UTF-8');
      }

      let r = null;
      for (let i=0;i<converterList.length;i++) {
        r = converterList[i](utf8body,url);
        if (r) break;
      }
      // remove all linebreaks
      r = r.replace(/(\r\n|\n|\r)/gm," ");
      return callback(null,r);
    }
  );
}

module.exports.getTitle = getTitle;

module.exports.fortestonly = {};
module.exports.fortestonly.linkFrom = linkFrom;

<|endoftext|>


<commit_before>"use strict";

var cheerio = require("cheerio");
var request = require("request");
var Iconv  = require("iconv").Iconv;
var debug = require("debug")("OSMBC:model:htmltitle");

function linkFrom(url, page) {
  if (url.substring(0, page.length + 7) === ("http://" + page)) return true;
  if (url.substring(0, page.length + 8) === ("https://" + page)) return true;
  return false;
}

function retrieveForum(body, url) {
  if (linkFrom(url, "forum.openstreetmap.org")) {
    let c = cheerio.load(body);
    let title = c("title").text().replace(" / OpenStreetMap Forum", "");
    return title;
  }
  return null;
}

function retrieveOsmBlog(body, url) {
  if (linkFrom(url, "www.openstreetmap.org")) {
    let c = cheerio.load(body);
    let title = c("title").text().replace("OpenStreetMap | ", "");
    return title;
  }
  return null;
}

function retrieveTwitter(body, url) {
  if (linkFrom(url, "twitter.com")) {
    let c = cheerio.load(body);
    let title = c('meta[property="og:description"]').attr("content");

    // Only replace Twitter Url, if it exists.
    if (title) title = title.replace(/(https?:\/\/[^[\] \n\r"”“]*)/gi, "<..>");
    return title;
  }
  return null;
}

function retrieveTitle(body) {
  let c = cheerio.load(body);
  let title = c("title").text();
  return title;
}

// Team wished only to grap title, not description.
/*
function retrieveDescription(body) {
  let c = cheerio.load(body);
  let title = c('meta[property="og:description"]').attr("content");
  if (typeof(title)=="undefined") title = null;
  return title;
} */

var converterList = [retrieveForum, retrieveTwitter, retrieveOsmBlog, retrieveTitle];

function getTitle(url, callback) {
  debug("getTitle");
  request({method: "GET", url: url, followAllRedirects: true, encoding: null, timeout: 2000},
    function (error, response, body) {
      if (error && error.code === "ESOCKETTIMEDOUT") return callback(null, url + " TIMEOUT");
      if (error) return callback(null, "Page not Found");

      // try to get charset from Headers (version 1)
      var fromcharset = response.headers["content-encoding"];

      // if not exist, try to get charset from Headers (version 2)
      if (!fromcharset) {
        let ct = response.headers["content-type"];
        if (ct) {
          let r = ct.match(/.*?charset=([^"']+)/);
          if (r)fromcharset = r[1];
        }
      }
      // if not exist, try to parse html page for charset in text
      if (!fromcharset) {
        let r = body.toString("utf-8").match((/<meta.*?charset=([^"']+)/));
        if (r) fromcharset = r[1];
      }

      // nothing given, to use parser set incoming & outcoming charset equal
      if (!fromcharset) fromcharset = "UTF-8";
      var utf8body = null;
      try {
        var iconv = new Iconv(fromcharset, "UTF-8");
        utf8body = iconv.convert(body).toString("UTF-8");
      } catch (err) {
        // There is a convert error, ognore it and convert with UTF-8
        utf8body = body.toString("UTF-8");
      }

      let r = null;
      for (let i = 0; i < converterList.length; i++) {
        r = converterList[i](utf8body, url);
        if (r) break;
      }
      // remove all linebreaks
      r = r.replace(/(\r\n|\n|\r)/gm, " ");
      if (r===null) r = "Not Found";
      return callback(null, r);
    }
  );
}

module.exports.getTitle = getTitle;

module.exports.fortestonly = {};
module.exports.fortestonly.linkFrom = linkFrom;

<commit_msg>Change from iconv to iconv-lite npm module<commit_after>"use strict";

var cheerio = require("cheerio");
var request = require("request");
var iconv = require('iconv-lite');
var debug = require("debug")("OSMBC:model:htmltitle");

function linkFrom(url, page) {
  if (url.substring(0, page.length + 7) === ("http://" + page)) return true;
  if (url.substring(0, page.length + 8) === ("https://" + page)) return true;
  return false;
}

function retrieveForum(body, url) {
  if (linkFrom(url, "forum.openstreetmap.org")) {
    let c = cheerio.load(body);
    let title = c("title").text().replace(" / OpenStreetMap Forum", "");
    return title;
  }
  return null;
}

function retrieveOsmBlog(body, url) {
  if (linkFrom(url, "www.openstreetmap.org")) {
    let c = cheerio.load(body);
    let title = c("title").text().replace("OpenStreetMap | ", "");
    return title;
  }
  return null;
}

function retrieveTwitter(body, url) {
  if (linkFrom(url, "twitter.com")) {
    let c = cheerio.load(body);
    let title = c('meta[property="og:description"]').attr("content");

    // Only replace Twitter Url, if it exists.
    if (title) title = title.replace(/(https?:\/\/[^[\] \n\r"”“]*)/gi, "<..>");
    return title;
  }
  return null;
}

function retrieveTitle(body) {
  let c = cheerio.load(body);
  let title = c("title").text();
  return title;
}

// Team wished only to grap title, not description.
/*
function retrieveDescription(body) {
  let c = cheerio.load(body);
  let title = c('meta[property="og:description"]').attr("content");
  if (typeof(title)=="undefined") title = null;
  return title;
} */

var converterList = [retrieveForum, retrieveTwitter, retrieveOsmBlog, retrieveTitle];

function getTitle(url, callback) {
  debug("getTitle");
  request({method: "GET", url: url, followAllRedirects: true, encoding: null, timeout: 2000},
    function (error, response, body) {
      if (error && error.code === "ESOCKETTIMEDOUT") return callback(null, url + " TIMEOUT");
      if (error) return callback(null, "Page not Found");

      // try to get charset from Headers (version 1)
      var fromcharset = response.headers["content-encoding"];

      // if not exist, try to get charset from Headers (version 2)
      if (!fromcharset) {
        let ct = response.headers["content-type"];
        if (ct) {
          let r = ct.match(/.*?charset=([^"']+)/);
          if (r)fromcharset = r[1];
        }
      }
      // if not exist, try to parse html page for charset in text
      if (!fromcharset) {
        let r = body.toString("utf-8").match((/<meta.*?charset=([^"']+)/));
        if (r) fromcharset = r[1];
      }

      // nothing given, to use parser set incoming & outcoming charset equal
      if (!fromcharset) fromcharset = "UTF-8";
      var utf8body = null;
      utf8body = iconv.decode(body,fromcharset);
      /*
      try {
        var iconv = new Iconv(fromcharset, "UTF-8");
        utf8body = iconv.convert(body).toString("UTF-8");
      } catch (err) {
        // There is a convert error, ognore it and convert with UTF-8
        utf8body = body.toString("UTF-8");
      }*/

      let r = null;
      for (let i = 0; i < converterList.length; i++) {
        r = converterList[i](utf8body, url);
        if (r) break;
      }
      // remove all linebreaks
      r = r.replace(/(\r\n|\n|\r)/gm, " ");
      if (r===null) r = "Not Found";
      return callback(null, r);
    }
  );
}

module.exports.getTitle = getTitle;

module.exports.fortestonly = {};
module.exports.fortestonly.linkFrom = linkFrom;

<|endoftext|>


<commit_before>'use strict';

var crypto = require('crypto');
var Sequelize = require('sequelize');

function QuestionModel(db) {
    this.questionSchema = db.question;
    this.sequelize = db.sequelize;
};

QuestionModel.prototype.insertQuestion = function(question, cb) {

    this.questionSchema.create(question).then(function(createdQuestion) {
        cb(createdQuestion);
    });
};

QuestionModel.prototype.editQuestion = function(question, cb) {

    this.questionSchema.findOne({
        where: {
            id: question.id

        }
    }).then(function(db_question) {
        db_question.option_a = question.option_a;
        db_question.option_b = question.option_b;
        db_question.question_text = question.question_text;
        db_question.question_image = question.question_image;

        db_question.save({ fields: ['option_a', 'option_b', 'question_text', 'question_image'] }).then(function() {
            cb(db_question);
        });

    });

};

QuestionModel.prototype.getQuestion = function(user_id,q_id,app, cb) {

  var rawQuery = "";
    var _replacements = [user_id, q_id, app];

    rawQuery = 'select * from proc_get_question_by_id(cast(? as UUID),cast(? as UUID),?)';

    this.sequelize.query(rawQuery, {
            replacements: _replacements,
            type: this.sequelize.QueryTypes.SELECT,
        })
        .then(function(questions) {
            cb(questions);
        });
};

QuestionModel.prototype.showAllQuestions = function(cb) {

    this.questionSchema.findAll().then(function(questions) {
        cb(questions);
    });
};

QuestionModel.prototype.userQuestions = function(user_id, app, limit, cb) {

    var rawQuery = "";
    var _replacements = [user_id, app, limit];

    rawQuery = 'select * from proc_fetch_user_questions(cast(? as UUID),?,?)';

    this.sequelize.query(rawQuery, {
            replacements: _replacements,
            type: this.sequelize.QueryTypes.SELECT,
        })
        .then(function(questions) {
            cb(questions);
        });

//TESTING
    // this.questionSchema.findAll({
    //     where: {
    //         user_id: user_id,
    //         app: app,
    //         is_deleted: false
    //     },
    //     limit: limit
    // }).then(function(questions) {
    //     cb(questions);
    // });
};

QuestionModel.prototype.userFavorites = function(user_id, app, limit, cb) {

    var rawQuery = 'select * from question where id in(SELECT question_id from answer where user_id=? and answer.is_favorite=true)' +
        'and question.is_deleted=FALSE and question.app=? limit ?;'
    this.sequelize.query(rawQuery, {
            replacements: [user_id, app, limit],
            type: this.sequelize.QueryTypes.SELECT,
            // model: this.questionSchema
        })
        .then(function(questions) {
            cb(questions);
        });

};

QuestionModel.prototype.fetchQuestions = function(app, limit, user_id, installation_id, debug, cb) {

    var debugMode = debug ? debug : 0;
    var rawQuery = "";
    var _replacements = [user_id, app, limit];
    if (debugMode == 1) {
        rawQuery = 'select * from proc_fetch_questions_by_user_id_debug(cast(? as UUID),?,?)';
    } else {
        rawQuery = 'select * from proc_fetch_questions_by_user_id(cast(? as UUID),?,?)';
        if (!user_id) {
            rawQuery = 'select * from proc_fetch_questions_by_imei(?,?,?)';
            _replacements = [installation_id, app, limit];
        }
    }

    this.sequelize.query(rawQuery, {
            replacements: _replacements,
            type: this.sequelize.QueryTypes.SELECT,
            // model: this.questionSchema
        })
        .then(function(questions) {
            cb(questions);
        });

    /*    if (debugMode == 1) {
            rawQuery = "DROP TABLE IF EXISTS tempUserQuestionTable; " +
                "CREATE TEMP TABLE tempUserQuestionTable AS " +
                "select  * from question where question.app=? and question.is_deleted=FALSE;";

            rawQuery = rawQuery + 'select tu.*,u.profile_img as asker_profile_img, u.name as asker_name from (select (row_number() over ()) as rn,* from tempUserQuestionTable) as tu inner JOIN "user" as u on u.id=tu.user_id where tu.rn in (' +
                "select DISTINCT round(random() * (select count( * ) from tempUserQuestionTable))::integer as id " +
                "from generate_series(1, 100)" +
                ") limit ?;";

        } else {
            rawQuery = "DROP TABLE IF EXISTS tempUserQuestionTable; " +
                "CREATE TEMP TABLE tempUserQuestionTable AS " +
                "select  * from question where question.app=? and question.is_deleted=FALSE " +
                "EXCEPT " +
                "select q.* from answer a inner JOIN question q on a.question_id=q.id ";

            rawQuery = rawQuery + ((user_id) ? "where a.user_id=(?::UUID); " : "where a.installation_id=?; ");

            rawQuery = rawQuery + 'select tu.*,u.profile_img as asker_profile_img,u.name as asker_name from (select (row_number() over ()) as rn,* from tempUserQuestionTable) as tu inner JOIN "user" as u on u.id=tu.user_id where tu.rn in (' +
                "select DISTINCT round(random() * (select count( * ) from tempUserQuestionTable))::integer as id " +
                "from generate_series(1, 100)" +
                ") limit ?;";
            this.sequelize.query(rawQuery, {
                    replacements: [app, (user_id) ? user_id : installation_id, limit],
                    type: this.sequelize.QueryTypes.SELECT,
                    // model: this.questionSchema
                })
                .then(function(questions) {
                    cb(questions);
                });
        }*/

};

QuestionModel.prototype.getAllKapistirForWeb = function(cb) {

    var rawQuery = 'select tu.*,u.profile_img as asker_profile_img,u.facebook_id,  u.name as asker_name from question as tu inner JOIN "user" as u on u.id=tu.user_id where tu.app=1 ORDER BY created_at desc';

    this.sequelize.query(rawQuery, {
            //replacements: [app, (user_id) ? user_id : installation_id, limit],
            type: this.sequelize.QueryTypes.SELECT,
            // model: this.questionSchema
        })
        .then(function(questions) {
            cb(questions);
        });

};

QuestionModel.prototype.deleteQuestion = function(id, cb) {

    this.questionSchema.update({ is_deleted: "true" }, {
        where: { id: id }
    }).then(function() {
        cb('OK');
    });

};

QuestionModel.prototype.increaseStats = function(answer, cb) {

    var incrementField = { skip_count: Sequelize.literal('skip_count+1') }

    switch (answer.option) {
        case 'a':
            incrementField = { option_a_count: Sequelize.literal('option_a_count+1') };
            break;
        case 'b':
            incrementField = { option_b_count: Sequelize.literal('option_b_count+1') };
            break;
        case 's':
            incrementField = { skip_count: Sequelize.literal('skip_count+1') };
            break;
        default:
            incrementField = { skip_count: Sequelize.literal('skip_count+1') };
            break;
    }

    this.questionSchema.update(incrementField, {
        where: { id: answer.question_id }
    }).then(function() {
        cb('OK');
    });

};

QuestionModel.prototype.increaseAbuse = function(answer, cb) {

    var incrementField = { abuse_count: Sequelize.literal('abuse_count+1') }

    this.questionSchema.update(incrementField, {
        where: { id: answer.question_id }
    }).then(function() {
        cb('OK');
    });

};

QuestionModel.prototype.increaseFavorite = function(answer, cb) {
    var incrementField = { favorite_count: Sequelize.literal('favorite_count+1') }
    if (answer.unfavorite === true) {
        incrementField = { favorite_count: Sequelize.literal('favorite_count-1') }
    }

    this.questionSchema.update(incrementField, {
        where: { id: answer.question_id }
    }).then(function() {
        cb('OK');
    });

};

module.exports = QuestionModel;
<commit_msg>user friends added to user favorites<commit_after>'use strict';

var crypto = require('crypto');
var Sequelize = require('sequelize');

function QuestionModel(db) {
    this.questionSchema = db.question;
    this.sequelize = db.sequelize;
};

QuestionModel.prototype.insertQuestion = function(question, cb) {

    this.questionSchema.create(question).then(function(createdQuestion) {
        cb(createdQuestion);
    });
};

QuestionModel.prototype.editQuestion = function(question, cb) {

    this.questionSchema.findOne({
        where: {
            id: question.id

        }
    }).then(function(db_question) {
        db_question.option_a = question.option_a;
        db_question.option_b = question.option_b;
        db_question.question_text = question.question_text;
        db_question.question_image = question.question_image;

        db_question.save({ fields: ['option_a', 'option_b', 'question_text', 'question_image'] }).then(function() {
            cb(db_question);
        });

    });

};

QuestionModel.prototype.getQuestion = function(user_id,q_id,app, cb) {

  var rawQuery = "";
    var _replacements = [user_id, q_id, app];

    rawQuery = 'select * from proc_get_question_by_id(cast(? as UUID),cast(? as UUID),?)';

    this.sequelize.query(rawQuery, {
            replacements: _replacements,
            type: this.sequelize.QueryTypes.SELECT,
        })
        .then(function(questions) {
            cb(questions);
        });
};

QuestionModel.prototype.showAllQuestions = function(cb) {

    this.questionSchema.findAll().then(function(questions) {
        cb(questions);
    });
};

QuestionModel.prototype.userQuestions = function(user_id, app, limit, cb) {

    var rawQuery = "";
    var _replacements = [user_id, app, limit];

    rawQuery = 'select * from proc_fetch_user_questions(cast(? as UUID),?,?)';

    this.sequelize.query(rawQuery, {
            replacements: _replacements,
            type: this.sequelize.QueryTypes.SELECT,
        })
        .then(function(questions) {
            cb(questions);
        });

//TESTING
    // this.questionSchema.findAll({
    //     where: {
    //         user_id: user_id,
    //         app: app,
    //         is_deleted: false
    //     },
    //     limit: limit
    // }).then(function(questions) {
    //     cb(questions);
    // });
};

QuestionModel.prototype.userFavorites = function(user_id, app, limit, cb) {

    var rawQuery = "";
    var _replacements = [user_id, app, limit];

    rawQuery = 'select * from proc_fetch_user_favorites(cast(? as UUID),?,?)';

    this.sequelize.query(rawQuery, {
            replacements: _replacements,
            type: this.sequelize.QueryTypes.SELECT,
        })
        .then(function(questions) {
            cb(questions);
        });

};

QuestionModel.prototype.fetchQuestions = function(app, limit, user_id, installation_id, debug, cb) {

    var debugMode = debug ? debug : 0;
    var rawQuery = "";
    var _replacements = [user_id, app, limit];
    if (debugMode == 1) {
        rawQuery = 'select * from proc_fetch_questions_by_user_id_debug(cast(? as UUID),?,?)';
    } else {
        rawQuery = 'select * from proc_fetch_questions_by_user_id(cast(? as UUID),?,?)';
        if (!user_id) {
            rawQuery = 'select * from proc_fetch_questions_by_imei(?,?,?)';
            _replacements = [installation_id, app, limit];
        }
    }

    this.sequelize.query(rawQuery, {
            replacements: _replacements,
            type: this.sequelize.QueryTypes.SELECT,
            // model: this.questionSchema
        })
        .then(function(questions) {
            cb(questions);
        });

    /*    if (debugMode == 1) {
            rawQuery = "DROP TABLE IF EXISTS tempUserQuestionTable; " +
                "CREATE TEMP TABLE tempUserQuestionTable AS " +
                "select  * from question where question.app=? and question.is_deleted=FALSE;";

            rawQuery = rawQuery + 'select tu.*,u.profile_img as asker_profile_img, u.name as asker_name from (select (row_number() over ()) as rn,* from tempUserQuestionTable) as tu inner JOIN "user" as u on u.id=tu.user_id where tu.rn in (' +
                "select DISTINCT round(random() * (select count( * ) from tempUserQuestionTable))::integer as id " +
                "from generate_series(1, 100)" +
                ") limit ?;";

        } else {
            rawQuery = "DROP TABLE IF EXISTS tempUserQuestionTable; " +
                "CREATE TEMP TABLE tempUserQuestionTable AS " +
                "select  * from question where question.app=? and question.is_deleted=FALSE " +
                "EXCEPT " +
                "select q.* from answer a inner JOIN question q on a.question_id=q.id ";

            rawQuery = rawQuery + ((user_id) ? "where a.user_id=(?::UUID); " : "where a.installation_id=?; ");

            rawQuery = rawQuery + 'select tu.*,u.profile_img as asker_profile_img,u.name as asker_name from (select (row_number() over ()) as rn,* from tempUserQuestionTable) as tu inner JOIN "user" as u on u.id=tu.user_id where tu.rn in (' +
                "select DISTINCT round(random() * (select count( * ) from tempUserQuestionTable))::integer as id " +
                "from generate_series(1, 100)" +
                ") limit ?;";
            this.sequelize.query(rawQuery, {
                    replacements: [app, (user_id) ? user_id : installation_id, limit],
                    type: this.sequelize.QueryTypes.SELECT,
                    // model: this.questionSchema
                })
                .then(function(questions) {
                    cb(questions);
                });
        }*/

};

QuestionModel.prototype.getAllKapistirForWeb = function(cb) {

    var rawQuery = 'select tu.*,u.profile_img as asker_profile_img,u.facebook_id,  u.name as asker_name from question as tu inner JOIN "user" as u on u.id=tu.user_id where tu.app=1 ORDER BY created_at desc';

    this.sequelize.query(rawQuery, {
            //replacements: [app, (user_id) ? user_id : installation_id, limit],
            type: this.sequelize.QueryTypes.SELECT,
            // model: this.questionSchema
        })
        .then(function(questions) {
            cb(questions);
        });

};

QuestionModel.prototype.deleteQuestion = function(id, cb) {

    this.questionSchema.update({ is_deleted: "true" }, {
        where: { id: id }
    }).then(function() {
        cb('OK');
    });

};

QuestionModel.prototype.increaseStats = function(answer, cb) {

    var incrementField = { skip_count: Sequelize.literal('skip_count+1') }

    switch (answer.option) {
        case 'a':
            incrementField = { option_a_count: Sequelize.literal('option_a_count+1') };
            break;
        case 'b':
            incrementField = { option_b_count: Sequelize.literal('option_b_count+1') };
            break;
        case 's':
            incrementField = { skip_count: Sequelize.literal('skip_count+1') };
            break;
        default:
            incrementField = { skip_count: Sequelize.literal('skip_count+1') };
            break;
    }

    this.questionSchema.update(incrementField, {
        where: { id: answer.question_id }
    }).then(function() {
        cb('OK');
    });

};

QuestionModel.prototype.increaseAbuse = function(answer, cb) {

    var incrementField = { abuse_count: Sequelize.literal('abuse_count+1') }

    this.questionSchema.update(incrementField, {
        where: { id: answer.question_id }
    }).then(function() {
        cb('OK');
    });

};

QuestionModel.prototype.increaseFavorite = function(answer, cb) {
    var incrementField = { favorite_count: Sequelize.literal('favorite_count+1') }
    if (answer.unfavorite === true) {
        incrementField = { favorite_count: Sequelize.literal('favorite_count-1') }
    }

    this.questionSchema.update(incrementField, {
        where: { id: answer.question_id }
    }).then(function() {
        cb('OK');
    });

};

module.exports = QuestionModel;
<|endoftext|>


<commit_before>var db = require('./database');
var io;

var getUserId = function(callback) {
	db.getUID(callback);
};

// var saveIPN = function(body) {
// 	db.save()
// };

var saveEntry = function(body, callback) {
	if(typeof callback !== 'function') {
		callback = function(){};
	}

	if(!body) {
		return callback('Invalid Body Data');
	}

	var uid = +body.uid;
	if(isNaN(uid)) {
		callback('Invalid UID');
	}

	db.save(uid, 'guess', body, callback);

	getChartData(function(err) {
		io.emit('chartData', chartData);
	});
};

var getChartData = function(callback) {
	if(typeof callback !== 'function') {
		callback = function(){};
	}
	console.log('getChartData');
	db.getAll('guess', function(err, guesses) {
		console.log(guesses);
		parseChartData(guesses, function(err) {

			callback(err);
		});
	});
};

exports.loadSocketIO = function(socketio) {
	io = socketio;

	getChartData();

	io.on('connection', function(socket) {
		socket.emit('chartData', chartData);
		console.log('A user connected.');
	});
};

exports.getUserId = getUserId;
exports.saveEntry = saveEntry;
exports.getChartData = getChartData;

function getTimeNow() {
	var year = new Date().getUTCFullYear();
	var month = new Date().getUTCMonth();
	var day = new Date().getUTCDate();

	return +new Date(year, month, day);
};

function parseChartData(guesses, callback) {

	chartData.date.options.xaxis.min = getTimeNow();

	var collateDates = {};
	var dates = [];
	var collateTimes = {};
	var times = [];
	var collateWeights = {};
	var weights = [];
	var collateHeights = {};
	var heights = [];
	var collateHair = {};
	var hair = [];
	var collateEyes = {};
	var eyes = [];

	var highestDate = getTimeNow();

	guesses.forEach(function(rawGuess, i) {
		var guess;

		try { guess = JSON.parse(rawGuess) }
		catch(e) { return false; }

		var dateGuess = parseDate(guess.date);
		if(dateGuess) {
			if(typeof collateDates[dateGuess] === 'undefined') {
				collateDates[dateGuess] = 1;
			} else {
				collateDates[dateGuess]++;
			}
		}

		var timeGuess = parseTime(guess.time);
		if(timeGuess) {
			if(typeof collateTimes[timeGuess] === 'undefined') {
				collateTimes[timeGuess] = 1;
			} else {
				collateTimes[timeGuess]++;
			}
		}

		var weightGuess = parseInt(+guess.weight);
		if(weightGuess) {
			if(typeof collateWeights[weightGuess] === 'undefined') {
				collateWeights[weightGuess] = 1;
			} else {
				collateWeights[weightGuess]++;
			}
		}

		var heightGuess = parseInt(+guess.height);
		if(heightGuess) {
			if(typeof collateHeights[heightGuess] === 'undefined') {
				collateHeights[heightGuess] = 1;
			} else {
				collateHeights[heightGuess]++;
			}
		}

		var hairGuess = guess.hair;
		if(hairGuess && hairGuess !== '') {
			if(typeof collateHair[hairGuess] === 'undefined') {
				collateHair[hairGuess] = 1;
			} else {
				collateHair[hairGuess]++;
			}
		}

		var eyeGuess = guess.eyes;
		if(eyeGuess && eyeGuess !== '') {
			if(typeof collateEyes[eyeGuess] === 'undefined') {
				collateEyes[eyeGuess] = 1;
			} else {
				collateEyes[eyeGuess]++;
			}
		}
	});

	for(var date in collateDates) {
		dates.push([+date, collateDates[date]]);
		if(date > highestDate) highestDate = +date;
	}
	for(var time in collateTimes) {
		times.push([+time, collateTimes[time]]);
	}
	for(var weight in collateWeights) {
		weights.push([+weight, collateWeights[weight]]);
	}
	for(var height in collateHeights) {
		heights.push([+height, collateHeights[height]]);
	}
	for(var h in collateHair) {
		hair.push({ data: [[0, collateHair[h]]], label: h, color: getColor(h) });
	}
	for(var e in collateEyes) {
		eyes.push({ data: [[0, collateEyes[e]]], label: e, color: getColor(e) });
	}

	chartData.date.data = [dates];
	chartData.time.data = [times];
	chartData.weight.data = [weights];
	chartData.height.data = [heights];
	chartData.hair.data = hair;
	chartData.eyes.data = eyes;

	chartData.date.options.xaxis.max = +highestDate;
	callback(null, chartData);
	console.log(chartData);
};

function parseDate(dateString) {
	var date = dateString.split('-');

	date[0] = +date[0];
	date[1] = +date[1];
	date[2] = +date[2];

	var thisYear = new Date().getUTCFullYear();
	if(isNaN(date[0]) || date[0] < thisYear || date[0] > thisYear+2) {
		return false;
	}

	var thisMonth = new Date().getUTCMonth();
	if(thisMonth > date[1] || date[1] > 12) {
		return false;
	}
	thisMonth = thisMonth - 1;

	if(1 > date[2] || date[2] > 31) {
		return false;
	}

	return Date.UTC(date[0], date[1], date[2]);
};

function parseTime(timeString) {
	var hour = +timeString.split(':')[0];
	if(isNaN(hour)) {
		return false;
	} else {
		return hour;
	}
};

function getColor(color) {
	color = color.replace('hair-', '').replace('eyes-', '');
	if(color === 'black') {
		return '#272B2A';
	} else if(color === 'blonde') {
		return '#BC9B34';
	} else if(color === 'brown') {
		return '#492D2A';
	} else if(color === 'red') {
		return '#cc3333';
	} else if(color === 'gray') {
		return '#a3a695';
	} else if(color === 'blue') {
		return '#3399ff';
	} else if(color === 'green') {
		return '#009966';
	} else if(color === 'hazel') {
		return '#6b7e47';
	} else {
		return '#eeeeee';
	}
};

var chartData = {
	date: {
		data: [],
		options: {
			HtmlText: false,
			shadowSize: 0,
			grid: { minorVerticalLines: true },
			yaxis: { min: 0, title: '# of Entries', titleAngle: 90 },
			xaxis: { mode: 'time', min: getTimeNow(), title: 'Birth Date' },
			bars: { show: true, barWidth: 0.5 },
			title: 'Birth Date'
		}
	},
	time: {
		data: [],
		options: {
			HtmlText: false,
			shadowSize: 0,
			grid: { minorVerticalLines: true },
			yaxis: { min: 0, title: '# of Entries', titleAngle: 90 },
			xaxis: { min: 0, max: 23, title: 'Birth Time (Hour of Day)',
				ticks: [[0, '12a'], [1, '1a'], [2, '2a'], [3, '3a'], [4, '4a'], [5, '5a'], [6, '6a'], [7, '7a'], [8, '8a'], [9, '9a'], [10, '10a'], [11, '11a'], [12, '12p'],
								[13, '1p'], [14, '2p'], [15, '3p'], [16, '4p'], [17, '5p'], [18, '6p'], [19, '7p'], [20, '8p'], [21, '9p'], [22, '10p'], [23, '11p']] },
			bars: { show: true }
		}
	},
	weight: {
		data: [],
		options: {
			HtmlText: false,
			shadowSize: 0,
			grid: { minorVerticalLines: true },
			yaxis: { min: 0, title: '# of Entries', titleAngle: 90 },
			xaxis: { min: 4, max: 12, title: 'Birth Weight in Pounds' },
			bars: { show: true }
		}
	},
	height: {
		data: [],
		options: {
			HtmlText: false,
			shadowSize: 0,
			grid: { minorVerticalLines: true },
			yaxis: { min: 0, title: '# of Entries', titleAngle: 90 },
			xaxis: { min: 16, max: 24, title: 'Birth Length in Inches' },
			bars: { show: true }
		}
	},
	hair: {
		data: [],
		options: {
	    HtmlText : false,
			shadowSize: 0,
	    grid : {
	      verticalLines : false,
	      horizontalLines : false
	    },
	    xaxis : { showLabels : false },
	    yaxis : { showLabels : false },
	    pie : {
	      show : true,
	      explode : 6
	    },
	    mouse : { track : true },
	    legend : {
	      position : 'se',
	      backgroundColor : '#D2E8FF'
	    },
			title: 'Hair Color'
		}
	},
	eyes: {
		data: [],
		options: {
	    HtmlText : false,
			shadowSize: 0,
	    grid : {
	      verticalLines : false,
	      horizontalLines : false
	    },
	    xaxis : { showLabels : false },
	    yaxis : { showLabels : false },
	    pie : {
	      show : true,
	      explode : 6
	    },
	    mouse : { track : true },
	    legend : {
	      position : 'se',
	      backgroundColor : '#D2E8FF'
	    },
			title: 'Eye Color'
		}
	}
};
<commit_msg>fix issue with no guesses entered<commit_after>var db = require('./database');
var io;

var getUserId = function(callback) {
	db.getUID(callback);
};

// var saveIPN = function(body) {
// 	db.save()
// };

var saveEntry = function(body, callback) {
	if(typeof callback !== 'function') {
		callback = function(){};
	}

	if(!body) {
		return callback('Invalid Body Data');
	}

	var uid = +body.uid;
	if(isNaN(uid)) {
		callback('Invalid UID');
	}

	db.save(uid, 'guess', body, callback);

	getChartData(function(err) {
		io.emit('chartData', chartData);
	});
};

var getChartData = function(callback) {
	if(typeof callback !== 'function') {
		callback = function(){};
	}

	db.getAll('guess', function(err, guesses) {
		if(!guesses) return callback('No guesses.');
		parseChartData(guesses, function(err) {
			callback(err);
		});
	});
};

exports.loadSocketIO = function(socketio) {
	io = socketio;

	getChartData();

	io.on('connection', function(socket) {
		socket.emit('chartData', chartData);
		console.log('A user connected.');
	});
};

exports.getUserId = getUserId;
exports.saveEntry = saveEntry;
exports.getChartData = getChartData;

function getTimeNow() {
	var year = new Date().getUTCFullYear();
	var month = new Date().getUTCMonth();
	var day = new Date().getUTCDate();

	return +new Date(year, month, day);
};

function parseChartData(guesses, callback) {

	chartData.date.options.xaxis.min = getTimeNow();

	var collateDates = {};
	var dates = [];
	var collateTimes = {};
	var times = [];
	var collateWeights = {};
	var weights = [];
	var collateHeights = {};
	var heights = [];
	var collateHair = {};
	var hair = [];
	var collateEyes = {};
	var eyes = [];

	var highestDate = getTimeNow();

	guesses.forEach(function(rawGuess, i) {
		var guess;

		try { guess = JSON.parse(rawGuess) }
		catch(e) { return false; }

		var dateGuess = parseDate(guess.date);
		if(dateGuess) {
			if(typeof collateDates[dateGuess] === 'undefined') {
				collateDates[dateGuess] = 1;
			} else {
				collateDates[dateGuess]++;
			}
		}

		var timeGuess = parseTime(guess.time);
		if(timeGuess) {
			if(typeof collateTimes[timeGuess] === 'undefined') {
				collateTimes[timeGuess] = 1;
			} else {
				collateTimes[timeGuess]++;
			}
		}

		var weightGuess = parseInt(+guess.weight);
		if(weightGuess) {
			if(typeof collateWeights[weightGuess] === 'undefined') {
				collateWeights[weightGuess] = 1;
			} else {
				collateWeights[weightGuess]++;
			}
		}

		var heightGuess = parseInt(+guess.height);
		if(heightGuess) {
			if(typeof collateHeights[heightGuess] === 'undefined') {
				collateHeights[heightGuess] = 1;
			} else {
				collateHeights[heightGuess]++;
			}
		}

		var hairGuess = guess.hair;
		if(hairGuess && hairGuess !== '') {
			if(typeof collateHair[hairGuess] === 'undefined') {
				collateHair[hairGuess] = 1;
			} else {
				collateHair[hairGuess]++;
			}
		}

		var eyeGuess = guess.eyes;
		if(eyeGuess && eyeGuess !== '') {
			if(typeof collateEyes[eyeGuess] === 'undefined') {
				collateEyes[eyeGuess] = 1;
			} else {
				collateEyes[eyeGuess]++;
			}
		}
	});

	for(var date in collateDates) {
		dates.push([+date, collateDates[date]]);
		if(date > highestDate) highestDate = +date;
	}
	for(var time in collateTimes) {
		times.push([+time, collateTimes[time]]);
	}
	for(var weight in collateWeights) {
		weights.push([+weight, collateWeights[weight]]);
	}
	for(var height in collateHeights) {
		heights.push([+height, collateHeights[height]]);
	}
	for(var h in collateHair) {
		hair.push({ data: [[0, collateHair[h]]], label: h, color: getColor(h) });
	}
	for(var e in collateEyes) {
		eyes.push({ data: [[0, collateEyes[e]]], label: e, color: getColor(e) });
	}

	chartData.date.data = [dates];
	chartData.time.data = [times];
	chartData.weight.data = [weights];
	chartData.height.data = [heights];
	chartData.hair.data = hair;
	chartData.eyes.data = eyes;

	chartData.date.options.xaxis.max = +highestDate;
	callback(null, chartData);
	console.log(chartData);
};

function parseDate(dateString) {
	var date = dateString.split('-');

	date[0] = +date[0];
	date[1] = +date[1];
	date[2] = +date[2];

	var thisYear = new Date().getUTCFullYear();
	if(isNaN(date[0]) || date[0] < thisYear || date[0] > thisYear+2) {
		return false;
	}

	var thisMonth = new Date().getUTCMonth();
	if(thisMonth > date[1] || date[1] > 12) {
		return false;
	}
	thisMonth = thisMonth - 1;

	if(1 > date[2] || date[2] > 31) {
		return false;
	}

	return Date.UTC(date[0], date[1], date[2]);
};

function parseTime(timeString) {
	var hour = +timeString.split(':')[0];
	if(isNaN(hour)) {
		return false;
	} else {
		return hour;
	}
};

function getColor(color) {
	color = color.replace('hair-', '').replace('eyes-', '');
	if(color === 'black') {
		return '#272B2A';
	} else if(color === 'blonde') {
		return '#BC9B34';
	} else if(color === 'brown') {
		return '#492D2A';
	} else if(color === 'red') {
		return '#cc3333';
	} else if(color === 'gray') {
		return '#a3a695';
	} else if(color === 'blue') {
		return '#3399ff';
	} else if(color === 'green') {
		return '#009966';
	} else if(color === 'hazel') {
		return '#6b7e47';
	} else {
		return '#eeeeee';
	}
};

var chartData = {
	date: {
		data: [],
		options: {
			HtmlText: false,
			shadowSize: 0,
			grid: { minorVerticalLines: true },
			yaxis: { min: 0, title: '# of Entries', titleAngle: 90 },
			xaxis: { mode: 'time', min: getTimeNow(), title: 'Birth Date' },
			bars: { show: true, barWidth: 0.5 },
			title: 'Birth Date'
		}
	},
	time: {
		data: [],
		options: {
			HtmlText: false,
			shadowSize: 0,
			grid: { minorVerticalLines: true },
			yaxis: { min: 0, title: '# of Entries', titleAngle: 90 },
			xaxis: { min: 0, max: 23, title: 'Birth Time (Hour of Day)',
				ticks: [[0, '12a'], [1, '1a'], [2, '2a'], [3, '3a'], [4, '4a'], [5, '5a'], [6, '6a'], [7, '7a'], [8, '8a'], [9, '9a'], [10, '10a'], [11, '11a'], [12, '12p'],
								[13, '1p'], [14, '2p'], [15, '3p'], [16, '4p'], [17, '5p'], [18, '6p'], [19, '7p'], [20, '8p'], [21, '9p'], [22, '10p'], [23, '11p']] },
			bars: { show: true }
		}
	},
	weight: {
		data: [],
		options: {
			HtmlText: false,
			shadowSize: 0,
			grid: { minorVerticalLines: true },
			yaxis: { min: 0, title: '# of Entries', titleAngle: 90 },
			xaxis: { min: 4, max: 12, title: 'Birth Weight in Pounds' },
			bars: { show: true }
		}
	},
	height: {
		data: [],
		options: {
			HtmlText: false,
			shadowSize: 0,
			grid: { minorVerticalLines: true },
			yaxis: { min: 0, title: '# of Entries', titleAngle: 90 },
			xaxis: { min: 16, max: 24, title: 'Birth Length in Inches' },
			bars: { show: true }
		}
	},
	hair: {
		data: [],
		options: {
	    HtmlText : false,
			shadowSize: 0,
	    grid : {
	      verticalLines : false,
	      horizontalLines : false
	    },
	    xaxis : { showLabels : false },
	    yaxis : { showLabels : false },
	    pie : {
	      show : true,
	      explode : 6
	    },
	    mouse : { track : true },
	    legend : {
	      position : 'se',
	      backgroundColor : '#D2E8FF'
	    },
			title: 'Hair Color'
		}
	},
	eyes: {
		data: [],
		options: {
	    HtmlText : false,
			shadowSize: 0,
	    grid : {
	      verticalLines : false,
	      horizontalLines : false
	    },
	    xaxis : { showLabels : false },
	    yaxis : { showLabels : false },
	    pie : {
	      show : true,
	      explode : 6
	    },
	    mouse : { track : true },
	    legend : {
	      position : 'se',
	      backgroundColor : '#D2E8FF'
	    },
			title: 'Eye Color'
		}
	}
};
<|endoftext|>


<commit_before>class Clan {
    removePlayer(player) {
        for (var i = 0; i < this.members.length; ++i) {
            if (this.members[i].player.sid === player.player.sid) {
                this.members.splice(i, 1);
                return true;
            }
        }
        return false;
    }
    addPlayer(player) {
        this.members.push(player);
    }
    constructor(name) {
        if (name) {
            this.name = name;
        } else {
            this.name = null;
        }
        this.members = [];
    }
}
module.exports = Clan;<commit_msg>Modify player teams upon clan add/remove<commit_after>class Clan {
    removePlayer(player) {
        for (var i = 0; i < this.members.length; ++i) {
            if (this.members[i].player.sid === player.player.sid) {
                this.members[i].player.team = null;
                this.members.splice(i, 1);
                return true;
            }
        }
        return false;
    }
    addPlayer(player) {
        player.player.team = this.name;
        this.members.push(player);
    }
    constructor(name) {
        if (name) {
            this.name = name;
        } else {
            this.name = null;
        }
        this.members = [];
    }
}
module.exports = Clan;<|endoftext|>


<commit_before>var Actor = function(args) {
  this.context = args.context;
  this.x = args.startX;
  this.y = args.startY;
  this.name = args.name;
  this.radius = 6;
  this.direction = args.direction;
  this.speed = PAC_MOVE_DELAY;
  this.isMoving = false;
  this.mouthPos = 0.0;
  this.mouthIsOpening = true;
  this.keyStates = {
    up: false,
    down: false,
    left: false,
    right: false
  }
}
Actor.prototype.clear = function() {
  this.context.clearRect(this.x - this.radius, this.y - this.radius, 2 * this.radius, 2 * this.radius);
}
Actor.prototype.render = function() {
  this.context.fillStyle = nameToColor[this.name];
  this.context.beginPath();

  var arcStart, arcEnd;
  var cheekX = 0;
  var cheekY = 0;
  switch(this.direction) {
    case "up":
      arcStart = (1.5 + this.mouthPos) * Math.PI;
      arcEnd = (3.5 - this.mouthPos) * Math.PI;
      cheekY = 2.5;
    break;
    case "down":
      arcStart = (0.5 + this.mouthPos) * Math.PI;
      arcEnd = (2.5 - this.mouthPos) * Math.PI;
      cheekY = -2.5;
    break;
    case "left":
      arcStart = (1.0 + this.mouthPos) * Math.PI;
      arcEnd = (3.0 - this.mouthPos) * Math.PI;
      cheekX = 2.5;
    break;
    case "right":
      arcStart = (0.0 + this.mouthPos) * Math.PI;
      arcEnd = (2.0 - this.mouthPos) * Math.PI;
      cheekX = -2.5;
    break;
  }

  if(this.name == "m") {
    this.context.arc(this.x, this.y, this.radius, arcStart, arcEnd, false);
    this.context.lineTo(this.x + cheekX, this.y + cheekY);
  }

  this.context.closePath();
  this.context.fill();
};
Actor.prototype.detectCollision = function(keyPressed) {
  var collision = "none";
  var xMod, yMod;
  var direction = keyPressed ? keyPressed : this.direction
  switch(direction) {
    case "up": xMod = 0; yMod = -1; break;
    case "down": xMod = 0; yMod = 1; break;
    case "left": xMod = -1; yMod = 0; break;
    case "right": xMod = 1; yMod = 0; break;
  }
  var x = Math.floor(this.x / 8);
  var y = Math.floor(this.y / 8) - 3;

  var cell = gameBoard.getCell({
    x: x + xMod,
    y: y + yMod
  });
  if(cell == "x" || cell == "-") {
    collision = "wall";
  }
  else if(cell == ".") {
    collision = "pellet";
  }
  else if(cell == "o") {
    collision = "powerPellet";
  }
  else if(cell == "b" || cell == "i" || cell == "p" || cell == "c") {
    collision = "ghost";
  }

  return collision;
};
Actor.prototype.move = function() {
  this.clear();
  this.mouthPos = Math.floor((this.mouthPos + ((this.mouthIsOpening ? 1 : -1) * 0.1)) * 10) / 10;
  if(this.mouthPos <= 0) {
    this.mouthIsOpening = true;
  }
  else if(this.mouthPos >= 0.5) {
    this.mouthIsOpening = false;
  }
  switch(this.direction) {
    case "up": this.y--; break;
    case "down": this.y++; break;
    case "left": this.x--; break;
    case "right": this.x++; break;
  }
  var newDirection = false;
  for(var prop in this.keyStates) {
    if(this.keyStates.hasOwnProperty(prop) && this.keyStates[prop]) {
      newDirection = prop;
      break;
    }
  }
  if(this.x + 8 <= 0) {
    if(this.direction == "left") {
      this.x = BOARD_WIDTH;
    }
  }
  else if(this.x - 8 > BOARD_WIDTH) {
    if(this.direction == "right") {
      this.x = 0 - 8;
    }
  }
  else if(this.x % 8 == 4 && this.y % 8 == 4) {
    if(this.detectCollision() == "wall") {
      if(newDirection && this.detectCollision(newDirection) != "wall") {
        this.direction = newDirection;
      }
      else {
        this.isMoving = false;
        clearInterval(this.moveIntervalID);
      }
    }
    else if(this.keyStates[this.direction] === false) {
      if(newDirection) {
        if(this.detectCollision(newDirection) != "wall") {
          this.direction = newDirection;
        }
      }
    }
  }
  this.render();
};
Actor.prototype.handleKeyDown = function(keyPressed) {
  if(keyPressed) {
    this.keyStates[keyPressed] = true;
    if(this.isMoving === false) {
      this.clear();
      if(this.detectCollision(keyPressed) == "wall") {
        this.isMoving = false;
      }
      else {
        this.direction = keyPressed;
        this.isMoving = true;
        this.moveIntervalID = setInterval(this.move.bind(this), this.speed);
      }
      this.render();
    }
  }
};
Actor.prototype.handleKeyUp = function(keyPressed) {
  this.keyStates[keyPressed] = false;
};
<commit_msg>Update Actor to change direction at any time if there will be no collision<commit_after>var Actor = function(args) {
  this.context = args.context;
  this.x = args.startX;
  this.y = args.startY;
  this.name = args.name;
  this.radius = 6;
  this.direction = args.direction;
  this.speed = PAC_MOVE_DELAY;
  this.mouthPos = 0.0;
  this.mouthIsOpening = true;
  this.moveIntervalID = false;
  this.keyStates = {
    up: false,
    down: false,
    left: false,
    right: false
  }
}
Actor.prototype.clear = function() {
  this.context.clearRect(this.x - this.radius, this.y - this.radius, 2 * this.radius, 2 * this.radius);
};
Actor.prototype.render = function() {
  this.context.fillStyle = nameToColor[this.name];
  this.context.beginPath();

  var arcStart, arcEnd;
  var cheekX = 0;
  var cheekY = 0;
  switch(this.direction) {
    case "up":
      arcStart = (1.5 + this.mouthPos) * Math.PI;
      arcEnd = (3.5 - this.mouthPos) * Math.PI;
      cheekY = 2.5;
    break;
    case "down":
      arcStart = (0.5 + this.mouthPos) * Math.PI;
      arcEnd = (2.5 - this.mouthPos) * Math.PI;
      cheekY = -2.5;
    break;
    case "left":
      arcStart = (1.0 + this.mouthPos) * Math.PI;
      arcEnd = (3.0 - this.mouthPos) * Math.PI;
      cheekX = 2.5;
    break;
    case "right":
      arcStart = (0.0 + this.mouthPos) * Math.PI;
      arcEnd = (2.0 - this.mouthPos) * Math.PI;
      cheekX = -2.5;
    break;
  }

  if(this.name == "m") {
    this.context.arc(this.x, this.y, this.radius, arcStart, arcEnd, false);
    this.context.lineTo(this.x + cheekX, this.y + cheekY);
  }

  this.context.closePath();
  this.context.fill();
};
Actor.prototype.detectCollision = function(keyPressed) {
  var collision = "none";
  var xMod, yMod;
  var direction = keyPressed ? keyPressed : this.direction
  switch(direction) {
    case "up": xMod = 0; yMod = -1; break;
    case "down": xMod = 0; yMod = 1; break;
    case "left": xMod = -1; yMod = 0; break;
    case "right": xMod = 1; yMod = 0; break;
  }
  var x = Math.floor(this.x / 8);
  var y = Math.floor(this.y / 8) - 3;

  var cell = gameBoard.getCell({
    x: x + xMod,
    y: y + yMod
  });
  if(cell == "x" || cell == "-") {
    collision = "wall";
  }
  else if(cell == ".") {
    collision = "pellet";
  }
  else if(cell == "o") {
    collision = "powerPellet";
  }
  else if(cell == "b" || cell == "i" || cell == "p" || cell == "c") {
    collision = "ghost";
  }

  return collision;
};
Actor.prototype.move = function() {
  this.clear();
  this.mouthPos = Math.floor((this.mouthPos + ((this.mouthIsOpening ? 1 : -1) * 0.1)) * 10) / 10;
  if(this.mouthPos <= 0) {
    this.mouthIsOpening = true;
  }
  else if(this.mouthPos >= 0.5) {
    this.mouthIsOpening = false;
  }
  var xInTile = this.x % 8;
  var yInTile = this.y % 8;
  switch(this.direction) {
    case "up": this.y--; break;
    case "down": this.y++; break;
    case "left": this.x--; break;
    case "right": this.x++; break;
  }
  if((this.direction == "up" || this.direction == "down") && xInTile != 4) {
    this.x += xInTile < 4 ? 1 : -1;
  }
  else if((this.direction == "left" || this.direction == "right") && yInTile != 4) {
    this.y += yInTile < 4 ? 1 : -1;
  }

  var newDirection = false;
  for(var prop in this.keyStates) {
    if(this.keyStates.hasOwnProperty(prop) && this.keyStates[prop]) {
      newDirection = prop;
      break;
    }
  }

  if(this.x + 8 <= 0) {
    if(this.direction == "left") {
      this.x = BOARD_WIDTH;
    }
  }
  else if(this.x - 8 > BOARD_WIDTH) {
    if(this.direction == "right") {
      this.x = 0 - 8;
    }
  }
  else {
    if(this.keyStates[this.direction] === false) {
      if(newDirection) {
        if(this.detectCollision(newDirection) != "wall") {
          this.direction = newDirection;
        }
      }
    }
    if(xInTile == 4 && yInTile == 4 && this.detectCollision() == "wall") {
      if(newDirection && this.detectCollision(newDirection) != "wall") {
        this.direction = newDirection;
      }
      else {
        clearInterval(this.moveIntervalID);
        this.moveIntervalID = false;
      }
    }
  }
  this.render();
};
Actor.prototype.handleKeyDown = function(keyPressed) {
  if(keyPressed) {
    if(this.keyStates[keyPressed] === false) {
      this.keyStates[keyPressed] = true;
      this.clear();
      if(this.moveIntervalID === false && this.detectCollision(keyPressed) != "wall") {
        this.moveIntervalID = setInterval(this.move.bind(this), this.speed);
      }
      this.render();
    }
  }
};
Actor.prototype.handleKeyUp = function(keyPressed) {
  this.keyStates[keyPressed] = false;
};
<|endoftext|>


<commit_before>(function () { "use strict";

var commonUtil = require('./common/util.js');
var _ = require('lodash');
var util = require('util');
var assert = require('assert');
var buscomponent = require('./stbuscomponent.js');

function Admin () {
	Admin.super_.apply(this, arguments);
}

util.inherits(Admin, buscomponent.BusComponent);

function _reqpriv_x (required, f) {
	var requiredPermission = required;

	return function(query, ctx, xdata, cb) {
		if (ctx.user === null || !ctx.access.has(requiredPermission))
			(cb ? cb : xdata)('permission-denied');
		else
			return _.bind(f, this)(query, ctx, xdata, cb);
	};
}

function _reqpriv (required, f) {
	return _reqpriv_x(required, function(query, ctx, xdata, cb) {
		return _.bind(f, this)(query, ctx, cb = xdata);
	});
}

Admin.prototype.listAllUsers = buscomponent.provideQT('client-list-all-users', _reqpriv('userdb', function(query, ctx, cb) {
	ctx.query('SELECT birthday, deletiontime, street, zipcode, town, `desc`, users.name, giv_name, fam_name, users.id AS uid, tradecount, ' +
		'email, email_verif AS emailverif, wprovision, lprovision, freemoney, totalvalue, wprov_sum, lprov_sum, ticks, registertime, ' +
		'schools.path AS schoolpath, schools.id AS schoolid, pending, jointime, ' +
		'(SELECT COUNT(*) FROM ecomments WHERE ecomments.commenter=users.id) AS commentcount, '+
		'(SELECT MAX(time) FROM ecomments WHERE ecomments.commenter=users.id) AS lastcommenttime FROM users ' +
		'JOIN users_data ON users.id = users_data.id ' +
		'JOIN users_finance ON users.id = users_finance.id ' +
		'LEFT JOIN schoolmembers AS sm ON sm.uid = users.id ' +
		'LEFT JOIN schools ON schools.id = sm.schoolid ',
		[], function(userlist) {
		cb('list-all-users-success', {results: userlist});
	});
}));

Admin.prototype.shutdown = buscomponent.provideQT('client-shutdown', _reqpriv('server', function(query, ctx, cb) {
	this.emit('globalShutdown');

	cb('shutdown-success');
}));

Admin.prototype.impersonateUser = buscomponent.provideWQT('client-impersonate-user', _reqpriv('server', function(query, ctx, cb) {
	if (parseInt(query.uid) != query.uid)
		return cb('permission-denied');

	ctx.query('SELECT COUNT(*) AS c FROM users WHERE id = ?', [parseInt(query.uid)], function(r) {
		assert.equal(r.length, 1);
		if (r[0].c == 0)
			return cb('impersonate-user-notfound', null, 'repush');

		ctx.query('UPDATE sessions SET uid = ? WHERE id = ?', [parseInt(query.uid), ctx.user.sid], function() {
			cb('impersonate-user-success', null, 'repush');
		});
	});
}));

Admin.prototype.deleteUser = buscomponent.provideWQT('client-delete-user', _reqpriv('userdb', function(query, ctx, cb) {
	if (ctx.user.id == query.uid)
		return cb('delete-user-self-notallowed');

	var uid = parseInt(query.uid);
	if (uid != uid) // NaN
		return cb('format-error');

	ctx.getConnection(function(conn, commit) {
		conn.query('START TRANSACTION', [], function() {
		conn.query('DELETE FROM sessions WHERE uid = ?', [uid], function() {
		conn.query('DELETE FROM schoolmembers WHERE uid = ?', [uid], function() {
		conn.query('UPDATE stocks SET name = CONCAT("leader:deleted", ?) WHERE leader = ?', [uid, uid], function() {
		conn.query('UPDATE users_data SET giv_name="__user_deleted__", fam_name="", birthday = NULL, ' +
			'street="", zipcode="", town="", traditye=0, `desc`="", realnamepublish = 0 WHERE id = ?', [uid], function() {
		conn.query('UPDATE users_finance SET wprovision=0, lprovision=0 WHERE id = ?', [uid], function() {
		conn.query('UPDATE users SET name = CONCAT("user_deleted", ?), email = CONCAT("deleted:", email), ' +
		'pwhash="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", deletiontime = UNIX_TIMESTAMP() WHERE id = ?', [uid, uid], function() {
			commit(function() {
				cb('delete-user-success');
			});
		});
		});
		});
		});
		});
		});
		});
	});
}));

Admin.prototype.changeUserEMail = buscomponent.provideWQT('client-change-user-email', _reqpriv('userdb', function(query, ctx, cb) {
	ctx.query('UPDATE users SET email = ?, email_verif = ? WHERE id = ?',
		[String(query.email), query.emailverif ? 1 : 0, parseInt(query.uid)], function() {
		cb('change-user-email-success');
	});
}));

Admin.prototype.changeCommentText = buscomponent.provideWQT('client-change-comment-text', _reqpriv('moderate', function(query, ctx, cb) {
	ctx.query('UPDATE ecomments SET comment = ?, trustedhtml = ? WHERE commentid = ?',
		[String(query.comment), ctx.access.has('server') && query.trustedhtml ? 1:0, parseInt(query.commentid)], function() {
		cb('change-comment-text-success');
	});
}));

Admin.prototype.notifyUnstickAll = buscomponent.provideWQT('client-notify-unstick-all', _reqpriv('moderate', function(query, ctx, cb) {
	ctx.query('UPDATE mod_notif SET sticky = 0', [], function() {
		cb('notify-unstick-all-success');
	});
}));

Admin.prototype.notifyAll = buscomponent.provideWQT('client-notify-all', _reqpriv('moderate', function(query, ctx, cb) {
	ctx.query('INSERT INTO mod_notif (content, sticky) VALUES (?, ?)', [String(query.content), query.sticky ? 1 : 0], function(res) {
		ctx.feed({'type': 'mod-notification', 'targetid': res.insertId, 'srcuser': ctx.user.id, 'everyone': true});
		cb('notify-all-success');
	});
}));

Admin.prototype.renameSchool = buscomponent.provideWQT('client-rename-school', _reqpriv('schooldb', function(query, ctx, cb) {
	ctx.query('SELECT path FROM schools WHERE id = ?', [parseInt(query.schoolid)], function(r) {
		if (r.length == 0)
			return cb('rename-school-notfound');

		ctx.query('SELECT COUNT(*) AS c FROM schools WHERE path = ?', [commonUtil.parentPath(query.schoolpath || '/')], function(pr) {
			assert.equal(pr.length, 1);
			if (pr[0].c !== (commonUtil.parentPath(query.schoolpath || '/') != '/' ? 1 : 0))
				return cb('rename-school-notfound');

			ctx.query('SELECT COUNT(*) AS c FROM schools WHERE path = ?', [String(query.schoolpath || '/')], function(er) {
				assert.equal(er.length, 1);
				if (query.schoolpath && er[0].c == 1)
					return cb('rename-school-already-exists');

				ctx.query('UPDATE schools SET name = ? WHERE id = ?', [String(query.schoolname), parseInt(query.schoolid)], function() {
					if (query.schoolpath) {
						ctx.query('UPDATE schools SET path = REPLACE(path, ?, ?) WHERE path LIKE ? OR path = ?',
							[r[0].path, String(query.schoolpath), r[0].path + '/%', r[0].path], function() {
							cb('rename-school-success');
						});
					} else {
						cb('rename-school-success');
					}
				});
			});
		});
	});
}));

Admin.prototype.joinSchools = buscomponent.provideWQT('client-join-schools', _reqpriv('schooldb', function(query, ctx, cb) {
	ctx.query('SELECT path FROM schools WHERE id = ?', [parseInt(query.masterschool)], function(mr) {
	ctx.query('SELECT path FROM schools WHERE id = ?', [parseInt(query.subschool)], function(sr) {
		assert.ok(mr.length <= 1);
		assert.ok(sr.length <= 1);

		if (sr.length == 0 || ((mr.length == 0 || mr[0].path == sr[0].path) && query.masterschool != null))
			return cb('join-schools-notfound');
		if (mr.length > 0 && commonUtil.parentPath(mr[0].path) != commonUtil.parentPath(sr[0].path))
			return cb('join-schools-diff-parent');

		ctx.query('UPDATE schoolmembers SET schoolid = ? WHERE schoolid = ?', [parseInt(query.masterschool), parseInt(query.subschool)], function() {
		ctx.query('DELETE FROM schooladmins WHERE schoolid = ?', [parseInt(query.subschool)], function() {
			ctx.query('DELETE FROM schools WHERE id = ?', [parseInt(query.subschool)], function() {
				cb('join-schools-success');
			});
		});
		});
	});
	});
}));

Admin.prototype.getFollowers = buscomponent.provideQT('client-get-followers', _reqpriv('userdb', function(query, ctx, cb) {
	ctx.query('SELECT u.name, u.id, ds.* ' +
		'FROM stocks AS s ' +
		'JOIN depot_stocks AS ds ON ds.stockid = s.id ' +
		'JOIN users AS u ON ds.userid = u.id ' +
		'WHERE s.leader = ?', [parseInt(query.uid)], function(res) {

		cb('get-followers-success', {results: res});
	});
}));

Admin.prototype.getServerStatistics = buscomponent.provideQT('client-get-server-statistics', _reqpriv('userdb', function(query, ctx, cb) {
	this.requestGlobal({name: 'internal-get-server-statistics'}, function(replies) {
		cb('get-server-statistics-success', {servers: replies});
	});
}));

Admin.prototype.showPacketLog = buscomponent.provideQT('client-show-packet-log', _reqpriv('userdb', function(query, ctx, cb) {
	/* The package log is mostly informal and not expected to be used for anything but debugging.
	 * This means that circular structures in it may exist and JSON is simply not the way to go here. */
	cb('show-packet-log-success', {result: util.inspect(this.bus.packetLog, null)});
}));

Admin.prototype.getTicksStatistics = buscomponent.provideQT('client-get-ticks-statistics', _reqpriv('userdb', function(query, ctx, cb) {
	var now = Math.floor(Date.now() / 1000);
	var todayStart = now - now % 86400;
	var ndays = parseInt(query.ndays) || 365;
	var timespanStart = todayStart - ndays * 86400;
	var dt = 300;

	ctx.query('SELECT FLOOR(time/?)*? AS timeindex, SUM(ticks) AS ticksum, COUNT(ticks) AS tickcount ' +
		'FROM tickshistory ' +
		'GROUP BY timeindex',
		[dt, dt, dt, timespanStart, todayStart], function(res) {
		cb('get-ticks-statistics-success', {results: res});
	});
}));

exports.Admin = Admin;

})();
<commit_msg><commit_after>(function () { "use strict";

var commonUtil = require('./common/util.js');
var _ = require('lodash');
var util = require('util');
var assert = require('assert');
var buscomponent = require('./stbuscomponent.js');

/**
 * Provides client requests for administrative tasks and information gathering.
 *
 * @public
 * @module admin
 */

/**
 * Main object of the {@link module:admin} module
 * @public
 * @constructor module:admin~Admin
 * @augments module:stbuscomponent~STBusComponent
 */
function Admin () {
	Admin.super_.apply(this, arguments);
}

util.inherits(Admin, buscomponent.BusComponent);

/**
 * Helper function to indicate that a client request requires admin privileges.
 *
 * @param {string} required  The required privilege level
 * @param {QTXCallback} f  A standard QTX client request handler
 *
 * @function module:admin~_reqpriv_x
 */
function _reqpriv_x (required, f) {
	var requiredPermission = required;

	return function(query, ctx, xdata, cb) {
		if (ctx.user === null || !ctx.access.has(requiredPermission))
			(cb ? cb : xdata)('permission-denied');
		else
			return _.bind(f, this)(query, ctx, xdata, cb);
	};
}

/**
 * Helper function to indicate that a client request requires admin privileges.
 *
 * @param {string} required  The required privilege level
 * @param {QTCallback} f  A standard QT client request handler
 *
 * @function module:admin~_reqpriv
 */
function _reqpriv (required, f) {
	return _reqpriv_x(required, function(query, ctx, xdata, cb) {
		return _.bind(f, this)(query, ctx, cb = xdata);
	});
}

/**
 * Returns all users and tons of information on them.
 *
 * @example
 * Example ouput:
 * [ …, {
 *  birthday: 713923200000,
 *  deletiontime: null,
 *  street: 'null',
 *  zipcode: 'null',
 *  town: 'null',
 *  desc: …,
 *  name: …,
 *  giv_name: …,
 *  fam_name: …,
 *  uid: 14,
 *  tradecount: 41,
 *  email: …,
 *  emailverif: 1,
 *  wprovision: 5,
 *  lprovision: 5,
 *  freemoney: 787240079,
 *  totalvalue: 787240064,
 *  wprov_sum: 0,
 *  lprov_sum: 0,
 *  registertime: 0,
 *  schoolpath: '/KIT',
 *  schoolid: 27,
 *  pending: 0,
 *  jointime: 0,
 *  commentcount: 7,
 *  lastcommenttime: 1403753220 }, … ]
 *
 * @return {object} Returns with list-all-users-success or a common error code
 *                  and populates .results with a
 *                  {@link module:user~UserEntryBase[]}, augmented by various data only
 *                  available to administrative users.
 *
 * @function c2s~list-all-users
 */
Admin.prototype.listAllUsers = buscomponent.provideQT('client-list-all-users', _reqpriv('userdb', function(query, ctx, cb) {
	ctx.query('SELECT birthday, deletiontime, street, zipcode, town, `desc`, users.name, giv_name, fam_name, users.id AS uid, tradecount, ' +
		'email, email_verif AS emailverif, wprovision, lprovision, freemoney, totalvalue, wprov_sum, lprov_sum, ticks, registertime, ' +
		'schools.path AS schoolpath, schools.id AS schoolid, pending, jointime, ' +
		'(SELECT COUNT(*) FROM ecomments WHERE ecomments.commenter=users.id) AS commentcount, '+
		'(SELECT MAX(time) FROM ecomments WHERE ecomments.commenter=users.id) AS lastcommenttime FROM users ' +
		'JOIN users_data ON users.id = users_data.id ' +
		'JOIN users_finance ON users.id = users_finance.id ' +
		'LEFT JOIN schoolmembers AS sm ON sm.uid = users.id ' +
		'LEFT JOIN schools ON schools.id = sm.schoolid ',
		[], function(userlist) {
		cb('list-all-users-success', {results: userlist});
	});
}));

/**
 * Shuts down the server. Not really something for the typical user.
 *
 * @return {object} Returns with shutdown-success.
 *
 * @function c2s~shutdown
 */
Admin.prototype.shutdown = buscomponent.provideQT('client-shutdown', _reqpriv('server', function(query, ctx, cb) {
	this.emit('globalShutdown');

	cb('shutdown-success');
}));

/**
 * Change the session user id.
 *
 * @param {int} query.uid  The user id to assign to the current session.
 *
 * @return {object} Returns with impersonate-user-success or
 *                  impersonate-user-notfound or a common error code.
 *
 * @function c2s~impersonate-user
 */
Admin.prototype.impersonateUser = buscomponent.provideWQT('client-impersonate-user', _reqpriv('server', function(query, ctx, cb) {
	if (parseInt(query.uid) != query.uid)
		return cb('permission-denied');

	ctx.query('SELECT COUNT(*) AS c FROM users WHERE id = ?', [parseInt(query.uid)], function(r) {
		assert.equal(r.length, 1);
		if (r[0].c == 0)
			return cb('impersonate-user-notfound', null, 'repush');

		ctx.query('UPDATE sessions SET uid = ? WHERE id = ?', [parseInt(query.uid), ctx.user.sid], function() {
			cb('impersonate-user-success', null, 'repush');
		});
	});
}));

/**
 * Removes data for a given user from the database.
 *
 * @param {int} query.uid  The numerical id of the user to be removed.
 *
 * @return {object} Returns with delete-user-self-notallowed or
 *                  delete-user-success or a common error code.
 *
 * @function c2s~delete-user
 */
Admin.prototype.deleteUser = buscomponent.provideWQT('client-delete-user', _reqpriv('userdb', function(query, ctx, cb) {
	var uid = parseInt(query.uid);
	if (uid != uid) // NaN
		return cb('format-error');

	if (ctx.user.id == uid)
		return cb('delete-user-self-notallowed');

	ctx.getConnection(function(conn, commit) {
		conn.query('START TRANSACTION', [], function() {
		conn.query('DELETE FROM sessions WHERE uid = ?', [uid], function() {
		conn.query('DELETE FROM schoolmembers WHERE uid = ?', [uid], function() {
		conn.query('UPDATE stocks SET name = CONCAT("leader:deleted", ?) WHERE leader = ?', [uid, uid], function() {
		conn.query('UPDATE users_data SET giv_name="__user_deleted__", fam_name="", birthday = NULL, ' +
			'street="", zipcode="", town="", traditye=0, `desc`="", realnamepublish = 0 WHERE id = ?', [uid], function() {
		conn.query('UPDATE users_finance SET wprovision=0, lprovision=0 WHERE id = ?', [uid], function() {
		conn.query('UPDATE users SET name = CONCAT("user_deleted", ?), email = CONCAT("deleted:", email), ' +
		'pwhash="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", deletiontime = UNIX_TIMESTAMP() WHERE id = ?', [uid, uid], function() {
			commit(function() {
				cb('delete-user-success');
			});
		});
		});
		});
		});
		});
		});
		});
	});
}));

/**
 * Change a user’s e-mail address administratively.
 *
 * @param {int} query.uid  The numerical id of the target user.
 * @param {string} query.email  The new e-mail address.
 * @param {boolean} query.emailverif  If truthy, automatically set the e-mail
 *                                    address to being verified.
 *
 * @return {object} Returns with change-user-email-success or
 *                  a common error code.
 *
 * @function c2s~change-user
 */
Admin.prototype.changeUserEMail = buscomponent.provideWQT('client-change-user-email', _reqpriv('userdb', function(query, ctx, cb) {
	ctx.query('UPDATE users SET email = ?, email_verif = ? WHERE id = ?',
		[String(query.email), query.emailverif ? 1 : 0, parseInt(query.uid)], function() {
		cb('change-user-email-success');
	});
}));

/**
 * Change a comment’s text.
 *
 * @param {int} query.commentid  The numerical id of the target comment.
 * @param {string} query.comment The new comment text.
 * @param {boolean} query.trustedhtml  If truthy, the new text is HTML-formatted.
 *
 * @return {object} Returns with change-comment-text-success or
 *                  a common error code.
 *
 * @function c2s~change-comment-text
 */
Admin.prototype.changeCommentText = buscomponent.provideWQT('client-change-comment-text', _reqpriv('moderate', function(query, ctx, cb) {
	ctx.query('UPDATE ecomments SET comment = ?, trustedhtml = ? WHERE commentid = ?',
		[String(query.comment), ctx.access.has('server') && query.trustedhtml ? 1:0, parseInt(query.commentid)], function() {
		cb('change-comment-text-success');
	});
}));

/**
 * Remove the sticky flag from all notifications.
 *
 * @return {object} Returns with notify-unstick-all-success or
 *                  a common error code.
 *
 * @function c2s~notify-unstick-all
 */
Admin.prototype.notifyUnstickAll = buscomponent.provideWQT('client-notify-unstick-all', _reqpriv('moderate', function(query, ctx, cb) {
	ctx.query('UPDATE mod_notif SET sticky = 0', [], function() {
		cb('notify-unstick-all-success');
	});
}));

/**
 * Inserts a message into all user feeds.
 *
 * @param {string} query.content  The message to be displayed.
 * @param {boolean} query.sticky  If truthy, display the message on top of each feed.
 *
 * @return {object} Returns with notify-all-success or
 *                  a common error code.
 *
 * @function c2s~notify-all
 */
Admin.prototype.notifyAll = buscomponent.provideWQT('client-notify-all', _reqpriv('moderate', function(query, ctx, cb) {
	ctx.query('INSERT INTO mod_notif (content, sticky) VALUES (?, ?)', [String(query.content), query.sticky ? 1 : 0], function(res) {
		ctx.feed({'type': 'mod-notification', 'targetid': res.insertId, 'srcuser': ctx.user.id, 'everyone': true});
		cb('notify-all-success');
	});
}));

/**
 * Changes a school’s name and/or path.
 * This is the proper way to change a group’s supergroup.
 *
 * @param {int} query.schoolid  The numerical id of the target school.
 * @param {string} query.schoolpath  The school’s new path.
 * @param {string} query.schoolname  The school’s new human-readable name.
 *
 * @return {object} Returns with rename-school-notfound,
 *                  rename-school-success or
 *                  a common error code.
 *
 * @function c2s~rename-school
 */
Admin.prototype.renameSchool = buscomponent.provideWQT('client-rename-school', _reqpriv('schooldb', function(query, ctx, cb) {
	ctx.query('SELECT path FROM schools WHERE id = ?', [parseInt(query.schoolid)], function(r) {
		if (r.length == 0)
			return cb('rename-school-notfound');

		ctx.query('SELECT COUNT(*) AS c FROM schools WHERE path = ?', [commonUtil.parentPath(query.schoolpath || '/')], function(pr) {
			assert.equal(pr.length, 1);
			if (pr[0].c !== (commonUtil.parentPath(query.schoolpath || '/') != '/' ? 1 : 0))
				return cb('rename-school-notfound');

			ctx.query('SELECT COUNT(*) AS c FROM schools WHERE path = ?', [String(query.schoolpath || '/')], function(er) {
				assert.equal(er.length, 1);
				if (query.schoolpath && er[0].c == 1)
					return cb('rename-school-already-exists');

				ctx.query('UPDATE schools SET name = ? WHERE id = ?', [String(query.schoolname), parseInt(query.schoolid)], function() {
					if (query.schoolpath) {
						ctx.query('UPDATE schools SET path = REPLACE(path, ?, ?) WHERE path LIKE ? OR path = ?',
							[r[0].path, String(query.schoolpath), r[0].path + '/%', r[0].path], function() {
							cb('rename-school-success');
						});
					} else {
						cb('rename-school-success');
					}
				});
			});
		});
	});
}));

/**
 * Merges two schools into a large school.
 * These schools need to have the same parent school.
 *
 * @param {int} query.masterschool  The numerical id of the target school.
 * @param {int} query.subschool  The numerical id of the source school.
 *
 * @return {object} Returns with join-schools-notfound,
 *                  join-schools-success,
 *                  join-schools-diff-parent or
 *                  a common error code.
 *
 * @function c2s~join-schools
 */
Admin.prototype.joinSchools = buscomponent.provideWQT('client-join-schools', _reqpriv('schooldb', function(query, ctx, cb) {
	ctx.query('SELECT path FROM schools WHERE id = ?', [parseInt(query.masterschool)], function(mr) {
	ctx.query('SELECT path FROM schools WHERE id = ?', [parseInt(query.subschool)], function(sr) {
		assert.ok(mr.length <= 1);
		assert.ok(sr.length <= 1);

		if (sr.length == 0 || ((mr.length == 0 || mr[0].path == sr[0].path) && query.masterschool != null))
			return cb('join-schools-notfound');
		if (mr.length > 0 && commonUtil.parentPath(mr[0].path) != commonUtil.parentPath(sr[0].path))
			return cb('join-schools-diff-parent');

		ctx.query('UPDATE schoolmembers SET schoolid = ? WHERE schoolid = ?', [parseInt(query.masterschool), parseInt(query.subschool)], function() {
		ctx.query('DELETE FROM schooladmins WHERE schoolid = ?', [parseInt(query.subschool)], function() {
			ctx.query('DELETE FROM schools WHERE id = ?', [parseInt(query.subschool)], function() {
				cb('join-schools-success');
			});
		});
		});
	});
	});
}));

/**
 * Return all current followers of a given leader account.
 *
 * @param {int} query.uid  The numerical user id of the leader.
 *
 * @return {object} Returns with get-followers-success
 *                  a common error code and, in case of success, sets
 *                  .results accordingly.
 *
 * @function c2s~get-followers
 */
Admin.prototype.getFollowers = buscomponent.provideQT('client-get-followers', _reqpriv('userdb', function(query, ctx, cb) {
	ctx.query('SELECT u.name, u.id, ds.* ' +
		'FROM stocks AS s ' +
		'JOIN depot_stocks AS ds ON ds.stockid = s.id ' +
		'JOIN users AS u ON ds.userid = u.id ' +
		'WHERE s.leader = ?', [parseInt(query.uid)], function(res) {

		cb('get-followers-success', {results: res});
	});
}));

/**
 * Return various server statistics information.
 *
 * @return {object} Returns with get-server-statistics-success or
 *                  a common error code and, in case of success, sets
 *                  .servers to an array of results of
 *                  calls to {@link busreq~internal-get-server-statistics}.
 *
 * @function c2s~get-server-statistics
 */
Admin.prototype.getServerStatistics = buscomponent.provideQT('client-get-server-statistics', _reqpriv('userdb', function(query, ctx, cb) {
	this.requestGlobal({name: 'internal-get-server-statistics'}, function(replies) {
		cb('get-server-statistics-success', {servers: replies});
	});
}));

/**
 * Returns the local bus’ packet log.
 *
 * @return {object} Returns with show-packet-log-success or
 *                  a common error code and, in case of success, sets
 *                  .result to a util.inspect
 *                  version of the bus’ packet log.
 *
 * @function c2s~show-packet-log
 */
Admin.prototype.showPacketLog = buscomponent.provideQT('client-show-packet-log', _reqpriv('userdb', function(query, ctx, cb) {
	/* The package log is mostly informal and not expected to be used for anything but debugging.
	 * This means that circular structures in it may exist and JSON is simply not the way to go here. */
	cb('show-packet-log-success', {result: util.inspect(this.bus.packetLog, null)});
}));

/**
 * Returns game usage statistics.
 *
 * This is likely to be subjected to larger modifications due to #270.
 *
 * @return {object} Returns with get-ticks-statistics or
 *                  a common error code and, in case of success, sets
 *                  .results appropiately.
 *
 * @function c2s~get-ticks-statistics
 */
Admin.prototype.getTicksStatistics = buscomponent.provideQT('client-get-ticks-statistics', _reqpriv('userdb', function(query, ctx, cb) {
	var now = Math.floor(Date.now() / 1000);
	var todayStart = now - now % 86400;
	var ndays = parseInt(query.ndays) || 365;
	var timespanStart = todayStart - ndays * 86400;
	var dt = 300;

	ctx.query('SELECT FLOOR(time/?)*? AS timeindex, SUM(ticks) AS ticksum, COUNT(ticks) AS tickcount ' +
		'FROM tickshistory ' +
		'GROUP BY timeindex',
		[dt, dt, dt, timespanStart, todayStart], function(res) {
		cb('get-ticks-statistics-success', {results: res});
	});
}));

exports.Admin = Admin;

})();
<|endoftext|>


<commit_before>(function () { "use strict";

var _ = require('underscore');
var util = require('util');
var assert = require('assert');

function AdminDB (db, config) {
	this.db = db;
	this.cfg = config;
}
util.inherits(AdminDB, require('./objects.js').DBSubsystemBase);

function _reqpriv (required, f) {
	var requiredPermission = required;
	return function(query, user, access, cb) {
		if (user === null || !access.has(requiredPermission))
			cb('not-logged-in')
		else
			return _.bind(f,this)(query, user, access, cb);
	};
}

AdminDB.prototype.listAllUsers = _reqpriv('userdb', function(query, user, access, cb) {
	this.query('SELECT birthday, deletiontime, street, zipcode, town, `desc`, giv_name, fam_name, users.id AS uid, tradecount, ' +
		'email, email_verif AS emailverif, wprovision, lprovision, freemoney, totalvalue, wprov_sum, lprov_sum, ticks, ' +
		'logins.logintime AS lastlogintime, schools.name AS schoolname, schools.id AS schoolid FROM users ' +
		'LEFT JOIN schools ON schools.id = users.school ' +
		'LEFT JOIN logins ON logins.id = (SELECT id FROM logins AS l WHERE l.uid = users.id ORDER BY logintime DESC LIMIT 1)', [], function(userlist)
	{
		cb('list-all-users-success', userlist);
	});
});

AdminDB.prototype.impersonateUser = _reqpriv('server', function(query, user, access, cb) {
	this.query('SELECT COUNT(*) AS c FROM users WHERE id=?', [query.userid], function(r) {
		assert.equal(r.length, 1);
		if (r[0].c == 0)
			return cb('impersonate-user-notfound');

		this.query('UPDATE sessions SET uid = ? WHERE id = ?', [query.userid, user.sid], function() {
			cb('impersonate-user-success');
		});
	});
});

AdminDB.prototype.deleteUser = _reqpriv('userdb', function(query, user, access, cb_) {
	if (user.id == query.uid)
		return cb_('delete-user-self-notallowed');

	this.locked(['userdb'], cb_, function(cb) {
		this.query('DELETE FROM sessions WHERE uid = ?', [query.uid], function() {
		this.query('UPDATE stocks SET name = CONCAT("leader:deleted", ?) WHERE leader = ?', [query.uid, query.uid], function() {
		this.query('UPDATE users SET name = CONCAT("user_deleted", ?), giv_name="__user_deleted__", email = CONCAT("deleted:", email), ' +
		'fam_name="", pwhash="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", birthday=NULL, school=NULL, realnamepublish=0, `desc`="", wprovision=0, lprovision=0, ' +
		'street="", zipcode="", town="", traderse=0, tradersp=0, traditye=0, wot=0, deletiontime = UNIX_TIMESTAMP() WHERE id = ?', [query.uid, query.uid], function() {
			cb('delete-user-success');
		});
		});
		});
	});
});

AdminDB.prototype.changeUserEMail = _reqpriv('userdb', function(query, user, access, cb) {
	this.query('UPDATE users SET email = ?, email_verif = ? WHERE id = ?', [query.email, query.emailverif ? 1 : 0, query.uid], function() {
		cb('change-user-email-success');
	});
});

AdminDB.prototype.changeCommentText = _reqpriv('moderate', function(query, user, access, cb) {
	this.query('UPDATE ecomments SET comment = ? WHERE commentid = ?', [query.comment, query.commentid], function() {
		cb('change-comment-text-success');
	});
});

AdminDB.prototype.notifyAll = _reqpriv('moderate', function(query, user, access, cb) {
	this.query('INSERT INTO mod_notif (time, content, sticky) VALUES (UNIX_TIMESTAMP(), ?, ?)', [query.content, query.sticky], function(res) {
		this.feed({'type': 'mod-notification', 'targetid': res.insertId, 'srcuser': user.id, 'everyone': true});
		cb('notify-all-success');
	});
});

AdminDB.prototype.createSchool = _reqpriv('schooldb', function(query, user, access, cb_) {
	this.locked(['userdb'], cb_, function(cb) {
		this.query('SELECT COUNT(*) AS c FROM schools WHERE name = ?', [query.schoolname], function(r) {
			assert.equal(r.length, 1);
			if (r[0].c == 1)
				return cb('create-school-already-exists');

			this.query('INSERT INTO schools (name) VALUES(?)', [query.schoolname], function() {
				cb('create-school-success');
			});
		});
	});
});

AdminDB.prototype.renameSchool = _reqpriv('schooldb', function(query, user, access, cb) {
	this.query('UPDATE schools SET name = ? WHERE id = ?', [query.schoolname, query.schoolid], function() {
		cb('rename-school-success');
	});
});

AdminDB.prototype.joinSchools = _reqpriv('schooldb', function(query, user, access, cb_) {
	this.locked(['userdb'], cb_, function(cb) {
		this.query('UPDATE users SET school = ? WHERE school = ?', [query.masterschool, query.subschool], function() {
			this.query('DELETE FROM schools WHERE id = ?', [query.subschool], function() {
				cb('join-schools-success');
			});
		});
	});
});

exports.AdminDB = AdminDB;

})();
<commit_msg><commit_after>(function () { "use strict";

var _ = require('underscore');
var util = require('util');
var assert = require('assert');

function AdminDB (db, config) {
	this.db = db;
	this.cfg = config;
}
util.inherits(AdminDB, require('./objects.js').DBSubsystemBase);

function _reqpriv (required, f) {
	var requiredPermission = required;
	return function(query, user, access, cb) {
		if (user === null || !access.has(requiredPermission))
			cb('not-logged-in')
		else
			return _.bind(f,this)(query, user, access, cb);
	};
}

AdminDB.prototype.listAllUsers = _reqpriv('userdb', function(query, user, access, cb) {
	this.query('SELECT birthday, deletiontime, street, zipcode, town, `desc`, giv_name, fam_name, users.id AS uid, tradecount, ' +
		'email, email_verif AS emailverif, wprovision, lprovision, freemoney, totalvalue, wprov_sum, lprov_sum, ticks, ' +
		'logins.logintime AS lastlogintime, schools.name AS schoolname, schools.id AS schoolid FROM users ' +
		'LEFT JOIN schools ON schools.id = users.school ' +
		'LEFT JOIN logins ON logins.id = (SELECT id FROM logins AS l WHERE l.uid = users.id ORDER BY logintime DESC LIMIT 1)', [], function(userlist)
	{
		cb('list-all-users-success', userlist);
	});
});

AdminDB.prototype.impersonateUser = _reqpriv('server', function(query, user, access, cb) {
	this.query('SELECT COUNT(*) AS c FROM users WHERE id=?', [query.userid], function(r) {
		assert.equal(r.length, 1);
		if (r[0].c == 0)
			return cb('impersonate-user-notfound');

		this.query('UPDATE sessions SET uid = ? WHERE id = ?', [query.userid, user.sid], function() {
			cb('impersonate-user-success');
		});
	});
});

AdminDB.prototype.deleteUser = _reqpriv('userdb', function(query, user, access, cb_) {
	if (user.id == query.uid)
		return cb_('delete-user-self-notallowed');

	this.locked(['userdb'], cb_, function(cb) {
		this.query('DELETE FROM sessions WHERE uid = ?', [query.uid], function() {
		this.query('UPDATE stocks SET name = CONCAT("leader:deleted", ?) WHERE leader = ?', [query.uid, query.uid], function() {
		this.query('UPDATE users SET name = CONCAT("user_deleted", ?), giv_name="__user_deleted__", email = CONCAT("deleted:", email), ' +
		'fam_name="", pwhash="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", birthday=NULL, school=NULL, realnamepublish=0, `desc`="", wprovision=0, lprovision=0, ' +
		'street="", zipcode="", town="", traderse=0, tradersp=0, traditye=0, wot=0, deletiontime = UNIX_TIMESTAMP() WHERE id = ?', [query.uid, query.uid], function() {
			cb('delete-user-success');
		});
		});
		});
	});
});

AdminDB.prototype.changeUserEMail = _reqpriv('userdb', function(query, user, access, cb) {
	this.query('UPDATE users SET email = ?, email_verif = ? WHERE id = ?', [query.email, query.emailverif ? 1 : 0, query.uid], function() {
		cb('change-user-email-success');
	});
});

AdminDB.prototype.changeCommentText = _reqpriv('moderate', function(query, user, access, cb) {
	this.query('UPDATE ecomments SET comment = ? WHERE commentid = ?', [query.comment, query.commentid], function() {
		cb('change-comment-text-success');
	});
});

AdminDB.prototype.notifyAll = _reqpriv('moderate', function(query, user, access, cb) {
	this.query('INSERT INTO mod_notif (content, sticky) VALUES (?, ?)', [query.content, query.sticky], function(res) {
		this.feed({'type': 'mod-notification', 'targetid': res.insertId, 'srcuser': user.id, 'everyone': true});
		cb('notify-all-success');
	});
});

AdminDB.prototype.createSchool = _reqpriv('schooldb', function(query, user, access, cb_) {
	this.locked(['userdb'], cb_, function(cb) {
		this.query('SELECT COUNT(*) AS c FROM schools WHERE name = ?', [query.schoolname], function(r) {
			assert.equal(r.length, 1);
			if (r[0].c == 1)
				return cb('create-school-already-exists');

			this.query('INSERT INTO schools (name) VALUES(?)', [query.schoolname], function() {
				cb('create-school-success');
			});
		});
	});
});

AdminDB.prototype.renameSchool = _reqpriv('schooldb', function(query, user, access, cb) {
	this.query('UPDATE schools SET name = ? WHERE id = ?', [query.schoolname, query.schoolid], function() {
		cb('rename-school-success');
	});
});

AdminDB.prototype.joinSchools = _reqpriv('schooldb', function(query, user, access, cb_) {
	this.locked(['userdb'], cb_, function(cb) {
		this.query('UPDATE users SET school = ? WHERE school = ?', [query.masterschool, query.subschool], function() {
			this.query('DELETE FROM schools WHERE id = ?', [query.subschool], function() {
				cb('join-schools-success');
			});
		});
	});
});

exports.AdminDB = AdminDB;

})();
<|endoftext|>


<commit_before>const format = require('util').format;
const inspect = require('util').inspect;
const Q = require('q');
const help = require('./help.json');
const anyRegex = /.*/;
const names = ['nickname', 'username', 'hostname'];
const adminKeys = names.concat('identifiedas');
// Hostmask :: {nickname: String, username: String, hostname: String}
// Response :: tennu$Response
// Admin :: {nickname: RegExp, username: RegExp, hostname: RegExp, identifiedas: String?}

function notHasIdentifiedasProperty (admin) {
    return !admin['identifiedas'];
}

function cloneOnlyAdminKeys (object) {
    const clone = {};

    adminKeys.forEach(function (key) {
        clone[key] = object[key];
    });

    return clone;
}

module.exports =

AdminModule = {
    init: function (client, imports) {
        const isIdentifiedAs = imports.user.isIdentifiedAs;

        var admins;

        // tennu.Client! -> {nickname: String?, username: String?, hostname: String?, identifiedas: String?} -> Admin
        function regexify (admin) {
            client.notice(format('Adding admin: %j', admin));

            names.forEach(function (name) {
                if (admin[name]) {
                    admin[name] = new RegExp(admin[name], 'i');
                } else {
                    admin[name] = anyRegex;
                }
            });

            return admin;
        }

        // tennu.Client! -> [Admin] throws Error
        function initalizeAdmins () {
            const admins = client.config('admins');

            if (!Array.isArray(admins)) {
                const errormsg = '\'admins\' property in configuration must be an array';
                client.error(errormsg);
                throw new Error(errormsg);
            }

            return admins.map(cloneOnlyAdminKeys).map(regexify);
        }

        // tennu.Client! -> Hostmask -> Admin -> boolean
        function checkHostmask (hostmask, admin) {
            return names.every(function (name) {
                const result = admin[name].test(hostmask[name]);

                client.debug(format('%s: %s, %s (%s)',
                    name, hostmask[name], admin[name], result));

                return admin[name].test(hostmask[name]);
            });
        }

        // Module Initialization
        admins = initalizeAdmins();

        // Hostmask -> Promise boolean
        const isAdmin = function (hostmask) {
            return Q(admins).then(function (admins) {
                const hostmask_passed = admins.filter(function (admin) {
                    return checkHostmask(hostmask, admin);
                });

                client.debug('isAdmin info!');
                client.debug(hostmask_passed);

                if (hostmask_passed.some(notHasIdentifiedasProperty)) {
                    return true;
                }

                return (function recur () {
                    if (hostmask_passed.length === 0) {
                        return false;
                    }

                    return Q(hostmask_passed.pop())
                    .get('identifiedas')
                    .then(function (accountname) {
                        return isIdentifiedAs(hostmask.nickname, accountname)
                        .then(function (isIdentifiedAs) {
                            if (isIdentifiedAs) {
                                client.debug('nickname is identified as accountname');
                                return true;
                            } else {
                                client.debug('Recurring');
                                return recur();
                            }
                        });
                    });
                }());
            });
        };

        // (Command -> Response) -> (Command -> Response)
        const requiresAdmin = function (fn) {
            return function (command) {
                if (isAdmin(command.hostmask)) {
                    return fn(command);
                } else {
                    client.warn('Invalid admin function usage by ' + command.prefix);
                    return 'Permission denied.';
                }
            }
        };

        return {
            exports: {
                isAdmin: isAdmin,
                requiresAdmin: requiresAdmin
            },

            handlers: {
                '!join' : requiresAdmin(function (command) {
                    if (command.args[0]) {
                        client.notice(format('Joining %s - requested by %s', command.channel, command.prefix));
                        client.join(command.args.join(' '));
                    }

                }),

                '!part' : requiresAdmin(function (command) {
                    const channel;

                    if (command.args[0]) {
                        channel = command.args[0];
                    } else if (!command.isQuery) {
                        channel = command.channel;
                    } else {
                        return;
                    }

                    client.notice(format('Parting %s - requested by %s', channel, command.prefix));
                    client.part(command.args[0]);
                }),

                '!quit' : requiresAdmin(function (command) {
                    client.notice(format('Quitting network - requested by %s', command.prefix));
                    client.quit();
                })
            },

            help: help,
            commands: ['join', 'part', 'quit']
        };

        return admin_module;
    },
    name: 'admin',
    role: 'admin',
    requires: ['user']
};<commit_msg>Remove dead code.<commit_after>const format = require('util').format;
const inspect = require('util').inspect;
const Q = require('q');
const help = require('./help.json');
const anyRegex = /.*/;
const names = ['nickname', 'username', 'hostname'];
const adminKeys = names.concat('identifiedas');
// Hostmask :: {nickname: String, username: String, hostname: String}
// Response :: tennu$Response
// Admin :: {nickname: RegExp, username: RegExp, hostname: RegExp, identifiedas: String?}

function notHasIdentifiedasProperty (admin) {
    return !admin['identifiedas'];
}

function cloneOnlyAdminKeys (object) {
    const clone = {};

    adminKeys.forEach(function (key) {
        clone[key] = object[key];
    });

    return clone;
}

module.exports =

AdminModule = {
    init: function (client, imports) {
        const isIdentifiedAs = imports.user.isIdentifiedAs;

        var admins;

        // tennu.Client! -> {nickname: String?, username: String?, hostname: String?, identifiedas: String?} -> Admin
        function regexify (admin) {
            client.notice(format('Adding admin: %j', admin));

            names.forEach(function (name) {
                if (admin[name]) {
                    admin[name] = new RegExp(admin[name], 'i');
                } else {
                    admin[name] = anyRegex;
                }
            });

            return admin;
        }

        // tennu.Client! -> [Admin] throws Error
        function initalizeAdmins () {
            const admins = client.config('admins');

            if (!Array.isArray(admins)) {
                const errormsg = '\'admins\' property in configuration must be an array';
                client.error(errormsg);
                throw new Error(errormsg);
            }

            return admins.map(cloneOnlyAdminKeys).map(regexify);
        }

        // tennu.Client! -> Hostmask -> Admin -> boolean
        function checkHostmask (hostmask, admin) {
            return names.every(function (name) {
                const result = admin[name].test(hostmask[name]);

                client.debug(format('%s: %s, %s (%s)',
                    name, hostmask[name], admin[name], result));

                return admin[name].test(hostmask[name]);
            });
        }

        // Module Initialization
        admins = initalizeAdmins();

        // Hostmask -> Promise boolean
        const isAdmin = function (hostmask) {
            return Q(admins).then(function (admins) {
                const hostmask_passed = admins.filter(function (admin) {
                    return checkHostmask(hostmask, admin);
                });

                client.debug('isAdmin info!');
                client.debug(hostmask_passed);

                if (hostmask_passed.some(notHasIdentifiedasProperty)) {
                    return true;
                }

                return (function recur () {
                    if (hostmask_passed.length === 0) {
                        return false;
                    }

                    return Q(hostmask_passed.pop())
                    .get('identifiedas')
                    .then(function (accountname) {
                        return isIdentifiedAs(hostmask.nickname, accountname)
                        .then(function (isIdentifiedAs) {
                            if (isIdentifiedAs) {
                                client.debug('nickname is identified as accountname');
                                return true;
                            } else {
                                client.debug('Recurring');
                                return recur();
                            }
                        });
                    });
                }());
            });
        };

        // (Command -> Response) -> (Command -> Response)
        const requiresAdmin = function (fn) {
            return function (command) {
                if (isAdmin(command.hostmask)) {
                    return fn(command);
                } else {
                    client.warn('Invalid admin function usage by ' + command.prefix);
                    return 'Permission denied.';
                }
            }
        };

        return {
            exports: {
                isAdmin: isAdmin,
                requiresAdmin: requiresAdmin
            },

            handlers: {
                '!join' : requiresAdmin(function (command) {
                    if (command.args[0]) {
                        client.notice(format('Joining %s - requested by %s', command.channel, command.prefix));
                        client.join(command.args.join(' '));
                    }

                }),

                '!part' : requiresAdmin(function (command) {
                    const channel;

                    if (command.args[0]) {
                        channel = command.args[0];
                    } else if (!command.isQuery) {
                        channel = command.channel;
                    } else {
                        return;
                    }

                    client.notice(format('Parting %s - requested by %s', channel, command.prefix));
                    client.part(command.args[0]);
                }),

                '!quit' : requiresAdmin(function (command) {
                    client.notice(format('Quitting network - requested by %s', command.prefix));
                    client.quit();
                })
            },

            help: help,
            commands: ['join', 'part', 'quit']
        };
    },
    name: 'admin',
    role: 'admin',
    requires: ['user']
};<|endoftext|>