Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/release'
Browse files Browse the repository at this point in the history
  • Loading branch information
daneryl committed Feb 8, 2021
2 parents d7cf068 + cdf5450 commit 25dd55a
Show file tree
Hide file tree
Showing 60 changed files with 1,213 additions and 816 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
[![Maintainability](https://api.codeclimate.com/v1/badges/8c98a251ca64daf434f2/maintainability)](https://codeclimate.com/github/huridocs/uwazi/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/8c98a251ca64daf434f2/test_coverage)](https://codeclimate.com/github/huridocs/uwazi/test_coverage)

Uwazi is an open-source document manager.
Uwazi is a flexible database application to capture and organise collections of information with a particular focus on document management. HURIDOCS started Uwazi and is supporting dozens of human rights organisations globally to use the tool.

[Uwazi](https://www.uwazi.io/) | [HURIDOCS](https://huridocs.org/)

Read the [user guide](https://github.com/huridocs/uwazi/wiki)

# Intallation guide
# Installation guide

- [Dependencies](#dependencies)
- [Production](#production)
Expand Down
2 changes: 1 addition & 1 deletion app/api/documents/specs/documents.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { catchErrors } from 'api/utils/jasmineHelpers';
import { mockID } from 'shared/uniqueID';
import relationships from 'api/relationships';
import entities from 'api/entities';
import search from 'api/search/search';
import { search } from 'api/search';
import db from 'api/utils/testing_db';
import { files } from 'api/files';
import { fileExists, uploadsPath } from 'api/files/filesystem';
Expand Down
26 changes: 18 additions & 8 deletions app/api/entities/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import ID from 'shared/uniqueID';
import { propertyTypes } from 'shared/propertyTypes';
import date from 'api/utils/date';
import relationships from 'api/relationships/relationships';
import search from 'api/search/search';
import { search } from 'api/search';
import templates from 'api/templates/templates';
import translationsModel from 'api/i18n/translations';
import path from 'path';
Expand Down Expand Up @@ -357,7 +357,7 @@ export default {
},

/** Bulk rebuild relationship-based metadata objects as {value = id, label: title}. */
async bulkUpdateMetadataFromRelationships(query, language, limit = 200) {
async bulkUpdateMetadataFromRelationships(query, language, limit = 200, reindex = true) {
const process = async (offset, totalRows) => {
if (offset >= totalRows) {
return;
Expand All @@ -366,7 +366,8 @@ export default {
const entities = await this.get(query, 'sharedId', { skip: offset, limit });
await this.updateMetdataFromRelationships(
entities.map(entity => entity.sharedId),
language
language,
reindex
);
await process(offset + limit, totalRows);
};
Expand Down Expand Up @@ -474,7 +475,7 @@ export default {
},

/** Rebuild relationship-based metadata objects as {value = id, label: title}. */
async updateMetdataFromRelationships(entities, language) {
async updateMetdataFromRelationships(entities, language, reindex = true) {
const entitiesToReindex = [];
const _templates = await templates.get();
await Promise.all(
Expand Down Expand Up @@ -507,11 +508,14 @@ export default {
}
})
);
await search.indexEntities({ sharedId: { $in: entitiesToReindex } });

if (reindex) {
await search.indexEntities({ sharedId: { $in: entitiesToReindex } });
}
},

/** Handle property deletion and renames. */
async updateMetadataProperties(template, currentTemplate, language) {
async updateMetadataProperties(template, currentTemplate, language, reindex = true) {
const actions = { $rename: {}, $unset: {} };
template.properties = await generateNamesAndIds(template.properties);
template.properties.forEach(property => {
Expand Down Expand Up @@ -540,10 +544,16 @@ export default {
await model.updateMany({ template: template._id }, actions);
}

if (!template.properties.find(p => p.type === propertyTypes.relationship)) {
if (!template.properties.find(p => p.type === propertyTypes.relationship) && reindex) {
return search.indexEntities({ template: template._id });
}
return this.bulkUpdateMetadataFromRelationships({ template: template._id, language }, language);

return this.bulkUpdateMetadataFromRelationships(
{ template: template._id, language },
language,
200,
reindex
);
},

async deleteFiles(deletedDocs) {
Expand Down
5 changes: 2 additions & 3 deletions app/api/entities/specs/entities.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import db from 'api/utils/testing_db';
import entitiesModel from 'api/entities/entitiesModel';
import fs from 'fs';
import relationships from 'api/relationships';
import search from 'api/search/search';
import { search } from 'api/search';
import { uploadsPath } from 'api/files/filesystem';

import entities from '../entities.js';
Expand Down Expand Up @@ -306,7 +306,6 @@ describe('entities', () => {
expect(relatedEntity.metadata.enemies[1].label).toBe('translated2');
});

/*eslint-disable */
it('should index entities changed after propagating label change', async () => {
const doc = {
_id: shared2,
Expand Down Expand Up @@ -1017,7 +1016,7 @@ describe('entities', () => {

describe('when database deletion throws an error', () => {
it('should reindex the documents', async () => {
spyOn(entitiesModel, 'delete').and.callFake(() => Promise.reject('error'));
spyOn(entitiesModel, 'delete').and.callFake(() => Promise.reject(new Error('error')));
let error;
try {
await entities.delete('shared');
Expand Down
2 changes: 1 addition & 1 deletion app/api/files/filesystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const appendFile = promisify(fs.appendFile);

const fileExists = async (filePath: FilePath): Promise<boolean> =>
new Promise((resolve, reject) => {
fs.stat(filePath, err => {
fs.access(filePath, err => {
if (err === null) {
resolve(true);
}
Expand Down
2 changes: 1 addition & 1 deletion app/api/files/specs/exportRoutes.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Writable } from 'stream';
import request from 'supertest';
import { setUpApp } from 'api/utils/testingRoutes';
import search from 'api/search/search';
import { search } from 'api/search';
import db from 'api/utils/testing_db';
import csvExporter from 'api/csv/csvExporter';
import * as filesystem from 'api/files/filesystem';
Expand Down
5 changes: 5 additions & 0 deletions app/api/files/specs/filesystem.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ describe('files', () => {
fs.writeFileSync(`${__dirname}/file2`, '');
});

afterAll(() => {
fs.unlinkSync(`${__dirname}/file1`);
fs.unlinkSync(`${__dirname}/file2`);
});

describe('deleteFiles', () => {
it('should delete all files passed', async () => {
await deleteFiles([`${__dirname}/file1`, `${__dirname}/file2`]);
Expand Down
2 changes: 1 addition & 1 deletion app/api/files/specs/jsRoutes.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { catchErrors } from 'api/utils/jasmineHelpers';
import db from 'api/utils/testing_db';
import entities from 'api/entities';
import { settingsModel } from 'api/settings/settingsModel';
import search from 'api/search/search';
import { search } from 'api/search';
import request from 'supertest';
import express from 'express';

Expand Down
6 changes: 3 additions & 3 deletions app/api/files/specs/publicRoutes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('public routes', () => {
beforeEach(async () => {
spyOn(search, 'indexEntities').and.returnValue(Promise.resolve());
spyOn(Date, 'now').and.returnValue(1000);
spyOn(errorLog, 'error'); //just to avoid annoying console output
spyOn(errorLog, 'error');
await db.clearAllAndLoad(fixtures);
setupTestUploadedPaths();
});
Expand All @@ -65,15 +65,15 @@ describe('public routes', () => {
);

const [newEntity] = await entities.get({ title: 'public submit' });
const attachments = newEntity.attachments || [];
const { attachments } = newEntity;
expect(attachments).toEqual([expect.objectContaining({ originalname: 'attachment.txt' })]);

const [uploadedFile] = await files.get({ entity: newEntity.sharedId });
expect(uploadedFile.originalname).toBe('12345.test.pdf');
expect(uploadedFile.status).toBe('ready');

expect(await fileExists(uploadsPath(uploadedFile.filename))).toBe(true);
expect(await fileExists(attachmentsPath(attachments[0].filename))).toBe(true);
expect(await fileExists(attachmentsPath(attachments?.[0].filename))).toBe(true);
});

it('should send an email', async () => {
Expand Down
3 changes: 2 additions & 1 deletion app/api/odm/specs/model.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ describe('ODM Model', () => {
};

it('should register all the models to the requirable models hashmap', () => {
expect(models).toEqual({});
expect(models.tempSchema).toBeUndefined();
expect(models.anotherSchema).toBeUndefined();
const model1 = instanceTestingModel('tempSchema', testSchema);
const model2 = instanceTestingModel('anotherSchema', new mongoose.Schema({ name: String }));

Expand Down
2 changes: 1 addition & 1 deletion app/api/relationships/relationships.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { generateID } from 'api/odm';
import { createError } from 'api/utils';

import model from './model';
import search from '../search/search';
import { search } from '../search';
import { generateNamesAndIds } from '../templates/utils';

import { filterRelevantRelationships, groupRelationships } from './groupByRelationships';
Expand Down
2 changes: 1 addition & 1 deletion app/api/relationships/specs/relationships.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import fixtures, {
template,
} from './fixtures';
import relationships from '../relationships';
import search from '../../search/search';
import { search } from '../../search';

describe('relationships', () => {
beforeEach(done => {
Expand Down
10 changes: 1 addition & 9 deletions app/api/search/deprecatedRoutes.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import Joi from 'joi';
import entities from 'api/entities';
import { searchSchema } from 'api/search/searchSchema';
import search from './search';
import { search } from './search';
import { validation, parseQuery } from '../utils';
import needsAuthorization from '../auth/authMiddleware';

export default app => {
app.get(
Expand Down Expand Up @@ -61,11 +60,4 @@ export default app => {
.then(results => res.json(results))
.catch(next)
);

app.get('/api/search/unpublished', needsAuthorization(['admin', 'editor']), (req, res, next) => {
search
.getUploadsByUser(req.user, req.language)
.then(response => res.json({ rows: response }))
.catch(next);
});
};
7 changes: 0 additions & 7 deletions app/api/search/elastic.js

This file was deleted.

86 changes: 86 additions & 0 deletions app/api/search/elastic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import elasticSearch, { RequestParams } from '@elastic/elasticsearch';
import {
TransportRequestOptions,
RequestBody,
RequestNDBody,
} from '@elastic/elasticsearch/lib/Transport';
import { tenants } from 'api/tenants';
import { EntitySchema } from 'shared/types/entityType';
import { SearchResponse, IndicesPutMapping, IndicesDelete, IndicesCreate } from './elasticTypes';

const elasticClient = new elasticSearch.Client({
node: process.env.ELASTICSEARCH_URL || 'http://localhost:9200',
});

const elastic = {
async search(params?: RequestParams.Search<RequestBody>, options?: TransportRequestOptions) {
return elasticClient.search<SearchResponse<EntitySchema>, RequestBody>(
{ ...params, index: tenants.current().indexName },
options
);
},

async delete(params: RequestParams.Delete, options?: TransportRequestOptions) {
return elasticClient.delete({ ...params, index: tenants.current().indexName }, options);
},

async bulk(params: RequestParams.Bulk<RequestNDBody>, options?: TransportRequestOptions) {
return elasticClient.bulk({ ...params, index: tenants.current().indexName }, options);
},

async deleteByQuery(
params: RequestParams.DeleteByQuery<RequestBody>,
options?: TransportRequestOptions
) {
return elasticClient.deleteByQuery({ ...params, index: tenants.current().indexName }, options);
},

indices: {
async putMapping(params: IndicesPutMapping, options?: TransportRequestOptions) {
return elasticClient.indices.putMapping(
{ ...params, index: tenants.current().indexName },
options
);
},

async getMapping(params?: RequestParams.IndicesGetMapping, options?: TransportRequestOptions) {
return elasticClient.indices.getMapping(
{ ...params, index: tenants.current().indexName },
options
);
},

async delete(params?: IndicesDelete, options?: TransportRequestOptions) {
return elasticClient.indices.delete(
{ ...params, index: tenants.current().indexName },
options
);
},

async create(params?: IndicesCreate, options?: TransportRequestOptions) {
return elasticClient.indices.create(
{ ...params, index: tenants.current().indexName },
options
);
},

async refresh(params?: RequestParams.IndicesRefresh, options?: TransportRequestOptions) {
return elasticClient.indices.refresh(
{ ...params, index: tenants.current().indexName },
options
);
},

async validateQuery(
params?: RequestParams.IndicesValidateQuery<RequestBody>,
options?: TransportRequestOptions
) {
return elasticClient.indices.validateQuery(
{ ...params, index: tenants.current().indexName },
options
);
},
},
};

export { elastic, elasticClient };
50 changes: 50 additions & 0 deletions app/api/search/elasticTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { RequestParams } from '@elastic/elasticsearch';
import { RequestBody } from '@elastic/elasticsearch/lib/Transport';

interface ShardsResponse {
total: number;
successful: number;
failed: number;
skipped: number;
}

interface Explanation {
value: number;
description: string;
details: Explanation[];
}

export interface SearchResponse<T> {
took: number;
// eslint-disable-next-line camelcase
timed_out: boolean;
// eslint-disable-next-line camelcase
_scroll_id?: string;
_shards: ShardsResponse;
hits: {
total: number;
// eslint-disable-next-line camelcase
max_score: number;
hits: Array<{
_index: string;
_type: string;
_id: string;
_score: number;
_source: T;
_version?: number;
_explanation?: Explanation;
fields?: any;
highlight?: any;
// eslint-disable-next-line camelcase
inner_hits?: any;
// eslint-disable-next-line camelcase
matched_queries?: string[];
sort?: string[];
}>;
};
aggregations?: any;
}

export type IndicesDelete = Omit<RequestParams.IndicesDelete, 'index'>;
export type IndicesCreate = Omit<RequestParams.IndicesCreate<RequestBody>, 'index'>;
export type IndicesPutMapping = Omit<RequestParams.IndicesPutMapping<RequestBody>, 'index'>;
Loading

0 comments on commit 25dd55a

Please sign in to comment.