Merge branch 'master' of github.com:designcreateplay/NodeBB

v1.18.x
Julian Lam 11 years ago
commit e3fb996a80

@ -109,11 +109,11 @@
var customTemplates = meta.config['theme:templates'] ? path.join(__dirname, 'node_modules', meta.config['theme:id'], meta.config['theme:templates']) : false; var customTemplates = meta.config['theme:templates'] ? path.join(__dirname, 'node_modules', meta.config['theme:id'], meta.config['theme:templates']) : false;
utils.walk(path.join(__dirname, 'public/templates'), function (err, tplsToLoad) { utils.walk(path.join(__dirname, 'public/templates'), function (err, tplsToLoad) {
templates.init(tplsToLoad, customTemplates); templates.init(tplsToLoad, customTemplates);
}); });
plugins.ready(function() { plugins.ready(function() {
templates.ready(webserver.init); templates.ready(webserver.init);
}); });

@ -7,6 +7,7 @@
"location": "Location", "location": "Location",
"age": "Age", "age": "Age",
"joined": "Joined", "joined": "Joined",
"lastonline": "Last Online",
"profile_views": "Profile views", "profile_views": "Profile views",
"reputation": "Reputation", "reputation": "Reputation",
"posts": "Posts", "posts": "Posts",

@ -48,7 +48,6 @@ define(['taskbar'], function(taskbar) {
socket.emit('api:composer.push', { socket.emit('api:composer.push', {
pid: pid pid: pid
}, function(threadData) { }, function(threadData) {
console.log(threadData);
push({ push({
pid: pid, pid: pid,
title: threadData.title, title: threadData.title,
@ -202,7 +201,7 @@ define(['taskbar'], function(taskbar) {
} }
}); });
postContainer.on('click', '.formatting-bar span .fa-picture-o', function() { postContainer.on('click', '.formatting-bar span .fa-picture-o, .formatting-bar span .fa-upload', function() {
$('#files').click(); $('#files').click();
}); });
@ -213,6 +212,7 @@ define(['taskbar'], function(taskbar) {
loadFile(post_uuid, files[i]); loadFile(post_uuid, files[i]);
} }
} }
$('#fileForm')[0].reset();
}); });
@ -317,7 +317,12 @@ define(['taskbar'], function(taskbar) {
} }
if(config.imgurClientIDSet) { if(config.imgurClientIDSet) {
postContainer.find('.upload-instructions').removeClass('hide') postContainer.find('.upload-instructions').removeClass('hide');
postContainer.find('.img-upload-btn').removeClass('hide');
}
if(config.allowFileUploads) {
postContainer.find('.file-upload-btn').removeClass('hide');
} }
postContainer.css('visibility', 'visible'); postContainer.css('visibility', 'visible');
@ -469,36 +474,41 @@ define(['taskbar'], function(taskbar) {
} }
function loadFile(post_uuid, file) { function loadFile(post_uuid, file) {
if (!file.type.match('image.*')) {
return;
}
var reader = new FileReader(), var reader = new FileReader(),
dropDiv = $('#cmp-uuid-' + post_uuid).find('.imagedrop'); dropDiv = $('#cmp-uuid-' + post_uuid).find('.imagedrop');
$(reader).on('loadend', function(e) { $(reader).on('loadend', function(e) {
var bin = this.result.split(',')[1]; var regex = /^data:.*;base64,(.*)$/;
console.log(file);
var matches = this.result.match(regex);
var img = { var fileData = {
name: file.name, name: file.name,
data: bin data: matches[1]
}; };
createImagePlaceholder(post_uuid, img);
dropDiv.hide(); dropDiv.hide();
if(file.type.match('image.*')) {
uploadFile('api:posts.uploadImage', post_uuid, fileData);
} else {
if(file.size > parseInt(config.maximumFileSize, 10) * 1024) {
return composerAlert('File too big', 'Maximum allowed file size is ' + config.maximumFileSize + 'kbs');
}
uploadFile('api:posts.uploadFile', post_uuid, fileData);
}
}); });
reader.readAsDataURL(file); reader.readAsDataURL(file);
} }
function createImagePlaceholder(post_uuid, img) { function uploadFile(method, post_uuid, img) {
var postContainer = $('#cmp-uuid-' + post_uuid), var linkStart = method === 'api:posts.uploadImage' ? '!' : '',
postContainer = $('#cmp-uuid-' + post_uuid),
textarea = postContainer.find('textarea'), textarea = postContainer.find('textarea'),
text = textarea.val(), text = textarea.val(),
imgText = "![" + img.name + "](uploading...)"; imgText = linkStart + '[' + img.name + '](uploading...)';
text += imgText; text += imgText;
textarea.val(text + " "); textarea.val(text + " ");
@ -509,18 +519,17 @@ define(['taskbar'], function(taskbar) {
composer.posts[post_uuid].uploadsInProgress.push(1); composer.posts[post_uuid].uploadsInProgress.push(1);
socket.emit("api:posts.uploadImage", img, function(err, data) { socket.emit(method, img, function(err, data) {
var currentText = textarea.val();
if(err) { if(err) {
textarea.val(currentText.replace(imgText, linkStart + '[' + img.name + '](upload error)'));
return app.alertError(err.message); return app.alertError(err.message);
} }
var currentText = textarea.val();
imgText = "![" + data.name + "](uploading...)";
if(!err) { textarea.val(currentText.replace(imgText, linkStart + '[' + data.name + '](' + data.url + ')'));
textarea.val(currentText.replace(imgText, "![" + data.name + "](" + data.url + ")"));
} else {
textarea.val(currentText.replace(imgText, "![" + data.name + "](upload error)"));
}
composer.posts[post_uuid].uploadsInProgress.pop(); composer.posts[post_uuid].uploadsInProgress.pop();
}); });
} }

@ -70,6 +70,10 @@
<span class="timeago" title="{joindate}"></span> <span class="timeago" title="{joindate}"></span>
<br/> <br/>
<span class="account-bio-label">[[user:lastonline]]</span>
<span class="timeago" title="{lastonline}"></span>
<br/>
<span class="account-bio-label">[[user:profile_views]]</span> <span class="account-bio-label">[[user:profile_views]]</span>
<span class="formatted-number">{profileviews}</span> <span class="formatted-number">{profileviews}</span>
<br/> <br/>

@ -121,6 +121,17 @@
<input type="checkbox" data-field="useOutgoingLinksPage"> <strong>Use Outgoing Links Warning Page</strong> <input type="checkbox" data-field="useOutgoingLinksPage"> <strong>Use Outgoing Links Warning Page</strong>
</label> </label>
</div> </div>
<div class="checkbox">
<label>
<input type="checkbox" data-field="disableSocialButtons"> <strong>Disable social buttons on posts</strong>
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" data-field="allowFileUploads"> <strong>Allow users to upload regular files</strong>
</label>
</div>
<strong>Maximum File Size</strong><br /> <input type="text" class="form-control" value="2048" data-field="maximumFileSize"><br />
</div> </div>
</form> </form>

@ -7,10 +7,15 @@
<span class="btn btn-link" tabindex="-1"><i class="fa fa-italic"></i></span> <span class="btn btn-link" tabindex="-1"><i class="fa fa-italic"></i></span>
<span class="btn btn-link" tabindex="-1"><i class="fa fa-list"></i></span> <span class="btn btn-link" tabindex="-1"><i class="fa fa-list"></i></span>
<span class="btn btn-link" tabindex="-1"><i class="fa fa-link"></i></span> <span class="btn btn-link" tabindex="-1"><i class="fa fa-link"></i></span>
<span class="btn btn-link" tabindex="-1"> <span class="btn btn-link img-upload-btn hide" tabindex="-1">
<input type="file" id="files" name="files[]" multiple class="hide"/>
<i class="fa fa-picture-o"></i> <i class="fa fa-picture-o"></i>
</span> </span>
<span class="btn btn-link file-upload-btn hide" tabindex="-1">
<i class="fa fa-upload"></i>
</span>
<form id="fileForm">
<input type="file" id="files" name="files[]" multiple class="hide"/>
</form>
</div> </div>
<!-- <div class="btn btn-link pull-right">Preview</div> --> <!-- <div class="btn btn-link pull-right">Preview</div> -->
</div> </div>

@ -86,9 +86,11 @@
<div class="pull-right"> <div class="pull-right">
<div class="btn-group post-tools"> <div class="btn-group post-tools">
<button class="btn btn-sm btn-default link" type="button" title="[[topic:link]]"><i class="fa fa-link"></i></button> <button class="btn btn-sm btn-default link" type="button" title="[[topic:link]]"><i class="fa fa-link"></i></button>
<!-- IF !disableSocialButtons -->
<button class="btn btn-sm btn-default facebook-share" type="button" title=""><i class="fa fa-facebook"></i></button> <button class="btn btn-sm btn-default facebook-share" type="button" title=""><i class="fa fa-facebook"></i></button>
<button class="btn btn-sm btn-default twitter-share" type="button" title=""><i class="fa fa-twitter"></i></button> <button class="btn btn-sm btn-default twitter-share" type="button" title=""><i class="fa fa-twitter"></i></button>
<button class="btn btn-sm btn-default google-share" type="button" title=""><i class="fa fa-google-plus"></i></button> <button class="btn btn-sm btn-default google-share" type="button" title=""><i class="fa fa-google-plus"></i></button>
<!-- ENDIF !disableSocialButtons -->
</div> </div>
<!-- IF posts.display_moderator_tools --> <!-- IF posts.display_moderator_tools -->

@ -50,13 +50,20 @@
function createCollections() { function createCollections() {
db.createCollection('objects', function(err, collection) { db.createCollection('objects', function(err, collection) {
if(err) { if(err) {
winston.error("Error creating collection " + err.message); winston.error('Error creating collection ' + err.message);
return; return;
} }
if(collection) { if(collection) {
collection.ensureIndex({_key :1}, {background:true}, function(err, name){ collection.ensureIndex({_key :1}, {background:true}, function(err, name) {
if(err) {
winston.error('Error creating index ' + err.message);
}
});
collection.ensureIndex({'expireAt':1}, {expireAfterSeconds:0, background:true}, function(err, name) {
if(err) { if(err) {
winston.error("Error creating index " + err.message); winston.error('Error creating index ' + err.message);
} }
}); });
} }
@ -64,13 +71,13 @@
db.createCollection('search', function(err, collection) { db.createCollection('search', function(err, collection) {
if(err) { if(err) {
winston.error("Error creating collection " + err.message); winston.error('Error creating collection ' + err.message);
return; return;
} }
if(collection) { if(collection) {
collection.ensureIndex({content:'text'}, {background:true}, function(err, name){ collection.ensureIndex({content:'text'}, {background:true}, function(err, name){
if(err) { if(err) {
winston.error("Error creating index " + err.message); winston.error('Error creating index ' + err.message);
} }
}); });
} }
@ -241,6 +248,14 @@
}); });
} }
module.expire = function(key, seconds, callback) {
module.expireAt(key, Math.round(Date.now() / 1000) + seconds, callback);
}
module.expireAt = function(key, timestamp, callback) {
module.setObjectField(key, 'expireAt', new Date(timestamp * 1000), callback);
}
//hashes //hashes
module.setObject = function(key, data, callback) { module.setObject = function(key, data, callback) {
data['_key'] = key; data['_key'] = key;

@ -211,6 +211,14 @@
redisClient.keys(key, callback); redisClient.keys(key, callback);
} }
module.expire = function(key, seconds, callback) {
redisClient.expire(key, seconds, callback);
}
module.expireAt = function(key, timestamp, callback) {
redisClient.expireat(key, timestamp, callback);
}
//hashes //hashes
module.setObject = function(key, data, callback) { module.setObject = function(key, data, callback) {

@ -20,6 +20,7 @@ var request = require('request'),
try { try {
var response = JSON.parse(body); var response = JSON.parse(body);
if(response.success) { if(response.success) {
callback(null, response.data); callback(null, response.data);
} else { } else {

@ -212,6 +212,12 @@ var async = require('async'),
}, { }, {
field: 'allowRegistration', field: 'allowRegistration',
value: 1 value: 1
}, {
field: 'allowFileUploads',
value: 0,
}, {
filed: 'maximumFileSize',
value: 2048
}, { }, {
field: 'minimumTitleLength', field: 'minimumTitleLength',
value: 3 value: 3

@ -12,6 +12,8 @@ var db = require('./database'),
meta = require('./meta'), meta = require('./meta'),
async = require('async'), async = require('async'),
path = require('path'),
fs = require('fs'),
nconf = require('nconf'), nconf = require('nconf'),
validator = require('validator'), validator = require('validator'),
winston = require('winston'), winston = require('winston'),
@ -358,6 +360,10 @@ var db = require('./database'),
Posts.uploadPostImage = function(image, callback) { Posts.uploadPostImage = function(image, callback) {
if(!meta.config.imgurClientID) {
return callback('imgurClientID not set', null);
}
if(!image) { if(!image) {
return callback('invalid image', null); return callback('invalid image', null);
} }
@ -374,6 +380,37 @@ var db = require('./database'),
}); });
} }
Posts.uploadPostFile = function(file, callback) {
if(!meta.config.allowFileUploads) {
return callback('File uploads are not allowed');
}
if(!file) {
return callback('invalid file');
}
var buffer = new Buffer(file.data, 'base64');
if(buffer.length > parseInt(meta.config.maximumFileSize, 10) * 1024) {
return callback('File too big');
}
var filename = 'upload-' + utils.generateUUID() + path.extname(file.name);
var uploadPath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), filename);
fs.writeFile(uploadPath, buffer, function (err) {
if(err) {
callback(err.message, null);
} else {
callback(null, {
url: nconf.get('upload_url') + filename,
name: file.name
});
}
});
}
Posts.getPostsByUid = function(uid, start, end, callback) { Posts.getPostsByUid = function(uid, start, end, callback) {
user.getPostIds(uid, start, end, function(err, pids) { user.getPostIds(uid, start, end, function(err, pids) {
if(err) { if(err) {

@ -40,6 +40,8 @@ var path = require('path'),
config.useOutgoingLinksPage = meta.config.useOutgoingLinksPage; config.useOutgoingLinksPage = meta.config.useOutgoingLinksPage;
config.allowGuestPosting = meta.config.allowGuestPosting; config.allowGuestPosting = meta.config.allowGuestPosting;
config.allowRegistration = meta.config.allowRegistration || '1'; config.allowRegistration = meta.config.allowRegistration || '1';
config.allowFileUploads = meta.config.allowFileUploads;
config.maximumFileSize = meta.config.maximumFileSize;
config.emailSetup = !!meta.config['email:from']; config.emailSetup = !!meta.config['email:from'];
res.json(200, config); res.json(200, config);

@ -530,6 +530,11 @@ var fs = require('fs'),
user.getUserData(uid, function (err, data) { user.getUserData(uid, function (err, data) {
if (data) { if (data) {
data.joindate = new Date(parseInt(data.joindate, 10)).toISOString(); data.joindate = new Date(parseInt(data.joindate, 10)).toISOString();
if(data.lastonline) {
data.lastonline = new Date(parseInt(data.lastonline, 10)).toISOString();
} else {
data.lastonline = data.joindate;
}
if (!data.birthday) { if (!data.birthday) {
data.age = ''; data.age = '';

@ -667,6 +667,7 @@ var async = require('async'),
'unreplied': parseInt(topicData.postcount, 10) > 1, 'unreplied': parseInt(topicData.postcount, 10) > 1,
'topic_id': tid, 'topic_id': tid,
'expose_tools': privileges.editable ? 1 : 0, 'expose_tools': privileges.editable ? 1 : 0,
'disableSocialButtons': meta.config.disableSocialButtons !== undefined ? parseInt(meta.config.disableSocialButtons, 10) !== 0 : false,
'posts': topicPosts 'posts': topicPosts
}); });
}); });

@ -14,7 +14,7 @@ var db = require('./database'),
Upgrade.check = function(callback) { Upgrade.check = function(callback) {
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema
var latestSchema = new Date(2013, 11, 31).getTime(); var latestSchema = new Date(2014, 0, 1).getTime();
db.get('schemaDate', function(err, value) { db.get('schemaDate', function(err, value) {
if (parseInt(value, 10) >= latestSchema) { if (parseInt(value, 10) >= latestSchema) {

@ -188,6 +188,13 @@ var path = require('path'),
// Authentication Routes // Authentication Routes
auth.initialize(app); auth.initialize(app);
app.use(function(req, res, next) {
if(req.user) {
user.setUserField(req.user.uid, 'lastonline', Date.now());
}
next();
})
next(); next();
}, },
function(next) { function(next) {

@ -638,6 +638,10 @@ websockets.init = function(io) {
posts.uploadPostImage(data, callback); posts.uploadPostImage(data, callback);
}); });
socket.on('api:posts.uploadFile', function(data, callback) {
posts.uploadPostFile(data, callback);
});
socket.on('api:posts.getRawPost', function(data, callback) { socket.on('api:posts.getRawPost', function(data, callback) {
posts.getPostField(data.pid, 'content', function(err, raw) { posts.getPostField(data.pid, 'content', function(err, raw) {
callback({ callback({

Loading…
Cancel
Save