mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-31 19:15:58 +01:00
full text search using reds, issue #142
This commit is contained in:
@@ -32,7 +32,8 @@
|
||||
"nconf": "~0.6.7",
|
||||
"sitemap": "~0.6.0",
|
||||
"cheerio": "~0.12.0",
|
||||
"request": "~2.25.0"
|
||||
"request": "~2.25.0",
|
||||
"reds": "0.2.3"
|
||||
},
|
||||
"bugs": {
|
||||
"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;
|
||||
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() {
|
||||
addTouchEvents();
|
||||
|
||||
$('#search-form').on('submit', function() {
|
||||
var input = $(this).find('input');
|
||||
ajaxify.go("search/"+input.val(), null, "search");
|
||||
input.val('');
|
||||
return false;
|
||||
})
|
||||
});
|
||||
|
||||
loadConfig();
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
"recent": "recent",
|
||||
"unread": "unread",
|
||||
"popular": "category",
|
||||
"active": "category"
|
||||
"active": "category",
|
||||
"search": "search"
|
||||
},
|
||||
"force_refresh": {
|
||||
"logout": true
|
||||
|
||||
@@ -57,6 +57,11 @@
|
||||
</li>
|
||||
</ul>
|
||||
<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">
|
||||
<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">
|
||||
|
||||
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'),
|
||||
|
||||
utils = require('../public/src/utils'),
|
||||
plugins = require('./plugins');
|
||||
plugins = require('./plugins'),
|
||||
reds = require('reds'),
|
||||
search = reds.createSearch('nodebbsearch');
|
||||
|
||||
(function(PostTools) {
|
||||
PostTools.isMain = function(pid, tid, callback) {
|
||||
@@ -56,6 +58,10 @@ var RDB = require('./redis.js'),
|
||||
posts.setPostField(pid, 'edited', Date.now());
|
||||
posts.setPostField(pid, 'editor', uid);
|
||||
|
||||
search.remove(pid, function() {
|
||||
search.index(content, pid);
|
||||
});
|
||||
|
||||
posts.getPostField(pid, 'tid', function(tid) {
|
||||
PostTools.isMain(pid, tid, function(isMainPost) {
|
||||
if (isMainPost)
|
||||
@@ -84,6 +90,7 @@ var RDB = require('./redis.js'),
|
||||
var success = function() {
|
||||
posts.setPostField(pid, 'deleted', 1);
|
||||
|
||||
search.remove(pid);
|
||||
|
||||
posts.getPostFields(pid, ['tid', 'uid'], function(postData) {
|
||||
|
||||
@@ -119,7 +126,7 @@ var RDB = require('./redis.js'),
|
||||
var success = function() {
|
||||
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);
|
||||
|
||||
@@ -132,6 +139,8 @@ var RDB = require('./redis.js'),
|
||||
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'),
|
||||
feed = require('./feed.js'),
|
||||
async = require('async'),
|
||||
plugins = require('./plugins');
|
||||
plugins = require('./plugins'),
|
||||
reds = require('reds'),
|
||||
search = reds.createSearch('nodebbsearch');
|
||||
|
||||
(function(Posts) {
|
||||
|
||||
@@ -323,46 +325,19 @@ var RDB = require('./redis.js'),
|
||||
|
||||
user.onNewPostMade(uid, tid, pid, timestamp);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
uploadPostImages(postData, images, function(err, uploadedImages) {
|
||||
if(err) {
|
||||
console.log('Uploading images failed!');
|
||||
} else {
|
||||
postData.uploadedImages = JSON.stringify(uploadedImages);
|
||||
Posts.setPostField(pid, 'uploadedImages', postData.uploadedImages);
|
||||
}
|
||||
callback(postData);
|
||||
});
|
||||
|
||||
plugins.fireHook('action:save_post_content', [pid, content]);
|
||||
|
||||
if(!images) {
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
search.index(content, pid);
|
||||
});
|
||||
});
|
||||
} 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) {
|
||||
|
||||
user.getPostIds(uid, start, end, function(pids) {
|
||||
|
||||
@@ -146,5 +146,36 @@ var user = require('./../user.js'),
|
||||
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));
|
||||
|
||||
@@ -382,6 +382,18 @@ var express = require('express'),
|
||||
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));
|
||||
|
||||
Reference in New Issue
Block a user