2015-08-18 21:27:14 +00:00
|
|
|
/* jslint node: true */
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
var msgDb = require('./database.js').dbs.message;
|
2015-08-20 22:35:04 +00:00
|
|
|
var Config = require('./config.js').config;
|
2015-09-06 21:58:58 +00:00
|
|
|
var Message = require('./message.js');
|
2016-01-04 00:47:39 +00:00
|
|
|
var Log = require('./logger.js').log;
|
2015-08-18 21:27:14 +00:00
|
|
|
|
|
|
|
var async = require('async');
|
|
|
|
var _ = require('lodash');
|
|
|
|
var assert = require('assert');
|
|
|
|
|
|
|
|
exports.getAvailableMessageAreas = getAvailableMessageAreas;
|
2015-09-26 06:20:17 +00:00
|
|
|
exports.getDefaultMessageArea = getDefaultMessageArea;
|
2015-08-21 04:51:00 +00:00
|
|
|
exports.getMessageAreaByName = getMessageAreaByName;
|
2015-08-20 22:35:04 +00:00
|
|
|
exports.changeMessageArea = changeMessageArea;
|
2015-08-28 04:20:24 +00:00
|
|
|
exports.getMessageListForArea = getMessageListForArea;
|
2015-12-31 05:29:10 +00:00
|
|
|
exports.getNewMessagesInAreaForUser = getNewMessagesInAreaForUser;
|
2015-10-22 21:44:44 +00:00
|
|
|
exports.getMessageAreaLastReadId = getMessageAreaLastReadId;
|
|
|
|
exports.updateMessageAreaLastReadId = updateMessageAreaLastReadId;
|
2015-08-18 21:27:14 +00:00
|
|
|
|
2015-10-18 03:39:54 +00:00
|
|
|
function getAvailableMessageAreas(options) {
|
2015-09-04 06:02:28 +00:00
|
|
|
// example: [ { "name" : "local_music", "desc" : "Music Discussion", "groups" : ["somegroup"] }, ... ]
|
2015-10-18 03:39:54 +00:00
|
|
|
options = options || {};
|
|
|
|
|
|
|
|
var areas = Config.messages.areas;
|
|
|
|
var avail = [];
|
|
|
|
for(var i = 0; i < areas.length; ++i) {
|
|
|
|
if(true !== options.includePrivate &&
|
|
|
|
Message.WellKnownAreaNames.Private === areas[i].name)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
avail.push(areas[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return avail;
|
2015-08-20 22:35:04 +00:00
|
|
|
}
|
|
|
|
|
2015-09-26 06:20:17 +00:00
|
|
|
function getDefaultMessageArea() {
|
2015-10-18 02:03:51 +00:00
|
|
|
//
|
|
|
|
// Return first non-private/etc. area name. This will be from config.hjson
|
|
|
|
//
|
2015-10-18 03:39:54 +00:00
|
|
|
return getAvailableMessageAreas()[0];
|
|
|
|
/*
|
2015-10-18 02:03:51 +00:00
|
|
|
var avail = getAvailableMessageAreas();
|
|
|
|
for(var i = 0; i < avail.length; ++i) {
|
|
|
|
if(Message.WellKnownAreaNames.Private !== avail[i].name) {
|
|
|
|
return avail[i];
|
|
|
|
}
|
|
|
|
}
|
2015-10-18 03:39:54 +00:00
|
|
|
*/
|
2015-09-26 06:20:17 +00:00
|
|
|
}
|
|
|
|
|
2015-08-21 04:51:00 +00:00
|
|
|
function getMessageAreaByName(areaName) {
|
|
|
|
areaName = areaName.toLowerCase();
|
|
|
|
|
2015-10-19 03:24:13 +00:00
|
|
|
var availAreas = getAvailableMessageAreas( { includePrivate : true } );
|
2015-08-21 04:51:00 +00:00
|
|
|
var index = _.findIndex(availAreas, function pred(an) {
|
|
|
|
return an.name == areaName;
|
|
|
|
});
|
|
|
|
|
|
|
|
if(index > -1) {
|
|
|
|
return availAreas[index];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-20 22:35:04 +00:00
|
|
|
function changeMessageArea(client, areaName, cb) {
|
|
|
|
|
|
|
|
async.waterfall(
|
|
|
|
[
|
|
|
|
function getArea(callback) {
|
2015-08-21 04:51:00 +00:00
|
|
|
var area = getMessageAreaByName(areaName);
|
2015-08-27 05:25:49 +00:00
|
|
|
|
2015-08-21 04:51:00 +00:00
|
|
|
if(area) {
|
|
|
|
callback(null, area);
|
|
|
|
} else {
|
|
|
|
callback(new Error('Invalid message area'));
|
|
|
|
}
|
2015-08-20 22:35:04 +00:00
|
|
|
},
|
|
|
|
function validateAccess(area, callback) {
|
2015-11-05 06:04:55 +00:00
|
|
|
if(_.isArray(area.groups) && !
|
|
|
|
client.user.isGroupMember(area.groups))
|
|
|
|
{
|
|
|
|
callback(new Error('User does not have access to this area'));
|
|
|
|
} else {
|
|
|
|
callback(null, area);
|
|
|
|
}
|
2015-08-20 22:35:04 +00:00
|
|
|
},
|
|
|
|
function changeArea(area, callback) {
|
2015-08-21 04:51:00 +00:00
|
|
|
client.user.persistProperty('message_area_name', area.name, function persisted(err) {
|
2015-08-20 22:35:04 +00:00
|
|
|
callback(err, area);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
],
|
|
|
|
function complete(err, area) {
|
|
|
|
if(!err) {
|
|
|
|
client.log.info( area, 'Current message area changed');
|
|
|
|
} else {
|
|
|
|
client.log.warn( { area : area, error : err.message }, 'Could not change message area');
|
|
|
|
}
|
|
|
|
|
|
|
|
cb(err);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
2015-08-27 05:25:49 +00:00
|
|
|
|
2016-01-04 00:47:39 +00:00
|
|
|
function getMessageFromRow(row) {
|
|
|
|
return {
|
|
|
|
messageId : row.message_id,
|
|
|
|
messageUuid : row.message_uuid,
|
|
|
|
replyToMsgId : row.reply_to_message_id,
|
|
|
|
toUserName : row.to_user_name,
|
|
|
|
fromUserName : row.from_user_name,
|
|
|
|
subject : row.subject,
|
|
|
|
modTimestamp : row.modified_timestamp,
|
|
|
|
viewCount : row.view_count,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-12-31 05:29:10 +00:00
|
|
|
function getNewMessagesInAreaForUser(userId, areaName, cb) {
|
|
|
|
//
|
|
|
|
// If |areaName| is Message.WellKnownAreaNames.Private,
|
|
|
|
// only messages addressed to |userId| should be returned.
|
|
|
|
//
|
|
|
|
// Only messages > lastMessageId should be returned
|
|
|
|
//
|
|
|
|
var msgList = [];
|
|
|
|
|
|
|
|
async.waterfall(
|
|
|
|
[
|
|
|
|
function getLastMessageId(callback) {
|
|
|
|
getMessageAreaLastReadId(userId, areaName, function fetched(err, lastMessageId) {
|
|
|
|
callback(null, lastMessageId || 0); // note: willingly ignoring any errors here!
|
|
|
|
});
|
|
|
|
},
|
|
|
|
function getMessages(lastMessageId, callback) {
|
|
|
|
var sql =
|
|
|
|
'SELECT message_id, message_uuid, reply_to_message_id, to_user_name, from_user_name, subject, modified_timestamp, view_count ' +
|
|
|
|
'FROM message ' +
|
|
|
|
'WHERE area_name="' + areaName + '" AND message_id > ' + lastMessageId;
|
|
|
|
|
|
|
|
if(Message.WellKnownAreaNames.Private === areaName) {
|
|
|
|
sql +=
|
|
|
|
' AND message_id in (' +
|
|
|
|
'SELECT message_id from message_meta where meta_category=' + Message.MetaCategories.System +
|
|
|
|
' AND meta_name="' + Message.SystemMetaNames.LocalToUserID + '" and meta_value=' + userId + ')';
|
|
|
|
}
|
|
|
|
|
|
|
|
sql += ' ORDER BY message_id;';
|
2016-01-04 00:47:39 +00:00
|
|
|
|
|
|
|
console.log(sql)
|
2015-12-31 05:29:10 +00:00
|
|
|
|
|
|
|
msgDb.each(sql, function msgRow(err, row) {
|
|
|
|
if(!err) {
|
2016-01-04 00:47:39 +00:00
|
|
|
msgList.push(getMessageFromRow(row));
|
2015-12-31 05:29:10 +00:00
|
|
|
}
|
|
|
|
}, callback);
|
|
|
|
}
|
|
|
|
],
|
|
|
|
function complete(err) {
|
|
|
|
console.log(msgList)
|
|
|
|
cb(err, msgList);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2015-08-27 05:25:49 +00:00
|
|
|
function getMessageListForArea(options, areaName, cb) {
|
|
|
|
//
|
|
|
|
// options.client (required)
|
|
|
|
//
|
|
|
|
|
2015-09-04 22:17:41 +00:00
|
|
|
options.client.log.debug( { areaName : areaName }, 'Fetching available messages');
|
|
|
|
|
2015-08-27 05:25:49 +00:00
|
|
|
assert(_.isObject(options.client));
|
|
|
|
|
|
|
|
/*
|
|
|
|
[
|
|
|
|
{
|
|
|
|
messageId, messageUuid, replyToId, toUserName, fromUserName, subject, modTimestamp,
|
|
|
|
status(new|old),
|
|
|
|
viewCount
|
|
|
|
}
|
|
|
|
]
|
|
|
|
*/
|
|
|
|
|
|
|
|
var msgList = [];
|
|
|
|
|
|
|
|
async.series(
|
|
|
|
[
|
|
|
|
function fetchMessages(callback) {
|
|
|
|
msgDb.each(
|
2015-08-27 22:14:56 +00:00
|
|
|
'SELECT message_id, message_uuid, reply_to_message_id, to_user_name, from_user_name, subject, modified_timestamp, view_count ' +
|
|
|
|
'FROM message ' +
|
|
|
|
'WHERE area_name=? ' +
|
2015-08-27 05:25:49 +00:00
|
|
|
'ORDER BY message_id;',
|
|
|
|
[ areaName.toLowerCase() ],
|
|
|
|
function msgRow(err, row) {
|
|
|
|
if(!err) {
|
2016-01-04 00:47:39 +00:00
|
|
|
msgList.push(getMessageFromRow(row));
|
2015-08-27 05:25:49 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
callback
|
|
|
|
);
|
2015-08-28 04:20:24 +00:00
|
|
|
},
|
|
|
|
function fetchStatus(callback) {
|
|
|
|
callback(null);// :TODO: fixmeh.
|
2015-08-27 05:25:49 +00:00
|
|
|
}
|
2015-08-28 04:20:24 +00:00
|
|
|
],
|
|
|
|
function complete(err) {
|
|
|
|
cb(err, msgList);
|
|
|
|
}
|
2015-08-27 05:25:49 +00:00
|
|
|
);
|
|
|
|
}
|
2015-09-06 21:58:58 +00:00
|
|
|
|
2015-10-22 21:44:44 +00:00
|
|
|
function getMessageAreaLastReadId(userId, areaName, cb) {
|
|
|
|
msgDb.get(
|
|
|
|
'SELECT message_id ' +
|
|
|
|
'FROM user_message_area_last_read ' +
|
|
|
|
'WHERE user_id = ? AND area_name = ?;',
|
|
|
|
[ userId, areaName ],
|
2016-01-04 00:47:39 +00:00
|
|
|
function complete(err, row) {
|
|
|
|
cb(err, row ? row.message_id : 0);
|
|
|
|
}
|
2015-10-22 21:44:44 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-01-04 00:47:39 +00:00
|
|
|
function updateMessageAreaLastReadId(userId, areaName, messageId, cb) {
|
2015-10-22 21:44:44 +00:00
|
|
|
// :TODO: likely a better way to do this...
|
|
|
|
async.waterfall(
|
|
|
|
[
|
|
|
|
function getCurrent(callback) {
|
|
|
|
getMessageAreaLastReadId(userId, areaName, function result(err, lastId) {
|
|
|
|
lastId = lastId || 0;
|
|
|
|
callback(null, lastId); // ignore errors as we default to 0
|
|
|
|
});
|
|
|
|
},
|
|
|
|
function update(lastId, callback) {
|
|
|
|
if(messageId > lastId) {
|
|
|
|
msgDb.run(
|
|
|
|
'REPLACE INTO user_message_area_last_read (user_id, area_name, message_id) ' +
|
|
|
|
'VALUES (?, ?, ?);',
|
2016-01-04 00:47:39 +00:00
|
|
|
[ userId, areaName, messageId ],
|
|
|
|
callback
|
2015-10-22 21:44:44 +00:00
|
|
|
);
|
2016-01-04 00:47:39 +00:00
|
|
|
} else {
|
|
|
|
callback(null);
|
2015-10-22 21:44:44 +00:00
|
|
|
}
|
|
|
|
}
|
2016-01-04 00:47:39 +00:00
|
|
|
],
|
|
|
|
function complete(err) {
|
|
|
|
if(err) {
|
|
|
|
Log.debug(
|
|
|
|
{ error : err.toString(), userId : userId, areaName : areaName, messageId : messageId },
|
|
|
|
'Failed updating area last read ID');
|
|
|
|
} else {
|
|
|
|
Log.trace(
|
|
|
|
{ userId : userId, areaName : areaName, messageId : messageId },
|
|
|
|
'Area last read ID updated');
|
|
|
|
}
|
|
|
|
cb(err);
|
|
|
|
}
|
2015-10-22 21:44:44 +00:00
|
|
|
);
|
|
|
|
}
|