diff --git a/app/api/documents/documentQueryBuilder.js b/app/api/documents/documentQueryBuilder.js
deleted file mode 100644
index 1aa117b88e..0000000000
--- a/app/api/documents/documentQueryBuilder.js
+++ /dev/null
@@ -1,102 +0,0 @@
-
-export default function () {
- let baseQuery = {
- _source: {
- include: [ 'doc.title', 'doc.processed', 'doc.creationDate', 'doc.template', 'doc.metadata']
- },
- from: 0,
- size: 12,
- query: {
- match_all: {}
- },
- sort: [],
- filter: {
- bool: {
- must: [
- {match: {'doc.published': true}}
- ]
- }
- }
- };
-
- return {
- query() {
- return baseQuery;
- },
-
- fullTextSearch(term, fieldsToSearch = ['doc.fullText', 'doc.metadata.*', 'doc.title']) {
- if (term) {
- baseQuery.query = {
- multi_match: {
- query: term,
- type: 'phrase_prefix',
- fields: fieldsToSearch
- }
- };
- }
- return this;
- },
-
- sort(property, order = 'desc') {
- let sort = {};
- sort[`doc.${property}`] = {order, ignore_unmapped: true};
- baseQuery.sort.push(sort);
- return this;
- },
-
- filterMetadata(filters = {}) {
- Object.keys(filters).forEach((property) => {
- if (filters[property].type === 'text') {
- let match = {};
- match[`doc.metadata.${property}`] = filters[property].value;
- baseQuery.filter.bool.must.push({match});
- }
-
- if (filters[property].type === 'range') {
- let range = {};
- range[`doc.metadata.${property}`] = {gte: filters[property].value.from, lte: filters[property].value.to};
- baseQuery.filter.bool.must.push({range});
- }
- });
- return this;
- },
-
- filterByTemplate(templates = []) {
- if (templates.length) {
- let match = {bool: {
- should: [],
- minimum_should_match: 1
- }};
-
- templates.forEach((templateId) => {
- match.bool.should.push({match: {'doc.template': templateId}});
- });
-
- baseQuery.filter.bool.must.push(match);
- }
- return this;
- },
-
- highlight(fields) {
- baseQuery.highlight = {
- pre_tags : [''],
- post_tags : ['']
- };
- baseQuery.highlight.fields = {};
- fields.forEach((field) => {
- baseQuery.highlight.fields[field] = {};
- });
- return this;
- },
-
- from(from) {
- baseQuery.from = from;
- return this;
- },
-
- limit(size) {
- baseQuery.size = size;
- return this;
- }
- };
-}
diff --git a/app/api/documents/specs/documentsQueryBuilder.spec.js b/app/api/documents/specs/documentsQueryBuilder.spec.js
deleted file mode 100644
index ca2059112f..0000000000
--- a/app/api/documents/specs/documentsQueryBuilder.spec.js
+++ /dev/null
@@ -1,117 +0,0 @@
-import queryBuilder from 'api/documents/documentQueryBuilder';
-
-describe('documentQueryBuilder', () => {
- beforeEach(() => {});
-
- describe('default query', () => {
- it('should do a match all on published documents', () => {
- expect(queryBuilder().query().query).toEqual({match_all: {}});
- expect(queryBuilder().query().filter.bool.must[0]).toEqual({match: {'doc.published': true}});
- });
- });
-
- describe('from', () => {
- it('should set from', () => {
- expect(queryBuilder().from(5).query().from).toEqual(5);
- });
- });
-
- describe('limit', () => {
- it('should set size', () => {
- expect(queryBuilder().limit(55).query().size).toEqual(55);
- });
- });
-
- describe('filterMetadata', () => {
- it('should add filter conditions', () => {
- let query = queryBuilder().filterMetadata({property1: {value: 'value1', type: 'text'}, property2: {value: 'value2', type: 'text'}}).query();
- expect(query.filter.bool.must[0]).toEqual({match: {'doc.published': true}});
- expect(query.filter.bool.must[1]).toEqual({match: {'doc.metadata.property1': 'value1'}});
- expect(query.filter.bool.must[2]).toEqual({match: {'doc.metadata.property2': 'value2'}});
- });
-
- it('should filter range filters', () => {
- let query = queryBuilder().filterMetadata({property1: {value: {from: 10, to: 20}, type: 'range'}}).query();
- expect(query.filter.bool.must[0]).toEqual({match: {'doc.published': true}});
- expect(query.filter.bool.must[1]).toEqual({range: {'doc.metadata.property1': {gte: 10, lte: 20}}});
- });
-
- describe('when there is no filters', () => {
- it('should add filter conditions', () => {
- let query = queryBuilder().filterMetadata().query();
- expect(query.filter.bool.must[0]).toEqual({match: {'doc.published': true}});
- expect(query.filter.bool.must.length).toBe(1);
- });
- });
- });
-
- describe('filterByTemplate', () => {
- it('should add a match to get only documents that match with the templates', () => {
- let query = queryBuilder().filterByTemplate(['template1', 'template2']).query();
- let expectedMatcher = {
- bool: {
- should: [
- {match: {'doc.template': 'template1'}},
- {match: {'doc.template': 'template2'}}
- ],
- minimum_should_match: 1
- }
- };
- expect(query.filter.bool.must[1]).toEqual(expectedMatcher);
- });
- });
-
- describe('fullTextSearch', () => {
- it('should do a multi_match on default fields', () => {
- let query = queryBuilder().fullTextSearch('term').query();
- expect(query.query).toEqual({
- multi_match: {
- query: 'term',
- type: 'phrase_prefix',
- fields: ['doc.fullText', 'doc.metadata.*', 'doc.title']
- }
- });
- });
-
- describe('when term is blank', () => {
- it('should return the default match_all', () => {
- let query = queryBuilder().fullTextSearch('').query();
- expect(query.query).toEqual({match_all: {}});
- });
- });
-
- describe('sort', () => {
- it('should add a sort property desc by default', () => {
- let query = queryBuilder().sort('title').query();
- expect(query.sort[0]).toEqual({'doc.title': {order: 'desc', ignore_unmapped: true}});
- });
- it('should sort by order passed', () => {
- let query = queryBuilder().sort('title', 'asc').query();
- expect(query.sort[0]).toEqual({'doc.title': {order: 'asc', ignore_unmapped: true}});
- });
- });
-
- describe('when passing fields', () => {
- it('should use them instead of the default ones', () => {
- let query = queryBuilder().fullTextSearch('term', ['another.field']).query();
- expect(query.query).toEqual({
- multi_match: {
- query: 'term',
- type: 'phrase_prefix',
- fields: ['another.field']
- }
- });
- });
- });
- });
-
- describe('highlights', () => {
- it('should return a query with hilight configuration for the fields passed', () => {
- let query = queryBuilder().highlight(['field1', 'field2']).query();
- expect(query.highlight.fields).toEqual({
- field1: {},
- field2: {}
- });
- });
- });
-});
diff --git a/app/api/search/specs/documentsQueryBuilder.spec.js b/app/api/search/specs/documentsQueryBuilder.spec.js
deleted file mode 100644
index 35d138b02e..0000000000
--- a/app/api/search/specs/documentsQueryBuilder.spec.js
+++ /dev/null
@@ -1,247 +0,0 @@
-/* eslint-disable camelcase */
-import queryBuilder from 'api/search/documentQueryBuilder';
-
-xdescribe('documentQueryBuilder', () => {
- beforeEach(() => {});
-
- describe('default query', () => {
- it('should do a match all on published documents', () => {
- expect(queryBuilder().query().query.bool.must[0]).toEqual({match: {published: true}});
- });
- });
-
- describe('unpublished', () => {
- it('should do a match all on published documents', () => {
- expect(queryBuilder().unpublished().query().query.bool.must[0]).toEqual({match: {published: false}});
- });
- });
-
- describe('owner', () => {
- it('should do a match all documents uploaded by a specific user', () => {
- const user = {_id: '123'};
- expect(queryBuilder().owner(user).query().query.bool.must[1]).toEqual({match: {user: '123'}});
- });
- });
-
- describe('from', () => {
- it('should set from', () => {
- expect(queryBuilder().from(5).query().from).toEqual(5);
- });
- });
-
- describe('limit', () => {
- it('should set size', () => {
- expect(queryBuilder().limit(55).query().size).toEqual(55);
- });
- });
-
- describe('language', () => {
- it('should set language', () => {
- let baseQuery = queryBuilder().language('es').query();
- expect(baseQuery.query.bool.must[1]).toEqual({match: {language: 'es'}});
-
- baseQuery = queryBuilder().language('en').query();
- expect(baseQuery.query.bool.must[1]).toEqual({match: {language: 'en'}});
- });
- });
-
- describe('includeUnpublished', () => {
- it('should allow including unpulbished documents', () => {
- let baseQuery = queryBuilder().includeUnpublished().query();
- expect(baseQuery.query.bool.must.length).toBe(0);
-
- baseQuery = queryBuilder().language('es').includeUnpublished().query();
- expect(baseQuery.query.bool.must[0]).toEqual({match: {language: 'es'}});
- });
- });
-
- describe('filterMetadata', () => {
- it('should add filter conditions', () => {
- let baseQuery = queryBuilder().filterMetadata({
- property1: {value: 'value1', type: 'text'},
- property2: {value: 'value2', type: 'text'}
- }).query();
- expect(baseQuery.query.bool.must[1]).toEqual({match: {'metadata.property1': 'value1'}});
- expect(baseQuery.query.bool.must[2]).toEqual({match: {'metadata.property2': 'value2'}});
- });
-
- it('should filter range filters', () => {
- let baseQuery = queryBuilder().filterMetadata({property1: {value: {from: 10, to: 20}, type: 'range'}}).query();
- expect(baseQuery.query.bool.must[1]).toEqual({range: {'metadata.property1': {gte: 10, lte: 20}}});
- });
-
- it('should filter multiselect filters', () => {
- let baseQuery = queryBuilder().filterMetadata({property1: {value: [23, 4, 16], type: 'multiselect'}}).query();
- expect(baseQuery.query.bool.must[1]).toEqual({terms: {'metadata.property1.raw': [23, 4, 16]}});
- });
- });
-
- describe('filterByTemplate', () => {
- it('should add a match to get only documents that match with the templates', () => {
- let baseQuery = queryBuilder().filterByTemplate(['template1', 'template2']).query();
- let expectedMatcher = {terms: {template: ['template1', 'template2']}};
- expect(baseQuery.query.bool.must[1]).toEqual(expectedMatcher);
- });
- });
-
- describe('filterById', () => {
- it('should add a match to get only documents that match with the passed ids', () => {
- let baseQuery = queryBuilder().filterById(['id1', 'id2']).query();
- let expectedMatcher = {terms: {'sharedId.raw': ['id1', 'id2']}};
- //expect(baseQuery.filter.bool.must[0]).toEqual(expectedMatcher);
- expect(baseQuery.query.bool.must[1]).toEqual(expectedMatcher);
- });
-
- describe('when id is a single value', () => {
- it('should add it to an array', () => {
- let baseQuery = queryBuilder().filterById('id').query();
- let expectedMatcher = {terms: {'sharedId.raw': ['id']}};
- expect(baseQuery.query.bool.must[1]).toEqual(expectedMatcher);
- });
- });
- });
-
- describe('aggregations', () => {
- it('default aggregations should contain types', () => {
- let baseQuery = queryBuilder().query();
- let typesAggregation = {
- terms: {
- field: 'template.raw',
- missing: 'missing',
- size: 9999
- },
- aggregations: {
- filtered: {
- filter: {
- bool: {
- must: []
- }
- }
- }
- }
- };
- expect(baseQuery.aggregations.types).toEqual(typesAggregation);
- });
-
- it('should add aggregations to the query with the current filters', () => {
- let baseQuery = queryBuilder().aggregations([{name: 'property1'}, {name: 'property2'}]).query();
- let property1Aggregation = {
- terms: {
- field: 'metadata.property1.raw',
- size: 9999
- },
- aggregations: {
- filtered: {
- filter: {
- bool: {
- must: [{match: {published: true}}]
- }
- }
- }
- }
- };
-
- expect(baseQuery.aggregations.property1).toEqual(property1Aggregation);
- });
- });
-
- describe('fullTextSearch', () => {
- it('should do a multi_match on default fields', () => {
- let baseQuery = queryBuilder().fullTextSearch('term').query();
- expect(baseQuery.query.bool.must[1]).toEqual(
- {
- bool: {
- should: [
- {
- has_child: {
- type: 'fullText',
- score_mode: 'max',
- inner_hits: {
- _source: false,
- highlight: {
- pre_tags: [''],
- post_tags: [''],
- fields: {
- fullText: {number_of_fragments: 10}
- }
- }
- },
- query: {
- multi_match: {
- query: 'term',
- type: 'phrase_prefix',
- fields: 'fullText'
- }
- }
- }
- },
- {
- multi_match: {
- query: 'term',
- type: 'phrase_prefix',
- fields: ['title']
- }
- }
- ]
- }
- }
- );
- });
-
- describe('when fieldsToSearch is empty', () => {
- it('shoud not include the multi_match', () => {
- let baseQuery = queryBuilder().fullTextSearch('term', [], false).query();
- expect(baseQuery.query.bool.must[1]).toEqual(
- {
- bool: {
- should: [
- ]
- }
- }
- );
- });
- });
-
- describe('when includeFullText = false', () => {
- it('should only search on the document by fieldsToSearch', () => {
- let baseQuery = queryBuilder().fullTextSearch('term', ['field1', 'field2'], false).query();
- expect(baseQuery.query.bool.must[1]).toEqual(
- {
- bool: {
- should: [
- {
- multi_match: {
- query: 'term',
- type: 'phrase_prefix',
- fields: ['field1', 'field2']
- }
- }
- ]
- }
- }
- );
- });
- });
-
- describe('sort', () => {
- it('should add a sort property desc by default', () => {
- let baseQuery = queryBuilder().sort('title').query();
- expect(baseQuery.sort[0]).toEqual({'title.raw': {order: 'desc', unmapped_type: 'boolean'}});
- });
- it('should sort by order passed', () => {
- let baseQuery = queryBuilder().sort('title', 'asc').query();
- expect(baseQuery.sort[0]).toEqual({'title.raw': {order: 'asc', unmapped_type: 'boolean'}});
- });
- });
- });
-
- describe('highlights', () => {
- it('should return a query with hilight configuration for the fields passed', () => {
- let baseQuery = queryBuilder().highlight(['field1', 'field2']).query();
- expect(baseQuery.highlight.fields).toEqual({
- field1: {},
- field2: {}
- });
- });
- });
-});
diff --git a/app/api/upload/PDF.js b/app/api/upload/PDF.js
index e1f842090c..0750bfece2 100644
--- a/app/api/upload/PDF.js
+++ b/app/api/upload/PDF.js
@@ -22,7 +22,7 @@ export default class PDF extends EventEmitter {
extractText() {
let logFile = fs.createWriteStream(this.logFile, {flags: 'a'});
let tmpPath = '/tmp/' + Date.now() + 'docsplit/';
- let options = ['text', '-o', tmpPath, this.filepath];
+ let options = ['text', '--no-ocr', '-o', tmpPath, this.filepath];
let extraction = spawn('docsplit', options);
extraction.stderr.pipe(logFile);
extraction.stdout.pipe(logFile);
diff --git a/app/api/upload/routes.js b/app/api/upload/routes.js
index 78face3141..6023dcbdfe 100644
--- a/app/api/upload/routes.js
+++ b/app/api/upload/routes.js
@@ -34,7 +34,6 @@ export default (app) => {
const docs = _docs.map((doc) => {
doc.file = req.files[0];
doc.uploaded = true;
- doc.processed = false;
return doc;
});
return entities.saveMultiple(docs);
diff --git a/app/react/Metadata/components/UploadButton.js b/app/react/Metadata/components/UploadButton.js
index 7c4bde1b3a..487806ffd6 100644
--- a/app/react/Metadata/components/UploadButton.js
+++ b/app/react/Metadata/components/UploadButton.js
@@ -3,7 +3,7 @@ import React, {Component} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {reuploadDocument} from 'app/Metadata/actions/actions';
-import io from 'socket.io-client';
+import socket from 'app/socket';
export class UploadButton extends Component {
@@ -11,34 +11,20 @@ export class UploadButton extends Component {
super(props, context);
this.state = {processing: false, failed: false, completed: false};
- }
- onChange(e) {
- let file = e.target.files[0];
- this.context.confirm({
- accept: () => {
- this.props.reuploadDocument(this.props.documentId, file, this.props.documentSharedId);
- },
- title: 'Confirm upload',
- message: 'Are you sure you want to upload a new document?\n\n' +
- 'All Table of Contents (TOC) and all text-based references linked to the previous document will be lost.'
+ socket.on('conversionStart', (docId) => {
+ if (docId === this.props.documentId) {
+ this.setState({processing: true, failed: false, completed: false});
+ }
});
- }
-
- componentWillMount() {
- //only on client
- if (!window.document) {
- return;
- }
- this.socket = io();
- this.socket.on('conversionStart', (docId) => {
+ socket.on('conversionFailed', (docId) => {
if (docId === this.props.documentId) {
- this.setState({processing: true, failed: false, completed: false});
+ this.setState({processing: false, failed: true, completed: false});
}
});
- this.socket.on('documentProcessed', (docId) => {
+ socket.on('documentProcessed', (docId) => {
if (docId === this.props.documentId) {
this.setState({processing: false, failed: false, completed: true}, () => {
setTimeout(() => {
@@ -47,20 +33,18 @@ export class UploadButton extends Component {
});
}
});
-
- this.socket.on('conversionFailed', (docId) => {
- if (docId === this.props.documentId) {
- this.setState({processing: false, failed: true, completed: false});
- }
- });
}
- componentWillUnmount() {
- //only on client
- if (!window.document) {
- return;
- }
- this.socket.disconnect();
+ onChange(e) {
+ let file = e.target.files[0];
+ this.context.confirm({
+ accept: () => {
+ this.props.reuploadDocument(this.props.documentId, file, this.props.documentSharedId);
+ },
+ title: 'Confirm upload',
+ message: 'Are you sure you want to upload a new document?\n\n' +
+ 'All Table of Contents (TOC) and all text-based references linked to the previous document will be lost.'
+ });
}
renderUploadButton() {
diff --git a/app/react/Uploads/components/UploadBox.js b/app/react/Uploads/components/UploadBox.js
index c4060e555f..cadd8dd8fa 100644
--- a/app/react/Uploads/components/UploadBox.js
+++ b/app/react/Uploads/components/UploadBox.js
@@ -7,9 +7,21 @@ import {wrapDispatch} from 'app/Multireducer';
import {uploadDocument, createDocument, documentProcessed, documentProcessError} from 'app/Uploads/actions/uploadsActions';
import {unselectAllDocuments} from 'app/Library/actions/libraryActions';
-import io from 'socket.io-client';
+import socket from 'app/socket';
export class UploadBox extends Component {
+
+ constructor(props) {
+ super(props);
+ socket.on('documentProcessed', (sharedId) => {
+ this.props.documentProcessed(sharedId);
+ });
+
+ socket.on('conversionFailed', (sharedId) => {
+ this.props.documentProcessError(sharedId);
+ });
+ }
+
onDrop(files) {
files.forEach((file) => {
let doc = {title: this.extractTitle(file)};
@@ -21,29 +33,6 @@ export class UploadBox extends Component {
this.props.unselectAllDocuments();
}
- componentWillMount() {
- //only on client
- if (!window.document) {
- return;
- }
- this.socket = io();
- this.socket.on('documentProcessed', (sharedId) => {
- this.props.documentProcessed(sharedId);
- });
-
- this.socket.on('conversionFailed', (sharedId) => {
- this.props.documentProcessError(sharedId);
- });
- }
-
- componentWillUnmount() {
- //only on client
- if (!window.document) {
- return;
- }
- this.socket.disconnect();
- }
-
extractTitle(file) {
let title = file.name
.replace(/\.[^/.]+$/, '')
diff --git a/app/react/socket.js b/app/react/socket.js
new file mode 100644
index 0000000000..379a687e89
--- /dev/null
+++ b/app/react/socket.js
@@ -0,0 +1,8 @@
+import io from 'socket.io-client';
+import {isClient} from 'app/utils';
+let socket = {on: () =>{}};
+if (isClient) {
+ socket = io();
+}
+
+export default socket;
diff --git a/app/react/sockets.js b/app/react/sockets.js
index b2234270f6..f6eb37da95 100644
--- a/app/react/sockets.js
+++ b/app/react/sockets.js
@@ -1,7 +1,6 @@
import {store} from './store';
import {actions} from 'app/BasicReducer';
-import io from 'socket.io-client';
-const socket = io();
+import socket from './socket';
socket.on('templateChange', (template) => {
store.dispatch(actions.update('templates', template));