mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-12-22 16:30:34 +01:00
full text search using reds, issue #142
This commit is contained in:
@@ -32,7 +32,8 @@
|
|||||||
"nconf": "~0.6.7",
|
"nconf": "~0.6.7",
|
||||||
"sitemap": "~0.6.0",
|
"sitemap": "~0.6.0",
|
||||||
"cheerio": "~0.12.0",
|
"cheerio": "~0.12.0",
|
||||||
"request": "~2.25.0"
|
"request": "~2.25.0",
|
||||||
|
"reds": "0.2.3"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/designcreateplay/NodeBB/issues"
|
"url": "https://github.com/designcreateplay/NodeBB/issues"
|
||||||
|
|||||||
@@ -823,3 +823,27 @@ body .navbar .nodebb-inline-block {
|
|||||||
-webkit-animation: scroll-0 6s ease 0.5s infinite normal;
|
-webkit-animation: scroll-0 6s ease 0.5s infinite normal;
|
||||||
animation: scroll-0 6s ease 0.5s infinite normal;/* Safari and Chrome: */
|
animation: scroll-0 6s ease 0.5s infinite normal;/* Safari and Chrome: */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-search {
|
||||||
|
float: left;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom:0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-post {
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
line-height: 16px;
|
||||||
|
padding: 5px;
|
||||||
|
overflow:hidden;
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
width:48px;
|
||||||
|
height:48px;
|
||||||
|
padding-right:10px;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
padding-left:10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -362,6 +362,13 @@ var socket,
|
|||||||
|
|
||||||
jQuery('document').ready(function() {
|
jQuery('document').ready(function() {
|
||||||
addTouchEvents();
|
addTouchEvents();
|
||||||
|
|
||||||
|
$('#search-form').on('submit', function() {
|
||||||
|
var input = $(this).find('input');
|
||||||
|
ajaxify.go("search/"+input.val(), null, "search");
|
||||||
|
input.val('');
|
||||||
|
return false;
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
loadConfig();
|
loadConfig();
|
||||||
|
|||||||
@@ -30,7 +30,8 @@
|
|||||||
"recent": "recent",
|
"recent": "recent",
|
||||||
"unread": "unread",
|
"unread": "unread",
|
||||||
"popular": "category",
|
"popular": "category",
|
||||||
"active": "category"
|
"active": "category",
|
||||||
|
"search": "search"
|
||||||
},
|
},
|
||||||
"force_refresh": {
|
"force_refresh": {
|
||||||
"logout": true
|
"logout": true
|
||||||
|
|||||||
@@ -57,6 +57,11 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul id="right-menu" class="nav pull-right nodebb-inline-block">
|
<ul id="right-menu" class="nav pull-right nodebb-inline-block">
|
||||||
|
<form id="search-form"
|
||||||
|
class="form-search form-inline" action="" method="GET">
|
||||||
|
<input type="text" name="query" class="input-medium search-query">
|
||||||
|
<button type="submit" class="btn hide">Search</button>
|
||||||
|
</form>
|
||||||
<li class="notifications dropdown text-center">
|
<li class="notifications dropdown text-center">
|
||||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#" id="notif_dropdown"><i class="icon-circle-blank"></i></a>
|
<a class="dropdown-toggle" data-toggle="dropdown" href="#" id="notif_dropdown"><i class="icon-circle-blank"></i></a>
|
||||||
<ul id="notif-list" class="dropdown-menu" aria-labelledby="notif_dropdown">
|
<ul id="notif-list" class="dropdown-menu" aria-labelledby="notif_dropdown">
|
||||||
|
|||||||
36
public/templates/search.tpl
Normal file
36
public/templates/search.tpl
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<div class="container">
|
||||||
|
<ul class="breadcrumb">
|
||||||
|
<li><a href="/">Home</a><span class="divider">/</span></li>
|
||||||
|
<li class="active">Search</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="alert alert-warning {show_no_results}" id="no-search-results">
|
||||||
|
<strong>No search results for {search_query}.</strong>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="category row">
|
||||||
|
<div class="span12">
|
||||||
|
<ul id="topics-container">
|
||||||
|
<!-- BEGIN posts -->
|
||||||
|
<a href="../../topic/{posts.topicSlug}#{posts.pid}" id="tid-{posts.tid}">
|
||||||
|
<li class="category-item">
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="span12 img-polaroid">
|
||||||
|
<div class="search-result-post">
|
||||||
|
<img src="{posts.picture}" />
|
||||||
|
<strong>{posts.username}</strong>: {posts.content}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</a>
|
||||||
|
<!-- END posts -->
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--
|
||||||
|
<script type="text/javascript" src="{relative_path}/src/forum/search.js"></script>
|
||||||
|
-->
|
||||||
@@ -6,7 +6,9 @@ var RDB = require('./redis.js'),
|
|||||||
async = require('async'),
|
async = require('async'),
|
||||||
|
|
||||||
utils = require('../public/src/utils'),
|
utils = require('../public/src/utils'),
|
||||||
plugins = require('./plugins');
|
plugins = require('./plugins'),
|
||||||
|
reds = require('reds'),
|
||||||
|
search = reds.createSearch('nodebbsearch');
|
||||||
|
|
||||||
(function(PostTools) {
|
(function(PostTools) {
|
||||||
PostTools.isMain = function(pid, tid, callback) {
|
PostTools.isMain = function(pid, tid, callback) {
|
||||||
@@ -56,6 +58,10 @@ var RDB = require('./redis.js'),
|
|||||||
posts.setPostField(pid, 'edited', Date.now());
|
posts.setPostField(pid, 'edited', Date.now());
|
||||||
posts.setPostField(pid, 'editor', uid);
|
posts.setPostField(pid, 'editor', uid);
|
||||||
|
|
||||||
|
search.remove(pid, function() {
|
||||||
|
search.index(content, pid);
|
||||||
|
});
|
||||||
|
|
||||||
posts.getPostField(pid, 'tid', function(tid) {
|
posts.getPostField(pid, 'tid', function(tid) {
|
||||||
PostTools.isMain(pid, tid, function(isMainPost) {
|
PostTools.isMain(pid, tid, function(isMainPost) {
|
||||||
if (isMainPost)
|
if (isMainPost)
|
||||||
@@ -84,6 +90,7 @@ var RDB = require('./redis.js'),
|
|||||||
var success = function() {
|
var success = function() {
|
||||||
posts.setPostField(pid, 'deleted', 1);
|
posts.setPostField(pid, 'deleted', 1);
|
||||||
|
|
||||||
|
search.remove(pid);
|
||||||
|
|
||||||
posts.getPostFields(pid, ['tid', 'uid'], function(postData) {
|
posts.getPostFields(pid, ['tid', 'uid'], function(postData) {
|
||||||
|
|
||||||
@@ -119,7 +126,7 @@ var RDB = require('./redis.js'),
|
|||||||
var success = function() {
|
var success = function() {
|
||||||
posts.setPostField(pid, 'deleted', 0);
|
posts.setPostField(pid, 'deleted', 0);
|
||||||
|
|
||||||
posts.getPostFields(pid, ['tid', 'uid'], function(postData) {
|
posts.getPostFields(pid, ['tid', 'uid', 'content'], function(postData) {
|
||||||
|
|
||||||
user.incrementUserFieldBy(postData.uid, 'postcount', 1);
|
user.incrementUserFieldBy(postData.uid, 'postcount', 1);
|
||||||
|
|
||||||
@@ -132,6 +139,8 @@ var RDB = require('./redis.js'),
|
|||||||
topics.updateTimestamp(postData.tid, timestamp);
|
topics.updateTimestamp(postData.tid, timestamp);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
search.index(postData.content, pid);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
87
src/posts.js
87
src/posts.js
@@ -8,7 +8,9 @@ var RDB = require('./redis.js'),
|
|||||||
postTools = require('./postTools'),
|
postTools = require('./postTools'),
|
||||||
feed = require('./feed.js'),
|
feed = require('./feed.js'),
|
||||||
async = require('async'),
|
async = require('async'),
|
||||||
plugins = require('./plugins');
|
plugins = require('./plugins'),
|
||||||
|
reds = require('reds'),
|
||||||
|
search = reds.createSearch('nodebbsearch');
|
||||||
|
|
||||||
(function(Posts) {
|
(function(Posts) {
|
||||||
|
|
||||||
@@ -323,46 +325,19 @@ var RDB = require('./redis.js'),
|
|||||||
|
|
||||||
user.onNewPostMade(uid, tid, pid, timestamp);
|
user.onNewPostMade(uid, tid, pid, timestamp);
|
||||||
|
|
||||||
var imgur = require('./imgur');
|
uploadPostImages(postData, images, function(err, uploadedImages) {
|
||||||
imgur.setClientID(global.nconf.get('imgurClientID'));
|
if(err) {
|
||||||
|
console.log('Uploading images failed!');
|
||||||
var uploadedImages = [];
|
} else {
|
||||||
|
postData.uploadedImages = JSON.stringify(uploadedImages);
|
||||||
function uploadImage(image, callback) {
|
Posts.setPostField(pid, 'uploadedImages', postData.uploadedImages);
|
||||||
imgur.upload(image.data, 'base64', function(err, data) {
|
}
|
||||||
if(err) {
|
callback(postData);
|
||||||
callback(err);
|
});
|
||||||
} else {
|
|
||||||
if(data.success) {
|
|
||||||
var img= {url:data.data.link, name:image.name};
|
|
||||||
uploadedImages.push(img);
|
|
||||||
callback(null);
|
|
||||||
} else {
|
|
||||||
callback(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
plugins.fireHook('action:save_post_content', [pid, content]);
|
plugins.fireHook('action:save_post_content', [pid, content]);
|
||||||
|
|
||||||
if(!images) {
|
search.index(content, pid);
|
||||||
postData.uploadedImages = JSON.stringify(uploadedImages);
|
|
||||||
Posts.setPostField(pid, 'uploadedImages', postData.uploadedImages);
|
|
||||||
callback(postData);
|
|
||||||
} else {
|
|
||||||
async.each(images, uploadImage, function(err) {
|
|
||||||
if(!err) {
|
|
||||||
postData.uploadedImages = JSON.stringify(uploadedImages);
|
|
||||||
Posts.setPostField(pid, 'uploadedImages', postData.uploadedImages);
|
|
||||||
|
|
||||||
callback(postData);
|
|
||||||
} else {
|
|
||||||
console.log(err);
|
|
||||||
callback(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -371,6 +346,42 @@ var RDB = require('./redis.js'),
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function uploadPostImages(postData, images, callback) {
|
||||||
|
var imgur = require('./imgur');
|
||||||
|
imgur.setClientID(global.nconf.get('imgurClientID'));
|
||||||
|
|
||||||
|
var uploadedImages = [];
|
||||||
|
|
||||||
|
function uploadImage(image, callback) {
|
||||||
|
imgur.upload(image.data, 'base64', function(err, data) {
|
||||||
|
if(err) {
|
||||||
|
callback(err);
|
||||||
|
} else {
|
||||||
|
if(data.success) {
|
||||||
|
var img= {url:data.data.link, name:image.name};
|
||||||
|
uploadedImages.push(img);
|
||||||
|
callback(null);
|
||||||
|
} else {
|
||||||
|
callback(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!images) {
|
||||||
|
callback(null, uploadedImages);
|
||||||
|
} else {
|
||||||
|
async.each(images, uploadImage, function(err) {
|
||||||
|
if(!err) {
|
||||||
|
callback(null, uploadedImages);
|
||||||
|
} else {
|
||||||
|
console.log(err);
|
||||||
|
callback(err, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Posts.getPostsByUid = function(uid, start, end, callback) {
|
Posts.getPostsByUid = function(uid, start, end, callback) {
|
||||||
|
|
||||||
user.getPostIds(uid, start, end, function(pids) {
|
user.getPostIds(uid, start, end, function(pids) {
|
||||||
|
|||||||
@@ -146,5 +146,36 @@ var user = require('./../user.js'),
|
|||||||
res.redirect(global.nconf.get('relative_path') + '/404');
|
res.redirect(global.nconf.get('relative_path') + '/404');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get('/api/search', function(req, res) {
|
||||||
|
return res.json({
|
||||||
|
show_no_results:'hide',
|
||||||
|
search_query:'',
|
||||||
|
posts:[]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/api/search/:term', function(req, res, next) {
|
||||||
|
|
||||||
|
var reds = require('reds');
|
||||||
|
var search = reds.createSearch('nodebbsearch');
|
||||||
|
|
||||||
|
search
|
||||||
|
.query(query = req.params.term).type('or')
|
||||||
|
.end(function(err, ids) {
|
||||||
|
if (err)
|
||||||
|
return next();
|
||||||
|
|
||||||
|
|
||||||
|
posts.getPostSummaryByPids(ids, function(posts) {
|
||||||
|
res.json(200, {
|
||||||
|
show_no_results:ids.length?'hide':'show',
|
||||||
|
search_query:req.params.term,
|
||||||
|
posts:posts
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}(exports));
|
}(exports));
|
||||||
|
|||||||
@@ -382,6 +382,18 @@ var express = require('express'),
|
|||||||
res.redirect(global.nconf.get('relative_path') + '/404');
|
res.redirect(global.nconf.get('relative_path') + '/404');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get('/search', function(req, res) {
|
||||||
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
|
res.send(header + app.create_route("search", null, "search") + templates['footer']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/search/:term', function(req, res) {
|
||||||
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
|
res.send(header + app.create_route("search/"+req.params.term, null, "search") + templates['footer']);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
}(WebServer));
|
}(WebServer));
|
||||||
|
|||||||
Reference in New Issue
Block a user