Adds models and methods for the UserController

This commit is contained in:
Shannon
2017-05-11 13:11:41 +10:00
parent 7bfe736e5e
commit d2d6b6654a
14 changed files with 292 additions and 57 deletions

View File

@@ -118,7 +118,7 @@
public const string Scripts = "scripts";
public const string Users = "usersV2";
public const string Users = "users";
//TODO: Fill in the rest!
}

View File

@@ -24,9 +24,10 @@
<add application="developer" alias="xslt" title="XSLT Files" type="umbraco.loadXslt, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="5" />
<add application="developer" alias="partialViewMacros" type="Umbraco.Web.Trees.PartialViewMacrosTreeController, umbraco" silent="false" initialize="true" sortOrder="6" title="Partial View Macro Files" iconClosed="icon-folder" iconOpen="icon-folder" />
<!--Users-->
<add application="users" alias="users" title="Users" type="umbraco.loadUsers, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="0" />
<add application="users" alias="userTypes" title="User Types" type="umbraco.cms.presentation.Trees.UserTypes, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="1" />
<add application="users" alias="userPermissions" title="User Permissions" type="umbraco.cms.presentation.Trees.UserPermissions, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="2" />
<add initialize="true" sortOrder="3" alias="users" application="users" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.UserTreeController, umbraco" />
<add initialize="true" sortOrder="0" alias="users_old" application="users" title="Users (Legacy)" iconClosed=".sprTreeFolder" iconOpen=".sprTreeFolder_o" type="umbraco.loadUsers, umbraco" />
<!--Members-->
<add initialize="true" sortOrder="0" alias="member" application="member" title="Members" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.MemberTreeController, umbraco" />
<add initialize="true" sortOrder="1" alias="memberTypes" application="member" title="Member Types" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.MemberTypeTreeController, umbraco" />
@@ -40,5 +41,5 @@
<add initialize="true" sortOrder="2" alias="datasource" application="forms" title="Datasources" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Forms.Web.Trees.DataSourceTreeController, Umbraco.Forms.Web" />
<add initialize="true" sortOrder="0" alias="form" application="forms" title="Forms" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Forms.Web.Trees.FormTreeController, Umbraco.Forms.Web" />
<add initialize="true" sortOrder="3" alias="prevaluesource" application="forms" title="Prevalue sources" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Forms.Web.Trees.PreValueSourceTreeController, Umbraco.Forms.Web" />
<add initialize="true" sortOrder="3" alias="formsecurity" application="users" title="Forms Security" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Forms.Web.Trees.FormSecurityTreeController, Umbraco.Forms.Web" />
<add initialize="true" sortOrder="3" alias="formsecurity" application="users" title="Forms Security" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Forms.Web.Trees.FormSecurityTreeController, Umbraco.Forms.Web" />
</trees>

View File

@@ -1370,7 +1370,7 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="templates">Templates</key>
<key alias="xslt">XSLT Files</key>
<key alias="analytics">Analytics</key>
<key alias="usersV2">Users</key>
<key alias="users">Users</key>
</area>
<area alias="update">
<key alias="updateAvailable">New update ready</key>

View File

@@ -1367,6 +1367,7 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="templates">Templates</key>
<key alias="xslt">XSLT Files</key>
<key alias="analytics">Analytics</key>
<key alias="users">Users</key>
</area>
<area alias="update">
<key alias="updateAvailable">New update ready</key>

View File

@@ -23,6 +23,7 @@ using System.Text;
namespace Umbraco.Web.Editors
{
/// <summary>
/// The API controller used for editing data types
/// </summary>

View File

@@ -1,5 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using AutoMapper;
using ClientDependency.Core;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Constants = Umbraco.Core.Constants;
@@ -15,7 +26,7 @@ namespace Umbraco.Web.Editors
/// </summary>
public UserController()
: this(UmbracoContext.Current)
{
{
}
/// <summary>
@@ -24,7 +35,87 @@ namespace Umbraco.Web.Editors
/// <param name="umbracoContext"></param>
public UserController(UmbracoContext umbracoContext)
: base(umbracoContext)
{
{
}
/// <summary>
/// Gets a user by Id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public UserDisplay GetById(int id)
{
var user = Services.UserService.GetUserById(id);
if (user == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return Mapper.Map<IUser, UserDisplay>(user);
}
//TODO: This will probably not be UserDisplay objects since there's probably too much data in the display object for a grid
public PagedResult<UserDisplay> GetPagedUsers(
int id,
int pageNumber = 1,
int pageSize = 0,
string orderBy = "SortOrder",
Direction orderDirection = Direction.Ascending,
string filter = "")
{
//TODO: Make this real, for now this is mock data
var startId = 100 + ((pageNumber -1) * pageSize);
var numUsers = pageSize;
var users = new List<UserDisplay>();
var userTypes = Services.UserService.GetAllUserTypes().ToDictionary(x => x.Alias, x => x.Name);
var cultures = Services.TextService.GetSupportedCultures().ToDictionary(x => x.Name, x => x.DisplayName);
for (int i = 0; i < numUsers; i++)
{
var display = new UserDisplay
{
Id = startId,
UserType = "writer",
AllowedSections = new[] {"content", "media"},
AvailableUserTypes = userTypes,
Email = "test" + startId + "@test.com",
Name = "User " + startId,
Culture = "en-US",
AvailableCultures = cultures,
Path = "-1," + startId,
ParentId = -1,
StartContentId = -1,
StartMediaId = -1
};
users.Add(display);
startId++;
}
return new PagedResult<UserDisplay>(100, pageNumber, pageSize)
{
Items = users
};
}
public UserDisplay PostSaveUser(UserSave userSave)
{
if (userSave == null) throw new ArgumentNullException("userSave");
if (ModelState.IsValid == false)
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
}
var intId = userSave.Id.TryConvertTo<int>();
if (intId.Success == false)
throw new HttpResponseException(HttpStatusCode.NotFound);
var found = Services.UserService.GetUserById(intId.Result);
if (found == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
//TODO: More validation, password changing logic, persisting
return Mapper.Map<IUser, UserDisplay>(found);
}
/// <summary>

View File

@@ -1,14 +1,15 @@
using System.ComponentModel.DataAnnotations;
using System;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
using Umbraco.Core.Models.Membership;
namespace Umbraco.Web.Models.ContentEditing
{
/// <summary>
/// A basic structure the represents a user
/// A bare minimum structure that represents a user, usually attached to other objects
/// </summary>
[DataContract(Name = "user", Namespace = "")]
public class UserBasic : System.IComparable
public class UserBasic : IComparable
{
[DataMember(Name = "id", IsRequired = true)]
[Required]
@@ -19,9 +20,9 @@ namespace Umbraco.Web.Models.ContentEditing
public string Name { get; set; }
int System.IComparable.CompareTo(object obj)
int IComparable.CompareTo(object obj)
{
return Name.CompareTo(((UserBasic)obj).Name);
return String.Compare(Name, ((UserBasic)obj).Name, StringComparison.Ordinal);
}
}
}

View File

@@ -3,7 +3,10 @@ using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
namespace Umbraco.Web.Models.ContentEditing
{
{
/// <summary>
/// Represents information for the current user
/// </summary>
[DataContract(Name = "user", Namespace = "")]
public class UserDetail : UserBasic
{

View File

@@ -0,0 +1,59 @@
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.Serialization;
namespace Umbraco.Web.Models.ContentEditing
{
/// <summary>
/// Represents a user that is being edited
/// </summary>
[DataContract(Name = "user", Namespace = "")]
public class UserDisplay : EntityBasic, INotificationModel
{
public UserDisplay()
{
Notifications = new List<Notification>();
}
[DataMember(Name = "culture", IsRequired = true)]
public string Culture { get; set; }
[DataMember(Name = "email", IsRequired = true)]
public string Email { get; set; }
[DataMember(Name = "userType")]
public string UserType { get; set; }
/// <summary>
/// Gets the available user types (i.e. to populate a drop down)
/// The key is the Alias the value is the Name - the Alias is what is used in the UserType property and for persistence
/// </summary>
[DataMember(Name = "availableUserTypes")]
public IDictionary<string, string> AvailableUserTypes { get; set; }
/// <summary>
/// Gets the available cultures (i.e. to populate a drop down)
/// The key is the culture stored in the database, the value is the Name
/// </summary>
[DataMember(Name = "availableCultures")]
public IDictionary<string, string> AvailableCultures { get; set; }
[DataMember(Name = "startContentId")]
public int StartContentId { get; set; }
[DataMember(Name = "startMediaId")]
public int StartMediaId { get; set; }
/// <summary>
/// A list of sections the user is allowed to view.
/// </summary>
[DataMember(Name = "allowedSections")]
public IEnumerable<string> AllowedSections { get; set; }
/// <summary>
/// This is used to add custom localized messages/strings to the response for the app to use for localized UI purposes.
/// </summary>
[DataMember(Name = "notifications")]
public List<Notification> Notifications { get; private set; }
}
}

View File

@@ -0,0 +1,51 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
namespace Umbraco.Web.Models.ContentEditing
{
/// <summary>
/// Represents the data used to persist a user
/// </summary>
/// <remarks>
/// This will be different from the model used to display a user and we don't want to "Overpost" data back to the server,
/// and there will most likely be different bits of data required for updating passwords which will be different from the
/// data used to display vs save
/// </remarks>
[DataContract(Name = "user", Namespace = "")]
public class UserSave : EntityBasic, IValidatableObject
{
//TODO: There will be more information to save along with the structure for changing passwords
[DataMember(Name = "locale", IsRequired = true)]
[Required]
public string Culture { get; set; }
[DataMember(Name = "email", IsRequired = true)]
[Required]
[EmailAddress]
public string Email { get; set; }
[DataMember(Name = "userType")]
[Required]
public string UserType { get; set; }
[DataMember(Name = "startContentId")]
public int StartContentId { get; set; }
[DataMember(Name = "startMediaId")]
public int StartMediaId { get; set; }
[DataMember(Name = "allowedSections")]
public IEnumerable<string> AllowedSections { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
//TODO: Add other server side validation
//if (CultureInfo.GetCultureInfo(Culture))
// yield return new ValidationResult("The culture is invalid", new[] { "Culture" });
yield break;
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Linq;
using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Models.Mapping;
@@ -15,6 +16,16 @@ namespace Umbraco.Web.Models.Mapping
{
public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
{
config.CreateMap<IUser, UserDisplay>()
.ForMember(detail => detail.Id, opt => opt.MapFrom(user => user.Id))
.ForMember(detail => detail.UserType, opt => opt.MapFrom(user => user.UserType.Alias))
.ForMember(detail => detail.StartContentId, opt => opt.MapFrom(user => user.StartContentId))
.ForMember(detail => detail.StartMediaId, opt => opt.MapFrom(user => user.StartMediaId))
.ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService)))
.ForMember(
detail => detail.AvailableUserTypes,
opt => opt.MapFrom(user => applicationContext.Services.SectionService.GetSections().ToDictionary(x => x.Alias, x => x.Name)));
config.CreateMap<IUser, UserDetail>()
.ForMember(detail => detail.UserId, opt => opt.MapFrom(user => GetIntId(user.Id)))
.ForMember(detail => detail.UserType, opt => opt.MapFrom(user => user.UserType.Alias))

View File

@@ -1,44 +1,57 @@
using System.Net.Http.Formatting;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Trees
{
[UmbracoTreeAuthorize(Constants.Trees.Users)]
[Tree(Constants.Applications.Users, Constants.Trees.Users, null, sortOrder: 3)]
[PluginController("UmbracoTrees")]
[CoreTree]
public class UsersTreeController : TreeController
{
/// <summary>
/// Helper method to create a root model for a tree
/// </summary>
/// <returns></returns>
protected override TreeNode CreateRootNode(FormDataCollection queryStrings)
{
var root = base.CreateRootNode(queryStrings);
//this will load in a custom UI instead of the dashboard for the root node
root.RoutePath = string.Format("{0}/{1}/{2}", Constants.Applications.Users, Constants.Trees.Users, "overview");
root.Icon = "icon-users";
return root;
}
protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
{
var baseUrl = Constants.Applications.Users + "/users/";
var nodes = new TreeNodeCollection();
return nodes;
}
protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
{
var menu = new MenuItemCollection();
return menu;
}
}
using System.Net.Http.Formatting;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Trees
{
[UmbracoTreeAuthorize(Constants.Trees.Users)]
[Tree(Constants.Applications.Users, Constants.Trees.Users, null, sortOrder: 3)]
[PluginController("UmbracoTrees")]
[CoreTree]
public class UserTreeController : TreeController
{
public UserTreeController()
{
}
public UserTreeController(UmbracoContext umbracoContext) : base(umbracoContext)
{
}
public UserTreeController(UmbracoContext umbracoContext, UmbracoHelper umbracoHelper) : base(umbracoContext, umbracoHelper)
{
}
/// <summary>
/// Helper method to create a root model for a tree
/// </summary>
/// <returns></returns>
protected override TreeNode CreateRootNode(FormDataCollection queryStrings)
{
var root = base.CreateRootNode(queryStrings);
//this will load in a custom UI instead of the dashboard for the root node
root.RoutePath = string.Format("{0}/{1}/{2}", Constants.Applications.Users, Constants.Trees.Users, "overview");
root.Icon = "icon-users";
root.HasChildren = false;
return root;
}
protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
{
var baseUrl = Constants.Applications.Users + "/users/";
var nodes = new TreeNodeCollection();
return nodes;
}
protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
{
var menu = new MenuItemCollection();
return menu;
}
}
}

View File

@@ -366,6 +366,8 @@
<Compile Include="Models\ContentEditing\SimpleNotificationModel.cs" />
<Compile Include="Models\ContentEditing\SnippetDisplay.cs" />
<Compile Include="Models\ContentEditing\TemplateDisplay.cs" />
<Compile Include="Models\ContentEditing\UserDisplay.cs" />
<Compile Include="Models\ContentEditing\UserSave.cs" />
<Compile Include="Models\LocalPackageInstallModel.cs" />
<Compile Include="Models\Mapping\CodeFileDisplayMapper.cs" />
<Compile Include="Models\Mapping\ContentTypeModelMapperExtensions.cs" />
@@ -433,7 +435,7 @@
<Compile Include="Models\Mapping\PropertyTypeGroupResolver.cs" />
<Compile Include="Security\Identity\PreviewAuthenticationMiddleware.cs" />
<Compile Include="SingletonHttpContextAccessor.cs" />
<Compile Include="Trees\UsersTreeController.cs" />
<Compile Include="Trees\UserTreeController.cs" />
<Compile Include="Trees\ContentTypeTreeController.cs" />
<Compile Include="Trees\PackagesTreeController.cs" />
<Compile Include="Trees\MediaTypeTreeController.cs" />

View File

@@ -34,7 +34,8 @@ namespace umbraco
/// <summary>
/// Handles loading of all umbraco users into the users application tree
/// </summary>
[Tree(Constants.Applications.Users, "users", "Users")]
[Tree(Constants.Applications.Users, "users_old", "Users (Legacy)")]
//TODO: Remove this tree when ready
public class loadUsers : BaseTree
{
public loadUsers(string application) : base(application) { }