diff --git a/Src/VideoGameQuotes.Web/Controllers/AdminController.cs b/Src/VideoGameQuotes.Web/Controllers/AdminController.cs index 2cc60b4..034a491 100644 --- a/Src/VideoGameQuotes.Web/Controllers/AdminController.cs +++ b/Src/VideoGameQuotes.Web/Controllers/AdminController.cs @@ -1,4 +1,5 @@ using System.Web.Mvc; +using Portoa.Persistence; using Portoa.Web; using Portoa.Web.ErrorHandling; using VideoGameQuotes.Api; @@ -17,6 +18,66 @@ namespace VideoGameQuotes.Web.Controllers { this.adminService = adminService; } + [HttpGet] + public ActionResult Create() { + var model = new CreateAdminModel(); + ResetCreateAdminModel(model); + return View(model); + } + + private void ResetCreateAdminModel(CreateAdminModel model) { + model.Users = adminService.GetAllUsers(); + } + + [HttpPost] + public ActionResult Create(CreateAdminModel model) { + if (!ModelState.IsValid) { + ResetCreateAdminModel(model); + return View(model); + } + + try { + var user = new User { + Username = model.Username, + Group = UserGroup.Admin + }; + + if (model.UserId > 0) { + user = adminService.GetUser(model.UserId); + if (user.Group == UserGroup.Admin) { + ModelState.AddModelError("UserId", string.Format("The user {0} is already an admin", user.Username)); + } else { + user.Group = UserGroup.Admin; + } + + if (user.Username == null) { + if (string.IsNullOrWhiteSpace(model.Username)) { + ModelState.AddModelError("Username", "Username must be given if the user does not have a username"); + } else { + user.Username = model.Username; + } + } + } else if (string.IsNullOrWhiteSpace(model.Username)) { + ModelState.AddModelError("Username", "Username must be non-empty if creating a new user"); + } + + if (!ModelState.IsValid) { + ResetCreateAdminModel(model); + return View(model); + } + + user.IpAddress = null; //must delete ip address or it's kind of a glaring security hole + user.ChangePassword(model.Password); + + adminService.SaveUser(user); + return View("CreateAdminSuccess", model); + } catch (EntityNotFoundException) { + ModelState.AddModelError("UserId", string.Format("User not found for id {0}", model.UserId)); + ResetCreateAdminModel(model); + return View(model); + } + } + public ActionResult Index() { return View(); } diff --git a/Src/VideoGameQuotes.Web/Models/CreateAdminModel.cs b/Src/VideoGameQuotes.Web/Models/CreateAdminModel.cs new file mode 100644 index 0000000..3f39ded --- /dev/null +++ b/Src/VideoGameQuotes.Web/Models/CreateAdminModel.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Web.Mvc; +using VideoGameQuotes.Api; + +namespace VideoGameQuotes.Web.Models { + public class CreateAdminModel { + [DisplayName("Use existing user")] + public int UserId { get; set; } + public string Username { get; set; } + [Required] + public string Password { get; set; } + + public IEnumerable Users { get; set; } + + public IEnumerable GetUserList() { + return new[] { new SelectListItem { Text = "--none--", Value = "0" } } + .Concat(Users + .Where(user => user.Group != UserGroup.Admin) + .OrderBy(user => user.Username) + .ThenBy(user => user.IpAddress) + .Select(user => new SelectListItem { Text = user.Username ?? user.IpAddress, Value = user.Id.ToString() }) + ); + } + } +} \ No newline at end of file diff --git a/Src/VideoGameQuotes.Web/Services/AdministrationService.cs b/Src/VideoGameQuotes.Web/Services/AdministrationService.cs index 785aec6..3ee025d 100644 --- a/Src/VideoGameQuotes.Web/Services/AdministrationService.cs +++ b/Src/VideoGameQuotes.Web/Services/AdministrationService.cs @@ -7,6 +7,8 @@ namespace VideoGameQuotes.Web.Services { public interface IAdministrationService { User SaveUser(User user); IEnumerable GetFlaggedQuotes(); + User GetUser(int id); + IEnumerable GetAllUsers(); } public class AdministrationService : IAdministrationService { @@ -31,5 +33,14 @@ namespace VideoGameQuotes.Web.Services { .OrderByDescending(quote => quote.Flags.Count()); } + [UnitOfWork] + public User GetUser(int id) { + return userRepository.FindById(id); + } + + [UnitOfWork] + public IEnumerable GetAllUsers() { + return userRepository.Records; + } } } \ No newline at end of file diff --git a/Src/VideoGameQuotes.Web/VideoGameQuotes.Web.csproj b/Src/VideoGameQuotes.Web/VideoGameQuotes.Web.csproj index 4917806..bb0f650 100644 --- a/Src/VideoGameQuotes.Web/VideoGameQuotes.Web.csproj +++ b/Src/VideoGameQuotes.Web/VideoGameQuotes.Web.csproj @@ -91,6 +91,7 @@ + @@ -131,6 +132,8 @@ + + diff --git a/Src/VideoGameQuotes.Web/Views/Admin/Create.aspx b/Src/VideoGameQuotes.Web/Views/Admin/Create.aspx new file mode 100644 index 0000000..ca5e887 --- /dev/null +++ b/Src/VideoGameQuotes.Web/Views/Admin/Create.aspx @@ -0,0 +1,30 @@ +<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Views/Shared/Site.Master" %> +<%@ Import Namespace="Portoa.Web.Util" %> +Create Admin + +

Create Admin

+ + <%= Html.ValidationSummary("Some errors occurred") %> + + <% using (Html.BeginForm()) { %> +

+ <%= Html.LabelFor(model => model.UserId) %> <%= Html.ValidationMessageFor(model => model.UserId) %> +
+ <%= Html.DropDownListFor(model => model.UserId, Model.GetUserList()) %> +

+ +

+ <%= Html.LabelFor(model => model.Username) %> <%= Html.ValidationMessageFor(model => model.Username) %> +
+ <%= Html.TextBoxFor(model => model.Username) %> +

+ +

+ <%= Html.LabelFor(model => model.Password) %> <%= Html.ValidationMessageFor(model => model.Password) %> +
+ <%= Html.PasswordFor(model => model.Password) %> +

+ + <%= Html.Submit("Create Admin") %> + <% } %> +
\ No newline at end of file diff --git a/Src/VideoGameQuotes.Web/Views/Admin/CreateAdminSuccess.aspx b/Src/VideoGameQuotes.Web/Views/Admin/CreateAdminSuccess.aspx new file mode 100644 index 0000000..26af07c --- /dev/null +++ b/Src/VideoGameQuotes.Web/Views/Admin/CreateAdminSuccess.aspx @@ -0,0 +1,9 @@ +<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" MasterPageFile="~/Views/Shared/Site.Master" %> +Create Admin + +

Success

+

+ The user <%= Html.ActionLink(Model.Username, "user", "admin", new { id = Model.UserId }, null) %> is now + an admin. +

+
diff --git a/Tests/VideoGameQuotes.Api.Tests/NHibernate/schema.sql b/Tests/VideoGameQuotes.Api.Tests/NHibernate/schema.sql index 3dd7f95..95456df 100644 --- a/Tests/VideoGameQuotes.Api.Tests/NHibernate/schema.sql +++ b/Tests/VideoGameQuotes.Api.Tests/NHibernate/schema.sql @@ -32,7 +32,7 @@ alter table quote_flag drop foreign key fk_flag_user ; -alter table quote_flag drop foreign key fk_flag_quote +alter table quote_flag drop foreign key fk_quote_flag ; @@ -61,6 +61,8 @@ alter table quote_category_map drop foreign key FK5892F846C2AA09DD drop table if exists publisher; + drop table if exists category; + drop table if exists vgquote_user; drop table if exists quote_flag; @@ -71,8 +73,6 @@ alter table quote_category_map drop foreign key FK5892F846C2AA09DD drop table if exists system; - drop table if exists category; - create table vote ( vote_id INTEGER NOT NULL AUTO_INCREMENT, created DATETIME not null, @@ -113,6 +113,13 @@ alter table quote_category_map drop foreign key FK5892F846C2AA09DD primary key (publisher_id) ); + create table category ( + category_id INTEGER NOT NULL AUTO_INCREMENT, + category_name VARCHAR(255) not null unique, + created DATETIME not null, + primary key (category_id) + ); + create table vgquote_user ( user_id INTEGER NOT NULL AUTO_INCREMENT, username VARCHAR(50), @@ -159,13 +166,6 @@ alter table quote_category_map drop foreign key FK5892F846C2AA09DD primary key (system_id) ); - create table category ( - category_id INTEGER NOT NULL AUTO_INCREMENT, - category_name VARCHAR(255) not null unique, - created DATETIME not null, - primary key (category_id) - ); - alter table vote add index (voter_id), add constraint fk_vote_user @@ -216,7 +216,7 @@ alter table quote_category_map drop foreign key FK5892F846C2AA09DD alter table quote_flag add index (quote_id), - add constraint fk_flag_quote + add constraint fk_quote_flag foreign key (quote_id) references game_quote (quote_id);