Skip to content

Commit

Permalink
Implemented full text search for documents in member-client #15
Browse files Browse the repository at this point in the history
  • Loading branch information
nicho90 committed May 5, 2017
1 parent 2bbadd8 commit 93bb2d8
Show file tree
Hide file tree
Showing 15 changed files with 1,576 additions and 37 deletions.
215 changes: 215 additions & 0 deletions controllers/documents/search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
var async = require('async');
var colors = require('colors');
var pg = require('pg');
var types = require('pg').types;
types.setTypeParser(1700, 'text', parseFloat);
var _ = require('underscore');
var jwt = require('jsonwebtoken');
var pool = require('../../server.js').pool;
var server_url = require('../../server.js').server_url;
var jwtSecret = require('../../server.js').jwtSecret;

var fs = require("fs");
var dir_1 = "/../../sql/queries/members/";
var dir_2 = "/../../sql/queries/documents/";
var query_get_member = fs.readFileSync(__dirname + dir_1 + 'get.sql', 'utf8').toString();
var query_search_documents_with_user = fs.readFileSync(__dirname + dir_2 + 'search_with_user.sql', 'utf8').toString();
var query_search_documents_with_user_with_course = fs.readFileSync(__dirname + dir_2 + 'search_with_user_with_course.sql', 'utf8').toString();
var query_search_documents_with_user_without_course = fs.readFileSync(__dirname + dir_2 + 'search_with_user_without_course.sql', 'utf8').toString();
var query_search_documents_filter_by_status = fs.readFileSync(__dirname + dir_2 + 'search_filter_by_status.sql', 'utf8').toString();
var query_search_documents_filter_by_status_and_status = fs.readFileSync(__dirname + dir_2 + 'search_filter_by_status_and_status.sql', 'utf8').toString();
var query_search_documents_filter_by_status_with_course = fs.readFileSync(__dirname + dir_2 + 'search_filter_by_status_with_course.sql', 'utf8').toString();
var query_search_documents_filter_by_status_and_status_with_course = fs.readFileSync(__dirname + dir_2 + 'search_filter_by_status_and_status_with_course.sql', 'utf8').toString();
var query_search_documents_filter_by_status_without_course = fs.readFileSync(__dirname + dir_2 + 'search_filter_by_status_without_course.sql', 'utf8').toString();
var query_search_documents_filter_by_status_and_status_without_course = fs.readFileSync(__dirname + dir_2 + 'search_filter_by_status_and_status_without_course.sql', 'utf8').toString();


// SEARCH ALL
exports.request = function(req, res) {

async.waterfall([
function(callback){
// Connect to database
pool.connect(function(err, client, done) {
if(err) {
callback(err, 500);
} else {
callback(null, client, done);
}
});
},
function(client, done, callback) {
// Authorization
if(req.headers.authorization) {
var token = req.headers.authorization.substring(7);

// Verify token
jwt.verify(token, jwtSecret, function(err, decoded) {
if(err){
callback(new Error("Authorization failed"), 401);
} else {
if(decoded.member){
// Database query
client.query(query_get_member, [
decoded.member_id
], function(err, result) {
done();
if (err) {
callback(err, 500);
} else {
// Check if Member exists
if (result.rows.length === 0) {
callback(new Error("Member not found"), 404);
} else {
callback(null, client, done, result.rows[0]);
}
}
});
} else {
callback(new Error("Authorization failed"), 401);
}
}
});
} else {
callback(new Error("Authorization failed"), 401);
}
},
function(client, done, member, callback) {
console.log(req.body);

var query;
var params = [];

// Pagination parameters
params.push(Number(req.query.offset) || null );
params.push(Number(req.query.limit) || null );

// Sorting
params.push(req.query.orderby || 'created.desc');

// Filter by institute
params.push(member.institute_id);

// Filter with/without course
query = query_search_documents_with_user;
switch(req.query.course){
case 'true': {
query = query_search_documents_with_user_with_course;
break;
}
case 'false': {
query = query_search_documents_with_user_without_course;
break;
}
default: {
query = query_search_documents_with_user;
}
}

// Filter by status
switch(req.query.status){
case '0': {
params.push(0);
break;
}
case '1': {
params.push(1);
break;
}
case '2': {
params.push(2);
break;
}
case '3': {
params.push(3);
break;
}
case '4': {
params.push(4);
break;
}
case '5': {
params.push(5);
break;
}
case '6': {
params.push(6);
break;
}
case '7': {
params.push(7);
break;
}
case '8': {
params.push(2);
params.push(6);
break;
}
}

// Filter by status with/without course
if(req.query.status){
// Check for status
if(params.length === 6){
query = query_search_documents_filter_by_status_and_status;
} else {
query = query_search_documents_filter_by_status;
}
// Check for course
switch(req.query.course){
case 'true': {
// Check for status
if(params.length === 6){
query = query_search_documents_filter_by_status_and_status_with_course;
} else {
query = query_search_documents_filter_by_status_with_course;
}
break;
}
case 'false': {
// Check for status
if(params.length === 6){
query = query_search_documents_filter_by_status_and_status_without_course;
} else {
query = query_search_documents_filter_by_status_without_course;
}
break;
}
}
}

// Prepare search-query
var search_text = req.body.search_text;
var search_array = search_text.split(' ');
var search_query_text = "";
for(var i=0; i<search_array.length; i++){
if(i !== search_array.length-1){
search_query_text = search_query_text + search_array[i] + ":*|";
} else {
search_query_text = search_query_text + search_array[i] + ":*";
}
}
params.push(search_query_text);

callback(null, client, done, query, params);
},
function(client, done, query, params, callback) {
// Database query
client.query(query, params, function(err, result) {
done();
if (err) {
callback(err, 500);
} else {
callback(null, 200, result.rows);
}
});
}
], function(err, code, result) {
if(err){
console.error(colors.red(err));
res.status(code).send(err.message);
} else {
res.status(code).send(result);
}
});
};
98 changes: 66 additions & 32 deletions public/member-client/js/controllers/document/listController.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,45 +40,79 @@ app.controller("documentListController", function($scope, $rootScope, $filter, $
* @return {[type]} [description]
*/
$scope.load = function(){

$documentsService.list($scope.filter)
.then(function onSuccess(response) {
$documentsService.set(response.data);
$scope.documents = $documentsService.get();

// Prepare pagination
if($scope.documents.length > 0){
// Set count
$documentsService.setCount($scope.documents[0].full_count);
} else {
// Reset count
$documentsService.setCount(0);

// Reset pagination
// Check for a search-text
if($scope.filter.search_text !== ""){
$documentsService.search($scope.filter)
.then(function onSuccess(response) {
$documentsService.set(response.data);
$scope.documents = $documentsService.get();

// Prepare pagination
if($scope.documents.length > 0){
// Set count
$documentsService.setCount($scope.documents[0].full_count);
} else {
// Reset count
$documentsService.setCount(0);

// Reset pagination
$scope.pages = [];
$scope.filter.offset = 0;
}

// Set pagination
$scope.pages = [];
$scope.filter.offset = 0;
}

// Set pagination
$scope.pages = [];
for(var i=0; i<Math.ceil($documentsService.getCount() / $scope.filter.limit); i++){
$scope.pages.push({
offset: i * $scope.filter.limit
});
}

$scope.$parent.loading = { status: false, message: "" };
})
.catch(function onError(response) {
$window.alert(response.data);
});
for(var i=0; i<Math.ceil($documentsService.getCount() / $scope.filter.limit); i++){
$scope.pages.push({
offset: i * $scope.filter.limit
});
}

$scope.$parent.loading = { status: false, message: "" };
})
.catch(function onError(response) {
$window.alert(response.data);
});
} else {
$documentsService.list($scope.filter)
.then(function onSuccess(response) {
$documentsService.set(response.data);
$scope.documents = $documentsService.get();

// Prepare pagination
if($scope.documents.length > 0){
// Set count
$documentsService.setCount($scope.documents[0].full_count);
} else {
// Reset count
$documentsService.setCount(0);

// Reset pagination
$scope.pages = [];
$scope.filter.offset = 0;
}

// Set pagination
$scope.pages = [];
for(var i=0; i<Math.ceil($documentsService.getCount() / $scope.filter.limit); i++){
$scope.pages.push({
offset: i * $scope.filter.limit
});
}

$scope.$parent.loading = { status: false, message: "" };
})
.catch(function onError(response) {
$window.alert(response.data);
});
}
};

/**
* [resetSearch description]
*/
$scope.resetSearch = function(){
$scope.searchText = "";
$scope.filter.search_text = "";
};

/**
Expand Down
31 changes: 29 additions & 2 deletions public/member-client/js/services/documentsService.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ app.factory('$documentsService', function($http, $log, config, $authenticationSe
limit: 50,
orderby: "created.desc",
course: "false",
status: "3"
status: "3",
search_text: ""
};
var full_count = 0;

Expand Down Expand Up @@ -92,7 +93,33 @@ app.factory('$documentsService', function($http, $log, config, $authenticationSe
'Authorization': 'Bearer ' + $authenticationService.getToken()
}
});
}
},
search: function(filter) {
var query = "?orderby=" + filter.orderby + "&";

if(filter.offset && filter.offset !== null){
query = query + "offset=" + filter.offset + "&";
}
if(filter.limit && filter.limit !== null){
query = query + "limit=" + filter.limit + "&";
}
if(filter.course !== null){
query = query + "course=" + filter.course + "&";
}
if(filter.status !== null){
query = query + "status=" + filter.status + "&";
}

query = query.slice(0, -1);

return $http.post(config.apiURL + "/search/documents" + query, {
search_text: filter.search_text
}, {
headers: {
'Authorization': 'Bearer ' + $authenticationService.getToken()
}
});
},

};

Expand Down
6 changes: 3 additions & 3 deletions public/member-client/js/templates/document/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
<span class="input-group-addon">
<i class="fa fa-search" aria-hidden="true"></i>
</span>
<input type="text" class="form-control" placeholder="{{ 'SEARCH' | translate }}" ng-model="searchText">
<span class="input-group-btn" ng-if="searchText">
<input type="text" class="form-control" placeholder="{{ 'SEARCH' | translate }}" ng-model="filter.search_text" ng-change="applyFilter()">
<span class="input-group-btn" ng-if="filter.search_text">
<a href="" class="btn btn-secondary" ng-click="resetSearch()">
<i class="fa fa-times" aria-hidden="true"></i>
</a>
Expand Down Expand Up @@ -86,7 +86,7 @@
</div>

<div class="list-group" ng-if="documents && documents.length>0">
<a href="" ng-click="redirect('/documents/' + document.document_id)" class="list-group-item list-group-item-action flex-column align-items-start" ng-repeat="document in documents | filter: searchText">
<a href="" ng-click="redirect('/documents/' + document.document_id)" class="list-group-item list-group-item-action flex-column align-items-start" ng-repeat="document in documents">
<div class="d-flex w-100 justify-content-between">
<div>
<i class="fa fa-file-text" aria-hidden="true"></i>
Expand Down
Loading

0 comments on commit 93bb2d8

Please sign in to comment.