2018-01-22 13:01:38 -08:00
'use strict' ;
/* global Clipboard */
2018-01-24 16:20:56 +01:00
// poor man's async
function asyncForEach ( items , handler , callback ) {
var cur = 0 ;
if ( items . length === 0 ) return callback ( ) ;
( function iterator ( ) {
handler ( items [ cur ] , function ( ) {
if ( cur >= items . length - 1 ) return callback ( ) ;
++ cur ;
iterator ( ) ;
} ) ;
} ) ( ) ;
}
2018-01-22 13:01:38 -08:00
angular . module ( 'Application' ) . controller ( 'UsersController' , [ '$scope' , '$location' , '$timeout' , 'Client' , function ( $scope , $location , $timeout , Client ) {
Client . onReady ( function ( ) { if ( ! Client . getUserInfo ( ) . admin ) $location . path ( '/' ) ; } ) ;
$scope . ready = false ;
$scope . users = [ ] ;
$scope . groups = [ ] ;
$scope . groupsById = { } ;
$scope . config = Client . getConfig ( ) ;
$scope . userInfo = Client . getUserInfo ( ) ;
2018-01-24 16:20:56 +01:00
$scope . emailDomains = [ ] ;
2018-01-23 17:09:47 +01:00
2018-01-22 13:01:38 -08:00
$scope . userremove = {
busy : false ,
error : { } ,
userInfo : { } ,
password : '' ,
show : function ( userInfo ) {
$scope . userremove . error . username = null ;
$scope . userremove . error . password = null ;
$scope . userremove . password = '' ;
$scope . userremove . userInfo = userInfo ;
$scope . userremove _form . $setPristine ( ) ;
$scope . userremove _form . $setUntouched ( ) ;
$ ( '#userRemoveModal' ) . modal ( 'show' ) ;
} ,
submit : function ( ) {
$scope . userremove . error . password = null ;
$scope . userremove . busy = true ;
Client . removeUser ( $scope . userremove . userInfo . id , $scope . userremove . password , function ( error ) {
$scope . userremove . busy = false ;
if ( error && error . statusCode === 403 ) {
$scope . userremove . error . password = 'Wrong password' ;
$scope . userremove . password = '' ;
$scope . userremove _form . password . $setPristine ( ) ;
$ ( '#inputUserRemovePassword' ) . focus ( ) ;
return ;
}
if ( error ) return console . error ( 'Unable to delete user.' , error ) ;
$scope . userremove . userInfo = { } ;
$scope . userremove . password = '' ;
$scope . userremove _form . $setPristine ( ) ;
$scope . userremove _form . $setUntouched ( ) ;
refresh ( ) ;
$ ( '#userRemoveModal' ) . modal ( 'hide' ) ;
} ) ;
}
} ;
$scope . useradd = {
busy : false ,
alreadyTaken : false ,
error : { } ,
email : '' ,
username : '' ,
displayName : '' ,
sendInvite : true ,
show : function ( ) {
$scope . useradd . error = { } ;
$scope . useradd . email = '' ;
$scope . useradd . username = '' ;
$scope . useradd . displayName = '' ;
$scope . useradd _form . $setUntouched ( ) ;
$scope . useradd _form . $setPristine ( ) ;
$ ( '#userAddModal' ) . modal ( 'show' ) ;
} ,
submit : function ( ) {
$scope . useradd . busy = true ;
$scope . useradd . alreadyTaken = false ;
$scope . useradd . error . email = null ;
$scope . useradd . error . username = null ;
$scope . useradd . error . displayName = null ;
Client . createUser ( $scope . useradd . username || null , $scope . useradd . email , $scope . useradd . displayName , $scope . useradd . sendInvite , function ( error ) {
$scope . useradd . busy = false ;
if ( error && error . statusCode === 409 ) {
if ( error . message . toLowerCase ( ) . indexOf ( 'email' ) !== - 1 ) {
$scope . useradd . error . email = 'Email already taken' ;
$scope . useradd _form . email . $setPristine ( ) ;
$ ( '#inputUserAddEmail' ) . focus ( ) ;
} else if ( error . message . toLowerCase ( ) . indexOf ( 'username' ) !== - 1 || error . message . toLowerCase ( ) . indexOf ( 'mailbox' ) !== - 1 ) {
$scope . useradd . error . username = 'Username already taken' ;
$scope . useradd _form . username . $setPristine ( ) ;
$ ( '#inputUserAddUsername' ) . focus ( ) ;
} else {
// should not happen!!
console . error ( error . message ) ;
}
return ;
}
if ( error && error . statusCode === 400 ) {
if ( error . message . toLowerCase ( ) . indexOf ( 'email' ) !== - 1 ) {
$scope . useradd . error . email = 'Invalid Email' ;
$scope . useradd . error . emailAttempted = $scope . useradd . email ;
$scope . useradd _form . email . $setPristine ( ) ;
$ ( '#inputUserAddEmail' ) . focus ( ) ;
} else if ( error . message . toLowerCase ( ) . indexOf ( 'username' ) !== - 1 ) {
$scope . useradd . error . username = error . message ;
$scope . useradd _form . username . $setPristine ( ) ;
$ ( '#inputUserAddUsername' ) . focus ( ) ;
} else {
console . error ( 'Unable to create user.' , error . statusCode , error . message ) ;
}
return ;
}
if ( error ) return console . error ( 'Unable to create user.' , error . statusCode , error . message ) ;
$scope . useradd . error = { } ;
$scope . useradd . email = '' ;
$scope . useradd . username = '' ;
$scope . useradd . displayName = '' ;
$scope . useradd _form . $setUntouched ( ) ;
$scope . useradd _form . $setPristine ( ) ;
refresh ( ) ;
$ ( '#userAddModal' ) . modal ( 'hide' ) ;
} ) ;
}
} ;
$scope . useredit = {
busy : false ,
2018-01-25 18:28:11 +01:00
busyFetching : false ,
2018-01-22 13:01:38 -08:00
error : { } ,
userInfo : { } ,
email : '' ,
fallbackEmail : '' ,
2018-01-25 18:17:40 +01:00
aliases : { } ,
2018-01-26 15:39:35 +01:00
selectedEmailDomains : [ ] ,
currentEmailDomains : [ ] ,
availableEmailDomains : [ ] ,
2018-01-22 13:01:38 -08:00
superuser : false ,
show : function ( userInfo ) {
2018-01-25 18:28:11 +01:00
$scope . useredit . busyFetching = true ;
2018-01-22 13:01:38 -08:00
$scope . useredit . error = { } ;
$scope . useredit . email = userInfo . email ;
$scope . useredit . fallbackEmail = userInfo . fallbackEmail ;
$scope . useredit . userInfo = userInfo ;
$scope . useredit . groupIds = angular . copy ( userInfo . groupIds ) ;
$scope . useredit . superuser = userInfo . groupIds . indexOf ( 'admin' ) !== - 1 ;
2018-02-28 15:21:42 -08:00
$scope . useredit . availableEmailDomains = userInfo . username ? $scope . emailDomains . map ( function ( d ) { return { domain : d , address : userInfo . username + '@' + d . domain } ; } ) : [ ] ; // username can be null if invited user has not signed up yet
2018-01-26 15:39:35 +01:00
$scope . useredit . currentEmailDomains = [ ] ;
$scope . useredit . selectedEmailDomains = [ ] ;
2018-01-25 18:17:40 +01:00
$scope . useredit . aliases = { } ;
2018-01-22 13:01:38 -08:00
2018-01-25 18:17:40 +01:00
// fetch user's mailboxes and aliases
2018-01-24 16:20:56 +01:00
var tmp = [ ] ;
asyncForEach ( $scope . emailDomains , function ( domain , callback ) {
Client . getUserMailbox ( domain . domain , userInfo . id , function ( error ) {
if ( error ) return callback ( ) ;
2018-01-26 15:39:35 +01:00
var d = $scope . useredit . availableEmailDomains . find ( function ( d ) { return d . domain . domain === domain . domain ; } ) ;
if ( ! d ) {
console . error ( 'Unable to map domain, this should never happen.' ) ;
return callback ( ) ;
}
$scope . useredit . currentEmailDomains . push ( d ) ;
tmp . push ( d ) ;
2018-01-25 18:17:40 +01:00
Client . getAliases ( domain . domain , userInfo . id , function ( error , result ) {
if ( error ) return callback ( ) ;
2018-01-24 16:20:56 +01:00
2018-01-26 15:39:35 +01:00
$scope . useredit . aliases [ d . address ] = result . join ( ',' ) ;
2018-01-25 18:17:40 +01:00
callback ( ) ;
} ) ;
2018-01-24 16:20:56 +01:00
} ) ;
2018-01-25 18:28:11 +01:00
} , function ( error ) {
$scope . useredit . busyFetching = false ;
if ( error ) return console . error ( error ) ;
2018-01-24 16:20:56 +01:00
// we need this copy as angular multiselect cannot deal with dynamic arrays!
2018-01-26 15:39:35 +01:00
$scope . useredit . selectedEmailDomains = tmp ;
2018-01-24 16:20:56 +01:00
} ) ;
2018-01-22 13:01:38 -08:00
$scope . useredit _form . $setPristine ( ) ;
$scope . useredit _form . $setUntouched ( ) ;
// clear any alias error when the model changes. this is required because tagInput directive is not angular forms aware
// http://blog.revolunet.com/blog/2013/11/28/create-resusable-angularjs-input-component/ has some notes on how to do that
$scope . $watch ( 'useredit.aliases' , function ( ) {
$scope . useredit . error . aliases = null ;
} ) ;
$ ( '#userEditModal' ) . modal ( 'show' ) ;
} ,
toggleGroup : function ( group ) {
var pos = $scope . useredit . groupIds . indexOf ( group . id ) ;
if ( pos === - 1 ) {
$scope . useredit . groupIds . push ( group . id ) ;
} else {
$scope . useredit . groupIds . splice ( pos , 1 ) ;
}
} ,
submit : function ( ) {
$scope . useredit . error = { } ;
$scope . useredit . busy = true ;
2018-01-26 15:39:35 +01:00
var userId = $scope . useredit . userInfo . id ;
2018-01-22 13:01:38 -08:00
var data = {
2018-01-26 15:39:35 +01:00
id : userId ,
2018-01-24 16:20:56 +01:00
email : $scope . useredit . email ,
fallbackEmail : $scope . useredit . fallbackEmail
2018-01-22 13:01:38 -08:00
} ;
Client . updateUser ( data , function ( error ) {
if ( error ) {
$scope . useredit . busy = false ;
if ( error . statusCode === 409 ) {
$scope . useredit . error . email = 'Email already taken' ;
$scope . useredit _form . email . $setPristine ( ) ;
$ ( '#inputUserEditEmail' ) . focus ( ) ;
} else {
console . error ( 'Unable to update user:' , error ) ;
}
return ;
}
if ( $scope . useredit . superuser ) {
if ( $scope . useredit . groupIds . indexOf ( 'admin' ) === - 1 ) $scope . useredit . groupIds . push ( 'admin' ) ;
} else {
$scope . useredit . groupIds = $scope . useredit . groupIds . filter ( function ( groupId ) { return groupId !== 'admin' ; } ) ;
}
Client . setGroups ( data . id , $scope . useredit . groupIds , function ( error ) {
if ( error ) return console . error ( 'Unable to update groups for user:' , error ) ;
2018-01-26 15:39:35 +01:00
var addedEmailDomains = $scope . useredit . selectedEmailDomains . filter ( function ( s ) {
return ! $scope . useredit . currentEmailDomains . find ( function ( c ) {
return c . domain . domain === s . domain . domain ;
} ) ;
} ) ;
var removedEmailDomains = $scope . useredit . currentEmailDomains . filter ( function ( c ) {
return ! $scope . useredit . selectedEmailDomains . find ( function ( s ) {
return s . domain . domain === c . domain . domain ;
} ) ;
} ) ;
2018-01-25 18:17:40 +01:00
2018-01-26 15:39:35 +01:00
asyncForEach ( removedEmailDomains , function ( emailDomain , callback ) {
// cleanup aliases first
Client . setAliases ( emailDomain . domain . domain , userId , [ ] , function ( error ) {
2018-01-25 18:17:40 +01:00
if ( error ) return callback ( error ) ;
2018-01-26 15:39:35 +01:00
Client . disableUserMailbox ( emailDomain . domain . domain , userId , callback ) ;
2018-01-25 18:17:40 +01:00
} ) ;
2018-01-24 16:20:56 +01:00
} , function ( error ) {
2018-01-26 15:39:35 +01:00
if ( error ) {
$scope . useredit . busy = false ;
return console . error ( 'Unable to remove mailboxes and aliases.' , error ) ;
}
// enable email on domains
asyncForEach ( addedEmailDomains , function ( emailDomain , callback ) {
Client . enableUserMailbox ( emailDomain . domain . domain , userId , function ( error ) {
if ( error ) return callback ( error ) ;
var aliases = $scope . useredit . aliases [ emailDomain . address ] ? $scope . useredit . aliases [ emailDomain . address ] . split ( ',' ) : [ ] ;
Client . setAliases ( emailDomain . domain . domain , userId , aliases , callback ) ;
} ) ;
} , function ( error ) {
if ( error ) {
$scope . useredit . busy = false ;
return console . error ( 'Unable to remove mailboxes and aliases.' , error ) ;
}
// sync the aliases for enabled domains
asyncForEach ( $scope . useredit . selectedEmailDomains , function ( emailDomain , callback ) {
var aliases = $scope . useredit . aliases [ emailDomain . address ] ? $scope . useredit . aliases [ emailDomain . address ] . split ( ',' ) : [ ] ;
Client . setAliases ( emailDomain . domain . domain , userId , aliases , callback ) ;
} , function ( error ) {
$scope . useredit . busy = false ;
if ( error ) return console . error ( 'unable to adjust email addresses.' , error ) ;
$scope . useredit . userInfo = { } ;
$scope . useredit . email = '' ;
$scope . useredit . superuser = false ;
$scope . useredit . groupIds = [ ] ;
$scope . useredit . availableEmailDomains = [ ] ;
$scope . useredit . currentEmailDomains = [ ] ;
$scope . useredit . selectedEmailDomains = [ ] ;
$scope . useredit . aliases = '' ;
$scope . useredit _form . $setPristine ( ) ;
$scope . useredit _form . $setUntouched ( ) ;
refresh ( ) ;
$ ( '#userEditModal' ) . modal ( 'hide' ) ;
} ) ;
} ) ;
2018-01-22 13:01:38 -08:00
} ) ;
} ) ;
} ) ;
}
} ;
$scope . groupAdd = {
busy : false ,
error : { } ,
name : '' ,
show : function ( ) {
$scope . groupAdd . busy = false ;
$scope . groupAdd . error = { } ;
$scope . groupAdd . name = '' ;
$scope . groupAddForm . $setUntouched ( ) ;
$scope . groupAddForm . $setPristine ( ) ;
$ ( '#groupAddModal' ) . modal ( 'show' ) ;
} ,
submit : function ( ) {
$scope . groupAdd . busy = true ;
$scope . groupAdd . error = { } ;
Client . createGroup ( $scope . groupAdd . name , function ( error ) {
$scope . groupAdd . busy = false ;
if ( error && error . statusCode === 409 ) {
$scope . groupAdd . error . name = 'Name already taken' ;
$scope . groupAddForm . name . $setPristine ( ) ;
$ ( '#groupAddName' ) . focus ( ) ;
return ;
}
if ( error && error . statusCode === 400 ) {
$scope . groupAdd . error . name = error . message ;
$scope . groupAddForm . name . $setPristine ( ) ;
$ ( '#groupAddName' ) . focus ( ) ;
return ;
}
if ( error ) return console . error ( 'Unable to create group.' , error . statusCode , error . message ) ;
refresh ( ) ;
$ ( '#groupAddModal' ) . modal ( 'hide' ) ;
} ) ;
}
} ;
$scope . inviteSent = {
email : '' ,
setupLink : ''
} ;
2018-01-26 11:31:43 +01:00
$scope . groupEdit = {
busy : false ,
busyFetching : false ,
error : { } ,
group : null ,
2018-01-26 15:39:35 +01:00
selectedLists : [ ] ,
currentLists : [ ] ,
2018-01-26 11:31:43 +01:00
availableLists : [ ] ,
show : function ( group ) {
$scope . groupEdit . busy = false ;
$scope . groupEdit . busyFetching = true ;
$scope . groupEdit . error = { } ;
$scope . groupEdit . availableLists = $scope . emailDomains . map ( function ( domain ) { return { domain : domain , address : group . name + '@' + domain . domain } ; } ) ;
$scope . groupEdit . selectedLists = [ ] ;
$scope . groupEdit . currentLists = [ ] ;
$scope . groupEdit . group = angular . copy ( group ) ;
var tmp = [ ] ;
asyncForEach ( $scope . emailDomains , function ( domain , callback ) {
Client . getMailingList ( domain . domain , $scope . groupEdit . group . id , function ( error ) {
if ( error ) return callback ( error ) ;
var list = $scope . groupEdit . availableLists . find ( function ( list ) { return list . domain . domain === domain . domain ; } ) ;
tmp . push ( list ) ;
$scope . groupEdit . currentLists . push ( list ) ;
callback ( ) ;
} ) ;
} , function ( error ) {
$scope . groupEdit . busyFetching = false ;
if ( error ) return console . error ( 'Unable to get mailing lists.' , error ) ;
$scope . groupEdit . selectedLists = tmp ;
} ) ;
$scope . groupEditForm . $setUntouched ( ) ;
$scope . groupEditForm . $setPristine ( ) ;
$ ( '#groupEditModal' ) . modal ( 'show' ) ;
} ,
submit : function ( ) {
$scope . groupEdit . busy = true ;
var addedLists = $scope . groupEdit . selectedLists . filter ( function ( s ) {
return ! $scope . groupEdit . currentLists . find ( function ( c ) {
return c . domain . domain === s . domain . domain ;
} ) ;
} ) ;
var removedLists = $scope . groupEdit . currentLists . filter ( function ( c ) {
return ! $scope . groupEdit . selectedLists . find ( function ( s ) {
return s . domain . domain === c . domain . domain ;
} ) ;
} ) ;
asyncForEach ( addedLists , function ( list , callback ) {
Client . addMailingList ( list . domain . domain , $scope . groupEdit . group . id , callback ) ;
} , function ( error ) {
if ( error ) {
$scope . groupEdit . busy = false ;
return console . error ( 'Failed to add group to mailinglists.' , error ) ;
}
asyncForEach ( removedLists , function ( list , callback ) {
Client . removeMailingList ( list . domain . domain , $scope . groupEdit . group . id , callback ) ;
} , function ( error ) {
$scope . groupEdit . busy = false ;
if ( error ) {
return console . error ( 'Failed to remove group to mailinglists.' , error ) ;
}
$ ( '#groupEditModal' ) . modal ( 'hide' ) ;
} ) ;
} ) ;
}
} ;
2018-01-22 13:01:38 -08:00
$scope . groupRemove = {
busy : false ,
error : { } ,
group : null ,
password : '' ,
memberCount : 0 ,
show : function ( group ) {
$scope . groupRemove . busy = false ;
$scope . groupRemove . error = { } ;
$scope . groupRemove . password = '' ;
$scope . groupRemove . group = angular . copy ( group ) ;
$scope . groupRemoveForm . $setUntouched ( ) ;
$scope . groupRemoveForm . $setPristine ( ) ;
Client . getGroup ( group . id , function ( error , result ) {
if ( error ) return console . error ( 'Unable to fetch group information.' , error . statusCode , error . message ) ;
$scope . groupRemove . memberCount = result . userIds . length ;
$ ( '#groupRemoveModal' ) . modal ( 'show' ) ;
} ) ;
} ,
submit : function ( ) {
$scope . groupRemove . busy = true ;
$scope . groupRemove . error = { } ;
Client . removeGroup ( $scope . groupRemove . group . id , $scope . groupRemove . password , function ( error ) {
$scope . groupRemove . busy = false ;
if ( error && error . statusCode === 403 ) {
$scope . groupRemove . error . password = 'Wrong password' ;
$scope . groupRemove . password = '' ;
$scope . groupRemoveForm . password . $setPristine ( ) ;
$ ( '#groupRemovePasswordInput' ) . focus ( ) ;
return ;
}
if ( error ) return console . error ( 'Unable to remove group.' , error . statusCode , error . message ) ;
refresh ( ) ;
$ ( '#groupRemoveModal' ) . modal ( 'hide' ) ;
} ) ;
}
} ;
$scope . isMe = function ( user ) {
return user . username === Client . getUserInfo ( ) . username ;
} ;
$scope . isAdmin = function ( user ) {
return ! ! user . admin ;
} ;
$scope . sendInvite = function ( user ) {
$scope . inviteSent . email = user . fallbackEmail ;
$scope . inviteSent . setupLink = '' ;
Client . sendInvite ( user , function ( error , resetToken ) {
if ( error ) return console . error ( error ) ;
// Client.notify('', 'Invitation was successfully sent to ' + user.email + '.', false, 'success');
$scope . inviteSent . setupLink = location . origin + '/api/v1/session/account/setup.html?reset_token=' + resetToken ;
$ ( '#inviteSentModal' ) . modal ( 'show' ) ;
} ) ;
} ;
$scope . copyToClipboard = function ( value ) {
document . execCommand ( 'copy' ) ;
} ;
function refresh ( ) {
Client . getGroups ( function ( error , result ) {
if ( error ) return console . error ( 'Unable to get group listing.' , error ) ;
$scope . groups = result ;
$scope . groupsById = { } ;
for ( var i = 0 ; i < result . length ; i ++ ) {
$scope . groupsById [ result [ i ] . id ] = result [ i ] ;
}
Client . getUsers ( function ( error , result ) {
if ( error ) return console . error ( 'Unable to get user listing.' , error ) ;
$scope . users = result ;
2018-01-24 16:20:56 +01:00
Client . getDomains ( function ( error , result ) {
if ( error ) return console . error ( 'Unable to get domain listing.' , error ) ;
// reset so we can push the fresh config
$scope . emailDomains = [ ] ;
asyncForEach ( result , function ( domain , callback ) {
Client . getMailConfigForDomain ( domain . domain , function ( error , mailConfig ) {
if ( error ) return callback ( error ) ;
domain . mailConfig = mailConfig ;
// only collect domains where email is enabled
if ( mailConfig . enabled ) $scope . emailDomains . push ( domain ) ;
callback ( ) ;
} ) ;
} , function ( error ) {
if ( error ) return console . error ( 'Unable to get mail config for domains.' , error ) ;
$scope . ready = true ;
} ) ;
} ) ;
2018-01-22 13:01:38 -08:00
} ) ;
} ) ;
}
2018-01-23 17:09:47 +01:00
Client . onReady ( refresh ) ;
2018-01-22 13:01:38 -08:00
// setup all the dialog focus handling
[ 'userAddModal' , 'userRemoveModal' , 'userEditModal' , 'groupAddModal' , 'groupRemoveModal' ] . forEach ( function ( id ) {
$ ( '#' + id ) . on ( 'shown.bs.modal' , function ( ) {
$ ( this ) . find ( "[autofocus]:first" ) . focus ( ) ;
} ) ;
} ) ;
var clipboard = new Clipboard ( '#setupLinkButton' ) ;
clipboard . on ( 'success' , function ( e ) {
$ ( '#setupLinkButton' ) . tooltip ( {
title : 'Copied!' ,
trigger : 'manual'
} ) . tooltip ( 'show' ) ;
$timeout ( function ( ) { $ ( '#setupLinkButton' ) . tooltip ( 'hide' ) ; } , 2000 ) ;
e . clearSelection ( ) ;
} ) ;
clipboard . on ( 'error' , function ( e ) {
$ ( '#setupLinkButton' ) . tooltip ( {
title : 'Press Ctrl+C to copy' ,
trigger : 'manual'
} ) . tooltip ( 'show' ) ;
$timeout ( function ( ) { $ ( '#setupLinkButton' ) . tooltip ( 'hide' ) ; } , 2000 ) ;
} ) ;
$ ( '.modal-backdrop' ) . remove ( ) ;
} ] ) ;