svn path=/trunk/mvcwrench/; revision=151641
This commit is contained in:
Jonathan Pobst 2010-02-12 17:44:22 +00:00
Родитель 7d39928fb3
Коммит 8a01d730ac
16 изменённых файлов: 699 добавлений и 2 удалений

Просмотреть файл

@ -35,6 +35,20 @@ namespace MvcWrench.Controllers
{
public abstract class ApplicationController : Controller
{
private User current_user;
protected override void OnActionExecuting (ActionExecutingContext filterContext)
{
if (User.Identity.IsAuthenticated) {
User user = UserRepository.GetUser (User.Identity.Name);
current_user = user;
ViewData["CurrentUser"] = current_user;
}
base.OnActionExecuting (filterContext);
}
protected override void OnActionExecuted (ActionExecutedContext filterContext)
{
List<Tab> tabs = new List<Tab> ();
@ -47,6 +61,8 @@ namespace MvcWrench.Controllers
base.OnActionExecuted (filterContext);
}
public User CurrentUser { get { return current_user; } }
}
}
}

Просмотреть файл

@ -0,0 +1,147 @@
namespace MvcWrench.Controllers
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.RelyingParty;
using MvcWrench.Models;
public class UserController : ApplicationController
{
private static OpenIdRelyingParty openid = new OpenIdRelyingParty ();
public ActionResult Index ()
{
if (!User.Identity.IsAuthenticated) {
Response.Redirect ("/User/Login?ReturnUrl=Index");
}
return View ("Index");
}
//public ActionResult LoginPopup ()
//{
// return View ("LoginPopup");
//}
public ActionResult Logout ()
{
FormsAuthentication.SignOut ();
return Redirect ("/Home");
}
public ActionResult Login ()
{
// Stage 1: display login form to user
return View ("Login");
}
public ActionResult Profile ()
{
return View ("Profile", CurrentUser);
}
[AcceptVerbs (HttpVerbs.Post)]
public ActionResult Profile (User user)
{
if (string.IsNullOrEmpty (user.Email))
ModelState.AddModelError ("Email", "You must provide an email address");
if (!UserRepository.IsSvnAccountAvailable (CurrentUser.ID, user.SvnAccount))
ModelState.AddModelError ("SvnAccount", "SVN account has already been claimed");
if (!ModelState.IsValid)
return View ("Profile", user);
UserRepository.SaveUser (user);
return RedirectToAction ("Index", "Home");
}
[ValidateInput (false)]
public ActionResult Authenticate (string returnUrl)
{
var response = openid.GetResponse ();
if (response == null) {
// Stage 2: user submitting Identifier
Identifier id;
if (Identifier.TryParse (Request.Form["openid_identifier"], out id)) {
try {
return openid.CreateRequest (Request.Form["openid_identifier"]).RedirectingResponse.AsActionResult ();
} catch (ProtocolException ex) {
ViewData["Message"] = ex.Message;
return View ("Login");
}
} else {
ViewData["Message"] = "Invalid identifier";
return View ("Login");
}
} else {
// Stage 3: OpenID Provider sending assertion response
switch (response.Status) {
case AuthenticationStatus.Authenticated:
User user = UserRepository.GetUserFromOpenId (response.ClaimedIdentifier);
// This is a new user, send them to a registration page
if (user == null) {
ViewData["openid"] = response.ClaimedIdentifier;
return Redirect (string.Format ("~/user/register?openid={0}", Url.Encode (response.ClaimedIdentifier)));
}
Session["FriendlyIdentifier"] = response.FriendlyIdentifierForDisplay;
FormsAuthentication.SetAuthCookie (user.Name, false);
if (!string.IsNullOrEmpty (returnUrl)) {
return Redirect (returnUrl);
} else {
return RedirectToAction ("Index", "Home");
}
case AuthenticationStatus.Canceled:
ViewData["Message"] = "Canceled at provider";
return View ("Login");
case AuthenticationStatus.Failed:
ViewData["Message"] = response.Exception.Message;
return View ("Login");
}
}
return new EmptyResult ();
}
public ActionResult Register ()
{
MvcWrench.Models.User user = new MvcWrench.Models.User ();
user.OpenID = Request.QueryString["openid"];
return View ("Registration", user);
}
[AcceptVerbs (HttpVerbs.Post)]
public ActionResult Register (User user)
{
if (string.IsNullOrEmpty (user.Name) || string.IsNullOrEmpty (user.Email)) {
if (string.IsNullOrEmpty (user.Name))
ModelState.AddModelError ("Name", "You must pick a username");
if (string.IsNullOrEmpty (user.Email))
ModelState.AddModelError ("Email", "You must provide an email address");
return View ("Registration", user);
}
if (UserRepository.IsUserNameAvailable (user.Name)) {
UserRepository.CreateUser (user);
FormsAuthentication.SetAuthCookie (user.Name, true);
return RedirectToAction ("Index", "Home");
}
ModelState.AddModelError ("Name", "This username is not available, please choose another");
return View ("Registration", user);
}
}
}

Двоичные данные
Media/novell16.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 268 B

Двоичные данные
Media/signin-google.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.2 KiB

Двоичные данные
Media/signin-novell.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 705 B

Двоичные данные
Media/signin-yahoo.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1012 B

Просмотреть файл

@ -34,6 +34,12 @@ pre
font-size: 10pt;
}
input
{
font-size: 12pt;
margin-top: 5px;
}
/* Header/Menu */
#header
{
@ -46,6 +52,32 @@ pre
padding-right: 10px;
}
#logindisplay
{
float: right;
margin-right: 10px;
margin-top: 13px;
text-align: left;
}
.usertext
{
float: right;
margin-left: 5px;
}
#logindisplay a, #logindisplay a:visited
{
color: #FFFFFF;
}
.userimage
{
float: left;
padding-top: 3px;
padding-right: 5px;
}
#topmenu
{
color: White;
@ -610,3 +642,28 @@ li.row-header { background-image: none; background-color: #FFFFFF; font-weight:
font-weight: bold;
color: #000000;
}
/* Log in Page */
#OIDother {line-height: 36px; margin: 5px 0 0}
#OIDother .spacer {padding-top: 0}
#OIDother a {text-indent: -5000px; border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; margin: 0 6px 0 0; background: url('../Media/signin-novell.png') no-repeat 50% 50%; height: 34px; float: left; border: 1px solid white; opacity: 0.9}
#OIDother a:hover {background-color: #eff4fa; border-color: #a7c3e1; cursor:pointer;}
#OIDother a#OIDnovell {width: 96px}
#OIDother a#OIDgoogle {width: 94px; background-image: url('../Media/signin-google.png')}
#OIDother a#OIDyahoo {width: 100px; background-image: url('../Media/signin-yahoo.png')}
.form-text {border-radius: 2px; -moz-border-radius: 2px; -webkit-border-radius: 2px; background: #fff url('../Media/input-bg.png') center top repeat-x; border: 1px solid #aaa; margin: 1px; padding: 3px; position: relative}
.form-text:focus {background: #FFF url('../Media/input-bga.png') center top repeat-x; border: 2px solid #729fcf; margin: 0}
.center
{
height: 300px;
width: 600px;
margin: auto;
padding-top: 25px;
text-align: center;
}
.form-item-info
{
color: #999999;
font-size: 8pt;
}

Просмотреть файл

@ -0,0 +1,230 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Npgsql;
using System.Web.Configuration;
namespace MvcWrench.Models
{
public static class UserRepository
{
private static string conn_string;
static UserRepository ()
{
conn_string = WebConfigurationManager.ConnectionStrings["Postgres"].ConnectionString;
}
public static User GetUserFromOpenId (string openid)
{
NpgsqlConnection conn = new NpgsqlConnection (conn_string);
conn.Open ();
NpgsqlCommand comm = conn.CreateCommand ();
string sql = "SELECT * FROM openids WHERE id = @id";
comm.CommandText = sql;
comm.Parameters.Add ("@id", openid);
NpgsqlDataReader reader = comm.ExecuteReader ();
int user_id = -1;
while (reader.Read ())
user_id = (int)reader["UserID"];
reader.Close ();
comm.Dispose ();
conn.Close ();
if (user_id == -1)
return null;
return GetUser (user_id);
}
public static User GetUserFromSvn (string svn)
{
NpgsqlConnection conn = new NpgsqlConnection (conn_string);
conn.Open ();
NpgsqlCommand comm = conn.CreateCommand ();
string sql = "SELECT * FROM users WHERE svn = @svn";
comm.CommandText = sql;
comm.Parameters.Add ("@svn", svn);
NpgsqlDataReader reader = comm.ExecuteReader ();
User user = null;
while (reader.Read ())
user = new User (reader);
reader.Close ();
comm.Dispose ();
conn.Close ();
return user;
}
public static User GetUser (int id)
{
NpgsqlConnection conn = new NpgsqlConnection (conn_string);
conn.Open ();
NpgsqlCommand comm = conn.CreateCommand ();
string sql = "SELECT * FROM users WHERE id = @id";
comm.CommandText = sql;
comm.Parameters.Add ("@id", id);
NpgsqlDataReader reader = comm.ExecuteReader ();
User user = null;
while (reader.Read ())
user = new User (reader);
reader.Close ();
comm.Dispose ();
conn.Close ();
return user;
}
public static User GetUser (string name)
{
NpgsqlConnection conn = new NpgsqlConnection (conn_string);
conn.Open ();
NpgsqlCommand comm = conn.CreateCommand ();
string sql = "SELECT * FROM users WHERE name = @name";
comm.CommandText = sql;
comm.Parameters.Add ("@name", name);
NpgsqlDataReader reader = comm.ExecuteReader ();
User user = null;
while (reader.Read ())
user = new User (reader);
reader.Close ();
comm.Dispose ();
conn.Close ();
return user;
}
public static User CreateUser (User user)
{
NpgsqlConnection conn = new NpgsqlConnection (conn_string);
NpgsqlCommand comm = conn.CreateCommand ();
// Add data to the User table
string sql = "INSERT INTO users (name, email) VALUES (@name, @email)";
comm.CommandText = sql;
comm.Parameters.Add ("@name", user.Name);
comm.Parameters.Add ("@email", user.Email);
conn.Open ();
comm.ExecuteNonQuery ();
comm.Dispose ();
User new_user = GetUser (user.Name);
// Add data to the OpenID table
comm = conn.CreateCommand ();
sql = "INSERT INTO openids (id, userid) VALUES (@id, @userid)";
comm.CommandText = sql;
comm.Parameters.Add ("@id", user.OpenID);
comm.Parameters.Add ("@userid", new_user.ID);
comm.ExecuteNonQuery ();
comm.Dispose ();
conn.Close ();
return new_user;
}
public static void SaveUser (User user)
{
NpgsqlConnection conn = new NpgsqlConnection (conn_string);
NpgsqlCommand comm = conn.CreateCommand ();
// Add data to the User table
string sql = "UPDATE users SET email = @email, gravatar = @gravatar, svn = @svn WHERE id = @id";
comm.CommandText = sql;
comm.Parameters.Add ("@id", user.ID);
comm.Parameters.Add ("@svn", user.SvnAccount);
comm.Parameters.Add ("@email", user.Email);
comm.Parameters.Add ("@gravatar", user.Gravatar);
conn.Open ();
comm.ExecuteNonQuery ();
comm.Dispose ();
}
internal static bool IsUserNameAvailable (string name)
{
return GetUser (name) == null;
}
internal static bool IsSvnAccountAvailable (int userId, string account)
{
NpgsqlConnection conn = new NpgsqlConnection (conn_string);
NpgsqlCommand comm = conn.CreateCommand ();
// Add data to the User table
string sql = "SELECT COUNT (*) FROM users WHERE id != @id AND svn = @svn";
comm.CommandText = sql;
comm.Parameters.Add ("@id", userId);
comm.Parameters.Add ("@svn", account);
conn.Open ();
Int64 count = (Int64)comm.ExecuteScalar ();
comm.Dispose ();
return count == 0;
}
public static List<Role> GetRolesForUser (int userId)
{
NpgsqlConnection conn = new NpgsqlConnection (conn_string);
NpgsqlCommand comm = conn.CreateCommand ();
string sql = "SELECT * FROM roles, userroles WHERE userroles.roleid = roles.id and userroles.userid = @userid";
comm.CommandText = sql;
comm.Parameters.Add ("@userid", userId);
conn.Open ();
NpgsqlDataReader reader = comm.ExecuteReader ();
List<Role> roles = new List<Role> ();
while (reader.Read ())
roles.Add (new Role (reader));
reader.Close ();
comm.Dispose ();
conn.Close ();
return roles;
}
}
}

22
Models/Users/Role.cs Normal file
Просмотреть файл

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Npgsql;
namespace MvcWrench.Models
{
public class Role
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
internal Role (NpgsqlDataReader reader)
{
ID = (int)reader["id"];
Name = (string)reader["name"];
Description = (string)reader["description"];
}
}
}

59
Models/Users/User.cs Normal file
Просмотреть файл

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Npgsql;
namespace MvcWrench.Models
{
public class User
{
public int ID { get; set; }
public string OpenID { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Gravatar { get; set; }
public string SvnAccount { get; set; }
public bool IsAdministrator { get { return IsInRole ("Administrator"); } }
public bool IsNovell { get { return IsInRole ("Novell"); } }
private List<Role> roles;
public User ()
{
}
internal User (NpgsqlDataReader reader)
{
ID = (int)reader["id"];
Name = (string)reader["name"];
Email = (string)reader["email"];
Gravatar = (string)reader["gravatar"];
SvnAccount = (string)reader["svn"];
}
public bool IsInRole (string role)
{
if (roles == null)
roles = UserRepository.GetRolesForUser (ID);
foreach (Role r in roles)
if (string.Compare (role, r.Name, true) == 0)
return true;
return false;
}
public string GetGravatar (int size)
{
string grav = Gravatar;
grav = string.IsNullOrEmpty (grav) ? SvnAccount : grav;
grav = string.IsNullOrEmpty (grav) ? Name : grav;
return UserHelpers.EmailToGravatar (grav, size);
}
}
}

Просмотреть файл

@ -31,7 +31,20 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="DotNetOpenAuth, Version=3.4.0.10015, Culture=neutral, PublicKeyToken=2780ccd10d57b246, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\Desktop\DotNetOpenAuth-3.4.0.10015\Bin\DotNetOpenAuth.dll</HintPath>
</Reference>
<Reference Include="Mono.Security, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\Program Files (x86)\Mono-2.6.1\lib\mono\gac\Mono.Security\2.0.0.0__0738eb9f132ed756\Mono.Security.dll</HintPath>
</Reference>
<Reference Include="Npgsql, Version=2.0.0.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\Program Files (x86)\Mono-2.6.1\lib\mono\gac\Npgsql\2.0.0.0__5d8b90d52f46fda7\Npgsql.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Data" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
@ -58,6 +71,7 @@
<Compile Include="Controllers\BuildsController.cs" />
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Controllers\StatusController.cs" />
<Compile Include="Controllers\UserController.cs" />
<Compile Include="Default.aspx.cs">
<DependentUpon>Default.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
@ -83,7 +97,7 @@
<Compile Include="Models\Gui\Users\SvnGravatars.cs" />
<Compile Include="Models\Users\Role.cs" />
<Compile Include="Models\Users\User.cs" />
<Compile Include="Models\Users\UserRepository.cs" />
<Compile Include="Models\Repositories\UserRepository.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Helpers\IncludeExtensions.cs" />
<Compile Include="Helpers\UrlBuilder.cs" />
@ -199,8 +213,12 @@
<Content Include="Media\fail.png" />
<Content Include="Media\house.png" />
<Content Include="Media\moon.png" />
<Content Include="Media\novell16.png" />
<Content Include="Media\pass.png" />
<Content Include="Media\report.png" />
<Content Include="Media\signin-google.png" />
<Content Include="Media\signin-novell.png" />
<Content Include="Media\signin-yahoo.png" />
<Content Include="Views\Builds\DiffViewControl.ascx" />
<Content Include="Views\Builds\RevisionDiff.aspx" />
<Content Include="Views\Home\BugChart.ascx" />
@ -213,9 +231,13 @@
<Content Include="Views\Home\RecentRevisions.ascx" />
<Content Include="Views\Builds\RevisionDetails.aspx" />
<Content Include="Views\Shared\CommitHeader.ascx" />
<Content Include="Views\Shared\LogOnUserControl.ascx" />
<Content Include="Views\Status\Index.aspx" />
<Content Include="Views\Status\List.aspx" />
<Content Include="Views\Status\Status.Master" />
<Content Include="Views\User\Login.aspx" />
<Content Include="Views\User\Profile.aspx" />
<Content Include="Views\User\Registration.aspx" />
<None Include="Web References\MonkeyWrench.Public\BuildRevision.datasource">
<DependentUpon>Reference.map</DependentUpon>
</None>

Просмотреть файл

@ -0,0 +1,21 @@
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%
if (Request.IsAuthenticated) {
MvcWrench.Models.User CurrentUser = (MvcWrench.Models.User)ViewData["CurrentUser"];
%>
<div class="userimage">
<img alt="user gravatar" src="<%= CurrentUser.GetGravatar (32) %>" />
</div>
<div class="usertext">
<b><%= Html.Encode (CurrentUser.Name)%></b>
<br />
<span style="font-size: .8em"><%= Html.ActionLink("Profile", "profile", "user") %> |
<%= Html.ActionLink("Logout", "logout", "user") %></span>
</div>
<%
} else {
%>
<%= Html.ActionLink("Sign in / Create account", "login", "user") %>
<%
}
%>

Просмотреть файл

@ -18,6 +18,9 @@
<body>
<div id="header">
<div id="logindisplay">
<% Html.RenderPartial ("LogOnUserControl"); %>
</div>
</div>
<div id="topmenu">

36
Views/User/Login.aspx Normal file
Просмотреть файл

@ -0,0 +1,36 @@
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content3" ContentPlaceHolderID="TitleContent" runat="server">
MonkeyWrench - Log in
</asp:Content>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<% if (ViewData["Message"] != null) { %>
<div style="border: solid 1px red">
<%= Html.Encode(ViewData["Message"].ToString())%>
</div>
<% } %>
<div class="center">
<span style="font-size: 1.6em">To log in, or to register an account, enter your OpenID:</span>
<br /><br /><br />
<form action="Authenticate?ReturnUrl=<%=HttpUtility.UrlEncode(Request.QueryString["ReturnUrl"]) %>" method="post">
<label for="openid_identifier">OpenID:</label>
<input id="openid_identifier" name="openid_identifier" size="40" />
<input id="openid_submit" type="submit" value="Login" />
</form>
<br /><br />
Or click your OpenID provider:
<div id="OIDother" style="padding-left: 195px;">
<%-- <a id="OIDnovell" onclick="document.getElementById('openid_identifier').value = 'http://novell.com/openid';document.getElementById('openid_submit').click()">Novell</a>--%>
<a id="OIDgoogle" onclick="document.getElementById('openid_identifier').value = 'https://www.google.com/accounts/o8/id';document.getElementById('openid_submit').click()">Google</a>
<a id="OIDyahoo" onclick="document.getElementById('openid_identifier').value = 'http://yahoo.com/';document.getElementById('openid_submit').click()">Yahoo!</a>
</div>
<script type="text/javascript">
document.getElementById("openid_identifier").focus();
</script>
</div>
</asp:Content>

50
Views/User/Profile.aspx Normal file
Просмотреть файл

@ -0,0 +1,50 @@
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcWrench.Models.User>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
MonkeyWrench - Edit Profile
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<div style="padding-left: 15px; font-size: 12pt;">
<h1>Your Profile</h1>
<%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>
<% using (Html.BeginForm ()) { %>
<table width="600" cellpadding="5px">
<%= Html.Hidden ("ID", Model.ID) %>
<%= Html.Hidden ("Name", Model.Name)%>
<tr>
<td>Username</td>
<td><%= Model.IsNovell ? string.Format ("<img src=\"{0}\" />", Html.ResolveUrl ("~/Media/novell16.png")) : "" %> <%= Model.Name %> </td>
</tr>
<tr>
<td style="vertical-align: top;">Email</td>
<td>
<%= Html.TextBox ("Email", Model.Email, new { @class = "form-text", style = "width: 260px;" }) %>
<%= Html.ValidationMessage ("Email", "*") %>
<div class="form-item-info">notifications</div>
</td>
</tr>
<tr>
<td style="vertical-align: top;">
Gravatar
</td>
<td>
<%= Html.TextBox ("Gravatar", Model.Gravatar, new { @class = "form-text", style = "width: 260px;" })%>
<%= Html.ValidationMessage ("Gravatar", "*")%>
<div class="form-item-info">optional, email used to get your <a href="http://www.gravatar.com/" target="_blank">Gravatar</a></div>
</td>
</tr>
<tr>
<td style="vertical-align: top;">
Svn Account
</td>
<td>
<%= Html.TextBox ("SvnAccount", Model.SvnAccount, new { @class = "form-text", style = "width: 260px;" })%>
<%= Html.ValidationMessage ("SvnAccount", "*")%>
<div class="form-item-info">optional, if you have a <a href="http://mono-project.com/SVN" target="_blank">Mono SVN</a> account</div>
</td>
</tr>
</table>
<input type="submit" value="Save" />
<% } %>
</div>
</asp:Content>

Просмотреть файл

@ -0,0 +1,34 @@
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
MonkeyWrench - Registration
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<div class="center">
<b>We can't find an account associated with the OpenID:</b><br />
<i><%= (Model as MvcWrench.Models.User).OpenID %></i>
<br /><br />
<b>To create a MonkeyWrench account tied to this OpenID, please fill out the following fields:</b><br />
<%= Html.ValidationSummary("Please correct the errors and try again.") %>
<% using (Html.BeginForm ()) {
MvcWrench.Models.User user = (MvcWrench.Models.User)Model; %>
<p>
<label for="Name">Username:</label><br />
<%= Html.TextBox ("Name", user.Name, new { @class = "form-text" })%>
<%= Html.ValidationMessage ("Name", "*")%>
</p>
<p>
<label for="Email">Email:</label><br />
<%= Html.TextBox("Email", user.Email, new { @class = "form-text" }) %>
<%= Html.ValidationMessage("Email", "*") %>
</p>
<p>
<input type="submit" value="Create Account" />
</p>
<% } %>
<% Html.RenderPartial ("BlueBox", "If you want to associate this OpenID with an existing MonkeyWrench account, this will not do it. That functionality is not available yet."); %>
</div>
</asp:Content>