diff --git a/WebsitePanel/Database/update_db.sql b/WebsitePanel/Database/update_db.sql
index b0d6956d..24dbdd04 100644
--- a/WebsitePanel/Database/update_db.sql
+++ b/WebsitePanel/Database/update_db.sql
@@ -1967,3 +1967,69 @@ GO
+
+ALTER PROCEDURE [dbo].[SearchExchangeAccounts]
+(
+ @ActorID int,
+ @ItemID int,
+ @IncludeMailboxes bit,
+ @IncludeContacts bit,
+ @IncludeDistributionLists bit,
+ @IncludeRooms bit,
+ @IncludeEquipment bit,
+ @FilterColumn nvarchar(50) = '',
+ @FilterValue nvarchar(50) = '',
+ @SortColumn nvarchar(50)
+)
+AS
+DECLARE @PackageID int
+SELECT @PackageID = PackageID FROM ServiceItems
+WHERE ItemID = @ItemID
+
+-- check rights
+IF dbo.CheckActorPackageRights(@ActorID, @PackageID) = 0
+RAISERROR('You are not allowed to access this package', 16, 1)
+
+-- start
+DECLARE @condition nvarchar(700)
+SET @condition = '
+((@IncludeMailboxes = 1 AND EA.AccountType = 1)
+OR (@IncludeContacts = 1 AND EA.AccountType = 2)
+OR (@IncludeDistributionLists = 1 AND EA.AccountType = 3)
+OR (@IncludeRooms = 1 AND EA.AccountType = 5)
+OR (@IncludeEquipment = 1 AND EA.AccountType = 6)
+OR (@IncludeEquipment = 0 AND @IncludeContacts = 0 AND @IncludeDistributionLists = 0 AND @IncludeRooms = 0 AND @IncludeEquipment = 0 AND EA.AccountType = 8))
+AND EA.ItemID = @ItemID
+'
+
+IF @FilterColumn <> '' AND @FilterColumn IS NOT NULL
+AND @FilterValue <> '' AND @FilterValue IS NOT NULL
+SET @condition = @condition + ' AND ' + @FilterColumn + ' LIKE ''' + @FilterValue + ''''
+
+IF @SortColumn IS NULL OR @SortColumn = ''
+SET @SortColumn = 'EA.DisplayName ASC'
+
+DECLARE @sql nvarchar(3500)
+
+set @sql = '
+SELECT
+ EA.AccountID,
+ EA.ItemID,
+ EA.AccountType,
+ EA.AccountName,
+ EA.DisplayName,
+ EA.PrimaryEmailAddress,
+ EA.MailEnabledPublicFolder,
+ EA.SubscriberNumber,
+ EA.UserPrincipalName
+FROM ExchangeAccounts AS EA
+WHERE ' + @condition
+
+print @sql
+
+exec sp_executesql @sql, N'@ItemID int, @IncludeMailboxes int, @IncludeContacts int,
+ @IncludeDistributionLists int, @IncludeRooms bit, @IncludeEquipment bit',
+@ItemID, @IncludeMailboxes, @IncludeContacts, @IncludeDistributionLists, @IncludeRooms, @IncludeEquipment
+
+RETURN
+GO
\ No newline at end of file
diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Client/OrganizationProxy.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Client/OrganizationProxy.cs
index d2c60dd8..89e5b4d7 100644
--- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Client/OrganizationProxy.cs
+++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Client/OrganizationProxy.cs
@@ -129,6 +129,12 @@ namespace WebsitePanel.EnterpriseServer.HostedSolution
private System.Threading.SendOrPostCallback AddUserToSecurityGroupOperationCompleted;
+ private System.Threading.SendOrPostCallback DeleteUserFromSecurityGroupOperationCompleted;
+
+ private System.Threading.SendOrPostCallback GetSecurityGroupsByMemberOperationCompleted;
+
+ private System.Threading.SendOrPostCallback SearchSecurityGroupsOperationCompleted;
+
///
public esOrganizations()
{
@@ -231,6 +237,15 @@ namespace WebsitePanel.EnterpriseServer.HostedSolution
///
public event AddUserToSecurityGroupCompletedEventHandler AddUserToSecurityGroupCompleted;
+ ///
+ public event DeleteUserFromSecurityGroupCompletedEventHandler DeleteUserFromSecurityGroupCompleted;
+
+ ///
+ public event GetSecurityGroupsByMemberCompletedEventHandler GetSecurityGroupsByMemberCompleted;
+
+ ///
+ public event SearchSecurityGroupsCompletedEventHandler SearchSecurityGroupsCompleted;
+
///
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/CheckOrgIdExists", RequestNamespace = "http://tempuri.org/", ResponseNamespace = "http://tempuri.org/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public bool CheckOrgIdExists(string orgId)
@@ -2158,22 +2173,22 @@ namespace WebsitePanel.EnterpriseServer.HostedSolution
///
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/AddUserToSecurityGroup", RequestNamespace = "http://tempuri.org/", ResponseNamespace = "http://tempuri.org/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
- public int AddUserToSecurityGroup(int itemId, int userAccountId, int groupAccountId)
+ public int AddUserToSecurityGroup(int itemId, int userAccountId, string groupName)
{
object[] results = this.Invoke("AddUserToSecurityGroup", new object[] {
itemId,
userAccountId,
- groupAccountId});
+ groupName});
return ((int)(results[0]));
}
///
- public System.IAsyncResult BeginAddUserToSecurityGroup(int itemId, int userAccountId, int groupAccountId, System.AsyncCallback callback, object asyncState)
+ public System.IAsyncResult BeginAddUserToSecurityGroup(int itemId, int userAccountId, string groupName, System.AsyncCallback callback, object asyncState)
{
return this.BeginInvoke("AddUserToSecurityGroup", new object[] {
itemId,
userAccountId,
- groupAccountId}, callback, asyncState);
+ groupName}, callback, asyncState);
}
///
@@ -2184,13 +2199,13 @@ namespace WebsitePanel.EnterpriseServer.HostedSolution
}
///
- public void AddUserToSecurityGroupAsync(int itemId, int userAccountId, int groupAccountId)
+ public void AddUserToSecurityGroupAsync(int itemId, int userAccountId, string groupName)
{
- this.AddUserToSecurityGroupAsync(itemId, userAccountId, groupAccountId, null);
+ this.AddUserToSecurityGroupAsync(itemId, userAccountId, groupName, null);
}
///
- public void AddUserToSecurityGroupAsync(int itemId, int userAccountId, int groupAccountId, object userState)
+ public void AddUserToSecurityGroupAsync(int itemId, int userAccountId, string groupName, object userState)
{
if ((this.AddUserToSecurityGroupOperationCompleted == null))
{
@@ -2199,7 +2214,7 @@ namespace WebsitePanel.EnterpriseServer.HostedSolution
this.InvokeAsync("AddUserToSecurityGroup", new object[] {
itemId,
userAccountId,
- groupAccountId}, this.AddUserToSecurityGroupOperationCompleted, userState);
+ groupName}, this.AddUserToSecurityGroupOperationCompleted, userState);
}
private void OnAddUserToSecurityGroupOperationCompleted(object arg)
@@ -2211,6 +2226,171 @@ namespace WebsitePanel.EnterpriseServer.HostedSolution
}
}
+ ///
+ [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/DeleteUserFromSecurityGroup", RequestNamespace = "http://tempuri.org/", ResponseNamespace = "http://tempuri.org/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
+ public int DeleteUserFromSecurityGroup(int itemId, int userAccountId, string groupName)
+ {
+ object[] results = this.Invoke("DeleteUserFromSecurityGroup", new object[] {
+ itemId,
+ userAccountId,
+ groupName});
+ return ((int)(results[0]));
+ }
+
+ ///
+ public System.IAsyncResult BeginDeleteUserFromSecurityGroup(int itemId, int userAccountId, string groupName, System.AsyncCallback callback, object asyncState)
+ {
+ return this.BeginInvoke("DeleteUserFromSecurityGroup", new object[] {
+ itemId,
+ userAccountId,
+ groupName}, callback, asyncState);
+ }
+
+ ///
+ public int EndDeleteUserFromSecurityGroup(System.IAsyncResult asyncResult)
+ {
+ object[] results = this.EndInvoke(asyncResult);
+ return ((int)(results[0]));
+ }
+
+ ///
+ public void DeleteUserFromSecurityGroupAsync(int itemId, int userAccountId, string groupName)
+ {
+ this.DeleteUserFromSecurityGroupAsync(itemId, userAccountId, groupName, null);
+ }
+
+ ///
+ public void DeleteUserFromSecurityGroupAsync(int itemId, int userAccountId, string groupName, object userState)
+ {
+ if ((this.DeleteUserFromSecurityGroupOperationCompleted == null))
+ {
+ this.DeleteUserFromSecurityGroupOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDeleteUserFromSecurityGroupOperationCompleted);
+ }
+ this.InvokeAsync("DeleteUserFromSecurityGroup", new object[] {
+ itemId,
+ userAccountId,
+ groupName}, this.DeleteUserFromSecurityGroupOperationCompleted, userState);
+ }
+
+ private void OnDeleteUserFromSecurityGroupOperationCompleted(object arg)
+ {
+ if ((this.DeleteUserFromSecurityGroupCompleted != null))
+ {
+ System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
+ this.DeleteUserFromSecurityGroupCompleted(this, new DeleteUserFromSecurityGroupCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
+ }
+ }
+
+ ///
+ [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/GetSecurityGroupsByMember", RequestNamespace = "http://tempuri.org/", ResponseNamespace = "http://tempuri.org/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
+ public ExchangeAccount[] GetSecurityGroupsByMember(int itemId, int accountId)
+ {
+ object[] results = this.Invoke("GetSecurityGroupsByMember", new object[] {
+ itemId,
+ accountId});
+ return ((ExchangeAccount[])(results[0]));
+ }
+
+ ///
+ public System.IAsyncResult BeginGetSecurityGroupsByMember(int itemId, int accountId, System.AsyncCallback callback, object asyncState)
+ {
+ return this.BeginInvoke("GetSecurityGroupsByMember", new object[] {
+ itemId,
+ accountId}, callback, asyncState);
+ }
+
+ ///
+ public ExchangeAccount[] EndGetSecurityGroupsByMember(System.IAsyncResult asyncResult)
+ {
+ object[] results = this.EndInvoke(asyncResult);
+ return ((ExchangeAccount[])(results[0]));
+ }
+
+ ///
+ public void GetSecurityGroupsByMemberAsync(int itemId, int accountId)
+ {
+ this.GetSecurityGroupsByMemberAsync(itemId, accountId, null);
+ }
+
+ ///
+ public void GetSecurityGroupsByMemberAsync(int itemId, int accountId, object userState)
+ {
+ if ((this.GetSecurityGroupsByMemberOperationCompleted == null))
+ {
+ this.GetSecurityGroupsByMemberOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetSecurityGroupsByMemberOperationCompleted);
+ }
+ this.InvokeAsync("GetSecurityGroupsByMember", new object[] {
+ itemId,
+ accountId}, this.GetSecurityGroupsByMemberOperationCompleted, userState);
+ }
+
+ private void OnGetSecurityGroupsByMemberOperationCompleted(object arg)
+ {
+ if ((this.GetSecurityGroupsByMemberCompleted != null))
+ {
+ System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
+ this.GetSecurityGroupsByMemberCompleted(this, new GetSecurityGroupsByMemberCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
+ }
+ }
+
+ ///
+ [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/SearchSecurityGroups", RequestNamespace = "http://tempuri.org/", ResponseNamespace = "http://tempuri.org/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
+ public ExchangeAccount[] SearchSecurityGroups(int itemId, string filterColumn, string filterValue, string sortColumn)
+ {
+ object[] results = this.Invoke("SearchSecurityGroups", new object[] {
+ itemId,
+ filterColumn,
+ filterValue,
+ sortColumn});
+ return ((ExchangeAccount[])(results[0]));
+ }
+
+ ///
+ public System.IAsyncResult BeginSearchSecurityGroups(int itemId, string filterColumn, string filterValue, string sortColumn, System.AsyncCallback callback, object asyncState)
+ {
+ return this.BeginInvoke("SearchSecurityGroups", new object[] {
+ itemId,
+ filterColumn,
+ filterValue,
+ sortColumn}, callback, asyncState);
+ }
+
+ ///
+ public ExchangeAccount[] EndSearchSecurityGroups(System.IAsyncResult asyncResult)
+ {
+ object[] results = this.EndInvoke(asyncResult);
+ return ((ExchangeAccount[])(results[0]));
+ }
+
+ ///
+ public void SearchSecurityGroupsAsync(int itemId, string filterColumn, string filterValue, string sortColumn)
+ {
+ this.SearchSecurityGroupsAsync(itemId, filterColumn, filterValue, sortColumn, null);
+ }
+
+ ///
+ public void SearchSecurityGroupsAsync(int itemId, string filterColumn, string filterValue, string sortColumn, object userState)
+ {
+ if ((this.SearchSecurityGroupsOperationCompleted == null))
+ {
+ this.SearchSecurityGroupsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnSearchSecurityGroupsOperationCompleted);
+ }
+ this.InvokeAsync("SearchSecurityGroups", new object[] {
+ itemId,
+ filterColumn,
+ filterValue,
+ sortColumn}, this.SearchSecurityGroupsOperationCompleted, userState);
+ }
+
+ private void OnSearchSecurityGroupsOperationCompleted(object arg)
+ {
+ if ((this.SearchSecurityGroupsCompleted != null))
+ {
+ System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
+ this.SearchSecurityGroupsCompleted(this, new SearchSecurityGroupsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
+ }
+ }
+
///
public new void CancelAsync(object userState)
{
@@ -3177,4 +3357,94 @@ namespace WebsitePanel.EnterpriseServer.HostedSolution
}
}
}
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
+ public delegate void DeleteUserFromSecurityGroupCompletedEventHandler(object sender, DeleteUserFromSecurityGroupCompletedEventArgs e);
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
+ [System.Diagnostics.DebuggerStepThroughAttribute()]
+ [System.ComponentModel.DesignerCategoryAttribute("code")]
+ public partial class DeleteUserFromSecurityGroupCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
+ {
+
+ private object[] results;
+
+ internal DeleteUserFromSecurityGroupCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
+ base(exception, cancelled, userState)
+ {
+ this.results = results;
+ }
+
+ ///
+ public int Result
+ {
+ get
+ {
+ this.RaiseExceptionIfNecessary();
+ return ((int)(this.results[0]));
+ }
+ }
+ }
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
+ public delegate void GetSecurityGroupsByMemberCompletedEventHandler(object sender, GetSecurityGroupsByMemberCompletedEventArgs e);
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
+ [System.Diagnostics.DebuggerStepThroughAttribute()]
+ [System.ComponentModel.DesignerCategoryAttribute("code")]
+ public partial class GetSecurityGroupsByMemberCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
+ {
+
+ private object[] results;
+
+ internal GetSecurityGroupsByMemberCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
+ base(exception, cancelled, userState)
+ {
+ this.results = results;
+ }
+
+ ///
+ public ExchangeAccount[] Result
+ {
+ get
+ {
+ this.RaiseExceptionIfNecessary();
+ return ((ExchangeAccount[])(this.results[0]));
+ }
+ }
+ }
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
+ public delegate void SearchSecurityGroupsCompletedEventHandler(object sender, SearchSecurityGroupsCompletedEventArgs e);
+
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
+ [System.Diagnostics.DebuggerStepThroughAttribute()]
+ [System.ComponentModel.DesignerCategoryAttribute("code")]
+ public partial class SearchSecurityGroupsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
+ {
+
+ private object[] results;
+
+ internal SearchSecurityGroupsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
+ base(exception, cancelled, userState)
+ {
+ this.results = results;
+ }
+
+ ///
+ public ExchangeAccount[] Result
+ {
+ get
+ {
+ this.RaiseExceptionIfNecessary();
+ return ((ExchangeAccount[])(this.results[0]));
+ }
+ }
+ }
}
diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/HostedSolution/OrganizationController.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/HostedSolution/OrganizationController.cs
index 9f87df13..f7a1df6f 100644
--- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/HostedSolution/OrganizationController.cs
+++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/HostedSolution/OrganizationController.cs
@@ -42,6 +42,7 @@ using WebsitePanel.Providers.SharePoint;
using WebsitePanel.Providers.Common;
using WebsitePanel.Providers.DNS;
using WebsitePanel.Providers.OCS;
+using System.Linq;
using System.IO;
using System.Xml;
@@ -2257,14 +2258,16 @@ namespace WebsitePanel.EnterpriseServer
Organizations orgProxy = GetOrganizationProxy(org.ServiceId);
- TaskManager.Write("accountName :" + displayName);
+ string groupName = BuildAccountNameWithOrgId(org.OrganizationId, displayName, org.ServiceId);
- if (orgProxy.CreateSecurityGroup(org.OrganizationId, displayName, managedBy) == 0)
+ TaskManager.Write("accountName :" + groupName);
+
+ if (orgProxy.CreateSecurityGroup(org.OrganizationId, groupName, managedBy) == 0)
{
- OrganizationSecurityGroup retSecurityGroup = orgProxy.GetSecurityGroupGeneralSettings(displayName, org.OrganizationId);
+ OrganizationSecurityGroup retSecurityGroup = orgProxy.GetSecurityGroupGeneralSettings(groupName, org.OrganizationId);
TaskManager.Write("sAMAccountName :" + retSecurityGroup.SAMAccountName);
- securityGroupId = AddAccount(itemId, ExchangeAccountType.SecurityGroup, displayName,
+ securityGroupId = AddAccount(itemId, ExchangeAccountType.SecurityGroup, groupName,
displayName, null, false,
0, retSecurityGroup.SAMAccountName, null, 0, null);
}
@@ -2324,16 +2327,25 @@ namespace WebsitePanel.EnterpriseServer
securityGroup.IsDefault = account.AccountType == ExchangeAccountType.DefaultSecurityGroup;
+ List members = new List();
+
foreach (OrganizationUser user in securityGroup.MembersAccounts)
{
OrganizationUser userAccount = GetAccountByAccountName(itemId, user.SamAccountName);
- user.AccountId = userAccount.AccountId;
- user.AccountName = userAccount.AccountName;
- user.PrimaryEmailAddress = userAccount.PrimaryEmailAddress;
- user.AccountType = userAccount.AccountType;
+ if (userAccount != null)
+ {
+ user.AccountId = userAccount.AccountId;
+ user.AccountName = userAccount.AccountName;
+ user.PrimaryEmailAddress = userAccount.PrimaryEmailAddress;
+ user.AccountType = userAccount.AccountType;
+
+ members.Add(user);
+ }
}
+ securityGroup.MembersAccounts = members.ToArray();
+
return securityGroup;
}
catch (Exception ex)
@@ -2497,7 +2509,7 @@ namespace WebsitePanel.EnterpriseServer
return result;
}
- public static int AddUserToSecurityGroup(int itemId, int userAccountId, int groupAccountId)
+ public static int AddUserToSecurityGroup(int itemId, int userAccountId, string groupName)
{
// check account
int accountCheck = SecurityContext.CheckAccount(DemandAccount.NotDemo | DemandAccount.IsActive);
@@ -2516,12 +2528,9 @@ namespace WebsitePanel.EnterpriseServer
// load user account
OrganizationUser userAccount = GetAccount(itemId, userAccountId);
- //load group account
- ExchangeAccount groupAccount = ExchangeServerController.GetAccount(itemId, groupAccountId);
-
Organizations orgProxy = GetOrganizationProxy(org.ServiceId);
- orgProxy.AddUserToSecurityGroup(org.OrganizationId, userAccount.AccountName, groupAccount.AccountName);
+ orgProxy.AddUserToSecurityGroup(org.OrganizationId, userAccount.AccountName, groupName);
return 0;
}
@@ -2534,6 +2543,130 @@ namespace WebsitePanel.EnterpriseServer
TaskManager.CompleteTask();
}
}
+
+ public static int DeleteUserFromSecurityGroup(int itemId, int userAccountId, string groupName)
+ {
+ // check account
+ int accountCheck = SecurityContext.CheckAccount(DemandAccount.NotDemo | DemandAccount.IsActive);
+ if (accountCheck < 0) return accountCheck;
+
+ // place log record
+ TaskManager.StartTask("ORGANIZATION", "DELETE_USER_FROM_SECURITY_GROUP", itemId);
+
+ try
+ {
+ // load organization
+ Organization org = GetOrganization(itemId);
+ if (org == null)
+ return -1;
+
+ // load user account
+ OrganizationUser userAccount = GetAccount(itemId, userAccountId);
+
+ Organizations orgProxy = GetOrganizationProxy(org.ServiceId);
+
+ orgProxy.DeleteUserFromSecurityGroup(org.OrganizationId, userAccount.AccountName, groupName);
+
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ throw TaskManager.WriteError(ex);
+ }
+ finally
+ {
+ TaskManager.CompleteTask();
+ }
+ }
+
+ public static ExchangeAccount[] GetSecurityGroupsByMember(int itemId, int accountId)
+ {
+ #region Demo Mode
+ if (IsDemoMode)
+ {
+ return null;
+ }
+ #endregion
+
+ // place log record
+ TaskManager.StartTask("ORGANIZATION", "GET_SECURITY_GROUPS_BYMEMBER");
+ TaskManager.ItemId = itemId;
+
+ List ret = new List();
+
+ try
+ {
+ // load organization
+ Organization org = GetOrganization(itemId);
+ if (org == null)
+ return null;
+
+ Organizations orgProxy = GetOrganizationProxy(org.ServiceId);
+
+ // load account
+ ExchangeAccount account = ExchangeServerController.GetAccount(itemId, accountId);
+
+ List SecurytyGroups = ExchangeServerController.GetAccounts(itemId, ExchangeAccountType.SecurityGroup);
+ foreach (ExchangeAccount SecurytyGroupAccount in SecurytyGroups)
+ {
+ OrganizationSecurityGroup SecurytyGroup = GetSecurityGroupGeneralSettings(itemId, SecurytyGroupAccount.AccountId);
+
+ foreach (OrganizationUser member in SecurytyGroup.MembersAccounts)
+ {
+ if (member.AccountName == account.AccountName)
+ {
+ ret.Add(SecurytyGroupAccount);
+ break;
+ }
+
+ }
+ }
+
+ return ret.ToArray();
+ }
+ catch (Exception ex)
+ {
+ throw TaskManager.WriteError(ex);
+ }
+ finally
+ {
+ TaskManager.CompleteTask();
+ }
+ }
+
+ public static List SearchSecurityGroups(int itemId, string filterColumn, string filterValue, string sortColumn)
+ {
+ #region Demo Mode
+
+ if (IsDemoMode)
+ {
+ List demoSecurityGroups = new List();
+
+ ExchangeAccount r1 = new ExchangeAccount();
+ r1.AccountId = 20;
+ r1.AccountName = "group1_fabrikam";
+ r1.AccountType = ExchangeAccountType.SecurityGroup;
+ r1.DisplayName = "Group 1";
+ demoSecurityGroups.Add(r1);
+
+ ExchangeAccount r2 = new ExchangeAccount();
+ r1.AccountId = 21;
+ r1.AccountName = "group2_fabrikam";
+ r1.AccountType = ExchangeAccountType.SecurityGroup;
+ r1.DisplayName = "Group 2";
+ demoSecurityGroups.Add(r2);
+
+ return demoSecurityGroups;
+ }
+
+ #endregion
+
+ List accounts = ObjectUtils.CreateListFromDataReader(
+ DataProvider.SearchExchangeAccounts(
+ SecurityContext.User.UserId, itemId, false, false, false, false, false, filterColumn, filterValue, sortColumn));
+
+ return accounts.Where(x => x.AccountType == ExchangeAccountType.SecurityGroup).ToList();
+ }
}
}
diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/esOrganizations.asmx.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/esOrganizations.asmx.cs
index 6d632462..22609706 100644
--- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/esOrganizations.asmx.cs
+++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/esOrganizations.asmx.cs
@@ -276,11 +276,29 @@ namespace WebsitePanel.EnterpriseServer
}
[WebMethod]
- public int AddUserToSecurityGroup(int itemId, int userAccountId, int groupAccountId)
+ public int AddUserToSecurityGroup(int itemId, int userAccountId, string groupName)
{
- return OrganizationController.AddUserToSecurityGroup(itemId, userAccountId, groupAccountId);
+ return OrganizationController.AddUserToSecurityGroup(itemId, userAccountId, groupName);
}
+ [WebMethod]
+ public int DeleteUserFromSecurityGroup(int itemId, int userAccountId, string groupName)
+ {
+ return OrganizationController.DeleteUserFromSecurityGroup(itemId, userAccountId, groupName);
+ }
+
+ [WebMethod]
+ public ExchangeAccount[] GetSecurityGroupsByMember(int itemId, int accountId)
+ {
+ return OrganizationController.GetSecurityGroupsByMember(itemId, accountId);
+ }
+
+ [WebMethod]
+ public List SearchSecurityGroups(int itemId, string filterColumn, string filterValue, string sortColumn)
+ {
+ return OrganizationController.SearchSecurityGroups(itemId, filterColumn, filterValue, sortColumn);
+ }
+
#endregion
}
diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/ActiveDirectoryUtils.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/ActiveDirectoryUtils.cs
index 773afad4..195ccdba 100644
--- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/ActiveDirectoryUtils.cs
+++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/ActiveDirectoryUtils.cs
@@ -51,7 +51,7 @@ namespace WebsitePanel.Providers.HostedSolution
DirectorySearcher deSearch = new DirectorySearcher
{
Filter =
- ("(&(objectClass=user))")
+ "(&(objectClass=user))"
};
SearchResultCollection srcUsers = deSearch.FindAll();
@@ -63,9 +63,19 @@ namespace WebsitePanel.Providers.HostedSolution
foreach (string str in props)
{
- if (str.IndexOf(group) != -1)
+ string groupName = "";
+
+ string[] parts = str.Split(',');
+ for (int i = 0; i < parts.Length; i++)
{
- rets.Add(de.Path);
+ if (parts[i].StartsWith("CN="))
+ {
+ if (parts[i].Substring(3) == group)
+ {
+ rets.Add(de.Path);
+ }
+ break;
+ }
}
}
}
diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/IOrganization.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/IOrganization.cs
index bda213b7..57aa3d98 100644
--- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/IOrganization.cs
+++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/IOrganization.cs
@@ -52,6 +52,8 @@ namespace WebsitePanel.Providers.HostedSolution
void AddUserToSecurityGroup(string organizationId, string loginName, string groupName);
+ void DeleteUserFromSecurityGroup(string organizationId, string loginName, string groupName);
+
void SetUserGeneralSettings(string organizationId, string accountName, string displayName, string password,
bool hideFromAddressBook, bool disabled, bool locked, string firstName, string initials,
string lastName,
diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/OrganizationProvider.cs b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/OrganizationProvider.cs
index f1cab4d2..bd03c64c 100644
--- a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/OrganizationProvider.cs
+++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/OrganizationProvider.cs
@@ -1041,6 +1041,34 @@ namespace WebsitePanel.Providers.HostedSolution
ActiveDirectoryUtils.AddUserToGroup(userPath, groupPath);
}
+ public void DeleteUserFromSecurityGroup(string organizationId, string loginName, string groupName)
+ {
+ DeleteUserFromSecurityGroupInternal(organizationId, loginName, groupName);
+ }
+
+ internal void DeleteUserFromSecurityGroupInternal(string organizationId, string loginName, string groupName)
+ {
+ HostedSolutionLog.LogStart("AddUserToSecurityGroupInternal");
+ HostedSolutionLog.DebugInfo("organizationId : {0}", organizationId);
+ HostedSolutionLog.DebugInfo("loginName : {0}", loginName);
+ HostedSolutionLog.DebugInfo("groupName : {0}", groupName);
+
+ if (string.IsNullOrEmpty(organizationId))
+ throw new ArgumentNullException("organizationId");
+
+ if (string.IsNullOrEmpty(loginName))
+ throw new ArgumentNullException("loginName");
+
+ if (string.IsNullOrEmpty(groupName))
+ throw new ArgumentNullException("groupName");
+
+ string userPath = GetUserPath(organizationId, loginName);
+
+ string groupPath = GetGroupPath(organizationId, groupName);
+
+ ActiveDirectoryUtils.RemoveUserFromGroup(userPath, groupPath);
+ }
+
#endregion
public override bool IsInstalled()
diff --git a/WebsitePanel/Sources/WebsitePanel.Server.Client/OrganizationProxy.cs b/WebsitePanel/Sources/WebsitePanel.Server.Client/OrganizationProxy.cs
index b01c7dc4..083d4c91 100644
--- a/WebsitePanel/Sources/WebsitePanel.Server.Client/OrganizationProxy.cs
+++ b/WebsitePanel/Sources/WebsitePanel.Server.Client/OrganizationProxy.cs
@@ -87,6 +87,8 @@ namespace WebsitePanel.Providers.HostedSolution
private System.Threading.SendOrPostCallback AddUserToSecurityGroupOperationCompleted;
+ private System.Threading.SendOrPostCallback DeleteUserFromSecurityGroupOperationCompleted;
+
private System.Threading.SendOrPostCallback SetUserGeneralSettingsOperationCompleted;
private System.Threading.SendOrPostCallback SetUserPasswordOperationCompleted;
@@ -142,6 +144,9 @@ namespace WebsitePanel.Providers.HostedSolution
///
public event AddUserToSecurityGroupCompletedEventHandler AddUserToSecurityGroupCompleted;
+ ///
+ public event DeleteUserFromSecurityGroupCompletedEventHandler DeleteUserFromSecurityGroupCompleted;
+
///
public event SetUserGeneralSettingsCompletedEventHandler SetUserGeneralSettingsCompleted;
@@ -757,6 +762,60 @@ namespace WebsitePanel.Providers.HostedSolution
}
}
+ ///
+ [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceProviderSettingsSoapHeaderValue")]
+ [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/DeleteUserFromSecurityGroup", RequestNamespace = "http://tempuri.org/", ResponseNamespace = "http://tempuri.org/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
+ public void DeleteUserFromSecurityGroup(string organizationId, string loginName, string groupName)
+ {
+ this.Invoke("DeleteUserFromSecurityGroup", new object[] {
+ organizationId,
+ loginName,
+ groupName});
+ }
+
+ ///
+ public System.IAsyncResult BeginDeleteUserFromSecurityGroup(string organizationId, string loginName, string groupName, System.AsyncCallback callback, object asyncState)
+ {
+ return this.BeginInvoke("DeleteUserFromSecurityGroup", new object[] {
+ organizationId,
+ loginName,
+ groupName}, callback, asyncState);
+ }
+
+ ///
+ public void EndDeleteUserFromSecurityGroup(System.IAsyncResult asyncResult)
+ {
+ this.EndInvoke(asyncResult);
+ }
+
+ ///
+ public void DeleteUserFromSecurityGroupAsync(string organizationId, string loginName, string groupName)
+ {
+ this.DeleteUserFromSecurityGroupAsync(organizationId, loginName, groupName, null);
+ }
+
+ ///
+ public void DeleteUserFromSecurityGroupAsync(string organizationId, string loginName, string groupName, object userState)
+ {
+ if ((this.DeleteUserFromSecurityGroupOperationCompleted == null))
+ {
+ this.DeleteUserFromSecurityGroupOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDeleteUserFromSecurityGroupOperationCompleted);
+ }
+ this.InvokeAsync("DeleteUserFromSecurityGroup", new object[] {
+ organizationId,
+ loginName,
+ groupName}, this.DeleteUserFromSecurityGroupOperationCompleted, userState);
+ }
+
+ private void OnDeleteUserFromSecurityGroupOperationCompleted(object arg)
+ {
+ if ((this.DeleteUserFromSecurityGroupCompleted != null))
+ {
+ System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
+ this.DeleteUserFromSecurityGroupCompleted(this, new System.ComponentModel.AsyncCompletedEventArgs(invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
+ }
+ }
+
///
[System.Web.Services.Protocols.SoapHeaderAttribute("ServiceProviderSettingsSoapHeaderValue")]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/SetUserGeneralSettings", RequestNamespace = "http://tempuri.org/", ResponseNamespace = "http://tempuri.org/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
@@ -1568,6 +1627,10 @@ namespace WebsitePanel.Providers.HostedSolution
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
public delegate void AddUserToSecurityGroupCompletedEventHandler(object sender, System.ComponentModel.AsyncCompletedEventArgs e);
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
+ public delegate void DeleteUserFromSecurityGroupCompletedEventHandler(object sender, System.ComponentModel.AsyncCompletedEventArgs e);
+
///
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
public delegate void SetUserGeneralSettingsCompletedEventHandler(object sender, System.ComponentModel.AsyncCompletedEventArgs e);
diff --git a/WebsitePanel/Sources/WebsitePanel.Server/Organizations.asmx.cs b/WebsitePanel/Sources/WebsitePanel.Server/Organizations.asmx.cs
index dd7f3504..3c1dced6 100644
--- a/WebsitePanel/Sources/WebsitePanel.Server/Organizations.asmx.cs
+++ b/WebsitePanel/Sources/WebsitePanel.Server/Organizations.asmx.cs
@@ -140,6 +140,12 @@ namespace WebsitePanel.Server
Organization.AddUserToSecurityGroup(organizationId, loginName, groupName);
}
+ [WebMethod, SoapHeader("settings")]
+ public void DeleteUserFromSecurityGroup(string organizationId, string loginName, string groupName)
+ {
+ Organization.DeleteUserFromSecurityGroup(organizationId, loginName, groupName);
+ }
+
[WebMethod, SoapHeader("settings")]
public void SetUserGeneralSettings(string organizationId, string accountName, string displayName, string password,
bool hideFromAddressBook, bool disabled, bool locked, string firstName, string initials, string lastName,
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationSecurityGroupGeneralSettings.ascx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationSecurityGroupGeneralSettings.ascx.cs
index d8f71bf4..3f65ec36 100644
--- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationSecurityGroupGeneralSettings.ascx.cs
+++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationSecurityGroupGeneralSettings.ascx.cs
@@ -77,6 +77,8 @@ namespace WebsitePanel.Portal.ExchangeServer
txtNotes.ReadOnly = true;
manager.Enabled = false;
members.Enabled = false;
+
+ btnSave.Visible = false;
}
}
catch (Exception ex)
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationSecurityGroups.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationSecurityGroups.ascx
index 14eabbc4..13dcbc4c 100644
--- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationSecurityGroups.ascx
+++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationSecurityGroups.ascx
@@ -53,7 +53,7 @@
DataSourceID="odsSecurityGroupsPaged" PageSize="20">
-
+
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationUserMemberOf.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationUserMemberOf.ascx
index 845db39c..36c12744 100644
--- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationUserMemberOf.ascx
+++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationUserMemberOf.ascx
@@ -10,7 +10,7 @@
<%@ Register Src="UserControls/Breadcrumb.ascx" TagName="Breadcrumb" TagPrefix="wsp" %>
<%@ Register Src="UserControls/EmailAddress.ascx" TagName="EmailAddress" TagPrefix="wsp" %>
<%@ Register Src="UserControls/AccountsList.ascx" TagName="AccountsList" TagPrefix="wsp" %>
-<%@ Register Src="UserControls/UsersList.ascx" TagName="UsersList" TagPrefix="wsp" %>
+<%@ Register Src="UserControls/GroupsList.ascx" TagName="GroupsList" TagPrefix="wsp" %>
@@ -63,11 +63,7 @@
-
+
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationUserMemberOf.ascx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationUserMemberOf.ascx.cs
index 616eb0b4..cf175d4a 100644
--- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationUserMemberOf.ascx.cs
+++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationUserMemberOf.ascx.cs
@@ -58,10 +58,17 @@ namespace WebsitePanel.Portal.HostedSolution
// title
litDisplayName.Text = mailbox.DisplayName;
-
+
+ //Distribution Lists
ExchangeAccount[] dLists = ES.Services.ExchangeServer.GetDistributionListsByMember(PanelRequest.ItemID, PanelRequest.AccountID);
distrlists.SetAccounts(dLists);
+
+ //Security Groups
+ ExchangeAccount[] securGroups = ES.Services.Organizations.GetSecurityGroupsByMember(PanelRequest.ItemID, PanelRequest.AccountID);
+
+ securegroups.SetAccounts(securGroups);
+
}
catch (Exception ex)
{
@@ -76,6 +83,7 @@ namespace WebsitePanel.Portal.HostedSolution
try
{
+ //Distribution Lists
ExchangeAccount[] oldDistributionLists = ES.Services.ExchangeServer.GetDistributionListsByMember(PanelRequest.ItemID, PanelRequest.AccountID);
List newDistributionLists = new List(distrlists.GetAccounts());
foreach (ExchangeAccount oldlist in oldDistributionLists)
@@ -89,7 +97,29 @@ namespace WebsitePanel.Portal.HostedSolution
foreach (string newlist in newDistributionLists)
ES.Services.ExchangeServer.AddDistributionListMember(PanelRequest.ItemID, newlist, PanelRequest.AccountID);
+ //Security Groups
+ ExchangeAccount[] oldDSecurityGroups = ES.Services.Organizations.GetSecurityGroupsByMember(PanelRequest.ItemID, PanelRequest.AccountID);
+ List newSecurityGroups = new List(securegroups.GetAccounts());
+ foreach (ExchangeAccount oldgroup in oldDSecurityGroups)
+ {
+ if (newSecurityGroups.Contains(oldgroup.AccountName))
+ {
+ newSecurityGroups.Remove(oldgroup.AccountName);
+ }
+ else
+ {
+ ES.Services.Organizations.DeleteUserFromSecurityGroup(PanelRequest.ItemID, PanelRequest.AccountID, oldgroup.AccountName);
+ }
+ }
+
+ foreach (string newgroup in newSecurityGroups)
+ {
+ ES.Services.Organizations.AddUserToSecurityGroup(PanelRequest.ItemID, PanelRequest.AccountID, newgroup);
+ }
+
messageBox.ShowSuccessMessage("EXCHANGE_UPDATE_MAILBOX_SETTINGS");
+
+
BindSettings();
}
catch (Exception ex)
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationUserMemberOf.ascx.designer.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationUserMemberOf.ascx.designer.cs
index 0de5ac65..a93df787 100644
--- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationUserMemberOf.ascx.designer.cs
+++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationUserMemberOf.ascx.designer.cs
@@ -163,7 +163,7 @@ namespace WebsitePanel.Portal.HostedSolution {
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
///
- protected global::WebsitePanel.Portal.ExchangeServer.UserControls.AccountsList securegroups;
+ protected global::WebsitePanel.Portal.ExchangeServer.UserControls.GroupsList securegroups;
///
/// btnSave control.
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/App_LocalResources/GroupsList.ascx.resx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/App_LocalResources/GroupsList.ascx.resx
new file mode 100644
index 00000000..58447d25
--- /dev/null
+++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/App_LocalResources/GroupsList.ascx.resx
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Add...
+
+
+ Add Groups
+
+
+ Cancel
+
+
+ Delete
+
+
+ Display Name
+
+
+ The list of groups is empty. Click "Add..." button to add groups.
+
+
+ Display Name
+
+
+ No groups found.
+
+
+ Groups
+
+
\ No newline at end of file
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/GroupsList.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/GroupsList.ascx
new file mode 100644
index 00000000..185955d8
--- /dev/null
+++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/GroupsList.ascx
@@ -0,0 +1,105 @@
+<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="GroupsList.ascx.cs" Inherits="WebsitePanel.Portal.ExchangeServer.UserControls.GroupsList" %>
+<%@ Register Src="../../UserControls/PopupHeader.ascx" TagName="PopupHeader" TagPrefix="wsp" %>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/GroupsList.ascx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/GroupsList.ascx.cs
new file mode 100644
index 00000000..85508aec
--- /dev/null
+++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/GroupsList.ascx.cs
@@ -0,0 +1,197 @@
+// Copyright (c) 2012, Outercurve Foundation.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// - Neither the name of the Outercurve Foundation nor the names of its
+// contributors may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using System;
+using System.Collections.Generic;
+using System.Web.UI;
+using System.Web.UI.WebControls;
+using WebsitePanel.Providers.HostedSolution;
+using System.Linq;
+
+namespace WebsitePanel.Portal.ExchangeServer.UserControls
+{
+ public partial class GroupsList : WebsitePanelControlBase
+ {
+ private enum SelectedState
+ {
+ All,
+ Selected,
+ Unselected
+ }
+
+ public void SetAccounts(ExchangeAccount[] accounts)
+ {
+ BindAccounts(accounts, false);
+ }
+
+ public string[] GetAccounts()
+ {
+ // get selected accounts
+ List selectedAccounts = GetGridViewAccounts(gvGroups, SelectedState.All);
+
+ List accountNames = new List();
+ foreach (ExchangeAccount account in selectedAccounts)
+ accountNames.Add(account.AccountName);
+
+ return accountNames.ToArray();
+ }
+
+ protected void Page_Load(object sender, EventArgs e)
+ {
+ // register javascript
+ if (!Page.ClientScript.IsClientScriptBlockRegistered("SelectAllCheckboxes"))
+ {
+ string script = @" function SelectAllCheckboxes(box)
+ {
+ var state = box.checked;
+ var elm = box.parentElement.parentElement.parentElement.parentElement.getElementsByTagName(""INPUT"");
+ for(i = 0; i < elm.length; i++)
+ if(elm[i].type == ""checkbox"" && elm[i].id != box.id && elm[i].checked != state && !elm[i].disabled)
+ elm[i].checked = state;
+ }";
+ Page.ClientScript.RegisterClientScriptBlock(typeof(AccountsList), "SelectAllCheckboxes",
+ script, true);
+ }
+ }
+
+ public string GetAccountImage(int accountTypeId)
+ {
+ ExchangeAccountType accountType = (ExchangeAccountType)accountTypeId;
+ string imgName = "dlist_16.gif";
+
+ return GetThemedImage("Exchange/" + imgName);
+ }
+
+ protected void btnAdd_Click(object sender, EventArgs e)
+ {
+ // bind all accounts
+ BindPopupAccounts();
+
+ // show modal
+ AddGroupsModal.Show();
+ }
+
+ protected void btnDelete_Click(object sender, EventArgs e)
+ {
+ // get selected accounts
+ List selectedAccounts = GetGridViewAccounts(gvGroups, SelectedState.Unselected);
+
+ // add to the main list
+ BindAccounts(selectedAccounts.ToArray(), false);
+ }
+
+ protected void btnAddSelected_Click(object sender, EventArgs e)
+ {
+ // get selected accounts
+ List selectedAccounts = GetGridViewAccounts(gvPopupGroups, SelectedState.Selected);
+
+ // add to the main list
+ BindAccounts(selectedAccounts.ToArray(), true);
+ }
+
+ private void BindPopupAccounts()
+ {
+ ExchangeAccount[] accounts = ES.Services.Organizations.SearchSecurityGroups(PanelRequest.ItemID,
+ ddlSearchColumn.SelectedValue, txtSearchValue.Text + "%", "");
+
+ accounts = accounts.Where(x => !GetAccounts().Contains(x.AccountName)).ToArray();
+
+ gvPopupGroups.DataSource = accounts;
+ gvPopupGroups.DataBind();
+ }
+
+ private void BindAccounts(ExchangeAccount[] newAccounts, bool preserveExisting)
+ {
+ // get binded addresses
+ List accounts = new List();
+ if(preserveExisting)
+ accounts.AddRange(GetGridViewAccounts(gvGroups, SelectedState.All));
+
+ // add new accounts
+ if (newAccounts != null)
+ {
+ foreach (ExchangeAccount newAccount in newAccounts)
+ {
+ // check if exists
+ bool exists = false;
+ foreach (ExchangeAccount account in accounts)
+ {
+ if (String.Compare(newAccount.AccountName, account.AccountName, true) == 0)
+ {
+ exists = true;
+ break;
+ }
+ }
+
+ if (exists)
+ continue;
+
+ accounts.Add(newAccount);
+ }
+ }
+
+ gvGroups.DataSource = accounts;
+ gvGroups.DataBind();
+
+ btnDelete.Visible = gvGroups.Rows.Count > 0;
+ }
+
+ private List GetGridViewAccounts(GridView gv, SelectedState state)
+ {
+ List accounts = new List();
+ for (int i = 0; i < gv.Rows.Count; i++)
+ {
+ GridViewRow row = gv.Rows[i];
+ CheckBox chkSelect = (CheckBox)row.FindControl("chkSelect");
+ if (chkSelect == null)
+ continue;
+
+ ExchangeAccount account = new ExchangeAccount();
+ account.AccountType = (ExchangeAccountType)Enum.Parse(typeof(ExchangeAccountType), ((Literal)row.FindControl("litAccountType")).Text);
+ account.AccountName = (string)gv.DataKeys[i][0];
+ account.DisplayName = ((Literal)row.FindControl("litDisplayName")).Text;
+
+ if(state == SelectedState.All ||
+ (state == SelectedState.Selected && chkSelect.Checked) ||
+ (state == SelectedState.Unselected && !chkSelect.Checked))
+ accounts.Add(account);
+ }
+ return accounts;
+ }
+
+ protected void chkIncludeMailboxes_CheckedChanged(object sender, EventArgs e)
+ {
+ BindPopupAccounts();
+ }
+
+ protected void cmdSearch_Click(object sender, ImageClickEventArgs e)
+ {
+ BindPopupAccounts();
+ }
+ }
+}
\ No newline at end of file
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/GroupsList.ascx.designer.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/GroupsList.ascx.designer.cs
new file mode 100644
index 00000000..1c6bff39
--- /dev/null
+++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/GroupsList.ascx.designer.cs
@@ -0,0 +1,159 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace WebsitePanel.Portal.ExchangeServer.UserControls {
+
+
+ public partial class GroupsList {
+
+ ///
+ /// GroupsUpdatePanel control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.UpdatePanel GroupsUpdatePanel;
+
+ ///
+ /// btnAdd control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Button btnAdd;
+
+ ///
+ /// btnDelete control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Button btnDelete;
+
+ ///
+ /// gvGroups control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.GridView gvGroups;
+
+ ///
+ /// AddGroupsPanel control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Panel AddGroupsPanel;
+
+ ///
+ /// headerAddGroups control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Localize headerAddGroups;
+
+ ///
+ /// AddGroupsUpdatePanel control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.UpdatePanel AddGroupsUpdatePanel;
+
+ ///
+ /// SearchPanel control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Panel SearchPanel;
+
+ ///
+ /// ddlSearchColumn control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.DropDownList ddlSearchColumn;
+
+ ///
+ /// txtSearchValue control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.TextBox txtSearchValue;
+
+ ///
+ /// cmdSearch control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.ImageButton cmdSearch;
+
+ ///
+ /// gvPopupGroups control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.GridView gvPopupGroups;
+
+ ///
+ /// btnAddSelected control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Button btnAddSelected;
+
+ ///
+ /// btnCancelAdd control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Button btnCancelAdd;
+
+ ///
+ /// btnAddAccountsFake control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::System.Web.UI.WebControls.Button btnAddAccountsFake;
+
+ ///
+ /// AddGroupsModal control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::AjaxControlToolkit.ModalPopupExtender AddGroupsModal;
+ }
+}
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/UsersList.ascx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/UsersList.ascx.cs
index d518459a..b8311fd5 100644
--- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/UsersList.ascx.cs
+++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/UserControls/UsersList.ascx.cs
@@ -31,6 +31,7 @@ using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
using WebsitePanel.Providers.HostedSolution;
+using System.Linq;
namespace WebsitePanel.Portal.ExchangeServer.UserControls
{
@@ -218,6 +219,10 @@ namespace WebsitePanel.Portal.ExchangeServer.UserControls
OrganizationUser[] accounts = ES.Services.Organizations.SearchAccounts(PanelRequest.ItemID,
ddlSearchColumn.SelectedValue, txtSearchValue.Text + "%", "", IncludeMailboxes);
+ List newAccounts = new List();
+
+ accounts = accounts.Where(x => !GetAccounts().Contains(x.AccountName)).ToArray();
+
if (ExcludeAccountId > 0)
{
List updatedAccounts = new List();
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebsitePanel.Portal.Modules.csproj b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebsitePanel.Portal.Modules.csproj
index 0216f51a..975475c9 100644
--- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebsitePanel.Portal.Modules.csproj
+++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebsitePanel.Portal.Modules.csproj
@@ -283,6 +283,13 @@
AccountsListWithPermissions.ascx
ASPXCodeBehind
+
+ GroupsList.ascx
+ ASPXCodeBehind
+
+
+ GroupsList.ascx
+
MailboxPlanSelector.ascx
ASPXCodeBehind
@@ -3977,6 +3984,7 @@
+
@@ -5189,6 +5197,9 @@
+
+ Designer
+
Designer