Skip to content

Commit

Permalink
v1.175.0
Browse files Browse the repository at this point in the history
  • Loading branch information
daneryl committed Jul 15, 2024
2 parents db0a457 + fc976c4 commit e3129cb
Show file tree
Hide file tree
Showing 57 changed files with 1,307 additions and 1,315 deletions.
21 changes: 0 additions & 21 deletions app/api/entities/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import templates from 'api/templates/templates';
import { generateNames } from 'api/templates/utils';
import date from 'api/utils/date';
import { unique } from 'api/utils/filters';
import { objectIndex } from 'shared/data_utils/objectIndex';
import { AccessLevels } from 'shared/types/permissionSchema';
import { propertyTypes } from 'shared/propertyTypes';
import ID from 'shared/uniqueID';
Expand Down Expand Up @@ -534,26 +533,6 @@ export default {
return doc;
},

async saveMultiple(docs) {
const templateIds = Array.from(new Set(docs.map(d => d.template)));
const indexedTemplates = objectIndex(
await templates.get({ _id: { $in: templateIds } }),
t => t._id.toString(),
t => t
);

await docs.reduce(async (prev, _doc) => {
await prev;
const template = indexedTemplates[_doc.template];
const doc = this.sanitize(_doc, template);
await validateEntity(doc);
}, Promise.resolve());

const response = await model.saveMultiple(docs);
await search.indexEntities({ _id: { $in: response.map(d => d._id) } }, '+fullText');
return response;
},

async multipleUpdate(ids, values, params) {
const { diffMetadata = {}, ...pureValues } = values;

Expand Down
97 changes: 1 addition & 96 deletions app/api/entities/specs/entities.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1127,101 +1127,6 @@ describe('entities', () => {
});
});

describe('saveMultiple()', () => {
it('should allow partial saveMultiple with correct full indexing', done => {
const partialDoc = { _id: batmanFinishesId, sharedId: 'shared', title: 'Updated title' };
const partialDoc2 = {
_id: syncPropertiesEntityId,
sharedId: 'shared',
title: 'Updated title 2',
};
entities
.saveMultiple([partialDoc, partialDoc2])
.then(response => Promise.all([response, entities.getById(batmanFinishesId)]))
.then(([response, savedEntity]) => {
const expectedQuery = {
_id: { $in: [batmanFinishesId, syncPropertiesEntityId] },
};

expect(response[0]._id.toString()).toBe(batmanFinishesId.toString());
expect(savedEntity.title).toBe('Updated title');
expect(savedEntity.metadata).toEqual(
expect.objectContaining({
property1: [{ value: 'value1' }],
friends: [{ icon: null, label: 'shared2title', type: 'entity', value: 'shared2' }],
})
);
expect(search.indexEntities).toHaveBeenCalledWith(expectedQuery, '+fullText');
done();
})
.catch(done.fail);
});

it('should sanitize the entities', async () => {
const sanitizationSpy = jest.spyOn(entities, 'sanitize');
const docsToSave = [
{
title: 'Batman begins',
template: templateId,
language: 'es',
metadata: {
multiselect: [{ value: 'country_one' }, { value: 'country_two' }],
friends: [{ value: 'id1' }, { value: 'id2' }],
},
},
{
title: 'Batman begins',
template: templateId,
language: 'en',
metadata: {
multiselect: [{ value: 'country_one' }, { value: 'country_two' }],
friends: [{ value: 'id1' }, { value: 'id2' }],
},
},
{
title: 'Batman Goes On',
template: entityGetTestTemplateId,
language: 'en',
metadata: {
some_property: [{ value: 'some value' }],
},
},
];
await entities.saveMultiple(docsToSave);
expect(sanitizationSpy.mock.calls).toMatchObject([
[
{
title: 'Batman begins',
language: 'es',
},
{
name: 'template_test',
},
],
[
{
title: 'Batman begins',
language: 'en',
},
{
name: 'template_test',
},
],
[
{
title: 'Batman Goes On',
language: 'en',
},
{
name: 'entityGetTestTemplate',
},
],
]);

sanitizationSpy.mockRestore();
});
});

describe('updateMetadataProperties', () => {
let currentTemplate;
beforeEach(() => {
Expand Down Expand Up @@ -1508,7 +1413,7 @@ describe('entities', () => {
});

it('should duplicate all the entities from the default language to the new one', async () => {
await entities.saveMultiple([{ _id: docId1, file: {} }]);
await entitiesModel.save({ _id: docId1, file: {} });

await entities.addLanguage('ab', 2);
const newEntities = await entities.get({ language: 'ab' }, '+permissions');
Expand Down
2 changes: 1 addition & 1 deletion app/api/i18n/specs/routes.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'isomorphic-fetch';
import 'cross-fetch/polyfill';
import request from 'supertest';
import waitForExpect from 'wait-for-expect';

Expand Down
4 changes: 1 addition & 3 deletions app/api/log/infoFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ const addTenant = (info: any, { instanceName }: { instanceName: string }) => {

const formatInfo = (info: any) => {
const message = info.message && info.message.join ? info.message.join('\n') : info.message;
return `${info.timestamp} [${info.tenant}] ${message}${
info.tenantError ? `\n[Tenant error] ${info.tenantError}` : ''
}`;
return `${info.timestamp} [${info.tenant}] ${message}${info.tenantError ? `\n[Tenant error] ${info.tenantError}` : ''}`;
};

const jsonFormatter = (info: { [k: string]: string }) =>
Expand Down
25 changes: 20 additions & 5 deletions app/api/permissions/entitiesPermissions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { WithId } from 'mongodb';

import { model as entityModel } from 'api/entities';
import entities from 'api/entities/entities';
import { search } from 'api/search';
import users from 'api/users/users';
import userGroups from 'api/usergroups/userGroups';
import { unique } from 'api/utils/filters';
Expand All @@ -15,6 +19,8 @@ import { ObjectIdSchema } from 'shared/types/commonTypes';
import { permissionsContext } from './permissionsContext';
import { PUBLIC_PERMISSION } from './publicPermission';

type PermissionUpdate = WithId<Pick<EntitySchema, '_id' | 'permissions' | 'published'>>;

const setAdditionalData = (
referencedList: { _id: ObjectIdSchema }[],
permission: PermissionSchema,
Expand Down Expand Up @@ -75,21 +81,30 @@ const publishingChanged = (newPublishedValue: boolean, currentEntities: EntitySc
false
);

const replaceMixedAccess = (entity: EntitySchema, newPermissions: PermissionSchema[]) =>
const replaceMixedAccess = (
entity: EntitySchema,
newPermissions: PermissionSchema[]
): PermissionSchema[] =>
newPermissions
.map(newPermission => {
if (newPermission.level !== MixedAccess.MIXED) return newPermission;

return entity.permissions?.find(p => p.refId.toString() === newPermission.refId.toString());
})
.filter(p => p);
.filter(p => p) as PermissionSchema[];

const getPublishingQuery = (newPublicPermission?: PermissionSchema) => {
if (newPublicPermission && newPublicPermission.level === MixedAccess.MIXED) return {};

return { published: !!newPublicPermission };
};

async function saveEntities(updates: PermissionUpdate[]) {
const response = await entityModel.saveMultiple(updates);
await search.indexEntities({ _id: { $in: response.map(d => d._id) } }, '+fullText');
return response;
}

export const entitiesPermissions = {
set: async (permissionsData: PermissionsDataSchema) => {
await validateUniquePermissions(permissionsData);
Expand All @@ -116,13 +131,13 @@ export const entitiesPermissions = {
throw new Error('Insuficient permissions to share/unshare publicly');
}

const toSave = currentEntities.map(entity => ({
_id: entity._id,
const toSave: PermissionUpdate[] = currentEntities.map(entity => ({
_id: entity._id!,
permissions: replaceMixedAccess(entity, nonPublicPermissions),
...getPublishingQuery(publicPermission),
}));

await entities.saveMultiple(toSave);
await saveEntities(toSave);
},

get: async (sharedIds: string[]) => {
Expand Down
46 changes: 37 additions & 9 deletions app/api/permissions/specs/entitiesPermissions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { testingDB } from 'api/utils/testing_db';
import entities from 'api/entities/entities';
import { entitiesPermissions } from 'api/permissions/entitiesPermissions';
import { AccessLevels, PermissionType, MixedAccess } from 'shared/types/permissionSchema';
import { search } from 'api/search';
import { fixtures, groupA, userA, userB } from 'api/permissions/specs/fixtures';
import { EntityWithFilesSchema } from 'shared/types/entityType';
import { EntitySchema, EntityWithFilesSchema } from 'shared/types/entityType';
import { PermissionsDataSchema } from 'shared/types/permissionType';
import { UserInContextMockFactory } from 'api/utils/testingUserInContext';
import { PUBLIC_PERMISSION } from '../publicPermission';
Expand Down Expand Up @@ -32,7 +33,15 @@ describe('permissions', () => {
});

describe('set entities permissions', () => {
it('should update the specified entities with the passed permissions in all entities languages', async () => {
it('should update the specified entities with the passed permissions in all entities languages and make no other changes', async () => {
const originalEntities = await entities.getUnrestricted({}, 'sharedId +permissions');
const originalUpdatedEntities = originalEntities.filter(entity =>
['shared1', 'shared2'].includes(entity.sharedId!)
);
const originalNotUpdatedEntities = originalEntities.filter(
entity => !['shared1', 'shared2'].includes(entity.sharedId!)
);

const permissionsData: PermissionsDataSchema = {
ids: ['shared1', 'shared2'],
permissions: [
Expand All @@ -47,17 +56,20 @@ describe('permissions', () => {
const updateEntities = storedEntities.filter(entity =>
['shared1', 'shared2'].includes(entity.sharedId!)
);
updateEntities.forEach(entity => {
expect(entity.permissions).toEqual(
permissionsData.permissions.filter(p => p.type !== PermissionType.PUBLIC)
);
const expectedNewPermissions = permissionsData.permissions.filter(
p => p.type !== PermissionType.PUBLIC
);
updateEntities.forEach((entity, index) => {
const original = originalUpdatedEntities[index];
expect(entity).toEqual({
...original,
permissions: expectedNewPermissions,
});
});
const notUpdatedEntities = storedEntities.filter(
entity => !['shared1', 'shared2'].includes(entity.sharedId!)
);
notUpdatedEntities.forEach(entity => {
expect(entity.permissions).toBe(undefined);
});
expect(notUpdatedEntities).toEqual(originalNotUpdatedEntities);
});

it('should invalidate if permissions are duplicated', async () => {
Expand Down Expand Up @@ -130,6 +142,22 @@ describe('permissions', () => {
expect(storedEntities[2].published).toBe(false);
});

it('should reindex the entities after updating the permissions', async () => {
const indexEntitiesSpy = jest.spyOn(search, 'indexEntities');

const permissionsData: PermissionsDataSchema = {
ids: ['shared1'],
permissions: [publicPermission],
};

await entitiesPermissions.set(permissionsData);
const storedEntities = (await entities.get({ sharedId: 'shared1' })) as EntitySchema[];
const ids = storedEntities.map(entity => entity._id);
expect(indexEntitiesSpy).toHaveBeenCalledWith({ _id: { $in: ids } }, '+fullText');

indexEntitiesSpy.mockRestore();
});

describe('share publicly', () => {
it('should save the entity with the publish field set to the correct value', async () => {
const permissionsData: PermissionsDataSchema = {
Expand Down
12 changes: 12 additions & 0 deletions app/api/permissions/specs/fixtures.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { getFixturesFactory } from 'api/utils/fixturesFactory';
import db, { DBFixture } from 'api/utils/testing_db';
import { AccessLevels, PermissionType } from 'shared/types/permissionSchema';
import { UserRole } from 'shared/types/userSchema';

const factory = getFixturesFactory();

const idUserA = db.id();
const idUserB = db.id();
const idGroupA = db.id();
Expand Down Expand Up @@ -36,6 +39,8 @@ const groupB = {

const entity1 = {
sharedId: 'shared1',
template: factory.id('template'),
metadata: { text: [{ value: 'one' }] },
type: 'entity',
language: 'en',
title: 'Entity 1',
Expand All @@ -60,6 +65,8 @@ const entity1 = {
};
const entity2 = {
sharedId: 'shared2',
template: factory.id('template'),
metadata: { text: [{ value: 'two' }] },
type: 'entity',
language: 'en',
title: 'Entity 2',
Expand All @@ -86,6 +93,8 @@ const entity2 = {

const entity3 = {
sharedId: 'shared3',
metadata: { text: [{ value: 'three' }] },
template: factory.id('template'),
type: 'entity',
language: 'en',
title: 'Entity 3',
Expand All @@ -95,6 +104,8 @@ const entity3 = {

const entity4 = {
sharedId: 'shared4',
metadata: { text: [{ value: 'four' }] },
template: factory.id('template'),
type: 'entity',
language: 'en',
title: 'Entity 4',
Expand All @@ -103,6 +114,7 @@ const entity4 = {
};

const fixtures: DBFixture = {
templates: [factory.template('template', [factory.property('text', 'text')])],
entities: [
{
...entity1,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { attachmentsPath, setupTestUploadedPaths } from 'api/files';
import { testingEnvironment } from 'api/utils/testingEnvironment';
import backend from 'fetch-mock';
import 'isomorphic-fetch';
import 'cross-fetch/polyfill';
// eslint-disable-next-line node/no-restricted-import
import { tenants } from 'api/tenants';
// eslint-disable-next-line node/no-restricted-import
Expand Down
5 changes: 5 additions & 0 deletions app/api/suggestions/pipelineStages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const filterFragments = {
},
nonLabeled: {
_fragment: { 'state.labeled': false },
withSuggestion: { 'state.labeled': false, 'state.withSuggestion': true },
noSuggestion: { 'state.labeled': false, 'state.withSuggestion': false },
noContext: { 'state.labeled': false, 'state.hasContext': false },
obsolete: { 'state.labeled': false, 'state.obsolete': true },
Expand All @@ -37,6 +38,10 @@ export const translateCustomFilter = (customFilter: SuggestionCustomFilter) => {
orFilters.push(filterFragments.labeled.mismatch);
}

if (customFilter.nonLabeled.withSuggestion) {
orFilters.push(filterFragments.nonLabeled.withSuggestion);
}

if (customFilter.nonLabeled.noSuggestion) {
orFilters.push(filterFragments.nonLabeled.noSuggestion);
}
Expand Down
Loading

0 comments on commit e3129cb

Please sign in to comment.