Commits

Clément Bourgeois  committed 74f6ecb

User management is fully working.

  • Participants
  • Parent commits 2f540d2

Comments (0)

Files changed (10)

File SQLServerBackupTool.Web/Controllers/UsersController.cs

             get { return Membership.Provider; }
         }
 
+        private static Type MembershipProviderUserKeyType
+        {
+            get { return typeof(Guid); }
+        }
+
         protected override void Initialize(RequestContext r)
         {
             base.Initialize(r);
             return View(new MembershipEditViewModel
             {
                 IsApproved = true,
+                Roles      = new string[] { }
             });
         }
 
         [ValidateAntiForgeryToken, HttpPost]
-        public ActionResult Create(MembershipUser u)
+        public ActionResult Create(MembershipEditViewModel u)
         {
-            return RedirectToAction("Edit", new { id=u.UserName });
+            if (ModelState.IsValid)
+            {
+                try
+                {
+                    MembershipCreateStatus mStatus;
+
+                    var userName = u.UserName;
+
+                    var newUser = Membership.CreateUser(
+                        userName,
+                        u.Password,
+                        u.Email,
+                        null,
+                        null,
+                        u.IsApproved,
+                        out mStatus
+                    );
+
+                    if (mStatus == MembershipCreateStatus.Success && newUser != null)
+                    {
+                        if (newUser.Comment != u.Comment)
+                        {
+                            newUser.Comment = u.Comment;
+                            Provider.UpdateUser(newUser);
+                        }
+
+                        HandleRoles(u);
+
+                        AddFlashMessage(string.Format("User '{0}' successfully created", userName), FlashMessageType.Success);
+
+                        return RedirectToAction("Edit", new { id = newUser.ProviderUserKey });
+                    }
+
+                    var status = GetMembershipCreateStatusMessage(mStatus);
+
+                    AddFlashMessage(
+                        string.Format("An error occurred during user creation : {0}", status),
+                        FlashMessageType.Error
+                    );
+                }
+                catch (Exception ex)
+                {
+                    Logger.ErrorException("An error occurred", ex);
+                    AddFlashMessage("An error occurred during user creation", FlashMessageType.Error);
+                }
+            }
+            else
+            {
+                DebugModelStateErrors();
+
+                AddFlashMessage("Unable to create user with provided values, please correct errors", FlashMessageType.Warning);
+            }
+
+            u.Roles = u.Roles ?? new string[] { };
+
+            return View(u);
         }
 
         /**
 
         public ActionResult Edit(string id)
         {
-            var u = Membership.GetUser(id);
+            var uKey = GetRealProviderUserKey(id);
+
+            if (uKey == null)
+            {
+                return HttpNotFound();
+            }
+
+            var u = Membership.GetUser(uKey);
 
             if (u == null)
             {
-                return HttpNotFound(string.Format("User : {0} not found", id));
+                return HttpNotFound(string.Format("User : {0} not found", u.UserName));
             }
 
             return View(new MembershipEditViewModel(u)
         [HttpPost, ValidateAntiForgeryToken]
         public ActionResult Delete(string id)
         {
+            var uKey = GetRealProviderUserKey(id);
+
+            if (uKey == null)
+            {
+                return HttpNotFound();
+            }
+
+            var mem = Membership.GetUser(uKey);
+
+            if (mem == null)
+            {
+                return HttpNotFound();
+            }
+
+            var userName = mem.UserName;
+
             try
             {
-                if (Provider.DeleteUser(id, true))
+                if (Provider.DeleteUser(userName, true))
                 {
-                    AddFlashMessage(string.Format("User '{0}' successfully deleted", id), FlashMessageType.Success);
+                    AddFlashMessage(string.Format("User '{0}' successfully deleted", userName), FlashMessageType.Success);
                 }
                 else
                 {
-                    AddFlashMessage(string.Format("Unable to delete user '{0}'", id), FlashMessageType.Warning);
+                    AddFlashMessage(string.Format("Unable to delete user '{0}'", userName), FlashMessageType.Warning);
                 }
             }
             catch (Exception ex)
             {
-                AddFlashMessage(string.Format("An error occurred while deleting user {0}", id), FlashMessageType.Error);
+                AddFlashMessage(string.Format("An error occurred while deleting user {0}", userName), FlashMessageType.Error);
                 Logger.ErrorException("An error occurred", ex);
             }
 
         }
 
         /// <summary>
+        /// Transforms <see cref="id"/> into the real under-laying <see cref="MembershipUser.ProviderUserKey"/> type
+        /// </summary>
+        /// <param name="id">Key as string</param>
+        /// <returns>A trans-typed object or what was initially given</returns>
+        protected static object GetRealProviderUserKey(string id)
+        {
+            object realProviderUserKey = null;
+
+            if (MembershipProviderUserKeyType == typeof(Guid))
+            {
+                try
+                {
+                    realProviderUserKey = Guid.Parse(id);
+                }
+                // ReSharper disable EmptyGeneralCatchClause : What can we do anyway ?
+                catch (Exception) { }
+                // ReSharper restore EmptyGeneralCatchClause
+            }
+            else if (MembershipProviderUserKeyType == typeof(int))
+            {
+                try
+                {
+                    realProviderUserKey = int.Parse(id);
+                }
+                // ReSharper disable EmptyGeneralCatchClause : What can we do anyway ?
+                catch (Exception) { }
+                // ReSharper restore EmptyGeneralCatchClause
+            }
+            else
+            {
+                realProviderUserKey = id;
+            }
+
+            return realProviderUserKey;
+        }
+
+        /// <summary>
         /// When roles are enabled adds/removes roles
         /// </summary>
         /// <param name="u"><see cref="MembershipEditViewModel"/> to get the roles from</param>
                 return;
             }
 
-            Roles.RemoveUserFromRoles(u.UserName, Roles.GetRolesForUser(u.UserName));
+            var rolesForUser = Roles.GetRolesForUser(u.UserName);
+
+            if (rolesForUser != null && rolesForUser.Length > 0)
+            {
+                Roles.RemoveUserFromRoles(u.UserName, rolesForUser);
+            }
 
             if (u.Roles != null && u.Roles.Any())
             {
                 Roles.AddUserToRoles(u.UserName, u.Roles.ToArray());
             }
         }
+
+        /// <summary>
+        /// Translates a <see cref="MembershipCreateStatus"/> to a human readable string
+        /// </summary>
+        /// <param name="status">The status to translate</param>
+        /// <returns>A status string</returns>
+        /// <exception cref="ArgumentOutOfRangeException">Unknown status type</exception>
+        protected static string GetMembershipCreateStatusMessage(MembershipCreateStatus status)
+        {
+            switch (status)
+            {
+                case MembershipCreateStatus.Success:
+                    return "The user was successfully created.";
+
+                case MembershipCreateStatus.InvalidUserName:
+                    return "The user name was not found in the database.";
+
+                case MembershipCreateStatus.InvalidPassword:
+                    return "The password is not formatted correctly.";
+
+                case MembershipCreateStatus.InvalidQuestion:
+                    return "The password question is not formatted correctly.";
+
+                case MembershipCreateStatus.InvalidAnswer:
+                    return "The password answer is not formatted correctly.";
+
+                case MembershipCreateStatus.InvalidEmail:
+                    return "The e-mail address is not formatted correctly.";
+
+                case MembershipCreateStatus.DuplicateUserName:
+                    return "The user name already exists in the database for the application.";
+
+                case MembershipCreateStatus.DuplicateEmail:
+                    return "The e-mail address already exists in the database for the application.";
+
+                case MembershipCreateStatus.UserRejected:
+                    return "The user was not created, for a reason defined by the provider.";
+
+                case MembershipCreateStatus.InvalidProviderUserKey:
+                    return "The provider user key is of an invalid type or format.";
+
+                case MembershipCreateStatus.DuplicateProviderUserKey:
+                    return "The provider user key already exists in the database for the application.";
+
+                case MembershipCreateStatus.ProviderError:
+                    return
+                        "The provider returned an error that is not described by other MembershipCreateStatus enumeration values.";
+            }
+
+            throw new ArgumentOutOfRangeException("status");
+        }
     }
 }

File SQLServerBackupTool.Web/Lib/Mvc/ApplicationController.cs

 using NLog;
 using SQLServerBackupTool.Web.Models;
 using System.Configuration;
+using System.Diagnostics;
+using System.Linq;
 using System.Web.Mvc;
 using System.Web.Routing;
 
             base.Initialize(r);
         }
 
+        [Conditional("DEBUG")]
+        protected void DebugModelStateErrors()
+        {
+            var errs = ModelState.Where(_ => _.Value.Errors.Any());
+
+            foreach (var e in errs)
+            {
+                Debug.WriteLine(
+                    "[ModelStateError] : '{0}' -> {1}",
+                    e.Key,
+                    string.Join(", ", e.Value.Errors.Select(_ => string.Format("'{0}'", _.ErrorMessage)))
+                );
+            }
+        }
+
         protected override void Dispose(bool disposing)
         {
             DbContext.Dispose();

File SQLServerBackupTool.Web/SQLServerBackupTool.Web.csproj

     <Content Include="Views\Users\Index.cshtml" />
     <Content Include="Views\Home\Schema.cshtml" />
     <Content Include="Views\Home\_BackupItem.cshtml" />
-    <Content Include="Views\Home\Schema.cshtml" />
     <Content Include="Views\Users\Edit.cshtml" />
     <Content Include="Views\Users\Create.cshtml" />
     <Content Include="Views\Users\_Form.cshtml" />
+    <Content Include="Views\Shared\_FormAntiforgeryToken.cshtml" />
   </ItemGroup>
   <ItemGroup>
     <Folder Include="App_Data\" />

File SQLServerBackupTool.Web/Scripts/ssbtw.js

     $('.pldr').pldr({ autostart: false });
     $('.loading').modal({ show: false, keyboard: false });
 
-    $('.select2').each(function() {
+    $('.select2').each(function () {
         var $me = $(this);
 
         $me.select2({
      * Users management
      */
 
+    $('.user-delete').on('click', function (e) {
+        e.preventDefault();
+
+        var $me = $(this),
+            href = $me.attr('href');
+
+        $f.attr('action', href).submit();
+    });
+
     $('#password-generate').on('click', function (e) {
         e.preventDefault();
         $.ajax({

File SQLServerBackupTool.Web/Views/Home/Index.cshtml

         </tr>
     </table>
 </div>
-@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "form-aft", style = "display:none;" }))
-{
-    @Html.AntiForgeryToken()
-}
+@Html.Partial("_FormAntiforgeryToken")

File SQLServerBackupTool.Web/Views/Shared/_FormAntiforgeryToken.cshtml

+@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "form-aft", style = "display:none;" }))
+{
+    @Html.AntiForgeryToken()
+}

File SQLServerBackupTool.Web/Views/Users/Create.cshtml

 }
 
 <div class="form-horizontal">
-    @using (Html.BeginForm())
+    @using (Html.BeginForm(null, null, new { id="" }, FormMethod.Post))
     {
         @Html.Partial("_Form", Model)
         <div class="form-actions">

File SQLServerBackupTool.Web/Views/Users/Edit.cshtml

 }
 
 <div class="form-horizontal">
-    @using (Html.BeginForm())
+    @using (Html.BeginForm(null, null, new { id="" }, FormMethod.Post))
     {
         @Html.Partial("_Form", Model)
         <div class="form-actions">

File SQLServerBackupTool.Web/Views/Users/Index.cshtml

                 </td>
                 <td>
                     <div class="btn-group">
-                        <a class="btn" href="@Url.Action("Edit", new { id=m.UserName })">
+                        <a class="btn" href="@Url.Action("Edit", new { id=m.ProviderUserKey })">
                             <i class="icon-edit"></i>&nbsp;Edit
                         </a>
-                        <a href="@Url.Action("Delete")" class="btn btn-danger">
+                        <a href="@Url.Action("Delete", new { id=m.ProviderUserKey })" class="btn btn-danger user-delete">
                             <i class="icon-trash icon-white"></i>&nbsp;Delete
                         </a>
                     </div>
 <div style="text-align: center;">
     @PagedList.Mvc.HtmlHelper.PagedListPager(Html, Model, i => Url.Action("Index", new { page = i }))
 </div>
+@Html.Partial("_FormAntiforgeryToken")

File SQLServerBackupTool.Web/Views/Users/_Form.cshtml

         <div class="controls">
             <div class="input-append">
                 @Html.TextBoxFor(m => m.Password, new { @type="password", @class="pw" })
-                <a class="btn" id="password-generate" href="#">Generate password</a>
+                <a class="btn" href="#" id="password-generate" tabindex="9999">Generate password</a>
             </div>
             @Html.ValidationMessageFor(m => m.Password)
         </div>
 <div class="control-group">
     @Html.LabelFor(m => m.Roles, new { @class="control-label" })
     <div class="controls">
-        @Html.ListBoxFor(_ => _.Roles, new MultiSelectList(MembershipEditViewModel.AvailableRoles.Select(_ => new {Value=_, Label=_}), "Value", "Label", Model.Roles.Select(_ => new {Value=_, Label=_})), new { @class="select2", data_placeholder="Select roles" })
+        @Html.ListBoxFor(_ => _.Roles, new MultiSelectList(MembershipEditViewModel.AvailableRoles.Select(_ => new { Value=_, Label=_ }), "Value", "Label", Model.Roles.Select(_ => new { Value=_, Label=_ })), new { @class="select2", data_placeholder="Select roles" })
         @Html.ValidationMessageFor(m => m.Roles)
     </div>
 </div>