Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • alphabet/laboite
  • arthur.lutz/laboite
  • daniel.dehennin/laboite
  • olivier.heintz/laboite
4 results
Show changes
Showing
with 3042 additions and 740 deletions
...@@ -4,14 +4,15 @@ import { Roles } from 'meteor/alanning:roles'; ...@@ -4,14 +4,15 @@ import { Roles } from 'meteor/alanning:roles';
import i18n from 'meteor/universe:i18n'; import i18n from 'meteor/universe:i18n';
import crypto from 'crypto'; import crypto from 'crypto';
import { parseStringPromise } from 'xml2js'; import { parseStringPromise } from 'xml2js';
import logServer from '../logging'; import logServer, { levels, scopes } from '../logging';
import Groups from '../groups/groups'; import Groups from '../groups/groups';
import { testMeteorSettingsUrl } from '../../ui/utils/utilsFuncs';
const bbbEnabled = Meteor.settings.public.enableBBB; const bbbEnabled = Meteor.settings.public.enableBBB;
class BigBlueButtonClient { class BigBlueButtonClient {
constructor() { constructor() {
this.bbbURL = Meteor.settings.public.BBBUrl; this.bbbURL = testMeteorSettingsUrl(Meteor.settings.public.BBBUrl);
this.bbbSecret = Meteor.settings.private.BBBSecret; this.bbbSecret = Meteor.settings.private.BBBSecret;
} }
...@@ -74,19 +75,49 @@ class BigBlueButtonClient { ...@@ -74,19 +75,49 @@ class BigBlueButtonClient {
meeting: meetingData, meeting: meetingData,
}, },
}); });
// logServer(`meeting created: ${JSON.stringify(meetingData)}`); logServer(
`APPCLIENT - BBBCLIENT - UPDATE - createMeeting - meeting created: ${JSON.stringify(meetingData)}`,
levels.INFO,
scopes.SYSTEM,
{
meetingParams,
slug,
userId,
},
);
return Promise.resolve(this.getJoinURL(slug, userId)); return Promise.resolve(this.getJoinURL(slug, userId));
} }
if (result.response.messageKey[0] === 'idNotUnique') { if (result.response.messageKey[0] === 'idNotUnique') {
// a meeting has already been created, ignore this error // a meeting has already been created, ignore this error
return Promise.resolve(this.getJoinURL(slug, userId)); return Promise.resolve(this.getJoinURL(slug, userId));
} }
logServer(
`APPCLIENT - BBBCLIENT - METEOR ERROR - createMeeting
- BBB create meeting Error: ${result.response.messageKey[0]}`,
levels.INFO,
scopes.SYSTEM,
{
meetingParams,
slug,
userId,
},
);
// use messageKey if translation needed // use messageKey if translation needed
throw new Meteor.Error('api.BBBClient.createMeeting.error', result.response.messageKey[0]); throw new Meteor.Error('api.BBBClient.createMeeting.error', result.response.messageKey[0]);
}), }),
) )
.catch((err) => { .catch((err) => {
logServer(`BBB create error: ${err}`, 'error'); logServer(
`APPCLIENT - BBBCLIENT - METEOR ERROR - createMeeting
- BBB create error: ${err}`,
levels.ERROR,
scopes.SYSTEM,
{
slug,
userId,
meetingParams,
},
);
throw new Meteor.Error('api.BBBClient.createMeeting.error', i18n.__('api.bbb.createError')); throw new Meteor.Error('api.BBBClient.createMeeting.error', i18n.__('api.bbb.createError'));
}); });
} }
...@@ -130,12 +161,27 @@ class BigBlueButtonClient { ...@@ -130,12 +161,27 @@ class BigBlueButtonClient {
if (result.response.returncode[0] === 'SUCCESS') { if (result.response.returncode[0] === 'SUCCESS') {
return Promise.resolve(result.response.running); return Promise.resolve(result.response.running);
} }
logServer(
`APPCLIENT - BBBCLIENT - METEOR ERROR - checkRunning -
BBB check runnning: ${result.response.messageKey[0]}`,
levels.ERROR,
scopes.SYSTEM,
{},
);
// use messageKey if translation needed // use messageKey if translation needed
throw new Meteor.Error('api.BBBClient.checkRunning.error', result.response.messageKey[0]); throw new Meteor.Error('api.BBBClient.checkRunning.error', result.response.messageKey[0]);
}), }),
) )
.catch((err) => { .catch((err) => {
logServer(`BBB checkRunning Error: ${JSON.stringify(err)}`); logServer(
`APPCLIENT - BBBCLIENT - ERROR - checkRunning - BBB checkRunning Error: ${JSON.stringify(err)}`,
levels.ERROR,
scopes.SYSTEM,
{
slug,
groupId,
},
);
return Promise.resolve(null); return Promise.resolve(null);
}); });
} }
...@@ -155,12 +201,22 @@ class BigBlueButtonClient { ...@@ -155,12 +201,22 @@ class BigBlueButtonClient {
if (result.response.returncode[0] === 'SUCCESS') { if (result.response.returncode[0] === 'SUCCESS') {
return Promise.resolve(result.response.meetings); return Promise.resolve(result.response.meetings);
} }
logServer(
`APPCLIENT - BBBCLIENT - METEOR ERROR - getMeetings -
BBB message missing: ${result.response.messageKey[0]}`,
levels.WARN,
scopes.SYSTEM,
);
// use messageKey if translation needed // use messageKey if translation needed
throw new Meteor.Error('api.BBBClient.getMeetings.error', result.response.messageKey[0]); throw new Meteor.Error('api.BBBClient.getMeetings.error', result.response.messageKey[0]);
}), }),
) )
.catch((err) => { .catch((err) => {
logServer(`BBB getMeetings Error: ${JSON.stringify(err)}`); logServer(
`APPCLIENT - BBBCLIENT - ERROR - getMeetings - BBB getMeetings Error: ${JSON.stringify(err)}`,
levels.ERROR,
scopes.SYSTEM,
);
return Promise.resolve(null); return Promise.resolve(null);
}); });
} }
...@@ -169,10 +225,25 @@ class BigBlueButtonClient { ...@@ -169,10 +225,25 @@ class BigBlueButtonClient {
let Client = null; let Client = null;
if (Meteor.isServer && bbbEnabled) { if (Meteor.isServer && bbbEnabled) {
Client = new BigBlueButtonClient(); Client = new BigBlueButtonClient();
logServer(i18n.__('api.bbb.checkConfig', { URL: Client.bbbURL })); logServer(
`APPCLIENT - BBBCLIENT - NEW OBJECT - BigBlueButtonClient
- ${i18n.__('api.bbb.checkConfig', { URL: Client.bbbURL })}`,
levels.INFO,
scopes.SYSTEM,
{
URL: Client.bbbURL,
},
);
Client.getMeetings().then(() => { Client.getMeetings().then(() => {
// console.log('*** ALL MEETINGS : ', JSON.stringify(response)); logServer(
logServer(i18n.__('api.bbb.configOk')); `APPCLIENT - BBBCLIENT - THEN - getMeetings
- ${i18n.__('api.bbb.configOk')}`,
levels.INFO,
scopes.SYSTEM,
{
URL: Client.bbbURL,
},
);
}); });
} }
const BBBClient = Client; const BBBClient = Client;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
import { Mongo } from 'meteor/mongo'; import { Mongo } from 'meteor/mongo';
import SimpleSchema from 'simpl-schema'; import SimpleSchema from 'simpl-schema';
import { Tracker } from 'meteor/tracker';
import { getLabel } from '../utils'; import { getLabel } from '../utils';
const AppSettings = new Mongo.Collection('appsettings'); const AppSettings = new Mongo.Collection('appsettings');
...@@ -50,6 +49,19 @@ const IntroductionI18n = new SimpleSchema({ ...@@ -50,6 +49,19 @@ const IntroductionI18n = new SimpleSchema({
}, },
}); });
const GlobalInfoI18n = new SimpleSchema({
language: {
type: String,
label: getLabel('api.appsettings.labels.language'),
optional: true,
},
content: {
type: String,
label: getLabel('api.appsettings.labels.content_globalInfo'),
optional: true,
},
});
AppSettings.schema = new SimpleSchema( AppSettings.schema = new SimpleSchema(
{ {
introduction: { introduction: {
...@@ -59,6 +71,13 @@ AppSettings.schema = new SimpleSchema( ...@@ -59,6 +71,13 @@ AppSettings.schema = new SimpleSchema(
'introduction.$': { 'introduction.$': {
type: IntroductionI18n, type: IntroductionI18n,
}, },
globalInfo: {
type: Array,
label: getLabel('api.appsettings.labels.globalInfo'),
},
'globalInfo.$': {
type: GlobalInfoI18n,
},
legal: { legal: {
type: SettingsType('legal'), type: SettingsType('legal'),
label: getLabel('api.appsettings.labels.legal'), label: getLabel('api.appsettings.labels.legal'),
...@@ -75,6 +94,10 @@ AppSettings.schema = new SimpleSchema( ...@@ -75,6 +94,10 @@ AppSettings.schema = new SimpleSchema(
type: SettingsType('personal_data'), type: SettingsType('personal_data'),
label: getLabel('api.appsettings.labels.personal_data'), label: getLabel('api.appsettings.labels.personal_data'),
}, },
personalSpace: {
type: SettingsType('personal_space'),
label: getLabel('api.appsettings.labels.personalSpace'),
},
maintenance: { maintenance: {
type: Boolean, type: Boolean,
defaultValue: false, defaultValue: false,
...@@ -85,24 +108,35 @@ AppSettings.schema = new SimpleSchema( ...@@ -85,24 +108,35 @@ AppSettings.schema = new SimpleSchema(
defaultValue: ' ', defaultValue: ' ',
label: getLabel('api.appsettings.labels.textMaintenance'), label: getLabel('api.appsettings.labels.textMaintenance'),
}, },
userStructureValidationMandatory: {
type: Boolean,
label: getLabel('api.appsettings.label.userStructureValidationMandatory'),
},
}, },
{ clean: { removeEmptyStrings: false }, tracker: Tracker }, { clean: { removeEmptyStrings: false } },
); );
AppSettings.publicFields = { AppSettings.publicFields = {
introduction: 1, introduction: 1,
legal: 1, legal: 1,
globalInfo: 1,
accessibility: 1, accessibility: 1,
gcu: 1, gcu: 1,
personalData: 1, personalData: 1,
maintenance: 1, maintenance: 1,
textMaintenance: 1, textMaintenance: 1,
userStructureValidationMandatory: 1,
personalSpace: 1,
}; };
AppSettings.introduction = { AppSettings.introduction = {
'introduction.content': 1, 'introduction.content': 1,
'introduction.language': 1, 'introduction.language': 1,
}; };
AppSettings.globalInfo = {
'globalInfo.content': 1,
'globalInfo.language': 1,
};
AppSettings.links = { AppSettings.links = {
'legal.link': 1, 'legal.link': 1,
'legal.external': 1, 'legal.external': 1,
...@@ -112,6 +146,8 @@ AppSettings.links = { ...@@ -112,6 +146,8 @@ AppSettings.links = {
'gcu.external': 1, 'gcu.external': 1,
'personalData.link': 1, 'personalData.link': 1,
'personalData.external': 1, 'personalData.external': 1,
'personalSpace.link': 1,
'personalSpace.external': 1,
}; };
AppSettings.legal = { AppSettings.legal = {
...@@ -134,6 +170,11 @@ AppSettings.personalData = { ...@@ -134,6 +170,11 @@ AppSettings.personalData = {
'personalData.external': 1, 'personalData.external': 1,
'personalData.content': 1, 'personalData.content': 1,
}; };
AppSettings.personalSpace = {
'personalSpace.link': 1,
'personalSpace.external': 1,
'personalSpace.content': 1,
};
AppSettings.attachSchema(AppSettings.schema); AppSettings.attachSchema(AppSettings.schema);
......
import { useTracker } from 'meteor/react-meteor-data'; import { useTracker } from 'meteor/react-meteor-data';
import { Meteor } from 'meteor/meteor'; import { Meteor } from 'meteor/meteor';
import AppSettings from './appsettings'; import AppSettings from './appsettings';
import { getCurrentIntroduction } from '../utils'; import { getCurrentIntroduction, getCurrentText } from '../utils';
export const useCurrentIntroduction = () => export const useCurrentIntroduction = () =>
useTracker(() => { useTracker(() => {
...@@ -14,3 +14,15 @@ export const useCurrentIntroduction = () => ...@@ -14,3 +14,15 @@ export const useCurrentIntroduction = () =>
return { data, loading }; return { data, loading };
}); });
export const useCurrentGlobalInfo = () =>
useTracker(() => {
const handle = Meteor.subscribe('appsettings.globalInfo');
const loading = !handle.ready();
const appsettings = AppSettings.findOne() || {};
const { globalInfo = [] } = appsettings;
const data = getCurrentText({ data: globalInfo });
return { data, loading };
});
...@@ -6,14 +6,20 @@ import SimpleSchema from 'simpl-schema'; ...@@ -6,14 +6,20 @@ import SimpleSchema from 'simpl-schema';
import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { ValidatedMethod } from 'meteor/mdg:validated-method';
import { Roles } from 'meteor/alanning:roles'; import { Roles } from 'meteor/alanning:roles';
import i18n from 'meteor/universe:i18n'; import i18n from 'meteor/universe:i18n';
import logServer from '../logging'; import sanitizeHtml from 'sanitize-html';
import { isActive, getLabel } from '../utils'; import logServer, { levels, scopes } from '../logging';
import { isActive, getLabel, validateString, sanitizeParameters } from '../utils';
import AppSettings from './appsettings'; import AppSettings from './appsettings';
export function checkMigrationStatus() { export function checkMigrationStatus() {
if (Migrations._getControl().locked === true) { if (Migrations._getControl().locked === true) {
logServer('Migration lock detected !!!!', 'error'); logServer(
`APPSETTINGS - METHODS - UPDATE - checkMigrationStatus,Migration lock detected !!!!`,
levels.WARN,
scopes.SYSTEM,
);
AppSettings.update({}, { $set: { maintenance: true, textMaintenance: 'api.appsettings.migrationLockedText' } }); AppSettings.update({}, { $set: { maintenance: true, textMaintenance: 'api.appsettings.migrationLockedText' } });
} }
} }
...@@ -43,14 +49,33 @@ export const updateAppsettings = new ValidatedMethod({ ...@@ -43,14 +49,33 @@ export const updateAppsettings = new ValidatedMethod({
run({ external, link, content, key }) { run({ external, link, content, key }) {
try { try {
if (link) validateString(link);
let sanitizedContent = '';
if (content) {
sanitizedContent = sanitizeHtml(content, sanitizeParameters);
validateString(sanitizedContent);
}
validateString(key, true);
// check if current user is admin // check if current user is admin
const authorized = isActive(this.userId) && Roles.userIsInRole(this.userId, 'admin'); const authorized = isActive(this.userId) && Roles.userIsInRole(this.userId, 'admin');
if (!authorized) { if (!authorized) {
throw new Meteor.Error('api.appsettings.updateAppsettings.notPermitted', i18n.__('api.users.adminNeeded')); throw new Meteor.Error('api.appsettings.updateAppsettings.notPermitted', i18n.__('api.users.adminNeeded'));
} }
const args = { content, external, link }; const args = { content: sanitizedContent, external, link };
logServer(
`APPSETTINGS - METHODS - UPDATE - updateAppsettings - args: ${JSON.stringify(args)}`,
levels.VERBOSE,
scopes.SYSTEM,
{ external, link, content, key },
);
return AppSettings.update({ _id: 'settings' }, { $set: { [key]: args } }); return AppSettings.update({ _id: 'settings' }, { $set: { [key]: args } });
} catch (error) { } catch (error) {
logServer(
`APPSETTINGS - METHODS - METEOR ERROR - updateAppsettings - error: ${error}`,
levels.ERROR,
scopes.SYSTEM,
{ external, link, content, key },
);
throw new Meteor.Error(error, error); throw new Meteor.Error(error, error);
} }
}, },
...@@ -86,8 +111,59 @@ export const switchMaintenanceStatus = new ValidatedMethod({ ...@@ -86,8 +111,59 @@ export const switchMaintenanceStatus = new ValidatedMethod({
checkMigrationStatus(); checkMigrationStatus();
return AppSettings.update({ _id: 'settings' }, { $set: { maintenance: newValue, textMaintenance: '' } }); return AppSettings.update({ _id: 'settings' }, { $set: { maintenance: newValue, textMaintenance: '' } });
} }
logServer(
`APPSETTINGS - METHODS - UPDATE - switchMaintenanceStatus - Maintenance: ${newValue}`,
levels.VERBOSE,
scopes.SYSTEM,
{ unlockMigration },
);
return AppSettings.update({ _id: 'settings' }, { $set: { maintenance: newValue } }); return AppSettings.update({ _id: 'settings' }, { $set: { maintenance: newValue } });
} catch (error) { } catch (error) {
logServer(`APPSETTINGS - METHODS - METEOR ERROR - switchMaintenanceStatus`, levels.ERROR, scopes.SYSTEM, {
error,
});
throw new Meteor.Error(error, error);
}
},
});
export const setUserStructureValidationMandatoryStatus = new ValidatedMethod({
name: 'appSettings.setUserStructureValidationMandatoryStatus',
validate: new SimpleSchema({ isValidationMandatory: { type: Boolean } }).validator(),
run({ isValidationMandatory }) {
try {
const authorized = isActive(this.userId) && Roles.userIsInRole(this.userId, 'admin');
if (!authorized) {
logServer(
`APPSETTINGS - METHODS - METEOR ERROR - setUserStructureValidationMandatoryStatus -
authorized: ${authorized}`,
levels.ERROR,
scopes.SYSTEM,
{ isValidationMandatory },
);
throw new Meteor.Error(
'api.appsettings.setUserStructureValidationMandatoryStatus.notPermitted',
i18n.__('api.users.admineeded'),
);
}
logServer(
`APPSETTINGS - METHODS - UPDATE - setUserStructureValidationMandatoryStatus -
isValidationMandatory: ${isValidationMandatory}`,
levels.VERBOSE,
scopes.SYSTEM,
{ isValidationMandatory },
);
return AppSettings.update(
{ _id: 'settings' },
{ $set: { userStructureValidationMandatory: isValidationMandatory } },
);
} catch (error) {
logServer(
`APPSETTINGS - METHODS - METEOR ERROR - setUserStructureValidationMandatoryStatus`,
levels.ERROR,
scopes.SYSTEM,
{ error },
);
throw new Meteor.Error(error, error); throw new Meteor.Error(error, error);
} }
}, },
...@@ -104,21 +180,29 @@ export const updateTextMaintenance = new ValidatedMethod({ ...@@ -104,21 +180,29 @@ export const updateTextMaintenance = new ValidatedMethod({
}).validator({ clean: true }), }).validator({ clean: true }),
run({ text }) { run({ text }) {
if (text) validateString(text);
try { try {
// check if current user is admin // check if current user is admin
const authorized = isActive(this.userId) && Roles.userIsInRole(this.userId, 'admin'); const authorized = isActive(this.userId) && Roles.userIsInRole(this.userId, 'admin');
if (!authorized) { if (!authorized) {
throw new Meteor.Error('api.appsettings.updateTextMaintenance.notPermitted', i18n.__('api.users.adminNeeded')); throw new Meteor.Error('api.appsettings.updateTextMaintenance.notPermitted', i18n.__('api.users.adminNeeded'));
} }
logServer(
`APPSETTINGS - METHODS - UPDATE - updateTextMaintenance - text maintenance: ${text}`,
levels.INFO,
scopes.SYSTEM,
{ text },
);
return AppSettings.update({ _id: 'settings' }, { $set: { textMaintenance: text } }); return AppSettings.update({ _id: 'settings' }, { $set: { textMaintenance: text } });
} catch (error) { } catch (error) {
logServer(`APPSETTINGS - METHODS - METEOR ERROR - updateTextMaintenance`, levels.ERROR, scopes.SYSTEM, { error });
throw new Meteor.Error(error, error); throw new Meteor.Error(error, error);
} }
}, },
}); });
export const updateIntroductionLanguage = new ValidatedMethod({ export const updateTextInfoLanguage = new ValidatedMethod({
name: 'appSettings.updateIntroductionLanguage', name: 'appSettings.updateTextInfoLanguage',
validate: new SimpleSchema({ validate: new SimpleSchema({
language: { language: {
type: String, type: String,
...@@ -130,29 +214,64 @@ export const updateIntroductionLanguage = new ValidatedMethod({ ...@@ -130,29 +214,64 @@ export const updateIntroductionLanguage = new ValidatedMethod({
label: getLabel('api.appsettings.labels.content'), label: getLabel('api.appsettings.labels.content'),
optional: true, optional: true,
}, },
tabkey: {
type: String,
label: getLabel('api.appsettings.labels.tabkey'),
optional: true,
},
}).validator({ clean: true }), }).validator({ clean: true }),
run({ language, content }) { run({ language, content, tabkey }) {
if (language) validateString(language, true);
if (tabkey) validateString(tabkey, true);
let sanitizedContent = '';
if (content) {
sanitizedContent = sanitizeHtml(content, sanitizeParameters);
validateString(sanitizedContent);
}
try { try {
// check if current user is admin // check if current user is admin
const authorized = isActive(this.userId) && Roles.userIsInRole(this.userId, 'admin'); const authorized = isActive(this.userId) && Roles.userIsInRole(this.userId, 'admin');
if (!authorized) { if (!authorized) {
logServer(
`APPSETTINGS - METHODS - METEOR ERROR - updateTextInfoLanguage - authorized: ${authorized}`,
levels.ERROR,
scopes.SYSTEM,
);
throw new Meteor.Error( throw new Meteor.Error(
'api.appsettings.updateIntroductionLanguage.notPermitted', 'api.appsettings.updateIntroductionLanguage.notPermitted',
i18n.__('api.users.adminNeeded'), i18n.__('api.users.adminNeeded'),
); );
} }
const appsettings = AppSettings.findOne({}); const appsettings = AppSettings.findOne({});
const { introduction } = appsettings; let newInfo;
const langIndex = introduction.findIndex((entry) => entry.language === language); let langIndex;
const newIntro = [...introduction]; if (tabkey === 'globalInfo') {
const { globalInfo } = appsettings;
newInfo = [...globalInfo];
langIndex = globalInfo.findIndex((entry) => entry.language === language);
} else if (tabkey === 'introduction') {
const { introduction } = appsettings;
newInfo = [...introduction];
langIndex = introduction.findIndex((entry) => entry.language === language);
}
if (langIndex > -1) { if (langIndex > -1) {
newIntro[langIndex].content = content; newInfo[langIndex].content = sanitizedContent;
} else { } else {
newIntro.push({ language, content }); newInfo.push({ language, content: sanitizedContent });
} }
return AppSettings.update({ _id: 'settings' }, { $set: { introduction: newIntro } }); logServer(
`APPSETTINGS - METHODS - UPDATE - updateTextInfoLanguage - new settings: ${JSON.stringify(newInfo)}`,
levels.VERBOSE,
scopes.SYSTEM,
{ language, content, tabkey },
);
return AppSettings.update({ _id: 'settings' }, { $set: { [tabkey]: newInfo } });
} catch (error) { } catch (error) {
logServer(`APPSETTINGS - METHODS - METEOR ERROR - updateTextInfoLanguage`, levels.ERROR, scopes.SYSTEM, {
error,
});
throw new Meteor.Error(error, error); throw new Meteor.Error(error, error);
} }
}, },
...@@ -172,7 +291,14 @@ export const getAppSettingsLinks = new ValidatedMethod({ ...@@ -172,7 +291,14 @@ export const getAppSettingsLinks = new ValidatedMethod({
// Get list of all method names on User // Get list of all method names on User
const LISTS_METHODS = _.pluck( const LISTS_METHODS = _.pluck(
[updateAppsettings, updateIntroductionLanguage, updateTextMaintenance, switchMaintenanceStatus, getAppSettingsLinks], [
updateAppsettings,
updateTextMaintenance,
updateTextInfoLanguage,
switchMaintenanceStatus,
getAppSettingsLinks,
setUserStructureValidationMandatoryStatus,
],
'name', 'name',
); );
......
...@@ -4,8 +4,9 @@ ...@@ -4,8 +4,9 @@
import { PublicationCollector } from 'meteor/johanbrook:publication-collector'; import { PublicationCollector } from 'meteor/johanbrook:publication-collector';
import { assert } from 'chai'; import { assert } from 'chai';
import { Meteor } from 'meteor/meteor'; import { Meteor } from 'meteor/meteor';
import { Random } from 'meteor/random';
import '../../../startup/i18n/en.i18n.json'; import '../../../startup/i18n/en.i18n.json';
import faker from 'faker'; import { faker } from '@faker-js/faker';
import { Factory } from 'meteor/dburles:factory'; import { Factory } from 'meteor/dburles:factory';
import { Accounts } from 'meteor/accounts-base'; import { Accounts } from 'meteor/accounts-base';
import { Roles } from 'meteor/alanning:roles'; import { Roles } from 'meteor/alanning:roles';
...@@ -13,10 +14,10 @@ import { Roles } from 'meteor/alanning:roles'; ...@@ -13,10 +14,10 @@ import { Roles } from 'meteor/alanning:roles';
import AppSettings from '../appsettings'; import AppSettings from '../appsettings';
import { import {
updateAppsettings, updateAppsettings,
updateIntroductionLanguage,
getAppSettingsLinks, getAppSettingsLinks,
switchMaintenanceStatus, switchMaintenanceStatus,
updateTextMaintenance, updateTextMaintenance,
updateTextInfoLanguage,
} from '../methods'; } from '../methods';
import './publications'; import './publications';
import './factories'; import './factories';
...@@ -37,6 +38,10 @@ describe('appsettings', function () { ...@@ -37,6 +38,10 @@ describe('appsettings', function () {
{ language: 'en', content: 'Hello' }, { language: 'en', content: 'Hello' },
{ language: 'fr', content: 'Salut' }, { language: 'fr', content: 'Salut' },
], ],
globalInfo: [
{ language: 'en', content: 'Hello' },
{ language: 'fr', content: 'Salut' },
],
gcu: { gcu: {
external: false, external: false,
link: 'gcu_link', link: 'gcu_link',
...@@ -57,6 +62,12 @@ describe('appsettings', function () { ...@@ -57,6 +62,12 @@ describe('appsettings', function () {
link: 'pdata_link', link: 'pdata_link',
content: 'pdata_content', content: 'pdata_content',
}, },
userStructureValidationMandatory: false,
personalSpace: {
external: false,
link: 'pSpaceData_link',
content: 'pSpaceData_content',
},
}; };
AppSettings.insert(appsettinit); AppSettings.insert(appsettinit);
}); });
...@@ -67,10 +78,15 @@ describe('appsettings', function () { ...@@ -67,10 +78,15 @@ describe('appsettings', function () {
assert.equal(collections.appsettings.length, 1); assert.equal(collections.appsettings.length, 1);
const appall = collections.appsettings[0]; const appall = collections.appsettings[0];
assert.property(appall, 'introduction'); assert.property(appall, 'introduction');
assert.property(appall, 'globalInfo');
assert.property(appall, 'gcu'); assert.property(appall, 'gcu');
assert.property(appall, 'legal'); assert.property(appall, 'legal');
assert.property(appall, 'accessibility'); assert.property(appall, 'accessibility');
assert.property(appall, 'personalData'); assert.property(appall, 'personalData');
assert.property(appall, 'personalSpace');
assert.property(appall, 'maintenance');
assert.property(appall, 'textMaintenance');
assert.property(appall, 'userStructureValidationMandatory');
done(); done();
}); });
}); });
...@@ -87,6 +103,18 @@ describe('appsettings', function () { ...@@ -87,6 +103,18 @@ describe('appsettings', function () {
}); });
}); });
}); });
describe('appsettings.globalInfo', function () {
it('sends the appsetting globalInfo', function (done) {
const collector = new PublicationCollector({});
collector.collect('appsettings.globalInfo', {}, (collections) => {
const appinfo = collections.appsettings[0];
assert.property(appinfo, 'globalInfo');
assert.typeOf(appinfo.globalInfo, 'array');
assert.lengthOf(appinfo.globalInfo, 2);
done();
});
});
});
describe('appsettings.gcu', function () { describe('appsettings.gcu', function () {
it('sends the appsetting gcu', function (done) { it('sends the appsetting gcu', function (done) {
const collector = new PublicationCollector({}); const collector = new PublicationCollector({});
...@@ -143,11 +171,26 @@ describe('appsettings', function () { ...@@ -143,11 +171,26 @@ describe('appsettings', function () {
}); });
}); });
}); });
describe('appsettings.personalSpace', function () {
it('sends the appsetting personalSpace', function (done) {
const collector = new PublicationCollector({});
collector.collect('appsettings.personalSpace', {}, (collections) => {
const apppersData = collections.appsettings[0];
assert.property(apppersData, 'personalSpace');
assert.typeOf(apppersData.personalSpace, 'object');
assert.property(apppersData.personalSpace, 'external');
assert.property(apppersData.personalSpace, 'link');
assert.property(apppersData.personalSpace, 'content');
done();
});
});
});
}); });
describe('methods', function () { describe('methods', function () {
let adminId; let adminId;
let userId; let userId;
beforeEach(function () { beforeEach(function () {
this.timeout(3000);
// Clear // Clear
AppSettings.remove({}); AppSettings.remove({});
Meteor.users.remove({}); Meteor.users.remove({});
...@@ -161,6 +204,10 @@ describe('appsettings', function () { ...@@ -161,6 +204,10 @@ describe('appsettings', function () {
{ language: 'en', content: 'Hello' }, { language: 'en', content: 'Hello' },
{ language: 'fr', content: 'Salut' }, { language: 'fr', content: 'Salut' },
], ],
globalInfo: [
{ language: 'en', content: 'Hello' },
{ language: 'fr', content: 'Salut' },
],
gcu: { gcu: {
external: false, external: false,
link: 'gcu_link', link: 'gcu_link',
...@@ -181,6 +228,12 @@ describe('appsettings', function () { ...@@ -181,6 +228,12 @@ describe('appsettings', function () {
link: 'pdata_link', link: 'pdata_link',
content: 'pdata_content', content: 'pdata_content',
}, },
userStructureValidationMandatory: false,
personalSpace: {
external: false,
link: 'pSpaceData_link',
content: 'pSpaceData_content',
},
}; };
AppSettings.insert(appsettinit); AppSettings.insert(appsettinit);
...@@ -190,18 +243,18 @@ describe('appsettings', function () { ...@@ -190,18 +243,18 @@ describe('appsettings', function () {
email, email,
username: email, username: email,
password: 'toto', password: 'toto',
structure: faker.company.companyName(), structure: Random.id(),
firstName: faker.name.firstName(), firstName: faker.person.firstName(),
lastName: faker.name.lastName(), lastName: faker.person.lastName(),
}); });
const emailAdmin = faker.internet.email(); const emailAdmin = faker.internet.email();
adminId = Accounts.createUser({ adminId = Accounts.createUser({
email: emailAdmin, email: emailAdmin,
username: emailAdmin, username: emailAdmin,
password: 'toto', password: 'toto',
structure: faker.company.companyName(), structure: Random.id(),
firstName: faker.name.firstName(), firstName: faker.person.firstName(),
lastName: faker.name.lastName(), lastName: faker.person.lastName(),
}); });
// set this user as global admin // set this user as global admin
Roles.addUsersToRoles(adminId, 'admin'); Roles.addUsersToRoles(adminId, 'admin');
...@@ -226,23 +279,35 @@ describe('appsettings', function () { ...@@ -226,23 +279,35 @@ describe('appsettings', function () {
assert.equal(appsett.gcu.external, 0); assert.equal(appsett.gcu.external, 0);
}); });
}); });
describe('updateIntroductionLanguage', function () { describe('updateInfoLanguage', function () {
it('normal users can not update introduction language in app settings', function () { it('normal users can not update informations language in app settings', function () {
assert.throws( assert.throws(
() => { () => {
updateIntroductionLanguage._execute({ userId }, { language: 'fr', content: 'coucou' }); updateTextInfoLanguage._execute({ userId }, { tabkey: 'introduction', language: 'fr', content: 'coucou' });
}, },
Meteor.Error, Meteor.Error,
/api.appsettings.updateIntroductionLanguage.notPermitted/, /api.appsettings.updateIntroductionLanguage.notPermitted/,
); );
}); });
it('admin can update app settings', function () { it('admin can update app settings', function () {
updateIntroductionLanguage._execute({ userId: adminId }, { language: 'fr', content: 'coucou' }); updateTextInfoLanguage._execute(
{ userId: adminId },
{ tabkey: 'introduction', language: 'fr', content: 'coucou' },
);
updateTextInfoLanguage._execute(
{ userId: adminId },
{ tabkey: 'globalInfo', language: 'fr', content: 'salut' },
);
const appsett = AppSettings.findOne({ const appsett = AppSettings.findOne({
_id: 'settings', _id: 'settings',
introduction: { $elemMatch: { language: 'fr', content: 'coucou' } }, introduction: { $elemMatch: { language: 'fr', content: 'coucou' } },
}); });
assert.typeOf(appsett, 'object'); assert.typeOf(appsett, 'object');
const appsett2 = AppSettings.findOne({
_id: 'settings',
globalInfo: { $elemMatch: { language: 'fr', content: 'salut' } },
});
assert.typeOf(appsett2, 'object');
}); });
}); });
describe('getAppSettingsLinks', function () { describe('getAppSettingsLinks', function () {
......
import faker from 'faker'; import { faker } from '@faker-js/faker';
import { Factory } from 'meteor/dburles:factory'; import { Factory } from 'meteor/dburles:factory';
import AppSettings from '../appsettings'; import AppSettings from '../appsettings';
...@@ -14,6 +14,16 @@ Factory.define('appsettings', AppSettings, { ...@@ -14,6 +14,16 @@ Factory.define('appsettings', AppSettings, {
content: faker.lorem.sentences(), content: faker.lorem.sentences(),
}, },
], ],
globalInfo: [
{
language: 'en',
content: faker.lorem.sentences(),
},
{
language: 'fr',
content: faker.lorem.sentences(),
},
],
legal: { legal: {
external: Boolean(Math.random() * 2), external: Boolean(Math.random() * 2),
link: faker.lorem.slug(), link: faker.lorem.slug(),
...@@ -34,4 +44,10 @@ Factory.define('appsettings', AppSettings, { ...@@ -34,4 +44,10 @@ Factory.define('appsettings', AppSettings, {
link: faker.lorem.slug(), link: faker.lorem.slug(),
content: faker.lorem.sentences(), content: faker.lorem.sentences(),
}, },
userStructureValidationMandatory: false,
personalSpace: {
external: Boolean(Math.random() * 2),
link: faker.lorem.slug(),
content: faker.lorem.sentences(),
},
}); });
...@@ -13,6 +13,11 @@ Meteor.publish('appsettings.introduction', () => { ...@@ -13,6 +13,11 @@ Meteor.publish('appsettings.introduction', () => {
return AppSettings.find({ _id: 'settings' }, { fields: introduction, sort: { _id: 1 }, limit: 1 }); return AppSettings.find({ _id: 'settings' }, { fields: introduction, sort: { _id: 1 }, limit: 1 });
}); });
Meteor.publish('appsettings.globalInfo', () => {
const { globalInfo } = AppSettings;
return AppSettings.find({ _id: 'settings' }, { fields: globalInfo, sort: { _id: 1 }, limit: 1 });
});
// publish GCU settings // publish GCU settings
Meteor.publish('appsettings.gcu', () => { Meteor.publish('appsettings.gcu', () => {
const { gcu } = AppSettings; const { gcu } = AppSettings;
...@@ -37,6 +42,12 @@ Meteor.publish('appsettings.personalData', () => { ...@@ -37,6 +42,12 @@ Meteor.publish('appsettings.personalData', () => {
return AppSettings.find({ _id: 'settings' }, { fields: personalData, sort: { _id: 1 }, limit: 1 }); return AppSettings.find({ _id: 'settings' }, { fields: personalData, sort: { _id: 1 }, limit: 1 });
}); });
// publish personal space intro settings
Meteor.publish('appsettings.personalSpace', () => {
const { personalSpace } = AppSettings;
return AppSettings.find({ _id: 'settings' }, { fields: personalSpace, sort: { _id: 1 }, limit: 1 });
});
// publish maintenance settings // publish maintenance settings
Meteor.publish('appsettings.maintenance', () => { Meteor.publish('appsettings.maintenance', () => {
const { maintenance } = AppSettings; const { maintenance } = AppSettings;
...@@ -48,3 +59,12 @@ Meteor.publish('appsettings.textMaintenance', () => { ...@@ -48,3 +59,12 @@ Meteor.publish('appsettings.textMaintenance', () => {
const { textMaintenance } = AppSettings; const { textMaintenance } = AppSettings;
return AppSettings.find({ _id: 'settings' }, { fields: textMaintenance, sort: { _id: 1 }, limit: 1 }); return AppSettings.find({ _id: 'settings' }, { fields: textMaintenance, sort: { _id: 1 }, limit: 1 });
}); });
// publish userStructureValidationMandatory settings
Meteor.publish('appsettings.userStructureValidationMandatory', () => {
const { userStructureValidationMandatory } = AppSettings;
return AppSettings.find(
{ _id: 'settings' },
{ fields: userStructureValidationMandatory, sort: { _id: 1 }, limit: 1 },
);
});
/* eslint-disable func-names */ /* eslint-disable func-names */
import { Mongo } from 'meteor/mongo'; import { Mongo } from 'meteor/mongo';
import SimpleSchema from 'simpl-schema'; import SimpleSchema from 'simpl-schema';
import { Tracker } from 'meteor/tracker';
import slugy from '../../ui/utils/slugy'; import slugy from '../../ui/utils/slugy';
import { getLabel } from '../utils'; import { getLabel } from '../utils';
import Groups from '../groups/groups'; import Groups from '../groups/groups';
import RegEx from '../regExp';
const Articles = new Mongo.Collection('articles'); const Articles = new Mongo.Collection('articles');
...@@ -57,7 +57,8 @@ Articles.schema = new SimpleSchema( ...@@ -57,7 +57,8 @@ Articles.schema = new SimpleSchema(
optional: true, optional: true,
}, },
structure: { structure: {
type: SimpleSchema.RegEx.Id, type: String,
// regEx: RegEx.Id, doesn't work, structure can be an empty string
label: getLabel('api.articles.labels.structure'), label: getLabel('api.articles.labels.structure'),
}, },
markdown: { type: Boolean, label: getLabel('api.articles.labels.markdown'), defaultValue: false }, markdown: { type: Boolean, label: getLabel('api.articles.labels.markdown'), defaultValue: false },
...@@ -74,11 +75,14 @@ Articles.schema = new SimpleSchema( ...@@ -74,11 +75,14 @@ Articles.schema = new SimpleSchema(
type: { type: Object }, type: { type: Object },
}, },
'groups.$._id': { 'groups.$._id': {
type: { type: String, regEx: SimpleSchema.RegEx.Id }, type: { type: String, regEx: RegEx.Id },
}, },
'groups.$.name': { 'groups.$.name': {
type: { type: String }, type: { type: String },
}, },
'groups.$.type': {
type: { type: SimpleSchema.Integer },
},
createdAt: { createdAt: {
type: Date, type: Date,
label: getLabel('api.articles.labels.createdAt'), label: getLabel('api.articles.labels.createdAt'),
...@@ -106,7 +110,7 @@ Articles.schema = new SimpleSchema( ...@@ -106,7 +110,7 @@ Articles.schema = new SimpleSchema(
defaultValue: '', defaultValue: '',
}, },
}, },
{ clean: { removeEmptyStrings: false }, tracker: Tracker }, { clean: { removeEmptyStrings: false } },
); );
Articles.publicFields = { Articles.publicFields = {
......
This diff is collapsed.
...@@ -4,12 +4,16 @@ ...@@ -4,12 +4,16 @@
import { PublicationCollector } from 'meteor/johanbrook:publication-collector'; import { PublicationCollector } from 'meteor/johanbrook:publication-collector';
import { assert } from 'chai'; import { assert } from 'chai';
import { Meteor } from 'meteor/meteor'; import { Meteor } from 'meteor/meteor';
import { Roles } from 'meteor/alanning:roles';
import { _ } from 'meteor/underscore'; import { _ } from 'meteor/underscore';
import '../../../startup/i18n/en.i18n.json'; import '../../../startup/i18n/en.i18n.json';
import faker from 'faker'; import { faker } from '@faker-js/faker';
import { Random } from 'meteor/random'; import { Random } from 'meteor/random';
import { Factory } from 'meteor/dburles:factory'; import { Factory } from 'meteor/dburles:factory';
import { Accounts } from 'meteor/accounts-base'; import { Accounts } from 'meteor/accounts-base';
import Groups from '../../groups/groups';
import '../../groups/server/factories';
import { setMemberOf } from '../../users/server/methods';
import Articles from '../articles'; import Articles from '../articles';
import { import {
...@@ -41,8 +45,8 @@ describe('articles', function () { ...@@ -41,8 +45,8 @@ describe('articles', function () {
username: email, username: email,
password: 'toto', password: 'toto',
structure: Random.id(), structure: Random.id(),
firstName: faker.name.firstName(), firstName: faker.person.firstName(),
lastName: faker.name.lastName(), lastName: faker.person.lastName(),
}); });
Meteor.users.update(userId, { $set: { isActive: true } }); Meteor.users.update(userId, { $set: { isActive: true } });
Articles.remove({}); Articles.remove({});
...@@ -95,6 +99,120 @@ describe('articles', function () { ...@@ -95,6 +99,120 @@ describe('articles', function () {
}); });
}); });
}); });
describe('group publications', function eventPublications() {
let userId;
let adminId;
let memberId;
let group;
let group2;
let groupId;
let group2Id;
beforeEach(function beforeTesting() {
Groups.remove({});
Articles.remove({});
Meteor.roleAssignment.remove({});
Meteor.roles.remove({});
Meteor.users.remove({});
Roles.createRole('admin');
Roles.createRole('member');
userId = Accounts.createUser({
username: 'randomguy',
password: 'toto',
email: faker.internet.email(),
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
groupCount: 0,
groupQuota: 10,
});
adminId = Accounts.createUser({
email: faker.internet.email(),
username: 'admin',
password: 'toto',
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
groupCount: 0,
groupQuota: 10,
});
memberId = Accounts.createUser({
email: faker.internet.email(),
username: 'member',
password: 'toto',
structure: Random.id(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
groupCount: 0,
groupQuota: 10,
});
Meteor.users.update({}, { $set: { isActive: true } }, { multi: true });
Roles.addUsersToRoles(adminId, 'admin');
group = Factory.create('group', { owner: adminId, type: 0 });
groupId = group._id;
group2 = Factory.create('group', { owner: adminId, type: 5 });
group2Id = group2._id;
setMemberOf._execute({ userId: memberId }, { userId: memberId, groupId });
setMemberOf._execute({ userId: adminId }, { userId: memberId, groupId: group2Id });
_.times(3, () => {
Factory.create('article', {
_id: Random.id(),
userId: adminId,
groups: [
{ _id: groupId, name: 'group', type: 0 },
{ _id: group2Id, name: 'group2', type: 5 },
],
});
});
});
describe('groups.articles', function eventsForUserPub() {
it('does send articles from a public group when not member', function groupArticlesPub(done) {
const collector = new PublicationCollector({ userId });
collector.collect(
'groups.articles',
{ page: 1, search: '', slug: group.slug, itemPerPage: 10 },
(collections) => {
assert.equal(collections.articles.length, 3);
done();
},
);
});
it('does not send articles from a protected group when not member', function groupArticlesProtected(done) {
const collector = new PublicationCollector({ userId });
collector.collect(
'groups.articles',
{ page: 1, search: '', slug: group2.slug, itemPerPage: 10 },
(collections) => {
assert.equal(collections.articles, undefined);
done();
},
);
});
it('does send articles from a protected group when admin', function groupArticlesProtectedAdmin(done) {
const collector = new PublicationCollector({ userId: adminId });
collector.collect(
'groups.articles',
{ page: 1, search: '', slug: group2.slug, itemPerPage: 10 },
(collections) => {
assert.equal(collections.articles.length, 3);
done();
},
);
});
it('does send articles from a protected group when member', function groupArticlesProtectedMember(done) {
const collector = new PublicationCollector({ userId: memberId });
collector.collect(
'groups.articles',
{ page: 1, search: '', slug: group2.slug, itemPerPage: 10 },
(collections) => {
assert.equal(collections.articles.length, 3);
done();
},
);
});
});
});
describe('methods', function () { describe('methods', function () {
let userId; let userId;
let userStructure; let userStructure;
...@@ -110,17 +228,17 @@ describe('articles', function () { ...@@ -110,17 +228,17 @@ describe('articles', function () {
email, email,
username: email, username: email,
password: 'toto', password: 'toto',
structure: `userId_${Random.id()}`, structure: Random.id(),
firstName: faker.name.firstName(), firstName: faker.person.firstName(),
lastName: faker.name.lastName(), lastName: faker.person.lastName(),
}); });
otherUserId = Accounts.createUser({ otherUserId = Accounts.createUser({
email: faker.internet.email(), email: faker.internet.email(),
username: 'otherUser', username: 'otherUser',
password: 'toto', password: 'toto',
structure: Random.id(), structure: Random.id(),
firstName: faker.name.firstName(), firstName: faker.person.firstName(),
lastName: faker.name.lastName(), lastName: faker.person.lastName(),
}); });
// set users as active // set users as active
Meteor.users.update({}, { $set: { isActive: true } }, { multi: true }); Meteor.users.update({}, { $set: { isActive: true } }, { multi: true });
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.