Merge branch 'master' into nodebb-loader

v1.18.x
Julian Lam 11 years ago
commit 4ef1d83acd

@ -1,4 +1,6 @@
# <img alt="NodeBB" src="http://i.imgur.com/3yj1n6N.png" />
![Dependency Management powered by David.](https://david-dm.org/designcreateplay/NodeBB.png)
**NodeBB Forum Software** is powered by Node.js and built on a Redis database. It utilizes web sockets for instant interactions and real-time notifications. NodeBB is compatible down to IE8 and has many modern features out of the box such as social network integration and streaming discussions.
* [Get NodeBB](http://www.nodebb.org/ "NodeBB")
@ -11,7 +13,7 @@
* [Get Plugins](http://community.nodebb.org/category/7/nodebb-plugins "NodeBB Plugins")
* [Get Themes](http://community.nodebb.org/category/10/nodebb-themes "NodeBB Themes")
## Screenshots
## Screenshots
[<img src="http://i.imgur.com/FLOUuIqb.png" />](http://i.imgur.com/FLOUuIq.png)&nbsp;[<img src="http://i.imgur.com/Ud1LrfIb.png" />](http://i.imgur.com/Ud1LrfI.png)&nbsp;[<img src="http://i.imgur.com/ZC8W39ab.png" />](http://i.imgur.com/ZC8W39a.png)&nbsp;[<img src="http://i.imgur.com/o90kVPib.png" />](http://i.imgur.com/o90kVPi.png)&nbsp;[<img src="http://i.imgur.com/AaRRrU2b.png" />](http://i.imgur.com/AaRRrU2.png)&nbsp;[<img src="http://i.imgur.com/LmHtPhob.png" />](http://i.imgur.com/LmHtPho.png)&nbsp;[<img src="http://i.imgur.com/paiJPJkb.jpg" />](http://i.imgur.com/paiJPJk.jpg)&nbsp;[<img src="http://i.imgur.com/ZfavPHDb.png" />](http://i.imgur.com/ZfavPHD.png)

@ -232,7 +232,7 @@ function reset() {
winston.info("Successfully reset theme to Vanilla and disabled all plugins.");
}
process.exit();
process.exit();
});
});
});

@ -16,13 +16,8 @@
"socket.io": "~0.9.16",
"express": "3.2.0",
"express-namespace": "~0.1.1",
"emailjs": "0.3.4",
"cookie": "0.0.6",
"passport": "0.1.17",
"passport": "~0.2.0",
"passport-local": "0.1.6",
"passport-twitter": "0.1.5",
"passport-google-oauth": "0.1.5",
"passport-facebook": "0.1.5",
"less-middleware": "0.1.12",
"marked": "0.2.8",
"async": "~0.2.8",
@ -30,35 +25,31 @@
"gravatar": "1.0.6",
"nconf": "~0.6.7",
"sitemap": "~0.7.1",
"request": "~2.25.0",
"reds": "~0.2.4",
"winston": "~0.7.2",
"rss": "~0.2.0",
"prompt": "~0.2.11",
"uglify-js": "~2.4.0",
"validator": "~3.2.1",
"nodebb-plugin-mentions": "~0.4",
"nodebb-plugin-markdown": "~0.3",
"nodebb-widget-essentials": "~0.0",
"nodebb-theme-vanilla": "~0.0.14",
"nodebb-theme-cerulean": "~0.0.13",
"nodebb-theme-lavender": "~0.0.21",
"cron": "~1.0.1",
"semver": "~2.2.1",
"string": "~1.7.0",
"xregexp": "~2.0.0",
"socket.io-wildcard": "~0.1.1",
"bcryptjs": "~0.7.10"
"bcryptjs": "~0.7.10",
"nodebb-plugin-mentions": "~0.4",
"nodebb-plugin-markdown": "~0.3",
"nodebb-widget-essentials": "~0.0",
"nodebb-theme-vanilla": "~0.0.14",
"nodebb-theme-cerulean": "~0.0.13",
"nodebb-theme-lavender": "~0.0.21"
},
"optionalDependencies": {
"redis": "0.8.3",
"mongodb": "~1.3.19",
"connect-redis": "1.4.5",
"connect-mongo": "0.4.0",
"hiredis": "~0.1.15",
"nodebb-plugin-sso-facebook": "~0.1.0",
"nodebb-plugin-sso-twitter": "~0.1.0",
"nodebb-plugin-sso-google": "~0.1.0"
"connect-redis": "1.4.5",
"mongodb": "~1.3.19",
"connect-mongo": "0.4.0"
},
"devDependencies": {
"mocha": "~1.13.0"
@ -69,7 +60,7 @@
"engines": {
"node": ">=0.8"
},
"contributors": [
"maintainers": [
{
"name": "Andrew Rodrigues",
"email": "andrew@designcreateplay.com",
@ -84,22 +75,6 @@
"name": "Barış Soner Uşaklı",
"email": "baris@designcreateplay.com",
"url": "https://github.com/barisusakli"
},
{
"name": "Andrew Darqui",
"url": "https://github.com/adarqui"
},
{
"name": "Damian Bushong",
"url": "https://github.com/damianb"
},
{
"name": "Matt Smith",
"url": "https://github.com/soimafreak"
},
{
"name": "Quinton Marchi",
"url": "https://github.com/iamcardinal"
}
]
}

@ -13,6 +13,7 @@
"reply": "Reply",
"edit": "Edit",
"delete": "Delete",
"restore": "Restore",
"move": "Move",
"fork": "Fork",
"banned": "banned",

@ -9,6 +9,6 @@
"posted": "posted",
"browsing": "viendo ahora",
"no_replies": "Nadie ha respondido aún",
"replied": "respondio",
"replied": "respondió",
"last_edited_by": "ultima edición por"
}

@ -2,6 +2,6 @@
"stats.online": "Online",
"stats.users": "Gente",
"stats.topics": "Temas",
"stats.posts": "Posts",
"success": "exito!"
"stats.posts": "Publicaciones",
"success": "éxito!"
}

@ -4,23 +4,23 @@
"buttons.close": "Cerrar",
"403.title": "Acceso denegado",
"403.message": "Al parecer no tienes premisos necesarios para estar en este lugar. Tal vez puedes <a href='/login'>intentar conectarte</a>?",
"404.title": "Ups... 404, no se encontra che!",
"404.title": "Ups... 404, no se encontró lo que buscabas!",
"404.message": "Al parecer lo que estas buscando no existe. Te recomendamos que vuelvas al <a href='/''>inicio</a>.",
"500.title": "Error Interno.",
"500.message": "Ooops! Algo salio mal!, No te alarmes. Nuestros simios hiperinteligentes lo solucionarán",
"register": "Registrarse",
"login": "Conectarse",
"welcome_back": "Bienvenido de nuevo !",
"welcome_back": "Bienvenido de nuevo!",
"you_have_successfully_logged_in": "Te has conectado!",
"logout": "Salir",
"logout.title": "Te has desconectado.",
"logout.message": "Haz sido desconectado correctamente",
"logout.message": "Has sido desconectado correctamente",
"save_changes": "Guardar Cambios",
"close": "Cerrar",
"pagination": "Paginación",
"header.admin": "Admin",
"header.admin": "Administración",
"header.recent": "Recientes",
"header.unread": "No Leeidos",
"header.unread": "No Leídos",
"header.popular": "Popular",
"header.users": "Miembros",
"header.chats": "Chats",
@ -29,28 +29,28 @@
"header.profile": "Perfil",
"notifications.loading": "Cargando Notificaciones",
"chats.loading": "Cargando Chats",
"motd.welcome": "Bienvenido a NodeBB, la plataforma de debate sobre el futuro.",
"motd.welcome": "Bienvenido a NodeBB, la plataforma de debate del el futuro.",
"motd.get": "Obtener NodeBB",
"motd.fork": "Fork",
"motd.fork": "Bifurcación",
"motd.like": "Me gusta",
"motd.follow": "Seguir",
"previouspage": "Pagina Anterior",
"nextpage": "Siguente Pagina",
"alert.success": "Exito!",
"previouspage": "Página Anterior",
"nextpage": "Siguente Página",
"alert.success": "Éxito!",
"alert.error": "Error",
"alert.banned": "Banneado",
"alert.banned.message": "Estas banneado, seras desconectado!",
"alert.unfollow": "Ya no estas siguiendo a %1!",
"alert.follow": "Estas siguiendo a %1!",
"posts": "Posts",
"alert.banned": "Baneado",
"alert.banned.message": "Estás baneado, serás desconectado!",
"alert.unfollow": "Ya no estás siguiendo a %1!",
"alert.follow": "Estás siguiendo a %1!",
"posts": "Publicaciones",
"views": "Visitas",
"posted": "publicado",
"in": "en",
"recentposts": "Posteos Recientes",
"recentposts": "Publicaciones Recientes",
"online": "Conectado",
"away": "No disponible",
"dnd": "No molestar",
"invisible": "Invisible",
"offline": "Desconectado",
"privacy": "Privacidad"
}
}

@ -5,6 +5,6 @@
"remember_me": "Recordarme?",
"forgot_password": "Olvidaste tu contraseña?",
"alternative_logins": "Conexiones Alternativas",
"failed_login_attempt": "Error al loguearte, intenta de nuevo.",
"login_successful": "Te has conectado con exito!"
"failed_login_attempt": "Error al iniciar sesión, intenta otra vez.",
"login_successful": "Te has conectado con éxito!"
}

@ -1,6 +1,6 @@
{
"chat.chatting_with": "Chatear con <span id='chat-with-name'></span>",
"chat.placeholder": "ingresa tu mensaje aqui, y presiona enter para enviar",
"chat.placeholder": "ingresa tu mensaje aquí, y presiona Intro para enviar",
"chat.send": "Enviar",
"chat.no_active": "No tiene conversaciones activas."
}

@ -3,7 +3,7 @@
"no_notifs": "No tiene nuevas notificaciones",
"see_all": "Ver todas las notificaciones",
"back_to_home": "Volver al Inicio",
"outgoing_link": "Link Externo",
"outgoing_link": "Enlace Externo",
"outgoing_link_message": "Estas saliendo del sitio",
"continue_to": "Continuar",
"return_to": "Volver a "

@ -1,13 +1,13 @@
{
"home": "Home",
"unread": "Unread Topics",
"popular": "Popular Topics",
"recent": "Recent Topics",
"users": "Registered Users",
"notifications": "Notifications",
"user.edit": "Editing \"%1\"",
"user.following": "People %1 Follows",
"user.followers": "People who Follow %1",
"user.favourites": "%1's Favourite Posts",
"user.settings": "User Settings"
"home": "Inicio",
"unread": "Temas No Leídos",
"popular": "Temas Populares",
"recent": "Temas Recientes",
"users": "Usuarios Registrado",
"notifications": "Notificaciones",
"user.edit": "Editando \"%1\"",
"user.following": "Gente que sigue %1 ",
"user.followers": "Seguidores de %1",
"user.favourites": "Publicaciones favoritas de %1 ",
"user.settings": "Preferencias del Usuario"
}

@ -3,5 +3,5 @@
"day": "Día",
"week": "Semana",
"month": "Mes",
"no_recent_topics": "No hay posts recientes"
"no_recent_topics": "No hay publicaciones recientes"
}

@ -1,10 +1,10 @@
{
"register": "Registrase",
"help.email": "Por defecto, tu email será oculto al publico.",
"help.username_restrictions": "El nombre de usuario debe tener entre %1 y %2 caracteres. Los miembros pueden responderte escribiendo @<span id='yourUsername'>usuario</span>.",
"help.minimum_password_length": "Tu contraseña debe tener al menos %1 caracteres.",
"email_address": "Email",
"email_address_placeholder": "Escribe tu email",
"help.email": "Por defecto, tu cuenta de correo electrónico será oculto al publico.",
"help.username_restrictions": "El nombre de usuario debe tener entre %1 y %2 carácteres. Los miembros pueden responderte escribiendo @<span id='yourUsername'>usuario</span>.",
"help.minimum_password_length": "Tu contraseña debe tener al menos %1 carácteres.",
"email_address": "Correo electrónico",
"email_address_placeholder": "Escribe tu correo electrónico",
"username": "Usuario",
"username_placeholder": "Escribe tu usuario",
"password": "Contraseña",
@ -12,7 +12,7 @@
"confirm_password": "Confirmar Contraseña",
"confirm_password_placeholder": "Confirmar Contraseña",
"register_now_button": "Registrarme ahora",
"alternative_registration": "Otros metodos interesantes para registrarse",
"alternative_registration": "Otros métodos interesantes para registrarse",
"terms_of_use": "Términos y Condiciones de uso",
"agree_to_terms_of_use": "Acepto los Terminos y condiciones de uso"
"agree_to_terms_of_use": "Acepto los Términos y Condiciones de uso"
}

@ -1,13 +1,13 @@
{
"reset_password": "Resetear Contraseña",
"reset_password": "Reiniciar Contraseña",
"update_password": "Actualizar contraseña",
"password_changed.title": "Contraseña editada",
"password_changed.message": "<p>La contraseña fue modificada con exito, por favor <a href=\"/login\">conectate de nuevo</a>.",
"wrong_reset_code.title": "Código de Reseteo Incorrecto",
"wrong_reset_code.message": "El código de reseteo ingresado no es correcto. Por favor intentalo de nuevo o <a href=\"/reset\">pide un nuevo código</a>.",
"password_changed.message": "<p>La contraseña fue modificada con éxito, por favor <a href=\"/login\">inicia sesión de nuevo</a>.",
"wrong_reset_code.title": "Código de reinicio Incorrecto",
"wrong_reset_code.message": "El código de reinicio ingresado no es correcto. Por favor inténtalo de nuevo o <a href=\"/reset\">pide un nuevo código</a>.",
"new_password": "Nueva Contraseña",
"repeat_password": "Confirmar Contraseña",
"enter_email": "Por favor ingresa tu <strong>email</strong> y te enviaremos un email de como resetear tu cuenta.",
"password_reset_sent": "Resteo de contraseña enviado",
"invalid_email": "Email Invalido o no existe!"
"enter_email": "Por favor ingresa tu <strong>correo electrónico</strong> y te enviaremos un correo con indicaciones para inicializar tu cuenta.",
"password_reset_sent": "Reinicio de contraseña enviado",
"invalid_email": "Correo Electrónico no válido o inexistente!"
}

@ -2,62 +2,62 @@
"topic": "Tema",
"topics": "Temas",
"no_topics_found": "No se encontraron temas!",
"no_posts_found": "No se encontraron posts!",
"no_posts_found": "No se encontraron publicaciones!",
"profile": "Perfil",
"posted_by": "Publicado por",
"chat": "Chat",
"notify_me": "Seras notificado cuando haya nuevas respuestas en este tema",
"notify_me": "Serás notificado cuando haya nuevas respuestas en este tema",
"quote": "Citar",
"reply": "Responder",
"edit": "Editar",
"delete": "Borrar",
"move": "Mover",
"fork": "Forkear",
"banned": "banneado",
"fork": "Bifurcar",
"banned": "baneado",
"link": "Link",
"share": "Compartir",
"tools": "Herramientas",
"flag": "Reportar",
"flag_title": "Reportar este post a los moderadores",
"flag_title": "Reportar esta publicación a los moderadores",
"deleted_message": "Este tema ha sido borrado. Solo los miembros con privilegios pueden verlo.",
"watch": "Seguir",
"share_this_post": "Compartir este post",
"thread_tools.title": "Herramientas del Tema",
"thread_tools.markAsUnreadForAll": "Marcar como no leido",
"thread_tools.markAsUnreadForAll": "Marcar como no leído",
"thread_tools.pin": "Tema Importante",
"thread_tools.unpin": "Quitar Importante",
"thread_tools.lock": "Cerrar Tema",
"thread_tools.unlock": "Abrir Tema",
"thread_tools.move": "Mover Tema",
"thread_tools.fork": "Fork Topic",
"thread_tools.fork": "Bifurcar Tema",
"thread_tools.delete": "Borrar Tema",
"thread_tools.restore": "Restaurar Tema",
"load_categories": "Cargando Categorias",
"disabled_categories_note": "Las categorías deshabilidas estan en gris",
"load_categories": "Cargando Categorías",
"disabled_categories_note": "Las categorías deshabilitadas estan en gris",
"confirm_move": "Mover",
"confirm_fork": "Forkear",
"confirm_fork": "Bifurcar",
"favourite": "Favorito",
"favourites": "Favoritos",
"favourites.not_logged_in.title": "No estas conectado :(",
"favourites.not_logged_in.message": "Por favor, conectate para agregar a favorito este post.",
"favourites.has_no_favourites": "No tienes favoritos, puedes agregar alguno y volver a verlos aqui!",
"vote.not_logged_in.title": "No estas conectado",
"vote.not_logged_in.message": "Por favor conectate para votar...",
"vote.cant_vote_self.title": "Voto Invalido",
"vote.cant_vote_self.message": "No puedes votar tus propios posts, palurdo!",
"loading_more_posts": "Cargando más posts",
"favourites.not_logged_in.title": "No estás conectado :(",
"favourites.not_logged_in.message": "Por favor, conáctate para agregar a favoritos esta publicación.",
"favourites.has_no_favourites": "No tienes favoritos, puedes agregar alguno y volver a verlos aquí!",
"vote.not_logged_in.title": "No estás conectado",
"vote.not_logged_in.message": "Por favor conéctate para votar...",
"vote.cant_vote_self.title": "Voto Inválido",
"vote.cant_vote_self.message": "No puedes votar tus propias publicaciones!",
"loading_more_posts": "Cargando más publicaciones",
"move_topic": "Mover Tema",
"move_post": "Mover post",
"fork_topic": "Forkear Tema",
"topic_will_be_moved_to": "Este tema sera movido a la categoría",
"fork_topic_instruction": "Click en los posts que quieres forkear",
"fork_no_pids": "No seleccionaste posts!",
"fork_success": "Forkeado con exito!",
"move_post": "Mover Publicación",
"fork_topic": "Bifurcar Tema",
"topic_will_be_moved_to": "Este tema será movido a la categoría",
"fork_topic_instruction": "Click en las publicaciones que quieres bifurcar",
"fork_no_pids": "No seleccionaste publicaciones!",
"fork_success": "Bifurcado con exito!",
"reputation": "Reputación",
"posts": "Posts",
"posts": "Publicaciones",
"composer.title_placeholder": "Ingresa el titulo de tu tema",
"composer.write": "Escribe",
"composer.preview": "Preview",
"composer.preview": "Previsualización",
"composer.discard": "Descartar",
"composer.submit": "Enviar",
"composer.replying_to": "Respondiendo a",

@ -1,6 +1,6 @@
{
"title": "No leeido",
"title": "No leído",
"no_unread_topics": "No hay temas nuevos para leer.",
"mark_all_read": "Marcar todo como leeido",
"mark_all_read": "Marcar todo como leído",
"load_more": "Cargar más"
}

@ -1,18 +1,18 @@
{
"banned": "Banneado",
"banned": "Baneado",
"offline": "Desconectado",
"username": "Usuario",
"email": "Email",
"email": "Correo Electrónico",
"fullname": "Nombre",
"website": "Website",
"website": "Sitio Web",
"location": "Ubicación",
"age": "Edad",
"joined": "Registro",
"lastonline": "Última vez online",
"lastonline": "Última vez conectado",
"profile": "Perfil",
"profile_views": "Visitas",
"reputation": "Reputación",
"posts": "Posts",
"posts": "Publicaciones",
"favourites": "Favoritos",
"followers": "Seguidores",
"following": "Sigue",
@ -26,22 +26,22 @@
"edit": "Editar",
"uploaded_picture": "Fotos Cargadas",
"upload_new_picture": "Cargar Nueva Foto",
"current_password": "Password actual",
"current_password": "Contraseña actual",
"change_password": "Cambiar Contraseña",
"confirm_password": "Confirmar Contraseña",
"password": "Contraseña",
"upload_picture": "Cargar foto",
"upload_a_picture": "Cargar una foto",
"image_spec": "Solo puedes subir, PNG, JPG o Archivos GIF.",
"max": "max.",
"image_spec": "Sólo puedes subir imágenes en formato PNG, JPG o GIF.",
"max": "máx.",
"settings": "Opciones",
"show_email": "Mostrar mi Email",
"has_no_follower": "Este miembro no tiene seguidores :(",
"follows_no_one": "Este miembro no sigue a nadie, que pena :(",
"has_no_posts": "Este usuario aun no ha publicado nada.",
"email_hidden": "Email Oculto",
"show_email": "Mostrar mi Correo electrónico",
"has_no_follower": "Este miembro no tiene seguidores.",
"follows_no_one": "Este miembro no sigue a nadie.",
"has_no_posts": "Este usuario aún no ha publicado nada.",
"email_hidden": "Correo electrónico Oculto",
"hidden": "oculto",
"paginate_description": "La paginación de los temas no es por pagina, ya que tiene scroll infinito.",
"topics_per_page": "Temas por pagina",
"posts_per_page": "Post por pagina"
"paginate_description": "La paginación de los temas no es por página, ya que tiene scroll infinito.",
"topics_per_page": "Temas por página",
"posts_per_page": "Post por página"
}

@ -1,9 +1,9 @@
{
"latest_users": "Ultimos Miembros",
"top_posters": "Top Posteadores",
"latest_users": "Últimos Miembros",
"top_posters": "Top Publicadores",
"most_reputation": "Mayor Reputación",
"online": "Conectados",
"search": "Buscar",
"enter_username": "Ingresa el nombre de usuario para buscar",
"enter_username": "Ingresa el nombre de usuario que quieres buscar",
"load_more": "Cargar más"
}

@ -290,9 +290,14 @@ var socket,
var el = jQuery(this),
uid = el.parents('li').attr('data-uid');
if (uid && users[uid]) {
el.siblings('i').attr('class', 'fa fa-circle status ' + users[uid].status)
}
translator.translate('[[global:' + users[uid].status + ']]', function(translated) {
if (uid && users[uid]) {
el.siblings('i')
.attr('class', 'fa fa-circle status ' + users[uid].status)
.attr('title', translated)
.attr('data-original-title', translated);
}
});
});
});
};
@ -325,6 +330,13 @@ var socket,
});
};
app.createStatusTooltips = function() {
$('body').tooltip({
selector:'.fa-circle.status',
placement: 'top'
});
}
app.makeNumbersHumanReadable = function(elements) {
elements.each(function() {
$(this).html(utils.makeNumberHumanReadable($(this).attr('title')));
@ -343,6 +355,8 @@ var socket,
app.createUserTooltips();
app.createStatusTooltips();
setTimeout(function () {
window.scrollTo(0, 1); // rehide address bar on mobile after page load completes.
}, 100);

@ -89,7 +89,12 @@ define(['forum/accountheader'], function(header) {
return;
}
onlineStatus.attr('class', 'account-online-status fa fa-circle status ' + data.status);
translator.translate('[[global:' + data.status + ']]', function(translated) {
onlineStatus.attr('class', 'account-online-status fa fa-circle status ' + data.status)
.attr('title', translated)
.attr('data-original-title', translated);
});
};
return Account;

@ -12,8 +12,9 @@ define(function() {
});
socket.on('admin.plugins.toggle', function(status) {
pluginTgl = document.querySelector('.plugins li[data-plugin-id="' + status.id + '"] button');
pluginTgl.innerHTML = '<i class="fa fa-power-off"></i> ' + (status.active ? 'Dea' : 'A') + 'ctivate';
pluginTgl = $('.plugins li[data-plugin-id="' + status.id + '"] button');
pluginTgl.html('<i class="fa fa-power-off"></i> ' + (status.active ? 'Dea' : 'A') + 'ctivate');
pluginTgl.toggleClass('btn-warning', status.active).toggleClass('btn-success', !status.active);
app.alert({
alert_id: 'plugin_toggled_' + status.id,

@ -12,7 +12,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
app.enterRoom('category_' + cid);
$('#twitter-intent').on('click', function () {
$('#twitter-share').on('click', function () {
window.open(twitterUrl, '_blank', 'width=550,height=420,scrollbars=no,status=no');
return false;
});

@ -280,41 +280,11 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
fixDeleteStateForPosts();
// Follow Thread State
var followEl = $('.posts .follow'),
set_follow_state = function(state, quiet) {
if (state && !followEl.hasClass('btn-success')) {
followEl.addClass('btn-success');
followEl.attr('title', 'You are currently receiving updates to this topic');
if (!quiet) {
app.alert({
alert_id: 'topic_follow',
timeout: 2500,
title: '[[topic:following_topic.title]]',
message: '[[topic:following_topic.message]]',
type: 'success'
});
}
} else if (!state && followEl.hasClass('btn-success')) {
followEl.removeClass('btn-success');
followEl.attr('title', 'Be notified of new replies in this topic');
if (!quiet) {
app.alert({
alert_id: 'topic_follow',
timeout: 2500,
title: '[[topic:not_following_topic.title]]',
message: '[[topic:not_following_topic.message]]',
type: 'success'
});
}
}
};
socket.emit('topics.followCheck', tid, function(err, state) {
set_follow_state(state, true);
set_follow_state(state, false);
});
followEl.on('click', function() {
$('.posts .follow').on('click', function() {
socket.emit('topics.follow', tid, function(err, state) {
if(err) {
return app.alert({
@ -326,7 +296,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
});
}
set_follow_state(state);
set_follow_state(state, true);
});
return false;
@ -405,13 +375,14 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
}
var username = '',
post = $(this).parents('li[data-pid]');
post = $(this).parents('li[data-pid]'),
pid = $(this).parents('.post-row').attr('data-pid');
if (post.length) {
username = '@' + post.attr('data-username').replace(/\s/g, '-') + ' ';
}
if (thread_state.locked !== '1') {
composer.newReply(tid, topic_name, selectionText.length > 0 ? selectionText + '\n\n' + username : '' + username);
composer.newReply(tid, pid, topic_name, selectionText.length > 0 ? selectionText + '\n\n' + username : '' + username);
}
});
@ -436,7 +407,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
if($('.composer').length) {
composer.addQuote(tid, pid, topic_name, username, quoted);
}else {
composer.newReply(tid, topic_name, username + ' said:\n' + quoted);
composer.newReply(tid, pid, topic_name, username + ' said:\n' + quoted);
}
});
}
@ -913,129 +884,75 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
favourites.html(currentFavourites).attr('data-favourites', currentFavourites);
}
function set_locked_state(locked, alert) {
var threadReplyBtn = $('.topic-main-buttons .post_reply'),
postReplyBtns = document.querySelectorAll('#post-container .post_reply'),
quoteBtns = document.querySelectorAll('#post-container .quote'),
editBtns = document.querySelectorAll('#post-container .edit'),
deleteBtns = document.querySelectorAll('#post-container .delete'),
numPosts = document.querySelectorAll('#post_container li[data-pid]').length,
lockThreadEl = $('.lock_thread'),
x;
if (locked === true) {
translator.translate('<i class="fa fa-fw fa-unlock"></i> [[topic:thread_tools.unlock]]', function(translated) {
lockThreadEl.html(translated);
});
threadReplyBtn.attr('disabled', true);
threadReplyBtn.html('Locked <i class="fa fa-lock"></i>');
for (x = 0; x < numPosts; x++) {
postReplyBtns[x].innerHTML = 'Locked <i class="fa fa-lock"></i>';
quoteBtns[x].style.display = 'none';
editBtns[x].style.display = 'none';
deleteBtns[x].style.display = 'none';
}
function set_follow_state(state, alert) {
if (alert) {
app.alert({
'alert_id': 'thread_lock',
type: 'success',
title: 'Thread Locked',
message: 'Thread has been successfully locked',
timeout: 5000
});
}
$('.posts .follow').toggleClass('btn-success', state).attr('title', state ? 'You are currently receiving updates to this topic' : 'Be notified of new replies in this topic');
thread_state.locked = '1';
} else {
translator.translate('<i class="fa fa-fw fa-lock"></i> [[topic:thread_tools.lock]]', function(translated) {
lockThreadEl.html(translated);
if(alert) {
app.alert({
alert_id: 'topic_follow',
timeout: 2500,
title: state ? '[[topic:following_topic.title]]' : '[[topic:not_following_topic.title]]',
message: state ? '[[topic:following_topic.message]]' : '[[topic:not_following_topic.message]]',
type: 'success'
});
threadReplyBtn.attr('disabled', false);
threadReplyBtn.html('Reply');
for (x = 0; x < numPosts; x++) {
postReplyBtns[x].innerHTML = 'Reply <i class="fa fa-reply"></i>';
quoteBtns[x].style.display = 'inline-block';
editBtns[x].style.display = 'inline-block';
deleteBtns[x].style.display = 'inline-block';
}
}
}
if (alert) {
app.alert({
'alert_id': 'thread_lock',
type: 'success',
title: 'Thread Unlocked',
message: 'Thread has been successfully unlocked',
timeout: 5000
});
}
function set_locked_state(locked, alert) {
translator.translate('<i class="fa fa-fw fa-' + (locked ? 'un': '') + 'lock"></i> [[topic:thread_tools.' + (locked ? 'un': '') + 'lock]]', function(translated) {
$('.lock_thread').html(translated);
});
$('.topic-main-buttons .post_reply').attr('disabled', locked).html(locked ? 'Locked <i class="fa fa-lock"></i>' : 'Reply');
$('#post-container .post_reply').html(locked ? 'Locked <i class="fa fa-lock"></i>' : 'Reply <i class="fa fa-reply"></i>');
$('#post-container').find('.quote, .edit, .delete').toggleClass('none', locked);
thread_state.locked = '0';
if (alert) {
app.alert({
'alert_id': 'thread_lock',
type: 'success',
title: 'Thread ' + (locked ? 'Locked' : 'Unlocked'),
message: 'Thread has been successfully ' + (locked ? 'locked' : 'unlocked'),
timeout: 5000
});
}
thread_state.locked = locked ? '1' : '0';
}
function set_delete_state(deleted) {
var deleteThreadEl = $('.delete_thread'),
deleteTextEl = $('.delete_thread span'),
//deleteThreadEl.getElementsByTagName('span')[0],
threadEl = $('#post-container'),
deleteNotice = document.getElementById('thread-deleted') || document.createElement('div');
if (deleted) {
translator.translate('<i class="fa fa-fw fa-comment"></i> [[topic:thread_tools.restore]]', function(translated) {
deleteTextEl.html(translated);
});
threadEl.addClass('deleted');
var threadEl = $('#post-container');
translator.translate('<i class="fa fa-fw ' + (deleted ? 'fa-comment' : 'fa-trash-o') + '"></i> [[topic:thread_tools.' + (deleted ? 'restore' : 'delete') + ']]', function(translated) {
$('.delete_thread span').html(translated);
});
// Spawn a 'deleted' notice at the top of the page
deleteNotice.setAttribute('id', 'thread-deleted');
deleteNotice.className = 'alert alert-warning';
deleteNotice.innerHTML = 'This thread has been deleted. Only users with thread management privileges can see it.';
threadEl.before(deleteNotice);
threadEl.toggleClass('deleted', deleted);
thread_state.deleted = deleted ? '1' : '0';
thread_state.deleted = '1';
if(deleted) {
$('<div id="thread-deleted">This thread has been deleted. Only users with thread management privileges can see it.</div>').insertBefore(threadEl);
} else {
translator.translate('<i class="fa fa-fw fa-trash-o"></i> [[topic:thread_tools.delete]]', function(translated) {
deleteTextEl.html(translated);
});
threadEl.removeClass('deleted');
deleteNotice.parentNode.removeChild(deleteNotice);
thread_state.deleted = '0';
$('#thread-deleted').remove();
}
}
function set_pinned_state(pinned, alert) {
var pinEl = $('.pin_thread');
translator.translate('<i class="fa fa-fw fa-thumb-tack"></i> [[topic:thread_tools.' + (pinned ? 'unpin' : 'pin') + ']]', function(translated) {
if (pinned) {
pinEl.html(translated);
if (alert) {
app.alert({
'alert_id': 'thread_pin',
type: 'success',
title: 'Thread Pinned',
message: 'Thread has been successfully pinned',
timeout: 5000
});
}
thread_state.pinned = '1';
} else {
pinEl.html(translated);
if (alert) {
app.alert({
'alert_id': 'thread_pin',
type: 'success',
title: 'Thread Unpinned',
message: 'Thread has been successfully unpinned',
timeout: 5000
});
}
$('.pin_thread').html(translated);
thread_state.pinned = '0';
if (alert) {
app.alert({
'alert_id': 'thread_pin',
type: 'success',
title: 'Thread ' + (pinned ? 'Pinned' : 'Unpinned'),
message: 'Thread has been successfully ' + (pinned ? 'pinned' : 'unpinned'),
timeout: 5000
});
}
thread_state.pinned = pinned ? '1' : '0';
});
}
@ -1052,23 +969,13 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
}
function toggle_post_tools(pid, isDeleted) {
var postEl = $('#post-container li[data-pid="' + pid + '"]'),
quoteEl = $(postEl[0].querySelector('.quote')),
favEl = $(postEl[0].querySelector('.favourite')),
replyEl = $(postEl[0].querySelector('.post_reply')),
chatEl = $(postEl[0].querySelector('.chat'));
if (isDeleted) {
quoteEl.addClass('none');
favEl.addClass('none');
replyEl.addClass('none');
chatEl.addClass('none');
} else {
quoteEl.removeClass('none');
favEl.removeClass('none');
replyEl.removeClass('none');
chatEl.removeClass('none');
}
var postEl = $('#post-container li[data-pid="' + pid + '"]');
postEl.find('.quote, .favourite, .post_reply, .chat').toggleClass('none', isDeleted);
translator.translate(isDeleted ? ' [[topic:restore]]' : ' [[topic:delete]]', function(translated) {
postEl.find('.delete').find('span').html(translated);
});
}
$(window).on('scroll', updateHeader);
@ -1135,8 +1042,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
var scrollBottom = scrollTop + $(window).height();
var elTop = el.offset().top;
var height = Math.floor(el.height());
var elBottom = elTop + height;
var elBottom = elTop + Math.floor(el.height());
return !(elTop > scrollBottom || elBottom < scrollTop);
}
@ -1315,18 +1221,8 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
}
function toggle_mod_tools(pid, state) {
var postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]')),
editEl = postEl.find('.edit'),
deleteEl = postEl.find('.delete');
if (state) {
editEl.removeClass('none');
deleteEl.removeClass('none');
} else {
editEl.addClass('none');
deleteEl.addClass('none');
}
function toggle_mod_tools(pid, editable) {
$('#post-container li[data-pid="' + pid + '"]').find('.edit, .delete').toggleClass('none', !editable);
}
function updatePostCount() {

@ -47,6 +47,7 @@ define(['forum/recent'], function(recent) {
if(!$('#topics-container').length) {
return;
}
loadingMoreTopics = true;
socket.emit('topics.loadMoreUnreadTopics', {
after: $('#topics-container').attr('data-nextstart')

@ -111,12 +111,14 @@ define(function() {
users: users
});
if(emptyContainer) {
$('#users-container .registered-user').remove();
}
translator.translate(html, function(translated) {
if(emptyContainer) {
$('#users-container .registered-user').remove();
}
$('#users-container').append(html);
$('#users-container .anon-user').appendTo($('#users-container'));
$('#users-container').append(translated);
$('#users-container .anon-user').appendTo($('#users-container'));
});
}
function loadMoreUsers() {

@ -91,7 +91,11 @@ define(['taskbar', 'string'], function(taskbar, S) {
function checkStatus(chatModal) {
socket.emit('user.isOnline', chatModal.touid, function(err, data) {
$('#chat-user-status').attr('class', 'fa fa-circle status ' + data.status);
translator.translate('[[global:' + data.status + ']]', function(translated) {
$('#chat-user-status').attr('class', 'fa fa-circle status ' + data.status)
.attr('title', translated)
.attr('data-original-title', translated);
});
});
}

@ -294,22 +294,22 @@ define(['taskbar'], function(taskbar) {
var prevText = bodyEl.val();
if(tid !== composer.posts[uuid].tid) {
text = username + ' said in ['+title+'](/topic/'+tid+'#'+pid+'):\n'+text;
}else {
} else {
text = username + ' said:\n' + text;
}
composer.posts[uuid].body = (prevText.length ? prevText + '\n\n' : '') + text;
bodyEl.val(composer.posts[uuid].body);
}else{
composer.newReply(tid,title,username + ' said:\n' + text);
} else {
composer.newReply(tid, pid, title, username + ' said:\n' + text);
}
}
};
composer.newReply = function(tid, title, text) {
composer.newReply = function(tid, pid, title, text) {
if(allowed()) {
push({
tid: tid,
toPid: pid,
title: title,
body: text,
modified: false,
@ -711,7 +711,9 @@ define(['taskbar'], function(taskbar) {
titleEl.val(titleEl.val().trim());
bodyEl.val(bodyEl.val().trim());
thumbEl.val(thumbEl.val().trim());
if(thumbEl.length) {
thumbEl.val(thumbEl.val().trim());
}
var checkTitle = parseInt(postData.cid, 10) || parseInt(postData.pid, 10);
@ -729,20 +731,21 @@ define(['taskbar'], function(taskbar) {
socket.emit('topics.post', {
title: titleEl.val(),
content: bodyEl.val(),
topic_thumb: thumbEl.val(),
topic_thumb: thumbEl.val() || '',
category_id: postData.cid
}, done);
} else if (parseInt(postData.tid, 10) > 0) {
socket.emit('posts.reply', {
topic_id: postData.tid,
content: bodyEl.val()
tid: postData.tid,
content: bodyEl.val(),
toPid: postData.toPid
}, done);
} else if (parseInt(postData.pid, 10) > 0) {
socket.emit('posts.edit', {
pid: postData.pid,
content: bodyEl.val(),
title: titleEl.val(),
topic_thumb: thumbEl.val()
topic_thumb: thumbEl.val() || ''
}, done);
}

@ -17,7 +17,7 @@
<div>
<div>
<span>
<i class="account-online-status fa fa-circle status offline"></i>
<i class="account-online-status fa fa-circle status offline" title="[[global:{status}]]"></i>
<span class="account-username"> {username}</span>
</span>
</div>

@ -1,11 +1,20 @@
<h1><i class="fa fa-code-fork"></i> Plugins</h1>
<div class="alert alert-warning">
<p>
<strong>Interested in writing plugins for NodeBB?</strong>
</p>
<p>
Full documentation regarding plugin authoring can be found in the <a target="_blank" href="https://github.com/designcreateplay/NodeBB/wiki/Writing-Plugins-for-NodeBB">NodeBB Wiki</a>.
</p>
</div>
<ul class="plugins">
<!-- BEGIN plugins -->
<li data-plugin-id="{plugins.id}">
<h2>{plugins.name}</h2>
<div class="pull-right">
<button data-action="toggleActive" class="btn btn-primary">{plugins.activeText}</button>
<button data-action="toggleActive" class="btn <!-- IF plugins.active -->btn-warning<!-- ELSE -->btn-success<!-- ENDIF plugins.active -->">{plugins.activeText}</button>
</div>
<p>{plugins.description}</p>
<p>For more information: <a href="{plugins.url}">{plugins.url}</a></p>
@ -13,11 +22,4 @@
<!-- END plugins -->
</ul>
<div class="alert alert-warning">
<p>
<strong>Interested in writing plugins for NodeBB?</strong>
</p>
<p>
Full documentation regarding plugin authoring can be found in the <a target="_blank" href="https://github.com/designcreateplay/NodeBB/wiki/Writing-Plugins-for-NodeBB">NodeBB Wiki</a>.
</p>
</div>

@ -14,7 +14,7 @@
<!-- IF !disableSocialButtons -->
<div class="inline-block pull-right">
<a href="#" id="facebook-share"><i class="fa fa-facebook-square fa-2x"></i></a>&nbsp;
<a href="#" id="twitter-intent"><i class="fa fa-twitter-square fa-2x"></i></a>&nbsp;
<a href="#" id="twitter-share"><i class="fa fa-twitter-square fa-2x"></i></a>&nbsp;
<a href="#" id="google-share"><i class="fa fa-google-plus-square fa-2x"></i></a>&nbsp;
</div>
<!-- ENDIF !disableSocialButtons -->
@ -43,7 +43,11 @@
todo: add a check for config.allowTopicsThumbnail if issue#1066 is a win
-->
<a href="../../user/{topics.userslug}" class="pull-left">
<img src="<!-- IF topics.thumb -->{topics.thumb}<!-- ELSE -->{topics.picture}<!-- ENDIF topics.thumb -->" class="img-rounded user-img" title="{topics.username}"/>
<!-- IF topics.thumb -->
<img src="{topics.thumb}" class="img-rounded user-img" title="{topics.username}"/>
<!-- ELSE -->
<img src="{topics.picture}" class="img-rounded user-img" title="{topics.username}"/>
<!-- ENDIF topics.thumb -->
</a>
<h3>

@ -4,7 +4,7 @@
<div class="modal-content">
<div class="modal-header">
<h4>[[modules:chat.chatting_with]] <i id="chat-user-status" class="fa fa-circle status offline"></i></h4>
<h4>[[modules:chat.chatting_with]] <i id="chat-user-status" class="fa fa-circle status offline" title="[[global:offline]]"></i></h4>
</div>
<div class="modal-body">

@ -101,9 +101,9 @@
<button title="[[topic:share]]"class="btn btn-sm btn-default share" data-toggle="dropdown" href="#"><i class="fa fa-share-square-o"></i></button>
<ul class="dropdown-menu text-center pull-right" role="menu" aria-labelledby="dLabel">
<!-- IF !disableSocialButtons -->
<li class="btn btn-sm btn-default facebook-share" type="button" title=""><i class="fa fa-facebook"></i></li>
<li class="btn btn-sm btn-default twitter-share" type="button" title=""><i class="fa fa-twitter"></i></li>
<li class="btn btn-sm btn-default google-share" type="button" title=""><i class="fa fa-google-plus"></i></li>
<li class="btn btn-sm btn-default facebook-share" type="button" title=""><i class="fa fa-facebook fa-fw"></i></li>
<li class="btn btn-sm btn-default twitter-share" type="button" title=""><i class="fa fa-twitter fa-fw"></i></li>
<li class="btn btn-sm btn-default google-share" type="button" title=""><i class="fa fa-google-plus fa-fw"></i></li>
<!-- ENDIF !disableSocialButtons -->
<li>
<input type="text" id="post_{posts.pid}_link" value="" class="form-control pull-right post-link" style=""></input>

@ -25,7 +25,7 @@
<br/>
<div class="user-info">
<span>
<i class="fa fa-circle status {users.status}"></i>
<i class="fa fa-circle status {users.status}" title="[[global:{users.status}]]"></i>
<a href="{relative_path}/user/{users.userslug}">{users.username}</a>
</span>
<br/>

@ -13,10 +13,12 @@ var db = require('./../database'),
for (var key in category) {
db.setObjectField('category:' + cid, key, category[key]);
if (key == 'name') {
if (key === 'name') {
// reset slugs if name is updated
var slug = cid + '/' + utils.slugify(category[key]);
db.setObjectField('category:' + cid, 'slug', slug);
} else if (key === 'order') {
db.sortedSetAdd('categories:cid', category[key], cid);
}
}

@ -18,11 +18,10 @@ var db = require('./database'),
Categories.create = function(data, callback) {
db.incrObjectField('global', 'nextCid', function(err, cid) {
if (err) {
return callback(err, null);
return callback(err);
}
var slug = cid + '/' + utils.slugify(data.name);
db.listAppend('categories:cid', cid);
var category = {
cid: cid,
@ -36,14 +35,20 @@ var db = require('./database'),
topic_count: 0,
disabled: 0,
order: data.order,
link: "",
link: '',
numRecentReplies: 2,
class: 'col-md-3 col-xs-6',
imageClass: 'default'
};
db.setObject('category:' + cid, category, function(err, data) {
callback(err, category);
db.setObject('category:' + cid, category, function(err) {
if(err) {
return callback(err);
}
db.sortedSetAdd('categories:cid', data.order, cid);
callback(null, category);
});
});
};
@ -132,6 +137,10 @@ var db = require('./database'),
return callback(err);
}
if (parseInt(topicCount, 10) === 0) {
return callback(null, 1);
}
user.getSettings(uid, function(err, settings) {
if(err) {
return callback(err);
@ -142,8 +151,8 @@ var db = require('./database'),
});
};
Categories.getAllCategories = function(current_user, callback) {
db.getListRange('categories:cid', 0, -1, function(err, cids) {
Categories.getAllCategories = function(uid, callback) {
db.getSortedSetRange('categories:cid', 0, -1, function(err, cids) {
if(err) {
return callback(err);
}
@ -152,7 +161,7 @@ var db = require('./database'),
return callback(null, {categories : []});
}
Categories.getCategories(cids, current_user, callback);
Categories.getCategories(cids, uid, callback);
});
};
@ -311,14 +320,11 @@ var db = require('./database'),
async.map(cids, getCategory, function(err, categories) {
if (err) {
winston.err(err);
return callback(err, null);
return callback(err);
}
categories = categories.filter(function(category) {
return !!category;
}).sort(function(a, b) {
return parseInt(a.order, 10) - parseInt(b.order, 10);
});
callback(null, {

@ -2,9 +2,14 @@ var Groups = require('./groups'),
User = require('./user'),
async = require('async'),
db = require('./database'),
CategoryTools = {};
CategoryTools.exists = function(cid, callback) {
db.isSortedSetMember('categories:cid', cid, callback);
};
CategoryTools.privileges = function(cid, uid, callback) {
async.parallel({
"+r": function(next) {

@ -339,7 +339,7 @@ var async = require('async'),
winston.info('Enabling default plugins');
var defaultEnabled = [
'nodebb-plugin-markdown', 'nodebb-plugin-mentions'
'nodebb-plugin-markdown', 'nodebb-plugin-mentions', 'nodebb-widget-essentials'
];
async.each(defaultEnabled, function (pluginId, next) {

@ -375,11 +375,15 @@ var fs = require('fs'),
dirs = dirs.map(function(file) {
return path.join(npmPluginPath, file);
}).filter(function(file) {
var stats = fs.statSync(file),
isPlugin = file.substr(npmPluginPath.length + 1, 14) === 'nodebb-plugin-' || file.substr(npmPluginPath.length + 1, 14) === 'nodebb-widget-';
if (fs.existsSync(file)) {
var stats = fs.statSync(file),
isPlugin = file.substr(npmPluginPath.length + 1, 14) === 'nodebb-plugin-' || file.substr(npmPluginPath.length + 1, 14) === 'nodebb-widget-';
if (stats.isDirectory() && isPlugin) return true;
else return false;
if (stats.isDirectory() && isPlugin) return true;
else return false;
} else {
return false;
}
});
next(err, dirs);

@ -20,7 +20,12 @@ var db = require('./database'),
(function(Posts) {
var customUserInfo = {};
Posts.create = function(uid, tid, content, callback) {
Posts.create = function(data, callback) {
var uid = data.uid,
tid = data.tid,
content = data.content,
toPid = data.toPid;
if (uid === null) {
return callback(new Error('invalid-user'), null);
}
@ -56,6 +61,10 @@ var db = require('./database'),
'deleted': 0
};
if (toPid) {
postData['toPid'] = toPid;
}
db.setObject('post:' + pid, postData, function(err) {
if(err) {
return next(err);
@ -78,7 +87,7 @@ var db = require('./database'),
function(postData, next) {
postTools.parse(postData.content, function(err, content) {
if(err) {
return next(err, null);
return next(err);
}
postData.content = content;
@ -294,24 +303,24 @@ var db = require('./database'),
});
},
function(postData, next) {
if (postData.content) {
postTools.parse(postData.content, function(err, content) {
if(err) {
return next(err);
}
if (!postData.content) {
return next(null, postData);
}
if(stripTags) {
var s = S(content);
postData.content = s.stripTags.apply(s, utils.getTagsExcept(['img', 'i'])).s;
} else {
postData.content = content;
}
postTools.parse(postData.content, function(err, content) {
if(err) {
return next(err);
}
if(stripTags) {
var s = S(content);
postData.content = s.stripTags.apply(s, utils.getTagsExcept(['img', 'i'])).s;
} else {
postData.content = content;
}
next(null, postData);
});
} else {
next(null, postData);
}
});
}
], callback);
}
@ -474,31 +483,31 @@ var db = require('./database'),
}
Posts.getPidPage = function(pid, uid, callback) {
Posts.getPostField(pid, 'tid', function(err, tid) {
if(err) {
return callback(err);
}
topics.getPids(tid, function(err, pids) {
if(err) {
return callback(err);
}
var index = pids.indexOf(pid);
if(!pid) {
return callback(new Error('invalid-pid'));
}
var index = 0;
async.waterfall([
function(next) {
Posts.getPostField(pid, 'tid', next);
},
function(tid, next) {
topics.getPids(tid, next);
},
function(pids, next) {
index = pids.indexOf(pid.toString());
if(index === -1) {
return callback(new Error('pid not found'));
return next(new Error('pid not found'));
}
user.getSettings(uid, function(err, settings) {
if(err) {
return callback(err);
}
var page = Math.ceil((index + 1) / settings.postsPerPage);
callback(null, page);
});
});
});
next();
},
function(next) {
user.getSettings(uid, next);
},
function(settings, next) {
next(null, Math.ceil((index + 1) / settings.postsPerPage));
}
], callback);
};
Posts.getPidIndex = function(pid, callback) {

@ -44,6 +44,7 @@ var path = require('path'),
app.get('/config', function (req, res, next) {
var config = require('../../public/config.json');
config.version = pkg.version;
config.postDelay = meta.config.postDelay;
config.minimumTitleLength = meta.config.minimumTitleLength;
config.maximumTitleLength = meta.config.maximumTitleLength;
@ -286,6 +287,9 @@ var path = require('path'),
app.get('/unread', function (req, res, next) {
var uid = (req.user) ? req.user.uid : 0;
if(!req.user) {
return res.json(403, 'not-allowed');
}
topics.getUnreadTopics(uid, 0, 19, function (err, data) {
if(err) {
return next(err);
@ -297,6 +301,9 @@ var path = require('path'),
app.get('/unread/total', function (req, res, next) {
var uid = (req.user) ? req.user.uid : 0;
if(!req.user) {
return res.json(403, 'not-allowed');
}
topics.getTotalUnread(uid, function (err, data) {
if(err) {
return next(err);

@ -14,6 +14,7 @@ var async = require('async'),
SocketPosts = {};
SocketPosts.reply = function(socket, data, callback) {
if (!socket.uid && !parseInt(meta.config.allowGuestPosting, 10)) {
socket.emit('event:alert', {
title: 'Reply Unsuccessful',
@ -24,11 +25,13 @@ SocketPosts.reply = function(socket, data, callback) {
return callback(new Error('not-logged-in'));
}
if(!data || !data.topic_id || !data.content) {
if(!data || !data.tid || !data.content) {
return callback(new Error('invalid data'));
}
topics.reply(data.topic_id, socket.uid, data.content, function(err, postData) {
data.uid = socket.uid;
topics.reply(data, function(err, postData) {
if(err) {
if (err.message === 'content-too-short') {
module.parent.exports.emitContentTooShortAlert(socket);

@ -1,6 +1,7 @@
var async = require('async'),
user = require('../user'),
topics = require('../topics'),
utils = require('./../../public/src/utils'),
SocketUser = {};
SocketUser.exists = function(socket, data, callback) {

@ -18,15 +18,7 @@ var winston = require('winston'),
(function(ThreadTools) {
ThreadTools.exists = function(tid, callback) {
db.isSortedSetMember('topics:tid', tid, function(err, ismember) {
if (err) {
callback(false);
}
callback(ismember);
});
db.isSortedSetMember('topics:tid', tid, callback);
}
ThreadTools.privileges = function(tid, uid, callback) {

@ -106,6 +106,12 @@ var async = require('async'),
async.waterfall([
function(next) {
categoryTools.exists(cid, next);
},
function(categoryExists, next) {
if(!categoryExists) {
return next(new Error('category doesn\'t exist'))
}
categoryTools.privileges(cid, uid, next);
},
function(privileges, next) {
@ -121,7 +127,7 @@ var async = require('async'),
Topics.create({uid: uid, title: title, cid: cid, thumb: thumb}, next);
},
function(tid, next) {
Topics.reply(tid, uid, content, next);
Topics.reply({uid:uid, tid:tid, content:content}, next);
},
function(postData, next) {
threadTools.toggleFollow(postData.tid, uid);
@ -143,12 +149,22 @@ var async = require('async'),
], callback);
};
Topics.reply = function(tid, uid, content, callback) {
var privileges;
var postData;
Topics.reply = function(data, callback) {
var tid = data.tid,
uid = data.uid,
toPid = data.toPid,
content = data.content,
privileges,
postData;
async.waterfall([
function(next) {
threadTools.exists(tid, next);
},
function(topicExists, next) {
if (!topicExists) {
return next(new Error('topic doesn\'t exist'));
}
threadTools.privileges(tid, uid, next);
},
function(privilegesData, next) {
@ -170,7 +186,7 @@ var async = require('async'),
return next(new Error('content-too-short'));
}
posts.create(uid, tid, content, next);
posts.create({uid:uid, tid:tid, content:content, toPid:toPid}, next);
},
function(data, next) {
postData = data;
@ -261,9 +277,9 @@ var async = require('async'),
};
Topics.movePostToTopic = function(pid, tid, callback) {
threadTools.exists(tid, function(exists) {
if(!exists) {
return callback(new Error('Topic doesn\'t exist'));
threadTools.exists(tid, function(err, exists) {
if(err || !exists) {
return callback(err || new Error('Topic doesn\'t exist'));
}
posts.getPostFields(pid, ['deleted', 'tid', 'timestamp'], function(err, postData) {
@ -422,7 +438,9 @@ var async = require('async'),
if(err) {
return callback(err);
}
if(!parseInt(postCount, 10)) {
return callback(null, 1);
}
user.getSettings(uid, function(err, settings) {
if(err) {
return callback(err);
@ -445,7 +463,8 @@ var async = require('async'),
function getTopics(set, uid, tids, callback) {
var returnTopics = {
'topics': []
topics: [],
nextStart: 0
};
if (!tids || !tids.length) {
@ -571,18 +590,14 @@ var async = require('async'),
};
Topics.getUnreadTopics = function(uid, start, stop, callback) {
var unreadTopics = {
'show_markallread_button': 'show',
'no_topics_message': 'hidden',
'topics': []
no_topics_message: '',
show_markallread_button: 'hidden',
nextStart : 0,
topics: []
};
function noUnreadTopics() {
unreadTopics.no_topics_message = '';
unreadTopics.show_markallread_button = 'hidden';
callback(null, unreadTopics);
}
function sendUnreadTopics(topicIds) {
Topics.getTopicsByTids(topicIds, 0, uid, function(err, topicData) {
@ -597,13 +612,8 @@ var async = require('async'),
unreadTopics.topics = topicData;
unreadTopics.nextStart = parseInt(rank, 10) + 1;
if (!topicData || topicData.length === 0) {
unreadTopics.no_topics_message = '';
}
if (uid === 0 || topicData.length === 0) {
unreadTopics.show_markallread_button = 'hidden';
}
unreadTopics.no_topics_message = (!topicData || topicData.length === 0) ? '' : 'hidden';
unreadTopics.show_markallread_button = topicData.length === 0 ? 'hidden' : '';
callback(null, unreadTopics);
});
@ -618,7 +628,7 @@ var async = require('async'),
if (unreadTids.length) {
sendUnreadTopics(unreadTids);
} else {
noUnreadTopics();
callback(null, unreadTopics);
}
});
};
@ -766,9 +776,9 @@ var async = require('async'),
};
Topics.getTopicWithPosts = function(tid, current_user, start, end, quiet, callback) {
threadTools.exists(tid, function(exists) {
if (!exists) {
return callback(new Error('Topic tid \'' + tid + '\' not found'));
threadTools.exists(tid, function(err, exists) {
if (err || !exists) {
return callback(err || new Error('Topic tid \'' + tid + '\' not found'));
}
// "quiet" is used for things like RSS feed updating, HTML parsing for non-js users, etc

@ -7,6 +7,7 @@ var db = require('./database'),
User = require('./user'),
Topics = require('./topics'),
Posts = require('./posts'),
Categories = require('./categories'),
Groups = require('./groups'),
Meta = require('./meta'),
Plugins = require('./plugins'),
@ -15,13 +16,20 @@ var db = require('./database'),
Upgrade = {},
minSchemaDate = new Date(2014, 0, 4).getTime(), // This value gets updated every new MINOR version
schemaDate, thisSchemaDate;
schemaDate, thisSchemaDate,
Upgrade.check = function(callback) {
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema
var latestSchema = new Date(2014, 1, 20, 20, 25).getTime();
latestSchema = new Date(2014, 1, 22).getTime();
Upgrade.check = function(callback) {
db.get('schemaDate', function(err, value) {
if(!value) {
db.set('schemaDate', latestSchema, function(err) {
callback(true);
});
return;
}
if (parseInt(value, 10) >= latestSchema) {
callback(true);
} else {
@ -39,9 +47,16 @@ Upgrade.upgrade = function(callback) {
function(next) {
// Prepare for upgrade & check to make sure the upgrade is possible
db.get('schemaDate', function(err, value) {
schemaDate = value;
if(!value) {
db.set('schemaDate', latestSchema, function(err) {
next();
});
schemaDate = latestSchema;
} else {
schemaDate = parseInt(value, 10);
}
if (schemaDate >= minSchemaDate || schemaDate === null) {
if (schemaDate >= minSchemaDate) {
next();
} else {
next(new Error('upgrade-not-possible'));
@ -691,7 +706,7 @@ Upgrade.upgrade = function(callback) {
if (schemaDate < thisSchemaDate) {
updatesMade = true;
db.setObjectField('widgets:home.tpl', 'motd', JSON.stringify([
{
"widget": "html",
@ -717,9 +732,9 @@ Upgrade.upgrade = function(callback) {
if (schemaDate < thisSchemaDate) {
updatesMade = true;
var container = '<div class="panel panel-default"><div class="panel-heading">{title}</div><div class="panel-body">{body}</div></div>';
db.setObjectField('widgets:category.tpl', 'sidebar', JSON.stringify([
{
"widget": "recentreplies",
@ -756,7 +771,7 @@ Upgrade.upgrade = function(callback) {
if (schemaDate < thisSchemaDate) {
updatesMade = true;
db.setObjectField('widgets:home.tpl', 'footer', JSON.stringify([
{
"widget": "forumstats",
@ -778,7 +793,7 @@ Upgrade.upgrade = function(callback) {
updatesMade = true;
var container = '<div class="panel panel-default"><div class="panel-heading">{title}</div><div class="panel-body">{body}</div></div>';
db.setObjectField('widgets:home.tpl', 'sidebar', JSON.stringify([
{
"widget": "html",
@ -813,9 +828,62 @@ Upgrade.upgrade = function(callback) {
winston.info('[2014/2/20] Activating NodeBB Essential Widgets - skipped');
next();
}
},
function(next) {
thisSchemaDate = new Date(2014, 1, 22).getTime();
if (schemaDate < thisSchemaDate) {
updatesMade = true;
db.exists('categories:cid', function(err, exists) {
if(err) {
return next(err);
}
if(!exists) {
winston.info('[2014/2/22] Added categories to sorted set - skipped');
return next();
}
db.getListRange('categories:cid', 0, -1, function(err, cids) {
if(err) {
return next(err);
}
if(!Array.isArray(cids)) {
winston.info('[2014/2/22] Add categories to sorted set - skipped (cant find any cids)');
return next();
}
db.rename('categories:cid', 'categories:cid:old', function(err) {
if(err) {
return next(err);
}
async.each(cids, function(cid, next) {
Categories.getCategoryField(cid, 'order', function(err, order) {
if(err) {
return next(err);
}
db.sortedSetAdd('categories:cid', order, cid, next);
});
}, function(err) {
if(err) {
return next(err);
}
winston.info('[2014/2/22] Added categories to sorted set');
db.delete('categories:cid:old', next);
});
});
});
});
} else {
winston.info('[2014/2/22] Added categories to sorted set - skipped');
next();
}
}
// Add new schema updates here
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 17!!!
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 22!!!
], function(err) {
if (!err) {
db.set('schemaDate', thisSchemaDate, function(err) {
@ -825,6 +893,7 @@ Upgrade.upgrade = function(callback) {
} else {
winston.info('[upgrade] Schema already up to date!');
}
if (callback) {
callback(err);
} else {

Loading…
Cancel
Save