diff --git a/app.js b/app.js index f9c2ab523b..018a70b3c1 100644 --- a/app.js +++ b/app.js @@ -16,8 +16,8 @@ along with this program. If not, see . */ -// Read config.js to grab redis info var fs = require('fs'), + winston = require('winston'), nconf = require('nconf'), pkg = require('./package.json'), url = require('url'); @@ -28,11 +28,26 @@ global.env = process.env.NODE_ENV || 'production', // Configuration setup nconf.argv().file({ file: __dirname + '/config.json'}); +winston.remove(winston.transports.Console); +winston.add(winston.transports.Console, { + colorize:true +}); + +winston.add(winston.transports.File, { + filename:'error.log', + level:'error' +}) + +// TODO: remove once https://github.com/flatiron/winston/issues/280 is fixed +winston.err = function(err) { + winston.error(err.stack); +}; + // Log GNU copyright info along with server info -console.log('Info: NodeBB v' + pkg.version + ' Copyright (C) 2013 DesignCreatePlay Inc.'); -console.log('Info: This program comes with ABSOLUTELY NO WARRANTY.'); -console.log('Info: This is free software, and you are welcome to redistribute it under certain conditions.'); -console.log('Info: ==='); +winston.info('NodeBB v' + pkg.version + ' Copyright (C) 2013 DesignCreatePlay Inc.'); +winston.info('This program comes with ABSOLUTELY NO WARRANTY.'); +winston.info('This is free software, and you are welcome to redistribute it under certain conditions.'); +winston.info('==='); if(nconf.get('upgrade')) { require('./src/upgrade').upgrade(); @@ -41,8 +56,8 @@ if(nconf.get('upgrade')) { nconf.set('upload_url', nconf.get('url') + 'uploads/'); global.nconf = nconf; - console.log('Info: Initializing NodeBB v' + pkg.version + ', on port ' + nconf.get('port') + ', using Redis store at ' + nconf.get('redis:host') + ':' + nconf.get('redis:port') + '.'); - console.log('Info: Base Configuration OK.'); + winston.info('Initializing NodeBB v' + pkg.version + ', on port ' + nconf.get('port') + ', using Redis store at ' + nconf.get('redis:host') + ':' + nconf.get('redis:port') + '.'); + winston.info('Base Configuration OK.'); // TODO: Replace this with nconf-redis var meta = require('./src/meta.js'); @@ -84,10 +99,10 @@ if(nconf.get('upgrade')) { //setup scripts to be moved outside of the app in future. function setup_categories() { - console.log('Info: Checking categories...'); + winston.info('Checking categories...'); categories.getAllCategories(function(data) { if (data.categories.length === 0) { - console.log('Info: Setting up default categories...'); + winston.info('Setting up default categories...'); fs.readFile(config.ROOT_DIRECTORY + '/install/data/categories.json', function(err, default_categories) { default_categories = JSON.parse(default_categories); @@ -98,21 +113,24 @@ if(nconf.get('upgrade')) { }); - console.log('Info: Hardcoding uid 1 as an admin'); + winston.info('Hardcoding uid 1 as an admin'); var user = require('./src/user.js'); user.makeAdministrator(1); + + } else { - console.log('Info: Categories OK. Found ' + data.categories.length + ' categories.'); + winston.info('Categories OK. Found ' + data.categories.length + ' categories.'); } }); } + setup_categories(); }(global.configuration)); }); } else { // New install, ask setup questions - if (nconf.get('setup')) console.log('Info: NodeBB Setup Triggered via Command Line'); - else console.log('Info: Configuration not found, starting NodeBB setup'); + if (nconf.get('setup')) winston.info('NodeBB Setup Triggered via Command Line'); + else winston.info('Configuration not found, starting NodeBB setup'); var install = require('./src/install'); @@ -124,7 +142,7 @@ if(nconf.get('upgrade')) { install.setup(function(err) { if (err) { - console.log('Error: There was a problem completing NodeBB setup: ', err.message); + winston.error('There was a problem completing NodeBB setup: ', err.message); } else { if (!nconf.get('setup')) { process.stdout.write( @@ -132,7 +150,7 @@ if(nconf.get('upgrade')) { ); } } - + process.exit(); }); } \ No newline at end of file diff --git a/package.json b/package.json index 68c77cde5a..ed0c057ace 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPLv3 or later", "description": "NodeBB Forum", - "version": "0.0.4", + "version": "0.0.5", "homepage": "http://www.nodebb.org", "repository": { "type": "git", @@ -33,7 +33,8 @@ "sitemap": "~0.6.0", "cheerio": "~0.12.0", "request": "~2.25.0", - "reds": "~0.2.4" + "reds": "~0.2.4", + "winston": "~0.7.2" }, "bugs": { "url": "https://github.com/designcreateplay/NodeBB/issues" diff --git a/public/css/style.less b/public/css/style.less index e325264302..bc7bb72e08 100644 --- a/public/css/style.less +++ b/public/css/style.less @@ -197,6 +197,12 @@ footer.footer { font-weight:bold; } +.account-block { + div { + padding-bottom:10px; + } +} + .account-picture-block{ display:inline-block; vertical-align:top; @@ -213,7 +219,6 @@ footer.footer { .user-profile-picture { width:128px; - margin-bottom:10px; } .user-picture-label { @@ -392,7 +397,7 @@ body .navbar .nodebb-inline-block { #admin-redis-info { span { display:inline-block; - width:200px; + width:220px; } } @@ -829,7 +834,7 @@ body .navbar .nodebb-inline-block { .form-search { float: left; margin-top: 5px; - margin-bottom:0px; + margin-bottom: 5px; } .search-result-post { diff --git a/public/css/topic.less b/public/css/topic.less index c6b02c10c3..ff770f7345 100644 --- a/public/css/topic.less +++ b/public/css/topic.less @@ -117,8 +117,6 @@ .topic-title { width: auto; - white-space: nowrap; - text-overflow:ellipsis; overflow: hidden; margin: 0; padding: 0; diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index d038fcf037..e1c2eea572 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -26,6 +26,7 @@ var ajaxify = {}; }; ajaxify.go = function(url, callback, template, quiet) { + $(window).off('scroll'); // leave room and join global app.enter_room('global'); diff --git a/public/src/app.js b/public/src/app.js index f28a25af5e..d166bb8104 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -5,11 +5,12 @@ var socket, (function() { - + var showWelcomeMessage = false; + function loadConfig() { $.ajax({ - url: RELATIVE_PATH + '/config.json?v=' + new Date().getTime(), + url: RELATIVE_PATH + '/api/config', success: function(data) { API_URL = data.api_url; @@ -28,10 +29,6 @@ var socket, socket.on('event:alert', function(data) { app.alert(data); }); - - socket.on('event:consolelog', function(data) { - console.log(data); - }); socket.on('connect', function(data){ if(reconnecting) { @@ -285,8 +282,9 @@ var socket, timeout: 5000 }); } - - if(location.href.indexOf('loggedin') !== -1) { + + if(showWelcomeMessage) { + showWelcomeMessage = false; if(document.readyState !== 'complete') { $(document).ready(showAlert); } else { @@ -371,6 +369,8 @@ var socket, }) }); + showWelcomeMessage = location.href.indexOf('loggedin') !== -1; + loadConfig(); diff --git a/public/src/forum/admin/users.js b/public/src/forum/admin/users.js index 37204dfbec..088cf2fa43 100644 --- a/public/src/forum/admin/users.js +++ b/public/src/forum/admin/users.js @@ -8,6 +8,11 @@ return (parent.attr('data-admin') !== "0"); } + function isUserBanned(element) { + var parent = $(element).parents('.users-box'); + return (parent.attr('data-banned') !== "" && parent.attr('data-banned') !== "0"); + } + function getUID(element) { var parent = $(element).parents('.users-box'); return parent.attr('data-uid'); @@ -34,6 +39,20 @@ deleteBtn.show(); }); + jQuery('.ban-btn').each(function(index, element) { + var banBtn = $(element); + var isAdmin = isUserAdmin(banBtn); + var isBanned = isUserBanned(banBtn); + + if(isAdmin) + banBtn.addClass('disabled'); + else if(isBanned) + banBtn.addClass('btn-warning'); + else + banBtn.removeClass('btn-warning'); + + }); + jQuery('.admin-btn').on('click', function() { var adminBtn = $(this); var isAdmin = isUserAdmin(adminBtn); @@ -74,13 +93,38 @@ return false; }); + + jQuery('.ban-btn').on('click', function() { + var banBtn = $(this); + var isAdmin = isUserAdmin(banBtn); + var isBanned = isUserBanned(banBtn); + var parent = banBtn.parents('.users-box'); + var uid = getUID(banBtn); + + if(!isAdmin) { + if(isBanned) { + socket.emit('api:admin.user.unbanUser', uid); + banBtn.removeClass('btn-warning'); + parent.attr('data-banned', 0); + } else { + bootbox.confirm('Do you really want to ban "' + parent.attr('data-username') +'"?', function(confirm) { + socket.emit('api:admin.user.banUser', uid); + banBtn.addClass('btn-warning'); + parent.attr('data-banned', 1); + }); + } + } + + return false; + }); } jQuery('document').ready(function() { - var yourid = templates.get('yourid'); - var timeoutId = 0; + var yourid = templates.get('yourid'), + timeoutId = 0, + loadingMoreUsers = false; var url = window.location.href, parts = url.split('/'), @@ -114,8 +158,7 @@ socket.removeAllListeners('api:admin.user.search'); socket.on('api:admin.user.search', function(data) { - - var html = templates.prepare(templates['admin/users'].blocks['users']).parse({ + var html = templates.prepare(templates['admin/users'].blocks['users']).parse({ users: data }), userListEl = document.querySelector('.users'); @@ -139,6 +182,45 @@ initUsers(); }); + function onUsersLoaded(users) { + var html = templates.prepare(templates['admin/users'].blocks['users']).parse({ users: users }); + $('#users-container').append(html); + } + + function loadMoreUsers() { + var set = ''; + if(active === 'latest') { + set = 'users:joindate'; + } else if(active === 'sort-posts') { + set = 'users:postcount'; + } else if(active === 'sort-reputation') { + set = 'users:reputation'; + } + + if(set) { + loadingMoreUsers = true; + socket.emit('api:users.loadMore', { + set: set, + after: $('#users-container').children().length + }, function(data) { + if(data.users.length) { + onUsersLoaded(data.users); + } + loadingMoreUsers = false; + }); + } + } + + $('#load-more-users-btn').on('click', loadMoreUsers); + + $(window).off('scroll').on('scroll', function() { + var bottom = (document.body.offsetHeight - $(window).height()) * 0.9; + + if (document.body.scrollTop > bottom && !loadingMoreUsers) { + loadMoreUsers(); + } + }); + }); - + }()); \ No newline at end of file diff --git a/public/src/forum/category.js b/public/src/forum/category.js index 5720988f74..4c94174488 100644 --- a/public/src/forum/category.js +++ b/public/src/forum/category.js @@ -122,10 +122,9 @@ } $(window).off('scroll').on('scroll', function(ev) { - var windowHeight = document.body.offsetHeight - $(window).height(), - half = windowHeight / 2; + var bottom = (document.body.offsetHeight - $(window).height()) * 0.9; - if (document.body.scrollTop > half && !loadingMoreTopics) { + if (document.body.scrollTop > bottom && !loadingMoreTopics) { loadMoreTopics(cid); } }); diff --git a/public/src/forum/login.js b/public/src/forum/login.js index d5faee48df..2be3b5e701 100644 --- a/public/src/forum/login.js +++ b/public/src/forum/login.js @@ -27,11 +27,15 @@ url: RELATIVE_PATH + '/login', data: loginData, success: function(data, textStatus, jqXHR) { - $('#login-error-notify').hide(); - window.location.replace(RELATIVE_PATH + "/?loggedin"); + if(!data.success) { + $('#login-error-notify').html(data.message).show(); + } else { + $('#login-error-notify').hide(); + window.location.replace(RELATIVE_PATH + "/?loggedin"); + } }, error : function(data, textStatus, jqXHR) { - $('#login-error-notify').show().delay(1000).fadeOut(250); + $('#login-error-notify').show(); }, dataType: 'json', async: true, diff --git a/public/src/forum/recent.js b/public/src/forum/recent.js index 44a078a278..1a81ac54fd 100644 --- a/public/src/forum/recent.js +++ b/public/src/forum/recent.js @@ -69,10 +69,9 @@ } $(window).off('scroll').on('scroll', function() { - var windowHeight = document.body.offsetHeight - $(window).height(), - half = windowHeight / 2; + var bottom = (document.body.offsetHeight - $(window).height()) * 0.9; - if (document.body.scrollTop > half && !loadingMoreTopics) { + if (document.body.scrollTop > bottom && !loadingMoreTopics) { loadMoreTopics(); } }); diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 2b04f4a2d3..fe3dd042fa 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -202,10 +202,9 @@ // Infinite scrolling of posts $(window).off('scroll').on('scroll', function() { - var windowHeight = document.body.offsetHeight - $(window).height(), - half = windowHeight / 2; + var bottom = (document.body.offsetHeight - $(window).height()) * 0.9; - if (document.body.scrollTop > half && !app.infiniteLoaderActive && $('#post-container').children().length) { + if (document.body.scrollTop > bottom && !app.infiniteLoaderActive && $('#post-container').children().length) { app.loadMorePosts(tid); } }); @@ -255,11 +254,9 @@ var element = $(this).find('i'); if(element.attr('class') == 'icon-star-empty') { - element.attr('class', 'icon-star'); socket.emit('api:posts.favourite', {pid: pid, room_id: app.current_room}); } else { - element.attr('class', 'icon-star-empty'); socket.emit('api:posts.unfavourite', {pid: pid, room_id: app.current_room}); } }); @@ -388,7 +385,14 @@ }); socket.on('api:posts.favourite', function(data) { - if (data.status !== 'ok' && data.pid) { + if (data.status === 'ok' && data.pid) { + var favEl = document.querySelector('.post_rep_' + data.pid).nextSibling; + if (favEl) favEl.className = 'icon-star'; + } + }); + + socket.on('api:posts.unfavourite', function(data) { + if (data.status === 'ok' && data.pid) { var favEl = document.querySelector('.post_rep_' + data.pid).nextSibling; if (favEl) favEl.className = 'icon-star-empty'; } diff --git a/public/src/forum/unread.js b/public/src/forum/unread.js index 8b2342df36..1515ba8966 100644 --- a/public/src/forum/unread.js +++ b/public/src/forum/unread.js @@ -84,10 +84,9 @@ } $(window).off('scroll').on('scroll', function() { - var windowHeight = document.body.offsetHeight - $(window).height(), - half = windowHeight / 2; - - if (document.body.scrollTop > half && !loadingMoreTopics) { + var bottom = (document.body.offsetHeight - $(window).height()) * 0.9; + + if (document.body.scrollTop > bottom && !loadingMoreTopics) { loadMoreTopics(); } }); diff --git a/public/src/forum/users.js b/public/src/forum/users.js index 8a56698e5d..74283a3467 100644 --- a/public/src/forum/users.js +++ b/public/src/forum/users.js @@ -2,6 +2,7 @@ $(document).ready(function() { var timeoutId = 0; + var loadingMoreUsers = false; var url = window.location.href, parts = url.split('/'), @@ -74,6 +75,46 @@ $(element).html(app.addCommas($(element).html())); }); + function onUsersLoaded(users) { + var html = templates.prepare(templates['users'].blocks['users']).parse({ users: users }); + $('#users-container').append(html); + } + + function loadMoreUsers() { + var set = ''; + if(active === 'users-latest' || active === 'users') { + set = 'users:joindate'; + } else if(active === 'users-sort-posts') { + set = 'users:postcount'; + } else if(active === 'users-sort-reputation') { + set = 'users:reputation'; + } + + if(set) { + loadingMoreUsers = true; + socket.emit('api:users.loadMore', { + set: set, + after: $('#users-container').children().length + }, function(data) { + if(data.users.length) { + onUsersLoaded(data.users); + } else { + $('#load-more-users-btn').addClass('disabled'); + } + loadingMoreUsers = false; + }); + } + } + + $('#load-more-users-btn').on('click', loadMoreUsers); + + $(window).off('scroll').on('scroll', function() { + var bottom = (document.body.offsetHeight - $(window).height()) * 0.9; + + if (document.body.scrollTop > bottom && !loadingMoreUsers) { + loadMoreUsers(); + } + }); }); }()); \ No newline at end of file diff --git a/public/src/modules/composer.js b/public/src/modules/composer.js index 1d00f68172..1f8235b9c0 100644 --- a/public/src/modules/composer.js +++ b/public/src/modules/composer.js @@ -299,22 +299,22 @@ define(['taskbar'], function(taskbar) { titleEl.value = titleEl.value.trim(); bodyEl.value = bodyEl.value.trim(); - if (titleEl.value.length < 3) { + if (titleEl.value.length < config.minimumTitleLength) { return app.alert({ type: 'error', timeout: 2000, title: 'Title too short', - message: "Please enter a longer title. At least 3 characters.", + message: "Please enter a longer title. At least " + config.minimumTitleLength+ " characters.", alert_id: 'post_error' }); } - if (bodyEl.value.length < 8) { + if (bodyEl.value.length < config.minimumPostLength) { return app.alert({ type: 'error', timeout: 2000, title: 'Content too short', - message: "Please enter a longer post. At least 8 characters.", + message: "Please enter a longer post. At least " + config.minimumPostLength + " characters.", alert_id: 'post_error' }); } diff --git a/public/templates/account.tpl b/public/templates/account.tpl index b90d4c307a..7d69bb4679 100644 --- a/public/templates/account.tpl +++ b/public/templates/account.tpl @@ -17,13 +17,16 @@
-
+