fixed conflicts, added new language key for users/online

This commit is contained in:
psychobunny
2013-09-24 15:15:39 -04:00
40 changed files with 11076 additions and 915 deletions

1
.gitignore vendored
View File

@@ -6,6 +6,7 @@ npm-debug.log
node_modules/
sftp-config.json
config.json
public/src/nodebb.min.js
public/config.json
public/css/*.css
public/themes/*

View File

@@ -1,9 +1,12 @@
Please support NodeBB development! Check out our IndieGoGo campaign and like, share, and follow us :)
[NodeBB Homepage](http://www.nodebb.org/ "NodeBB") # [Follow on Twitter](http://www.twitter.com/NodeBB/ "NodeBB Twitter") # [Like us on Facebook](http://www.facebook.com/NodeBB/ "NodeBB Facebook")
# NodeBB
**NodeBB** is a robust Node.js driven forum built on a redis database. It is powered by web sockets, and is compatible down to IE8.
* [NodeBB Homepage](http://www.nodebb.org/ "NodeBB")
* [Follow on Twitter](http://www.twitter.com/NodeBB/ "NodeBB Twitter")
* [Like us on Facebook](http://www.facebook.com/NodeBB/ "NodeBB Facebook")
* [Join us on IRC](https://kiwiirc.com/client/irc.freenode.net/nodebb) - #nodebb on Freenode
![NodeBB Main Category Listing](http://i.imgur.com/ZBrHqLr.png)
![NodeBB Topic Page](http://i.imgur.com/YSBA6Vr.png)

2
app.js
View File

@@ -24,8 +24,10 @@
nconf.argv().env();
var fs = require('fs'),
async = require('async'),
winston = require('winston'),
pkg = require('./package.json'),
path = require('path'),
meta;
// Runtime environment

View File

@@ -13,7 +13,7 @@
"socket.io": "~0.9.16",
"redis": "0.8.3",
"express": "3.2.0",
"express-namespace": "0.1.1",
"express-namespace": "~0.1.1",
"emailjs": "0.3.4",
"cookie": "0.0.6",
"connect-redis": "1.4.5",
@@ -37,7 +37,9 @@
"nodebb-plugin-mentions": "~0.1.0",
"nodebb-plugin-markdown": "~0.1.0",
"rss": "~0.2.0",
"prompt": "~0.2.11"
"prompt": "~0.2.11",
"uglify-js": "~2.4.0",
"validator": "~1.5.1"
},
"bugs": {
"url": "https://github.com/designcreateplay/NodeBB/issues"

View File

@@ -2,6 +2,7 @@
"latest_users": "Latest Users",
"top_posters": "Top Posters",
"most_reputation": "Most Reputation",
"online": "Online",
"search": "Search",
"enter_username": "Enter a username to search",
"load_more": "Load More"

View File

@@ -62,10 +62,12 @@ var ajaxify = {};
if (templates.is_available(tpl_url) && !templates.force_refresh(tpl_url)) {
if (quiet !== true) {
if (window.history && window.history.pushState) {
window.history.pushState({
"url": url
}, url, RELATIVE_PATH + "/" + url);
}
}
translator.load(tpl_url);
@@ -105,26 +107,29 @@ var ajaxify = {};
// Enhancing all anchors to ajaxify...
$(document.body).on('click', 'a', function (e) {
function hrefEmpty(href) {
return href == 'javascript:;' || href == window.location.href + "#" || href.slice(-1) === "#";
}
if (hrefEmpty(this.href)) return;
var url = this.href.replace(rootUrl + '/', '');
if (this.target !== '') return;
if (this.protocol === 'javascript:') return;
if (!e.ctrlKey && e.which === 1) {
if (this.host === window.location.host) {
var url = this.href.replace(rootUrl + '/', '');
if (ajaxify.go(url)) {
e.preventDefault();
}
} else {
ajaxify.go('outgoing?url=' + encodeURIComponent(this.href));
e.preventDefault();
}
}
});
});
function exec_body_scripts(body_el) {
// modified from http://stackoverflow.com/questions/2592092/executing-script-elements-inserted-with-innerhtml
@@ -156,7 +161,7 @@ var ajaxify = {};
var scripts = [],
script,
children_nodes = body_el.childNodes,
children_nodes = $(body_el).children(),
child,
i;

View File

@@ -7,7 +7,7 @@ var socket,
(function () {
var showWelcomeMessage = false;
function loadConfig() {
app.loadConfig = function() {
$.ajax({
url: RELATIVE_PATH + '/api/config',
@@ -15,15 +15,21 @@ var socket,
API_URL = data.api_url;
config = data;
if(socket) {
socket.disconnect();
socket.socket.connect();
} else {
socket = io.connect(config.socket.address);
var reconnecting = false;
var reconnectTries = 0;
socket.on('event:connect', function (data) {
console.log('connected to nodebb socket: ', data);
app.username = data.username;
app.showLoginMessage();
socket.emit('api:updateHeader', {
fields: ['username', 'picture', 'userslug']
});
});
socket.on('event:alert', function (data) {
@@ -116,8 +122,7 @@ var socket,
});
app.enter_room('global');
}
},
async: false
});
@@ -275,7 +280,7 @@ var socket,
if (active) {
jQuery('#main-nav li a').each(function () {
var href = this.getAttribute('href');
if (active == "sort-posts" || active == "sort-reputation" || active == "search" || active == "latest")
if (active == "sort-posts" || active == "sort-reputation" || active == "search" || active == "latest" || active == "online")
active = 'users';
if (href && href.match(active)) {
jQuery(this.parentNode).addClass('active');
@@ -286,6 +291,7 @@ var socket,
$('span.timeago').timeago();
setTimeout(function () {
window.scrollTo(0, 1); // rehide address bar on mobile after page load completes.
}, 100);
@@ -402,7 +408,8 @@ var socket,
function animateScroll() {
$('body,html').animate({
scrollTop: scrollTo.offset().top - container.offset().top + container.scrollTop() - $('#header-menu').height()
});
}, 400);
//$('body,html').scrollTop(scrollTo.offset().top - container.offset().top + container.scrollTop() - $('#header-menu').height());
}
if (!scrollTo.length && tid) {
@@ -427,19 +434,16 @@ var socket,
}
jQuery('document').ready(function () {
translator.load('global');
$('#search-form').on('submit', function () {
var input = $(this).find('input');
ajaxify.go("search/" + input.val(), null, "search");
input.val('');
return false;
})
});
});
showWelcomeMessage = location.href.indexOf('loggedin') !== -1;
loadConfig();
app.loadConfig();
}());

View File

@@ -27,6 +27,7 @@ $(document).ready(function() {
},
uploadProgress: function(event, position, total, percent) {
console.log(percent);
$('#upload-progress-bar').css('width', percent + '%');
},
@@ -60,25 +61,25 @@ $(document).ready(function() {
});
function hideAlerts() {
$('#alert-status').hide();
$('#alert-success').hide();
$('#alert-error').hide();
$('#upload-progress-box').hide();
$('#alert-status').addClass('hide');
$('#alert-success').addClass('hide');
$('#alert-error').addClass('hide');
$('#upload-progress-box').addClass('hide');
}
function status(message) {
hideAlerts();
$('#alert-status').text(message).show();
$('#alert-status').text(message).removeClass('hide');
}
function success(message) {
hideAlerts();
$('#alert-success').text(message).show();
$('#alert-success').text(message).removeClass('hide');
}
function error(message) {
hideAlerts();
$('#alert-error').text(message).show();
$('#alert-error').text(message).removeClass('hide');
}
function changeUserPicture(type) {

View File

@@ -26,7 +26,6 @@
fields: ['username', 'picture', 'userslug']
});
socket.on('api:updateHeader', function(data) {
jQuery('#search-button').on('click', function() {
jQuery('#search-fields').removeClass('hide').show();
jQuery(this).hide();
@@ -59,6 +58,7 @@
if (data['username'])
userLabel.find('span').html(data['username']);
} else {
rightMenu.empty();
var userli = $('<li> \
<a id="user_label" href="/user/' + data['userslug'] + '"> \
<img src="' + data['picture'] + '"/> \
@@ -67,7 +67,16 @@
</li>');
rightMenu.append(userli);
var logoutli = $('<li><a href="' + RELATIVE_PATH + '/logout">Log out</a></li>');
var logoutli = $('<li><a href="#">Log out</a></li>');
logoutli.on('click', function() {
var csrf_token = $('#csrf_token').val();
$.post(RELATIVE_PATH + '/logout', {
_csrf: csrf_token
}, function() {
window.location = RELATIVE_PATH + '/';
});
});
rightMenu.append(logoutli);
}
} else {
@@ -86,6 +95,11 @@
right_menu.appendChild(registerEl);
right_menu.appendChild(loginEl);
}
$('#main-nav a,#right-menu a').off('click').on('click', function() {
if($('.navbar .navbar-collapse').hasClass('in'))
$('.navbar-header button').click();
});
});
// Notifications dropdown

View File

@@ -32,7 +32,12 @@
$('#login-error-notify').show();
} else {
$('#login-error-notify').hide();
window.location.replace(RELATIVE_PATH + "/?loggedin");
//window.location.replace(RELATIVE_PATH + "/?loggedin");
history.go(-1);
//setTimeout(function(){
app.loadConfig();
//}, 500);
//socket.emit('api:updateHeader');
}
},
error: function(data, textStatus, jqXHR) {

View File

@@ -12,6 +12,13 @@
$('#search-form input').val(searchQuery);
$('#mobile-search-form').off('submit').on('submit', function() {
var input = $(this).find('input');
ajaxify.go("search/" + input.val(), null, "search");
input.val('');
return false;
});
});
})();

View File

@@ -215,19 +215,30 @@
}, false);
}
$(window).off('scroll').on('scroll', function() {
var bottom = ($(document).height() - $(window).height()) * 0.9;
enableInfiniteLoading();
if ($(window).scrollTop() > bottom && !app.infiniteLoaderActive && $('#post-container').children().length) {
app.loadMorePosts(tid);
var bookmark = localStorage.getItem('topic:' + tid + ':bookmark');
if(bookmark) {
app.scrollToPost(parseInt(bookmark, 10));
}
});
$('#post-container').on('click', '.deleted', function(ev) {
$(this).toggleClass('deleted-expanded');
});
});
function enableInfiniteLoading() {
$(window).off('scroll').on('scroll', function() {
var bottom = ($(document).height() - $(window).height()) * 0.9;
if ($(window).scrollTop() > bottom && !app.infiniteLoaderActive && $('#post-container').children().length) {
app.loadMorePosts(tid);
console.log('window scrolling');
}
});
}
var reply_fn = function() {
var selectionText = '',
selection = window.getSelection() || document.getSelection();
@@ -659,6 +670,7 @@
var scrollBottom = scrollTop + windowHeight;
if (scrollTop < 50 && postcount > 1) {
localStorage.removeItem("topic:" + tid + ":bookmark");
postAuthorImage.src = (jQuery('.main-post .avatar img').attr('src'));
mobileAuthorOverlay.innerHTML = 'Posted by ' + jQuery('.main-post').attr('data-username') + ', ' + jQuery('.main-post').find('.relativeTimeAgo').html();
pagination.innerHTML = '0 out of ' + postcount;
@@ -666,7 +678,7 @@
}
var count = 0;
var count = 0, smallestNonNegative = 0;
jQuery('.sub-posts').each(function() {
count++;
@@ -682,6 +694,11 @@
if (inView) {
if(elTop - scrollTop > smallestNonNegative) {
localStorage.setItem("topic:" + tid + ":bookmark", el.attr('data-pid'));
smallestNonNegative = Number.MAX_VALUE;
}
pagination.innerHTML = this.postnumber + ' out of ' + postcount;
postAuthorImage.src = (jQuery(this).find('.profile-image-block img').attr('src'));
mobileAuthorOverlay.innerHTML = 'Posted by ' + jQuery(this).attr('data-username') + ', ' + jQuery(this).find('.relativeTimeAgo').html();

View File

@@ -74,7 +74,12 @@
});
socket.on('api:user.isOnline', function(data) {
if(active == 'online' && !loadingMoreUsers) {
$('#users-container').empty();
startLoading('users:online', 0);
}
});
function onUsersLoaded(users) {
var html = templates.prepare(templates['users'].blocks['users']).parse({
@@ -91,23 +96,31 @@
set = 'users:postcount';
} else if (active === 'sort-reputation') {
set = 'users:reputation';
} else if (active === 'online') {
set = 'users:online';
}
if (set) {
startLoading(set, $('#users-container').children().length);
}
}
function startLoading(set, after) {
loadingMoreUsers = true;
socket.emit('api:users.loadMore', {
set: set,
after: $('#users-container').children().length
after: after
}, function(data) {
if (data.users.length) {
onUsersLoaded(data.users);
$('#load-more-users-btn').removeClass('disabled');
} else {
$('#load-more-users-btn').addClass('disabled');
}
loadingMoreUsers = false;
});
}
}
$('#load-more-users-btn').on('click', loadMoreUsers);

View File

@@ -180,7 +180,6 @@
else
template_data['relative_path'] = RELATIVE_PATH;
translator.translate(templates[tpl_url].parse(template_data), function (translatedTemplate) {
document.getElementById('content').innerHTML = translatedTemplate;
});
@@ -233,7 +232,7 @@
}
function makeRegex(block) {
return new RegExp("<!-- BEGIN " + block + " -->[^]*<!-- END " + block + " -->", 'g');
return new RegExp("<!-- BEGIN " + block + " -->[\\s\\S]*<!-- END " + block + " -->", 'g');
}
function getBlock(regex, block, template) {
@@ -302,7 +301,7 @@
}
if (namespace) {
var regex = new RegExp("{" + namespace + "[^]*?}", 'g');
var regex = new RegExp("{" + namespace + "[\\s\\S]*?}", 'g');
template = template.replace(regex, '');
}

View File

@@ -48,13 +48,15 @@
<input id="imageUploadCsrf" type="hidden" name="_csrf" value="" />
</form>
<div id="upload-progress-box" class="progress progress-striped active hide">
<div id="upload-progress-bar" class="bar" style="width: 0%;"></div>
<div id="upload-progress-box" class="progress progress-striped">
<div id="upload-progress-bar" class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="0" aria-valuemin="0">
<span class="sr-only"> success</span>
</div>
</div>
<div id="alert-status" class="alert hide"></div>
<div id="alert-status" class="alert alert-info hide"></div>
<div id="alert-success" class="alert alert-success hide"></div>
<div id="alert-error" class="alert alert-error hide"></div>
<div id="alert-error" class="alert alert-danger hide"></div>
</div>
<div class="modal-footer">
<button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>

View File

@@ -15,7 +15,7 @@
<div class="alert alert-warning">
<p>
<strong>Interesed in writing plugins for NodeBB?</strong>
<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>.

View File

@@ -9,7 +9,9 @@
<label>Site Description</label>
<input type="text" class="form-control" placeholder="A short description about your community" data-field="description" /><br />
<label>Imgur Client ID</label>
<input type="text" class="form-control" placeholder="Imgur ClientID for image uploads" data-field="imgurClientID" />
<input type="text" class="form-control" placeholder="Imgur ClientID for image uploads" data-field="imgurClientID" /><br />
<label>Maximum User Image Size</label>
<input type="text" class="form-control" placeholder="Maximum size of uploaded user images in kilobytes" data-field="maximumProfileImageSize" />
</form>
</div>

View File

@@ -28,10 +28,12 @@
<div class="{topic_row_size}">
<ul id="topics-container">
<!-- BEGIN topics -->
<a href="../../topic/{topics.slug}"><li class="category-item {topics.deleted-class}">
<li class="category-item {topics.deleted-class}">
<div class="row">
<div class="col-md-12 topic-row">
<div class="latest-post visible-lg visible-md">
<a href="../../topic/{topics.slug}#{topics.teaser_pid}">
<div class="pull-right">
<img class="img-rounded" style="width: 48px; height: 48px; /*temporary*/" src="{topics.teaser_userpicture}" />
<p>{topics.teaser_text}</p>
@@ -39,7 +41,9 @@
<strong>{topics.teaser_username}</strong> posted <span class="timeago" title="{topics.teaser_timestamp}"></span>
</p>
</div>
</a>
</div>
<a href="../../topic/{topics.slug}">
<div>
<h3><span class="topic-title"><span class="badge {topics.badgeclass}">{topics.postcount}</span>{topics.title}</span></h3>
<small>
@@ -48,9 +52,11 @@
<strong>{topics.username}</strong>.
</small>
</div>
</a>
</div>
</div>
</li></a>
</li>
<!-- END topics -->
</ul>
</div>

View File

@@ -1,17 +1,17 @@
{
"custom_mapping": {
"admin/testing/categories[^]*": "admin/testing/categories",
"admin/topics[^]*": "admin/topics",
"admin/categories[^]*": "admin/categories",
"admin/users[^]*": "admin/users",
"admin/redis[^]*": "admin/redis",
"admin/index[^]*": "admin/index",
"admin/themes[^]*": "admin/themes",
"admin/plugins[^]*": "admin/plugins",
"^admin/settings[^]*": "admin/settings",
"admin/twitter[^]*": "admin/twitter",
"admin/facebook[^]*": "admin/facebook",
"admin/gplus[^]*": "admin/gplus",
"admin/testing/categories.*": "admin/testing/categories",
"admin/topics.*": "admin/topics",
"admin/categories.*": "admin/categories",
"admin/users.*": "admin/users",
"admin/redis.*": "admin/redis",
"admin/index.*": "admin/index",
"admin/themes.*": "admin/themes",
"admin/plugins.*": "admin/plugins",
"^admin/settings.*": "admin/settings",
"admin/twitter.*": "admin/twitter",
"admin/facebook.*": "admin/facebook",
"admin/gplus.*": "admin/gplus",
"admin/motd/?$": "admin/motd",
"admin/groups/?$": "admin/groups",
"install/?$": "install/mail",
@@ -22,19 +22,19 @@
"users/latest": "users",
"users/sort-reputation": "users",
"users/search": "users",
"user[^]*edit": "accountedit",
"user[^]*following": "following",
"user[^]*followers": "followers",
"user[^]*settings": "accountsettings",
"user[^]*favourites": "favourites",
"user/[^]*": "account",
"user.*edit": "accountedit",
"user.*following": "following",
"user.*followers": "followers",
"user.*settings": "accountsettings",
"user.*favourites": "favourites",
"user/.*": "account",
"recent": "recent",
"unread": "unread",
"popular": "category",
"active": "category",
"search": "search",
"reset/[^]*": "reset_code",
"reset/.*": "reset_code",
"reset": "reset"
},

View File

@@ -8,28 +8,18 @@
<script>
var RELATIVE_PATH = "{relative_path}";
</script>
<script src="http://code.jquery.com/jquery.js"></script>
<script src="{relative_path}/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js"></script>
<script src="{relative_path}/vendor/jquery/js/jquery.timeago.js"></script>
<script src="{relative_path}/vendor/bootstrap/js/bootstrap.min.js"></script>
<script src="{relative_path}/socket.io/socket.io.js"></script>
<script src="{relative_path}/src/app.js"></script>
<script src="{relative_path}/vendor/requirejs/require.js"></script>
<script src="{relative_path}/vendor/bootbox/bootbox.min.js"></script>
<!-- BEGIN clientScripts -->
<script src="{relative_path}/{clientScripts.script}"></script>
<!-- END clientScripts -->
<script>
require.config({
baseUrl: "{relative_path}/src/modules",
waitSeconds: 3
});
</script>
<script src="{relative_path}/src/templates.js"></script>
<script src="{relative_path}/src/ajaxify.js"></script>
<script src="{relative_path}/src/translator.js"></script>
<script src="{relative_path}/src/jquery.form.js"></script>
<script src="{relative_path}/src/utils.js"></script>
<link rel="stylesheet" type="text/css" href="{relative_path}/css/nodebb.css" />
</head>
<body>
@@ -41,7 +31,9 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">{title}</a>
<a href="/">
<h1 class="navbar-brand forum-title">{title}</h1>
</a>
</div>
<div class="navbar-collapse collapse navbar-ex1-collapse">
@@ -58,6 +50,9 @@
<li class="visible-xs">
<a href="/search">[[global:header.search]]</a>
</li>
<li class="visible-xs">
<a href="/search">Search</a>
</li>
<li>
<a href="/"></a>
</li>

View File

@@ -6,11 +6,12 @@
<ul class="topics">
<!-- BEGIN topics -->
<li>
<span class="timestamp">{topics.teaser_timestamp}</span>
<a href="../../topic/{topics.slug}">{topics.title} ({topics.postcount})</a>
<div class="teaser">
<img class="img-thumbnail" src="{topics.teaser_userpicture}" />
<p>
{topics.teaser_text} &mdash; {topics.teaser_timestamp} ago
{topics.teaser_text}
</p>
<div class="clear"></div>
</div>

View File

@@ -3,8 +3,18 @@
<li class="active">Search</li>
</ol>
<form id="mobile-search-form" class="navbar-form navbar-right visible-xs" role="search" method="GET" action="">
<div class="" id="search-fields">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search" name="query" value="">
</div>
<button type="submit" class="btn btn-default hide">Search</button>
</div>
</form>
<div class="category search">
<div class="">
<div class="{show_results}">
<ul id="topics-container" data-search-query="{search_query}">
<h3>Topics</h3>
<div class="alert alert-info {show_no_topics}">No topics found!</div>

View File

@@ -3,6 +3,7 @@
<li class=''><a href='/users/latest'>[[users:latest_users]]</a></li>
<li class=''><a href='/users/sort-posts'>[[users:top_posters]]</a></li>
<li class=''><a href='/users/sort-reputation'>[[users:most_reputation]]</a></li>
<li class=''><a href='/users/online'>[[users:online]]</a></li>
<li class=''><a href='/users/search'>[[users:search]]</a></li>
</ul>

View File

@@ -7,7 +7,7 @@
padding-right: 30px;
}
a {
ul {
li {
list-style: none;
padding-bottom: 10px;
@@ -105,6 +105,8 @@
width: 70%;
margin-left: 10px;
overflow: hidden;
max-height: 33px;
margin-bottom: 0px;
}
}
}

View File

@@ -22,6 +22,12 @@
}
}
.forum-title {
padding-top: 15px;
padding-bottom: 15px;
margin: 0px;
}
.pagination-block {
position: absolute;
background: rgb(34, 34, 34);

View File

@@ -32,6 +32,13 @@ noscript {
.default;
}
.timestamp {
float: right;
color: #999;
font-style: italic;
font-size: 12px;
}
.teaser {
margin-left: 16px;
margin-top: 8px;

9921
public/vendor/jquery/js/jquery.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -113,6 +113,9 @@ var async = require('async'),
}, {
field: 'imgurClientID',
value: ''
}, {
field: 'maximumProfileImageSize',
value: 256
}];
async.each(defaults, function (configObj, next) {

View File

@@ -14,7 +14,9 @@ var utils = require('./../public/src/utils.js'),
if (!err) {
Meta.config = config;
callback();
} else winston.error(err);
} else {
winston.error(err);
}
});
},
list: function (callback) {
@@ -36,20 +38,24 @@ var utils = require('./../public/src/utils.js'),
},
set: function (field, value, callback) {
RDB.hset('config', field, value, function (err, res) {
if (callback)
if (callback) {
callback(err, res);
}
});
},
setOnEmpty: function (field, value, callback) {
this.get(field, function (err, curValue) {
if (!curValue) Meta.configs.set(field, value, callback);
else callback();
if (!curValue) {
Meta.configs.set(field, value, callback);
} else {
callback();
}
});
},
remove: function (field) {
RDB.hdel('config', field);
}
}
};
Meta.themes = {
get: function (callback) {
@@ -57,7 +63,9 @@ var utils = require('./../public/src/utils.js'),
fs.readdir(themePath, function (err, files) {
async.filter(files, function (file, next) {
fs.stat(path.join(themePath, file), function (err, fileStat) {
if (err) next(false);
if (err) {
next(false);
}
next((fileStat.isDirectory() && file.slice(0, 13) === 'nodebb-theme-'));
});
@@ -68,10 +76,15 @@ var utils = require('./../public/src/utils.js'),
if (fs.existsSync(config)) {
fs.readFile(config, function (err, file) {
var configObj = JSON.parse(file.toString());
if (!configObj.screenshot) configObj.screenshot = nconf.get('relative_path') + '/images/themes/default.png';
if (!configObj.screenshot) {
configObj.screenshot = nconf.get('relative_path') + '/images/themes/default.png';
}
next(err, configObj);
});
} else next();
} else {
next();
}
}, function (err, themes) {
themes = themes.filter(function (theme) {
return (theme !== undefined);
@@ -81,7 +94,7 @@ var utils = require('./../public/src/utils.js'),
});
});
}
}
};
Meta.title = {
build: function (urlFragment, current_user, callback) {
@@ -98,8 +111,11 @@ var utils = require('./../public/src/utils.js'),
}, function (err, values) {
var title;
if (err) title = Meta.config.title || 'NodeBB';
else title = (values.title ? values.title + ' | ' : '') + (Meta.config.title || 'NodeBB');
if (err) {
title = Meta.config.title || 'NodeBB';
} else {
title = (values.title ? values.title + ' | ' : '') + (Meta.config.title || 'NodeBB');
}
callback(null, title, values.notifCount);
});
@@ -125,9 +141,86 @@ var utils = require('./../public/src/utils.js'),
require('./topics').getTopicField(tid, 'title', function (err, title) {
callback(null, title);
});
} else callback(null);
} else {
callback(null);
}
}
};
Meta.js = {
scripts: [
'vendor/jquery/js/jquery.js',
'vendor/jquery/js/jquery-ui-1.10.3.custom.min.js',
'vendor/jquery/js/jquery.timeago.js',
'vendor/bootstrap/js/bootstrap.min.js',
'src/app.js',
'vendor/requirejs/require.js',
'vendor/bootbox/bootbox.min.js',
'src/templates.js',
'src/ajaxify.js',
'src/translator.js',
'src/jquery.form.js',
'src/utils.js'
],
minFile: path.join(__dirname, '..', 'public/src/nodebb.min.js'),
get: function (callback) {
var mtime,
jsPaths = this.scripts.map(function (jsPath) {
return path.join(__dirname, '..', '/public', jsPath);
});
if (process.env.NODE_ENV !== 'development') {
async.parallel({
mtime: function (next) {
async.map(jsPaths, fs.stat, function (err, stats) {
async.reduce(stats, 0, function (memo, item, callback) {
mtime = +new Date(item.mtime);
callback(null, mtime > memo ? mtime : memo);
}, next);
});
},
minFile: function (next) {
if (!fs.existsSync(Meta.js.minFile)) {
winston.warn('No minified client-side library found');
return next(null, 0);
}
fs.stat(Meta.js.minFile, function (err, stat) {
next(err, +new Date(stat.mtime));
});
}
}, function (err, results) {
if (results.minFile > results.mtime) {
winston.info('No changes to client-side libraries -- skipping minification');
callback(null, [path.relative(path.join(__dirname, '../public'), Meta.js.minFile)]);
} else {
Meta.js.minify(function () {
callback(null, [path.relative(path.join(__dirname, '../public'), Meta.js.minFile)]);
});
}
});
} else {
callback(null, this.scripts);
}
},
minify: function (callback) {
var uglifyjs = require('uglify-js'),
jsPaths = this.scripts.map(function (jsPath) {
return path.join(__dirname, '..', '/public', jsPath);
}),
minified;
winston.info('Minifying client-side libraries');
minified = uglifyjs.minify(jsPaths);
fs.writeFile(Meta.js.minFile, minified.code, function (err) {
if (!err) {
winston.info('Minified client-side libraries');
callback();
} else {
winston.error('Problem minifying client-side libraries, exiting.');
process.exit();
}
});
}
};
}(exports));

View File

@@ -137,7 +137,7 @@ var fs = require('fs'),
hookList = this.loadedHooks[hook];
if (hookList && Array.isArray(hookList)) {
if (global.env === 'development') winston.info('[plugins] Firing hook: \'' + hook + '\'');
//if (global.env === 'development') winston.info('[plugins] Firing hook: \'' + hook + '\'');
var hookType = hook.split(':')[0];
switch (hookType) {
case 'filter':

View File

@@ -87,7 +87,7 @@ var RDB = require('./redis.js'),
});
},
function(next) {
PostTools.toHTML(content, next);
PostTools.parse(content, next);
}
], function(err, results) {
io.sockets.in('topic_' + results[0].tid).emit('event:post_edited', {
@@ -128,7 +128,7 @@ var RDB = require('./redis.js'),
});
// Delete the thread if it is the last undeleted post
threadTools.get_latest_undeleted_pid(postData.tid, function(err, pid) {
threadTools.getLatestUndeletedPid(postData.tid, function(err, pid) {
if (err && err.message === 'no-undeleted-pids-found') {
threadTools.delete(postData.tid, -1, function(err) {
if (err) winston.error('Could not delete topic (tid: ' + postData.tid + ')', err.stack);
@@ -164,7 +164,7 @@ var RDB = require('./redis.js'),
pid: pid
});
threadTools.get_latest_undeleted_pid(postData.tid, function(err, pid) {
threadTools.getLatestUndeletedPid(postData.tid, function(err, pid) {
posts.getPostField(pid, 'timestamp', function(timestamp) {
topics.updateTimestamp(postData.tid, timestamp);
});
@@ -190,28 +190,11 @@ var RDB = require('./redis.js'),
});
}
PostTools.toHTML = function(raw, callback) {
PostTools.parse = function(raw, callback) {
raw = raw || '';
plugins.fireHook('filter:post.parse', raw, function(parsed) {
var cheerio = require('cheerio');
if (parsed && parsed.length > 0) {
var parsedContentDOM = cheerio.load(parsed);
var domain = nconf.get('url');
parsedContentDOM('a').each(function() {
this.attr('rel', 'nofollow');
var href = this.attr('href');
if (href && !href.match(domain) && !utils.isRelativeUrl(href)) {
this.attr('href', domain + 'outgoing?url=' + encodeURIComponent(href));
}
});
callback(null, parsedContentDOM.html());
} else {
callback(null, '<p></p>');
}
callback(null, parsed);
});
}

View File

@@ -36,7 +36,7 @@ var RDB = require('./redis.js'),
user.getUserFields(post.uid, ['username', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned'], function(err, userData) {
if (err) return callback();
postTools.toHTML(userData.signature, function(err, signature) {
postTools.parse(userData.signature, function(err, signature) {
post.username = userData.username || 'anonymous';
post.userslug = userData.userslug || '';
post.user_rep = userData.reputation || 0;
@@ -70,7 +70,7 @@ var RDB = require('./redis.js'),
Posts.getPostFields(pid, ['pid', 'tid', 'content', 'uid', 'timestamp', 'deleted'], function(postData) {
if (postData.deleted === '1') return callback(null);
else {
postData.relativeTime = new Date(parseInt(postData.timestamp, 10)).toISOString();
postData.relativeTime = new Date(parseInt(postData.timestamp || 0, 10)).toISOString();
next(null, postData);
}
});
@@ -91,7 +91,7 @@ var RDB = require('./redis.js'),
},
function(postData, next) {
if (postData.content) {
postTools.toHTML(postData.content, function(err, content) {
postTools.parse(postData.content, function(err, content) {
if (!err) postData.content = utils.strip_tags(content);
next(err, postData);
});
@@ -164,7 +164,7 @@ var RDB = require('./redis.js'),
postData['edited-class'] = postData.editor !== '' ? '' : 'none';
postData['relativeEditTime'] = postData.edited !== '0' ? (new Date(parseInt(postData.edited,10)).toISOString()) : '';
postTools.toHTML(postData.content, function(err, content) {
postTools.parse(postData.content, function(err, content) {
postData.content = content;
posts.push(postData);
callback(null);
@@ -321,7 +321,7 @@ var RDB = require('./redis.js'),
async.parallel({
content: function(next) {
plugins.fireHook('filter:post.get', postData, function(postData) {
postTools.toHTML(postData.content, function(err, content) {
postTools.parse(postData.content, function(err, content) {
next(null, content);
});
});

View File

@@ -53,21 +53,24 @@ var user = require('./../user.js'),
}());
app.get('/admin', Admin.isAdmin, function(req, res) {
app.namespace('/admin', function () {
app.get('/', Admin.isAdmin, function (req, res) {
res.send(Admin.build_header(res) + app.create_route('admin/index') + templates['admin/footer']);
});
app.get('/admin/index', Admin.isAdmin, function(req, res) {
app.get('/index', Admin.isAdmin, function (req, res) {
res.send(Admin.build_header(res) + app.create_route('admin/index') + templates['admin/footer']);
});
});
app.get('/api/admin/index', function(req, res) {
app.namespace('/api/admin', function () {
app.get('/index', function (req, res) {
res.json({
version: pkg.version
});
});
app.get('/api/admin/users/search', function(req, res) {
app.get('/users/search', function (req, res) {
res.json({
search_display: 'block',
loadmore_display: 'none',
@@ -75,7 +78,7 @@ var user = require('./../user.js'),
});
});
app.get('/api/admin/users/latest', function(req, res) {
app.get('/users/latest', function (req, res) {
user.getUsers('users:joindate', 0, 49, function (err, data) {
res.json({
search_display: 'none',
@@ -86,7 +89,7 @@ var user = require('./../user.js'),
});
});
app.get('/api/admin/users/sort-posts', function(req, res) {
app.get('/users/sort-posts', function (req, res) {
user.getUsers('users:postcount', 0, 49, function (err, data) {
res.json({
search_display: 'none',
@@ -97,7 +100,7 @@ var user = require('./../user.js'),
});
});
app.get('/api/admin/users/sort-reputation', function(req, res) {
app.get('/users/sort-reputation', function (req, res) {
user.getUsers('users:reputation', 0, 49, function (err, data) {
res.json({
search_display: 'none',
@@ -108,7 +111,7 @@ var user = require('./../user.js'),
});
});
app.get('/api/admin/users', function(req, res) {
app.get('/users', function (req, res) {
user.getUsers('users:joindate', 0, 49, function (err, data) {
res.json({
search_display: 'none',
@@ -118,13 +121,13 @@ var user = require('./../user.js'),
});
});
app.get('/api/admin/categories', function(req, res) {
app.get('/categories', function (req, res) {
categories.getAllCategories(function (data) {
res.json(data);
});
});
app.get('/api/admin/categories/active', function(req, res) {
app.get('/categories/active', function (req, res) {
categories.getAllCategories(function (data) {
data.categories = data.categories.filter(function (category) {
return (!category.disabled || category.disabled === "0");
@@ -133,7 +136,7 @@ var user = require('./../user.js'),
});
});
app.get('/api/admin/categories/disabled', function(req, res) {
app.get('/categories/disabled', function (req, res) {
categories.getAllCategories(function (data) {
data.categories = data.categories.filter(function (category) {
return category.disabled === "1";
@@ -142,7 +145,7 @@ var user = require('./../user.js'),
});
});
app.get('/api/admin/topics', function(req, res) {
app.get('/topics', function (req, res) {
topics.getAllTopics(10, null, function (topics) {
res.json({
topics: topics
@@ -150,7 +153,7 @@ var user = require('./../user.js'),
});
});
app.get('/api/admin/redis', function(req, res) {
app.get('/redis', function (req, res) {
RDB.info(function (err, data) {
data = data.split("\r\n");
var finalData = {};
@@ -177,7 +180,7 @@ var user = require('./../user.js'),
});
});
app.get('/api/admin/plugins', function(req, res) {
app.get('/plugins', function (req, res) {
plugins.showInstalled(function (err, plugins) {
if (err || !Array.isArray(plugins)) plugins = [];
@@ -187,35 +190,35 @@ var user = require('./../user.js'),
});
});
app.get('/api/admin/settings', function(req, res) {
app.get('/settings', function (req, res) {
res.json(200, {});
});
app.get('/api/admin/motd', function(req, res) {
app.get('/motd', function (req, res) {
res.json(200, {});
});
app.get('/api/admin/themes', function(req, res) {
app.get('/themes', function (req, res) {
res.json(200, {});
});
app.get('/api/admin/twitter', function(req, res) {
app.get('/twitter', function (req, res) {
res.json(200, {});
});
app.get('/api/admin/facebook', function(req, res) {
app.get('/facebook', function (req, res) {
res.json(200, {});
});
app.get('/api/admin/gplus', function(req, res) {
app.get('/gplus', function (req, res) {
res.json(200, {});
});
app.get('/api/admin/testing/categories', function(req, res) {
app.get('/testing/categories', function (req, res) {
res.json(200, {});
});
app.get('/api/admin/groups', function(req, res) {
app.get('/groups', function (req, res) {
Groups.list({
expand: true
}, function (err, groups) {
@@ -224,6 +227,7 @@ var user = require('./../user.js'),
});
});
});
});
};

View File

@@ -11,27 +11,28 @@ var user = require('./../user.js'),
(function (Api) {
Api.create_routes = function (app) {
app.get('/api/get_templates_listing', function(req, res) {
app.namespace('/api', function () {
app.get('/get_templates_listing', function (req, res) {
utils.walk(path.join(__dirname, '../../', 'public/templates'), function (err, data) {
res.json(data);
});
});
app.get('/api/config', function(req, res, next) {
app.get('/config', function (req, res, next) {
var config = require('../../public/config.json');
config['postDelay'] = meta.config['postDelay'];
config['minimumTitleLength'] = meta.config['minimumTitleLength'];
config['minimumPostLength'] = meta.config['minimumPostLength'];
config['imgurClientIDSet'] = !! meta.config['imgurClientID'];
config['minimumUsernameLength'] = meta.config['minimumUsernameLength'];
config['maximumUsernameLength'] = meta.config['maximumUsernameLength'];
config['minimumPasswordLength'] = meta.config['minimumPasswordLength'];
config.postDelay = meta.config.postDelay;
config.minimumTitleLength = meta.config.minimumTitleLength;
config.minimumPostLength = meta.config.minimumPostLength;
config.imgurClientIDSet = !! meta.config.imgurClientID;
config.minimumUsernameLength = meta.config.minimumUsernameLength;
config.maximumUsernameLength = meta.config.maximumUsernameLength;
config.minimumPasswordLength = meta.config.minimumPasswordLength;
res.json(200, config);
});
app.get('/api/home', function(req, res) {
app.get('/home', function (req, res) {
var uid = (req.user) ? req.user.uid : 0;
categories.getAllCategories(function (data) {
data.categories = data.categories.filter(function (category) {
@@ -40,8 +41,8 @@ var user = require('./../user.js'),
function iterator(category, callback) {
categories.getRecentReplies(category.cid, 2, function (posts) {
category["posts"] = posts;
category["post_count"] = posts.length > 2 ? 2 : posts.length;
category.posts = posts;
category.post_count = posts.length > 2 ? 2 : posts.length;
callback(null);
});
}
@@ -55,7 +56,7 @@ var user = require('./../user.js'),
}, uid);
});
app.get('/api/login', function(req, res) {
app.get('/login', function (req, res) {
var data = {},
login_strategies = auth.get_login_strategies(),
num_strategies = login_strategies.length;
@@ -80,7 +81,7 @@ var user = require('./../user.js'),
res.json(data);
});
app.get('/api/register', function(req, res) {
app.get('/register', function (req, res) {
var data = {},
login_strategies = auth.get_login_strategies(),
num_strategies = login_strategies.length;
@@ -107,7 +108,7 @@ var user = require('./../user.js'),
res.json(data);
});
app.get('/api/topic/:id/:slug?', function(req, res, next) {
app.get('/topic/:id/:slug?', function (req, res, next) {
var uid = (req.user) ? req.user.uid : 0;
topics.getTopicWithPosts(req.params.id, uid, 0, 10, function (err, data) {
if (!err) {
@@ -119,7 +120,7 @@ var user = require('./../user.js'),
});
});
app.get('/api/category/:id/:slug?', function(req, res, next) {
app.get('/category/:id/:slug?', function (req, res, next) {
var uid = (req.user) ? req.user.uid : 0;
categories.getCategoryById(req.params.id, uid, function (err, data) {
if (!err)
@@ -129,28 +130,28 @@ var user = require('./../user.js'),
}, req.params.id, uid);
});
app.get('/api/recent', function(req, res) {
app.get('/recent', function (req, res) {
var uid = (req.user) ? req.user.uid : 0;
topics.getLatestTopics(uid, 0, 19, function (data) {
res.json(data);
});
});
app.get('/api/unread', function(req, res) {
app.get('/unread', function (req, res) {
var uid = (req.user) ? req.user.uid : 0;
topics.getUnreadTopics(uid, 0, 19, function (data) {
res.json(data);
});
});
app.get('/api/unread/total', function(req, res) {
app.get('/unread/total', function (req, res) {
var uid = (req.user) ? req.user.uid : 0;
topics.getTotalUnread(uid, function (data) {
res.json(data);
});
});
app.get('/api/confirm/:id', function(req, res) {
app.get('/confirm/:id', function (req, res) {
user.email.confirm(req.params.id, function (data) {
if (data.status === 'ok') {
res.json({
@@ -168,7 +169,7 @@ var user = require('./../user.js'),
});
});
app.get('/api/outgoing', function(req, res) {
app.get('/outgoing', function (req, res) {
var url = req.query.url;
if (url) {
@@ -182,17 +183,18 @@ var user = require('./../user.js'),
}
});
app.get('/api/search', function(req, res) {
app.get('/search', function (req, res) {
return res.json({
show_no_topics: 'hide',
show_no_posts: 'hide',
show_results: 'hide',
search_query: '',
posts: [],
topics: []
});
});
app.get('/api/search/:term', function(req, res, next) {
app.get('/search/:term', function (req, res, next) {
var reds = require('reds');
var postSearch = reds.createSearch('nodebbpostsearch');
@@ -235,6 +237,7 @@ var user = require('./../user.js'),
return res.json({
show_no_topics: results[1].length ? 'hide' : '',
show_no_posts: results[0].length ? 'hide' : '',
show_results: '',
search_query: req.params.term,
posts: results[0],
topics: results[1]
@@ -242,22 +245,23 @@ var user = require('./../user.js'),
});
});
app.get('/api/reset', function(req, res) {
app.get('/reset', function (req, res) {
res.json({});
});
app.get('/api/reset/:code', function(req, res) {
app.get('/reset/:code', function (req, res) {
res.json({
reset_code: req.params.code
});
});
app.get('/api/404', function(req, res) {
app.get('/404', function (req, res) {
res.json({});
});
app.get('/api/403', function(req, res) {
app.get('/403', function (req, res) {
res.json({});
});
});
}
}(exports));

View File

@@ -90,19 +90,14 @@
}
Auth.create_routes = function(app) {
app.get('/logout', function(req, res) {
app.post('/logout', function(req, res) {
if (req.user && req.user.uid > 0) {
winston.info('[Auth] Session ' + req.sessionID + ' logout (uid: ' + req.user.uid + ')');
req.logout();
app.build_header({
req: req,
res: res
}, function(err, header) {
res.send(header + templates['logout'] + templates['footer']);
});
} else res.redirect('/');
}
res.send(200)
});
if (login_strategies.indexOf('twitter') !== -1) {

View File

@@ -5,7 +5,8 @@ var user = require('./../user.js'),
utils = require('./../../public/src/utils.js'),
path = require('path'),
winston = require('winston'),
nconf = require('nconf');
nconf = require('nconf'),
meta = require('./../meta');
(function (User) {
User.create_routes = function (app) {
@@ -24,10 +25,10 @@ var user = require('./../user.js'),
});
}
});
});
app.get('/users', function(req, res) {
app.namespace('/users', function () {
app.get('', function (req, res) {
app.build_header({
req: req,
res: res
@@ -36,7 +37,7 @@ var user = require('./../user.js'),
});
});
app.get('/users/latest', function(req, res) {
app.get('/latest', function (req, res) {
app.build_header({
req: req,
res: res
@@ -45,7 +46,7 @@ var user = require('./../user.js'),
});
});
app.get('/users/sort-posts', function(req, res) {
app.get('/sort-posts', function (req, res) {
app.build_header({
req: req,
res: res
@@ -54,7 +55,7 @@ var user = require('./../user.js'),
});
});
app.get('/users/sort-reputation', function(req, res) {
app.get('/sort-reputation', function (req, res) {
app.build_header({
req: req,
res: res
@@ -63,7 +64,16 @@ var user = require('./../user.js'),
});
});
app.get('/users/search', function(req, res) {
app.get('/online', function (req, res) {
app.build_header({
req: req,
res: res
}, function (err, header) {
res.send(header + app.create_route("users/online", "users") + templates['footer']);
});
});
app.get('/search', function (req, res) {
app.build_header({
req: req,
res: res
@@ -71,8 +81,10 @@ var user = require('./../user.js'),
res.send(header + app.create_route("users/search", "users") + templates['footer']);
});
});
});
app.get('/user/:userslug', function(req, res, next) {
app.namespace('/user', function () {
app.get('/:userslug', function (req, res, next) {
if (!req.params.userslug) {
next();
@@ -94,7 +106,7 @@ var user = require('./../user.js'),
});
});
app.get('/user/:userslug/edit', function(req, res) {
app.get('/:userslug/edit', function (req, res) {
if (!req.user)
return res.redirect('/403');
@@ -113,7 +125,7 @@ var user = require('./../user.js'),
});
});
app.get('/user/:userslug/settings', function(req, res) {
app.get('/:userslug/settings', function (req, res) {
if (!req.user)
return res.redirect('/403');
@@ -132,13 +144,15 @@ var user = require('./../user.js'),
});
});
app.post('/user/uploadpicture', function(req, res) {
app.post('/uploadpicture', function (req, res) {
if (!req.user)
return res.redirect('/403');
if (req.files.userPhoto.size > 262144) {
var uploadSize = meta.config.maximumProfileImageSize || 256;
if (req.files.userPhoto.size > uploadSize * 1024) {
res.send({
error: 'Images must be smaller than 256kb!'
error: 'Images must be smaller than ' + uploadSize + ' kb!'
});
return;
}
@@ -169,6 +183,7 @@ var user = require('./../user.js'),
});
});
});
});
function uploadUserPicture(uid, extension, tempPath, res) {
if (!extension) {
@@ -415,7 +430,7 @@ var user = require('./../user.js'),
if (callerUID !== userData.uid)
user.incrementUserFieldBy(userData.uid, 'profileviews', 1);
postTools.toHTML(userData.signature, function(err, signature) {
postTools.parse(userData.signature, function (err, signature) {
userData.signature = signature;
res.json(userData);
});
@@ -433,6 +448,7 @@ var user = require('./../user.js'),
app.get('/api/users/sort-posts', getUsersSortedByPosts);
app.get('/api/users/sort-reputation', getUsersSortedByReputation);
app.get('/api/users/latest', getUsersSortedByJoinDate);
app.get('/api/users/online', getOnlineUsers);
app.get('/api/users/search', getUsersForSearch);
@@ -466,6 +482,16 @@ var user = require('./../user.js'),
});
}
function getOnlineUsers(req, res) {
user.getUsers('users:online', 0, 49, function (err, data) {
res.json({
search_display: 'none',
loadmore_display: 'block',
users: data
});
});
}
function getUsersForSearch(req, res) {
res.json({
search_display: 'block',

View File

@@ -297,22 +297,20 @@ var RDB = require('./redis.js'),
});
}
ThreadTools.get_latest_undeleted_pid = function(tid, callback) {
ThreadTools.getLatestUndeletedPid = function(tid, callback) {
RDB.lrange('tid:' + tid + ':posts', 0, -1, function(err, pids) {
if (pids.length === 0) return callback(new Error('no-undeleted-pids-found'));
posts.getPostsByTid(tid, 0, -1, function(posts) {
var numPosts = posts.length;
if (!numPosts)
return callback(new Error('no-undeleted-pids-found'));
while (numPosts--) {
if (posts[numPosts].deleted !== '1') {
callback(null, posts[numPosts].pid);
return;
}
}
callback(new Error('no-undeleted-pids-found'));
pids.reverse();
async.detectSeries(pids, function(pid, next) {
RDB.hget('post:' + pid, 'deleted', function(err, deleted) {
if (deleted === '0') next(true);
else next(false);
});
}, function(pid) {
if (pid) callback(null, pid);
else callback(new Error('no-undeleted-pids-found'));
});
});
}
}(exports));

View File

@@ -12,7 +12,8 @@ schema = require('./schema.js'),
feed = require('./feed.js'),
favourites = require('./favourites.js'),
reds = require('reds'),
topicSearch = reds.createSearch('nodebbtopicsearch');
topicSearch = reds.createSearch('nodebbtopicsearch'),
validator = require('validator');
(function(Topics) {
@@ -312,6 +313,7 @@ schema = require('./schema.js'),
topicData.teaser_text = topicInfo.teaserInfo.text || '',
topicData.teaser_username = topicInfo.teaserInfo.username || '';
topicData.teaser_userpicture = topicInfo.teaserInfo.picture || '';
topicData.teaser_pid = topicInfo.teaserInfo.pid;
topicData.teaser_timestamp = topicInfo.teaserInfo.timestamp ? (new Date(parseInt(topicInfo.teaserInfo.timestamp, 10)).toISOString()) : '';
@@ -572,9 +574,9 @@ schema = require('./schema.js'),
}
Topics.getTeaser = function(tid, callback) {
threadTools.get_latest_undeleted_pid(tid, function(err, pid) {
threadTools.getLatestUndeletedPid(tid, function(err, pid) {
if (!err) {
posts.getPostFields(pid, ['content', 'uid', 'timestamp'], function(postData) {
posts.getPostFields(pid, ['pid', 'content', 'uid', 'timestamp'], function(postData) {
user.getUserFields(postData.uid, ['username', 'picture'], function(err, userData) {
if (err)
@@ -583,6 +585,7 @@ schema = require('./schema.js'),
var stripped = postData.content,
timestamp = postData.timestamp,
returnObj = {
"pid": postData.pid,
"username": userData.username,
"picture": userData.picture,
"timestamp": timestamp
@@ -590,7 +593,7 @@ schema = require('./schema.js'),
if (postData.content) {
stripped = postData.content.replace(/>.+\n\n/, '');
postTools.toHTML(stripped, function(err, stripped) {
postTools.parse(stripped, function(err, stripped) {
returnObj.text = utils.strip_tags(stripped);
callback(null, returnObj);
});
@@ -655,7 +658,7 @@ schema = require('./schema.js'),
var slug = tid + '/' + utils.slugify(title);
var timestamp = Date.now();
title = validator.sanitize(title).escape();
RDB.hmset('topic:' + tid, {
'tid': tid,
'uid': uid,

View File

@@ -25,7 +25,17 @@ var express = require('express'),
nconf = require('nconf');
(function (app) {
var templates = null;
var templates = null,
clientScripts;
// Minify client-side libraries
meta.js.get(function (err, scripts) {
clientScripts = scripts.map(function (script) {
return script = {
script: script
}
});
});
/**
* `options` object requires: req, res
@@ -44,33 +54,35 @@ var express = require('express'),
}, {
property: 'og:site_name',
content: meta.config.title || 'NodeBB'
}, ],
}],
metaString = utils.buildMetaTags(defaultMetaTags.concat(options.metaTags || [])),
templateValues = {
cssSrc: meta.config['theme:src'] || nconf.get('relative_path') + '/vendor/bootstrap/css/bootstrap.min.css',
title: meta.config['title'] || 'NodeBB',
browserTitle: meta.config['title'] || 'NodeBB',
title: meta.config.title || 'NodeBB',
browserTitle: meta.config.title || 'NodeBB',
csrf: options.res.locals.csrf_token,
relative_path: nconf.get('relative_path'),
meta_tags: metaString
meta_tags: metaString,
clientScripts: clientScripts
};
translator.translate(templates['header'].parse(templateValues), function(template) {
translator.translate(templates.header.parse(templateValues), function(template) {
callback(null, template);
});
};
// Middlewares
app.use(express.compress());
app.use(express.favicon(path.join(__dirname, '../', 'public', 'favicon.ico')));
app.use(require('less-middleware')({
src: path.join(__dirname, '../', 'public'),
prefix: nconf.get('relative_path')
prefix: nconf.get('relative_path'),
yuicompress: true
}));
app.use(nconf.get('relative_path'), express.static(path.join(__dirname, '../', 'public')));
app.use(express.bodyParser()); // Puts POST vars in request.body
app.use(express.cookieParser()); // If you want to parse cookies (res.cookies)
app.use(express.compress());
app.use(express.session({
store: new RedisStore({
client: RDB,
@@ -238,6 +250,11 @@ var express = require('express'),
},
"categories": function (next) {
categories.getAllCategories(function (returnData) {
returnData.categories = returnData.categories.filter(function (category) {
if (category.disabled !== '1') return true;
else return false;
});
next(null, returnData);
}, 0);
}
@@ -433,7 +450,6 @@ var express = require('express'),
app.get('/robots.txt', function (req, res) {
res.set('Content-Type', 'text/plain');
res.send("User-agent: *\n" +
"Disallow: \n" +
"Disallow: /admin/\n" +
"Sitemap: " + nconf.get('url') + "sitemap.xml");
});
@@ -481,6 +497,8 @@ var express = require('express'),
});
app.get('/search', function (req, res) {
if (!req.user)
return res.redirect('/403');
app.build_header({
req: req,
res: res
@@ -490,6 +508,8 @@ var express = require('express'),
});
app.get('/search/:term', function (req, res) {
if (!req.user)
return res.redirect('/403');
app.build_header({
req: req,
res: res
@@ -514,7 +534,6 @@ var express = require('express'),
});
});
});
}(WebServer));

View File

@@ -23,6 +23,7 @@ var SocketIO = require('socket.io').listen(global.server, {
client: RDB,
ttl: 60 * 60 * 24 * 14
}),
nconf = require('nconf'),
socketCookieParser = express.cookieParser(nconf.get('secret')),
admin = {
'categories': require('./admin/categories.js'),
@@ -53,6 +54,8 @@ var SocketIO = require('socket.io').listen(global.server, {
userSockets[uid].push(socket);
if (uid) {
RDB.zadd('users:online', Date.now(), uid, function(err, data) {
socket.join('uid_' + uid);
io.sockets. in ('global').emit('api:user.isOnline', isUserOnline(uid));
@@ -63,6 +66,7 @@ var SocketIO = require('socket.io').listen(global.server, {
uid: uid
});
});
});
}
});
});
@@ -80,7 +84,9 @@ var SocketIO = require('socket.io').listen(global.server, {
delete users[sessionID];
delete userSockets[uid];
if (uid) {
RDB.zrem('users:online', uid, function(err, data) {
io.sockets. in ('global').emit('api:user.isOnline', isUserOnline(uid));
});
}
}
@@ -100,7 +106,7 @@ var SocketIO = require('socket.io').listen(global.server, {
socket.on('api:get_all_rooms', function(data) {
socket.emit('api:get_all_rooms', io.sockets.manager.rooms);
})
});
function updateRoomBrowsingText(roomName) {