diff --git a/src/Umbraco.Core/Constants-Applications.cs b/src/Umbraco.Core/Constants-Applications.cs
index 9a910e131a..4ae32d1b2d 100644
--- a/src/Umbraco.Core/Constants-Applications.cs
+++ b/src/Umbraco.Core/Constants-Applications.cs
@@ -53,6 +53,11 @@
///
public const string Content = "content";
+ ///
+ /// alias for the media tree.
+ ///
+ public const string Members = "member";
+
///
/// alias for the media tree.
///
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/member.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/member.resource.js
new file mode 100644
index 0000000000..f5f32037ad
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/member.resource.js
@@ -0,0 +1,131 @@
+/**
+ * @ngdoc service
+ * @name umbraco.resources.memberResource
+ * @description Loads in data for members
+ **/
+function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
+
+ /** internal method process the saving of data and post processing the result */
+ function saveMember(content, action, files) {
+ return umbRequestHelper.postSaveContent(
+ umbRequestHelper.getApiUrl(
+ "memberApiBaseUrl",
+ "PostSave"),
+ content, action, files);
+ }
+
+ return {
+
+
+ /**
+ * @ngdoc method
+ * @name umbraco.resources.memberResource#getByLogin
+ * @methodOf umbraco.resources.memberResource
+ *
+ * @description
+ * Gets a member item with a given id
+ *
+ * ##usage
+ *
+ * memberResource.getByLogin("tom")
+ * .then(function(member) {
+ * var mymember = member;
+ * alert('its here!');
+ * });
+ *
+ *
+ * @param {Int} id id of member item to return
+ * @returns {Promise} resourcePromise object containing the member item.
+ *
+ */
+ getByLogin: function (loginName) {
+
+ return umbRequestHelper.resourcePromise(
+ $http.get(
+ umbRequestHelper.getApiUrl(
+ "memberApiBaseUrl",
+ "GetByLogin",
+ [{ loginName: loginName }])),
+ 'Failed to retreive data for member id ' + loginName);
+ },
+
+ /**
+ * @ngdoc method
+ * @name umbraco.resources.memberResource#deleteByLogin
+ * @methodOf umbraco.resources.memberResource
+ *
+ * @description
+ * Deletes a member item with a given id
+ *
+ * ##usage
+ *
+ * memberResource.deleteByLogin(1234)
+ * .then(function() {
+ * alert('its gone!');
+ * });
+ *
+ *
+ * @param {Int} id id of member item to delete
+ * @returns {Promise} resourcePromise object.
+ *
+ */
+ deleteByLogin: function (id) {
+ return umbRequestHelper.resourcePromise(
+ $http.delete(
+ umbRequestHelper.getApiUrl(
+ "memberApiBaseUrl",
+ "DeleteById",
+ [{ id: id }])),
+ 'Failed to delete item ' + id);
+ },
+
+ /**
+ * @ngdoc method
+ * @name umbraco.resources.memberResource#getScaffold
+ * @methodOf umbraco.resources.memberResource
+ *
+ * @description
+ * Returns a scaffold of an empty member item, given the id of the member item to place it underneath and the member type alias.
+ *
+ * - Member Type alias must be provided so umbraco knows which properties to put on the member scaffold
+ *
+ * The scaffold is used to build editors for member that has not yet been populated with data.
+ *
+ * ##usage
+ *
+ * memberResource.getScaffold('client')
+ * .then(function(scaffold) {
+ * var myDoc = scaffold;
+ * myDoc.name = "My new member item";
+ *
+ * memberResource.save(myDoc, true)
+ * .then(function(member){
+ * alert("Retrieved, updated and saved again");
+ * });
+ * });
+ *
+ *
+ * @param {String} alias membertype alias to base the scaffold on
+ * @returns {Promise} resourcePromise object containing the member scaffold.
+ *
+ */
+ getScaffold: function (alias) {
+
+ return umbRequestHelper.resourcePromise(
+ $http.get(
+ umbRequestHelper.getApiUrl(
+ "memberApiBaseUrl",
+ "GetEmpty",
+ [{ contentTypeAlias: alias }])),
+ 'Failed to retreive data for empty member item type ' + alias);
+
+ },
+
+ /** saves or updates a member object */
+ save: function (member, isNew, files) {
+ return saveMember(member, "save" + (isNew ? "New" : ""), files);
+ }
+ };
+}
+
+angular.module('umbraco.resources').factory('memberResource', memberResource);
diff --git a/src/Umbraco.Web.UI.Client/src/views/member/delete.html b/src/Umbraco.Web.UI.Client/src/views/member/delete.html
new file mode 100644
index 0000000000..c4d931b53b
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/views/member/delete.html
@@ -0,0 +1,12 @@
+
+
+
+
+ Are you sure you want to delete {{currentNode.name}} ?
+
+
+
+
+
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/member/edit.html b/src/Umbraco.Web.UI.Client/src/views/member/edit.html
new file mode 100644
index 0000000000..221886e162
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/views/member/edit.html
@@ -0,0 +1,40 @@
+
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/views/member/member.delete.controller.js b/src/Umbraco.Web.UI.Client/src/views/member/member.delete.controller.js
new file mode 100644
index 0000000000..27d01f6a4a
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/views/member/member.delete.controller.js
@@ -0,0 +1,32 @@
+/**
+ * @ngdoc controller
+ * @name Umbraco.Editors.Member.DeleteController
+ * @function
+ *
+ * @description
+ * The controller for deleting content
+ */
+function MemberDeleteController($scope, memberResource, treeService, navigationService) {
+
+ $scope.performDelete = function() {
+
+ //mark it for deletion (used in the UI)
+ $scope.currentNode.loading = true;
+
+ memberResource.deleteByLogin($scope.currentNode.id).then(function () {
+ $scope.currentNode.loading = false;
+
+ //TODO: Need to sync tree, etc...
+ treeService.removeNode($scope.currentNode);
+
+ navigationService.hideMenu();
+ });
+
+ };
+
+ $scope.cancel = function() {
+ navigationService.hideDialog();
+ };
+}
+
+angular.module("umbraco").controller("Umbraco.Editors.Member.DeleteController", MemberDeleteController);
diff --git a/src/Umbraco.Web.UI.Client/src/views/member/member.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/member/member.edit.controller.js
new file mode 100644
index 0000000000..4ff85a6f95
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/views/member/member.edit.controller.js
@@ -0,0 +1,88 @@
+/**
+ * @ngdoc controller
+ * @name Umbraco.Editors.Member.EditController
+ * @function
+ *
+ * @description
+ * The controller for the member editor
+ */
+function MemberEditController($scope, $routeParams, $q, $timeout, $window, memberResource, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, editorContextService) {
+
+ //initialize the file manager
+ fileManager.clearFiles();
+
+ if ($routeParams.create) {
+ //we are creating so get an empty member item
+ memberResource.getScaffold($routeParams.id, $routeParams.doctype)
+ .then(function(data) {
+ $scope.loaded = true;
+ $scope.content = data;
+ editorContextService.setContext($scope.content);
+ });
+ }
+ else {
+ //we are editing so get the content item from the server
+ memberResource.getByLogin($routeParams.id)
+ .then(function(data) {
+ $scope.loaded = true;
+ $scope.content = data;
+ editorContextService.setContext($scope.content);
+
+ //in one particular special case, after we've created a new item we redirect back to the edit
+ // route but there might be server validation errors in the collection which we need to display
+ // after the redirect, so we will bind all subscriptions which will show the server validation errors
+ // if there are any and then clear them so the collection no longer persists them.
+ serverValidationManager.executeAndClearAllSubscriptions();
+ });
+ }
+
+ //TODO: Need to figure out a way to share the saving and event broadcasting with all editors!
+
+ $scope.setStatus = function(status){
+ //add localization
+ $scope.status = status;
+ $timeout(function(){
+ $scope.status = undefined;
+ }, 2500);
+ };
+
+ $scope.save = function () {
+ var deferred = $q.defer();
+
+ $scope.setStatus("Saving...");
+ $scope.$broadcast("saving", { scope: $scope });
+
+ var currentForm = angularHelper.getRequiredCurrentForm($scope);
+
+ //don't continue if the form is invalid
+ if (currentForm.$invalid) return;
+
+ serverValidationManager.reset();
+
+ memberResource.save($scope.content, $routeParams.create, fileManager.getFiles())
+ .then(function (data) {
+
+ contentEditingHelper.handleSuccessfulSave({
+ scope: $scope,
+ newContent: data,
+ rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, data)
+ });
+
+ deferred.resolve(data);
+
+ }, function (err) {
+ contentEditingHelper.handleSaveError({
+ err: err,
+ allNewProps: contentEditingHelper.getAllProps(err.data),
+ allOrigProps: contentEditingHelper.getAllProps($scope.content)
+ });
+
+ deferred.reject(err);
+ });
+
+ return deferred.promise;
+ };
+
+}
+
+angular.module("umbraco").controller("Umbraco.Editors.Member.EditController", MemberEditController);
diff --git a/src/Umbraco.Web.UI/config/trees.config b/src/Umbraco.Web.UI/config/trees.config
index e18f473875..58c3560e54 100644
--- a/src/Umbraco.Web.UI/config/trees.config
+++ b/src/Umbraco.Web.UI/config/trees.config
@@ -30,7 +30,7 @@
-
+
diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs
index 30d9fc55ee..8c17fcc663 100644
--- a/src/Umbraco.Web/Editors/BackOfficeController.cs
+++ b/src/Umbraco.Web/Editors/BackOfficeController.cs
@@ -66,7 +66,8 @@ namespace Umbraco.Web.Editors
{"entityApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl("GetById")},
{"dataTypeApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl("GetById")},
{"dashboardApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl("GetDashboard")},
- {"logApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl("GetEntityLog")}
+ {"logApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl("GetEntityLog")},
+ {"memberApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl("GetByLogin")},
}
},
{
diff --git a/src/Umbraco.Web/Editors/ContentControllerBase.cs b/src/Umbraco.Web/Editors/ContentControllerBase.cs
index a7d603c562..6413173ce8 100644
--- a/src/Umbraco.Web/Editors/ContentControllerBase.cs
+++ b/src/Umbraco.Web/Editors/ContentControllerBase.cs
@@ -39,7 +39,7 @@ namespace Umbraco.Web.Editors
{
}
- protected HttpResponseMessage HandleContentNotFound(int id, bool throwException = true)
+ protected HttpResponseMessage HandleContentNotFound(object id, bool throwException = true)
{
ModelState.AddModelError("id", string.Format("content with id: {0} was not found", id));
var errorResponse = Request.CreateErrorResponse(
diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs
index 8d1dd5c3c6..b32b709df5 100644
--- a/src/Umbraco.Web/Editors/MediaController.cs
+++ b/src/Umbraco.Web/Editors/MediaController.cs
@@ -33,6 +33,7 @@ using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Editors
{
+
///
/// This controller is decorated with the UmbracoApplicationAuthorizeAttribute which means that any user requesting
/// access to ALL of the methods on this controller will need access to the media application.
diff --git a/src/Umbraco.Web/Editors/MemberController.cs b/src/Umbraco.Web/Editors/MemberController.cs
index aa07dc4923..a67f472f1a 100644
--- a/src/Umbraco.Web/Editors/MemberController.cs
+++ b/src/Umbraco.Web/Editors/MemberController.cs
@@ -3,17 +3,19 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
-
+using System.Web.Http;
+using AutoMapper;
using Examine.LuceneEngine.SearchCriteria;
using Examine.SearchCriteria;
-
-using umbraco.cms.businesslogic.member;
+using Umbraco.Core.Models;
+using Umbraco.Web.WebApi;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Constants = Umbraco.Core.Constants;
using Examine;
using System.Web.Security;
+using Member = umbraco.cms.businesslogic.member.Member;
namespace Umbraco.Web.Editors
{
@@ -23,71 +25,47 @@ namespace Umbraco.Web.Editors
///
[PluginController("UmbracoApi")]
[UmbracoApplicationAuthorizeAttribute(Constants.Applications.Members)]
- public class MemberController : UmbracoAuthorizedJsonController
+ public class MemberController : ContentControllerBase
{
- public IEnumerable Search(string query)
+ ///
+ /// Constructor
+ ///
+ public MemberController()
+ : this(UmbracoContext.Current)
+ {
+ }
+
+ ///
+ /// Constructor
+ ///
+ ///
+ public MemberController(UmbracoContext umbracoContext)
+ : base(umbracoContext)
{
- if (string.IsNullOrEmpty(query))
- throw new ArgumentException("A search query must be defined", "query");
+ }
-
- //this will change when we add the new members API, but for now, we need to live with this setup
+ ///
+ /// Gets the content json for the member
+ ///
+ ///
+ ///
+ public MemberDisplay GetByLogin(string loginName)
+ {
if (Member.InUmbracoMemberMode())
{
- var internalSearcher = ExamineManager.Instance.SearchProviderCollection[Constants.Examine.InternalMemberSearcher];
- var criteria = internalSearcher.CreateSearchCriteria("member", BooleanOperation.Or);
- var fields = new[] { "id", "__nodeName", "email" };
- var term = new[] { query.ToLower().Escape() };
- var operation = criteria.GroupedOr(fields, term).Compile();
-
- var results = internalSearcher.Search(operation)
- .Select(x => new MemberEntityBasic
- {
- Id = int.Parse(x["id"]),
- Name = x["nodeName"],
- Email = x["email"],
- LoginName = x["loginName"],
- Icon = ".icon-user"
- });
-
- return results;
+ var foundMember = Services.MemberService.GetByUsername(loginName);
+ if (foundMember == null)
+ {
+ HandleContentNotFound(loginName);
+ }
+ return Mapper.Map(foundMember);
}
else
{
- IEnumerable results;
-
- if (query.Contains("@"))
- {
- results = from MembershipUser x in Membership.FindUsersByEmail(query)
- select
- new MemberEntityBasic()
- {
- //how do we get ID?
- Id = 0,
- Email = x.Email,
- LoginName = x.UserName,
- Name = x.UserName,
- Icon = "icon-user"
- };
- }
- else
- {
- results = from MembershipUser x in Membership.FindUsersByName(query + "%")
- select
- new MemberEntityBasic()
- {
- //how do we get ID?
- Id = 0,
- Email = x.Email,
- LoginName = x.UserName,
- Name = x.UserName,
- Icon = "icon-user"
- };
- }
-
- return results;
+ //TODO: Support this
+ throw new HttpResponseException(Request.CreateValidationErrorResponse("Editing member with a non-umbraco membership provider is currently not supported"));
}
+
}
-
}
}
diff --git a/src/Umbraco.Web/Models/ContentEditing/MemberDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/MemberDisplay.cs
new file mode 100644
index 0000000000..27a4eaca0f
--- /dev/null
+++ b/src/Umbraco.Web/Models/ContentEditing/MemberDisplay.cs
@@ -0,0 +1,20 @@
+using System.Runtime.Serialization;
+using Umbraco.Core.Models;
+
+namespace Umbraco.Web.Models.ContentEditing
+{
+ ///
+ /// A model representing a member to be displayed in the back office
+ ///
+ [DataContract(Name = "content", Namespace = "")]
+ public class MemberDisplay : ContentItemDisplayBase
+ {
+
+ [DataMember(Name = "username")]
+ public string Username { get; set; }
+
+ [DataMember(Name = "email")]
+ public string Email { get; set; }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Models/ContentEditing/MemberEntityBasic.cs b/src/Umbraco.Web/Models/ContentEditing/MemberEntityBasic.cs
deleted file mode 100644
index d836cb71a4..0000000000
--- a/src/Umbraco.Web/Models/ContentEditing/MemberEntityBasic.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.Serialization;
-using System.Text;
-using System.Threading.Tasks;
-using Umbraco.Core.Models.Validation;
-
-namespace Umbraco.Web.Models.ContentEditing
-{
- public class MemberEntityBasic : EntityBasic
- {
- [DataMember(Name = "email", IsRequired = true)]
- [RequiredForPersistence(AllowEmptyStrings = false, ErrorMessage = "Required")]
- public string Email { get; set; }
-
- [DataMember(Name = "loginName", IsRequired = true)]
- [RequiredForPersistence(AllowEmptyStrings = false, ErrorMessage = "Required")]
- public string LoginName { get; set; }
- }
-}
diff --git a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs
new file mode 100644
index 0000000000..d1689e6eb2
--- /dev/null
+++ b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs
@@ -0,0 +1,88 @@
+using AutoMapper;
+using Umbraco.Core;
+using Umbraco.Core.Models;
+using Umbraco.Core.Models.Mapping;
+using Umbraco.Web.Models.ContentEditing;
+using umbraco;
+
+namespace Umbraco.Web.Models.Mapping
+{
+ ///
+ /// Declares model mappings for members.
+ ///
+ internal class MemberModelMapper : MapperConfiguration
+ {
+ public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
+ {
+ //FROM IMember TO MediaItemDisplay
+ config.CreateMap()
+ .ForMember(
+ dto => dto.Owner,
+ expression => expression.ResolveUsing>())
+ .ForMember(
+ dto => dto.Icon,
+ expression => expression.MapFrom(content => content.ContentType.Icon))
+ .ForMember(
+ dto => dto.ContentTypeAlias,
+ expression => expression.MapFrom(content => content.ContentType.Alias))
+ .ForMember(
+ dto => dto.ContentTypeName,
+ expression => expression.MapFrom(content => content.ContentType.Name))
+ .ForMember(display => display.Properties, expression => expression.Ignore())
+ .ForMember(display => display.Tabs, expression => expression.ResolveUsing())
+ .AfterMap(MapGenericCustomProperties);
+
+ //FROM IMember TO ContentItemBasic
+ config.CreateMap>()
+ .ForMember(
+ dto => dto.Owner,
+ expression => expression.ResolveUsing>())
+ .ForMember(
+ dto => dto.Icon,
+ expression => expression.MapFrom(content => content.ContentType.Icon))
+ .ForMember(
+ dto => dto.ContentTypeAlias,
+ expression => expression.MapFrom(content => content.ContentType.Alias));
+
+ //FROM IMember TO ContentItemDto
+ config.CreateMap>()
+ .ForMember(
+ dto => dto.Owner,
+ expression => expression.ResolveUsing>());
+ }
+
+ ///
+ /// Maps the generic tab with custom properties for content
+ ///
+ ///
+ ///
+ private static void MapGenericCustomProperties(IMember member, MemberDisplay display)
+ {
+
+ TabsAndPropertiesResolver.MapGenericProperties(
+ member, display,
+ new ContentPropertyDisplay
+ {
+ Alias = string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
+ Label = ui.Text("login"),
+ Value = display.Username,
+ View = "textbox"
+ },
+ new ContentPropertyDisplay
+ {
+ Alias = string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
+ Label = ui.Text("password"),
+ Value = "",
+ View = "changepassword" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
+ },
+ new ContentPropertyDisplay
+ {
+ Alias = string.Format("{0}template", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
+ Label = ui.Text("general", "email"),
+ Value = display.Email,
+ View = "textbox"
+ });
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Trees/MediaTreeController.cs b/src/Umbraco.Web/Trees/MediaTreeController.cs
index 4c2a3dd3c0..ee2432bf15 100644
--- a/src/Umbraco.Web/Trees/MediaTreeController.cs
+++ b/src/Umbraco.Web/Trees/MediaTreeController.cs
@@ -1,8 +1,11 @@
using System;
+using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http.Formatting;
+using System.Web;
using System.Web.Http;
+using System.Web.Security;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
@@ -11,9 +14,86 @@ using Umbraco.Web.Trees.Menu;
using umbraco;
using umbraco.BusinessLogic.Actions;
using Constants = Umbraco.Core.Constants;
+using LegacyMember = umbraco.cms.businesslogic.member.Member;
namespace Umbraco.Web.Trees
{
+ [LegacyBaseTree(typeof (loadMembers))]
+ [Tree(Constants.Applications.Members, Constants.Trees.Members, "Members")]
+ [PluginController("UmbracoTrees")]
+ public class MemberTreeController : TreeController
+ {
+ protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
+ {
+ var nodes = new TreeNodeCollection();
+
+ if (id == Constants.System.Root.ToInvariantString())
+ {
+ //list out all the letters
+ for (var i = 97; i < 123; i++)
+ {
+ var charString = ((char) i).ToString(CultureInfo.InvariantCulture);
+ nodes.Add(CreateTreeNode(charString, queryStrings, charString, "icon-folder-close", true));
+ }
+ //list out 'Others' if the membership provider is umbraco
+ if (LegacyMember.InUmbracoMemberMode())
+ {
+ nodes.Add(CreateTreeNode("others", queryStrings, "Others", "icon-folder-close", true));
+ }
+ }
+ else
+ {
+ //if it is a letter
+ if (id.Length == 1 && char.IsLower(id, 0))
+ {
+ if (LegacyMember.InUmbracoMemberMode())
+ {
+ //get the members from our member data layer
+ nodes.AddRange(
+ LegacyMember.getMemberFromFirstLetter(id.ToCharArray()[0])
+ .Select(m => CreateTreeNode(m.LoginName, queryStrings, m.Text, "icon-user")));
+ }
+ else
+ {
+ //get the members from the provider
+ int total;
+ nodes.AddRange(
+ Membership.Provider.FindUsersByName(id + "%", 0, 9999, out total).Cast()
+ .Select(m => CreateTreeNode(m.UserName, queryStrings, m.UserName, "icon-user")));
+ }
+ }
+ else if (id == "others")
+ {
+ //others will only show up when in umbraco membership mode
+ nodes.AddRange(
+ LegacyMember.getAllOtherMembers()
+ .Select(m => CreateTreeNode(m.Id.ToInvariantString(), queryStrings, m.Text, "icon-user")));
+ }
+ }
+ return nodes;
+ }
+
+ protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
+ {
+ var menu = new MenuItemCollection();
+
+ if (id == Constants.System.Root.ToInvariantString())
+ {
+ //set default
+ menu.DefaultMenuAlias = ActionNew.Instance.Alias;
+
+ // root actions
+ menu.AddMenuItem();
+ menu.AddMenuItem(true);
+ return menu;
+ }
+
+ menu.AddMenuItem();
+ return menu;
+ }
+ }
+
+
[LegacyBaseTree(typeof(loadMedia))]
[Tree(Constants.Applications.Media, Constants.Trees.Media, "Media")]
[PluginController("UmbracoTrees")]
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index a09ed7c6df..4b64498c0b 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -314,10 +314,12 @@
+
+
@@ -333,7 +335,6 @@
-
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadMembers.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadMembers.cs
index 26e0a59b40..3e11a35f49 100644
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadMembers.cs
+++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadMembers.cs
@@ -31,7 +31,7 @@ namespace umbraco
///
/// Handles loading of the member application into the application tree
///
- [Tree(Constants.Applications.Members, "member", "Members")]
+ [Obsolete("This is no longer used and will be removed from the codebase in the future")]
public class loadMembers : BaseTree
{
public loadMembers(string application) : base(application) { }