sonarr-repo-only/NzbDrone.Web/Models/AccountModels.cs

299 lines
11 KiB
C#
Raw Normal View History

2010-09-23 03:19:47 +00:00
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Web.Security;
namespace NzbDrone.Web.Models
{
#region Models
2011-04-10 02:44:01 +00:00
[PropertiesMustMatch("NewPassword", "ConfirmPassword",
ErrorMessage = "The new password and confirmation password do not match.")]
2010-09-23 03:19:47 +00:00
public class ChangePasswordModel
{
[Required]
[DataType(DataType.Password)]
[DisplayName("Current password")]
public string OldPassword { get; set; }
[Required]
[ValidatePasswordLength]
[DataType(DataType.Password)]
[DisplayName("New password")]
public string NewPassword { get; set; }
[Required]
[DataType(DataType.Password)]
[DisplayName("Confirm new password")]
public string ConfirmPassword { get; set; }
}
public class LogOnModel
{
[Required]
[DisplayName("User name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[DisplayName("Password")]
public string Password { get; set; }
[DisplayName("Remember me?")]
public bool RememberMe { get; set; }
}
2011-04-10 02:44:01 +00:00
[PropertiesMustMatch("Password", "ConfirmPassword",
ErrorMessage = "The password and confirmation password do not match.")]
2010-09-23 03:19:47 +00:00
public class RegisterModel
{
[Required]
[DisplayName("User name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[DisplayName("Email address")]
public string Email { get; set; }
[Required]
[ValidatePasswordLength]
[DataType(DataType.Password)]
[DisplayName("Password")]
public string Password { get; set; }
[Required]
[DataType(DataType.Password)]
[DisplayName("Confirm password")]
public string ConfirmPassword { get; set; }
}
2011-04-10 02:44:01 +00:00
2010-09-23 03:19:47 +00:00
#endregion
#region Services
2011-04-10 02:44:01 +00:00
2010-09-23 03:19:47 +00:00
// The FormsAuthentication type is sealed and contains static members, so it is difficult to
// unit test code that calls its members. The interface and helper class below demonstrate
// how to create an abstract wrapper around such a type in order to make the AccountController
// code unit testable.
public interface IMembershipService
{
int MinPasswordLength { get; }
bool ValidateUser(string userName, string password);
MembershipCreateStatus CreateUser(string userName, string password, string email);
bool ChangePassword(string userName, string oldPassword, string newPassword);
}
public class AccountMembershipService : IMembershipService
{
private readonly MembershipProvider _provider;
public AccountMembershipService()
: this(null)
{
}
public AccountMembershipService(MembershipProvider provider)
{
_provider = provider ?? Membership.Provider;
}
2011-04-10 02:44:01 +00:00
#region IMembershipService Members
2010-09-23 03:19:47 +00:00
public int MinPasswordLength
{
2011-04-10 02:44:01 +00:00
get { return _provider.MinRequiredPasswordLength; }
2010-09-23 03:19:47 +00:00
}
public bool ValidateUser(string userName, string password)
{
2011-04-10 02:44:01 +00:00
if (String.IsNullOrEmpty(userName))
throw new ArgumentException("Value cannot be null or empty.", "userName");
if (String.IsNullOrEmpty(password))
throw new ArgumentException("Value cannot be null or empty.", "password");
2010-09-23 03:19:47 +00:00
return _provider.ValidateUser(userName, password);
}
public MembershipCreateStatus CreateUser(string userName, string password, string email)
{
2011-04-10 02:44:01 +00:00
if (String.IsNullOrEmpty(userName))
throw new ArgumentException("Value cannot be null or empty.", "userName");
if (String.IsNullOrEmpty(password))
throw new ArgumentException("Value cannot be null or empty.", "password");
2010-09-23 03:19:47 +00:00
if (String.IsNullOrEmpty(email)) throw new ArgumentException("Value cannot be null or empty.", "email");
MembershipCreateStatus status;
_provider.CreateUser(userName, password, email, null, null, true, null, out status);
return status;
}
public bool ChangePassword(string userName, string oldPassword, string newPassword)
{
2011-04-10 02:44:01 +00:00
if (String.IsNullOrEmpty(userName))
throw new ArgumentException("Value cannot be null or empty.", "userName");
if (String.IsNullOrEmpty(oldPassword))
throw new ArgumentException("Value cannot be null or empty.", "oldPassword");
if (String.IsNullOrEmpty(newPassword))
throw new ArgumentException("Value cannot be null or empty.", "newPassword");
2010-09-23 03:19:47 +00:00
// The underlying ChangePassword() will throw an exception rather
// than return false in certain failure scenarios.
try
{
MembershipUser currentUser = _provider.GetUser(userName, true /* userIsOnline */);
return currentUser.ChangePassword(oldPassword, newPassword);
}
catch (ArgumentException)
{
return false;
}
catch (MembershipPasswordException)
{
return false;
}
}
2011-04-10 02:44:01 +00:00
#endregion
2010-09-23 03:19:47 +00:00
}
public interface IFormsAuthenticationService
{
void SignIn(string userName, bool createPersistentCookie);
void SignOut();
}
public class FormsAuthenticationService : IFormsAuthenticationService
{
2011-04-10 02:44:01 +00:00
#region IFormsAuthenticationService Members
2010-09-23 03:19:47 +00:00
public void SignIn(string userName, bool createPersistentCookie)
{
2011-04-10 02:44:01 +00:00
if (String.IsNullOrEmpty(userName))
throw new ArgumentException("Value cannot be null or empty.", "userName");
2010-09-23 03:19:47 +00:00
FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
}
public void SignOut()
{
FormsAuthentication.SignOut();
}
2011-04-10 02:44:01 +00:00
#endregion
2010-09-23 03:19:47 +00:00
}
2011-04-10 02:44:01 +00:00
2010-09-23 03:19:47 +00:00
#endregion
#region Validation
2011-04-10 02:44:01 +00:00
2010-09-23 03:19:47 +00:00
public static class AccountValidation
{
public static string ErrorCodeToString(MembershipCreateStatus createStatus)
{
// See http://go.microsoft.com/fwlink/?LinkID=177550 for
// a full list of status codes.
switch (createStatus)
{
case MembershipCreateStatus.DuplicateUserName:
return "Username already exists. Please enter a different user name.";
case MembershipCreateStatus.DuplicateEmail:
return "A username for that e-mail address already exists. Please enter a different e-mail address.";
case MembershipCreateStatus.InvalidPassword:
return "The password provided is invalid. Please enter a valid password value.";
case MembershipCreateStatus.InvalidEmail:
return "The e-mail address provided is invalid. Please check the value and try again.";
case MembershipCreateStatus.InvalidAnswer:
return "The password retrieval answer provided is invalid. Please check the value and try again.";
case MembershipCreateStatus.InvalidQuestion:
return "The password retrieval question provided is invalid. Please check the value and try again.";
case MembershipCreateStatus.InvalidUserName:
return "The user name provided is invalid. Please check the value and try again.";
case MembershipCreateStatus.ProviderError:
2011-04-10 02:44:01 +00:00
return
"The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
2010-09-23 03:19:47 +00:00
case MembershipCreateStatus.UserRejected:
2011-04-10 02:44:01 +00:00
return
"The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
2010-09-23 03:19:47 +00:00
default:
2011-04-10 02:44:01 +00:00
return
"An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
2010-09-23 03:19:47 +00:00
}
}
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public sealed class PropertiesMustMatchAttribute : ValidationAttribute
{
private const string _defaultErrorMessage = "'{0}' and '{1}' do not match.";
private readonly object _typeId = new object();
public PropertiesMustMatchAttribute(string originalProperty, string confirmProperty)
: base(_defaultErrorMessage)
{
OriginalProperty = originalProperty;
ConfirmProperty = confirmProperty;
}
public string ConfirmProperty { get; private set; }
public string OriginalProperty { get; private set; }
public override object TypeId
{
2011-04-10 02:44:01 +00:00
get { return _typeId; }
2010-09-23 03:19:47 +00:00
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
2011-04-10 02:44:01 +00:00
OriginalProperty, ConfirmProperty);
2010-09-23 03:19:47 +00:00
}
public override bool IsValid(object value)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
object originalValue = properties.Find(OriginalProperty, true /* ignoreCase */).GetValue(value);
object confirmValue = properties.Find(ConfirmProperty, true /* ignoreCase */).GetValue(value);
2011-04-10 02:44:01 +00:00
return Equals(originalValue, confirmValue);
2010-09-23 03:19:47 +00:00
}
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class ValidatePasswordLengthAttribute : ValidationAttribute
{
private const string _defaultErrorMessage = "'{0}' must be at least {1} characters long.";
private readonly int _minCharacters = Membership.Provider.MinRequiredPasswordLength;
public ValidatePasswordLengthAttribute()
: base(_defaultErrorMessage)
{
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
2011-04-10 02:44:01 +00:00
name, _minCharacters);
2010-09-23 03:19:47 +00:00
}
public override bool IsValid(object value)
{
string valueAsString = value as string;
return (valueAsString != null && valueAsString.Length >= _minCharacters);
}
}
2011-04-10 02:44:01 +00:00
#endregion
}