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
Commits on Source (136)
Showing
with 333 additions and 106 deletions
......@@ -69,8 +69,7 @@ cache-dependencies:
# This job update dependencies
policy: pull-push
script:
- meteor npm ci && meteor npm install
- meteor npm install
###############################################################################
# `test` stage: `meteor-lint`, `meteor-tests`
......
......@@ -30,7 +30,7 @@
"ignorePatterns": ["packages/**/*.js", "packages/**/*.jsx"],
"rules": {
"import/prefer-default-export": "off",
"no-restricted-imports": ["error", "@material-ui/core", "@material-ui/icons", "@material-ui/lab"],
"no-restricted-imports": ["error", "@mui/material", "@mui/icons-material", "@material-ui/lab"],
"no-underscore-dangle": "off",
"react/no-danger": "off",
"react/jsx-props-no-spreading": "off",
......
......@@ -3,11 +3,12 @@
"reporters": ["console"],
"ignore": [
"**/node_modules/**",
"**/.meteor/**",
"./packages/**",
"./i18n/*.json",
"**/.meteor/**",
"./packages/**",
"./i18n/*.json",
"**/*.svg",
"**.test.js",
"*/**/**/themes",
"*/**/**.tests.jsx",
"*/**/**.tests.js"
],
......
......@@ -101,6 +101,10 @@ Articles.schema = new SimpleSchema(
type: SimpleSchema.Integer,
defaultValue: 0,
},
licence: {
type: String,
defaultValue: '',
},
},
{ clean: { removeEmptyStrings: false }, tracker: Tracker },
);
......@@ -119,6 +123,7 @@ Articles.publicFields = {
visits: 1,
tags: 1,
structure: 1,
licence: 1,
};
Articles.attachSchema(Articles.schema);
......
......@@ -500,3 +500,18 @@ Migrations.add({
Structures.rawCollection().updateMany({}, { $unset: { introduction: 1 } }, { multi: true });
},
});
Migrations.add({
version: 26,
name: 'Add licence to articles',
up: () => {
Articles.find({})
.fetch()
.forEach((article) => {
Articles.update({ _id: article._id }, { $set: { licence: '' } });
});
},
down: () => {
Articles.rawCollection().updateMany({}, { $unset: { licence: 1 } }, { multi: true });
},
});
......@@ -14,34 +14,37 @@ import { addService, removeElement } from '../personalspaces/methods';
export const createService = new ValidatedMethod({
name: 'services.createService',
validate: Services.schema.omit('slug').validator({ clean: true }),
validate: new SimpleSchema({
data: Services.schema.omit('slug'),
}).validator({ clean: true }),
run(args) {
run({ data }) {
// admins can create structure services only for their structure if they have adminStructure permissions
const isStructureAdmin =
args.structure && hasAdminRightOnStructure({ userId: this.userId, structureId: args.structure });
data.structure && hasAdminRightOnStructure({ userId: this.userId, structureId: data.structure });
const isAdmin = Roles.userIsInRole(this.userId, 'admin');
const authorized = isActive(this.userId) && (isAdmin || isStructureAdmin);
if (!authorized) {
throw new Meteor.Error('api.services.createService.notPermitted', i18n.__('api.users.adminNeeded'));
}
const sv = Services.findOne({ slug: slugy(args.title), structure: args.structure });
const sv = Services.findOne({ slug: slugy(data.title), structure: data.structure });
if (sv !== undefined) {
throw new Meteor.Error(
'api.services.createService.ServiceAlreadyExists',
i18n.__('api.services.ServiceAlreadyExists'),
);
}
const serviceId = Services.insert(args);
const serviceId = Services.insert(data);
Services.update(serviceId, {
$set: {
logo: args.logo.replace('/undefined/', `/${serviceId}/`),
screenshots: args.screenshots.map((screen) => screen.replace('/undefined/', `/${serviceId}/`)),
logo: data.logo.replace('/undefined/', `/${serviceId}/`),
screenshots: data.screenshots.map((screen) => screen.replace('/undefined/', `/${serviceId}/`)),
},
});
if (Meteor.isServer && !Meteor.isTest && Meteor.settings.public.minioEndPoint) {
const files = [args.logo, ...args.screenshots];
const files = [data.logo, ...data.screenshots];
try {
Meteor.call('files.move', {
sourcePath: 'services/undefined',
......
......@@ -202,23 +202,25 @@ describe('services', function () {
// add service to userId favorites
Meteor.users.update({ _id: userId }, { $set: { favServices: [serviceId, structureServiceId] } });
chatData = {
title: 'Chat sur un nuage de liconre',
description: "Chevaucher un dragon rose à pois. C'est en fait une fée pour piéger Peter Pan",
url: 'https://chat.licorne.ovh',
logo: 'https://rocket.chat/images/default/logo--dark.svg',
categories: [],
team: 'Dijon',
usage: 'Discuter en Troubadour',
screenshots: [],
content: "<div>c'est un service de fou</div>",
state: 0,
structure: '',
data: {
title: 'Chat sur un nuage de liconre',
description: "Chevaucher un dragon rose à pois. C'est en fait une fée pour piéger Peter Pan",
url: 'https://chat.licorne.ovh',
logo: 'https://rocket.chat/images/default/logo--dark.svg',
categories: [],
team: 'Dijon',
usage: 'Discuter en Troubadour',
screenshots: [],
content: "<div>c'est un service de fou</div>",
state: 0,
structure: '',
},
};
});
describe('createService', function () {
it('does create a service with admin user', function () {
createService._execute({ userId: adminId }, chatData);
const service = Services.findOne({ title: chatData.title });
const service = Services.findOne({ title: chatData.data.title });
assert.typeOf(service, 'object');
});
it("does not create a service if you're not admin", function () {
......@@ -239,27 +241,27 @@ describe('services', function () {
);
});
it('does create a structure specific service with adminStructure user', function () {
createService._execute({ userId: adminStructureId }, { ...chatData, structure: 'maStructure' });
const service = Services.findOne({ title: chatData.title });
createService._execute({ userId: adminStructureId }, { data: { ...chatData.data, structure: 'maStructure' } });
const service = Services.findOne({ title: chatData.data.title });
assert.typeOf(service, 'object');
});
it('does create a structure specific service with adminStructure user', function () {
createService._execute({ userId: adminId }, { ...chatData, structure: 'uneStructure' });
const service = Services.findOne({ title: chatData.title });
createService._execute({ userId: adminId }, { data: { ...chatData.data, structure: 'uneStructure' } });
const service = Services.findOne({ title: chatData.data.title });
assert.typeOf(service, 'object');
});
it("does not create a structure specific service if you're not adminStructure or admin", function () {
// Throws if non admin user, or logged out user, tries to create a service
assert.throws(
() => {
createService._execute({ userId }, { ...chatData, structure: 'maStructure' });
createService._execute({ userId }, { data: { ...chatData.data, structure: 'maStructure' } });
},
Meteor.Error,
/api.services.createService.notPermitted/,
);
assert.throws(
() => {
createService._execute({}, { ...chatData, structure: 'maStructure' });
createService._execute({}, { data: { ...chatData.data, structure: 'maStructure' } });
},
Meteor.Error,
/api.services.createService.notPermitted/,
......@@ -269,7 +271,10 @@ describe('services', function () {
// Throws if non admin user, or logged out user, tries to create a service
assert.throws(
() => {
createService._execute({ userId: adminStructureId }, { ...chatData, structure: 'autreStructure' });
createService._execute(
{ userId: adminStructureId },
{ data: { ...chatData.data, structure: 'autreStructure' } },
);
},
Meteor.Error,
/api.services.createService.notPermitted/,
......
......@@ -55,7 +55,7 @@ Services.schema = new SimpleSchema(
},
state: {
type: SimpleSchema.Integer,
allowedValues: [0, 5, 10], // 0 displayed, 5 inactive, 10 invisible
allowedValues: [0, 5, 10, 15], // 0 displayed, 5 inactive, 10 invisible, 15 maintenance
label: getLabel('api.services.labels.state'),
},
categories: { type: Array, defaultValue: [], label: getLabel('api.services.labels.categories') },
......@@ -81,6 +81,7 @@ Services.stateLabels = {
0: 'api.services.states.displayed',
5: 'api.services.states.inactive',
10: 'api.services.states.invisible',
15: 'api.services.states.maintenance',
};
Services.publicFields = {
......
import { Email } from 'meteor/email';
import sanitizeHtml from 'sanitize-html';
import i18n from 'meteor/universe:i18n';
import { DDPRateLimiter } from 'meteor/ddp-rate-limiter';
import { _ } from 'meteor/underscore';
import SimpleSchema from 'simpl-schema';
import { ValidatedMethod } from 'meteor/mdg:validated-method';
import Structures from '../structures/structures';
import { getTargetMail } from './utils';
Meteor.startup(function startSmtp() {
process.env.MAIL_URL = Meteor.settings.smtp.url;
});
Meteor.methods({
sendContactEmail(firstName, lastName, email, text, structureSelect) {
check([firstName, lastName, email, text, structureSelect], [String]);
export const sendContactEmail = new ValidatedMethod({
name: 'smtp.sendContactEmail',
validate: new SimpleSchema({
firstName: {
type: String,
},
lastName: {
type: String,
},
email: {
type: String,
regEx: SimpleSchema.RegEx.Email,
},
text: {
type: String,
},
structureId: {
type: String,
regEx: SimpleSchema.RegEx.Id,
},
}).validator(),
run({ firstName, lastName, email, text, structureId }) {
const structure = Structures.findOne({ _id: structureId });
if (structure === undefined) {
throw new Meteor.Error('api.smtp.sendContactEmail.unknownStructure', i18n.__('api.structures.unknownStructure'));
}
const object = `[Contact LaBoite] ${firstName} ${lastName} (${structureSelect})`;
const { appName = 'LaBoite' } = Meteor.settings.public;
const object = `[Contact ${appName}] ${firstName} ${lastName} (${structure.name})`;
const cleanText = sanitizeHtml(text, {
allowedTags: ['b', 'i', 'strong', 'em'],
});
const msg = `Message de: ${firstName} ${lastName}
Structure de rattachement: ${structureSelect}
Structure de rattachement: ${structure.name}
Adresse mail: ${email}
${cleanText}`;
const tabTo = Meteor.roleAssignment
.find({ 'role._id': 'adminStructure', scope: structureSelect })
.find({ 'role._id': 'adminStructure', scope: structureId })
.fetch()
.map((role) => Meteor.users.findOne({ _id: role.user._id }).emails[0].address);
const from = Meteor.settings.smtp.fromEmail;
const to = Meteor.settings.smtp.toEmail;
const structureTargetMail = getTargetMail({ structure });
// if a structure contact mail if found, use it
// if not, use settings one
const to = structureTargetMail || Meteor.settings.smtp.toEmail;
this.unblock();
......@@ -39,3 +73,24 @@ ${cleanText}`;
}
},
});
// Get list of all method names on Helps
const LISTS_METHODS = _.pluck([sendContactEmail], 'name');
if (Meteor.isServer) {
// Only allow 5 list operations per connection per second
DDPRateLimiter.addRule(
{
name(name) {
return _.contains(LISTS_METHODS, name);
},
// Rate limit per connection ID
connectionId() {
return true;
},
},
5,
1000,
);
}
import Structures from '../structures/structures';
/**
* - Check first if structure has a contact email
* - If not, check if ancestors have one
* - I nothing find, return null
*/
export const getTargetMail = ({ structure }) => {
const { contactEmail } = structure;
if (contactEmail !== null) return contactEmail;
const mails = Structures.find({ _id: { $in: structure.ancestorsIds } }, { fields: { contactEmail: 1 } }).fetch();
// reverse the array since we get the structures in descending order
const result = mails.reverse().find((mail) => mail.contactEmail !== null);
return result || null;
};
......@@ -198,6 +198,35 @@ export const getAllChilds = new ValidatedMethod({
},
});
export const updateStructureContactEmail = new ValidatedMethod({
name: 'structures.updateContactEmail',
validate: new SimpleSchema({
contactEmail: {
type: String,
regEx: SimpleSchema.RegEx.Email,
},
structureId: { type: String, regEx: SimpleSchema.RegEx.Id, label: getLabel('api.structures.labels.id') },
}).validator(),
run({ structureId, contactEmail }) {
const structure = Structures.findOne({ _id: structureId });
if (structure === undefined) {
throw new Meteor.Error(
'api.structures.updateContactEmail.unknownStructure',
i18n.__('api.structures.unknownStructure'),
);
}
const authorized = isActive(this.userId) && hasAdminRightOnStructure({ userId: this.userId, structureId });
if (!authorized) {
throw new Meteor.Error('api.structures.updateContactEmail.notPermitted', i18n.__('api.users.notPermitted'));
}
return Structures.update({ _id: structureId }, { $set: { contactEmail } });
},
});
export const updateStructureIntroduction = new ValidatedMethod({
name: 'structures.updateIntroduction',
validate: new SimpleSchema({
......@@ -248,7 +277,14 @@ export const updateStructureIntroduction = new ValidatedMethod({
// Get list of all method names on Structures
const LISTS_METHODS = _.pluck(
[createStructure, updateStructure, removeStructure, getAllChilds, updateStructureIntroduction],
[
createStructure,
updateStructure,
removeStructure,
getAllChilds,
updateStructureIntroduction,
updateStructureContactEmail,
],
'name',
);
......
......@@ -5,4 +5,6 @@ import Structures from '../structures';
Factory.define('structure', Structures, {
name: faker.company.companyName(),
parentId: null,
ancestorsIds: [],
childrenIds: [],
});
......@@ -86,6 +86,13 @@ Structures.schema = new SimpleSchema(
'introduction.$': {
type: IntroductionSchema,
},
contactEmail: {
type: String,
label: getLabel('api.structures.labels.contactEmail'),
optional: true,
defaultValue: null,
regEx: SimpleSchema.RegEx.Email,
},
},
{
tracker: Tracker,
......@@ -99,6 +106,7 @@ Structures.publicFields = {
childrenIds: 1,
ancestorsIds: 1,
introduction: 1,
contactEmail: 1,
};
Structures.attachSchema(Structures.schema);
......
......@@ -20,6 +20,7 @@ import { getRandomNCloudURL } from '../../nextcloud/methods';
import Structures from '../../structures/structures';
import Nextcloud from '../../nextcloud/nextcloud';
import { hasAdminRightOnStructure } from '../../structures/utils';
import EventsAgenda from '../../eventsAgenda/eventsAgenda';
if (Meteor.settings.public.enableKeycloak === true) {
const { whiteDomains } = Meteor.settings.private;
......@@ -193,6 +194,32 @@ export const removeUser = new ValidatedMethod({
},
});
export const removeUserFromStructure = new ValidatedMethod({
name: 'users.removeUserFromStructure',
validate: new SimpleSchema({
userId: validateSchema.userId,
}).validator(),
run({ userId }) {
const user = Meteor.users.findOne({ _id: userId });
// check if current user has structure admin rights or self removal
const authorized =
isActive(this.userId) &&
(hasAdminRightOnStructure({ userId: this.userId, structureId: user.structure }) || userId === this.userId);
if (!authorized) {
throw new Meteor.Error('api.users.removeUserFromStructure.notPermitted', i18n.__('api.users.notPermitted'));
}
// check user existence
if (user === undefined) {
throw new Meteor.Error('api.users.removeUserFromStructure.unknownUser', i18n.__('api.users.unknownUser'));
}
if (Roles.userIsInRole(userId, 'adminStructure', user.structure)) {
Roles.removeUsersFromRoles(userId, 'adminStructure', user.structure);
}
Meteor.users.update({ _id: userId }, { $set: { structure: null } });
},
});
export const setUsername = new ValidatedMethod({
name: 'users.setUsername',
validate: new SimpleSchema({
......@@ -696,6 +723,15 @@ export const setMemberOf = new ValidatedMethod({
}
// update user personalSpace
favGroup._execute({ userId }, { groupId });
const insertUser = { email: user.emails[0].address, _id: userId, groupId, status: 1 };
// update Events
EventsAgenda.rawCollection().updateMany(
{ groups: { $elemMatch: { _id: groupId } } },
{ $push: { participants: insertUser } },
);
// Notify user
if (this.userId !== userId) createRoleNotification(this.userId, userId, groupId, 'member', true);
},
......@@ -1015,6 +1051,7 @@ const LISTS_METHODS = _.pluck(
setArticlesEnable,
setActive,
removeUser,
removeUserFromStructure,
setAdminOf,
unsetAdminOf,
setAdminStructure,
......
......@@ -34,6 +34,7 @@ import {
toggleAdvancedPersonalPage,
setArticlesEnable,
resetAuthToken,
removeUserFromStructure,
} from './methods';
import Groups from '../../groups/groups';
import PersonalSpaces from '../../personalspaces/personalspaces';
......@@ -721,6 +722,36 @@ describe('users', function () {
);
});
});
describe('removeUserFromStructure', function () {
it('structure admin can remove an existing user and associated data', function () {
// set admin as a structure admin
Meteor.users.update({ _id: userId }, { $set: { structure: 'test' } });
Meteor.users.update({ _id: adminId }, { $set: { structure: 'test' } });
setAdminStructure._execute({ userId: adminId }, { userId: adminId });
// check that user data exists before deletion
removeUserFromStructure._execute({ userId: adminId }, { userId });
const user = Meteor.users.findOne(userId);
// check that personalspace, roles and group entries are removed
assert.equal(user.structure, null);
});
it('only structure admin can remove another user from structure', function () {
// Throws if non admin user, or logged out user
assert.throws(
() => {
removeUserFromStructure._execute({ userId }, { userId: adminId });
},
Meteor.Error,
/api.users.removeUserFromStructure.notPermitted/,
);
assert.throws(
() => {
removeUserFromStructure._execute({}, { userId });
},
Meteor.Error,
/api.users.removeUserFromStructure.notPermitted/,
);
});
});
describe('(un)setActive', function () {
it('global admin can set a user as active/not active', function () {
let user = Meteor.users.findOne(userId);
......
......@@ -112,7 +112,8 @@
"title": "Structure introduction title",
"content": "Structure introduction content",
"language": "Structure introduction language"
}
},
"contactEmail": "Structure contact email"
}
},
"users": {
......@@ -196,7 +197,8 @@
"states": {
"displayed": "displayed",
"inactive": "inactive",
"invisible": "invisible"
"invisible": "invisible",
"maintenance" : "maintenance"
},
"labels": {
"id": "Service Id",
......@@ -548,7 +550,7 @@
"menuAdminBackHome": "Back to Personnal Space",
"menuUserStructure": "Structures Management",
"menuAdminOfStructures": "Sub structures Management",
"menuAdminStructureIntroduction": "Structure introduction"
"menuAdminStructureSettings": "Structure settings"
},
"NotValidatedMessage": {
"inactiveAccount": "Your account has not been activated",
......@@ -825,6 +827,9 @@
"title": "Title (optional)",
"content": "Content"
}
},
"AdminStructureChangeEmailContact": {
"label": "Email de contact"
}
},
"validatejs": {
......@@ -897,6 +902,7 @@
}
},
"SignIn": {
"back":"Go back",
"appDescription": "Digital services shared by National Education agents",
"appVersion": "Test Alpha 0.1 Version",
"emailLabel": "Username or Email",
......@@ -1008,7 +1014,9 @@
"viewSimple": "Simple view",
"endOfList": "End of the list",
"filterGroup": "Show only joined groups",
"noGroup": "There is no group to display."
"noGroup": "There is no group to display.",
"addEvent": "Add new event",
"addPoll": "Add new poll"
},
"AdminHome": {
"title": "Administration Page",
......@@ -1177,6 +1185,7 @@
"categories": "Categories",
"open": "Open",
"inactive": "Inactive service",
"maintenance" : "Service on Maintenance",
"propulsedBy": "Propulsed by"
},
"PersonalPage": {
......@@ -1315,12 +1324,22 @@
"selectTag": "Add",
"save_draf": "Save Draft",
"draft": "Draft",
"license": "License",
"createTag": "Create",
"CloseEditArticle": {
"title": "Discard changes",
"mainText": "Do you really want to close this page ? Any unsaved changes will be lost.",
"confirm": "Confirm",
"cancel": "Cancel"
},
"licenceInfo": "For more information about licenses, check the documentation on the Creative Commons website: ",
"Licences": {
"CC_BY": "Attribution",
"CC_BY-SA": "Attribution-ShareAlike",
"CC_BY-ND": "Attribution-NoDerivatives",
"CC_BY-NC": "Attribution-NonCommercial",
"CC_BY-NC-SA": "Attribution-NonCommercial-ShareAlike",
"CC_BY-NC-ND": "Attribution-NonCommercial-NoDerivatives"
}
},
"PublicArticlePage": {
......@@ -1380,8 +1399,8 @@
"informationsOf": "Informations of",
"titleStructures": "Structures informations"
},
"AdminIntroductionByStructurePage": {
"title": "Structure's introduction texts"
"AdminStructureSettingsPage": {
"title": "Structure settings"
}
},
"layouts": {
......
......@@ -112,7 +112,8 @@
"title": "Titre d'introduction de structure",
"content": "Contenu d'introduction de structure",
"language": "Language d'introduction de structure"
}
},
"contactEmail": "Email de contact de la structure"
}
},
"users": {
......@@ -126,7 +127,7 @@
"logWhiteDomains": "Les utilisateurs correspondant à ces domaines seront activés à leur connexion: {$domains}",
"labels": {
"id": "Id Utilisateur",
"username": "Pseudonyme",
"username": "Nom d'utilisateur",
"firstName": "Prénom",
"lastName": "Nom",
"emails": "Adresse Électronique",
......@@ -196,7 +197,8 @@
"states": {
"displayed": "affiché",
"inactive": "inactif",
"invisible": "caché"
"invisible": "caché",
"maintenance" : "maintenance"
},
"labels": {
"id": "Id de Service",
......@@ -548,7 +550,7 @@
"menuAdminBackHome": "Retour à l'espace perso",
"menuUserStructure": "Gestion des Structures",
"menuAdminOfStructures": "Gestion des sous-structures",
"menuAdminStructureIntroduction": "Introduction de structure"
"menuAdminStructureSettings": "Réglages de structure"
},
"NotValidatedMessage": {
"inactiveAccount": "Votre compte n'a pas été activé",
......@@ -828,6 +830,9 @@
"title": "Titre (facultatif)",
"content": "Contenu"
}
},
"AdminStructureChangeEmailContact": {
"label": "Email de contact"
}
},
"validatejs": {
......@@ -900,6 +905,7 @@
}
},
"SignIn": {
"back": "Retour",
"appDescription": "Les services numériques partagés des agents de l&apos;Éducation nationale",
"appVersion": "Version Test Alpha 0.1",
"emailLabel": "Identifiant ou Courriel",
......@@ -1011,7 +1017,9 @@
"viewSimple": "Mode simple",
"endOfList": "Fin de la liste",
"filterGroup": "Afficher uniquement les groupes rejoints",
"noGroup": "Il n'y a aucun groupe à afficher."
"noGroup": "Il n'y a aucun groupe à afficher.",
"addEvent": "Ajouer un nouvel événement",
"addPoll": "Ajouter un nouveau sondage"
},
"AdminHome": {
"title": "Interface d'administration",
......@@ -1180,6 +1188,7 @@
"categories": "Catégories",
"open": "Ouvrir",
"inactive": "Service inactif",
"maintenance" : "Service en maintenance",
"propulsedBy": "Propulsé par"
},
"PersonalPage": {
......@@ -1317,12 +1326,22 @@
"selectTag": "Ajouter",
"save_draf": "Enregistrer le brouillon",
"draft": "Brouillon",
"license": "Licence",
"createTag": "Créer",
"CloseEditArticle": {
"title": "Annuler les modifications",
"mainText": "Souhaitez-vous réellement fermer cette page ? Toutes les modifications non enregistrées seront perdues.",
"confirm": "Confirmer",
"cancel": "Annuler"
},
"licenceInfo": "Pour plus d'informations sur les licences, consultez la documentation sur le site Creative Commons: ",
"Licences": {
"CC_BY": "Attribution",
"CC_BY-SA": "Attribution - Partage dans les Mêmes Conditions",
"CC_BY-ND": "Attribution - Pas de Modification",
"CC_BY-NC": "Attribution - Pas d’Utilisation Commerciale",
"CC_BY-NC-SA": "Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions",
"CC_BY-NC-ND": "Pas d’Utilisation Commerciale - Pas de Modification"
}
},
"PublicArticlePage": {
......@@ -1382,8 +1401,8 @@
"informationsOf": "Informations de",
"titleStructures": "Informations de structures"
},
"AdminIntroductionByStructurePage": {
"title": "Texte d'introduction de structure"
"AdminStructureSettingsPage": {
"title": "Paramétrage de la structure"
}
},
"layouts": {
......
......@@ -7,7 +7,7 @@ import logServer from '../../../api/logging';
function createStructure(structure) {
logServer(` Creating structure `);
logServer(structure);
Structures.insert(structure);
return Structures.insert(structure);
}
/** When running app for first time, pass a settings file to set up a default user account. */
......@@ -16,8 +16,8 @@ if (Structures.find().count() === 0) {
logServer('Creating the default structures');
if (fakeData.defaultStructures !== undefined) {
fakeData.defaultStructures.forEach((structure) => {
createStructure(structure);
Roles.createRole(structure._id);
const structureId = createStructure(structure);
Roles.createRole(structureId);
});
}
} else {
......
......@@ -4,14 +4,12 @@
"email": "admin@ac-dijon.fr",
"password": "changeme",
"role": "admin",
"structure": "EviKfwAnFtcjEWFdz",
"firstName": "Jean",
"lastName": "Dupont"
},
{
"email": "eole@ac-dijon.fr",
"password": "changeme",
"structure": "EviKfwAnFtcjEWFdz",
"firstName": "Guy",
"lastName": "Durand"
}
......@@ -256,147 +254,126 @@
],
"defaultStructures": [
{
"_id": "EviKfwznFZcjEWFdz",
"name": "Ministère Education",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfwAnFZcrEWFdz",
"name": "Éducation",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfwgnFZcjEWFdz",
"name": "Auvergne-Rhône-Alpes",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKdwAnFZcjEWFdz",
"name": "Bourgogne-Franche-Comté",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfwqdFZcjEWFdz",
"name": "Bretagne",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfwAnFtcjEWFdz",
"name": "Centre-Val de Loire",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EbiKfwAnFZcjEWFdz",
"name": "Corse",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfwAnFrcjEWFdz",
"name": "Grand Est",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfwAnFZcjEWFdm",
"name": "Guadeloupe",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfwAnFZcjlWFdz",
"name": "Guyane",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfoioFZcjEWFdz",
"name": "Hauts-de-France",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfwAnFZcjuWFdz",
"name": "Île-de-France",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfdsnFZcjEWFdz",
"name": "Martinique",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfwAnFZcjEazdz",
"name": "Normandie",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfwAnFZcjEWFde",
"name": "Nouvelle-Aquitaine",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfwAnFZcjEWFdc",
"name": "Occitanie",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfwAnFZcjEWsqz",
"name": "Pays de la Loire",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EvijfwAnFZcjEWFdz",
"name": "Provence-Alpes-Côte d'Azur",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfwAnfbcjEWFdz",
"name": "La Réunion",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfwAnzfcjEWFdz",
"name": "Collectivité",
"parentId": null,
"childrenIds": [],
"ancestorsIds": []
},
{
"_id": "EviKfwAnFZcxEWFdz",
"name": "Autre",
"parentId": null,
"childrenIds": [],
......
import React from 'react';
import i18n from 'meteor/universe:i18n';
import { makeStyles } from '@material-ui/core/styles';
import Card from '@material-ui/core/Card';
import CardHeader from '@material-ui/core/CardHeader';
import CardActions from '@material-ui/core/CardActions';
import IconButton from '@material-ui/core/IconButton';
import Button from '@material-ui/core/Button';
import Modal from '@material-ui/core/Modal';
import ClearIcon from '@material-ui/icons/Clear';
import { makeStyles } from 'tss-react/mui';
import Card from '@mui/material/Card';
import CardHeader from '@mui/material/CardHeader';
import CardActions from '@mui/material/CardActions';
import IconButton from '@mui/material/IconButton';
import Button from '@mui/material/Button';
import Modal from '@mui/material/Modal';
import ClearIcon from '@mui/icons-material/Clear';
import PropTypes from 'prop-types';
import CardContent from '@material-ui/core/CardContent';
import Typography from '@material-ui/core/Typography';
import CardContent from '@mui/material/CardContent';
import Typography from '@mui/material/Typography';
import { useHistory } from 'react-router-dom';
import { useAppContext } from '../../contexts/context';
import COMMON_STYLES from '../../themes/styles';
const useStyles = (isMobile) =>
makeStyles((theme) => ({
root: COMMON_STYLES.root,
actions: COMMON_STYLES.actions,
paper: COMMON_STYLES.paper(isMobile),
groupCountInfo: COMMON_STYLES.groupCountInfo,
buttonGroup: {
display: 'flex',
justifyContent: 'space-between',
marginTop: theme.spacing(5),
},
alert: COMMON_STYLES.alert,
}));
const useStyles = makeStyles()((theme, isMobile) => ({
root: COMMON_STYLES.root,
actions: COMMON_STYLES.actions,
paper: COMMON_STYLES.paper(isMobile),
groupCountInfo: COMMON_STYLES.groupCountInfo,
buttonGroup: {
display: 'flex',
justifyContent: 'space-between',
marginTop: theme.spacing(5),
},
alert: COMMON_STYLES.alert,
}));
const AdminGroupDelete = ({ group, open, onClose }) => {
const [{ isMobile }] = useAppContext();
const history = useHistory();
const classes = useStyles(isMobile)();
const { classes } = useStyles(isMobile);
const removeGroup = () => {
Meteor.call('groups.removeGroup', { groupId: group._id }, (err) => {
if (err) {
......@@ -54,7 +53,7 @@ const AdminGroupDelete = ({ group, open, onClose }) => {
<CardHeader
title={i18n.__('components.AdminGroupDelete.subtitle')}
action={
<IconButton onClick={onClose}>
<IconButton onClick={onClose} size="large">
<ClearIcon />
</IconButton>
}
......