mirror of
https://github.com/wekan/wekan.git
synced 2025-09-22 01:50:48 +02:00
Admin panel:
Only invited user can register in strict mode, Set mail server in admin panel, Switch strict mode in admin panel, Invite people to system in admin panel
This commit is contained in:
parent
29fdfb9c88
commit
1dfb6ef477
20 changed files with 638 additions and 10 deletions
|
@ -119,6 +119,8 @@
|
|||
"allowIsBoardMember": true,
|
||||
"allowIsBoardMemberByCard": true,
|
||||
"Emoji": true,
|
||||
"Checklists": true
|
||||
"Checklists": true,
|
||||
"Settings": true,
|
||||
"InvitationCodes": true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
Meteor.subscribe('boards');
|
||||
Meteor.subscribe('setting');
|
||||
Meteor.subscribe('user-admin');
|
||||
|
||||
BlazeLayout.setRoot('body');
|
||||
|
||||
|
|
5
client/components/settings/invitationCode.jade
Normal file
5
client/components/settings/invitationCode.jade
Normal file
|
@ -0,0 +1,5 @@
|
|||
template(name='invitationCode')
|
||||
.at-input#invitationcode
|
||||
label(for='at-field-code') {{_ 'invitation-code'}}
|
||||
|
||||
input#at-field-invitationcode(type="text" name='at-field-invitationcode' placeholder="{{_ 'invitation-code'}}")
|
6
client/components/settings/invitationCode.js
Normal file
6
client/components/settings/invitationCode.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
Template.invitationCode.onRendered(() => {
|
||||
const strict = Settings.findOne().strict;
|
||||
if(!strict){
|
||||
$('#invitationcode').hide();
|
||||
}
|
||||
});
|
72
client/components/settings/settingBody.jade
Normal file
72
client/components/settings/settingBody.jade
Normal file
|
@ -0,0 +1,72 @@
|
|||
template(name="setting")
|
||||
.setting-content
|
||||
.content-title
|
||||
span Settings
|
||||
.content-body
|
||||
.side-menu
|
||||
ul
|
||||
li.active
|
||||
a.js-setting-menu(data-id="general-setting") System
|
||||
li
|
||||
a.js-setting-menu(data-id="email-setting") Email
|
||||
.main-body
|
||||
if loading.get
|
||||
+spinner
|
||||
else if generalSetting.get
|
||||
+general
|
||||
else if emailSetting.get
|
||||
+email
|
||||
|
||||
template(name="general")
|
||||
ul#general-setting.setting-detail
|
||||
li
|
||||
a.flex.js-toggle-strict-mode
|
||||
.materialCheckBox(class="{{#if currentSetting.strict}}is-checked{{/if}}")
|
||||
|
||||
span Use Strict Mode
|
||||
li
|
||||
.invite-people(class="{{#if currentSetting.strict}}{{else}}hide{{/if}}")
|
||||
ul
|
||||
li
|
||||
.title Invite People
|
||||
textarea#email-to-invite.form-control(rows='5', placeholder="Email Adresses")
|
||||
li
|
||||
.title To board(s)
|
||||
.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='email')
|
||||
ul#email-setting.setting-detail
|
||||
li.smtp-form
|
||||
.title SMTP Host {{currentSetting.mailServer.port}}
|
||||
.description The address of the SMTP server that handles your emails.
|
||||
.form-group
|
||||
input.form-control#mail-server-host(type="text", placeholder="smtp.domain.com" value="{{currentSetting.mailServer.host}}")
|
||||
li.smtp-form
|
||||
.title SMTP Port
|
||||
.description The port your SMTP server uses for outgoing emails.
|
||||
.form-group
|
||||
input.form-control#mail-server-port(type="text", placeholder="25" value="{{currentSetting.mailServer.port}}")
|
||||
li.smtp-form
|
||||
.title SMTP user name
|
||||
.form-group
|
||||
input.form-control#mail-server-username(type="text", placeholder="user name" value="{{currentSetting.mailServer.username}}")
|
||||
li.smtp-form
|
||||
.title SMTP password
|
||||
.form-group
|
||||
input.form-control#mail-server-password(type="text", placeholder="password" value="{{currentSetting.mailServer.password}}")
|
||||
li.smtp-form
|
||||
.title From
|
||||
.Email address you want to use to send emails.
|
||||
.form-group
|
||||
input.form-control#mail-server-from(type="email", placeholder="no-reply@domain.com" value="{{currentSetting.mailServer.from}}")
|
||||
|
||||
li
|
||||
button.js-save.primary Save
|
126
client/components/settings/settingBody.js
Normal file
126
client/components/settings/settingBody.js
Normal file
|
@ -0,0 +1,126 @@
|
|||
Meteor.subscribe('setting');
|
||||
Meteor.subscribe('mailServer');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
this.loading = new ReactiveVar(false);
|
||||
this.generalSetting = new ReactiveVar(true);
|
||||
this.emailSetting = new ReactiveVar(false);
|
||||
},
|
||||
|
||||
setError(error) {
|
||||
this.error.set(error);
|
||||
},
|
||||
|
||||
setLoading(w) {
|
||||
this.loading.set(w);
|
||||
},
|
||||
|
||||
checkField(selector) {
|
||||
const value = $(selector).val();
|
||||
if(!value || value.trim() === ''){
|
||||
$(selector).parents('li.smtp-form').addClass('has-error');
|
||||
throw Error('blank field');
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
|
||||
currentSetting(){
|
||||
return Settings.findOne();
|
||||
},
|
||||
|
||||
boards() {
|
||||
return Boards.find({
|
||||
archived: false,
|
||||
'members.userId': Meteor.userId(),
|
||||
'members.isAdmin': true,
|
||||
}, {
|
||||
sort: ['title'],
|
||||
});
|
||||
},
|
||||
toggleStrictMode(){
|
||||
this.setLoading(true);
|
||||
const isStrictMode = this.currentSetting().strict;
|
||||
Settings.update(Settings.findOne()._id, {$set:{strict: !isStrictMode}});
|
||||
this.setLoading(false);
|
||||
if(isStrictMode){
|
||||
$('.invite-people').slideUp();
|
||||
}else{
|
||||
$('.invite-people').slideDown();
|
||||
}
|
||||
},
|
||||
|
||||
switchMenu(event){
|
||||
const target = $(event.target);
|
||||
if(!target.hasClass('active')){
|
||||
$('.side-menu li.active').removeClass('active');
|
||||
target.parent().addClass('active');
|
||||
const targetID = target.data('id');
|
||||
this.generalSetting.set('general-setting' === targetID);
|
||||
this.emailSetting.set('email-setting' === targetID);
|
||||
}
|
||||
},
|
||||
|
||||
checkBoard(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');
|
||||
},
|
||||
|
||||
inviteThroughEmail(){
|
||||
this.setLoading(true);
|
||||
const emails = $('#email-to-invite').val().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());
|
||||
}
|
||||
});
|
||||
Meteor.call('sendInvitation', validEmails, boardsToInvite, () => {
|
||||
// if (!err) {
|
||||
// TODO - show more info to user
|
||||
// }
|
||||
this.setLoading(false);
|
||||
});
|
||||
},
|
||||
|
||||
saveMailServerInfo(){
|
||||
this.setLoading(true);
|
||||
$('li').removeClass('has-error');
|
||||
|
||||
try{
|
||||
const host = this.checkField('#mail-server-host');
|
||||
const port = this.checkField('#mail-server-port');
|
||||
const username = this.checkField('#mail-server-username');
|
||||
const password = this.checkField('#mail-server-password');
|
||||
const from = this.checkField('#mail-server-from');
|
||||
Settings.update(Settings.findOne()._id, {$set:{'mailServer.host':host, 'mailServer.port': port, 'mailServer.username': username,
|
||||
'mailServer.password': password, 'mailServer.from': from}});
|
||||
} catch (e) {
|
||||
return;
|
||||
} finally {
|
||||
this.setLoading(false);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
events(){
|
||||
return [{
|
||||
'click a.js-toggle-strict-mode': this.toggleStrictMode,
|
||||
'click a.js-setting-menu': this.switchMenu,
|
||||
'click a.js-toggle-board-choose': this.checkBoard,
|
||||
'click button.js-email-invite': this.inviteThroughEmail,
|
||||
'click button.js-save': this.saveMailServerInfo,
|
||||
}];
|
||||
},
|
||||
}).register('setting');
|
112
client/components/settings/settingBody.styl
Normal file
112
client/components/settings/settingBody.styl
Normal file
|
@ -0,0 +1,112 @@
|
|||
.flex
|
||||
display: -webkit-box
|
||||
display: -moz-box
|
||||
display: -webkit-flex
|
||||
display: -moz-flex
|
||||
display: -ms-flexbox
|
||||
display: flex
|
||||
|
||||
.setting-content
|
||||
padding 30px
|
||||
color: #727479
|
||||
background: #dedede
|
||||
width 100%
|
||||
height 100%
|
||||
position: absolute;
|
||||
|
||||
.content-title
|
||||
font-size 20px
|
||||
|
||||
.content-body
|
||||
display flex
|
||||
padding-top 15px
|
||||
height 100%
|
||||
|
||||
.side-menu
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
width: 250px;
|
||||
box-shadow: inset -1px -1px 3px rgba(0,0,0,.05);
|
||||
|
||||
ul
|
||||
|
||||
li
|
||||
margin: 0.1rem 0.2rem;
|
||||
|
||||
&.active
|
||||
background #fff
|
||||
box-shadow 0 1px 2px rgba(0,0,0,0.15);
|
||||
|
||||
&:hover
|
||||
background #fff
|
||||
box-shadow 0 1px 2px rgba(0,0,0,0.15);
|
||||
a
|
||||
@extends .flex
|
||||
padding: 1rem 0 1rem 1rem
|
||||
width: 100% - 5rem
|
||||
|
||||
|
||||
span
|
||||
font-size: 13px
|
||||
|
||||
.main-body
|
||||
padding: 0.1em 1em
|
||||
|
||||
ul
|
||||
li
|
||||
padding: 0.5rem 0.5rem;
|
||||
|
||||
a
|
||||
.is-checked
|
||||
border-bottom: 2px solid #2980b9;
|
||||
border-right: 2px solid #2980b9;
|
||||
|
||||
span
|
||||
padding: 0 0.5rem
|
||||
|
||||
.invite-people
|
||||
padding-left 20px;
|
||||
li
|
||||
min-width: 500px;
|
||||
|
||||
ul.no-margin-bottom
|
||||
margin-bottom: 0;
|
||||
|
||||
.bg-white
|
||||
a
|
||||
background #f7f7f7
|
||||
&.is-checked
|
||||
background #fff
|
||||
|
||||
|
||||
.option
|
||||
@extends .flex
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
background: #fff;
|
||||
text-decoration: none;
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
||||
margin-top: 5px;
|
||||
padding: 5px;
|
||||
|
||||
.title
|
||||
font-weight 700;
|
||||
margin-bottom 0.5rem;
|
||||
.description
|
||||
margin-bottom 0.5rem;
|
||||
.bg-white
|
||||
background #f9fbfc;
|
||||
|
||||
.form-control.has-error
|
||||
border-color: #a94442;
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
|
||||
li.has-error
|
||||
color #a94442
|
||||
.form-group
|
||||
.form-control
|
||||
border-color: #a94442;
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
|
21
client/components/settings/settingHeader.jade
Normal file
21
client/components/settings/settingHeader.jade
Normal file
|
@ -0,0 +1,21 @@
|
|||
template(name="settingHeaderBar")
|
||||
h1.header-setting-menu
|
||||
span {{_ 'admin-panel'}}
|
||||
|
||||
.setting-header-btns.left
|
||||
unless isMiniScreen
|
||||
unless isSandstorm
|
||||
if currentUser
|
||||
a.setting-header-btn.settings.active
|
||||
i.fa(class="fa-cog")
|
||||
span {{_ 'option-setting'}}
|
||||
//TODO
|
||||
// a.setting-header-btn.people
|
||||
// i.fa(class="fa-users")
|
||||
// span {{_ 'option-people'}}
|
||||
|
||||
else
|
||||
a.setting-header-btn.js-log-in(
|
||||
title="{{_ 'log-in'}}")
|
||||
i.fa.fa-sign-in
|
||||
span {{_ 'log-in'}}
|
25
client/components/settings/settingHeader.styl
Normal file
25
client/components/settings/settingHeader.styl
Normal file
|
@ -0,0 +1,25 @@
|
|||
#header #header-main-bar .setting-header-btn
|
||||
&.active,
|
||||
&:hover:not(.is-disabled)
|
||||
background: rgba(0, 0, 0, .15)
|
||||
color: darken(white, 5%)
|
||||
margin-left: 20px;
|
||||
padding-right: 10px;
|
||||
height: 28px;
|
||||
font-size: 13px;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
line-height: @height;
|
||||
margin: 0 2px;
|
||||
|
||||
i.fa
|
||||
float: left
|
||||
display: block
|
||||
line-height: 28px
|
||||
color: darken(white, 5%)
|
||||
margin: 0 10px
|
||||
|
||||
+ span
|
||||
display: inline-block
|
||||
margin-top: 1px
|
||||
margin-right: 10px
|
|
@ -17,6 +17,8 @@ template(name="memberMenuPopup")
|
|||
li: a.js-change-password {{_ 'changePasswordPopup-title'}}
|
||||
li: a.js-change-language {{_ 'changeLanguagePopup-title'}}
|
||||
li: a.js-edit-notification {{_ 'editNotificationPopup-title'}}
|
||||
if currentUser.isAdmin
|
||||
li: a.js-go-setting(href='/setting') {{_ 'admin-panel'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-logout {{_ 'log-out'}}
|
||||
|
|
|
@ -15,6 +15,9 @@ Template.memberMenuPopup.events({
|
|||
|
||||
AccountsTemplates.logout();
|
||||
},
|
||||
'click .js-go-setting'() {
|
||||
Popup.close();
|
||||
},
|
||||
});
|
||||
|
||||
Template.editProfilePopup.events({
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
const passwordField = AccountsTemplates.removeField('password');
|
||||
const emailField = AccountsTemplates.removeField('email');
|
||||
|
||||
AccountsTemplates.addFields([{
|
||||
_id: 'username',
|
||||
type: 'text',
|
||||
displayName: 'username',
|
||||
required: true,
|
||||
minLength: 2,
|
||||
}, emailField, passwordField]);
|
||||
}, emailField, passwordField, {
|
||||
_id: 'invitationcode',
|
||||
type: 'text',
|
||||
displayName: 'Invitation Code',
|
||||
required: false,
|
||||
minLength: 6,
|
||||
errStr: 'Invitation code doesn\'t exist',
|
||||
template: 'invitationCode',
|
||||
}]);
|
||||
|
||||
AccountsTemplates.configure({
|
||||
defaultLayout: 'userFormsLayout',
|
||||
|
@ -48,9 +57,6 @@ AccountsTemplates.configureRoute('changePwd', {
|
|||
});
|
||||
|
||||
if (Meteor.isServer) {
|
||||
if (process.env.MAIL_FROM) {
|
||||
Accounts.emailTemplates.from = process.env.MAIL_FROM;
|
||||
}
|
||||
|
||||
['resetPassword-subject', 'resetPassword-text', 'verifyEmail-subject', 'verifyEmail-text', 'enrollAccount-subject', 'enrollAccount-text'].forEach((str) => {
|
||||
const [templateName, field] = str.split('-');
|
||||
|
@ -63,3 +69,4 @@ if (Meteor.isServer) {
|
|||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -99,6 +99,16 @@ FlowRouter.route('/import', {
|
|||
},
|
||||
});
|
||||
|
||||
FlowRouter.route('/setting', {
|
||||
name: 'setting',
|
||||
action() {
|
||||
BlazeLayout.render('defaultLayout', {
|
||||
headerBar: 'settingHeaderBar',
|
||||
content: 'setting',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
FlowRouter.notFound = {
|
||||
action() {
|
||||
BlazeLayout.render('defaultLayout', { content: 'notFound' });
|
||||
|
|
|
@ -323,5 +323,13 @@
|
|||
"welcome-board": "Welcome Board",
|
||||
"welcome-list1": "Basics",
|
||||
"welcome-list2": "Advanced",
|
||||
"what-to-do": "What do you want to do?"
|
||||
"what-to-do": "What do you want to do?",
|
||||
"admin-panel": "Admin Panel",
|
||||
"system-setting": "System Setting",
|
||||
"option-setting": "Settings",
|
||||
"option-people": "People",
|
||||
"invitation-code": "Invitation Code",
|
||||
"email-invite-register-subject": "__inviter__ sent you an invitation",
|
||||
"email-invite-register-text": "Dear __user__,\n\n__inviter__ invites you to Wekan for collaborations.\n\nPlease follow the link below:\n__url__\n\nAnd your invitation code is: __icode__\n\nThanks.\n",
|
||||
"error-invitation-code-not-exist": "Invitation code doesn't exist"
|
||||
}
|
|
@ -322,5 +322,12 @@
|
|||
"welcome-board": "“欢迎”看板",
|
||||
"welcome-list1": "基本",
|
||||
"welcome-list2": "高阶",
|
||||
"what-to-do": "要做什么?"
|
||||
"what-to-do": "要做什么?",
|
||||
"system-setting": "系统设置",
|
||||
"option-setting": "设置",
|
||||
"option-people": "成员",
|
||||
"invitation-code": "邀请码",
|
||||
"email-invite-register-subject": "__inviter__ 向您发出邀请",
|
||||
"email-invite-register-text": "尊敬的 __user__,\n\n__inviter__ 邀请您加入看板参与协作。\n\n请点击下面的链接访问进行注册:\n\n__url__\n您的邀请码是: __icode__\n\n谢谢。\n",
|
||||
"error-invitation-code-not-exist": "验证码不存在"
|
||||
}
|
45
models/invitationCodes.js
Normal file
45
models/invitationCodes.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
InvitationCodes = new Mongo.Collection('invitation_codes');
|
||||
|
||||
InvitationCodes.attachSchema(new SimpleSchema({
|
||||
code: {
|
||||
type: String,
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
unique: true,
|
||||
regEx: SimpleSchema.RegEx.Email,
|
||||
},
|
||||
createdAt: {
|
||||
type: Date,
|
||||
denyUpdate: false,
|
||||
},
|
||||
// always be the admin if only one admin
|
||||
authorId: {
|
||||
type: String,
|
||||
},
|
||||
boardsToBeInvited: {
|
||||
type: [String],
|
||||
optional: true,
|
||||
},
|
||||
valid: {
|
||||
type: Boolean,
|
||||
defaultValue: true,
|
||||
},
|
||||
}));
|
||||
|
||||
InvitationCodes.helpers({
|
||||
author(){
|
||||
return Users.findOne(this.authorId);
|
||||
},
|
||||
});
|
||||
|
||||
// InvitationCodes.before.insert((userId, doc) => {
|
||||
// doc.createdAt = new Date();
|
||||
// doc.authorId = userId;
|
||||
// });
|
||||
|
||||
if (Meteor.isServer) {
|
||||
Boards.deny({
|
||||
fetch: ['members'],
|
||||
});
|
||||
}
|
111
models/settings.js
Normal file
111
models/settings.js
Normal file
|
@ -0,0 +1,111 @@
|
|||
Settings = new Mongo.Collection('settings');
|
||||
|
||||
Settings.attachSchema(new SimpleSchema({
|
||||
strict: {
|
||||
type: Boolean,
|
||||
},
|
||||
'mailServer.username': {
|
||||
type: String,
|
||||
},
|
||||
'mailServer.password': {
|
||||
type: String,
|
||||
},
|
||||
'mailServer.host': {
|
||||
type: String,
|
||||
},
|
||||
'mailServer.port': {
|
||||
type: String,
|
||||
},
|
||||
'mailServer.from': {
|
||||
type: String,
|
||||
defaultValue: 'Kanban',
|
||||
},
|
||||
createdAt: {
|
||||
type: Date,
|
||||
denyUpdate: true,
|
||||
},
|
||||
modifiedAt: {
|
||||
type: Date,
|
||||
},
|
||||
}));
|
||||
Settings.helpers({
|
||||
mailUrl () {
|
||||
const mailUrl = `smtp://${this.mailServer.username}:${this.mailServer.password}@${this.mailServer.host}:${this.mailServer.port}/`;
|
||||
return mailUrl;
|
||||
},
|
||||
});
|
||||
Settings.allow({
|
||||
update(userId) {
|
||||
const user = Users.findOne(userId);
|
||||
return user && user.isAdmin;
|
||||
},
|
||||
});
|
||||
|
||||
Settings.before.update((userId, doc, fieldNames, modifier) => {
|
||||
modifier.$set = modifier.$set || {};
|
||||
modifier.$set.modifiedAt = new Date();
|
||||
});
|
||||
|
||||
if (Meteor.isServer) {
|
||||
Meteor.startup(() => {
|
||||
const setting = Settings.findOne({});
|
||||
if(!setting){
|
||||
const now = new Date();
|
||||
const defaultSetting = {strict: false, mailServer: {
|
||||
username: '', password:'', host: '', port:'', from: '',
|
||||
}, createdAt: now, modifiedAt: now};
|
||||
Settings.insert(defaultSetting);
|
||||
}
|
||||
const newSetting = Settings.findOne();
|
||||
process.env.MAIL_URL = newSetting.mailUrl();
|
||||
Accounts.emailTemplates.from = newSetting.mailServer.from;
|
||||
});
|
||||
|
||||
function getRandomNum (min, max) {
|
||||
const range = max - min;
|
||||
const rand = Math.random();
|
||||
return (min + Math.round(rand * range));
|
||||
}
|
||||
|
||||
function sendInvitationEmail (_id){
|
||||
const icode = InvitationCodes.findOne(_id);
|
||||
const author = Users.findOne(Meteor.userId());
|
||||
try {
|
||||
const params = {
|
||||
email: icode.email,
|
||||
inviter: Users.findOne(icode.authorId).username,
|
||||
user: icode.email.split('@')[0],
|
||||
icode: icode.code,
|
||||
url: FlowRouter.url('sign-up'),
|
||||
};
|
||||
const lang = author.getLanguage();
|
||||
Email.send({
|
||||
to: icode.email,
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject: TAPi18n.__('email-invite-register-subject', params, lang),
|
||||
text: TAPi18n.__('email-invite-register-text', params, lang),
|
||||
});
|
||||
} catch (e) {
|
||||
throw new Meteor.Error('email-fail', e.message);
|
||||
}
|
||||
}
|
||||
|
||||
Meteor.methods({
|
||||
sendInvitation(emails, boards) {
|
||||
check(emails, [String]);
|
||||
check(boards, [String]);
|
||||
const user = Users.findOne(Meteor.userId());
|
||||
if(!user.isAdmin){
|
||||
throw new Meteor.Error('not-allowed');
|
||||
}
|
||||
emails.forEach((email) => {
|
||||
if (email && SimpleSchema.RegEx.Email.test(email)) {
|
||||
const code = getRandomNum(100000, 999999);
|
||||
InvitationCodes.insert({code, email, boardsToBeInvited: boards, createdAt: new Date(), authorId: Meteor.userId()}, function(err, _id){
|
||||
if(!err && _id) sendInvitationEmail(_id);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
|
@ -348,7 +348,7 @@ if (Meteor.isServer) {
|
|||
if (user._id === inviter._id) throw new Meteor.Error('error-user-notAllowSelf');
|
||||
} else {
|
||||
if (posAt <= 0) throw new Meteor.Error('error-user-doesNotExist');
|
||||
|
||||
if (Settings.findOne().strict) throw new Meteor.Error('error-user-notCreated');
|
||||
const email = username;
|
||||
username = email.substring(0, posAt);
|
||||
const newUserId = Accounts.createUser({ username, email });
|
||||
|
@ -389,6 +389,28 @@ if (Meteor.isServer) {
|
|||
return { username: user.username, email: user.emails[0].address };
|
||||
},
|
||||
});
|
||||
Accounts.onCreateUser((options, user) => {
|
||||
const userCount = Users.find().count();
|
||||
if (userCount === 0){
|
||||
user.isAdmin = true;
|
||||
return user;
|
||||
}
|
||||
const strict = Settings.findOne().strict;
|
||||
if (!strict) {
|
||||
return user;
|
||||
}
|
||||
|
||||
const iCode = options.profile.invitationcode | '';
|
||||
|
||||
const invitationCode = InvitationCodes.findOne({code: iCode, valid:true});
|
||||
if (!invitationCode) {
|
||||
throw new Meteor.Error('error-invitation-code-not-exist');
|
||||
}else{
|
||||
user.profile = {icode: options.profile.invitationcode};
|
||||
}
|
||||
|
||||
return user;
|
||||
});
|
||||
}
|
||||
|
||||
if (Meteor.isServer) {
|
||||
|
@ -458,4 +480,25 @@ if (Meteor.isServer) {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
Users.after.insert((userId, doc) => {
|
||||
|
||||
//invite user to corresponding boards
|
||||
const strict = Settings.findOne().strict;
|
||||
if (strict) {
|
||||
const user = Users.findOne(doc._id);
|
||||
const invitationCode = InvitationCodes.findOne({code: user.profile.icode, valid:true});
|
||||
if (!invitationCode) {
|
||||
throw new Meteor.Error('error-user-notCreated');
|
||||
}else{
|
||||
invitationCode.boardsToBeInvited.forEach((boardId) => {
|
||||
const board = Boards.findOne(boardId);
|
||||
board.addMember(doc._id);
|
||||
});
|
||||
user.profile = {invitedBoards: invitationCode.boardsToBeInvited};
|
||||
InvitationCodes.update(invitationCode._id, {$set: {valid:false}});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
13
server/publications/settings.js
Normal file
13
server/publications/settings.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
Meteor.publish('setting', () => {
|
||||
return Settings.find({}, {fields:{strict: 1}});
|
||||
});
|
||||
|
||||
Meteor.publish('mailServer', function () {
|
||||
if (!Match.test(this.userId, String))
|
||||
return [];
|
||||
const user = Users.findOne(this.userId);
|
||||
if(user && user.isAdmin){
|
||||
return Settings.find({}, {fields: {mailServer: 1}});
|
||||
}
|
||||
return [];
|
||||
});
|
|
@ -9,3 +9,11 @@ Meteor.publish('user-miniprofile', function(userId) {
|
|||
},
|
||||
});
|
||||
});
|
||||
|
||||
Meteor.publish('user-admin', function() {
|
||||
return Meteor.users.find(this.userId, {
|
||||
fields: {
|
||||
isAdmin: 1,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue