Starting to test some controller

* BlogUnitTest.cs: Should test the user registration

* NpgsqlBlogProvider.cs: Fixes usage of Npgsql upgrade to latest
  version

* TestAPI.csproj: switch to .Net framework 4.5.1

* AccountController.cs: refactoring password validation

* CalendarController.cs:
* WorkFlowController.cs: SendActivationMessage became an extension
  method

* style.css: menu items already have a background and color, since
  they're `<A>` tags

* Unregister.aspx:
* AccountController.cs: refactoring user registration

* BlogsController.cs: Fixes a confusion between Author and reader ...

* YavscHelpers.cs: refactoring the password reset

* App.master: no more <div class="menuitem">, they're hyperlinks

* Login.aspx:
* Profile.aspx: refactoring the user registration

* BlogEntryCollection.cs: implements a method to filter a given post
  collection in order to be displayed tu a given user or anonymous
This commit is contained in:
Paul Schneider 2015-10-07 11:50:44 +02:00
commit 303aaa5e1b
19 changed files with 218 additions and 65 deletions

View file

@ -72,7 +72,7 @@ namespace Yavsc.ApiControllers
break;
case MembershipCreateStatus.Success:
if (!model.IsApprouved)
YavscHelpers.SendActivationMessage (user);
Url.SendActivationMessage (user);
ProfileBase prtu = ProfileBase.Create (model.UserName);
prtu.SetPropertyValue("Name",model.Name);
prtu.SetPropertyValue("Address",model.Address);
@ -99,9 +99,12 @@ namespace Yavsc.ApiControllers
public void ResetPassword(LostPasswordModel model)
{
StringDictionary errors;
YavscHelpers.ResetPassword (model, out errors);
MembershipUser user;
YavscHelpers.ValidatePasswordReset (model, out errors, out user);
foreach (string key in errors.Keys)
ModelState.AddModelError (key, errors [key]);
if (user != null && ModelState.IsValid)
Url.SendActivationMessage (user);
}
}
}

View file

@ -27,6 +27,7 @@ using Yavsc.Helpers;
using System.Web.Profile;
using Yavsc.Model.Circles;
using Yavsc.Model.Calendar;
using System.Web.Http.Routing;
namespace Yavsc.ApiControllers
@ -160,7 +161,7 @@ namespace Yavsc.ApiControllers
"déjà enregistré");
break;
case MembershipCreateStatus.Success:
YavscHelpers.SendActivationMessage (user);
Url.SendActivationMessage (user);
// TODO set registration id
throw new NotImplementedException ();
}

View file

@ -85,7 +85,8 @@ namespace Yavsc.ApiControllers
return ;
case MembershipCreateStatus.Success:
if (!userModel.IsApprouved)
YavscHelpers.SendActivationMessage (user);
Url.SendActivationMessage (user);
return;
default:
throw new InvalidOperationException (string.Format("Unexpected user creation code :{0}",mcs));

View file

@ -235,7 +235,6 @@ input, select {
.menuitem {
background-color: rgba(0,0,40,.8);
border-radius:5px;
margin:.5em;
padding:.5em;

View file

@ -1,3 +1,28 @@
2015-10-07 Paul Schneider <paul@pschneider.fr>
* AccountController.cs: refactoring password validation
* CalendarController.cs:
* WorkFlowController.cs: SendActivationMessage became an
extension method
* style.css: menu items already have a background and color,
since they're `<A>` tags
* Unregister.aspx:
* AccountController.cs: refactoring user registration
* BlogsController.cs: Fixes a confusion between Author and
reader ...
* YavscHelpers.cs: refactoring the password reset
* App.master: no more <div class="menuitem">, they're
hyperlinks
* Login.aspx:
* Profile.aspx: refactoring the user registration
2015-10-06 Paul Schneider <paul@pschneider.fr>
* style.css: reactive margins

View file

@ -126,11 +126,17 @@ namespace Yavsc.Controllers
return View ();
}
public ActionResult RegisterForm()
{
return View ("Register");
}
/// <summary>
/// Register the specified model and returnUrl.
/// </summary>
/// <param name="model">Model.</param>
/// <param name="returnUrl">Return URL.</param>
[HttpPost]
public ActionResult Register (RegisterViewModel model, string returnUrl)
{
ViewData ["returnUrl"] = returnUrl;
@ -138,7 +144,8 @@ namespace Yavsc.Controllers
foreach (string k in ModelState.Keys)
ModelState [k].Errors.Clear ();
return View (model);
}
}
if (ModelState.IsValid) {
if (model.ConfirmPassword != model.Password) {
ModelState.AddModelError ("ConfirmPassword", "Veuillez confirmer votre mot de passe");
@ -164,7 +171,7 @@ namespace Yavsc.Controllers
"déjà enregistré");
return View (model);
case MembershipCreateStatus.Success:
YavscHelpers.SendActivationMessage (user);
Url.SendActivationMessage (user);
ViewData ["username"] = user.UserName;
ViewData ["email"] = user.Email;
return View ("RegistrationPending");
@ -203,14 +210,20 @@ namespace Yavsc.Controllers
}
/// <summary>
/// Unregister the specified confirmed.
/// Unregister the specified id and confirmed.
/// </summary>
/// <param name="id">Identifier.</param>
/// <param name="confirmed">If set to <c>true</c> confirmed.</param>
[Authorize]
public ActionResult Unregister (bool confirmed = false)
public ActionResult Unregister (string id, bool confirmed = false)
{
ViewData ["UserName"] = id;
if (!confirmed)
return View ();
string logged = Membership.GetUser ().UserName;
if (logged != id)
if (!Roles.IsUserInRole ("Admin"))
throw new Exception ("Unregister another user");
Membership.DeleteUser (
Membership.GetUser ().UserName);
@ -381,9 +394,13 @@ namespace Yavsc.Controllers
{
if (Request.HttpMethod == "POST") {
StringDictionary errors;
YavscHelpers.ResetPassword (model, out errors);
MembershipUser user;
YavscHelpers.ValidatePasswordReset (model, out errors, out user);
foreach (string key in errors.Keys)
ModelState.AddModelError (key, errors [key]);
if (user != null && ModelState.IsValid)
Url.SendActivationMessage (user);
}
return View (model);
}

View file

@ -185,8 +185,8 @@ namespace Yavsc.Controllers
ViewData ["Avatar"] = pr.avatar;
ViewData ["BlogTitle"] = pr.BlogTitle;
MembershipUser u = Membership.GetUser ();
if (u != null)
ViewData ["Author"] = u.UserName;
ViewData ["Author"] = bec.Author;
if (!pr.BlogVisible) {
// only deliver to admins or owner
if (u == null)
@ -197,6 +197,13 @@ namespace Yavsc.Controllers
return View ("NotAuthorized");
}
}
if (u == null || (u.UserName != bec.Author) && !Roles.IsUserInRole (u.UserName, "Admin")) {
// Filer on allowed posts
BlogEntryCollection filtered = bec.FilterFor((u == null)?null : u.UserName);
UUTBlogEntryCollection nbec = new UUTBlogEntryCollection (bec.Author, bec.Title);
nbec.AddRange (filtered);
View ("UserPost",nbec);
}
}
return View ("UserPost",bec);
}

View file

@ -5,11 +5,9 @@ using System.Web.Security;
using System.IO;
using System.Web.Configuration;
using System.Net.Mail;
using System.Web.Http.ModelBinding;
using Yavsc.Model.RolesAndMembers;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web.Mvc;
using Yavsc.Model.Circles;
using System.Web.UI;
using System.Linq.Expressions;
@ -22,31 +20,6 @@ namespace Yavsc.Helpers
/// </summary>
public static class YavscHelpers
{
/// <summary>
/// Formats the circle.
/// </summary>
/// <returns>The circle.</returns>
/// <param name="c">C.</param>
public static HtmlString FormatCircle (Circle c)
{
if (c.Members!=null)
if (c.Members.Length > 0) {
TagBuilder i = new TagBuilder ("i");
i.SetInnerText (String.Join (", ", c.Members));
return new HtmlString (c.Title+"<br/>\n"+i.ToString());
}
return new HtmlString (c.Title);
}
/// <summary>
/// Formats the circle.
/// </summary>
/// <returns>The circle as Html string.</returns>
/// <param name="helper">Helper.</param>
/// <param name="c">C.</param>
public static HtmlString FormatCircle(this HtmlHelper helper, Circle c)
{
return FormatCircle (c);
}
private static string siteName = null;
/// <summary>
@ -76,19 +49,33 @@ namespace Yavsc.Helpers
/// <summary>
/// Sends the activation message.
/// </summary>
/// <param name="helper">Helper.</param>
/// <param name="user">User.</param>
public static void SendActivationMessage(MembershipUser user)
public static void SendActivationMessage(this System.Web.Http.Routing.UrlHelper helper, MembershipUser user)
{
SendEmail (WebConfigurationManager.AppSettings ["RegistrationMessage"],
SendActivationMessage (helper.Route("~/Account/Validate/",new { id=user.UserName, key=user.ProviderUserKey.ToString() } )
, WebConfigurationManager.AppSettings ["RegistrationMessage"],
user);
}
/// <summary>
/// Sends the activation message.
/// </summary>
/// <param name="helper">Helper.</param>
/// <param name="user">User.</param>
public static void SendActivationMessage(this System.Web.Mvc.UrlHelper helper, MembershipUser user)
{
SendActivationMessage (helper.Content("~/Account/Validate/"+user.UserName+"/?key="+user.ProviderUserKey.ToString())
, WebConfigurationManager.AppSettings ["RegistrationMessage"],
user);
}
/// <summary>
/// Sends the email.
/// Sends the activation message.
/// </summary>
/// <param name="validationUrl">Validation URL.</param>
/// <param name="registrationMessage">Registration message.</param>
/// <param name="user">User.</param>
public static void SendEmail(string registrationMessage, MembershipUser user) {
public static void SendActivationMessage(string validationUrl, string registrationMessage, MembershipUser user) {
FileInfo fi = new FileInfo (
HttpContext.Current.Server.MapPath (registrationMessage));
if (!fi.Exists) {
@ -103,12 +90,8 @@ namespace Yavsc.Helpers
string body = sr.ReadToEnd ();
body = body.Replace ("<%SiteName%>", YavscHelpers.SiteName);
body = body.Replace ("<%UserName%>", user.UserName);
body = body.Replace ("<%UserActivatonUrl%>",
string.Format ("<{0}://{1}/Account/Validate/{2}?key={3}>",
HttpContext.Current.Request.Url.Scheme,
HttpContext.Current.Request.Url.Authority,
user.UserName,
user.ProviderUserKey.ToString ()));
body = body.Replace ("<%UserActivatonUrl%>", validationUrl);
using (MailMessage msg = new MailMessage (
Admail, user.Email,
string.Format ("Validation de votre compte {0}", YavscHelpers.SiteName),
@ -122,15 +105,16 @@ namespace Yavsc.Helpers
}
/// <summary>
/// Resets the password.
/// Validates the password reset.
/// </summary>
/// <param name="model">Model.</param>
/// <param name="errors">Errors.</param>
public static void ResetPassword(LostPasswordModel model, out StringDictionary errors)
/// <param name="user">User.</param>
public static void ValidatePasswordReset(LostPasswordModel model, out StringDictionary errors, out MembershipUser user)
{
MembershipUserCollection users = null;
errors = new StringDictionary ();
user = null;
if (!string.IsNullOrEmpty (model.UserName)) {
users =
Membership.FindUsersByName (model.UserName);
@ -158,10 +142,7 @@ namespace Yavsc.Helpers
if (users==null)
return;
// Assert users.Count == 1
if (users.Count != 1)
throw new InvalidProgramException ("Emails and user's names are uniques, and we find more than one result here, aborting.");
foreach (MembershipUser u in users)
YavscHelpers.SendActivationMessage (u);
foreach (MembershipUser u in users) user = u;
}
/// <summary>
/// Avatars the URL.
@ -169,7 +150,7 @@ namespace Yavsc.Helpers
/// <returns>The URL.</returns>
/// <param name="helper">Helper.</param>
/// <param name="username">Username.</param>
public static string AvatarUrl (this HtmlHelper helper, string username) {
public static string AvatarUrl (this System.Web.WebPages.Html.HtmlHelper helper, string username) {
ProfileBase pr = ProfileBase.Create (username);
var a = pr.GetPropertyValue("Avatar") ;
if (a == null || a is DBNull) return "/avatars/" + helper.Encode(username)+".png";

View file

@ -103,11 +103,9 @@ $(document).ready(function(){
</div>
</a>
<% } else { %>
<a href="/Blog/<%= HttpContext.Current.User.Identity.Name%>" accesskey = "B" >
<div class="menuitem">
<a href="/Blog/<%= HttpContext.Current.User.Identity.Name%>" accesskey = "B" class="menuitem">
<img src="<%=Html.AvatarUrl(HttpContext.Current.User.Identity.Name)%>" alt="vos billets" class="iconsmall" />
<div class="hint">Vos billets</div>
</div>
</a>
<a href="<%= Url.Content("~/Account/Profile/" + HttpContext.Current.User.Identity.Name) %>" accesskey="L" class="menuitem">
<i class="fa fa-user"></i> <%= HttpContext.Current.User.Identity.Name %>

View file

@ -20,7 +20,7 @@
<input type="submit"/>
<% } %></div>
<div class="panel">
<%= Html.ActionLink("S'enregistrer","Register",new {returnUrl=ViewData["returnUrl"]}, new { @class="actionlink" }) %>
<%= Html.ActionLink("S'enregistrer","RegisterForm",new {returnUrl=ViewData["returnUrl"]}, new { @class="actionlink" }) %>
</div>
<div class="panel">
<a href="<%=Request.Url.Scheme + "://" + Request.Url.Authority + "/Google/Login"%>?returnUrl=<%=ViewData["returnUrl"]==null?Request.Url.PathAndQuery:(string)ViewData["returnUrl"]%>" class="actionlink">

View file

@ -112,7 +112,7 @@ Avatar : <img class="avatar" src="<%=Model.avatar%>?version=<%=Html.Encode(DateT
<% } %>
<aside>
<%= Html.ActionLink("Changer de mot de passe","ChangePassword", "Account",null, new { @class="actionlink" })%>
<%= Html.ActionLink("Désincription","Unregister", "Account",null, new { @class="actionlink" })%>
<%= Html.ActionLink("Désincription","Unregister", "Account", new { id=ViewData["UserName"] } , new { @class="actionlink" })%>
</aside>
<aside>
<% if (Roles.IsUserInRole((string)ViewData ["UserName"],"Admin")) { %>

View file

@ -7,5 +7,6 @@ Warning: This will delete all of your data here, your profile, your posts and ot
<label for="confirmed">Unregister</label>
<%=Html.CheckBox("confirmed")%>
<input type="submit"/>
<%= Html.Hidden("UserName") %>
<% } %>
</asp:Content>