diff options
author | floatinghotpot <rjfun.mobile@gmail.com> | 2015-12-07 11:15:57 +0800 |
---|---|---|
committer | floatinghotpot <rjfun.mobile@gmail.com> | 2015-12-07 11:15:57 +0800 |
commit | 011f53ad0828c0979d15e232abf501180c741288 (patch) | |
tree | 41330fe4e47c443dd9fefd0493f30a186e4c4999 /models/users.js | |
parent | d4c5310d65cbdfbd002288d33eba429ace33bc3c (diff) | |
download | wekan-011f53ad0828c0979d15e232abf501180c741288.tar.gz wekan-011f53ad0828c0979d15e232abf501180c741288.tar.bz2 wekan-011f53ad0828c0979d15e232abf501180c741288.zip |
add: invite user via email, invited user can accept or decline, allow member to quit
Diffstat (limited to 'models/users.js')
-rw-r--r-- | models/users.js | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/models/users.js b/models/users.js index 49c30127..2c9ae380 100644 --- a/models/users.js +++ b/models/users.js @@ -41,6 +41,16 @@ Users.helpers({ return _.contains(starredBoards, boardId); }, + invitedBoards() { + const {invitedBoards = []} = this.profile; + return Boards.find({archived: false, _id: {$in: invitedBoards}}); + }, + + isInvitedTo(boardId) { + const {invitedBoards = []} = this.profile; + return _.contains(invitedBoards, boardId); + }, + getAvatarUrl() { // Although we put the avatar picture URL in the `profile` object, we need // to support Sandstorm which put in the `picture` attribute by default. @@ -90,6 +100,22 @@ Users.mutations({ }; }, + addInvite(boardId) { + return { + $addToSet: { + 'profile.invitedBoards': boardId, + }, + }; + }, + + removeInvite(boardId) { + return { + $pull: { + 'profile.invitedBoards': boardId, + }, + }; + }, + setAvatarUrl(avatarUrl) { return { $set: { 'profile.avatarUrl': avatarUrl }}; }, @@ -107,6 +133,85 @@ Meteor.methods({ }, }); +if (Meteor.isServer) { + Meteor.methods({ + // we accept userId, username, email + inviteUserToBoard(username, boardId) { + check(username, String); + check(boardId, String); + + const inviter = Meteor.user(); + const board = Boards.findOne(boardId); + const allowInvite = inviter && + board && + board.members && + _.contains(_.pluck(board.members, 'userId'), inviter._id) && + _.where(board.members, {userId: inviter._id})[0].isActive && + _.where(board.members, {userId: inviter._id})[0].isAdmin; + if (!allowInvite) throw new Meteor.Error('error-board-notAMember'); + + this.unblock(); + + const posAt = username.indexOf('@'); + let user = null; + if (posAt>=0) { + user = Users.findOne({emails: {$elemMatch: {address: username}}}); + } else { + user = Users.findOne(username) || Users.findOne({ username }); + } + if (user) { + if (user._id === inviter._id) throw new Meteor.Error('error-user-notAllowSelf'); + } else { + if (posAt <= 0) throw new Meteor.Error('error-user-doesNotExist'); + + const email = username; + username = email.substring(0, posAt); + const newUserId = Accounts.createUser({ username, email }); + if (!newUserId) throw new Meteor.Error('error-user-notCreated'); + // assume new user speak same language with inviter + if (inviter.profile && inviter.profile.language) { + Users.update(newUserId, { + $set: { + 'profile.language': inviter.profile.language, + }, + }); + } + Accounts.sendEnrollmentEmail(newUserId); + user = Users.findOne(newUserId); + } + + board.addMember(user._id); + user.addInvite(boardId); + + if (!process.env.MAIL_URL || (!Email)) return { username: user.username }; + + try { + let rootUrl = Meteor.absoluteUrl.defaultOptions.rootUrl || ''; + if (!rootUrl.endsWith('/')) rootUrl = `${rootUrl}/`; + const boardUrl = `${rootUrl}b/${board._id}/${board.slug}`; + + const vars = { + user: user.username, + inviter: inviter.username, + board: board.title, + url: boardUrl, + }; + const lang = user.getLanguage(); + Email.send({ + to: user.emails[0].address, + from: Accounts.emailTemplates.from, + subject: TAPi18n.__('email-invite-subject', vars, lang), + text: TAPi18n.__('email-invite-text', vars, lang), + }); + } catch (e) { + throw new Meteor.Error('email-fail', e.message); + } + + return { username: user.username, email: user.emails[0].address }; + }, + }); +} + Users.before.insert((userId, doc) => { doc.profile = doc.profile || {}; |