Skip to content
Commits on Source (92)
......@@ -2,7 +2,6 @@ import { Mongo } from 'meteor/mongo';
import SimpleSchema from 'simpl-schema';
import moment from 'moment';
import { getLabel } from '../utils';
import RegEx from '../regExp';
const AnalyticsEvents = new Mongo.Collection('analytics');
......@@ -43,7 +42,7 @@ AnalyticsEvents.schema = new SimpleSchema({
defaultValue: 0,
},
structureId: {
type: RegEx.Id,
type: String,
label: getLabel('api.analytics.labels.structure'),
optional: true,
index: true,
......
......@@ -796,7 +796,7 @@ if (Meteor.isServer) {
}
});
Meteor.afterMethod('groups.removeGroup', function kcRemoveGroup({ groupId }) {
Meteor.afterMethod('groups.groupRemoved', function kcRemoveGroup({ groupId }) {
if (!this.error) {
const groupData = this.result;
if (groupData) {
......@@ -855,7 +855,7 @@ if (Meteor.isServer) {
}
});
Meteor.afterMethod('users.unsetAnimatorOf', function kcUnsetAnimator({ userId, groupId }) {
Meteor.afterMethod('users.animatorOfUnset', function kcUnsetAnimator({ userId, groupId }) {
if (!this.error) {
if (!Roles.userIsInRole(userId, 'member', groupId)) {
const group = Groups.findOne({ _id: groupId });
......@@ -873,7 +873,7 @@ if (Meteor.isServer) {
}
});
Meteor.afterMethod('users.unsetMemberOf', function kcUnsetMember({ userId, groupId }) {
Meteor.afterMethod('users.memberOfUnset', function kcUnsetMember({ userId, groupId }) {
if (!this.error) {
if (!Roles.userIsInRole(userId, 'animator', groupId)) {
const group = Groups.findOne({ _id: groupId });
......
......@@ -26,7 +26,7 @@ function checkResponse(response) {
function logError(error, action, callerId) {
logServer(`APPCLIENT - NEXTCLOUD - ApiError - ${action}`, levels.ERROR, scopes.SYSTEM, {
error: error.error,
error: error.reason || error.message,
callerId,
});
}
......@@ -602,7 +602,7 @@ export default class NextcloudClient {
}
logServer(
`APPCLIENT - NEXTCLOUD - addUser - ${i18n.__('api.nextcloud.userAlreadyExists', { username: user.username })}`,
levels.INFO,
levels.VERBOSE,
scopes.SYSTEM,
{
username: user.username,
......@@ -669,12 +669,12 @@ if (Meteor.isServer && nextcloudPlugin && nextcloudPlugin.enable) {
}
if (circleId) {
try {
nextClient.inviteMembers(group, circleId, this.userId);
await nextClient.inviteMembers(group, circleId, this.userId);
} catch (error) {
logError(error, 'createGroup.inviteMembers', this.userId);
}
try {
nextClient.ensureShare(group, circleId, this.userId);
await nextClient.ensureShare(group, circleId, this.userId);
} catch (error) {
logError(error, 'createGroup.ensureShare', this.userId);
}
......@@ -683,7 +683,7 @@ if (Meteor.isServer && nextcloudPlugin && nextcloudPlugin.enable) {
}
});
Meteor.afterMethod('groups.removeGroup', function nextRemoveGroup({ groupId }) {
Meteor.afterMethod('groups.groupRemoved', async function nextRemoveGroup({ groupId }) {
if (!this.error) {
const groupData = this.result;
const isAdmin = isActive(this.userId) && Roles.userIsInRole(this.userId, 'admin', groupId);
......@@ -691,12 +691,12 @@ if (Meteor.isServer && nextcloudPlugin && nextcloudPlugin.enable) {
if (groupData.plugins.nextcloud === true) {
// remove circle and share folder group from nextcloud
try {
nextClient.deleteCircle(groupData, this.userId);
await nextClient.deleteCircle(groupData, this.userId);
} catch (error) {
logError(error, 'removeGroup.deleteCircle', this.userId);
}
try {
nextClient.deleteFolder(groupData, this.userId);
await nextClient.deleteFolder(groupData, this.userId);
} catch (error) {
logError(error, 'removeGroup.deleteFolder', this.userId);
}
......@@ -719,12 +719,12 @@ if (Meteor.isServer && nextcloudPlugin && nextcloudPlugin.enable) {
if (circleId) {
// add all group members to circle
try {
nextClient.inviteMembers(group, circleId, this.userId);
await nextClient.inviteMembers(group, circleId, this.userId);
} catch (error) {
logError(error, 'updateGroup.inviteMembers', this.userId);
}
try {
nextClient.ensureShare(group, circleId, this.userId);
await nextClient.ensureShare(group, circleId, this.userId);
} catch (error) {
logError(error, 'updateGroup.ensureShare', this.userId);
}
......@@ -732,12 +732,12 @@ if (Meteor.isServer && nextcloudPlugin && nextcloudPlugin.enable) {
} else if (group.plugins.nextcloud === false && group.circleId) {
// remove circle and share from nextcloud
try {
nextClient.deleteCircle(group, this.userId);
await nextClient.deleteCircle(group, this.userId);
} catch (error) {
logError(error, 'updateGroup.deleteCircle', this.userId);
}
try {
nextClient.deleteFolder(group, this.userId);
await nextClient.deleteFolder(group, this.userId);
} catch (error) {
logError(error, 'updateGroup.deleteFolder', this.userId);
}
......@@ -745,13 +745,13 @@ if (Meteor.isServer && nextcloudPlugin && nextcloudPlugin.enable) {
}
});
Meteor.afterMethod('users.memberOfSet', function nextSetMember({ userId, groupId }) {
Meteor.afterMethod('users.memberOfSet', async function nextSetMember({ userId, groupId }) {
if (!this.error) {
// invite user to group circle if needed
const group = Groups.findOne({ _id: groupId });
if (group.plugins.nextcloud === true) {
try {
nextClient.inviteUser(userId, group, this.userId);
await nextClient.inviteUser(userId, group, this.userId);
} catch (error) {
logError(error, 'setMemberOf.inviteUser', this.userId);
}
......@@ -759,14 +759,14 @@ if (Meteor.isServer && nextcloudPlugin && nextcloudPlugin.enable) {
}
});
Meteor.afterMethod('users.unsetMemberOf', function nextUnsetMember({ userId, groupId }) {
Meteor.afterMethod('users.unsetMemberOf', async function nextUnsetMember({ userId, groupId }) {
if (!this.error) {
// remove user from circle if needed
const group = Groups.findOne({ _id: groupId });
if (group.plugins.nextcloud === true) {
if (!group.animators.includes(userId)) {
try {
nextClient.kickUser(userId, group, this.userId);
await nextClient.kickUser(userId, group, this.userId);
} catch (error) {
logError(error, 'unsetMemberOf.kickUser', this.userId);
}
......@@ -775,13 +775,13 @@ if (Meteor.isServer && nextcloudPlugin && nextcloudPlugin.enable) {
}
});
Meteor.afterMethod('users.animatorOfSet', function nextSetAnimator({ userId, groupId }) {
Meteor.afterMethod('users.animatorOfSet', async function nextSetAnimator({ userId, groupId }) {
if (!this.error) {
// invite user to group circle if needed
const group = Groups.findOne({ _id: groupId });
if (group.plugins.nextcloud === true) {
try {
nextClient.inviteUser(userId, group, this.userId);
await nextClient.inviteUser(userId, group, this.userId);
} catch (error) {
logError(error, 'setAnimatorOf.inviteUser', this.userId);
}
......@@ -789,14 +789,14 @@ if (Meteor.isServer && nextcloudPlugin && nextcloudPlugin.enable) {
}
});
Meteor.afterMethod('users.unsetAnimatorOf', function nextUnsetAnimator({ userId, groupId }) {
Meteor.afterMethod('users.unsetAnimatorOf', async function nextUnsetAnimator({ userId, groupId }) {
if (!this.error) {
// invite user from circle if needed
const group = Groups.findOne({ _id: groupId });
if (group.plugins.nextcloud === true) {
if (!group.members.includes(userId)) {
try {
nextClient.kickUser(userId, group, this.userId);
await nextClient.kickUser(userId, group, this.userId);
} catch (error) {
logError(error, 'unsetAnimatorOf.kickUser', this.userId);
}
......@@ -805,24 +805,24 @@ if (Meteor.isServer && nextcloudPlugin && nextcloudPlugin.enable) {
}
});
Meteor.afterMethod('users.setActive', function nextAddUser({ userId }) {
Meteor.afterMethod('users.setActive', async function nextAddUser({ userId }) {
if (!this.error) {
// create nextcloud user if needed
// get nclocator for this user
try {
nextClient.addUser(userId, this.userId);
await nextClient.addUser(userId, this.userId);
} catch (error) {
logError(error, 'setActive.addUser', this.userId);
}
}
});
Meteor.afterMethod('users.userUpdated', function rcUserUpdated(params) {
Meteor.afterMethod('users.userUpdated', async function rcUserUpdated(params) {
if (!this.error) {
const { userId, data } = params;
if (data.isActive && data.isActive === true) {
try {
nextClient.addUser(userId, this.userId);
await nextClient.addUser(userId, this.userId);
} catch (error) {
logError(error, 'userUpdated.addUser', this.userId);
}
......
......@@ -797,11 +797,15 @@ if (Meteor.isServer && rcEnabled) {
}
});
Meteor.beforeMethod('groups.removeGroup', function rcRemoveGroup({ groupId }) {
const group = Groups.findOne({ _id: groupId });
if (group.plugins.rocketChat === true) {
const isAdmin = isActive(this.userId) && Roles.userIsInRole(this.userId, 'admin', groupId);
if (isAdmin || this.userId === group.owner) rcClient.removeGroup(group.slug, this.userId);
Meteor.afterMethod('groups.groupRemoved', function rcRemoveGroup({ groupId }) {
if (!this.error) {
const group = this.result;
if (group) {
if (group.plugins.rocketChat === true) {
const isAdmin = isActive(this.userId) && Roles.userIsInRole(this.userId, 'admin', groupId);
if (isAdmin || this.userId === group.owner) rcClient.removeGroup(group.slug, this.userId);
}
}
}
});
......@@ -857,9 +861,8 @@ if (Meteor.isServer && rcEnabled) {
}
});
Meteor.beforeMethod('users.unsetAdminOf', function rcUnsetAdminOf({ userId, groupId }) {
const authorized = isActive(this.userId) && Roles.userIsInRole(this.userId, 'admin', groupId);
if (authorized) {
Meteor.afterMethod('users.adminOfUnset', function rcUnsetAdminOf({ userId, groupId }) {
if (!this.error) {
const group = Groups.findOne({ _id: groupId });
if (group.plugins.rocketChat === true) {
rcClient.ensureUser(userId, this.userId).then((rcUser) => {
......@@ -892,9 +895,8 @@ if (Meteor.isServer && rcEnabled) {
}
});
Meteor.beforeMethod('users.unsetAnimatorOf', function rcUnsetAnimatorOf({ userId, groupId }) {
const authorized = userId === this.userId || Roles.userIsInRole(this.userId, 'admin', groupId);
if (isActive(this.userId) && authorized) {
Meteor.afterMethod('users.animatorOfUnset', function rcUnsetAnimatorOf({ userId, groupId }) {
if (!this.error) {
const group = Groups.findOne({ _id: groupId });
if (group.plugins.rocketChat === true) {
rcClient.ensureUser(userId, this.userId).then((user) => {
......@@ -944,9 +946,8 @@ if (Meteor.isServer && rcEnabled) {
}
});
Meteor.beforeMethod('users.unsetMemberOf', function rcUnsetMemberOf({ userId, groupId }) {
const authorized = userId === this.userId || Roles.userIsInRole(this.userId, ['admin', 'animator'], groupId);
if (isActive(this.userId) && authorized) {
Meteor.afterMethod('users.memberOfUnset', function rcUnsetMemberOf({ userId, groupId }) {
if (!this.error) {
const group = Groups.findOne({ _id: groupId });
if (group.plugins.rocketChat === true) {
if (!Roles.userIsInRole(userId, ['animator', 'admin'], groupId)) {
......
......@@ -4,6 +4,7 @@
import { PublicationCollector } from 'meteor/johanbrook:publication-collector';
import { assert } from 'chai';
import { Meteor } from 'meteor/meteor';
import { Random } from 'meteor/random';
import '../../../startup/i18n/en.i18n.json';
import { faker } from '@faker-js/faker';
import { Factory } from 'meteor/dburles:factory';
......@@ -242,7 +243,7 @@ describe('appsettings', function () {
email,
username: email,
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
});
......@@ -251,7 +252,7 @@ describe('appsettings', function () {
email: emailAdmin,
username: emailAdmin,
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
});
......
......@@ -120,7 +120,7 @@ describe('articles', function () {
username: 'randomguy',
password: 'toto',
email: faker.internet.email(),
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
groupCount: 0,
......@@ -130,7 +130,7 @@ describe('articles', function () {
email: faker.internet.email(),
username: 'admin',
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
groupCount: 0,
......@@ -140,7 +140,7 @@ describe('articles', function () {
email: faker.internet.email(),
username: 'member',
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
groupCount: 0,
......@@ -228,7 +228,7 @@ describe('articles', function () {
email,
username: email,
password: 'toto',
structure: `userId_${Random.id()}`,
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
});
......
......@@ -40,7 +40,8 @@ AsamExtensions.schema = new SimpleSchema({
familleNomCourt: { type: String, label: getLabel('api.asamextensions.labels.familleNomCourt') },
familleNomLong: { type: String, label: getLabel('api.asamextensions.labels.familleNomLong') },
structureId: {
type: RegEx.Id,
type: String,
regEx: RegEx.Id,
label: getLabel('api.asamextensions.labels.structureId'),
defaultValue: null,
},
......
......@@ -22,10 +22,12 @@ export const assignStructureToAsam = new ValidatedMethod({
name: 'asam.assignStructureToAsam',
validate: new SimpleSchema({
structureId: {
type: RegEx.Id,
type: String,
regEx: RegEx.Id,
},
extensionId: {
type: RegEx.Id,
type: String,
regEx: RegEx.Id,
},
extension: {
type: String,
......@@ -75,7 +77,7 @@ export const assignStructureToAsam = new ValidatedMethod({
export const unassignStructureToAsam = new ValidatedMethod({
name: 'asam.unassignStructureToAsam',
validate: new SimpleSchema({ extensionId: { type: RegEx.Id } }).validator(),
validate: new SimpleSchema({ extensionId: { type: String, regEx: RegEx.Id } }).validator(),
run({ extensionId }) {
const isAdmin = Roles.userIsInRole(this.userId, 'admin');
if (!isAdmin) {
......@@ -98,7 +100,7 @@ export const unassignStructureToAsam = new ValidatedMethod({
export const deleteAsam = new ValidatedMethod({
name: 'asam.deleteAsam',
validate: new SimpleSchema({ extensionId: { type: RegEx.Id } }).validator(),
validate: new SimpleSchema({ extensionId: { type: String, regEx: RegEx.Id } }).validator(),
run({ extensionId }) {
const isAdmin = Roles.userIsInRole(this.userId, 'admin');
if (!isAdmin) {
......
......@@ -18,7 +18,7 @@ function GetStructure(strucs, parent, index) {
return parent;
}
function CreateASAMFromAPI(asam) {
function CreateRuleFromAPI(asam) {
const strucs = asam.path.split('/');
if (strucs) {
const struc = GetStructure(strucs, null, 0);
......@@ -42,13 +42,13 @@ function CreateASAMFromAPI(asam) {
// curl -X POST -H "X-API-KEY: createuser-password" \
// -H "Content-Type: application/json" \
// -d '[{"extension":"structure1.fr", "path": "api1/api2/api3"}]' \
// http://localhost:3000/api/asams/createmany
// http://localhost:3000/api/structureruledispatchs/createmany
// eslint-disable-next-line spaced-comment
// curl -X POST -H "X-API-KEY: createuser-password" -H "Content-Type: application/json" -d '[{"extension":"api3.fr", "path": "api1 - api2 - api3"}]' http://localhost:3000/api/asams/createmany
export default async function createDomainMails(req, content) {
// curl -X POST -H "X-API-KEY: createuser-password" -H "Content-Type: application/json" -d '[{"extension":"api3.fr", "path": "api1 - api2 - api3"}]' http://localhost:3000/api/structureruledispatchs/createmany
export default async function createStructureRuleDispatch(req, content) {
if (content) {
content.forEach((asam) => {
CreateASAMFromAPI(asam);
CreateRuleFromAPI(asam);
});
return 200;
}
......@@ -60,12 +60,12 @@ export default async function createDomainMails(req, content) {
// curl -X POST -H "X-API-KEY: createuser-password" \
// -H "Content-Type: application/json" \
// -d '{"extension":"structure1.fr", "path": "api1/api2/api3"}' \
// http://localhost:3000/api/asams/create
// http://localhost:3000/api/structureruledispatchs/create
// eslint-disable-next-line spaced-comment
// curl -X POST -H "X-API-KEY: createuser-password" -H "Content-Type: application/json" -d '{"extension":"api3.fr", "path": "api1/api2/api3"}' http://localhost:3000/api/asams/create
export async function createOneDomainMail(req, content) {
// curl -X POST -H "X-API-KEY: createuser-password" -H "Content-Type: application/json" -d '{"extension":"api3.fr", "path": "api1/api2/api3"}' http://localhost:3000/api/structureruledispatchs/create
export async function createOneStructureRuleDispatch(req, content) {
if (content) {
return CreateASAMFromAPI(content);
return CreateRuleFromAPI(content);
}
logServer(`API - ASAM - GET - Invalid or empty content`, levels.ERROR, scopes.SYSTEM);
throw new Meteor.Error('api.createOneDomainMail.emptyContent', 'Empty content');
......@@ -81,31 +81,80 @@ function GeneratePath(structure, tree) {
}
}
function generateStructureRuleDispatchData(asam) {
const struc = Structures.findOne({ _id: asam.structureId });
if (struc) {
const tree = [struc.name];
if (struc.parentId) {
const parent = Structures.findOne({ _id: struc.parentId });
if (parent) {
tree.push(parent.name);
GeneratePath(parent, tree);
}
}
const reversed = tree.reverse();
const obj = { extension: asam.extension, path: reversed.join('/') };
return obj;
}
return null;
}
// sample use:
// curl -X POST -H "X-API-KEY: createuser-password" \
// -H "Content-Type: application/json" \
// -d '{"name":"test" }' \
// http://localhost:3000/api/structureruledispatchs
// curl -X POST -H "X-API-KEY: createuser-password" -H "Content-Type: application/json" -d '{"extension":"test" }' http://localhost:3000/api/structureruledispatchs
export async function getStructureRuleDispatchs(req, content) {
if ('extension' in content) {
const asam = AsamExtensions.findOne({ extension: content.extension });
if (asam) {
const obj = generateStructureRuleDispatchData(asam);
return obj;
}
}
logServer(`API - ASAM - GET - Invalid or empty content`, levels.ERROR, scopes.SYSTEM);
throw new Meteor.Error('api.createOneDomainMail.emptyContent', 'Invalid or empty content');
}
// sample use:
// curl -H "X-API-KEY: createuser-password" http://localhost:3000/api/asams | jq
export async function getDomainMails() {
// curl -H "X-API-KEY: createuser-password" http://localhost:3000/api/structureruledispatchs | jq
export async function getAllStructureRuleDispatchs() {
const res = [];
const asams = AsamExtensions.find().fetch();
if (asams) {
asams.forEach((asam) => {
const struc = Structures.findOne({ _id: asam.structureId });
if (struc) {
const tree = [struc.name];
if (struc.parentId) {
const parent = Structures.findOne({ _id: struc.parentId });
if (parent) {
tree.push(parent.name);
GeneratePath(parent, tree);
}
}
const reversed = tree.reverse();
const obj = { extension: asam.extension, path: reversed.join('/') };
const obj = generateStructureRuleDispatchData(asam);
if (obj) {
res.push(obj);
}
});
} else {
logServer(`API - ASAM - GET - No Domain mail found`, levels.ERROR, scopes.SYSTEM);
return res;
}
logServer(`API - ASAM - GET - No Structure rule dispatch found`, levels.ERROR, scopes.SYSTEM);
throw new Meteor.Error('api.createOneDomainMail.emptyContent', 'No Structure rule dispatch found');
}
// sample use:
// curl -X DELETE -H "X-API-KEY: createuser-password" \
// -H "Content-Type: application/json" \
// -d '{"extension":"structure1.fr"}' \
// http://localhost:3000/api/structureruledispatchs/delete
// eslint-disable-next-line spaced-comment
// curl -X DELETE -H "X-API-KEY: createuser-password" -H "Content-Type: application/json" -d '{"extension":"api3.fr"}' http://localhost:3000/api/structureruledispatchs/delete
export async function deleteStructureRuleDispatch(req, content) {
if (content) {
const asam = AsamExtensions.findOne({ extension: content.extension });
if (asam) {
AsamExtensions.remove({ _id: asam._id });
return 200;
}
logServer(`API - ASAM - DELETE - Structure rule dispatch not found`, levels.ERROR, scopes.SYSTEM);
throw new Meteor.Error('api.deleteDomainMail.emptyContent', 'Structure rule dispatch not found');
}
return res;
logServer(`API - ASAM - DELETE - Invalid or empty content`, levels.ERROR, scopes.SYSTEM);
throw new Meteor.Error('api.deleteDomainMail.emptyContent', 'Empty content');
}
......@@ -53,7 +53,7 @@ export function _createBookmarkUrl(url, name, tag, groupId, author) {
groupId,
author,
});
Bookmarks.insert({ url, name, tag, groupId, author });
return Bookmarks.insert({ url, name, tag, groupId, author });
} catch (error) {
if (error.code === 11000) {
logServer(
......@@ -77,9 +77,19 @@ export function _createBookmarkUrl(url, name, tag, groupId, author) {
export const createBookmark = new ValidatedMethod({
name: 'bookmark.create',
validate: Bookmarks.schema.omit('author', 'icon').validator({ clean: true }),
validate: new SimpleSchema({
url: { type: String, label: getLabel('api.bookmarks.labels.url') },
name: { type: String, label: getLabel('api.bookmarks.labels.name') },
tag: { type: String, label: getLabel('api.bookmarks.labels.tag'), defaultValue: '' },
groupId: { type: String, label: getLabel('api.bookmarks.labels.groupId') },
favUserBookmarkDirectry: {
type: Boolean,
label: getLabel('api.users.labels.favUserBookmarks'),
defaultValue: false,
},
}).validator({ clean: true }),
run({ url, name, groupId, tag }) {
run({ url, name, groupId, tag, favUserBookmarkDirectry }) {
const isAllowed =
isActive(this.userId) &&
(Roles.userIsInRole(this.userId, ['member', 'animator', 'admin'], groupId) ||
......@@ -96,7 +106,19 @@ export const createBookmark = new ValidatedMethod({
const finalUrl = _formatURL(url);
_createBookmarkUrl(finalUrl, name, tag, groupId, this.userId);
const bookmarkId = _createBookmarkUrl(finalUrl, name, tag, groupId, this.userId);
if (favUserBookmarkDirectry) {
if (bookmarkId && bookmarkId !== undefined) {
Meteor.users.update(this.userId, {
$push: { favUserBookmarks: bookmarkId },
});
// update user personalSpace
addUserBookmark._execute({ userId: this.userId }, { bookmarkId, type: 'groupLink' });
}
}
return finalUrl;
},
});
......
......@@ -5,6 +5,7 @@ import { assert } from 'chai';
import { Factory } from 'meteor/dburles:factory';
import { PublicationCollector } from 'meteor/johanbrook:publication-collector';
import { Meteor } from 'meteor/meteor';
import { Random } from 'meteor/random';
import '../../../startup/i18n/en.i18n.json';
import { faker } from '@faker-js/faker';
import { Roles } from 'meteor/alanning:roles';
......@@ -35,7 +36,7 @@ describe('bookmarks', function () {
username: 'randomguy',
password: 'toto',
email: faker.internet.email(),
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
groupCount: 0,
......@@ -45,7 +46,7 @@ describe('bookmarks', function () {
email: faker.internet.email(),
username: 'admin',
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
groupCount: 0,
......@@ -55,7 +56,7 @@ describe('bookmarks', function () {
email: faker.internet.email(),
username: 'member',
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
groupCount: 0,
......@@ -132,7 +133,7 @@ describe('bookmarks', function () {
email: emailAdmin,
username: emailAdmin,
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
groupCount: 0,
......@@ -146,7 +147,7 @@ describe('bookmarks', function () {
email: emailGroupAdmin,
username: emailGroupAdmin,
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
groupCount: 0,
......@@ -159,7 +160,7 @@ describe('bookmarks', function () {
email: userGroupEmail,
username: userGroupEmail,
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
groupCount: 0,
......@@ -171,7 +172,7 @@ describe('bookmarks', function () {
username: 'yo',
password: 'toto',
email: faker.internet.email(),
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
nclocator: '',
......
......@@ -61,30 +61,89 @@ export async function createOneBookmark(req, content) {
throw new Meteor.Error('api.createOneBookmark.emptyContent', 'Empty content');
}
function generateDataForBookmark(bookmark) {
const gr = Groups.findOne({ _id: bookmark.groupId });
if (gr) {
const author = Meteor.users.findOne({ _id: bookmark.author });
if (author) {
const obj = {
name: bookmark.name,
tag: bookmark.tag,
group: gr.name,
author: author.username,
url: bookmark.url,
};
return obj;
}
return null;
}
return null;
}
// sample use:
// curl -X POST -H "X-API-KEY: createuser-password" \
// -H "Content-Type: application/json" \
// -d '{"name":"test" }' \
// http://localhost:3000/api/bookmarks
// curl -X POST -H "X-API-KEY: createuser-password" -H "Content-Type: application/json" -d '{"name":"test", "url":"http://test.com" }' http://localhost:3000/api/bookmarks
export async function getBookmarks(req, content) {
if ('name' in content || 'url' in content) {
let bookmark;
if ('name' in content && 'url' in content) {
bookmark = Bookmarks.findOne({ $and: [{ name: content.name }, { url: content.url }] });
} else if ('url' in content) {
bookmark = Bookmarks.findOne({ url: content.url });
} else if ('name' in content) {
bookmark = Bookmarks.findOne({ name: content.name });
}
if (bookmark) {
const obj = generateDataForBookmark(bookmark);
return obj;
}
throw new Meteor.Error('api.createOneBookmark.notFound', 'Bookmark not found');
}
throw new Meteor.Error('api.createOneBookmark.emptyContent', 'Empty or invalid content');
}
// sample use:
// curl -H "X-API-KEY: createuser-password" http://localhost:3000/api/bookmarks | jq
export async function getBookmarks() {
export async function getAllBookmarks() {
const bookmarks = Bookmarks.find().fetch();
const res = [];
if (bookmarks) {
bookmarks.forEach((bookmark) => {
if (bookmark.groupId) {
const gr = Groups.findOne({ _id: bookmark.groupId });
if (gr) {
const author = Meteor.users.findOne({ _id: bookmark.author });
if (author) {
const obj = {
name: bookmark.name,
tag: bookmark.tag,
group: gr.name,
author: author.username,
url: bookmark.url,
};
res.push(obj);
}
const obj = generateDataForBookmark(bookmark);
if (obj) {
res.push(obj);
}
}
});
}
return res;
}
export async function deleteBookmark(req, content) {
// sample use:
// curl -X DELETE -H "X-API-KEY: createuser-password" \
// -H "Content-Type: application/json" \
// -d '{"url":"http://url.com"}',
// http://localhost:3000/api/bookmarks/delete
// eslint-disable-next-line spaced-comment
// curl -X DELETE -H "X-API-KEY: createuser-password" -H "Content-Type: application/json" -d '{"url":"http://url.com"}' http://localhost:3000/api/bookmarks/delete
if (content) {
const bookmark = Bookmarks.findOne({ url: content.url });
if (bookmark) {
Bookmarks.remove({ url: bookmark.url });
return 200;
}
logServer(`API - BOOKMARKS - DELETE - Bookmark not found`, levels.ERROR, scopes.SYSTEM, {
group: bookmark.group,
});
throw new Meteor.Error('api.deleteBookmarks.noFound', 'Bookmark not founds');
}
throw new Meteor.Error('api.deleteBookmarks.emptyContent', 'Empty content');
}
import { Mongo } from 'meteor/mongo';
import SimpleSchema from 'simpl-schema';
import { getLabel } from '../utils';
import RegEx from '../regExp';
const BusinessReGrouping = new Mongo.Collection('BusinessReGrouping');
......@@ -25,7 +24,7 @@ BusinessReGrouping.schema = new SimpleSchema({
label: getLabel('api.businessReGrouping.labels.name'),
},
structure: {
type: RegEx.Id,
type: String,
label: getLabel('api.businessReGrouping.labels.structure'),
defaultValue: '',
},
......
......@@ -4,6 +4,7 @@
import { PublicationCollector } from 'meteor/johanbrook:publication-collector';
import { assert } from 'chai';
import { Meteor } from 'meteor/meteor';
import { Random } from 'meteor/random';
import { _ } from 'meteor/underscore';
import '../../../startup/i18n/en.i18n.json';
import { faker } from '@faker-js/faker';
......@@ -34,7 +35,7 @@ describe('businessReGrouping', function () {
email,
username: email,
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
});
......@@ -73,7 +74,7 @@ describe('businessReGrouping', function () {
email,
username: email,
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
});
......@@ -82,7 +83,7 @@ describe('businessReGrouping', function () {
email: emailAdmin,
username: emailAdmin,
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
});
......
......@@ -4,6 +4,7 @@
import { PublicationCollector } from 'meteor/johanbrook:publication-collector';
import { assert } from 'chai';
import { Meteor } from 'meteor/meteor';
import { Random } from 'meteor/random';
import { _ } from 'meteor/underscore';
import '../../../startup/i18n/en.i18n.json';
import { faker } from '@faker-js/faker';
......@@ -34,7 +35,7 @@ describe('categories', function () {
email,
username: email,
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
});
......@@ -71,7 +72,7 @@ describe('categories', function () {
email,
username: email,
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
});
......@@ -80,7 +81,7 @@ describe('categories', function () {
email: emailAdmin,
username: emailAdmin,
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
});
......
import { Mongo } from 'meteor/mongo';
import SimpleSchema from 'simpl-schema';
import { Tracker } from 'meteor/tracker';
const ContextSettings = new Mongo.Collection('contextsettings');
......@@ -22,6 +21,9 @@ ContextSettings.schema = new SimpleSchema(
key: {
type: String,
},
type: {
type: String,
},
value: {
type: Array,
},
......@@ -29,7 +31,7 @@ ContextSettings.schema = new SimpleSchema(
type: { any: {} },
},
},
{ clean: { removeEmptyStrings: false }, tracker: Tracker },
{ clean: { removeEmptyStrings: false } },
);
ContextSettings.publicFields = {
......
......@@ -922,11 +922,6 @@ export const data = [
type: 'string',
value: [''],
},
{
key: 'nextcloud.nextcloudQuota',
type: 'string',
value: [''],
},
{
key: 'rocketChat.rocketChatUser',
type: 'string',
......@@ -1053,7 +1048,7 @@ export const data = [
},
{
key: 'disabledFeatures.getApiToken',
type: 'bool',
type: 'boolean',
value: [false],
},
{
......
......@@ -41,7 +41,7 @@ describe('eventAgenda', function eventTests() {
username: 'randomguy',
password: 'toto',
email: faker.internet.email(),
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
groupCount: 0,
......@@ -51,7 +51,7 @@ describe('eventAgenda', function eventTests() {
email: faker.internet.email(),
username: 'admin',
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
groupCount: 0,
......@@ -61,7 +61,7 @@ describe('eventAgenda', function eventTests() {
email: faker.internet.email(),
username: 'member',
password: 'toto',
structure: faker.company.name(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
groupCount: 0,
......
......@@ -76,7 +76,7 @@ Groups.schema = new SimpleSchema({
},
type: {
type: SimpleSchema.Integer,
allowedValues: [0, 5, 10, 15], // 0 Ouvert, 5 Modéré, 10 Fermé, 15: Automatique
allowedValues: [0, 5, 10, 15, 20], // 0 Ouvert, 5 Modéré, 10 Fermé, 15: Automatique, 20: Restreint
label: getLabel('api.groups.labels.type'),
},
avatar: {
......@@ -196,6 +196,7 @@ Groups.typeLabels = {
5: 'api.groups.types.moderated',
10: 'api.groups.types.private',
15: 'api.groups.types.automatic',
20: 'api.groups.types.restricted',
};
Groups.publicFields = {
......
......@@ -151,68 +151,6 @@ export const findGroups = new ValidatedMethod({
},
});
// eslint-disable-next-line react/prop-types
export function _removeGroup({ groupId, userId }) {
// check group existence
const group = Groups.findOne({ _id: groupId });
if (group === undefined) {
logServer(
`GROUPS - METHODS - METEOR ERROR - _removeGroup - ${i18n.__('api.groups.unknownGroup')}`,
levels.ERROR,
scopes.SYSTEM,
{ groupId, userId },
);
throw new Meteor.Error('api.groups.removeGroup.unknownGroup', i18n.__('api.groups.unknownGroup'));
}
// check if current user has admin rights on group (or global admin)
// FIXME : allow only for owner or for all admins ?
const isAdmin = isActive(userId) && Roles.userIsInRole(userId, 'admin', groupId);
const authorized = isAdmin || userId === group.owner;
if (!authorized) {
logServer(
`GROUPS - METHODS - METEOR ERROR - _removeGroup - ${i18n.__('api.groups.adminGroupNeeded')}`,
levels.ERROR,
scopes.SYSTEM,
{ groupId, userId },
);
throw new Meteor.Error('api.groups.removeGroup.notPermitted', i18n.__('api.groups.adminGroupNeeded'));
}
if (group.type !== 15) {
// Update group quota for owner
const owner = Meteor.users.findOne({ _id: group.owner });
if (owner !== undefined) {
owner.groupCount -= 1;
if (owner.groupCount <= 0) {
owner.groupCount = 0;
}
Meteor.users.update(group.owner, {
$set: { groupCount: owner.groupCount },
});
}
}
// remove all roles set on this group
Roles.removeScope(groupId);
logServer(`GROUPS - METHODS - REMOVE - _removeGroup - groupId: ${groupId}`, levels.INFO, scopes.USER);
Groups.remove(groupId);
// remove from users favorite groups
Meteor.users.update({ favGroups: { $all: [groupId] } }, { $pull: { favGroups: groupId } }, { multi: true });
logServer(`GROUPS - METHODS - UPDATE - user ${userId} remove group ${groupId}`, levels.VERBOSE, scopes.USER);
return group;
}
export const removeGroup = new ValidatedMethod({
name: 'groups.removeGroup',
validate: new SimpleSchema({
groupId: { type: String, regEx: RegEx.Id, label: getLabel('api.groups.labels.id') },
}).validator(),
run({ groupId }) {
return _removeGroup({ groupId, userId: this.userId });
},
});
function _updateGroup(groupId, groupData, oldGroup) {
if (Meteor.isServer) {
// before update, check if some users are no longer authorized (based on structureIds)
......@@ -266,7 +204,7 @@ export const updateGroup = new ValidatedMethod({
},
'data.type': {
type: SimpleSchema.Integer,
allowedValues: [0, 5, 10, 15],
allowedValues: [0, 5, 10, 15, 20],
optional: true,
label: getLabel('api.groups.labels.type'),
},
......@@ -386,10 +324,7 @@ export const checkShareName = new ValidatedMethod({
if (Meteor.isServer) {
// Get list of all method names on User
const LISTS_METHODS = _.pluck(
[favGroup, unfavGroup, removeGroup, updateGroup, countMembersOfGroup, checkShareName],
'name',
);
const LISTS_METHODS = _.pluck([favGroup, unfavGroup, updateGroup, countMembersOfGroup, checkShareName], 'name');
// Only allow 5 list operations per connection per second
DDPRateLimiter.addRule(
{
......