diff --git a/client/components/settings/settingBody.jade b/client/components/settings/settingBody.jade index f9d66c884..bdb242f8c 100644 --- a/client/components/settings/settingBody.jade +++ b/client/components/settings/settingBody.jade @@ -184,6 +184,10 @@ template(name='layoutSettings') .title {{_ 'oidc-button-text'}} .form-group input.wekan-form-control#oidcBtnTextvalue(type="text", placeholder="" value="{{currentSetting.oidcBtnText}}") + li.layout-form + .title {{_ 'can-invite-if-same-mailDomainName'}} + .form-group + input.wekan-form-control#mailDomaineNamevalue(type="text", placeholder="" value="{{currentSetting.mailDomaineName}}") li.layout-form .title {{_ 'display-authentication-method'}} .form-group.flex diff --git a/client/components/settings/settingBody.js b/client/components/settings/settingBody.js index c857f3ed1..157f7ac54 100644 --- a/client/components/settings/settingBody.js +++ b/client/components/settings/settingBody.js @@ -205,6 +205,11 @@ BlazeComponent.extendComponent({ ) .val() .trim(); + const mailDomaineName = $( + '#mailDomaineNamevalue', + ) + .val() + .trim(); const hideLogoChange = $('input[name=hideLogo]:checked').val() === 'true'; const displayAuthenticationMethod = $('input[name=displayAuthenticationMethod]:checked').val() === 'true'; @@ -228,6 +233,7 @@ BlazeComponent.extendComponent({ automaticLinkedUrlSchemes, spinnerName, oidcBtnText, + mailDomaineName, }, }); } catch (e) { diff --git a/client/components/users/userHeader.jade b/client/components/users/userHeader.jade index d5fe14739..4d7bd89a5 100644 --- a/client/components/users/userHeader.jade +++ b/client/components/users/userHeader.jade @@ -49,6 +49,11 @@ template(name="memberMenuPopup") i.fa.fa-lock | {{_ 'admin-panel'}} hr + if isSameDomainNameSettingValue + li + a.js-invite-people + i.fa.fa-envelope + | {{_ 'invite-people'}} if isNotOAuth2AuthenticationMethod li a.js-edit-profile @@ -80,6 +85,30 @@ template(name="memberMenuPopup") i.fa.fa-sign-out | {{_ 'log-out'}} +template(name="invitePeoplePopup") + ul#registration-setting.setting-detail + li + #invite-people-infos + li + br + li + .invite-people(class="{{#if currentSetting.disableRegistration}}{{else}}hide{{/if}}") + ul + li + .title {{_ 'invite-people'}} + textarea#email-to-invite.wekan-form-control(rows='5', placeholder="{{_ 'email-addresses'}}") + li + .title {{_ 'to-boards'}} + .bg-white + each boards + a.option.flex.js-toggle-board-choose(id= _id) + .materialCheckBox(data-id= _id) + + span= title + + li + button.js-email-invite.primary {{_ 'invite'}} + template(name="editProfilePopup") form label diff --git a/client/components/users/userHeader.js b/client/components/users/userHeader.js index 08056e054..3d0679a78 100644 --- a/client/components/users/userHeader.js +++ b/client/components/users/userHeader.js @@ -3,6 +3,12 @@ Template.headerUserBar.events({ 'click .js-change-avatar': Popup.open('changeAvatar'), }); +BlazeComponent.extendComponent({ + onCreated() { + Meteor.subscribe('setting'); + }, +}).register('memberMenuPopup'); + Template.memberMenuPopup.helpers({ templatesBoardId() { currentUser = Meteor.user(); @@ -22,6 +28,26 @@ Template.memberMenuPopup.helpers({ return false; } }, + isSameDomainNameSettingValue(){ + const currSett = Settings.findOne(); + if(currSett && currSett != undefined && currSett.disableRegistration && currSett.mailDomaineName !== undefined && currSett.mailDomaineName != ""){ + currentUser = Meteor.user(); + if (currentUser) { + let found = false; + for(let i = 0; i < currentUser.emails.length; i++) { + if(currentUser.emails[i].address.endsWith(currSett.mailDomaineName)){ + found = true; + break; + } + } + return found; + } else { + return true; + } + } + else + return false; + }, isNotOAuth2AuthenticationMethod(){ currentUser = Meteor.user(); if (currentUser) { @@ -42,6 +68,7 @@ Template.memberMenuPopup.events({ 'click .js-open-archived-board'() { Modal.open('archivedBoards'); }, + 'click .js-invite-people': Popup.open('invitePeople'), 'click .js-edit-profile': Popup.open('editProfile'), 'click .js-change-settings': Popup.open('changeSettings'), 'click .js-change-avatar': Popup.open('changeAvatar'), @@ -57,6 +84,66 @@ Template.memberMenuPopup.events({ }, }); +BlazeComponent.extendComponent({ + onCreated() { + Meteor.subscribe('setting'); + }, +}).register('editProfilePopup'); + +Template.invitePeoplePopup.events({ + 'click a.js-toggle-board-choose'(event){ + let target = $(event.target); + if (!target.hasClass('js-toggle-board-choose')) { + target = target.parent(); + } + const checkboxId = target.attr('id'); + $(`#${checkboxId} .materialCheckBox`).toggleClass('is-checked'); + $(`#${checkboxId}`).toggleClass('is-checked'); + }, + 'click button.js-email-invite'(event){ + const emails = $('#email-to-invite') + .val() + .toLowerCase() + .trim() + .split('\n') + .join(',') + .split(','); + const boardsToInvite = []; + $('.js-toggle-board-choose .materialCheckBox.is-checked').each(function() { + boardsToInvite.push($(this).data('id')); + }); + const validEmails = []; + emails.forEach(email => { + if (email && SimpleSchema.RegEx.Email.test(email.trim())) { + validEmails.push(email.trim()); + } + }); + if (validEmails.length) { + Meteor.call('sendInvitation', validEmails, boardsToInvite, (_, rc) => { + if (rc == 0) { + let divInfos = document.getElementById("invite-people-infos"); + if(divInfos && divInfos !== undefined){ + divInfos.innerHTML = "" + TAPi18n.__('invite-people-success') + ""; + } + } + else{ + let divInfos = document.getElementById("invite-people-infos"); + if(divInfos && divInfos !== undefined){ + divInfos.innerHTML = "" + TAPi18n.__('invite-people-error') + ""; + } + } + // Popup.close(); + }); + } + }, +}); + +Template.invitePeoplePopup.helpers({ + currentSetting() { + return Settings.findOne(); + }, +}); + Template.editProfilePopup.helpers({ allowEmailChange() { Meteor.call('AccountSettings.allowEmailChange', (_, result) => { diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index a8592d61d..0f3d8eb3b 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -1095,5 +1095,7 @@ "remove-team-from-table": "Are you sure you want to remove this team from the board ?", "confirm-btn": "Confirm", "remove-btn": "Remove", - "filter-card-title-label": "Filter by card title" + "invite-people-success": "Invitation for inscription sent wiht success", + "invite-people-error": "Error while sending inscription invitation", + "can-invite-if-same-mailDomainName": "E-mail domain name" } diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index 19eb994bd..be71a95fd 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -1091,8 +1091,10 @@ "cardDetailsPopup-title": "Détails de la carte", "add-teams": "Ajouter des équipes", "add-teams-label": "Les équipes ajoutées sont affichées ci-dessous :", - "remove-team-from-table": "Voulez-vous vraiment supprimer cette équipe du tableau ?", - "confirm-btn": "Confirmer", + "remove-team-from-table": "Are you sure you want to remove this team from the board ?", + "confirm-btn": "Confirm", "remove-btn": "Supprimer", - "filter-card-title-label": "Filtrer par titre de carte" -} \ No newline at end of file + "invite-people-success": "L'invitation à l'inscription a été envoyé avec succèss", + "invite-people-error": "Erreur lors de l'envoie d'une invitation à l'inscription", + "can-invite-if-same-mailDomainName": "Nom de domaine" +} diff --git a/models/settings.js b/models/settings.js index 60dbe8134..46eda7df5 100644 --- a/models/settings.js +++ b/models/settings.js @@ -88,6 +88,10 @@ Settings.attachSchema( type: String, optional: true, }, + mailDomaineName: { + type: String, + optional: true, + }, createdAt: { type: Date, denyUpdate: true, @@ -290,11 +294,13 @@ if (Meteor.isServer) { Meteor.methods({ sendInvitation(emails, boards) { + let rc = 0; check(emails, [String]); check(boards, [String]); const user = Users.findOne(Meteor.userId()); if (!user.isAdmin) { + rc = -1; throw new Meteor.Error('not-allowed'); } emails.forEach(email => { @@ -302,6 +308,7 @@ if (Meteor.isServer) { // Checks if the email is already link to an account. const userExist = Users.findOne({ email }); if (userExist) { + rc = -1; throw new Meteor.Error( 'user-exist', `The user with the email ${email} has already an account.`, @@ -328,6 +335,7 @@ if (Meteor.isServer) { if (!err && _id) { sendInvitationEmail(_id); } else { + rc = -1; throw new Meteor.Error( 'invitation-generated-fail', err.message, @@ -338,6 +346,7 @@ if (Meteor.isServer) { } } }); + return rc; }, sendSMTPTestEmail() { diff --git a/server/publications/settings.js b/server/publications/settings.js index 1a3fbd04d..4f496fa28 100644 --- a/server/publications/settings.js +++ b/server/publications/settings.js @@ -25,6 +25,7 @@ Meteor.publish('setting', () => { defaultAuthenticationMethod: 1, spinnerName: 1, oidcBtnText: 1, + mailDomaineName: 1, }, }, );