password reset scheduler added

This commit is contained in:
vfedosevich 2015-04-02 04:36:45 -07:00
parent c5b6c0d9f6
commit aa59d180e2
33 changed files with 2180 additions and 1078 deletions

View file

@ -9459,4 +9459,147 @@ BEGIN
(SELECT TOP 1 @item_type_id, @group_id, 'SharePointSiteCollection', TypeName, 100, CalculateDiskSpace, CalculateBandwidth, Suspendable, Disposable, Searchable, Importable, Backupable FROM [dbo].[ServiceItemTypes] WHERE DisplayName = 'SharePointFoundationSiteCollection')
END
GO
GO
-- USER PASSWORD EXPIRATION NOTIFICATION tasks
IF NOT EXISTS (SELECT * FROM [dbo].[ScheduleTasks] WHERE [TaskID] = N'SCHEDULE_TASK_USER_PASSWORD_EXPIRATION_NOTIFICATION')
BEGIN
INSERT [dbo].[ScheduleTasks] ([TaskID], [TaskType], [RoleID]) VALUES (N'SCHEDULE_TASK_USER_PASSWORD_EXPIRATION_NOTIFICATION', N'WebsitePanel.EnterpriseServer.UserPasswordExpirationNotificationTask, WebsitePanel.EnterpriseServer.Code', 1)
END
GO
IF NOT EXISTS (SELECT * FROM [dbo].[ScheduleTaskViewConfiguration] WHERE [TaskID] = N'SCHEDULE_TASK_USER_PASSWORD_EXPIRATION_NOTIFICATION')
BEGIN
INSERT [dbo].[ScheduleTaskViewConfiguration] ([TaskID], [ConfigurationID], [Environment], [Description]) VALUES (N'SCHEDULE_TASK_USER_PASSWORD_EXPIRATION_NOTIFICATION', N'ASP_NET', N'ASP.NET', N'~/DesktopModules/WebsitePanel/ScheduleTaskControls/UserPasswordExpirationNotificationView.ascx')
END
GO
IF NOT EXISTS (SELECT * FROM [dbo].[ScheduleTaskParameters] WHERE [TaskID] = N'SCHEDULE_TASK_USER_PASSWORD_EXPIRATION_NOTIFICATION' AND [ParameterID]= N'DAYS_BEFORE_EXPIRATION' )
BEGIN
INSERT [dbo].[ScheduleTaskParameters] ([TaskID], [ParameterID], [DataTypeID], [DefaultValue], [ParameterOrder]) VALUES (N'SCHEDULE_TASK_USER_PASSWORD_EXPIRATION_NOTIFICATION', N'DAYS_BEFORE_EXPIRATION', N'String', NULL, 1)
END
GO
-- USER PASSWORD EXPIRATION EMAIL TEMPLATE
IF NOT EXISTS (SELECT * FROM [dbo].[UserSettings] WHERE [UserID] = 1 AND [SettingsName]= N'UserPasswordExpirationLetter' AND [PropertyName]= N'WebDavPortalResetUrl' )
BEGIN
INSERT [dbo].[UserSettings] ([UserID], [SettingsName], [PropertyName], [PropertyValue]) VALUES (1, N'UserPasswordExpirationLetter', N'WebDavPortalResetUrl', N'http://webdav.virtuworks.net/')
END
GO
IF NOT EXISTS (SELECT * FROM [dbo].[UserSettings] WHERE [UserID] = 1 AND [SettingsName]= N'UserPasswordExpirationLetter' AND [PropertyName]= N'From' )
BEGIN
INSERT [dbo].[UserSettings] ([UserID], [SettingsName], [PropertyName], [PropertyValue]) VALUES (1, N'UserPasswordExpirationLetter', N'From', N'support@HostingCompany.com')
END
GO
DECLARE @UserPasswordExpirationLetterHtmlBody nvarchar(2500)
Set @UserPasswordExpirationLetterHtmlBody = N'<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Password expiration notification</title>
<style type="text/css">
.Summary { background-color: ##ffffff; padding: 5px; }
.Summary .Header { padding: 10px 0px 10px 10px; font-size: 16pt; background-color: ##E5F2FF; color: ##1F4978; border-bottom: solid 2px ##86B9F7; }
.Summary A { color: ##0153A4; }
.Summary { font-family: Tahoma; font-size: 9pt; }
.Summary H1 { font-size: 1.7em; color: ##1F4978; border-bottom: dotted 3px ##efefef; }
.Summary H2 { font-size: 1.3em; color: ##1F4978; }
.Summary TABLE { border: solid 1px ##e5e5e5; }
.Summary TH,
.Summary TD.Label { padding: 5px; font-size: 8pt; font-weight: bold; background-color: ##f5f5f5; }
.Summary TD { padding: 8px; font-size: 9pt; }
.Summary UL LI { font-size: 1.1em; font-weight: bold; }
.Summary UL UL LI { font-size: 0.9em; font-weight: normal; }
</style>
</head>
<body>
<div class="Summary">
<div class="Header">
<img src="#logoUrl#">
</div>
<h1>Password expiration notification</h1>
<ad:if test="#user#">
<p>
Hello #user.FirstName#,
</p>
</ad:if>
<p>
Your password will expire at #user.PasswordExpirationDateTime#. You can reset your own password by visiting the following page:
</p>
<a href="#passwordResetLink#">#passwordResetLink#</a>
<p>
If you have any questions regarding your hosting account, feel free to contact our support department at any time.
</p>
<p>
Best regards
</p>
</div>
</body>';
IF NOT EXISTS (SELECT * FROM [dbo].[UserSettings] WHERE [UserID] = 1 AND [SettingsName]= N'UserPasswordExpirationLetter' AND [PropertyName]= N'HtmlBody' )
BEGIN
INSERT [dbo].[UserSettings] ([UserID], [SettingsName], [PropertyName], [PropertyValue]) VALUES (1, N'UserPasswordExpirationLetter', N'HtmlBody', @UserPasswordExpirationLetterHtmlBody)
END
ELSE
UPDATE [dbo].[UserSettings] SET [PropertyValue] = @UserPasswordExpirationLetterHtmlBody WHERE [UserID] = 1 AND [SettingsName]= N'UserPasswordExpirationLetter' AND [PropertyName]= N'HtmlBody'
GO
IF NOT EXISTS (SELECT * FROM [dbo].[UserSettings] WHERE [UserID] = 1 AND [SettingsName]= N'UserPasswordExpirationLetter' AND [PropertyName]= N'Priority' )
BEGIN
INSERT [dbo].[UserSettings] ([UserID], [SettingsName], [PropertyName], [PropertyValue]) VALUES (1, N'UserPasswordExpirationLetter', N'Priority', N'Normal')
END
GO
IF NOT EXISTS (SELECT * FROM [dbo].[UserSettings] WHERE [UserID] = 1 AND [SettingsName]= N'UserPasswordExpirationLetter' AND [PropertyName]= N'Subject' )
BEGIN
INSERT [dbo].[UserSettings] ([UserID], [SettingsName], [PropertyName], [PropertyValue]) VALUES (1, N'UserPasswordExpirationLetter', N'Subject', N'Password expiration notification')
END
GO
IF NOT EXISTS (SELECT * FROM [dbo].[UserSettings] WHERE [UserID] = 1 AND [SettingsName]= N'UserPasswordExpirationLetter' AND [PropertyName]= N'LogoUrl' )
BEGIN
INSERT [dbo].[UserSettings] ([UserID], [SettingsName], [PropertyName], [PropertyValue]) VALUES (1, N'UserPasswordExpirationLetter', N'LogoUrl', N'https://controlpanel.virtuworks.net/App_Themes/Default/Images/logo.png')
END
GO
DECLARE @UserPasswordExpirationLetterTextBody nvarchar(2500)
Set @UserPasswordExpirationLetterTextBody = N'=========================================
Password expiration notification
=========================================
<ad:if test="#user#">
Hello #user.FirstName#,
</ad:if>
Your password will expire at #user.PasswordExpirationDateTime#. You can reset your own password by visiting the following page:
#passwordResetLink#
If you have any questions regarding your hosting account, feel free to contact our support department at any time.
Best regards'
IF NOT EXISTS (SELECT * FROM [dbo].[UserSettings] WHERE [UserID] = 1 AND [SettingsName]= N'UserPasswordExpirationLetter' AND [PropertyName]= N'TextBody' )
BEGIN
INSERT [dbo].[UserSettings] ([UserID], [SettingsName], [PropertyName], [PropertyValue]) VALUES (1, N'UserPasswordExpirationLetter', N'TextBody', @UserPasswordExpirationLetterTextBody)
END
ELSE
UPDATE [dbo].[UserSettings] SET [PropertyValue] = @UserPasswordExpirationLetterTextBody WHERE [UserID] = 1 AND [SettingsName]= N'UserPasswordExpirationLetter' AND [PropertyName]= N'TextBody'
GO

View file

@ -65,6 +65,8 @@ namespace WebsitePanel.EnterpriseServer
public const string DEFAULT_LYNCUSERPLANS = "DefaultLyncUserPlans";
public const string RDS_SETUP_LETTER = "RDSSetupLetter";
public const string RDS_POLICY = "RdsPolicy";
public const string USER_PASSWORD_EXPIRATION_LETTER = "UserPasswordExpirationLetter";
public int UserId;
public string SettingsName;

View file

@ -1494,7 +1494,65 @@ namespace WebsitePanel.EnterpriseServer
return result;
}
public static List<OrganizationUser> GetOrganizationUsersWithExpiredPassword(int itemId, int daysBeforeExpiration)
{
// load organization
Organization org = GetOrganization(itemId);
if (org == null)
{
return null;
}
Organizations orgProxy = GetOrganizationProxy(org.ServiceId);
var expiredUsersAd = orgProxy.GetOrganizationUsersWithExpiredPassword(org.OrganizationId, daysBeforeExpiration);
var expiredUsersDb = GetOrganizationUsersPaged(itemId, null, null, null, 0, int.MaxValue).PageUsers.Where(x => expiredUsersAd.Any(z => z.SamAccountName == x.SamAccountName)).ToList();
foreach (var user in expiredUsersDb)
{
var adUser = expiredUsersAd.First(x => x.SamAccountName == user.SamAccountName);
user.PasswordExpirationDateTime = adUser.PasswordExpirationDateTime;
}
return expiredUsersDb;
}
public static void SendResetUserPasswordEmail(UserInfo owner, OrganizationUser user, string mailTo, string logoUrl)
{
UserSettings settings = UserController.GetUserSettings(owner.UserId, UserSettings.USER_PASSWORD_EXPIRATION_LETTER);
if (string.IsNullOrEmpty(logoUrl))
{
logoUrl = settings["LogoUrl"];
}
string from = settings["From"];
string subject = settings["Subject"];
string body = owner.HtmlMail ? settings["HtmlBody"] : settings["TextBody"];
bool isHtml = owner.HtmlMail;
MailPriority priority = MailPriority.Normal;
if (!String.IsNullOrEmpty(settings["Priority"]))
{
priority = (MailPriority)Enum.Parse(typeof(MailPriority), settings["Priority"], true);
}
Hashtable items = new Hashtable();
items["user"] = user;
items["logoUrl"] = logoUrl;
items["passwordResetLink"] = "reset link";
body = PackageController.EvaluateTemplate(body, items);
// send mail message
//MailHelper.SendMessage(from, mailTo, string.Empty, subject, body, priority, isHtml);
}
private static bool EmailAddressExists(string emailAddress)
{

View file

@ -0,0 +1,63 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using WebsitePanel.Providers.HostedSolution;
namespace WebsitePanel.EnterpriseServer
{
public class UserPasswordExpirationNotificationTask : SchedulerTask
{
private static readonly string TaskId = "SCHEDULE_TASK_DOMAIN_EXPIRATION";
// Input parameters:
private static readonly string DaysBeforeNotify = "DAYS_BEFORE_EXPIRATION";
public override void DoWork()
{
BackgroundTask topTask = TaskManager.TopTask;
int daysBeforeNotify;
// check input parameters
if (!int.TryParse((string)topTask.GetParamValue(DaysBeforeNotify), out daysBeforeNotify))
{
TaskManager.WriteWarning("Specify 'Notify before (days)' task parameter");
return;
}
var owner = UserController.GetUser(topTask.EffectiveUserId);
var packages = PackageController.GetMyPackages(topTask.EffectiveUserId);
foreach (var package in packages)
{
var organizations = ExchangeServerController.GetExchangeOrganizations(package.PackageId, true);
foreach (var organization in organizations)
{
var usersWithExpiredPasswords = OrganizationController.GetOrganizationUsersWithExpiredPassword(organization.Id, daysBeforeNotify);
foreach (var user in usersWithExpiredPasswords)
{
if (string.IsNullOrEmpty(user.PrimaryEmailAddress))
{
TaskManager.WriteWarning(string.Format("Unable to send email to {0} user (organization: {1}), user primary email address is not set.", user.DisplayName, organization.OrganizationId));
continue;
}
TaskManager.Write(string.Format("Email sent to {0} user (organization: {1}).", user.DisplayName, organization.OrganizationId));
OrganizationController.SendResetUserPasswordEmail(owner, user, user.PrimaryEmailAddress, string.Empty);
}
}
}
// send mail message
// MailHelper.SendMessage(mailFrom, mailTo, mailSubject, mailBody, false);
}
}
}

View file

@ -158,6 +158,7 @@
<Compile Include="SchedulerTasks\SendMailNotificationTask.cs" />
<Compile Include="SchedulerTasks\SuspendOverdueInvoicesTask.cs" />
<Compile Include="SchedulerTasks\SuspendOverusedPackagesTask.cs" />
<Compile Include="SchedulerTasks\UserPasswordExpirationNotificationTask.cs" />
<Compile Include="SchedulerTasks\ZipFilesTask.cs" />
<Compile Include="Scheduling\Scheduler.cs" />
<Compile Include="Scheduling\SchedulerController.cs" />

View file

@ -26,6 +26,7 @@
// (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.Collections.Generic;
using WebsitePanel.Providers.OS;
using WebsitePanel.Providers.ResultObjects;
@ -96,5 +97,7 @@ namespace WebsitePanel.Providers.HostedSolution
void SetDriveMapsTargetingFilter(string organizationId, ExchangeAccount[] accounts, string folderName);
void ChangeDriveMapFolderPath(string organizationId, string oldFolder, string newFolder);
List<OrganizationUser> GetOrganizationUsersWithExpiredPassword(string organizationId, int daysBeforeExpiration);
}
}

View file

@ -334,5 +334,7 @@ namespace WebsitePanel.Providers.HostedSolution
get { return userMustChangePassword; }
set { userMustChangePassword = value; }
}
public DateTime PasswordExpirationDateTime { get; set; }
}
}

View file

@ -27,6 +27,7 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System;
using System.DirectoryServices.ActiveDirectory;
using System.IO;
using System.Xml;
using System.Linq;
@ -480,6 +481,77 @@ namespace WebsitePanel.Providers.HostedSolution
return Errors.OK;
}
public List<OrganizationUser> GetOrganizationUsersWithExpiredPassword(string organizationId, int daysBeforeExpiration)
{
return GetOrganizationUsersWithExpiredPasswordInternal(organizationId, daysBeforeExpiration);
}
internal List<OrganizationUser> GetOrganizationUsersWithExpiredPasswordInternal(string organizationId, int daysBeforeExpiration)
{
var result = new List<OrganizationUser>();
var maxPasswordAgeSpan = GetMaxPasswordAge();
var searchRoot = new DirectoryEntry(GetOrganizationPath(organizationId));
var search = new DirectorySearcher(searchRoot)
{
SearchScope = SearchScope.Subtree,
Filter = "(objectClass=user)"
};
search.PropertiesToLoad.Add("pwdLastSet");
search.PropertiesToLoad.Add("sAMAccountName");
SearchResultCollection searchResults = search.FindAll();
foreach (SearchResult searchResult in searchResults)
{
var pwdLastSetTicks = (long)searchResult.Properties["pwdLastSet"][0];
var pwdLastSetDate = DateTime.FromFileTimeUtc(pwdLastSetTicks);
var expirationDate = pwdLastSetDate.AddDays(maxPasswordAgeSpan.Days);
if (pwdLastSetDate > expirationDate.AddDays(-daysBeforeExpiration))
{
var user = new OrganizationUser();
user.PasswordExpirationDateTime = expirationDate;
user.SamAccountName = (string)searchResult.Properties["sAMAccountName"][0];
result.Add(user);
}
}
return result;
}
internal TimeSpan GetMaxPasswordAge()
{
using (Domain d = Domain.GetCurrentDomain())
{
using (DirectoryEntry domain = d.GetDirectoryEntry())
{
DirectorySearcher ds = new DirectorySearcher(
domain,
"(objectClass=*)",
null,
SearchScope.Base
);
SearchResult sr = ds.FindOne();
if (sr != null && sr.Properties.Contains("maxPwdAge"))
{
return TimeSpan.FromTicks((long)sr.Properties["maxPwdAge"][0]).Duration();
}
throw new Exception("'maxPwdAge' property not found.");
}
}
}
public PasswordPolicyResult GetPasswordPolicy()
{
return GetPasswordPolicyInternal();

View file

@ -27,6 +27,7 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Web.Services;
using System.Web.Services.Protocols;
@ -254,5 +255,11 @@ namespace WebsitePanel.Server
{
Organization.ChangeDriveMapFolderPath(organizationId, oldFolder, newFolder);
}
[WebMethod, SoapHeader("settings")]
public List<OrganizationUser> GetOrganizationUsersWithExpiredPassword(string organizationId, int daysBeforeExpiration)
{
return Organization.GetOrganizationUsersWithExpiredPassword(organizationId, daysBeforeExpiration);
}
}
}

View file

@ -13,6 +13,7 @@
<Control key="edit_user" general_key="users" /> <!--?-->
<Control key="create_user" general_key="users" />
<Control key="user_memberof" general_key="users" />
<Control key="user_reset_password" general_key="users" />
<!--<Control key="organization_user_setup" />-->
<Control key="deleted_users" />

View file

@ -471,6 +471,7 @@
<Control key="" src="WebsitePanel/ExchangeServer/Organizations.ascx" title="Organizations" type="View" />
<Control key="edit_user" src="WebsitePanel/ExchangeServer/OrganizationUserGeneralSettings.ascx" title="OrganizationUserGeneralSettings" type="View" />
<Control key="users" src="WebsitePanel/ExchangeServer/OrganizationUsers.ascx" title="OrganizationUsers" type="View" />
<Control key="user_reset_password" src="WebsitePanel/ExchangeServer/OrganizationUserResetPassword.ascx" title="OrganizationUsers" type="View" />
<Control key="create_user" src="WebsitePanel/ExchangeServer/OrganizationCreateUser.ascx" title="CreateUser" type="View" />
<Control key="create_organization" src="WebsitePanel/ExchangeServer/OrganizationCreateOrganization.ascx" title="OrganizationCreateOrganization" type="View" />
<Control key="organization_home" src="WebsitePanel/ExchangeServer/OrganizationHome.ascx" title="OrganizationHome" type="View" />

View file

@ -3345,7 +3345,6 @@
</data>
<data name="ResourceGroup.Hosted CRM" xml:space="preserve">
<value>CRM 4/2011</value>
<comment> </comment>
</data>
<data name="ResourceGroup.BlackBerry" xml:space="preserve">
<value>BlackBerry</value>
@ -3377,7 +3376,7 @@
<data name="ResourceGroup.SharePoint Foundation Server" xml:space="preserve">
<value>SharePoint Foundation Server</value>
</data>
<data name="ResourceGroup.SharePoint Server" xml:space="preserve">
<data name="ResourceGroup.SharePoint Server" xml:space="preserve">
<value>SharePoint Server</value>
</data>
<data name="ResourceGroup.OCS" xml:space="preserve">
@ -5711,4 +5710,7 @@
<data name="Success.REMOTE_DESKTOP_SERVICES_USER_EXPERIENCE" xml:space="preserve">
<value>RDS User experience has been updated</value>
</data>
<data name="SchedulerTask.SCHEDULE_TASK_USER_PASSWORD_EXPIRATION_NOTIFICATION" xml:space="preserve">
<value>User password expiration notification</value>
</data>
</root>

View file

@ -0,0 +1,156 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ddlPriorityItem.High" xml:space="preserve">
<value>High</value>
</data>
<data name="ddlPriorityItem.Low" xml:space="preserve">
<value>Low</value>
</data>
<data name="ddlPriorityItem.Normal" xml:space="preserve">
<value>Normal</value>
</data>
<data name="lblFrom.Text" xml:space="preserve">
<value>From:</value>
</data>
<data name="lblHtmlBody.Text" xml:space="preserve">
<value>HTML Body:</value>
</data>
<data name="lblLogoUrl.Text" xml:space="preserve">
<value>Logo Url:</value>
</data>
<data name="lblNoChangesHtmlBody" xml:space="preserve">
<value>No Changes HTML Body:</value>
</data>
<data name="lblNoChangesTextBody.Text" xml:space="preserve">
<value>No Changes Text Body:</value>
</data>
<data name="lblPriority.Text" xml:space="preserve">
<value>Priority:</value>
</data>
<data name="lblSubject.Text" xml:space="preserve">
<value>Subject:</value>
</data>
<data name="lblTextBody.Text" xml:space="preserve">
<value>Text Body:</value>
</data>
<data name="lblWebDavPortalResetUrl.Text" xml:space="preserve">
<value>Webdav portal reset URL:</value>
</data>
</root>

View file

@ -150,4 +150,7 @@
<data name="lnkRdsSetupLetter.Text" xml:space="preserve">
<value>RDS Setup Letter</value>
</data>
<data name="lnkUserPasswordExpirationLetter.Text" xml:space="preserve">
<value>User Password Expiration Letter</value>
</data>
</root>

View file

@ -255,4 +255,7 @@
<data name="chkUserMustChangePassword.Text" xml:space="preserve">
<value>User must change password at next logon</value>
</data>
<data name="btnResetUserPassword.Text" xml:space="preserve">
<value>Reset Password</value>
</data>
</root>

View file

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="btnResetPassoword.Text" xml:space="preserve">
<value>Sent Password Reset Email</value>
</data>
<data name="locEmailAddress.Text" xml:space="preserve">
<value>Email:</value>
</data>
<data name="locReason.Text" xml:space="preserve">
<value>Reason:</value>
</data>
<data name="locTitle.Text" xml:space="preserve">
<value>Reset Password</value>
</data>
</root>

View file

@ -74,6 +74,8 @@
<asp:Button id="btnSetUserPassword" runat="server" Text="Set Password" CssClass="Button1"
meta:resourcekey="btnSetUserPassword" OnClick="btnSetUserPassword_Click" ValidationGroup="ValidatePassword"></asp:Button>
<asp:ValidationSummary ID="ValidationSummary2" runat="server" ShowMessageBox="True" ShowSummary="False" ValidationGroup="ValidatePassword" />
<asp:Button id="btnResetUserPassword" runat="server" Text="Reset Password" CssClass="Button1"
meta:resourcekey="btnResetUserPassword" OnClick="btnResetUserPassword_Click"></asp:Button>
</td>
</tr>

View file

@ -435,5 +435,13 @@ namespace WebsitePanel.Portal.HostedSolution
}
protected void btnResetUserPassword_Click(object sender, EventArgs e)
{
Response.Redirect(PortalUtils.EditUrl("ItemID", PanelRequest.ItemID.ToString(),
"user_reset_password",
"SpaceID=" + PanelSecurity.PackageId,
"Context=" + ((PanelRequest.Context == "Mailbox") ? "Mailbox" : "User"),
"AccountID=" + PanelRequest.AccountID));
}
}
}

View file

@ -210,6 +210,15 @@ namespace WebsitePanel.Portal.HostedSolution {
/// </remarks>
protected global::System.Web.UI.WebControls.ValidationSummary ValidationSummary2;
/// <summary>
/// btnResetUserPassword control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Button btnResetUserPassword;
/// <summary>
/// chkUserMustChangePassword control.
/// </summary>

View file

@ -0,0 +1,45 @@
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="OrganizationUserResetPassword.ascx.cs" Inherits="WebsitePanel.Portal.ExchangeServer.OrganizationUserResetPassword" %>
<%@ Register Src="../UserControls/ItemButtonPanel.ascx" TagName="ItemButtonPanel" TagPrefix="wsp" %>
<div id="ExchangeContainer">
<div class="Module">
<div class="Left">
</div>
<div class="Content">
<div class="Center">
<div class="Title">
<asp:Image ID="Image1" SkinID="OrganizationUser48" runat="server" />
<asp:Localize ID="locTitle" runat="server" meta:resourcekey="locTitle" Text="Reset Password"></asp:Localize>
-
<asp:Literal ID="litDisplayName" runat="server" Text="John Smith" />
</div>
<div class="FormBody">
<table>
<tr>
<td class="FormLabel150" valign="top"><asp:Localize ID="locEmailAddress" runat="server" meta:resourcekey="locEmailAddress" ></asp:Localize></td>
<td>
<asp:TextBox runat="server" ID="txtEmailAddress" CssClass="TextBox200"/>
<asp:RequiredFieldValidator ID="valEmailAddress" runat="server" ErrorMessage="*" ControlToValidate="txtEmailAddress" ValidationGroup="ResetUserPassword"></asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="regexEmailValid" runat="server" ValidationExpression="\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" ValidationGroup="ResetUserPassword" ControlToValidate="txtEmailAddress" ErrorMessage="Invalid Email Format"></asp:RegularExpressionValidator>
</td>
</tr>
<tr>
<td class="FormLabel150"><asp:Localize ID="locReason" runat="server" meta:resourcekey="locReason" Text="Reason:"></asp:Localize></td>
<td>
<asp:TextBox ID="txtReason" runat="server" CssClass="TextBox200" Rows="4" TextMode="MultiLine"></asp:TextBox>
<asp:RequiredFieldValidator ID="valReason" runat="server" ErrorMessage="*" ControlToValidate="txtReason" ValidationGroup="ResetUserPassword"></asp:RequiredFieldValidator>
</td>
</tr>
</table>
<div class="FormFooterClean">
<asp:Button id="btnResetPassoword" runat="server" Text="Reset Password" CssClass="Button1" meta:resourcekey="btnResetPassoword" ValidationGroup="ResetUserPassword" OnClick="btnResetPassoword_Click"></asp:Button>
</div>
</div>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using WebsitePanel.Providers.HostedSolution;
namespace WebsitePanel.Portal.ExchangeServer
{
public partial class OrganizationUserResetPassword : WebsitePanelModuleBase
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindSettings();
}
}
private void BindSettings()
{
OrganizationUser user = ES.Services.Organizations.GetUserGeneralSettings(PanelRequest.ItemID,
PanelRequest.AccountID);
litDisplayName.Text = PortalAntiXSS.Encode(user.DisplayName);
txtEmailAddress.Text = user.PrimaryEmailAddress;
}
protected void btnResetPassoword_Click(object sender, EventArgs e)
{
if (!Page.IsValid)
{
return;
}
Response.Redirect(PortalUtils.EditUrl("ItemID", PanelRequest.ItemID.ToString(),
(PanelRequest.Context == "Mailbox") ? "mailboxes" : "users",
"SpaceID=" + PanelSecurity.PackageId));
}
}
}

View file

@ -0,0 +1,114 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace WebsitePanel.Portal.ExchangeServer {
public partial class OrganizationUserResetPassword {
/// <summary>
/// Image1 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Image Image1;
/// <summary>
/// locTitle control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locTitle;
/// <summary>
/// litDisplayName control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Literal litDisplayName;
/// <summary>
/// locEmailAddress control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locEmailAddress;
/// <summary>
/// txtEmailAddress control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.TextBox txtEmailAddress;
/// <summary>
/// valEmailAddress control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.RequiredFieldValidator valEmailAddress;
/// <summary>
/// regexEmailValid control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.RegularExpressionValidator regexEmailValid;
/// <summary>
/// locReason control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Localize locReason;
/// <summary>
/// txtReason control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.TextBox txtReason;
/// <summary>
/// valReason control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.RequiredFieldValidator valReason;
/// <summary>
/// btnResetPassoword control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Button btnResetPassoword;
}
}

View file

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -0,0 +1,13 @@
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="UserPasswordExpirationNotificationView.ascx.cs" Inherits="WebsitePanel.Portal.ScheduleTaskControls.UserPasswordExpirationNotificationView" %>
<table cellspacing="0" cellpadding="4" width="100%">
<tr>
<td class="SubHead" nowrap>
<asp:Label ID="lblDayBeforeNotify" runat="server" meta:resourcekey="lblDayBeforeNotify" Text="Notify before (days):"></asp:Label>
</td>
<td class="Normal" width="100%">
<asp:TextBox ID="txtDaysBeforeNotify" runat="server" Width="95%" CssClass="NormalTextBox" MaxLength="1000"></asp:TextBox>
</td>
</tr>
</table>

View file

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using WebsitePanel.EnterpriseServer;
using WebsitePanel.Portal.UserControls.ScheduleTaskView;
namespace WebsitePanel.Portal.ScheduleTaskControls
{
public partial class UserPasswordExpirationNotificationView : EmptyView
{
private static readonly string DaysBeforeParameter = "DAYS_BEFORE_EXPIRATION";
protected void Page_Load(object sender, EventArgs e)
{
}
/// <summary>
/// Sets scheduler task parameters on view.
/// </summary>
/// <param name="parameters">Parameters list to be set on view.</param>
public override void SetParameters(ScheduleTaskParameterInfo[] parameters)
{
base.SetParameters(parameters);
this.SetParameter(this.txtDaysBeforeNotify, DaysBeforeParameter);
}
/// <summary>
/// Gets scheduler task parameters from view.
/// </summary>
/// <returns>Parameters list filled from view.</returns>
public override ScheduleTaskParameterInfo[] GetParameters()
{
ScheduleTaskParameterInfo daysBefore = this.GetParameter(this.txtDaysBeforeNotify, DaysBeforeParameter);
return new[] { daysBefore };
}
}
}

View file

@ -0,0 +1,33 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace WebsitePanel.Portal.ScheduleTaskControls {
public partial class UserPasswordExpirationNotificationView {
/// <summary>
/// lblDayBeforeNotify control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label lblDayBeforeNotify;
/// <summary>
/// txtDaysBeforeNotify control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.TextBox txtDaysBeforeNotify;
}
}

View file

@ -0,0 +1,49 @@
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="SettingsUserPasswordExpirationLetter.ascx.cs" Inherits="WebsitePanel.Portal.SettingsUserPasswordExpirationLetter" %>
<table>
<tr>
<td class="SubHead" width="150" nowrap><asp:Label ID="lblFrom" runat="server" meta:resourcekey="lblFrom" Text="From:"></asp:Label></td>
<td class="Normal" width="100%">
<asp:TextBox ID="txtFrom" runat="server" Width="500px" CssClass="NormalTextBox"></asp:TextBox></td>
</tr>
<tr>
<td class="SubHead"><asp:Label ID="lblSubject" runat="server" meta:resourcekey="lblSubject" Text="Subject:"></asp:Label></td>
<td class="Normal">
<asp:TextBox ID="txtSubject" runat="server" Width="500px" CssClass="NormalTextBox"></asp:TextBox></td>
</tr>
<tr>
<td class="SubHead"><asp:Label ID="lblPriority" runat="server" meta:resourcekey="lblPriority" Text="Priority"></asp:Label></td>
<td class="Normal">
<asp:DropDownList ID="ddlPriority" runat="server" CssClass="NormalTextBox" resourcekey="ddlPriority">
<asp:ListItem Value="High">High</asp:ListItem>
<asp:ListItem Value="Normal">Normal</asp:ListItem>
<asp:ListItem Value="Low">Low</asp:ListItem>
</asp:DropDownList>
</td>
</tr>
<tr>
<td class="SubHead"><asp:Label ID="lblLogoUrl" runat="server" meta:resourcekey="lblLogoUrl" Text="Logo Url:"></asp:Label></td>
<td class="Normal">
<asp:TextBox ID="txtLogoUrl" runat="server" Width="500px" CssClass="NormalTextBox"></asp:TextBox></td>
</tr>
<tr>
<td class="SubHead"><asp:Label ID="lblWebDavPortalResetUrl" runat="server" meta:resourcekey="lblWebDavPortalResetUrl" Text="CC:"></asp:Label></td>
<td class="Normal">
<asp:TextBox ID="txtWebDavPortalResetUrl" runat="server" Width="500px" CssClass="NormalTextBox"></asp:TextBox></td>
</tr>
<tr>
<td class="SubHead" colspan="2"><br /><br /><asp:Label ID="lblHtmlBody" runat="server" meta:resourcekey="lblHtmlBody" Text="HTML Body:"></asp:Label></td>
</tr>
<tr>
<td class="Normal" colspan="2">
<asp:TextBox ID="txtHtmlBody" runat="server" Rows="15" TextMode="MultiLine" Width="680px" CssClass="NormalTextBox" Wrap="false"></asp:TextBox></td>
</tr>
<tr>
<td class="SubHead" colspan="2"><br /><br /><asp:Label ID="lblTextBody" runat="server" meta:resourcekey="lblTextBody" Text="Text Body:"></asp:Label></td>
</tr>
<tr>
<td class="Normal" colspan="2">
<asp:TextBox ID="txtTextBody" runat="server" Rows="15" TextMode="MultiLine" Width="680px" CssClass="NormalTextBox" Wrap="false"></asp:TextBox></td>
</tr>
</table>

View file

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using WebsitePanel.EnterpriseServer;
namespace WebsitePanel.Portal
{
public partial class SettingsUserPasswordExpirationLetter : WebsitePanelControlBase, IUserSettingsEditorControl
{
public void BindSettings(UserSettings settings)
{
txtFrom.Text = settings["From"];
txtWebDavPortalResetUrl.Text = settings["WebDavPortalResetUrl"];
txtSubject.Text = settings["Subject"];
Utils.SelectListItem(ddlPriority, settings["Priority"]);
txtHtmlBody.Text = settings["HtmlBody"];
txtTextBody.Text = settings["TextBody"];
txtLogoUrl.Text = settings["LogoUrl"];
}
public void SaveSettings(UserSettings settings)
{
settings["From"] = txtFrom.Text;
settings["WebDavPortalResetUrl"] = txtWebDavPortalResetUrl.Text;
settings["Subject"] = txtSubject.Text;
settings["Priority"] = ddlPriority.SelectedValue;
settings["HtmlBody"] = txtHtmlBody.Text;
settings["TextBody"] = txtTextBody.Text;
settings["LogoUrl"] = txtLogoUrl.Text;
}
}
}

View file

@ -0,0 +1,141 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace WebsitePanel.Portal {
public partial class SettingsUserPasswordExpirationLetter {
/// <summary>
/// lblFrom control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label lblFrom;
/// <summary>
/// txtFrom control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.TextBox txtFrom;
/// <summary>
/// lblSubject control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label lblSubject;
/// <summary>
/// txtSubject control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.TextBox txtSubject;
/// <summary>
/// lblPriority control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label lblPriority;
/// <summary>
/// ddlPriority control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.DropDownList ddlPriority;
/// <summary>
/// lblLogoUrl control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label lblLogoUrl;
/// <summary>
/// txtLogoUrl control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.TextBox txtLogoUrl;
/// <summary>
/// lblWebDavPortalResetUrl control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label lblWebDavPortalResetUrl;
/// <summary>
/// txtWebDavPortalResetUrl control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.TextBox txtWebDavPortalResetUrl;
/// <summary>
/// lblHtmlBody control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label lblHtmlBody;
/// <summary>
/// txtHtmlBody control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.TextBox txtHtmlBody;
/// <summary>
/// lblTextBody control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label lblTextBody;
/// <summary>
/// txtTextBody control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.TextBox txtTextBody;
}
}

View file

@ -42,6 +42,10 @@
<asp:HyperLink ID="lnkRdsSetupLetter" runat="server" meta:resourcekey="lnkRdsSetupLetter"
Text="RDS Setup Letter" NavigateUrl='<%# GetSettingsLink("RdsSetupLetter", "SettingsRdsSetupLetter") %>'></asp:HyperLink>
</li>
<li>
<asp:HyperLink ID="lnkUserPasswordExpirationLetter" runat="server" meta:resourcekey="lnkUserPasswordExpirationLetter"
Text="User Password Expiration Letter" NavigateUrl='<%# GetSettingsLink("UserPasswordExpirationLetter", "SettingsUserPasswordExpirationLetter") %>'></asp:HyperLink>
</li>
</ul>
</div>
<div class="FormFooter">

View file

@ -102,6 +102,15 @@ namespace WebsitePanel.Portal {
/// </remarks>
protected global::System.Web.UI.WebControls.HyperLink lnkRdsSetupLetter;
/// <summary>
/// lnkUserPasswordExpirationLetter control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.HyperLink lnkUserPasswordExpirationLetter;
/// <summary>
/// btnCancel control.
/// </summary>

View file

@ -244,6 +244,13 @@
<DependentUpon>OrganizationDeletedUserGeneralSettings.ascx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="ExchangeServer\OrganizationUserResetPassword.ascx.cs">
<DependentUpon>OrganizationUserResetPassword.ascx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="ExchangeServer\OrganizationUserResetPassword.ascx.designer.cs">
<DependentUpon>OrganizationUserResetPassword.ascx</DependentUpon>
</Compile>
<Compile Include="ExchangeServer\UserControls\EnterpriseStorageEditFolderTabs.ascx.cs">
<DependentUpon>EnterpriseStorageEditFolderTabs.ascx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
@ -265,6 +272,20 @@
<Compile Include="ProviderControls\HyperV2012R2_Settings.ascx.designer.cs">
<DependentUpon>HyperV2012R2_Settings.ascx</DependentUpon>
</Compile>
<Compile Include="ScheduleTaskControls\UserPasswordExpirationNotificationView.ascx.cs">
<DependentUpon>UserPasswordExpirationNotificationView.ascx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="ScheduleTaskControls\UserPasswordExpirationNotificationView.ascx.designer.cs">
<DependentUpon>UserPasswordExpirationNotificationView.ascx</DependentUpon>
</Compile>
<Compile Include="SettingsUserPasswordExpirationLetter.ascx.cs">
<DependentUpon>SettingsUserPasswordExpirationLetter.ascx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="SettingsUserPasswordExpirationLetter.ascx.designer.cs">
<DependentUpon>SettingsUserPasswordExpirationLetter.ascx</DependentUpon>
</Compile>
<Compile Include="VPS\ProviderControls\HyperV2012R2_Create.ascx.cs">
<DependentUpon>HyperV2012R2_Create.ascx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
@ -4536,9 +4557,12 @@
<Content Include="ExchangeServer\EnterpriseStorageFolderSettingsFolderPermissions.ascx" />
<Content Include="ExchangeServer\EnterpriseStorageFolderSettingsOwaEditing.ascx" />
<Content Include="ExchangeServer\ExchangeCheckDomainName.ascx" />
<Content Include="ExchangeServer\OrganizationUserResetPassword.ascx" />
<Content Include="ExchangeServer\UserControls\EnterpriseStorageEditFolderTabs.ascx" />
<Content Include="ExchangeServer\UserControls\EnterpriseStorageOwaUsersList.ascx" />
<Content Include="ProviderControls\HyperV2012R2_Settings.ascx" />
<Content Include="ScheduleTaskControls\UserPasswordExpirationNotificationView.ascx" />
<Content Include="SettingsUserPasswordExpirationLetter.ascx" />
<Content Include="VPS\ProviderControls\HyperV2012R2_Create.ascx" />
<Content Include="ProviderControls\SmarterMail100_EditAccount.ascx" />
<Content Include="ProviderControls\SmarterMail100_EditDomain.ascx" />
@ -4596,6 +4620,8 @@
<Content Include="ProviderControls\App_LocalResources\HyperV2012R2_Settings.ascx.resx">
<SubType>Designer</SubType>
</Content>
<Content Include="ExchangeServer\App_LocalResources\OrganizationUserResetPassword.ascx.resx" />
<Content Include="App_LocalResources\SettingsUserPasswordExpirationLetter.ascx.resx" />
<EmbeddedResource Include="RDS\App_LocalResources\RDSEditCollectionSettings.ascx.resx" />
<Content Include="RDSServersEditServer.ascx" />
<Content Include="RDS\AssignedRDSServers.ascx" />
@ -4791,6 +4817,7 @@
<Content Include="UserControls\App_LocalResources\UserActions.ascx.resx" />
<Content Include="UserControls\App_LocalResources\DomainActions.ascx.resx" />
<Content Include="UserControls\App_LocalResources\MailAccountActions.ascx.resx" />
<Content Include="ScheduleTaskControls\App_LocalResources\UserPasswordExpirationNotificationView.ascx.resx" />
<EmbeddedResource Include="UserControls\App_LocalResources\WebsiteActions.ascx.resx" />
</ItemGroup>
<ItemGroup>