Skip to content

Commit

Permalink
version 1.30.0
Browse files Browse the repository at this point in the history
  • Loading branch information
daneryl committed May 24, 2021
2 parents 16f4cdf + 1255f54 commit ae14cef
Show file tree
Hide file tree
Showing 292 changed files with 10,677 additions and 2,936 deletions.
7 changes: 7 additions & 0 deletions app/api/activitylog/activitylogParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,13 @@ const entryValues: { [key: string]: EntryValue } = {
method: Methods.Delete,
nameField: '_id',
},
'POST/api/entities/permissions': {
desc: 'Updated permissions on entity',
method: Methods.Update,
related: helpers.loadPermissionsData,
nameFunc: helpers.entitiesNames,
extra: helpers.loadAllowedUsersAndGroups,
},
};

const getSemanticData = async (data: any) => {
Expand Down
56 changes: 52 additions & 4 deletions app/api/activitylog/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { allLanguages } from 'shared/languagesList';
import { typeParsers } from 'api/activitylog/migrationsParser';
import templates from 'api/templates/templates';
import entities from 'api/entities/entities';
import users from 'api/users/users';
import userGroups from 'api/usergroups/userGroups';
import { files } from 'api/files';
import { PermissionType } from 'shared/types/permissionSchema';

export const formatLanguage = langKey => {
const lang = allLanguages.find(({ key }) => key === langKey);
Expand Down Expand Up @@ -43,7 +46,7 @@ export const loadEntity = async data => {
const _id = data.entityId || data._id;
const sharedId = data.sharedId || data.entity;
const query = { ...(_id && { _id }), ...(sharedId && { sharedId }) };
const [entity] = await entities.get(query);
const [entity] = await entities.getUnrestricted(query);
return { ...data, entity, title: entity ? entity.title : undefined };
};

Expand All @@ -66,9 +69,6 @@ export const extraAttachmentLanguage = data =>
)} version`
: null;

export const searchName = data =>
data.search ? `${data.search.searchTerm} (${data.searchId})` : data.searchId;

export const updatedFile = data => {
let name;
if (data.toc) {
Expand All @@ -83,3 +83,51 @@ export const groupMembers = data => {
const members = data.members.map(member => member.username).join(', ');
return members.length > 0 ? `with members: ${members}` : 'with no members';
};

export const loadPermissionsData = async data => {
const updateEntities = await entities.getUnrestricted(
{ sharedId: { $in: data.ids } },
{ title: 1 }
);
const permissionsIds = data.permissions
.filter(p => p.type !== PermissionType.PUBLIC)
.map(pu => pu.refId);
const allowedUsers = await users.get({ _id: { $in: permissionsIds } }, { username: 1 });
const allowedGroups = await userGroups.get(
{ _id: { $in: permissionsIds } },
{ name: 1, members: 1 }
);
const publicPermission = !!data.permissions.find(p => p.type === PermissionType.PUBLIC);

return {
...data,
entities: updateEntities,
users: allowedUsers,
userGroups: allowedGroups,
public: publicPermission,
};
};

export const entitiesNames = data => data.entities.map(e => e.title).join(', ');

function getNameOfAllowedPeople(source, field) {
return p => {
const people = source.find(u => u._id.toString() === p.refId);
return `${people && people[field] ? people[field] : p.refId} - ${p.level}`;
};
}

export const loadAllowedUsersAndGroups = data => {
const usersPermissions = data.permissions.filter(p => p.type === PermissionType.USER);
const groupsPermissions = data.permissions.filter(p => p.type === PermissionType.GROUP);
const grantedUsers = usersPermissions
.map(getNameOfAllowedPeople(data.users, 'username'))
.join(', ');
const grantedNames = groupsPermissions
.map(getNameOfAllowedPeople(data.userGroups, 'name'))
.join(', ');

return ` with permissions for${grantedUsers.length ? ` USERS: ${grantedUsers};` : ''}${
grantedNames.length ? ` GROUPS: ${grantedNames}` : ''
}${data.public ? '; PUBLIC' : ''}`;
};
30 changes: 29 additions & 1 deletion app/api/activitylog/specs/activitylogParser.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* eslint-disable max-statements */

import db from 'api/utils/testing_db';
import { fileId } from 'api/activitylog/specs/fixturesParser';
import { fileId, groupId, userId } from 'api/activitylog/specs/fixturesParser';
import fixtures, {
firstTemplate,
firstDoc,
Expand Down Expand Up @@ -1002,6 +1002,34 @@ describe('Activitylog Parser', () => {
});
});
});

describe('routes: /api/entities/permissions', () => {
describe('method: POST /api/entities/permissions', () => {
it('should beautify as UPDATE with entities names and permissions as extra data', async () => {
await testBeautified(
{
method: 'POST',
url: '/api/entities/permissions',
body: JSON.stringify({
ids: [firstDocSharedId],
permissions: [
{ refId: groupId, type: 'group', level: 'read' },
{ refId: userId, type: 'user', level: 'write' },
{ refId: 'public', type: 'public', level: 'read' },
],
}),
},
{
action: 'UPDATE',
description: 'Updated permissions on entity',
name: 'My Doc',
extra: ' with permissions for USERS: User 1 - write; GROUPS: Group 1 - read; PUBLIC',
}
);
});
});
});

describe('MIGRATIONS logs', () => {
afterEach(() => {
jest.resetAllMocks();
Expand Down
27 changes: 26 additions & 1 deletion app/api/activitylog/specs/fixturesParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const firstDocSharedId = 'doc1';
const firstSemanticSearch = db.id();
const nonExistentId = db.id();
const fileId = db.id();
const userId = db.id();
const groupId = db.id();

export default {
activitylogs: [
Expand Down Expand Up @@ -40,6 +42,29 @@ export default {
],

semanticsearches: [{ _id: firstSemanticSearch, searchTerm: 'foo' }],

users: [
{
_id: userId,
username: 'User 1',
},
],
usergroups: [
{
_id: groupId,
name: 'Group 1',
members: [{ refId: userId }],
},
],
};

export { firstTemplate, firstDoc, firstDocSharedId, firstSemanticSearch, nonExistentId, fileId };
export {
firstTemplate,
firstDoc,
firstDocSharedId,
firstSemanticSearch,
nonExistentId,
fileId,
userId,
groupId,
};
2 changes: 2 additions & 0 deletions app/api/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default (app, server) => {
require('./templates/routes').default(app);
require('./search/deprecatedRoutes').default(app);
require('./search/routes').default(app);
require('./search.v2/routes').searchRoutes(app);
require('./topicclassification/routes').default(app);
require('./thesauri/routes').default(app);
require('./relationtypes/routes').default(app);
Expand All @@ -36,4 +37,5 @@ export default (app, server) => {
require('./swagger/swaggerconfig').default(app);
require('./tasks/routes').default(app);
require('./usergroups/routes').default(app);
require('./permissions/routes').permissionRoutes(app);
};
9 changes: 5 additions & 4 deletions app/api/auth/passport_conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import passport from 'passport';
import LocalStrategy from 'passport-local';
import users from 'api/users/users';
import { tenants } from 'api/tenants/tenantContext';
import { appContext } from 'api/utils/AppContext';

const getDomain = req => `${req.protocol}://${req.get('host')}`;

Expand All @@ -25,14 +26,14 @@ passport.serializeUser((user, done) => {
done(null, `${user._id}///${tenants.current().name}`);
});

passport.deserializeUser((serializeUser, done) => {
passport.deserializeUser(async (serializeUser, done) => {
const currentTenant = tenants.current().name;
const [id, serializedTenant] = serializeUser.split('///');
if (serializedTenant !== currentTenant) {
return done(null, false);
}

users.getById(id, '-password').then(user => {
done(null, user);
});
const user = await users.getById(id, '-password', true);
appContext.set('user', user);
done(null, user);
});
3 changes: 2 additions & 1 deletion app/api/auth/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ export default app => {

app.get('/api/captcha', cors(corsOptions), async (_req, res) => {
const captcha = svgCaptcha.create({ ignoreChars: '0OoiILluvUV' });
const storedCaptcha = await CaptchaModel.save({ text: captcha.text });
const text = process.env.DATABASE_NAME !== 'uwazi_e2e' ? captcha.text : '42hf';
const storedCaptcha = await CaptchaModel.save({ text });

res.json({ svg: captcha.data, id: storedCaptcha._id.toString() });
});
Expand Down
4 changes: 2 additions & 2 deletions app/api/auth2fa/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { validation } from 'api/utils';
export default (app: Application) => {
app.post(
'/api/auth2fa-secret',
needsAuthorization(['admin', 'editor']),
needsAuthorization(['admin', 'editor', 'collaborator']),
validation.validateRequest(Joi.object().keys({})),
async (req, res, next) => {
try {
Expand All @@ -21,7 +21,7 @@ export default (app: Application) => {

app.post(
'/api/auth2fa-enable',
needsAuthorization(['admin', 'editor']),
needsAuthorization(['admin', 'editor', 'collaborator']),
validation.validateRequest(
Joi.object()
.keys({ token: Joi.string().required() })
Expand Down
9 changes: 6 additions & 3 deletions app/api/csv/importEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,23 @@ import { ImportFile } from 'api/csv/importFile';
import { EntitySchema } from 'shared/types/entityType';
import { ensure } from 'shared/tsUtils';

import typeParsers from './typeParsers';
import { attachmentsPath, files } from 'api/files';
import typeParsers from './typeParsers';

const parse = async (toImportEntity: RawEntity, prop: PropertySchema) =>
typeParsers[prop.type]
? typeParsers[prop.type](toImportEntity, prop)
: typeParsers.text(toImportEntity, prop);

const hasValidValue = (prop: PropertySchema, toImportEntity: RawEntity) =>
prop.name ? toImportEntity[prop.name] || prop.type === 'generatedid' : false;

const toMetadata = async (
template: TemplateSchema,
toImportEntity: RawEntity
): Promise<MetadataSchema> =>
(template.properties || [])
.filter(prop => (prop.name ? toImportEntity[prop.name] : false))
.filter(prop => hasValidValue(prop, toImportEntity))
.reduce<Promise<MetadataSchema>>(
async (meta, prop) =>
({
Expand Down Expand Up @@ -57,7 +60,7 @@ const importEntity = async (
importFile: ImportFile,
{ user = {}, language }: Options
) => {
const attachments = toImportEntity.attachments;
const { attachments } = toImportEntity;
delete toImportEntity.attachments;
const eo = await entityObject(toImportEntity, template, { language });
const entity = await entities.save(eo, { user, language }, true, false);
Expand Down
8 changes: 4 additions & 4 deletions app/api/csv/specs/__snapshots__/importFile.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`importFile readStream should return a readable stream for the csv file 1`] = `
"Title , text label , numeric label, non configured, select label, not defined type, geolocation_geolocation
"Title , text label , numeric label, non configured, select label, not defined type, geolocation_geolocation,auto id
title1, text value 1, 1977, ______________, thesauri1 , notType1 , 1|1,
title2, text value 2, 2019, ______________, thesauri2 , notType2 , ,
title3, text value 3, 2020, ______________, thesauri2 , notType3 , 0|0,
title1, text value 1, 1977, ______________, thesauri1 , notType1 , 1|1,,
title2, text value 2, 2019, ______________, thesauri2 , notType2 , ,,
title3, text value 3, 2020, ______________, thesauri2 , notType3 , 0|0,,
"
`;

Expand Down
12 changes: 10 additions & 2 deletions app/api/csv/specs/csvLoader.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import path from 'path';
import translations from 'api/i18n';
import { search } from 'api/search';

import { CSVLoader } from '../csvLoader';
import { CSVLoader } from 'api/csv';
import fixtures, { template1Id } from './fixtures';
import { stream } from './helpers';
import typeParsers from '../typeParsers';
Expand Down Expand Up @@ -64,9 +64,18 @@ describe('csvLoader', () => {
'select_label',
'not_defined_type',
'geolocation_geolocation',
'auto_id',
]);
});

it('should generate an id when the template has a property with generatedid type', () => {
expect(imported[0].metadata).toEqual(
expect.objectContaining({
auto_id: [{ value: expect.stringMatching(/^[a-zA-Z0-9-]{12}$/) }],
})
);
});

it('should ignore properties not configured in the template', () => {
const textValues = imported.map(i => i.metadata.non_configured).filter(i => i);

Expand Down Expand Up @@ -195,7 +204,6 @@ describe('csvLoader', () => {

describe('when sharedId is provided', () => {
it('should update the entitiy', async () => {
entities.save.mockRestore();
const entity = await entities.save(
{ title: 'entity4444', template: template1Id },
{ user: {}, language: 'en' }
Expand Down
5 changes: 5 additions & 0 deletions app/api/csv/specs/fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ export default {
label: 'geolocation',
name: templateUtils.safeName('geolocation_geolocation'),
},
{
type: propertyTypes.generatedid,
label: 'Auto ID',
name: templateUtils.safeName('auto id'),
},
],
},
],
Expand Down
8 changes: 4 additions & 4 deletions app/api/csv/specs/test.csv
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Title , text label , numeric label, non configured, select label, not defined type, geolocation_geolocation
Title , text label , numeric label, non configured, select label, not defined type, geolocation_geolocation,auto id

title1, text value 1, 1977, ______________, thesauri1 , notType1 , 1|1,
title2, text value 2, 2019, ______________, thesauri2 , notType2 , ,
title3, text value 3, 2020, ______________, thesauri2 , notType3 , 0|0,
title1, text value 1, 1977, ______________, thesauri1 , notType1 , 1|1,,
title2, text value 2, 2019, ______________, thesauri2 , notType2 , ,,
title3, text value 3, 2020, ______________, thesauri2 , notType3 , 0|0,,
3 changes: 2 additions & 1 deletion app/api/csv/typeParsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { RawEntity } from 'api/csv/entityRow';
import { PropertySchema, MetadataObjectSchema } from 'shared/types/commonTypes';
import { ensure } from 'shared/tsUtils';

import generatedid from './typeParsers/generatedid';
import geolocation from './typeParsers/geolocation';
import multiselect from './typeParsers/multiselect';
import select from './typeParsers/select';
Expand All @@ -24,7 +25,7 @@ export default {
media: defaultParser,
markdown: defaultParser,
text: defaultParser,

generatedid,
geolocation,
select,
multiselect,
Expand Down
14 changes: 14 additions & 0 deletions app/api/csv/typeParsers/generatedid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { RawEntity } from 'api/csv/entityRow';
import { MetadataObjectSchema, PropertySchema } from 'shared/types/commonTypes';
import { ensure } from 'shared/tsUtils';
import { generateID } from 'shared/IDGenerator';

const generatedid = async (
entityToImport: RawEntity,
property: PropertySchema
): Promise<MetadataObjectSchema[]> => {
const value = entityToImport[ensure<string>(property.name)] || generateID(3, 4, 4);
return [{ value }];
};

export default generatedid;
Loading

0 comments on commit ae14cef

Please sign in to comment.