mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 11:05:54 +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); | ||||||
| 			}); | 			}); | ||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										45
									
								
								src/posts.js
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								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,6 +325,28 @@ var	RDB = require('./redis.js'), | |||||||
| 						 | 						 | ||||||
| 						user.onNewPostMade(uid, tid, pid, timestamp);					 | 						user.onNewPostMade(uid, tid, pid, timestamp);					 | ||||||
|  |  | ||||||
|  | 						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]); | ||||||
|  | 						 | ||||||
|  | 						search.index(content, pid); | ||||||
|  | 					}); | ||||||
|  | 				}); | ||||||
|  | 			} else { | ||||||
|  | 				callback(null); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function uploadPostImages(postData, images, callback) { | ||||||
| 		var imgur = require('./imgur'); | 		var imgur = require('./imgur'); | ||||||
| 		imgur.setClientID(global.nconf.get('imgurClientID')); | 		imgur.setClientID(global.nconf.get('imgurClientID')); | ||||||
| 						 | 						 | ||||||
| @@ -344,31 +368,18 @@ var	RDB = require('./redis.js'), | |||||||
| 			});			 | 			});			 | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 						plugins.fireHook('action:save_post_content', [pid, content]); |  | ||||||
| 						 |  | ||||||
| 		if(!images) { | 		if(!images) { | ||||||
| 							postData.uploadedImages = JSON.stringify(uploadedImages); | 			callback(null, uploadedImages); | ||||||
| 							Posts.setPostField(pid, 'uploadedImages', postData.uploadedImages); |  | ||||||
| 							callback(postData); |  | ||||||
| 		} else { | 		} else { | ||||||
| 			async.each(images, uploadImage, function(err) { | 			async.each(images, uploadImage, function(err) { | ||||||
| 				if(!err) { | 				if(!err) { | ||||||
| 									postData.uploadedImages = JSON.stringify(uploadedImages); | 					callback(null, uploadedImages); | ||||||
| 									Posts.setPostField(pid, 'uploadedImages', postData.uploadedImages); |  | ||||||
| 		 |  | ||||||
| 									callback(postData); |  | ||||||
| 				} else { | 				} else { | ||||||
| 					console.log(err); | 					console.log(err); | ||||||
| 									callback(null); | 					callback(err, null); | ||||||
| 				} | 				} | ||||||
| 			}); | 			}); | ||||||
| 		} | 		} | ||||||
| 					}); |  | ||||||
| 				}); |  | ||||||
| 			} else { |  | ||||||
| 				callback(null); |  | ||||||
| 			} |  | ||||||
| 		}); |  | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	Posts.getPostsByUid = function(uid, start, end, callback) { | 	Posts.getPostsByUid = function(uid, start, end, callback) { | ||||||
|   | |||||||
| @@ -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