mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-06-26 14:31:22 +02:00
Merge commit 'aca0a893e7ab52003e016eec382ea3f0d3610ba7' into weekly
This commit is contained in:
10
.travis.yml
10
.travis.yml
@@ -5,13 +5,15 @@ before_install:
|
||||
- "echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list"
|
||||
- "sudo apt-get update"
|
||||
- "sudo apt-get install mongodb-org-server"
|
||||
- npm i --production
|
||||
- node app --setup="{\"url\":\"http://127.0.0.1:4567/\",\"secret\":\"abcdef\",\"database\":\"mongo\",\"mongo:host\":\"127.0.0.1\",\"mongo:port\":27017,\"mongo:username\":\"\",\"mongo:password\":\"\",\"mongo:database\":0,\"redis:host\":\"127.0.0.1\",\"redis:port\":6379,\"redis:password\":\"\",\"redis:database\":0,\"admin:username\":\"admin\",\"admin:email\":\"test@example.org\",\"admin:password\":\"abcdef\",\"admin:password:confirm\":\"abcdef\"}" --ci="{\"host\":\"127.0.0.1\",\"port\":27017,\"database\":0}"
|
||||
before_script:
|
||||
- "npm i --production"
|
||||
- sh -c "if [ '$DB' = 'mongodb' ]; then node app --setup=\"{\\\"url\\\":\\\"http://127.0.0.1:4567/\\\",\\\"secret\\\":\\\"abcdef\\\",\\\"database\\\":\\\"mongo\\\",\\\"mongo:host\\\":\\\"127.0.0.1\\\",\\\"mongo:port\\\":27017,\\\"mongo:username\\\":\\\"\\\",\\\"mongo:password\\\":\\\"\\\",\\\"mongo:database\\\":0,\\\"redis:host\\\":\\\"127.0.0.1\\\",\\\"redis:port\\\":6379,\\\"redis:password\\\":\\\"\\\",\\\"redis:database\\\":0,\\\"admin:username\\\":\\\"admin\\\",\\\"admin:email\\\":\\\"test@example.org\\\",\\\"admin:password\\\":\\\"abcdef\\\",\\\"admin:password:confirm\\\":\\\"abcdef\\\"}\" --ci=\"{\\\"host\\\":\\\"127.0.0.1\\\",\\\"port\\\":27017,\\\"database\\\":0}\"; fi"
|
||||
- sh -c "if [ '$DB' = 'redis' ]; then node app --setup=\"{\\\"url\\\":\\\"http://127.0.0.1:4567/\\\",\\\"secret\\\":\\\"abcdef\\\",\\\"database\\\":\\\"redis\\\",\\\"mongo:host\\\":\\\"127.0.0.1\\\",\\\"mongo:port\\\":27017,\\\"mongo:username\\\":\\\"\\\",\\\"mongo:password\\\":\\\"\\\",\\\"mongo:database\\\":0,\\\"redis:host\\\":\\\"127.0.0.1\\\",\\\"redis:port\\\":6379,\\\"redis:password\\\":\\\"\\\",\\\"redis:database\\\":0,\\\"admin:username\\\":\\\"admin\\\",\\\"admin:email\\\":\\\"test@example.org\\\",\\\"admin:password\\\":\\\"abcdef\\\",\\\"admin:password:confirm\\\":\\\"abcdef\\\"}\" --ci=\"{\\\"host\\\":\\\"127.0.0.1\\\",\\\"port\\\":6379,\\\"database\\\":0}\"; fi"
|
||||
before_script:
|
||||
- "until nc -z localhost 27017; do echo Waiting for MongoDB; sleep 1; done"
|
||||
language: node_js
|
||||
env:
|
||||
- CXX=g++-4.8
|
||||
- CXX=g++-4.8 DB=mongodb
|
||||
- CXX=g++-4.8 DB=redis
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "nodebb",
|
||||
"license": "GPL-3.0",
|
||||
"description": "NodeBB Forum",
|
||||
"version": "1.1.3-auto.6",
|
||||
"version": "1.2.0",
|
||||
"homepage": "http://www.nodebb.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -61,8 +61,8 @@
|
||||
"nodebb-plugin-spam-be-gone": "0.4.10",
|
||||
"nodebb-rewards-essentials": "0.0.9",
|
||||
"nodebb-theme-lavender": "3.0.14",
|
||||
"nodebb-theme-persona": "4.1.50",
|
||||
"nodebb-theme-vanilla": "5.1.33",
|
||||
"nodebb-theme-persona": "4.1.56",
|
||||
"nodebb-theme-vanilla": "5.1.37",
|
||||
"nodebb-widget-essentials": "2.0.11",
|
||||
"nodemailer": "2.0.0",
|
||||
"nodemailer-sendmail-transport": "1.0.0",
|
||||
@@ -81,7 +81,7 @@
|
||||
"sitemap": "^1.4.0",
|
||||
"socket.io": "^1.4.8",
|
||||
"socket.io-client": "^1.4.0",
|
||||
"socket.io-redis": "^1.0.0",
|
||||
"socket.io-redis": "1.1.1",
|
||||
"socketio-wildcard": "~0.3.0",
|
||||
"string": "^3.0.0",
|
||||
"templates.js": "0.3.4",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"tags": "Tags",
|
||||
"tag": "Topics tagged under \"%1\"",
|
||||
"register": "Register an account",
|
||||
"registration-complete": "Registration complete",
|
||||
"login": "Login to your account",
|
||||
"reset": "Reset your account password",
|
||||
"categories": "Categories",
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
"ignore": "관심 해제",
|
||||
"watching": "Watching",
|
||||
"ignoring": "Ignoring",
|
||||
"watching.description": "Show topics in unread",
|
||||
"ignoring.description": "Do not show topics in unread",
|
||||
"watching.description": "읽지 않은 주제를 표시합니다",
|
||||
"ignoring.description": "읽지 않은 주제를 표시하지 않습니다",
|
||||
"watch.message": "이 카테고리에 올라오는 글을 주시하고 있습니다.",
|
||||
"ignore.message": "이 카테고리에 올라오는 글을 무시합니다.",
|
||||
"watched-categories": "관심 카테고리"
|
||||
|
||||
@@ -319,7 +319,7 @@ define('admin/manage/users', ['admin/modules/selectable', 'translator'], functio
|
||||
}
|
||||
|
||||
templates.parse('admin/manage/users', 'users', data, function(html) {
|
||||
$('#users-container').html(html);
|
||||
$('#users-container').html(html).find('.timeago').timeago();
|
||||
|
||||
$('.fa-spinner').addClass('hidden');
|
||||
|
||||
|
||||
@@ -85,13 +85,19 @@ app.cacheBuster = null;
|
||||
};
|
||||
|
||||
app.logout = function() {
|
||||
$(window).trigger('action:app.logout');
|
||||
$.ajax(config.relative_path + '/logout', {
|
||||
type: 'POST',
|
||||
headers: {
|
||||
'x-csrf-token': config.csrf_token
|
||||
},
|
||||
success: function() {
|
||||
window.location.href = config.relative_path + '/';
|
||||
var payload = {
|
||||
next: config.relative_path + '/'
|
||||
};
|
||||
|
||||
$(window).trigger('action:app.loggedOut', payload);
|
||||
window.location.href = payload.next;
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -260,7 +266,7 @@ app.cacheBuster = null;
|
||||
}
|
||||
};
|
||||
|
||||
app.openChat = function (roomId) {
|
||||
app.openChat = function (roomId, uid) {
|
||||
if (!app.user.uid) {
|
||||
return app.alertError('[[error:not-logged-in]]');
|
||||
}
|
||||
@@ -275,13 +281,14 @@ app.cacheBuster = null;
|
||||
if (chat.modalExists(roomId)) {
|
||||
loadAndCenter(chat.getModal(roomId));
|
||||
} else {
|
||||
socket.emit('modules.chats.loadRoom', {roomId: roomId}, function(err, roomData) {
|
||||
socket.emit('modules.chats.loadRoom', {roomId: roomId, uid: uid || app.user.uid}, function(err, roomData) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
roomData.users = roomData.users.filter(function(user) {
|
||||
return user && parseInt(user.uid, 10) !== parseInt(app.user.uid, 10);
|
||||
});
|
||||
roomData.uid = uid || app.user.uid;
|
||||
chat.createModal(roomData, loadAndCenter);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ define('forum/account/edit', ['forum/account/header', 'uploader', 'translator',
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
updateHeader(type === 'default' ? '' : src);
|
||||
updateHeader(type === 'default' ? '' : modal.find('.list-group-item.active img').attr('src'));
|
||||
ajaxify.refresh();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -62,12 +62,12 @@ define('forum/chats', [
|
||||
var roomId = ajaxify.data.roomId;
|
||||
|
||||
if (app.previousUrl && app.previousUrl.match(/chats/)) {
|
||||
ajaxify.go('chats', function() {
|
||||
app.openChat(roomId);
|
||||
ajaxify.go('user/' + ajaxify.data.userslug + '/chats', function() {
|
||||
app.openChat(roomId, ajaxify.data.uid);
|
||||
}, true);
|
||||
} else {
|
||||
window.history.go(-1);
|
||||
app.openChat(roomId);
|
||||
app.openChat(roomId, ajaxify.data.uid);
|
||||
}
|
||||
|
||||
$(window).one('action:chat.loaded', function() {
|
||||
@@ -79,7 +79,6 @@ define('forum/chats', [
|
||||
|
||||
recentChats.init();
|
||||
|
||||
Chats.addSinceHandler(ajaxify.data.roomId, $('.expanded-chat .chat-content'), $('.expanded-chat [data-since]'));
|
||||
Chats.addRenameHandler(ajaxify.data.roomId, $('[component="chat/room/name"]'));
|
||||
Chats.addScrollHandler(ajaxify.data.roomId, ajaxify.data.uid, $('.chat-content'));
|
||||
};
|
||||
@@ -96,12 +95,14 @@ define('forum/chats', [
|
||||
return;
|
||||
}
|
||||
loading = true;
|
||||
|
||||
socket.emit('modules.chats.getMessages', {roomId: roomId, uid: uid, start: $('.chat-content').children('[data-index]').first().attr('data-index')}, function(err, data) {
|
||||
var start = parseInt($('.chat-content').children('[data-index]').first().attr('data-index'), 10) + 1;
|
||||
socket.emit('modules.chats.getMessages', {roomId: roomId, uid: uid, start: start}, function(err, data) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
messages.parseMessage(data, function(html) {
|
||||
var currentScrollTop = el.scrollTop();
|
||||
var previousHeight = el[0].scrollHeight;
|
||||
@@ -156,16 +157,6 @@ define('forum/chats', [
|
||||
});
|
||||
};
|
||||
|
||||
Chats.addSinceHandler = function(roomId, chatContentEl, sinceEl) {
|
||||
sinceEl.on('click', function() {
|
||||
var since = $(this).attr('data-since');
|
||||
sinceEl.removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
Chats.loadChatSince(roomId, chatContentEl, since);
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
Chats.addRenameHandler = function(roomId, inputEl) {
|
||||
var oldName = inputEl.val();
|
||||
inputEl.on('blur keypress', function(ev) {
|
||||
@@ -290,7 +281,7 @@ define('forum/chats', [
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
if (parseInt(roomId, 10) === ajaxify.data.roomId) {
|
||||
ajaxify.go('chats');
|
||||
ajaxify.go('user/' + ajaxify.data.userslug + '/chats');
|
||||
} else {
|
||||
el.remove();
|
||||
}
|
||||
@@ -301,21 +292,6 @@ define('forum/chats', [
|
||||
ajaxify.go('user/' + ajaxify.data.userslug + '/chats/' + roomid);
|
||||
};
|
||||
|
||||
Chats.loadChatSince = function(roomId, chatContentEl, since) {
|
||||
if (!roomId) {
|
||||
return;
|
||||
}
|
||||
socket.emit('modules.chats.get', {roomId: roomId, since: since}, function(err, messageData) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
chatContentEl.find('[component="chat/message"]').remove();
|
||||
|
||||
messages.appendChatMessage(chatContentEl, messageData);
|
||||
});
|
||||
};
|
||||
|
||||
Chats.addGlobalEventListeners = function() {
|
||||
$(window).on('resize', Chats.resizeMainWindow);
|
||||
$(window).on('mousemove keypress click', function() {
|
||||
|
||||
@@ -75,7 +75,7 @@ define('forum/chats/search', ['components'], function(components) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
if (roomId) {
|
||||
ajaxify.go('chats/' + roomId);
|
||||
Chats.switchChat(roomId);
|
||||
} else {
|
||||
app.newChat(userObj.uid);
|
||||
}
|
||||
@@ -84,4 +84,4 @@ define('forum/chats/search', ['components'], function(components) {
|
||||
}
|
||||
|
||||
return search;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,8 +26,11 @@ define('chat', [
|
||||
module.loadChatsDropdown(chatsListEl);
|
||||
});
|
||||
|
||||
chatsListEl.on('click', '[data-roomid]', function() {
|
||||
var roomId = this.getAttribute('data-roomid');
|
||||
chatsListEl.on('click', '[data-roomid]', function(ev) {
|
||||
if ($(ev.target).parents('.user-link').length) {
|
||||
return;
|
||||
}
|
||||
var roomId = $(this).attr('data-roomid');
|
||||
if (!ajaxify.currentPage.match(/^chats\//)) {
|
||||
app.openChat(roomId);
|
||||
} else {
|
||||
@@ -80,6 +83,7 @@ define('chat', [
|
||||
return user && parseInt(user.uid, 10) !== parseInt(app.user.uid, 10);
|
||||
});
|
||||
roomData.silent = true;
|
||||
roomData.uid = app.user.uid;
|
||||
module.createModal(roomData, function(modal) {
|
||||
module.toggleNew(modal.attr('UUID'), !isSelf, true);
|
||||
if (!isSelf) {
|
||||
@@ -150,134 +154,117 @@ define('chat', [
|
||||
return $('#chat-modal-' + roomId).length !== 0;
|
||||
};
|
||||
|
||||
function checkStatus(chatModal) {
|
||||
socket.emit('user.checkStatus', chatModal.attr('touid'), function(err, status) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
module.createModal = function(data, callback) {
|
||||
app.parseAndTranslate('chat', data, function(chatModal) {
|
||||
|
||||
var uuid = utils.generateUUID();
|
||||
var dragged = false;
|
||||
|
||||
chatModal.attr('id', 'chat-modal-' + data.roomId);
|
||||
chatModal.attr('roomId', data.roomId);
|
||||
chatModal.attr('intervalId', 0);
|
||||
chatModal.attr('UUID', uuid);
|
||||
chatModal.css('position', 'fixed');
|
||||
chatModal.css('zIndex', 100);
|
||||
chatModal.appendTo($('body'));
|
||||
chatModal.find('.timeago').timeago();
|
||||
module.center(chatModal);
|
||||
|
||||
app.loadJQueryUI(function() {
|
||||
chatModal.find('.modal-content').resizable({
|
||||
handles: 'n, e, s, w, se',
|
||||
minHeight: 250,
|
||||
minWidth: 400
|
||||
});
|
||||
|
||||
chatModal.find('.modal-content').on('resize', function(event, ui) {
|
||||
if (ui.originalSize.height === ui.size.height) {
|
||||
return;
|
||||
}
|
||||
|
||||
chatModal.find('.chat-content').css('height', module.calculateChatListHeight(chatModal));
|
||||
});
|
||||
|
||||
chatModal.draggable({
|
||||
start:function() {
|
||||
module.bringModalToTop(chatModal);
|
||||
},
|
||||
stop:function() {
|
||||
chatModal.find('#chat-message-input').focus();
|
||||
},
|
||||
distance: 10,
|
||||
handle: '.modal-header'
|
||||
});
|
||||
});
|
||||
|
||||
chatModal.find('#chat-close-btn').on('click', function() {
|
||||
module.close(chatModal);
|
||||
});
|
||||
|
||||
function gotoChats() {
|
||||
var text = components.get('chat/input').val();
|
||||
$(window).one('action:ajaxify.end', function() {
|
||||
components.get('chat/input').val(text);
|
||||
});
|
||||
|
||||
ajaxify.go('user/' + app.user.userslug + '/chats/' + chatModal.attr('roomId'));
|
||||
module.close(chatModal);
|
||||
}
|
||||
|
||||
app.updateUserStatus(chatModal.find('[component="user/status"]'), status);
|
||||
});
|
||||
}
|
||||
chatModal.find('.modal-header').on('dblclick', gotoChats);
|
||||
chatModal.find('button[data-action="maximize"]').on('click', gotoChats);
|
||||
|
||||
module.createModal = function(data, callback) {
|
||||
templates.parse('chat', data, function(chatTpl) {
|
||||
translator.translate(chatTpl, function (chatTpl) {
|
||||
chatModal.on('click', function() {
|
||||
module.bringModalToTop(chatModal);
|
||||
|
||||
var chatModal = $(chatTpl),
|
||||
uuid = utils.generateUUID(),
|
||||
if (dragged) {
|
||||
dragged = false;
|
||||
|
||||
chatModal.attr('id', 'chat-modal-' + data.roomId);
|
||||
chatModal.attr('roomId', data.roomId);
|
||||
chatModal.attr('intervalId', 0);
|
||||
chatModal.attr('UUID', uuid);
|
||||
chatModal.css('position', 'fixed');
|
||||
chatModal.css('zIndex', 100);
|
||||
chatModal.appendTo($('body'));
|
||||
module.center(chatModal);
|
||||
|
||||
app.loadJQueryUI(function() {
|
||||
chatModal.find('.modal-content').resizable({
|
||||
handles: 'n, e, s, w, se',
|
||||
minHeight: 250,
|
||||
minWidth: 400
|
||||
});
|
||||
|
||||
chatModal.find('.modal-content').on('resize', function(event, ui) {
|
||||
if (ui.originalSize.height === ui.size.height) {
|
||||
return;
|
||||
}
|
||||
|
||||
chatModal.find('.chat-content').css('height', module.calculateChatListHeight(chatModal));
|
||||
});
|
||||
|
||||
chatModal.draggable({
|
||||
start:function() {
|
||||
module.bringModalToTop(chatModal);
|
||||
},
|
||||
stop:function() {
|
||||
chatModal.find('#chat-message-input').focus();
|
||||
},
|
||||
distance: 10,
|
||||
handle: '.modal-header'
|
||||
});
|
||||
});
|
||||
|
||||
chatModal.find('#chat-close-btn').on('click', function() {
|
||||
module.close(chatModal);
|
||||
});
|
||||
|
||||
function gotoChats() {
|
||||
var text = components.get('chat/input').val();
|
||||
$(window).one('action:ajaxify.end', function() {
|
||||
components.get('chat/input').val(text);
|
||||
});
|
||||
|
||||
ajaxify.go('user/' + app.user.userslug + '/chats/' + chatModal.attr('roomId'));
|
||||
module.close(chatModal);
|
||||
}
|
||||
|
||||
chatModal.find('.modal-header').on('dblclick', gotoChats);
|
||||
chatModal.find('button[data-action="maximize"]').on('click', gotoChats);
|
||||
|
||||
chatModal.on('click', function() {
|
||||
module.bringModalToTop(chatModal);
|
||||
|
||||
if (dragged) {
|
||||
dragged = false;
|
||||
}
|
||||
});
|
||||
|
||||
chatModal.on('mousemove', function(e) {
|
||||
if (e.which === 1) {
|
||||
dragged = true;
|
||||
}
|
||||
});
|
||||
|
||||
chatModal.on('mousemove keypress click', function() {
|
||||
if (newMessage) {
|
||||
socket.emit('modules.chats.markRead', data.roomId);
|
||||
newMessage = false;
|
||||
}
|
||||
});
|
||||
|
||||
Chats.addEditDeleteHandler(chatModal.find('[component="chat/messages"]'), data.roomId);
|
||||
|
||||
chatModal.find('[component="chat/controlsToggle"]').on('click', function() {
|
||||
var messagesEl = chatModal.find('[component="chat/messages"]');
|
||||
|
||||
chatModal.find('[component="chat/controls"]').toggle();
|
||||
messagesEl.css('height', module.calculateChatListHeight(chatModal));
|
||||
});
|
||||
|
||||
Chats.addSinceHandler(chatModal.attr('roomId'), chatModal.find('.chat-content'), chatModal.find('[data-since]'));
|
||||
Chats.addRenameHandler(chatModal.attr('roomId'), chatModal.find('[component="chat/room/name"]'));
|
||||
|
||||
Chats.addSendHandlers(chatModal.attr('roomId'), chatModal.find('#chat-message-input'), chatModal.find('#chat-message-send-btn'));
|
||||
|
||||
Chats.createTagsInput(chatModal.find('.users-tag-input'), data);
|
||||
Chats.createAutoComplete(chatModal.find('[component="chat/input"]'));
|
||||
|
||||
Chats.loadChatSince(chatModal.attr('roomId'), chatModal.find('.chat-content'), 'recent');
|
||||
|
||||
Chats.addScrollHandler(chatModal.attr('roomId'), app.user.uid, chatModal.find('.chat-content'));
|
||||
|
||||
checkStatus(chatModal);
|
||||
|
||||
taskbar.push('chat', chatModal.attr('UUID'), {
|
||||
title: data.users.length ? data.users[0].username : '',
|
||||
roomId: data.roomId,
|
||||
icon: 'fa-comment',
|
||||
state: ''
|
||||
});
|
||||
|
||||
$(window).trigger('action:chat.loaded', chatModal);
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback(chatModal);
|
||||
}
|
||||
});
|
||||
|
||||
chatModal.on('mousemove', function(e) {
|
||||
if (e.which === 1) {
|
||||
dragged = true;
|
||||
}
|
||||
});
|
||||
|
||||
chatModal.on('mousemove keypress click', function() {
|
||||
if (newMessage) {
|
||||
socket.emit('modules.chats.markRead', data.roomId);
|
||||
newMessage = false;
|
||||
}
|
||||
});
|
||||
|
||||
Chats.addEditDeleteHandler(chatModal.find('[component="chat/messages"]'), data.roomId);
|
||||
|
||||
chatModal.find('[component="chat/controlsToggle"]').on('click', function() {
|
||||
var messagesEl = chatModal.find('[component="chat/messages"]');
|
||||
|
||||
chatModal.find('[component="chat/controls"]').toggle();
|
||||
messagesEl.css('height', module.calculateChatListHeight(chatModal));
|
||||
});
|
||||
|
||||
Chats.addRenameHandler(chatModal.attr('roomId'), chatModal.find('[component="chat/room/name"]'));
|
||||
|
||||
Chats.addSendHandlers(chatModal.attr('roomId'), chatModal.find('#chat-message-input'), chatModal.find('#chat-message-send-btn'));
|
||||
|
||||
Chats.createTagsInput(chatModal.find('.users-tag-input'), data);
|
||||
Chats.createAutoComplete(chatModal.find('[component="chat/input"]'));
|
||||
|
||||
Chats.addScrollHandler(chatModal.attr('roomId'), data.uid, chatModal.find('.chat-content'));
|
||||
|
||||
taskbar.push('chat', chatModal.attr('UUID'), {
|
||||
title: data.users.length ? data.users[0].username : '',
|
||||
roomId: data.roomId,
|
||||
icon: 'fa-comment',
|
||||
state: ''
|
||||
});
|
||||
|
||||
$(window).trigger('action:chat.loaded', chatModal);
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback(chatModal);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -339,7 +326,7 @@ define('chat', [
|
||||
});
|
||||
};
|
||||
|
||||
module.disableMobileBehaviour = function(modalEl) {
|
||||
module.disableMobileBehaviour = function() {
|
||||
app.toggleNavbar(true);
|
||||
};
|
||||
|
||||
@@ -347,7 +334,6 @@ define('chat', [
|
||||
var totalHeight = modalEl.find('.modal-content').outerHeight() - modalEl.find('.modal-header').outerHeight();
|
||||
var padding = parseInt(modalEl.find('.modal-body').css('padding-top'), 10) + parseInt(modalEl.find('.modal-body').css('padding-bottom'), 10);
|
||||
var contentMargin = parseInt(modalEl.find('.chat-content').css('margin-top'), 10) + parseInt(modalEl.find('.chat-content').css('margin-bottom'), 10);
|
||||
var sinceHeight = modalEl.find('.since-bar').outerHeight(true);
|
||||
var inputGroupHeight = modalEl.find('.input-group').outerHeight();
|
||||
|
||||
return totalHeight - padding - contentMargin - inputGroupHeight;
|
||||
|
||||
@@ -30,10 +30,13 @@ chatsController.get = function(req, res, callback) {
|
||||
if (!uid) {
|
||||
return callback();
|
||||
}
|
||||
messaging.getRecentChats(uid, 0, 19, next);
|
||||
messaging.getRecentChats(req.uid, uid, 0, 19, next);
|
||||
},
|
||||
function(_recentChats, next) {
|
||||
recentChats = _recentChats;
|
||||
if (!recentChats) {
|
||||
return callback();
|
||||
}
|
||||
if (!req.params.roomid) {
|
||||
return res.render('chats', {
|
||||
rooms: recentChats.rooms,
|
||||
@@ -48,15 +51,15 @@ chatsController.get = function(req, res, callback) {
|
||||
messaging.isUserInRoom(req.uid, req.params.roomid, next);
|
||||
},
|
||||
function(inRoom, next) {
|
||||
if (!inRoom && parseInt(req.uid, 10) === parseInt(uid, 10)) {
|
||||
if (!inRoom) {
|
||||
return callback();
|
||||
}
|
||||
async.parallel({
|
||||
users: async.apply(messaging.getUsersInRoom, req.params.roomid, 0, -1),
|
||||
messages: async.apply(messaging.getMessages, {
|
||||
callerUid: req.uid,
|
||||
uid: uid,
|
||||
roomId: req.params.roomid,
|
||||
since: 'recent',
|
||||
isNew: false
|
||||
}),
|
||||
room: async.apply(messaging.getRoomData, req.params.roomid)
|
||||
@@ -74,6 +77,7 @@ chatsController.get = function(req, res, callback) {
|
||||
return user && parseInt(user.uid, 10) && parseInt(user.uid, 10) !== req.uid;
|
||||
});
|
||||
|
||||
room.groupChat = room.hasOwnProperty('groupChat') ? room.groupChat : room.users.length > 2;
|
||||
room.rooms = recentChats.rooms;
|
||||
room.uid = uid;
|
||||
room.userslug = req.params.userslug;
|
||||
|
||||
@@ -87,6 +87,10 @@ helpers.getUserDataByUserSlug = function(userslug, callerUID, callback) {
|
||||
userData.ips = results.ips;
|
||||
}
|
||||
|
||||
if (!isAdmin && !isGlobalModerator) {
|
||||
userData.moderationNote = undefined;
|
||||
}
|
||||
|
||||
userData.uid = userData.uid;
|
||||
userData.yourid = callerUID;
|
||||
userData.theirid = userData.uid;
|
||||
@@ -120,6 +124,7 @@ helpers.getUserDataByUserSlug = function(userslug, callerUID, callback) {
|
||||
userData.signature = validator.escape(String(userData.signature || ''));
|
||||
userData.aboutme = validator.escape(String(userData.aboutme || ''));
|
||||
userData.birthday = validator.escape(String(userData.birthday || ''));
|
||||
userData.moderationNote = validator.escape(String(userData.moderationNote || ''));
|
||||
|
||||
userData['cover:url'] = userData['cover:url'] || require('../../coverPhoto').getDefaultProfileCover(userData.uid);
|
||||
userData['cover:position'] = userData['cover:position'] || '50% 50%';
|
||||
|
||||
@@ -22,8 +22,8 @@ infoController.get = function(req, res, callback) {
|
||||
async.parallel({
|
||||
history: async.apply(user.getModerationHistory, userData.uid),
|
||||
sessions: async.apply(user.auth.getSessions, userData.uid, req.sessionID),
|
||||
usernames: async.apply(user.getUsernameHistory, userData.uid),
|
||||
emails: async.apply(user.getEmailHistory, userData.uid)
|
||||
usernames: async.apply(user.getHistory, 'user:' + userData.uid + ':usernames'),
|
||||
emails: async.apply(user.getHistory, 'user:' + userData.uid + ':emails')
|
||||
}, next);
|
||||
}
|
||||
], function(err, data) {
|
||||
|
||||
@@ -56,7 +56,7 @@ flagsController.get = function(req, res, next) {
|
||||
assignees: results.assignees,
|
||||
analytics: results.analytics,
|
||||
categories: results.categories,
|
||||
byUsername: validator(String(byUsername)),
|
||||
byUsername: validator.escape(String(byUsername)),
|
||||
sortByCount: sortBy === 'count',
|
||||
sortByTime: sortBy === 'time',
|
||||
pagination: pagination.create(page, pageCount, req.query),
|
||||
|
||||
@@ -221,6 +221,7 @@ Controllers.registerInterstitial = function(req, res, next) {
|
||||
}
|
||||
|
||||
res.render('registerComplete', {
|
||||
title: '[[pages:registration-complete]]',
|
||||
errors: errors,
|
||||
sections: sections
|
||||
});
|
||||
|
||||
@@ -58,6 +58,9 @@ topicsController.get = function(req, res, callback) {
|
||||
if (req.params.post_index){
|
||||
url += '/'+req.params.post_index;
|
||||
}
|
||||
if (currentPage > 1) {
|
||||
url += '?page=' + currentPage;
|
||||
}
|
||||
return helpers.redirect(res, url);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@ module.exports = function(db, module) {
|
||||
value = helpers.valueToString(value);
|
||||
|
||||
db.collection('objects').update({_key: key, value: value}, {$set: {score: parseInt(score, 10)}}, {upsert:true, w: 1}, function(err) {
|
||||
if (err && err.message.startsWith('E11000 duplicate key error')) {
|
||||
return module.sortedSetAdd(key, score, value, callback);
|
||||
}
|
||||
callback(err);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -65,15 +65,18 @@
|
||||
};
|
||||
|
||||
module.connect = function(options) {
|
||||
var redis_socket_or_host = nconf.get('redis:host'),
|
||||
cxn, dbIdx;
|
||||
|
||||
options = options || {};
|
||||
var redis_socket_or_host = nconf.get('redis:host');
|
||||
var cxn;
|
||||
|
||||
if (!redis) {
|
||||
redis = require('redis');
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
if (nconf.get('redis:password')) {
|
||||
options.auth_pass = nconf.get('redis:password');
|
||||
}
|
||||
|
||||
if (redis_socket_or_host && redis_socket_or_host.indexOf('/') >= 0) {
|
||||
/* If redis.host contains a path name character, use the unix dom sock connection. ie, /tmp/redis.sock */
|
||||
cxn = redis.createClient(nconf.get('redis:host'), options);
|
||||
@@ -91,7 +94,7 @@
|
||||
cxn.auth(nconf.get('redis:password'));
|
||||
}
|
||||
|
||||
dbIdx = parseInt(nconf.get('redis:database'), 10);
|
||||
var dbIdx = parseInt(nconf.get('redis:database'), 10);
|
||||
if (dbIdx) {
|
||||
cxn.select(dbIdx, function(error) {
|
||||
if(error) {
|
||||
|
||||
@@ -5,6 +5,12 @@ module.exports = function(redisClient, module) {
|
||||
|
||||
module.setAdd = function(key, value, callback) {
|
||||
callback = callback || function() {};
|
||||
if (!Array.isArray(value)) {
|
||||
value = [value];
|
||||
}
|
||||
if (!value.length) {
|
||||
return callback();
|
||||
}
|
||||
redisClient.sadd(key, value, function(err, res) {
|
||||
callback(err);
|
||||
});
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var async = require('async'),
|
||||
|
||||
db = require('./database'),
|
||||
batch = require('./batch'),
|
||||
user = require('./user'),
|
||||
utils = require('../public/src/utils');
|
||||
|
||||
var async = require('async');
|
||||
var validator = require('validator');
|
||||
|
||||
var db = require('./database');
|
||||
var batch = require('./batch');
|
||||
var user = require('./user');
|
||||
var utils = require('../public/src/utils');
|
||||
|
||||
(function(events) {
|
||||
events.log = function(data, callback) {
|
||||
@@ -54,6 +54,11 @@ var async = require('async'),
|
||||
},
|
||||
function(eventsData, next) {
|
||||
eventsData.forEach(function(event) {
|
||||
Object.keys(event).forEach(function(key) {
|
||||
if (typeof event[key] === 'string') {
|
||||
event[key] = validator.escape(String(event[key] || ''));
|
||||
}
|
||||
});
|
||||
var e = utils.merge(event);
|
||||
e.eid = e.uid = e.type = e.ip = e.user = undefined;
|
||||
event.jsonString = JSON.stringify(e, null, 4);
|
||||
@@ -123,7 +128,7 @@ var async = require('async'),
|
||||
callback = callback || function() {};
|
||||
|
||||
batch.processSortedSet('events:time', function(eids, next) {
|
||||
events.deleteEvents(eids, callback);
|
||||
events.deleteEvents(eids, next);
|
||||
}, {alwaysStartAt: 0}, callback);
|
||||
};
|
||||
|
||||
|
||||
@@ -189,9 +189,9 @@ module.exports = function(Groups) {
|
||||
if (!checks.exists) {
|
||||
return next(new Error('[[error:no-group]]'));
|
||||
} else if (checks.isMember) {
|
||||
return next(new Error('[[error:group-already-member]]'));
|
||||
return callback();
|
||||
} else if (type === 'invite' && checks.isInvited) {
|
||||
return next(new Error('[[error:group-already-invited]]'));
|
||||
return callback();
|
||||
} else if (type === 'request' && checks.isPending) {
|
||||
return next(new Error('[[error:group-already-requested]]'));
|
||||
}
|
||||
|
||||
212
src/messaging.js
212
src/messaging.js
@@ -1,18 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
var async = require('async'),
|
||||
winston = require('winston'),
|
||||
S = require('string'),
|
||||
var async = require('async');
|
||||
var winston = require('winston');
|
||||
var S = require('string');
|
||||
|
||||
|
||||
db = require('./database'),
|
||||
user = require('./user'),
|
||||
plugins = require('./plugins'),
|
||||
meta = require('./meta'),
|
||||
utils = require('../public/src/utils'),
|
||||
notifications = require('./notifications'),
|
||||
userNotifications = require('./user/notifications');
|
||||
var db = require('./database');
|
||||
var user = require('./user');
|
||||
var plugins = require('./plugins');
|
||||
var meta = require('./meta');
|
||||
var utils = require('../public/src/utils');
|
||||
var notifications = require('./notifications');
|
||||
var userNotifications = require('./user/notifications');
|
||||
|
||||
(function(Messaging) {
|
||||
|
||||
@@ -23,13 +22,6 @@ var async = require('async'),
|
||||
require('./messaging/unread')(Messaging);
|
||||
require('./messaging/notifications')(Messaging);
|
||||
|
||||
var terms = {
|
||||
day: 86400000,
|
||||
week: 604800000,
|
||||
month: 2592000000,
|
||||
threemonths: 7776000000
|
||||
};
|
||||
|
||||
Messaging.getMessageField = function(mid, field, callback) {
|
||||
Messaging.getMessageFields(mid, [field], function(err, fields) {
|
||||
callback(err, fields ? fields[field] : null);
|
||||
@@ -51,46 +43,42 @@ var async = require('async'),
|
||||
Messaging.getMessages = function(params, callback) {
|
||||
var uid = params.uid;
|
||||
var roomId = params.roomId;
|
||||
var since = params.since;
|
||||
var isNew = params.isNew;
|
||||
var isNew = params.isNew || false;
|
||||
var start = params.hasOwnProperty('start') ? params.start : 0;
|
||||
var count = params.count || 250;
|
||||
var stop = parseInt(start, 10) + ((params.count || 50) - 1);
|
||||
var markRead = params.markRead || true;
|
||||
|
||||
var min = params.count ? 0 : Date.now() - (terms[since] || terms.day);
|
||||
|
||||
if (since === 'recent') {
|
||||
count = 50;
|
||||
min = 0;
|
||||
}
|
||||
|
||||
db.getSortedSetRevRangeByScore('uid:' + uid + ':chat:room:' + roomId + ':mids', start, count, '+inf', min, function(err, mids) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!Array.isArray(mids) || !mids.length) {
|
||||
return callback(null, []);
|
||||
}
|
||||
var indices = {};
|
||||
mids.forEach(function(mid, index) {
|
||||
indices[mid] = start + index;
|
||||
});
|
||||
|
||||
mids.reverse();
|
||||
|
||||
Messaging.getMessagesData(mids, uid, roomId, isNew, function(err, messageData) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
var indices = {};
|
||||
async.waterfall([
|
||||
function(next) {
|
||||
canGetMessages(params.callerUid, params.uid, next);
|
||||
},
|
||||
function(canGet, next) {
|
||||
if (!canGet) {
|
||||
return callback(null, null);
|
||||
}
|
||||
db.getSortedSetRevRange('uid:' + uid + ':chat:room:' + roomId + ':mids', start, stop, next);
|
||||
},
|
||||
function(mids, next) {
|
||||
if (!Array.isArray(mids) || !mids.length) {
|
||||
return callback(null, []);
|
||||
}
|
||||
|
||||
for(var i=0; i<messageData.length; i++) {
|
||||
messageData[i].index = indices[messageData[i].messageId.toString()];
|
||||
}
|
||||
mids.forEach(function(mid, index) {
|
||||
indices[mid] = start + index;
|
||||
});
|
||||
|
||||
callback(null, messageData);
|
||||
});
|
||||
});
|
||||
mids.reverse();
|
||||
|
||||
Messaging.getMessagesData(mids, uid, roomId, isNew, next);
|
||||
},
|
||||
function(messageData, next) {
|
||||
messageData.forEach(function(messageData) {
|
||||
messageData.index = indices[messageData.messageId.toString()];
|
||||
});
|
||||
next(null, messageData);
|
||||
}
|
||||
], callback);
|
||||
|
||||
if (markRead) {
|
||||
notifications.markRead('chat_' + roomId + '_' + uid, uid, function(err) {
|
||||
@@ -103,6 +91,16 @@ var async = require('async'),
|
||||
}
|
||||
};
|
||||
|
||||
function canGetMessages(callerUid, uid, callback) {
|
||||
plugins.fireHook('filter:messaging.canGetMessages', {
|
||||
callerUid: callerUid,
|
||||
uid: uid,
|
||||
canGet: parseInt(callerUid, 10) === parseInt(uid, 10)
|
||||
}, function(err, data) {
|
||||
callback(err, data ? data.canGet : false);
|
||||
});
|
||||
}
|
||||
|
||||
Messaging.getMessagesData = function(mids, uid, roomId, isNew, callback) {
|
||||
|
||||
var keys = mids.map(function(mid) {
|
||||
@@ -250,44 +248,49 @@ var async = require('async'),
|
||||
};
|
||||
|
||||
|
||||
Messaging.getRecentChats = function(uid, start, stop, callback) {
|
||||
db.getSortedSetRevRange('uid:' + uid + ':chat:rooms', start, stop, function(err, roomIds) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
async.parallel({
|
||||
roomData: function(next) {
|
||||
Messaging.getRoomsData(roomIds, next);
|
||||
},
|
||||
unread: function(next) {
|
||||
db.isSortedSetMembers('uid:' + uid + ':chat:rooms:unread', roomIds, next);
|
||||
},
|
||||
users: function(next) {
|
||||
async.map(roomIds, function(roomId, next) {
|
||||
db.getSortedSetRevRange('chat:room:' + roomId + ':uids', 0, 3, function(err, uids) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
uids = uids.filter(function(value) {
|
||||
return value && parseInt(value, 10) !== parseInt(uid, 10);
|
||||
Messaging.getRecentChats = function(callerUid, uid, start, stop, callback) {
|
||||
async.waterfall([
|
||||
function(next) {
|
||||
canGetRecentChats(callerUid, uid, next);
|
||||
},
|
||||
function(canGet, next) {
|
||||
if (!canGet) {
|
||||
return callback(null, null);
|
||||
}
|
||||
db.getSortedSetRevRange('uid:' + uid + ':chat:rooms', start, stop, next);
|
||||
},
|
||||
function(roomIds, next) {
|
||||
async.parallel({
|
||||
roomData: function(next) {
|
||||
Messaging.getRoomsData(roomIds, next);
|
||||
},
|
||||
unread: function(next) {
|
||||
db.isSortedSetMembers('uid:' + uid + ':chat:rooms:unread', roomIds, next);
|
||||
},
|
||||
users: function(next) {
|
||||
async.map(roomIds, function(roomId, next) {
|
||||
db.getSortedSetRevRange('chat:room:' + roomId + ':uids', 0, 9, function(err, uids) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
uids = uids.filter(function(value) {
|
||||
return value && parseInt(value, 10) !== parseInt(uid, 10);
|
||||
});
|
||||
user.getUsersFields(uids, ['uid', 'username', 'userslug', 'picture', 'status', 'lastonline'] , next);
|
||||
});
|
||||
user.getUsersFields(uids, ['uid', 'username', 'userslug', 'picture', 'status', 'lastonline'] , next);
|
||||
});
|
||||
}, next);
|
||||
},
|
||||
teasers: function(next) {
|
||||
async.map(roomIds, function(roomId, next) {
|
||||
Messaging.getTeaser(uid, roomId, next);
|
||||
}, next);
|
||||
}
|
||||
}, function(err, results) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
}, next);
|
||||
},
|
||||
teasers: function(next) {
|
||||
async.map(roomIds, function(roomId, next) {
|
||||
Messaging.getTeaser(uid, roomId, next);
|
||||
}, next);
|
||||
}
|
||||
}, next);
|
||||
},
|
||||
function(results, next) {
|
||||
results.roomData.forEach(function(room, index) {
|
||||
room.users = results.users[index];
|
||||
room.groupChat = room.hasOwnProperty('groupChat') ? room.groupChat : room.users.length > 2;
|
||||
room.unread = results.unread[index];
|
||||
room.teaser = results.teasers[index];
|
||||
|
||||
@@ -306,12 +309,23 @@ var async = require('async'),
|
||||
}).join(', ');
|
||||
});
|
||||
|
||||
callback(null, {rooms: results.roomData, nextStart: stop + 1});
|
||||
});
|
||||
});
|
||||
next(null, {rooms: results.roomData, nextStart: stop + 1});
|
||||
}
|
||||
], callback);
|
||||
};
|
||||
|
||||
function canGetRecentChats(callerUid, uid, callback) {
|
||||
plugins.fireHook('filter:messaging.canGetRecentChats', {
|
||||
callerUid: callerUid,
|
||||
uid: uid,
|
||||
canGet: parseInt(callerUid, 10) === parseInt(uid, 10)
|
||||
}, function(err, data) {
|
||||
callback(err, data ? data.canGet : false);
|
||||
});
|
||||
}
|
||||
|
||||
Messaging.getTeaser = function (uid, roomId, callback) {
|
||||
var teaser;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.getSortedSetRevRange('uid:' + uid + ':chat:room:' + roomId + ':mids', 0, 0, next);
|
||||
@@ -320,14 +334,22 @@ var async = require('async'),
|
||||
if (!mids || !mids.length) {
|
||||
return next(null, null);
|
||||
}
|
||||
Messaging.getMessageFields(mids[0], ['content', 'timestamp'], next);
|
||||
Messaging.getMessageFields(mids[0], ['fromuid', 'content', 'timestamp'], next);
|
||||
},
|
||||
function (teaser, next) {
|
||||
if (teaser && teaser.content) {
|
||||
function (_teaser, next) {
|
||||
teaser = _teaser;
|
||||
if (!teaser) {
|
||||
return callback();
|
||||
}
|
||||
if (teaser.content) {
|
||||
teaser.content = S(teaser.content).stripTags().decodeHTMLEntities().s;
|
||||
teaser.timestampISO = utils.toISOString(teaser.timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
teaser.timestampISO = utils.toISOString(teaser.timestamp);
|
||||
user.getUserFields(teaser.fromuid, ['uid', 'username', 'userslug', 'picture', 'status', 'lastonline'] , next);
|
||||
},
|
||||
function(user, next) {
|
||||
teaser.user = user;
|
||||
next(null, teaser);
|
||||
}
|
||||
], callback);
|
||||
|
||||
@@ -5,6 +5,7 @@ var validator = require('validator');
|
||||
|
||||
var db = require('../database');
|
||||
var user = require('../user');
|
||||
var plugins = require('../plugins');
|
||||
|
||||
module.exports = function(Messaging) {
|
||||
|
||||
@@ -13,10 +14,7 @@ module.exports = function(Messaging) {
|
||||
if (err || !data) {
|
||||
return callback(err || new Error('[[error:no-chat-room]]'));
|
||||
}
|
||||
data.roomName = data.roomName || '[[modules:chat.roomname, ' + roomId + ']]';
|
||||
if (data.roomName) {
|
||||
data.roomName = validator.escape(String(data.roomName));
|
||||
}
|
||||
modifyRoomData([data]);
|
||||
callback(null, data);
|
||||
});
|
||||
};
|
||||
@@ -29,16 +27,23 @@ module.exports = function(Messaging) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
roomData.forEach(function(data) {
|
||||
if (data) {
|
||||
data.roomName = data.roomName || '[[modules:chat.roomname, ' + data.roomId + ']]';
|
||||
data.roomName = validator.escape(String(data.roomName));
|
||||
}
|
||||
});
|
||||
modifyRoomData(roomData);
|
||||
callback(null, roomData);
|
||||
});
|
||||
};
|
||||
|
||||
function modifyRoomData(rooms) {
|
||||
rooms.forEach(function(data) {
|
||||
if (data) {
|
||||
data.roomName = data.roomName || '[[modules:chat.roomname, ' + data.roomId + ']]';
|
||||
data.roomName = validator.escape(String(data.roomName));
|
||||
if (data.hasOwnProperty('groupChat')) {
|
||||
data.groupChat = parseInt(data.groupChat, 10) === 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Messaging.newRoom = function(uid, toUids, callback) {
|
||||
var roomId;
|
||||
var now = Date.now();
|
||||
@@ -70,7 +75,17 @@ module.exports = function(Messaging) {
|
||||
};
|
||||
|
||||
Messaging.isUserInRoom = function(uid, roomId, callback) {
|
||||
db.isSortedSetMember('chat:room:' + roomId + ':uids', uid, callback);
|
||||
async.waterfall([
|
||||
function(next) {
|
||||
db.isSortedSetMember('chat:room:' + roomId + ':uids', uid, next);
|
||||
},
|
||||
function(inRoom, next) {
|
||||
plugins.fireHook('filter:messaging.isUserInRoom', {uid: uid, roomId: roomId, inRoom: inRoom}, next);
|
||||
},
|
||||
function(data, next) {
|
||||
next(null, data.inRoom);
|
||||
}
|
||||
], callback);
|
||||
};
|
||||
|
||||
Messaging.roomExists = function(roomId, callback) {
|
||||
@@ -105,6 +120,18 @@ module.exports = function(Messaging) {
|
||||
return now;
|
||||
});
|
||||
db.sortedSetAdd('chat:room:' + roomId + ':uids', timestamps, uids, next);
|
||||
},
|
||||
function(next) {
|
||||
async.parallel({
|
||||
userCount: async.apply(db.sortedSetCard, 'chat:room:' + roomId + ':uids'),
|
||||
roomData: async.apply(db.getObject, 'chat:room:' + roomId)
|
||||
}, next);
|
||||
},
|
||||
function(results, next) {
|
||||
if (!results.roomData.hasOwnProperty('groupChat') && results.userCount > 2) {
|
||||
return db.setObjectField('chat:room:' + roomId, 'groupChat', 1, next);
|
||||
}
|
||||
next();
|
||||
}
|
||||
], callback);
|
||||
};
|
||||
|
||||
@@ -120,7 +120,7 @@ module.exports = function(middleware) {
|
||||
results.user.isAdmin = results.isAdmin;
|
||||
results.user.isGlobalMod = results.isGlobalMod;
|
||||
results.user.uid = parseInt(results.user.uid, 10);
|
||||
results.user.email = String(results.user.email).replace(/\\/g, '\\\\');
|
||||
results.user.email = String(results.user.email).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
||||
results.user['email:confirmed'] = parseInt(results.user['email:confirmed'], 10) === 1;
|
||||
results.user.isEmailConfirmSent = !!results.isEmailConfirmSent;
|
||||
|
||||
|
||||
@@ -31,6 +31,6 @@ module.exports = function (app, middleware, controllers) {
|
||||
app.delete('/api/user/:userslug/session/:uuid', [middleware.requireUser], controllers.accounts.session.revoke);
|
||||
|
||||
setupPageRoute(app, '/notifications', middleware, [middleware.authenticate], controllers.accounts.notifications.get);
|
||||
setupPageRoute(app, '/user/:userslug/chats/:roomid?', middleware, accountMiddlewares, controllers.accounts.chats.get);
|
||||
setupPageRoute(app, '/user/:userslug/chats/:roomid?', middleware, middlewares, controllers.accounts.chats.get);
|
||||
setupPageRoute(app, '/chats/:roomid?', middleware, [], controllers.accounts.chats.redirectToChat);
|
||||
};
|
||||
|
||||
@@ -142,7 +142,7 @@ module.exports = function(app, middleware, hotswapIds) {
|
||||
}
|
||||
|
||||
app.use(middleware.privateUploads);
|
||||
app.use('/language/:code', middleware.processLanguages);
|
||||
app.use(relativePath + '/language/:code', middleware.processLanguages);
|
||||
app.use(relativePath, express.static(path.join(__dirname, '../../', 'public'), {
|
||||
maxAge: app.enabled('cache') ? 5184000000 : 0
|
||||
}));
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
|
||||
var async = require('async');
|
||||
var validator = require('validator');
|
||||
|
||||
var db = require('../../database');
|
||||
var groups = require('../../groups');
|
||||
var user = require('../../user');
|
||||
@@ -204,7 +205,7 @@ User.search = function(socket, data, callback) {
|
||||
|
||||
userData.forEach(function(user, index) {
|
||||
if (user && userInfo[index]) {
|
||||
user.email = userInfo[index].email || '';
|
||||
user.email = validator.escape(String(userInfo[index].email || ''));
|
||||
user.flags = userInfo[index].flags || 0;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -152,7 +152,7 @@ SocketGroups.issueMassInvite = isOwner(function(socket, data, callback) {
|
||||
});
|
||||
|
||||
async.eachSeries(uids, function(uid, next) {
|
||||
groups.invite(data.groupName, uid, callback);
|
||||
groups.invite(data.groupName, uid, next);
|
||||
}, callback);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -177,9 +177,8 @@ var ratelimit = require('../middleware/ratelimit');
|
||||
if (nconf.get('redis')) {
|
||||
var redisAdapter = require('socket.io-redis');
|
||||
var redis = require('../database/redis');
|
||||
var pub = redis.connect({return_buffers: true});
|
||||
var pub = redis.connect();
|
||||
var sub = redis.connect({return_buffers: true});
|
||||
|
||||
io.adapter(redisAdapter({pubClient: pub, subClient: sub}));
|
||||
} else if (nconf.get('isCluster') === 'true') {
|
||||
winston.warn('[socket.io] Clustering detected, you are advised to configure Redis as a websocket store.');
|
||||
|
||||
@@ -12,26 +12,13 @@ var server = require('./');
|
||||
var user = require('../user');
|
||||
|
||||
var SocketModules = {
|
||||
chats: {},
|
||||
sounds: {},
|
||||
settings: {}
|
||||
};
|
||||
chats: {},
|
||||
sounds: {},
|
||||
settings: {}
|
||||
};
|
||||
|
||||
/* Chat */
|
||||
|
||||
SocketModules.chats.get = function(socket, data, callback) {
|
||||
if(!data || !data.roomId) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
|
||||
Messaging.getMessages({
|
||||
uid: socket.uid,
|
||||
roomId: data.roomId,
|
||||
since: data.since,
|
||||
isNew: false
|
||||
}, callback);
|
||||
};
|
||||
|
||||
SocketModules.chats.getRaw = function(socket, data, callback) {
|
||||
if (!data || !data.hasOwnProperty('mid')) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
@@ -68,7 +55,7 @@ SocketModules.chats.newRoom = function(socket, data, callback) {
|
||||
};
|
||||
|
||||
SocketModules.chats.send = function(socket, data, callback) {
|
||||
if (!data || !data.roomId) {
|
||||
if (!data || !data.roomId || !socket.uid) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
|
||||
@@ -128,11 +115,19 @@ SocketModules.chats.loadRoom = function(socket, data, callback) {
|
||||
|
||||
async.parallel({
|
||||
roomData: async.apply(Messaging.getRoomData, data.roomId),
|
||||
users: async.apply(Messaging.getUsersInRoom, data.roomId, 0, -1)
|
||||
users: async.apply(Messaging.getUsersInRoom, data.roomId, 0, -1),
|
||||
messages: async.apply(Messaging.getMessages, {
|
||||
callerUid: socket.uid,
|
||||
uid: data.uid || socket.uid,
|
||||
roomId: data.roomId,
|
||||
isNew: false
|
||||
}),
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
results.roomData.users = results.users;
|
||||
results.roomData.messages = results.messages;
|
||||
results.roomData.groupChat = results.roomData.hasOwnProperty('groupChat') ? results.roomData.groupChat : results.users.length > 2;
|
||||
results.roomData.isOwner = parseInt(results.roomData.owner, 10) === socket.uid;
|
||||
results.roomData.maximumUsersInChatRoom = parseInt(meta.config.maximumUsersInChatRoom, 10) || 0;
|
||||
results.roomData.showUserInput = !results.roomData.maximumUsersInChatRoom || results.roomData.maximumUsersInChatRoom > 2;
|
||||
@@ -231,6 +226,9 @@ SocketModules.chats.canMessage = function(socket, roomId, callback) {
|
||||
};
|
||||
|
||||
SocketModules.chats.markRead = function(socket, roomId, callback) {
|
||||
if (!socket.uid) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
async.parallel({
|
||||
usersInRoom: async.apply(Messaging.getUidsInRoom, roomId, 0, -1),
|
||||
markRead: async.apply(Messaging.markRead, socket.uid, roomId)
|
||||
@@ -292,21 +290,12 @@ SocketModules.chats.renameRoom = function(socket, data, callback) {
|
||||
};
|
||||
|
||||
SocketModules.chats.getRecentChats = function(socket, data, callback) {
|
||||
if (!data || !utils.isNumber(data.after)) {
|
||||
if (!data || !utils.isNumber(data.after) || !utils.isNumber(data.uid)) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
var start = parseInt(data.after, 10);
|
||||
var stop = start + 9;
|
||||
if (socket.uid === parseInt(data.uid, 10)) {
|
||||
return Messaging.getRecentChats(socket.uid, start, stop, callback);
|
||||
}
|
||||
|
||||
user.isAdminOrGlobalMod(socket.uid, function(err, isAdminOrGlobalMod) {
|
||||
if (err || !isAdminOrGlobalMod) {
|
||||
return callback(err || new Error('[[error:no-privileges]]'));
|
||||
}
|
||||
Messaging.getRecentChats(data.uid, start, stop, callback);
|
||||
});
|
||||
Messaging.getRecentChats(socket.uid, data.uid, start, stop, callback);
|
||||
};
|
||||
|
||||
SocketModules.chats.hasPrivateChat = function(socket, uid, callback) {
|
||||
@@ -320,22 +309,21 @@ SocketModules.chats.getMessages = function(socket, data, callback) {
|
||||
if (!socket.uid || !data.uid || !data.roomId) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
|
||||
var params = {
|
||||
callerUid: socket.uid,
|
||||
uid: data.uid,
|
||||
roomId: data.roomId,
|
||||
start: parseInt(data.start, 10) + 1,
|
||||
start: parseInt(data.start, 10) || 0,
|
||||
count: 50,
|
||||
markRead: false
|
||||
};
|
||||
if (socket.uid === parseInt(data.uid, 10)) {
|
||||
return Messaging.getMessages(params, callback);
|
||||
|
||||
if (data.hasOwnProperty('markRead')) {
|
||||
params.markRead = data.markRead;
|
||||
}
|
||||
user.isAdminOrGlobalMod(socket.uid, function(err, isAdminOrGlobalMod) {
|
||||
if (err || !isAdminOrGlobalMod) {
|
||||
return callback(err || new Error('[[error:no-privileges]]'));
|
||||
}
|
||||
Messaging.getMessages(params, callback);
|
||||
});
|
||||
|
||||
Messaging.getMessages(params, callback);
|
||||
};
|
||||
|
||||
/* Sounds */
|
||||
|
||||
@@ -345,7 +345,7 @@ var social = require('./social');
|
||||
}
|
||||
};
|
||||
|
||||
Topics.getTopicBookmarks = function( tid, callback ){
|
||||
Topics.getTopicBookmarks = function(tid, callback) {
|
||||
db.getSortedSetRangeWithScores(['tid:' + tid + ':bookmarks'], 0, -1, callback);
|
||||
};
|
||||
|
||||
@@ -372,49 +372,26 @@ var social = require('./social');
|
||||
};
|
||||
});
|
||||
|
||||
async.map(uidData, function(data, mapCallback) {
|
||||
posts.getPostIndices(forkedPosts, data.uid, function(err, indices) {
|
||||
async.eachLimit(uidData, 50, function(data, next) {
|
||||
posts.getPostIndices(forkedPosts, data.uid, function(err, postIndices) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
return next(err);
|
||||
}
|
||||
data.postIndices = indices;
|
||||
mapCallback(null, data);
|
||||
});
|
||||
}, function(err, results) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
async.map(results, function(data, mapCallback) {
|
||||
var uid = data.uid;
|
||||
|
||||
var bookmark = data.bookmark;
|
||||
bookmark = bookmark < maxIndex ? bookmark : maxIndex;
|
||||
var postIndices = data.postIndices;
|
||||
|
||||
for (var i = 0; i < postIndices.length && postIndices[i] < data.bookmark; ++i ){
|
||||
for (var i = 0; i < postIndices.length && postIndices[i] < data.bookmark; ++i) {
|
||||
--bookmark;
|
||||
}
|
||||
|
||||
if (parseInt(bookmark, 10) !== parseInt(data.bookmark, 10)) {
|
||||
mapCallback( null, { uid: uid, bookmark: bookmark } );
|
||||
Topics.setUserBookmark(tid, data.uid, bookmark, next);
|
||||
} else {
|
||||
mapCallback( null, null );
|
||||
next();
|
||||
}
|
||||
}, function(err, results) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
async.map(results, function(ui, cb) {
|
||||
if( ui && ui.bookmark) {
|
||||
Topics.setUserBookmark(tid, ui.uid, ui.bookmark, cb);
|
||||
} else {
|
||||
return cb(null, null);
|
||||
}
|
||||
}, function(err) {
|
||||
next(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
}, next);
|
||||
}
|
||||
], function(err){
|
||||
callback(err);
|
||||
|
||||
@@ -61,24 +61,15 @@ module.exports = function(User) {
|
||||
});
|
||||
};
|
||||
|
||||
User.getEmailHistory = function(uid, callback) {
|
||||
db.getSortedSetRevRangeWithScores('user:' + uid + ':emails', 0, -1, function(err, data) {
|
||||
callback(err, data.map(function(set) {
|
||||
User.getHistory = function(set, callback) {
|
||||
db.getSortedSetRevRangeWithScores(set, 0, -1, function(err, data) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
callback(null, data.map(function(set) {
|
||||
set.timestamp = set.score;
|
||||
set.timestampISO = new Date(set.score).toISOString();
|
||||
set.value = set.value.split(':')[0];
|
||||
delete set.score;
|
||||
return set;
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
User.getUsernameHistory = function(uid, callback) {
|
||||
db.getSortedSetRevRangeWithScores('user:' + uid + ':usernames', 0, -1, function(err, data) {
|
||||
callback(err, data.map(function(set) {
|
||||
set.timestamp = set.score;
|
||||
set.timestampISO = new Date(set.score).toISOString();
|
||||
set.value = set.value.split(':')[0];
|
||||
set.value = validator.escape(String(set.value.split(':')[0]));
|
||||
delete set.score;
|
||||
return set;
|
||||
}));
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
<a href="{config.relative_path}/user/{users.userslug}" target="_blank">{users.username} ({users.uid})</a><br/>
|
||||
<!-- IF users.email -->
|
||||
<small><span title="{users.email}">{users.email}</span></small>
|
||||
<small><span title="{users.email}">{users.email}</span></small><br/>
|
||||
<!-- ENDIF users.email -->
|
||||
|
||||
joined <span class="timeago" title="{users.joindateISO}"></span><br/>
|
||||
|
||||
Reference in New Issue
Block a user