add email with optional message when kicking user from group

This commit is contained in:
Matteo Pagliazzi
2015-03-18 19:12:53 +01:00
parent 0722a17897
commit 9e540e86af
8 changed files with 128 additions and 82 deletions

View File

@@ -7173,7 +7173,6 @@ process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};
function noop() {}

View File

@@ -96,6 +96,7 @@
"inactivityEmails": "Your account is inactive",
"questStarted": "Your Quest has Begun",
"invitedQuest": "Invited to Quest",
"kickedGroup": "Kicked from group",
"remindersToLogin": "Reminders to check in to HabitRPG",
"unsubscribeAllEmails": "Check to Unsubscribe from Emails",
"unsubscribeAllEmailsText": "By checking this box, I certify that I understand that by unsubscribing from all emails, HabitRPG will never be able to notify me via email about important changes to the site or my account.",

View File

@@ -21,88 +21,105 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
return ~(memberIds.indexOf(userid));
}
$scope.isMember = function(user, group){
return ~(group.members.indexOf(user._id));
$scope.isMember = function(user, group){
return ~(group.members.indexOf(user._id));
}
$scope.Members = Members;
$scope._editing = {group:false};
$scope.save = function(group){
if(group._newLeader && group._newLeader._id) group.leader = group._newLeader._id;
group.$save();
group._editing = false;
}
$scope.deleteAllMessages = function() {
if (confirm(window.env.t('confirmDeleteAllMessages'))) {
User.user.ops.clearPMs({});
}
}
$scope.Members = Members;
$scope._editing = {group:false};
// ------ Modals ------
$scope.save = function(group){
if(group._newLeader && group._newLeader._id) group.leader = group._newLeader._id;
group.$save();
group._editing = false;
}
$scope.deleteAllMessages = function() {
if (confirm(window.env.t('confirmDeleteAllMessages'))) {
User.user.ops.clearPMs({});
}
}
// ------ Modals ------
$scope.clickMember = function(uid, forceShow) {
if (User.user._id == uid && !forceShow) {
if ($state.is('tasks')) {
$state.go('options.profile.avatar');
} else {
$state.go('tasks');
}
$scope.clickMember = function(uid, forceShow) {
if (User.user._id == uid && !forceShow) {
if ($state.is('tasks')) {
$state.go('options.profile.avatar');
} else {
// We need the member information up top here, but then we pass it down to the modal controller
// down below. Better way of handling this?
Members.selectMember(uid, function(){
$rootScope.openModal('member', {controller:'MemberModalCtrl', windowClass:'profile-modal', size:'lg'});
});
$state.go('tasks');
}
}
$scope.removeMember = function(group, member, isMember){
$rootScope.openModal('remove-member');
/*var yes = confirm(window.env.t('sureKick'))
if(yes){
Groups.Group.removeMember({gid: group._id, uuid: member._id }, undefined, function(){
if(isMember){
_.pull(group.members, member);
}else{
_.pull(group.invites, member);
}
});
}*/
}
$scope.openInviteModal = function(group){
$rootScope.openModal('invite-friends', {controller:'InviteToGroupCtrl', resolve:
{injectedGroup: function(){
return group;
}}});
};
//var serializeQs = function(obj, prefix){
// var str = [];
// for(var p in obj) {
// if (obj.hasOwnProperty(p)) {
// var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
// str.push(typeof v == "object" ?
// serializeQs(v, k) :
// encodeURIComponent(k) + "=" + encodeURIComponent(v));
// }
// }
// return str.join("&");
//}
//
//$scope.inviteLink = function(obj){
// return window.env.BASE_URL + '?' + serializeQs({partyInvite: obj});
//}
$scope.quickReply = function(uid) {
} else {
// We need the member information up top here, but then we pass it down to the modal controller
// down below. Better way of handling this?
Members.selectMember(uid, function(){
$rootScope.openModal('private-message',{controller:'MemberModalCtrl'});
$rootScope.openModal('member', {controller:'MemberModalCtrl', windowClass:'profile-modal', size:'lg'});
});
}
}
])
$scope.removeMember = function(group, member, isMember){
// TODO find a better way to do this (share data with remove member modal)
$scope.removeMemberData = {
group: group,
member: member,
isMember: isMember
};
$rootScope.openModal('remove-member', {scope: $scope});
}
$scope.confirmRemoveMember = function(confirm){
if(confirm){
Groups.Group.removeMember({
gid: $scope.removeMemberData.group._id,
uuid: $scope.removeMemberData.member._id,
message: $scope.removeMemberData.message,
}, undefined, function(){
if($scope.removeMemberData.isMember){
_.pull($scope.removeMemberData.group.members, $scope.removeMemberData.member);
}else{
_.pull($scope.removeMemberData.group.invites, $scope.removeMemberData.member);
}
$scope.removeMemberData = undefined;
});
}else{
$scope.removeMemberData = undefined;
}
}
$scope.openInviteModal = function(group){
$rootScope.openModal('invite-friends', {controller:'InviteToGroupCtrl', resolve:
{injectedGroup: function(){
return group;
}}});
};
//var serializeQs = function(obj, prefix){
// var str = [];
// for(var p in obj) {
// if (obj.hasOwnProperty(p)) {
// var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
// str.push(typeof v == "object" ?
// serializeQs(v, k) :
// encodeURIComponent(k) + "=" + encodeURIComponent(v));
// }
// }
// return str.join("&");
//}
//
//$scope.inviteLink = function(obj){
// return window.env.BASE_URL + '?' + serializeQs({partyInvite: obj});
//}
$scope.quickReply = function(uid) {
Members.selectMember(uid, function(){
$rootScope.openModal('private-message',{controller:'MemberModalCtrl'});
});
}
}])
.controller('InviteToGroupCtrl', ['$scope', 'User', 'Groups', 'injectedGroup', '$http', 'Notification', function($scope, User, Groups, injectedGroup, $http, Notification){
$scope.group = injectedGroup;

View File

@@ -660,8 +660,21 @@ api.invite = function(req, res, next){
api.removeMember = function(req, res, next){
var group = res.locals.group;
var uuid = req.query.uuid;
var message = req.query.message;
var user = res.locals.user;
// Send an email to the removed user with an optional message from the leader
var sendMessage = function(removedUser){
if(removedUser.preferences.emailNotifications.kickedGroup !== false){
utils.txnEmail(removedUser, ('kicked-from-' + group.type), [
{name: 'GROUP_NAME', content: group.name},
{name: 'MESSAGE', content: message},
{name: 'GUILDS_LINK', content: nconf.get('BASE_URL') + '/#/options/groups/guilds/public'},
{name: 'PARTY_WANTED_GUILD', content: nconf.get('BASE_URL') + '/#/options/groups/guilds/f2db2a7f-13c5-454d-b3ee-ea1f5089e601'}
]);
}
}
if(group.leader !== user._id){
return res.json(401, {err: "Only group leader can remove a member!"});
}
@@ -678,12 +691,21 @@ api.removeMember = function(req, res, next){
Group.update({_id:group._id},update, function(err, saved){
if (err) return next(err);
// Sending an empty 204 because Group.update doesn't return the group
// see http://mongoosejs.com/docs/api.html#model_Model.update
return res.send(204);
User.findById(uuid, function(err, removedUser){
if(err) return next(err);
sendMessage(removedUser);
// Sending an empty 204 because Group.update doesn't return the group
// see http://mongoosejs.com/docs/api.html#model_Model.update
group = uuid = null;
return res.send(204);
});
});
}else if(_.contains(group.invites, uuid)){
User.findById(uuid, function(err,invited){
if(err) return next(err);
var invitations = invited.invitations;
if(group.type === 'guild'){
invitations.guilds.splice(_.indexOf(invitations.guilds, group._id), 1);
@@ -703,8 +725,9 @@ api.removeMember = function(req, res, next){
// Sending an empty 204 because Group.update doesn't return the group
// see http://mongoosejs.com/docs/api.html#model_Model.update
return res.send(204);
sendMessage(invited);
group = uuid = null;
return res.send(204);
});
});

View File

@@ -308,6 +308,7 @@ var UserSchema = new Schema({
emailNotifications: {
unsubscribeFromAll: {type: Boolean, 'default': false},
newPM: {type: Boolean, 'default': true},
kickedGroup: {type: Boolean, 'default': true},
wonChallenge: {type: Boolean, 'default': true},
giftedGems: {type: Boolean, 'default': true},
giftedSubscription: {type: Boolean, 'default': true},

View File

@@ -69,7 +69,7 @@ module.exports.txnEmail = function(mailingInfoArray, emailType, variables){
// When only one recipient send his info as variables
if(mailingInfoArray.length === 1 && mailingInfoArray[0].name){
variables.push({name: 'RECIPIENT_NAME', content: mailingInfoArray[0].name});
}
}
if(isProd && mailingInfoArray.length > 0){
request({

View File

@@ -305,6 +305,11 @@ script(id='partials/options.settings.notifications.html', type="text/ng-template
input(type='checkbox', ng-disabled='user.preferences.emailNotifications.unsubscribeFromAll === true', ng-model='user.preferences.emailNotifications.invitedGuild', ng-change='set({"preferences.emailNotifications.invitedGuild": user.preferences.emailNotifications.invitedGuild ? true: false})')
span=env.t('invitedGuild')
.checkbox
label
input(type='checkbox', ng-disabled='user.preferences.emailNotifications.unsubscribeFromAll === true', ng-model='user.preferences.emailNotifications.kickedGroup', ng-change='set({"preferences.emailNotifications.kickedGroup": user.preferences.emailNotifications.kickedGroup ? true: false})')
span=env.t('kickedGroup')
.checkbox
label
input(type='checkbox', ng-disabled='user.preferences.emailNotifications.unsubscribeFromAll === true', ng-model='user.preferences.emailNotifications.questStarted', ng-change='set({"preferences.emailNotifications.questStarted": user.preferences.emailNotifications.questStarted ? true: false})')

View File

@@ -106,7 +106,7 @@ script(type='text/ng-template', id='modals/remove-member.html')
.modal-header
h4=env.t('sureKick')
.modal-body
textarea.form-control(type='text',rows='5', placeholder=env.t('optionalMessage'))
textarea.form-control(type='text',rows='5',placeholder=env.t('optionalMessage'),ng-model='removeMemberData.message')
.modal-footer
button.pull-left.btn.btn-danger(ng-click='')=env.t('yesRemove')
button.btn.btn-default(ng-click='$close()')=env.t('cancel')
button.pull-left.btn.btn-danger(ng-click='confirmRemoveMember(true); $close()')=env.t('yesRemove')
button.btn.btn-default(ng-click='confirmRemoveMember(false); $close()')=env.t('cancel')