mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-12 00:45:47 +01:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -25,7 +25,6 @@
|
||||
"passport-facebook": "0.1.5",
|
||||
"less-middleware": "0.1.12",
|
||||
"marked": "0.2.8",
|
||||
"bcrypt": "0.7.5",
|
||||
"async": "~0.2.8",
|
||||
"node-imagemagick": "0.1.8",
|
||||
"gravatar": "1.0.6",
|
||||
@@ -47,7 +46,8 @@
|
||||
"semver": "~2.2.1",
|
||||
"string": "~1.7.0",
|
||||
"xregexp": "~2.0.0",
|
||||
"socket.io-wildcard": "~0.1.1"
|
||||
"socket.io-wildcard": "~0.1.1",
|
||||
"bcryptjs": "~0.7.10"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"redis": "0.8.3",
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
"header.recent": "Recent",
|
||||
"header.unread": "Unread",
|
||||
"header.users": "Users",
|
||||
"header.chats": "Chats",
|
||||
"header.notifications": "Notifications",
|
||||
"header.search": "Search",
|
||||
"header.profile": "Profile",
|
||||
|
||||
|
||||
14
public/language/pt_br/category.json
Normal file
14
public/language/pt_br/category.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"new_topic_button": "New Topic",
|
||||
"no_topics": "<strong>There are no topics in this category.</strong><br />Why don't you try posting one?",
|
||||
"sidebar.recent_replies": "Recent Replies",
|
||||
"sidebar.active_participants": "Active Participants",
|
||||
"sidebar.moderators": "Moderators",
|
||||
"posts": "posts",
|
||||
"views": "views",
|
||||
"posted": "posted",
|
||||
"browsing": "browsing",
|
||||
"no_replies": "No one has replied",
|
||||
"replied": "replied",
|
||||
"last_edited_by": "last edited by"
|
||||
}
|
||||
7
public/language/pt_br/footer.json
Normal file
7
public/language/pt_br/footer.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"stats.online": "Online",
|
||||
"stats.users": "Testers",
|
||||
"stats.topics": "Tópicos",
|
||||
"stats.posts": "Posts",
|
||||
"success": "Sucesso"
|
||||
}
|
||||
40
public/language/pt_br/global.json
Normal file
40
public/language/pt_br/global.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"home": "Home",
|
||||
"search": "Procurar",
|
||||
"buttons.close": "Fechar",
|
||||
"403.title": "Acesso Negado",
|
||||
"403.message": "Parece que voc<6F> não tem acesso a essa página. talvez voc<6F> devesse <a href='/login'>tentar logar...</a>?",
|
||||
"404.title": "Not Found",
|
||||
"404.message": "Essa página não existe... volte para <a href='/'>página principal</a>.",
|
||||
"500.title": "Erro Interno.",
|
||||
"500.message": "Oops! deu algo errado!",
|
||||
|
||||
"register": "Cadastrar",
|
||||
"login": "Logar",
|
||||
|
||||
"logout": "Logout",
|
||||
"logout.title": "Logout com sucesso.",
|
||||
"logout.message": "Logado com Sucesso!",
|
||||
|
||||
"save_changes": "Salvar Alterações",
|
||||
"close": "Fechar",
|
||||
|
||||
"header.admin": "Admin",
|
||||
"header.recent": "Recente",
|
||||
"header.unread": "N<>o Lido",
|
||||
"header.users": "Usuários",
|
||||
"header.search": "Procurar",
|
||||
"header.profile": "Profile",
|
||||
|
||||
"notifications.loading": "Carregando Notificações",
|
||||
"chats.loading": "Carregando Bate-Papo",
|
||||
|
||||
"motd.welcome": "Welcome to NodeBB, the discussion platform of the future.",
|
||||
"motd.get": "Get NodeBB",
|
||||
"motd.fork": "Fork",
|
||||
"motd.like": "Like",
|
||||
"motd.follow": "Seguir",
|
||||
|
||||
"previouspage": "Página Anterior",
|
||||
"nextpage": "Próxima pagina;"
|
||||
}
|
||||
4
public/language/pt_br/language.json
Normal file
4
public/language/pt_br/language.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "Português Brasileiro",
|
||||
"code": "pt_br"
|
||||
}
|
||||
10
public/language/pt_br/login.json
Normal file
10
public/language/pt_br/login.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"login": "Login",
|
||||
"username": "Usuário",
|
||||
"password": "Senha",
|
||||
"remember_me": "Lembrar?",
|
||||
"forgot_password": "Esqueceu a Senha?",
|
||||
"alternative_logins": "Voc<6F> pode logar usando também...",
|
||||
"failed_login_attempt": "Falha no login, por favor tente novamente.",
|
||||
"login_successful": "Voc<6F> logou com sucesso!"
|
||||
}
|
||||
6
public/language/pt_br/modules.json
Normal file
6
public/language/pt_br/modules.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"chat.chatting_with": "Conversar com <span id=\"chat-with-name\"></span>",
|
||||
"chat.placeholder": "Digite sua mensagem aqui e pressione 'enter' para enviar",
|
||||
"chat.send": "Enviar",
|
||||
"chat.no_active": "Voc<6F> não tem chats ativos."
|
||||
}
|
||||
8
public/language/pt_br/notifications.json
Normal file
8
public/language/pt_br/notifications.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"title": "Notificações",
|
||||
"back_to_home": "voltar para home",
|
||||
"outgoing_link": "Link Externo",
|
||||
"outgoing_link_message": "Voc<6F> está saindo do agiletesters com um link externo",
|
||||
"continue_to": "Continuar para",
|
||||
"return_to": "Voltar para"
|
||||
}
|
||||
5
public/language/pt_br/recent.json
Normal file
5
public/language/pt_br/recent.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"day": "Dia",
|
||||
"week": "Semana",
|
||||
"month": "M<>s"
|
||||
}
|
||||
16
public/language/pt_br/register.json
Normal file
16
public/language/pt_br/register.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"register": "Cadastrar",
|
||||
"help.email": "Por padrão, seu email não ficará visivel.",
|
||||
"help.username_restrictions": "Um usuário <20>nico com %1 e %2 caracteres. Outros poderão te mencionar digitando @<span id='yourUsername'>usuário</span>.",
|
||||
"help.minimum_password_length": "Sua senha tem que ter no mínimo %1 caracteres.",
|
||||
"email_address": "Email",
|
||||
"email_address_placeholder": "Digite seu Email",
|
||||
"username": "Usuário",
|
||||
"username_placeholder": "Digiter Usuário",
|
||||
"password": "Senha",
|
||||
"password_placeholder": "Digitar Senha",
|
||||
"confirm_password": "Confirmar Senha",
|
||||
"confirm_password_placeholder": "Confirmar Senha",
|
||||
"register_now_button": "Cadastrar Agora",
|
||||
"alternative_registration": "Voc<6F> pode usar essas outras formas de cadastro"
|
||||
}
|
||||
13
public/language/pt_br/reset_password.json
Normal file
13
public/language/pt_br/reset_password.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"reset_Senha": "Resetar Senha",
|
||||
"update_Senha": "Alterar Senha",
|
||||
"Senha_changed.title": "Senha Alterada",
|
||||
"Senha_changed.message": "<p>Senha resetada com sucesso, por favor <a href=\"/login\">logue novamente</a>.",
|
||||
"wrong_reset_code.title": "Código De Reset Incorreto",
|
||||
"wrong_reset_code.message": "Codigo de Reset Incorreto. Tente novamente, ou <a href=\"/reset\">peça um novo</a>.",
|
||||
"new_Senha": "Nova Senha",
|
||||
"repeat_Senha": "Confirmar Senha",
|
||||
"enter_email": "Por digite seu <strong>email</strong> nós enviaremos para voc<6F> as instruções de como resetar sua senha.",
|
||||
"Senha_reset_sent": "Reset de Senha Enviado",
|
||||
"invalid_email": "Email inválido!"
|
||||
}
|
||||
53
public/language/pt_br/topic.json
Normal file
53
public/language/pt_br/topic.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"topic": "Tópico",
|
||||
"topics": "Tópicos",
|
||||
|
||||
"no_topics_found": "Nenhum tópico encontrado!",
|
||||
|
||||
"profile": "Profile",
|
||||
"posted_by": "Postado por",
|
||||
"chat": "Chat",
|
||||
"notify_me": "Ser notificado a cada nova resposta",
|
||||
"quote": "Citar",
|
||||
"reply": "Esponder",
|
||||
"edit": "Editar",
|
||||
"delete": "Deletar",
|
||||
"move": "Mover",
|
||||
"fork": "Fork",
|
||||
"banned": "Banido",
|
||||
"link": "Link",
|
||||
"share": "Compartilho",
|
||||
"tools": "Ferramentas",
|
||||
|
||||
"thread_tools.title": "Ferramentas da Thread",
|
||||
"thread_tools.markAsUnreadForAll": "Marcar como não lido",
|
||||
"thread_tools.pin": "Fixar Thread",
|
||||
"thread_tools.lock": "Travar Thread",
|
||||
"thread_tools.move": "Mover Thread",
|
||||
"thread_tools.fork": "Fork Thread",
|
||||
"thread_tools.delete": "Deletar Thread",
|
||||
|
||||
"load_categories": "Carregando Categorias",
|
||||
"disabled_categories_note": "Categorias desabilitadas estão em cinza",
|
||||
"confirm_move": "Mover",
|
||||
"confirm_fork": "Fork",
|
||||
|
||||
"favourite": "Favoritar",
|
||||
"favourites": "Favoritos",
|
||||
"favourites.not_logged_in.title": "Não Logado",
|
||||
"favourites.not_logged_in.message": "Por Favor logar para favoritar o tópico",
|
||||
"favourites.has_no_favourites": "Voc<6F> não tem nenhum item favoritado!",
|
||||
|
||||
"posted_by": "postado por",
|
||||
"loading_more_posts": "Carregando mais posts",
|
||||
"move_topic": "Mover Tópico",
|
||||
"move_post": "Mover Post",
|
||||
"fork_topic": "Fork Tópico",
|
||||
"topic_will_be_moved_to": "Este tópico será movido para categoria",
|
||||
"fork_topic_instruction": "Clique nos postas que voc<6F> fazer o fork",
|
||||
"fork_no_pids": "Nenhum Tópico selecionado",
|
||||
"fork_success": "Fork realizado com sucesso!",
|
||||
|
||||
"reputation": "Reputação",
|
||||
"posts": "Posts"
|
||||
}
|
||||
5
public/language/pt_br/unread.json
Normal file
5
public/language/pt_br/unread.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"no_unread_topics": "Todos os topicos lidos.",
|
||||
"mark_all_read": "Marcar como Lido",
|
||||
"load_more": "Carregar"
|
||||
}
|
||||
41
public/language/pt_br/user.json
Normal file
41
public/language/pt_br/user.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"banned": "Banido",
|
||||
"offline": "Offline",
|
||||
"username": "Usuário",
|
||||
"email": "Email",
|
||||
"fullname": "Nome Completo",
|
||||
"website": "Website",
|
||||
"location": "Localização",
|
||||
"age": "Idade",
|
||||
"joined": "Cadastrou",
|
||||
"lastonline": "Visto á",
|
||||
"profile_views": "Visualizações de Profile",
|
||||
"reputation": "Reputação",
|
||||
"posts": "Posts",
|
||||
"followers": "Seguidores",
|
||||
"following": "Seguindo",
|
||||
"signature": "Assinatura",
|
||||
"gravatar": "Gravatar",
|
||||
"birthday": "Aniversário",
|
||||
|
||||
"change_picture": "Alterar Foto",
|
||||
"edit": "Editar",
|
||||
"uploaded_picture": "Foto Carregada",
|
||||
"upload_new_picture": "Carregar novo Foto",
|
||||
"change_password": "Alterar Senha",
|
||||
"confirm_password": "Confirmar Senha",
|
||||
"password": "Senha",
|
||||
|
||||
"upload_picture": "Carregar Foto",
|
||||
"upload_a_picture": "Carregar Foto",
|
||||
"image_spec": "Somente arquivos jpg, png e gif com no maximo 256kb.",
|
||||
|
||||
"settings": "Configurações",
|
||||
"show_email": "Mostrar meu email",
|
||||
|
||||
"has_no_follower": "Ninguém está seguindo esse usuário...",
|
||||
"follows_no_one": "Este usuário não está seguindo ninguem...",
|
||||
|
||||
"email_hidden": "Email Escondido",
|
||||
"hidden": "Escondido"
|
||||
}
|
||||
9
public/language/pt_br/users.json
Normal file
9
public/language/pt_br/users.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"latest_users": "Usuários Recentes",
|
||||
"top_posters": "Top Posters",
|
||||
"most_reputation": "Com Mais Reputação",
|
||||
"online": "Online",
|
||||
"search": "Procurar",
|
||||
"enter_username": "Digite um usuário para buscar",
|
||||
"load_more": "Carregar mais"
|
||||
}
|
||||
@@ -537,12 +537,28 @@ var socket,
|
||||
app.alternatingTitle('');
|
||||
});
|
||||
|
||||
createHeaderTooltips();
|
||||
|
||||
templates.setGlobal('relative_path', RELATIVE_PATH);
|
||||
templates.setGlobal('usePagination', config.usePagination);
|
||||
templates.setGlobal('topicsPerPage', config.topicsPerPage);
|
||||
templates.setGlobal('postsPerPage', config.postsPerPage);
|
||||
});
|
||||
|
||||
function createHeaderTooltips() {
|
||||
$('#header-menu li i[title]').each(function() {
|
||||
$(this).parents('li').tooltip({
|
||||
placement: 'bottom',
|
||||
title: $(this).attr('title')
|
||||
});
|
||||
});
|
||||
|
||||
$('#user_label').tooltip({
|
||||
placement: 'bottom',
|
||||
title: $('#user_dropdown').attr('title')
|
||||
});
|
||||
}
|
||||
|
||||
showWelcomeMessage = location.href.indexOf('loggedin') !== -1;
|
||||
|
||||
app.loadConfig();
|
||||
|
||||
@@ -178,13 +178,13 @@ define(['uploader'], function(uploader) {
|
||||
});
|
||||
|
||||
// Permissions modal
|
||||
$('.permissions').on('click', function() {
|
||||
$('.admin-categories').on('click', '.permissions', function() {
|
||||
var cid = $(this).parents('li[data-cid]').attr('data-cid');
|
||||
Categories.launchPermissionsModal(cid);
|
||||
});
|
||||
|
||||
|
||||
$('.upload-button').on('click', function() {
|
||||
$('.admin-categories').on('click', '.upload-button', function() {
|
||||
var inputEl = this;
|
||||
var cid = $(this).parents('li[data-cid]').attr('data-cid');
|
||||
uploader.open(RELATIVE_PATH + '/admin/category/uploadpicture', {cid:cid}, function(imageUrlOnServer) {
|
||||
@@ -196,7 +196,7 @@ define(['uploader'], function(uploader) {
|
||||
});
|
||||
});
|
||||
|
||||
$('.admin-categories').delegate('.delete-image', 'click', function() {
|
||||
$('.admin-categories').on('click', '.delete-image', function() {
|
||||
var parent = $(this).parents('li[data-cid]'),
|
||||
inputEl = parent.find('.upload-button'),
|
||||
preview = parent.find('.preview-box'),
|
||||
|
||||
@@ -18,6 +18,7 @@ define(function() {
|
||||
};
|
||||
|
||||
Admin.updateRoomUsage = function(err, data) {
|
||||
|
||||
function getUserCountIn(room) {
|
||||
var count = 0;
|
||||
for(var user in data[room]) {
|
||||
@@ -25,27 +26,36 @@ define(function() {
|
||||
}
|
||||
return count;
|
||||
}
|
||||
var active_users = $('#active_users'),
|
||||
|
||||
var active_users = $('#active_users').html(''),
|
||||
total = 0;
|
||||
|
||||
if(!active_users.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
active_users.html('');
|
||||
|
||||
var usersHtml = '';
|
||||
var sortedData = [];
|
||||
|
||||
for (var room in data) {
|
||||
if (room !== '') {
|
||||
var count = getUserCountIn(room);
|
||||
total += count;
|
||||
usersHtml += "<div class='alert alert-success'><strong>" + room + "</strong> " + count + " active user" + (count > 1 ? "s" : "") + "</div>";
|
||||
sortedData.push({room: room, count: data[room].length});
|
||||
total += data[room].length;
|
||||
}
|
||||
}
|
||||
|
||||
sortedData.sort(function(a, b) {
|
||||
return parseInt(b.count, 10) - parseInt(a.count, 10);
|
||||
});
|
||||
|
||||
var usersHtml = '';
|
||||
for(var i=0; i<sortedData.length; ++i) {
|
||||
usersHtml += "<div class='alert alert-success'><strong>" + sortedData[i].room + "</strong> " +
|
||||
sortedData[i].count + " active user" + (sortedData[i].count > 1 ? "s" : "") + "</div>";
|
||||
}
|
||||
|
||||
active_users.html(usersHtml);
|
||||
document.getElementById('connections').innerHTML = total;
|
||||
$('#connections').html(total);
|
||||
};
|
||||
|
||||
return Admin;
|
||||
|
||||
@@ -145,7 +145,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
|
||||
loadingMoreTopics = true;
|
||||
socket.emit('categories.loadMore', {
|
||||
cid: cid,
|
||||
after: $('#topics-container').children('.category-item').length
|
||||
after: $('#topics-container').attr('data-nextstart')
|
||||
}, function (err, data) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
@@ -153,6 +153,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
|
||||
|
||||
if (data && data.topics.length) {
|
||||
Category.onTopicsLoaded(data.topics);
|
||||
$('#topics-container').attr('data-nextstart', data.nextStart);
|
||||
}
|
||||
loadingMoreTopics = false;
|
||||
});
|
||||
|
||||
@@ -86,7 +86,7 @@ define(function() {
|
||||
Recent.loadMoreTopics = function() {
|
||||
loadingMoreTopics = true;
|
||||
socket.emit('topics.loadMoreRecentTopics', {
|
||||
after: $('#topics-container').children('li').length,
|
||||
after: $('#topics-container').attr('data-nextstart'),
|
||||
term: active
|
||||
}, function(err, data) {
|
||||
if(err) {
|
||||
@@ -95,6 +95,7 @@ define(function() {
|
||||
|
||||
if (data.topics && data.topics.length) {
|
||||
Recent.onTopicsLoaded('recent', data.topics);
|
||||
$('#topics-container').attr('data-nextstart', data.nextStart);
|
||||
}
|
||||
|
||||
loadingMoreTopics = false;
|
||||
|
||||
@@ -2,9 +2,9 @@ define(function() {
|
||||
var Search = {};
|
||||
|
||||
Search.init = function() {
|
||||
var searchQuery = $('#topics-container').attr('data-search-query');
|
||||
|
||||
$('.search-result-text').each(function() {
|
||||
var searchQuery = $('#topic-results').attr('data-search-query');
|
||||
console.log(searchQuery);
|
||||
$('.search-result-text').children().each(function() {
|
||||
var text = $(this).html();
|
||||
var regex = new RegExp(searchQuery, 'gi');
|
||||
text = text.replace(regex, '<span class="label label-success">' + searchQuery + '</span>');
|
||||
|
||||
@@ -46,7 +46,7 @@ define(['forum/recent'], function(recent) {
|
||||
function loadMoreTopics() {
|
||||
loadingMoreTopics = true;
|
||||
socket.emit('topics.loadMoreUnreadTopics', {
|
||||
after: parseInt($('#topics-container').attr('data-next-start'), 10)
|
||||
after: $('#topics-container').attr('data-nextstart')
|
||||
}, function(err, data) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
@@ -54,7 +54,7 @@ define(['forum/recent'], function(recent) {
|
||||
|
||||
if (data.topics && data.topics.length) {
|
||||
recent.onTopicsLoaded('unread', data.topics);
|
||||
$('#topics-container').attr('data-next-start', data.nextStart);
|
||||
$('#topics-container').attr('data-nextstart', data.nextStart);
|
||||
} else {
|
||||
$('#load-more-btn').hide();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ define(function() {
|
||||
var notifContainer = document.getElementsByClassName('notifications')[0],
|
||||
notifTrigger = notifContainer.querySelector('a'),
|
||||
notifList = document.getElementById('notif-list'),
|
||||
notifIcon = $('.notifications a');
|
||||
notifIcon = $('.notifications a i');
|
||||
|
||||
notifTrigger.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
@@ -46,14 +46,14 @@ define(function() {
|
||||
notifList.appendChild(notifFrag);
|
||||
|
||||
if (data.unread.length > 0) {
|
||||
notifIcon.toggleClass('active', true);
|
||||
notifIcon.removeClass('fa-bell-o').addClass('fa-bell');
|
||||
} else {
|
||||
notifIcon.toggleClass('active', false);
|
||||
notifIcon.removeClass('fa-bell').addClass('fa-bell-o');
|
||||
}
|
||||
|
||||
socket.emit('modules.notifications.mark_all_read', null, function(err) {
|
||||
if (!err) {
|
||||
notifIcon.toggleClass('active', false);
|
||||
notifIcon.removeClass('fa-bell').addClass('fa-bell-o');
|
||||
app.refreshTitle();
|
||||
|
||||
// Update favicon + local count
|
||||
@@ -87,9 +87,9 @@ define(function() {
|
||||
var updateNotifCount = function(count) {
|
||||
// Update notification icon, if necessary
|
||||
if (count > 0) {
|
||||
notifIcon.toggleClass('active', true);
|
||||
notifIcon.removeClass('fa-bell-o').addClass('fa-bell');
|
||||
} else {
|
||||
notifIcon.toggleClass('active', false);
|
||||
notifIcon.removeClass('fa-bell').addClass('fa-bell-o');
|
||||
}
|
||||
|
||||
// Update the favicon + saved local count
|
||||
@@ -106,7 +106,9 @@ define(function() {
|
||||
});
|
||||
|
||||
socket.on('event:new_notification', function() {
|
||||
notifIcon.toggleClass('active', true);
|
||||
|
||||
notifIcon.removeClass('fa-bell-o').addClass('fa-bell');
|
||||
|
||||
app.alert({
|
||||
alert_id: 'new_notif',
|
||||
title: 'New notification',
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
collapseWhitespace : /\s+/g,
|
||||
collapseDash : /-+/g,
|
||||
trimTrailingDash : /-$/g,
|
||||
trimLeadingDash : /^-/g,
|
||||
isLatin : /^[\w]+$/,
|
||||
|
||||
//http://dense13.com/blog/2009/05/03/converting-string-to-slug-javascript/
|
||||
@@ -120,6 +121,7 @@
|
||||
str = str.replace(utils.collapseWhitespace, '-')
|
||||
str = str.replace(utils.collapseDash, '-');
|
||||
str = str.replace(utils.trimTrailingDash, '');
|
||||
str = str.replace(utils.trimLeadingDash, '');
|
||||
return str;
|
||||
},
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<h1><i class="fa fa-facebook-square"></i> Facebook Social Authentication</h1>
|
||||
<hr />
|
||||
|
||||
<form>
|
||||
<div class="alert alert-warning">
|
||||
<p>
|
||||
Create a <strong>Facebook Application</strong> via the
|
||||
<a href="https://developers.facebook.com/">Facebook Developers Page</a> and
|
||||
then paste your application details here.
|
||||
</p>
|
||||
<br />
|
||||
<input type="text" data-field="social:facebook:app_id" title="Application ID" class="form-control input-lg" placeholder="App ID"><br />
|
||||
<input type="text" data-field="social:facebook:secret" title="Application Secret" class="form-control input-md" placeholder="App Secret"><br />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<button class="btn btn-lg btn-primary" id="save">Save</button>
|
||||
|
||||
<script>
|
||||
require(['forum/admin/settings'], function(Settings) {
|
||||
Settings.prepare();
|
||||
});
|
||||
</script>
|
||||
@@ -1,23 +0,0 @@
|
||||
<h1><i class="fa fa-google-plus-square"></i> Google Accounts Social Authentication</h1>
|
||||
<hr />
|
||||
|
||||
<form>
|
||||
<div class="alert alert-warning">
|
||||
<p>
|
||||
Create a <strong>Google Application</strong> via the
|
||||
<a href="https://code.google.com/apis/console/">API Console</a> and then paste
|
||||
your application details here.
|
||||
</p>
|
||||
<br />
|
||||
<input type="text" data-field="social:google:id" title="Client ID" class="form-control input-lg" placeholder="Client ID"><br />
|
||||
<input type="text" data-field="social:google:secret" title="Client Secret" class="form-control" placeholder="Client Secret"><br />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<button class="btn btn-lg btn-primary" id="save">Save</button>
|
||||
|
||||
<script>
|
||||
require(['forum/admin/settings'], function(Settings) {
|
||||
Settings.prepare();
|
||||
});
|
||||
</script>
|
||||
@@ -115,9 +115,6 @@
|
||||
<div class="well sidebar-nav">
|
||||
<ul class="nav nav-list">
|
||||
<li class="nav-header">Social Authentication</li>
|
||||
<li><a href="{relative_path}/admin/twitter"><i class="fa fa-fw fa-twitter-square"></i> Twitter</a></li>
|
||||
<li><a href="{relative_path}/admin/facebook"><i class="fa fa-fw fa-facebook-square"></i> Facebook</a></li>
|
||||
<li><a href="{relative_path}/admin/gplus"><i class="fa fa-fw fa-google-plus-square"></i> Google+</a></li>
|
||||
<!-- BEGIN authentication -->
|
||||
<li>
|
||||
<a href="{relative_path}/admin{authentication.route}"><i class="fa fa-fw {authentication.icon}"></i> {authentication.name}</a>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<h1><i class="fa fa-twitter-square"></i> Twitter Social Authentication</h1>
|
||||
<hr />
|
||||
|
||||
<form>
|
||||
<div class="alert alert-warning">
|
||||
<p>
|
||||
Create a <strong>Twitter Application</strong> via the
|
||||
<a href="https://dev.twitter.com/">Twitter Developers Page</a> and then
|
||||
paste your application details here.
|
||||
</p>
|
||||
<br />
|
||||
<input type="text" data-field="social:twitter:key" title="Consumer Key" class="form-control input-lg" placeholder="Consumer Key"><br />
|
||||
<input type="text" data-field="social:twitter:secret" title="Consumer Secret" class="form-control input-md" placeholder="Consumer Secret">
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<button class="btn btn-lg btn-primary" id="save">Save</button>
|
||||
|
||||
<script>
|
||||
require(['forum/admin/settings'], function(Settings) {
|
||||
Settings.prepare();
|
||||
});
|
||||
</script>
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
<div class="category row">
|
||||
<div class="{topic_row_size}">
|
||||
<ul id="topics-container" itemscope itemtype="http://www.schema.org/ItemList">
|
||||
<ul id="topics-container" itemscope itemtype="http://www.schema.org/ItemList" data-nextstart="{nextStart}">
|
||||
<meta itemprop="itemListOrder" content="descending">
|
||||
<!-- BEGIN topics -->
|
||||
<li class="category-item {topics.deleted-class}" itemprop="itemListElement">
|
||||
|
||||
@@ -11,10 +11,7 @@
|
||||
"^admin/plugins/?$": "admin/plugins",
|
||||
"^admin/languages/?$": "admin/languages",
|
||||
"^admin/settings.*": "admin/settings",
|
||||
"^admin/twitter.*": "admin/twitter",
|
||||
"^admin/facebook.*": "admin/facebook",
|
||||
"^admin/logger.*": "admin/logger",
|
||||
"^admin/gplus.*": "admin/gplus",
|
||||
"^admin/motd/?$": "admin/motd",
|
||||
"^admin/groups/?$": "admin/groups",
|
||||
"^users/sort-posts": "users",
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
</li>
|
||||
|
||||
<li class="notifications dropdown text-center hidden-xs">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#" id="notif_dropdown"></a>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#" id="notif_dropdown"><i class="fa fa-bell-o" title="[[global:header.notifications]]"></i></a>
|
||||
<ul id="notif-list" class="dropdown-menu" aria-labelledby="notif_dropdown">
|
||||
<li>
|
||||
<a href="#"><i class="fa fa-refresh fa-spin"></i> [[global:notifications.loading]]</a>
|
||||
@@ -104,7 +104,7 @@
|
||||
</li>
|
||||
|
||||
<li class="chats dropdown text-center hidden-xs">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#" id="chat_dropdown"><i class="fa fa-comment-o"></i></a>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#" id="chat_dropdown"><i class="fa fa-comment-o" title="[[global:header.chats]]"></i></a>
|
||||
<ul id="chat-list" class="dropdown-menu" aria-labelledby="chat_dropdown">
|
||||
<li>
|
||||
<a href="#"><i class="fa fa-refresh fa-spin"></i> [[global:chats.loading]]</a>
|
||||
@@ -113,7 +113,7 @@
|
||||
</li>
|
||||
|
||||
<li id="user_label" class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#" id="user_dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#" id="user_dropdown" title="[[global:header.profile]]">
|
||||
<img src=""/>
|
||||
</a>
|
||||
<ul id="user-control-list" class="dropdown-menu" aria-labelledby="user_dropdown">
|
||||
@@ -152,7 +152,7 @@
|
||||
</li>
|
||||
|
||||
<li class="hidden-xs">
|
||||
<a href="#" id="search-button" class="hide"><i class="fa fa-search"></i></a>
|
||||
<a href="#" id="search-button" class="hide"><i class="fa fa-search" title="[[global:header.search]]"></i></a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
<div class="category row">
|
||||
<div class="col-md-12">
|
||||
<ul id="topics-container">
|
||||
<ul id="topics-container" data-nextstart="{nextStart}">
|
||||
<!-- BEGIN topics -->
|
||||
<li class="category-item {topics.deleted-class}">
|
||||
<div class="col-md-12 col-xs-12 panel panel-default topic-row">
|
||||
|
||||
@@ -13,8 +13,11 @@
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="category search">
|
||||
<div class="{show_results}">
|
||||
<div class="search favourites well">
|
||||
<div class="{show_results} row">
|
||||
|
||||
<div id="topic-results" class="col-md-12" data-search-query="{search_query}">
|
||||
|
||||
<h3>[[topic:topics]]</h3>
|
||||
|
||||
<!-- IF topic_matches -->
|
||||
@@ -22,47 +25,74 @@
|
||||
<!-- ENDIF topic_matches -->
|
||||
<div class="alert alert-info {show_no_topics}">[[topic:no_topics_found]]</div>
|
||||
|
||||
<ul id="topics-container" data-search-query="{search_query}">
|
||||
|
||||
<!-- BEGIN topics -->
|
||||
<li class="category-item">
|
||||
<a href="{relative_path}/topic/{topics.slug}" id="tid-{topics.tid}">
|
||||
<div>
|
||||
<div class="col-md-12 img-thumbnail">
|
||||
<div class="search-result-post">
|
||||
<img src="{topics.teaser_userpicture}" />
|
||||
<strong>{topics.teaser_username}</strong>: <span class="search-result-text">{topics.title}</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="topic-row panel panel-default clearfix">
|
||||
<div class="panel-body">
|
||||
<a href="../../user/{topics.userslug}">
|
||||
<img title="{topics.username}" class="img-rounded user-img" src="{topics.picture}">
|
||||
</a>
|
||||
</li>
|
||||
<!-- END topics -->
|
||||
</ul>
|
||||
|
||||
<a href="../../user/{topics.userslug}">
|
||||
<strong><span>{topics.username}</span></strong>
|
||||
</a>
|
||||
<span class="search-result-text">
|
||||
<p>{topics.title}</p>
|
||||
</span>
|
||||
|
||||
<div>
|
||||
<small>
|
||||
<span class="pull-right">
|
||||
<a href="../../topic/{topics.slug}">posted</a>
|
||||
in
|
||||
<a href="../../category/{topics.categorySlug}">
|
||||
<i class="fa {topics.categoryIcon}"></i> {topics.categoryName}
|
||||
</a>
|
||||
<span class="timeago" title="{topics.relativeTime}"></span>
|
||||
</span>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END topics -->
|
||||
</div>
|
||||
|
||||
<div id="post-results" class="col-md-12" data-search-query="{search_query}">
|
||||
<h3>Posts</h3>
|
||||
|
||||
<!-- IF post_matches -->
|
||||
<small>{post_matches} result(s) matching "{search_query}"</small>
|
||||
<!-- ENDIF post_matches -->
|
||||
<div class="alert alert-info {show_no_posts}">No posts found!</div>
|
||||
|
||||
<ul id="topics-container" data-search-query="{search_query}">
|
||||
<!-- BEGIN posts -->
|
||||
<li class="category-item">
|
||||
<a href="{relative_path}/topic/{posts.topicSlug}#{posts.pid}" id="tid-{posts.tid}">
|
||||
<div>
|
||||
<div class="col-md-12 img-thumbnail">
|
||||
<div class="search-result-post">
|
||||
<img src="{posts.picture}" />
|
||||
<strong>{posts.username}</strong>: <span class="search-result-text">{posts.content}</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="topic-row panel panel-default clearfix">
|
||||
<div class="panel-body">
|
||||
<a href="../../user/{posts.userslug}">
|
||||
<img title="{posts.username}" class="img-rounded user-img" src="{posts.picture}">
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<a href="../../user/{posts.userslug}">
|
||||
<strong><span>{posts.username}</span></strong>
|
||||
</a>
|
||||
<span class="search-result-text">
|
||||
{posts.content}
|
||||
</span>
|
||||
|
||||
<div>
|
||||
<small>
|
||||
<span class="pull-right">
|
||||
<a href="../../topic/{posts.topicSlug}#{posts.pid}">posted</a>
|
||||
in
|
||||
<a href="../../category/{posts.categorySlug}">
|
||||
<i class="fa {posts.categoryIcon}"></i> {posts.categoryName}
|
||||
</a>
|
||||
<span class="timeago" title="{posts.relativeTime}"></span>
|
||||
</span>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END posts -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<div class="category row">
|
||||
<div class="col-md-12">
|
||||
<ul id="topics-container" data-next-start="{nextStart}">
|
||||
<ul id="topics-container" data-nextstart="{nextStart}">
|
||||
<!-- BEGIN topics -->
|
||||
<li class="category-item {topics.deleted-class}">
|
||||
<div class="col-md-12 col-xs-12 panel panel-default topic-row">
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
var db = require('./database.js'),
|
||||
posts = require('./posts.js'),
|
||||
utils = require('./../public/src/utils.js'),
|
||||
user = require('./user.js'),
|
||||
topics = require('./topics.js'),
|
||||
var db = require('./database'),
|
||||
posts = require('./posts'),
|
||||
utils = require('./../public/src/utils'),
|
||||
user = require('./user'),
|
||||
topics = require('./topics'),
|
||||
plugins = require('./plugins'),
|
||||
CategoryTools = require('./categoryTools'),
|
||||
meta = require('./meta'),
|
||||
@@ -52,8 +52,8 @@ var db = require('./database.js'),
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
function getTopicIds(next) {
|
||||
Categories.getTopicIds(category_id, start, end, next);
|
||||
function getTopics(next) {
|
||||
Categories.getCategoryTopics(category_id, start, end, current_user, next);
|
||||
}
|
||||
|
||||
function getActiveUsers(next) {
|
||||
@@ -70,9 +70,12 @@ var db = require('./database.js'),
|
||||
Categories.getPageCount(category_id, next);
|
||||
}
|
||||
|
||||
async.parallel([getTopicIds, getActiveUsers, getSidebars, getPageCount], function(err, results) {
|
||||
var tids = results[0],
|
||||
active_users = results[1],
|
||||
async.parallel([getTopics, getActiveUsers, getSidebars, getPageCount], function(err, results) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var active_users = results[1],
|
||||
sidebars = results[2],
|
||||
pageCount = results[3];
|
||||
|
||||
@@ -87,27 +90,22 @@ var db = require('./database.js'),
|
||||
'topic_row_size': 'col-md-9',
|
||||
'category_id': category_id,
|
||||
'active_users': [],
|
||||
'topics': [],
|
||||
'topics': results[0].topics,
|
||||
'nextStart': results[0].nextStart,
|
||||
'pageCount': pageCount,
|
||||
'disableSocialButtons': meta.config.disableSocialButtons !== undefined ? parseInt(meta.config.disableSocialButtons, 10) !== 0 : false,
|
||||
'sidebars': sidebars
|
||||
};
|
||||
|
||||
function getTopics(next) {
|
||||
topics.getTopicsByTids(tids, category_id, current_user, next);
|
||||
}
|
||||
|
||||
function getModerators(next) {
|
||||
Categories.getModerators(category_id, next);
|
||||
}
|
||||
|
||||
function getActiveUsers(next) {
|
||||
user.getMultipleUserFields(active_users, ['uid', 'username', 'userslug', 'picture'], function(err, users) {
|
||||
next(err, users);
|
||||
});
|
||||
user.getMultipleUserFields(active_users, ['uid', 'username', 'userslug', 'picture'], next);
|
||||
}
|
||||
|
||||
if (tids.length === 0) {
|
||||
if (!category.topics.length) {
|
||||
getModerators(function(err, moderators) {
|
||||
category.moderator_block_class = moderators.length > 0 ? '' : 'none';
|
||||
category.moderators = moderators;
|
||||
@@ -116,11 +114,10 @@ var db = require('./database.js'),
|
||||
callback(null, category);
|
||||
});
|
||||
} else {
|
||||
async.parallel([getTopics, getModerators, getActiveUsers], function(err, results) {
|
||||
category.topics = results[0];
|
||||
category.moderator_block_class = results[1].length > 0 ? '' : 'none';
|
||||
category.moderators = results[1];
|
||||
category.active_users = results[2];
|
||||
async.parallel([getModerators, getActiveUsers], function(err, results) {
|
||||
category.moderator_block_class = results[0].length > 0 ? '' : 'none';
|
||||
category.moderators = results[0];
|
||||
category.active_users = results[1];
|
||||
category.show_sidebar = category.topics.length > 0 ? 'show' : 'hidden';
|
||||
callback(null, category);
|
||||
});
|
||||
@@ -131,13 +128,26 @@ var db = require('./database.js'),
|
||||
};
|
||||
|
||||
Categories.getCategoryTopics = function(cid, start, stop, uid, callback) {
|
||||
Categories.getTopicIds(cid, start, stop, function(err, tids) {
|
||||
async.waterfall([
|
||||
function(next) {
|
||||
Categories.getTopicIds(cid, start, stop, next);
|
||||
},
|
||||
function(tids, next) {
|
||||
topics.getTopicsByTids(tids, cid, uid, next);
|
||||
},
|
||||
function(topics, next) {
|
||||
db.sortedSetRevRank('categories:' + cid + ':tid', topics[topics.length - 1].tid, function(err, rank) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
return next(err);
|
||||
}
|
||||
|
||||
topics.getTopicsByTids(tids, cid, uid, callback);
|
||||
return next(null, {
|
||||
topics: topics,
|
||||
nextStart: parseInt(rank, 10) + 1
|
||||
});
|
||||
});
|
||||
}
|
||||
], callback);
|
||||
};
|
||||
|
||||
Categories.getTopicIds = function(cid, start, stop, callback) {
|
||||
|
||||
@@ -656,6 +656,23 @@
|
||||
});
|
||||
}
|
||||
|
||||
module.sortedSetRevRank = function(key, value, callback) {
|
||||
if(value !== null && value !== undefined) {
|
||||
value = value.toString();
|
||||
}
|
||||
module.getSortedSetRange(key, 0, -1, function(err, result) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
var rank = result.indexOf(value);
|
||||
if(rank === -1) {
|
||||
return callback(null, null);
|
||||
}
|
||||
|
||||
callback(null, result.length - rank - 1);
|
||||
});
|
||||
}
|
||||
|
||||
module.sortedSetScore = function(key, value, callback) {
|
||||
if(value !== null && value !== undefined) {
|
||||
value = value.toString();
|
||||
|
||||
@@ -382,6 +382,10 @@
|
||||
redisClient.zrank(key, value, callback);
|
||||
}
|
||||
|
||||
module.sortedSetRevRank = function(key, value, callback) {
|
||||
redisClient.zrevrank(key, value, callback);
|
||||
}
|
||||
|
||||
module.sortedSetScore = function(key, value, callback) {
|
||||
redisClient.zscore(key, value, callback);
|
||||
}
|
||||
|
||||
10
src/feed.js
10
src/feed.js
@@ -38,13 +38,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
var description = topicData.posts.length ? topicData.posts[0].content : '';
|
||||
var image_url = topicData.posts.length ? topicData.posts[0].picture : '';
|
||||
var author = topicData.posts.length ? topicData.posts[0].username : '';
|
||||
|
||||
var feed = new rss({
|
||||
title: topicData.topic_name,
|
||||
description: topicData.posts[0].content,
|
||||
description: description,
|
||||
feed_url: Feed.defaults.baseUrl + '/topics/' + tid + '.rss',
|
||||
site_url: nconf.get('url') + '/topic/' + topicData.slug,
|
||||
image_url: topicData.posts[0].picture,
|
||||
author: topicData.posts[0].username,
|
||||
image_url: image_url,
|
||||
author: author,
|
||||
ttl: Feed.defaults.ttl
|
||||
}),
|
||||
dateStamp;
|
||||
|
||||
127
src/login.js
127
src/login.js
@@ -1,5 +1,5 @@
|
||||
var user = require('./user'),
|
||||
bcrypt = require('bcrypt'),
|
||||
bcrypt = require('bcryptjs'),
|
||||
db = require('./database'),
|
||||
path = require('path'),
|
||||
winston = require('winston'),
|
||||
@@ -56,129 +56,4 @@ var user = require('./user'),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Login.loginViaTwitter = function(twid, handle, photos, callback) {
|
||||
user.getUidByTwitterId(twid, function(err, uid) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (uid !== null) {
|
||||
// Existing User
|
||||
callback(null, {
|
||||
uid: uid
|
||||
});
|
||||
} else {
|
||||
// New User
|
||||
user.create({username: handle}, function(err, uid) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// Save twitter-specific information to the user
|
||||
user.setUserField(uid, 'twid', twid);
|
||||
db.setObjectField('twid:uid', twid, uid);
|
||||
|
||||
// Save their photo, if present
|
||||
if (photos && photos.length > 0) {
|
||||
var photoUrl = photos[0].value;
|
||||
photoUrl = path.dirname(photoUrl) + '/' + path.basename(photoUrl, path.extname(photoUrl)).slice(0, -6) + 'bigger' + path.extname(photoUrl);
|
||||
user.setUserField(uid, 'uploadedpicture', photoUrl);
|
||||
user.setUserField(uid, 'picture', photoUrl);
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
uid: uid
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Login.loginViaGoogle = function(gplusid, handle, email, callback) {
|
||||
user.getUidByGoogleId(gplusid, function(err, uid) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (uid !== null) {
|
||||
// Existing User
|
||||
callback(null, {
|
||||
uid: uid
|
||||
});
|
||||
} else {
|
||||
// New User
|
||||
var success = function(uid) {
|
||||
// Save google-specific information to the user
|
||||
user.setUserField(uid, 'gplusid', gplusid);
|
||||
db.setObjectField('gplusid:uid', gplusid, uid);
|
||||
callback(null, {
|
||||
uid: uid
|
||||
});
|
||||
};
|
||||
|
||||
user.getUidByEmail(email, function(err, uid) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!uid) {
|
||||
user.create({username: handle, email: email}, function(err, uid) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
success(uid);
|
||||
});
|
||||
} else {
|
||||
success(uid); // Existing account -- merge
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Login.loginViaFacebook = function(fbid, name, email, callback) {
|
||||
user.getUidByFbid(fbid, function(err, uid) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (uid !== null) {
|
||||
// Existing User
|
||||
callback(null, {
|
||||
uid: uid
|
||||
});
|
||||
} else {
|
||||
// New User
|
||||
var success = function(uid) {
|
||||
// Save facebook-specific information to the user
|
||||
user.setUserField(uid, 'fbid', fbid);
|
||||
db.setObjectField('fbid:uid', fbid, uid);
|
||||
callback(null, {
|
||||
uid: uid
|
||||
});
|
||||
};
|
||||
|
||||
user.getUidByEmail(email, function(err, uid) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!uid) {
|
||||
user.create({username: name, email: email}, function(err, uid) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
success(uid);
|
||||
});
|
||||
} else {
|
||||
success(uid); // Existing account -- merge
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}(exports));
|
||||
|
||||
@@ -56,13 +56,16 @@ var db = require('./database'),
|
||||
|
||||
var messages = [];
|
||||
|
||||
userData[0].uid = touid;
|
||||
userData[1].uid = fromuid;
|
||||
|
||||
function getMessage(mid, next) {
|
||||
db.getObject('message:' + mid, function(err, message) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
Messaging.parse(message.content, message.fromuid, fromuid, userData[1], userData[0], function(result) {
|
||||
Messaging.parse(message.content, message.fromuid, fromuid, userData[1], userData[0], false, function(result) {
|
||||
message.content = result;
|
||||
messages.push(message);
|
||||
next(null);
|
||||
@@ -81,7 +84,7 @@ var db = require('./database'),
|
||||
});
|
||||
};
|
||||
|
||||
Messaging.parse = function (message, fromuid, myuid, toUserData, myUserData, callback) {
|
||||
Messaging.parse = function (message, fromuid, myuid, toUserData, myUserData, isNew, callback) {
|
||||
plugins.fireHook('filter:post.parse', message, function(err, parsed) {
|
||||
if (err) {
|
||||
return callback(message);
|
||||
@@ -104,6 +107,7 @@ var db = require('./database'),
|
||||
myuid: myuid,
|
||||
toUserData: toUserData,
|
||||
myUserData: myUserData,
|
||||
isNew: isNew,
|
||||
parsedMessage: picture + username + parsed
|
||||
};
|
||||
|
||||
|
||||
@@ -58,8 +58,7 @@ var nconf = require('nconf'),
|
||||
(function () {
|
||||
var routes = [
|
||||
'categories/active', 'categories/disabled', 'users', 'topics', 'settings', 'themes',
|
||||
'twitter', 'facebook', 'gplus', 'database', 'events', 'motd', 'groups', 'plugins',
|
||||
'languages', 'logger',
|
||||
'database', 'events', 'motd', 'groups', 'plugins', 'languages', 'logger',
|
||||
'users/latest', 'users/sort-posts', 'users/sort-reputation', 'users/search'
|
||||
];
|
||||
|
||||
@@ -409,18 +408,6 @@ var nconf = require('nconf'),
|
||||
res.json(200, {});
|
||||
});
|
||||
|
||||
app.get('/twitter', function (req, res) {
|
||||
res.json(200, {});
|
||||
});
|
||||
|
||||
app.get('/facebook', function (req, res) {
|
||||
res.json(200, {});
|
||||
});
|
||||
|
||||
app.get('/gplus', function (req, res) {
|
||||
res.json(200, {});
|
||||
});
|
||||
|
||||
app.get('/testing/categories', function (req, res) {
|
||||
res.json(200, {});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
(function(Auth) {
|
||||
var passport = require('passport'),
|
||||
passportLocal = require('passport-local').Strategy,
|
||||
passportTwitter = require('passport-twitter').Strategy,
|
||||
passportGoogle = require('passport-google-oauth').OAuth2Strategy,
|
||||
passportFacebook = require('passport-facebook').Strategy,
|
||||
login_strategies = [],
|
||||
nconf = require('nconf'),
|
||||
meta = require('../meta'),
|
||||
@@ -32,75 +29,6 @@
|
||||
});
|
||||
});
|
||||
|
||||
if (meta.config['social:twitter:key'] && meta.config['social:twitter:secret']) {
|
||||
passport.use(new passportTwitter({
|
||||
consumerKey: meta.config['social:twitter:key'],
|
||||
consumerSecret: meta.config['social:twitter:secret'],
|
||||
callbackURL: nconf.get('url') + '/auth/twitter/callback'
|
||||
}, function(token, tokenSecret, profile, done) {
|
||||
login_module.loginViaTwitter(profile.id, profile.username, profile.photos, function(err, user) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
done(null, user);
|
||||
});
|
||||
}));
|
||||
|
||||
login_strategies.push({
|
||||
name: 'twitter',
|
||||
url: '/auth/twitter',
|
||||
callbackURL: '/auth/twitter/callback',
|
||||
icon: 'twitter',
|
||||
scope: ''
|
||||
});
|
||||
}
|
||||
|
||||
if (meta.config['social:google:id'] && meta.config['social:google:secret']) {
|
||||
passport.use(new passportGoogle({
|
||||
clientID: meta.config['social:google:id'],
|
||||
clientSecret: meta.config['social:google:secret'],
|
||||
callbackURL: nconf.get('url') + '/auth/google/callback'
|
||||
}, function(accessToken, refreshToken, profile, done) {
|
||||
login_module.loginViaGoogle(profile.id, profile.displayName, profile.emails[0].value, function(err, user) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
done(null, user);
|
||||
});
|
||||
}));
|
||||
|
||||
login_strategies.push({
|
||||
name: 'google',
|
||||
url: '/auth/google',
|
||||
callbackURL: '/auth/google/callback',
|
||||
icon: 'google-plus',
|
||||
scope: 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email'
|
||||
});
|
||||
}
|
||||
|
||||
if (meta.config['social:facebook:app_id'] && meta.config['social:facebook:secret']) {
|
||||
passport.use(new passportFacebook({
|
||||
clientID: meta.config['social:facebook:app_id'],
|
||||
clientSecret: meta.config['social:facebook:secret'],
|
||||
callbackURL: nconf.get('url') + '/auth/facebook/callback'
|
||||
}, function(accessToken, refreshToken, profile, done) {
|
||||
login_module.loginViaFacebook(profile.id, profile.displayName, profile.emails[0].value, function(err, user) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
done(null, user);
|
||||
});
|
||||
}));
|
||||
|
||||
login_strategies.push({
|
||||
name: 'facebook',
|
||||
url: '/auth/facebook',
|
||||
callbackURL: '/auth/facebook/callback',
|
||||
icon: 'facebook',
|
||||
scope: 'email'
|
||||
});
|
||||
}
|
||||
|
||||
passport.serializeUser(function(user, done) {
|
||||
done(null, user.uid);
|
||||
});
|
||||
|
||||
@@ -75,12 +75,12 @@ var DebugRoute = function(app) {
|
||||
|
||||
app.get('/test', function(req, res) {
|
||||
|
||||
/*topics.getTopicPosts2(2, 0, 10, 5, function(err, data) {
|
||||
res.json(data);
|
||||
})*/
|
||||
topics.getTopicWithPosts(2, 1, 0, -1, true, function (err, topicData) {
|
||||
res.json(topicData);
|
||||
var db = require('./../database');
|
||||
|
||||
db.getSortedSetRevRange('topics:recent', 0 , -1, function(err, tids) {
|
||||
res.json(tids);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -18,14 +18,10 @@ SocketCategories.loadMore = function(socket, data, callback) {
|
||||
|
||||
var topicsPerPage = parseInt(meta.config.topicsPerPage, 10) || 20;
|
||||
|
||||
var start = data.after,
|
||||
var start = parseInt(data.after, 10),
|
||||
end = start + topicsPerPage - 1;
|
||||
|
||||
categories.getCategoryTopics(data.cid, start, end, socket.uid, function(err, topics) {
|
||||
callback(err, {
|
||||
topics: topics
|
||||
});
|
||||
});
|
||||
categories.getCategoryTopics(data.cid, start, end, socket.uid, callback);
|
||||
};
|
||||
|
||||
SocketCategories.getPageCount = function(socket, cid, callback) {
|
||||
|
||||
@@ -22,12 +22,11 @@ var SocketIO = require('socket.io'),
|
||||
|
||||
/* === */
|
||||
|
||||
var users = {},
|
||||
io;
|
||||
|
||||
var io;
|
||||
|
||||
|
||||
Sockets.userSockets = {};
|
||||
Sockets.rooms = {};
|
||||
|
||||
|
||||
Sockets.init = function(server) {
|
||||
@@ -59,9 +58,9 @@ Sockets.init = function(server) {
|
||||
sessionID = socket.handshake.signedCookies["express.sid"];
|
||||
db.sessionStore.get(sessionID, function(err, sessionData) {
|
||||
if (!err && sessionData && sessionData.passport && sessionData.passport.user) {
|
||||
uid = users[sessionID] = sessionData.passport.user;
|
||||
uid = sessionData.passport.user;
|
||||
} else {
|
||||
uid = users[sessionID] = 0;
|
||||
uid = 0;
|
||||
}
|
||||
|
||||
socket.uid = parseInt(uid, 10);
|
||||
@@ -110,8 +109,8 @@ Sockets.init = function(server) {
|
||||
}
|
||||
|
||||
if (Sockets.userSockets[uid] && Sockets.userSockets[uid].length === 0) {
|
||||
delete users[sessionID];
|
||||
delete Sockets.userSockets[uid];
|
||||
|
||||
if (uid) {
|
||||
db.sortedSetRemove('users:online', uid, function(err, data) {
|
||||
});
|
||||
@@ -126,17 +125,10 @@ Sockets.init = function(server) {
|
||||
|
||||
emitOnlineUserCount();
|
||||
|
||||
for (var roomName in Sockets.rooms) {
|
||||
if (Sockets.rooms.hasOwnProperty(roomName)) {
|
||||
socket.leave(roomName);
|
||||
|
||||
if (Sockets.rooms[roomName][socket.id]) {
|
||||
delete Sockets.rooms[roomName][socket.id];
|
||||
for(var roomName in io.sockets.manager.roomClients[socket.id]) {
|
||||
updateRoomBrowsingText(roomName.slice(1));
|
||||
}
|
||||
|
||||
updateRoomBrowsingText(roomName);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('*', function(payload, callback) {
|
||||
@@ -222,9 +214,10 @@ function updateRoomBrowsingText(roomName) {
|
||||
|
||||
function getUidsInRoom(room) {
|
||||
var uids = [];
|
||||
for (var socketId in room) {
|
||||
if (uids.indexOf(room[socketId]) === -1) {
|
||||
uids.push(room[socketId]);
|
||||
var clients = io.sockets.clients(roomName);
|
||||
for(var i=0; i<clients.length; ++i) {
|
||||
if (uids.indexOf(clients[i].uid) === -1 && clients[i].uid !== 0) {
|
||||
uids.push(clients[i].uid);
|
||||
}
|
||||
}
|
||||
return uids;
|
||||
@@ -235,15 +228,14 @@ function updateRoomBrowsingText(roomName) {
|
||||
var anonCount = 0;
|
||||
|
||||
for (var i = 0; i < clients.length; ++i) {
|
||||
var hs = clients[i].handshake;
|
||||
if (hs && clients[i].state && clients[i].state.user.uid === 0) {
|
||||
if(clients[i].uid === 0) {
|
||||
++anonCount;
|
||||
}
|
||||
}
|
||||
return anonCount;
|
||||
}
|
||||
|
||||
var uids = getUidsInRoom(Sockets.rooms[roomName]),
|
||||
var uids = getUidsInRoom(roomName),
|
||||
anonymousCount = getAnonymousCount(roomName);
|
||||
|
||||
user.getMultipleUserFields(uids, ['uid', 'username', 'userslug', 'picture'], function(err, users) {
|
||||
|
||||
@@ -84,18 +84,6 @@ SocketMeta.rooms.enter = function(socket, data) {
|
||||
}
|
||||
|
||||
socket.join(data.enter);
|
||||
server.rooms[data.enter] = server.rooms[data.enter] || {};
|
||||
|
||||
if (socket.uid) {
|
||||
server.rooms[data.enter][socket.id] = socket.uid;
|
||||
|
||||
if (data.leave && server.rooms[data.leave] && server.rooms[data.leave][socket.id] && data.enter !== data.leave) {
|
||||
delete server.rooms[data.leave][socket.id];
|
||||
if(!Object.keys(server.rooms[data.leave]).length) {
|
||||
delete server.rooms[data.leave];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.leave) {
|
||||
module.parent.exports.updateRoomBrowsingText(data.leave);
|
||||
@@ -104,12 +92,12 @@ SocketMeta.rooms.enter = function(socket, data) {
|
||||
module.parent.exports.updateRoomBrowsingText(data.enter);
|
||||
|
||||
if (data.enter != 'admin') {
|
||||
server.in('admin').emit('event:meta.rooms.update', null, server.rooms);
|
||||
server.in('admin').emit('event:meta.rooms.update', null, server.server.sockets.manager.rooms);
|
||||
}
|
||||
};
|
||||
|
||||
SocketMeta.rooms.getAll = function(socket, data, callback) {
|
||||
callback(null, server.rooms);
|
||||
callback(null, server.server.sockets.manager.rooms);
|
||||
};
|
||||
|
||||
/* Exports */
|
||||
|
||||
@@ -109,7 +109,11 @@ SocketModules.chats.send = function(socket, data) {
|
||||
});
|
||||
});
|
||||
}
|
||||
Messaging.parse(msg, socket.uid, socket.uid, usersData[1], usersData[0], function(parsed) {
|
||||
|
||||
usersData[0].uid = socket.uid;
|
||||
usersData[1].uid = touid;
|
||||
|
||||
Messaging.parse(msg, socket.uid, socket.uid, usersData[1], usersData[0], true, function(parsed) {
|
||||
Messaging.addMessage(socket.uid, touid, msg, function(err, message) {
|
||||
var numSockets = 0,
|
||||
x;
|
||||
|
||||
@@ -236,7 +236,7 @@ SocketTopics.loadMore = function(socket, data, callback) {
|
||||
var postsPerPage = parseInt(meta.config.postsPerPage, 10);
|
||||
postsPerPage = postsPerPage ? postsPerPage : 20;
|
||||
|
||||
var start = data.after,
|
||||
var start = parseInt(data.after, 10),
|
||||
end = start + postsPerPage - 1;
|
||||
|
||||
async.parallel({
|
||||
@@ -256,14 +256,14 @@ SocketTopics.loadMoreRecentTopics = function(socket, data, callback) {
|
||||
return callback(new Error('invalid data'));
|
||||
}
|
||||
|
||||
var start = data.after,
|
||||
var start = parseInt(data.after, 10),
|
||||
end = start + 9;
|
||||
|
||||
topics.getLatestTopics(socket.uid, start, end, data.term, callback);
|
||||
};
|
||||
|
||||
SocketTopics.loadMoreUnreadTopics = function(socket, data, callback) {
|
||||
var start = data.after,
|
||||
var start = parseInt(data.after, 10),
|
||||
end = start + 9;
|
||||
|
||||
topics.getUnreadTopics(socket.uid, start, end, callback);
|
||||
|
||||
@@ -426,8 +426,9 @@ var async = require('async'),
|
||||
};
|
||||
|
||||
var since = terms['day'];
|
||||
if(terms[term])
|
||||
if(terms[term]) {
|
||||
since = terms[term];
|
||||
}
|
||||
|
||||
var args = ['topics:recent', '+inf', timestamp - since, 'LIMIT', start, end - start + 1];
|
||||
db.getSortedSetRevRangeByScore(args, function(err, tids) {
|
||||
@@ -442,23 +443,29 @@ var async = require('async'),
|
||||
|
||||
if (!tids || !tids.length) {
|
||||
latestTopics.no_topics_message = 'show';
|
||||
callback(err, latestTopics);
|
||||
return;
|
||||
return callback(null, latestTopics);
|
||||
}
|
||||
|
||||
// Filter out topics that belong to categories that this user cannot access
|
||||
async.filter(tids, function(tid, next) {
|
||||
threadTools.privileges(tid, current_user, function(err, privileges) {
|
||||
if (!err && privileges.read) {
|
||||
next(true);
|
||||
} else {
|
||||
next(false);
|
||||
}
|
||||
next(!err && privileges.read);
|
||||
});
|
||||
}, function(tids) {
|
||||
Topics.getTopicsByTids(tids, 0, current_user, function(err, topicData) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if(!topicData || !topicData.length) {
|
||||
latestTopics.no_topics_message = 'show';
|
||||
return callback(null, latestTopics);
|
||||
}
|
||||
|
||||
db.sortedSetRevRank('topics:recent', topicData[topicData.length - 1].tid, function(err, rank) {
|
||||
latestTopics.nextStart = parseInt(rank,10) + 1;
|
||||
latestTopics.topics = topicData;
|
||||
callback(err, latestTopics);
|
||||
callback(null, latestTopics);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -538,7 +545,7 @@ var async = require('async'),
|
||||
return parseInt(read[index], 10) === 0;
|
||||
});
|
||||
|
||||
// Filter out topics that belong to categories that this user cannot access
|
||||
|
||||
async.filter(newtids, function(tid, next) {
|
||||
threadTools.privileges(tid, uid, function(err, privileges) {
|
||||
if (!err && privileges.read) {
|
||||
@@ -588,8 +595,14 @@ var async = require('async'),
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
db.sortedSetRevRank('topics:recent', topicData[topicData.length - 1].tid, function(err, rank) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
unreadTopics.topics = topicData;
|
||||
unreadTopics.nextStart = stop + 1;
|
||||
unreadTopics.nextStart = parseInt(rank, 10) + 1;
|
||||
|
||||
if (!topicData || topicData.length === 0) {
|
||||
unreadTopics.no_topics_message = 'show';
|
||||
}
|
||||
@@ -599,6 +612,7 @@ var async = require('async'),
|
||||
|
||||
callback(null, unreadTopics);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Topics.getUnreadTids(uid, start, stop, function(err, unreadTids) {
|
||||
@@ -700,6 +714,7 @@ var async = require('async'),
|
||||
|
||||
function isTopicVisible(topicData, topicInfo) {
|
||||
var deleted = parseInt(topicData.deleted, 10) !== 0;
|
||||
|
||||
return !deleted || (deleted && topicInfo.privileges.view_deleted) || topicData.uid === current_user;
|
||||
}
|
||||
|
||||
|
||||
37
src/user.js
37
src/user.js
@@ -1,4 +1,4 @@
|
||||
var bcrypt = require('bcrypt'),
|
||||
var bcrypt = require('bcryptjs'),
|
||||
async = require('async'),
|
||||
nconf = require('nconf'),
|
||||
winston = require('winston'),
|
||||
@@ -742,33 +742,6 @@ var bcrypt = require('bcrypt'),
|
||||
});
|
||||
};
|
||||
|
||||
User.getUidByTwitterId = function(twid, callback) {
|
||||
db.getObjectField('twid:uid', twid, function(err, uid) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
callback(null, uid);
|
||||
});
|
||||
};
|
||||
|
||||
User.getUidByGoogleId = function(gplusid, callback) {
|
||||
db.getObjectField('gplusid:uid', gplusid, function(err, uid) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
callback(null, uid);
|
||||
});
|
||||
};
|
||||
|
||||
User.getUidByFbid = function(fbid, callback) {
|
||||
db.getObjectField('fbid:uid', fbid, function(err, uid) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
callback(null, uid);
|
||||
});
|
||||
};
|
||||
|
||||
User.isModerator = function(uid, cid, callback) {
|
||||
db.isSetMember('cid:' + cid + ':moderators', uid, function(err, exists) {
|
||||
if(err) {
|
||||
@@ -926,11 +899,12 @@ var bcrypt = require('bcrypt'),
|
||||
confirm: function(code, callback) {
|
||||
db.getObject('confirm:' + code, function(err, confirmObj) {
|
||||
if (err) {
|
||||
callback({
|
||||
return callback({
|
||||
status:'error'
|
||||
});
|
||||
} else {
|
||||
if (confirmObj.uid && confirmObj.email) {
|
||||
}
|
||||
|
||||
if (confirmObj && confirmObj.uid && confirmObj.email) {
|
||||
db.setObjectField('email:confirmed', confirmObj.email, '1', function() {
|
||||
callback({
|
||||
status: 'ok'
|
||||
@@ -941,7 +915,6 @@ var bcrypt = require('bcrypt'),
|
||||
status: 'not_ok'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -43,9 +43,9 @@ describe('Categories', function() {
|
||||
|
||||
describe('.getCategoryTopics', function() {
|
||||
it('should return a list of topics', function(done) {
|
||||
Categories.getCategoryTopics(categoryObj.cid, 0, 10, 0, function(err, topics) {
|
||||
assert(Array.isArray(topics));
|
||||
assert(topics.every(function(topic) {
|
||||
Categories.getCategoryTopics(categoryObj.cid, 0, 10, 0, function(err, result) {
|
||||
assert(Array.isArray(result.topics));
|
||||
assert(result.topics.every(function(topic) {
|
||||
return topic instanceof Object;
|
||||
}));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user