Pārlūkot izejas kodu

Rollenverwaltung fast zu 100% abgeschlossen!

Arne Diekmann 8 gadi atpakaļ
vecāks
revīzija
cd308da0ae
36 mainītis faili ar 1038 papildinājumiem un 196 dzēšanām
  1. 14 0
      GreenTree.Nachtragsmanagement.Core/Authentication/UserContext.cs
  2. 30 4
      GreenTree.Nachtragsmanagement.Core/CommonHelper.cs
  3. 10 0
      GreenTree.Nachtragsmanagement.Core/Domain/User/Function.cs
  4. 13 0
      GreenTree.Nachtragsmanagement.Core/Domain/User/Role.cs
  5. 15 0
      GreenTree.Nachtragsmanagement.Core/Domain/User/User.cs
  6. 1 0
      GreenTree.Nachtragsmanagement.Core/GreenTree.Nachtragsmanagement.Core.csproj
  7. 31 1
      GreenTree.Nachtragsmanagement.Data/AppendixObjectContext.cs
  8. 2 0
      GreenTree.Nachtragsmanagement.Data/Mapping/User/FunctionMap.cs
  9. 6 0
      GreenTree.Nachtragsmanagement.Services/User/IUserService.cs
  10. 13 0
      GreenTree.Nachtragsmanagement.Services/User/UserService.cs
  11. 59 0
      GreenTree.Nachtragsmanagement.Web.Framework/Extension/DevExpress/TreeViewSettingsExtension.cs
  12. 61 0
      GreenTree.Nachtragsmanagement.Web.Framework/GreenTree.Nachtragsmanagement.Web.Framework.csproj
  13. 4 1
      GreenTree.Nachtragsmanagement.Web/Content/devex.css
  14. 5 0
      GreenTree.Nachtragsmanagement.Web/Content/function.css
  15. 0 4
      GreenTree.Nachtragsmanagement.Web/Content/global.css
  16. 198 7
      GreenTree.Nachtragsmanagement.Web/Controllers/AdminController.cs
  17. 3 65
      GreenTree.Nachtragsmanagement.Web/Controllers/HomeController.cs
  18. 11 5
      GreenTree.Nachtragsmanagement.Web/GreenTree.Nachtragsmanagement.Web.csproj
  19. 59 0
      GreenTree.Nachtragsmanagement.Web/Models/Admin/User/RoleDataModel.cs
  20. 3 3
      GreenTree.Nachtragsmanagement.Web/Models/Admin/User/UserDataModel.cs
  21. 14 0
      GreenTree.Nachtragsmanagement.Web/Models/Global/OptionDialogItemModel.cs
  22. 15 0
      GreenTree.Nachtragsmanagement.Web/Models/Global/OptionDialogModel.cs
  23. 0 0
      GreenTree.Nachtragsmanagement.Web/Models/Global/YesNoDialogModel.cs
  24. 25 0
      GreenTree.Nachtragsmanagement.Web/Validation/Admin/User/RoleDataModelValidator.cs
  25. 1 0
      GreenTree.Nachtragsmanagement.Web/Validation/AppendixValidatorFactory.cs
  26. 174 3
      GreenTree.Nachtragsmanagement.Web/Views/Admin/Roles/View.cshtml
  27. 140 0
      GreenTree.Nachtragsmanagement.Web/Views/Admin/Roles/_RoleEditPartial.cshtml
  28. 65 0
      GreenTree.Nachtragsmanagement.Web/Views/Admin/Roles/_RoleGridPartial.cshtml
  29. 2 2
      GreenTree.Nachtragsmanagement.Web/Views/Admin/Users/View.cshtml
  30. 1 1
      GreenTree.Nachtragsmanagement.Web/Views/Admin/Users/_UserEditPartial.cshtml
  31. 23 16
      GreenTree.Nachtragsmanagement.Web/Views/Admin/Users/_UserGridPartial.cshtml
  32. 0 55
      GreenTree.Nachtragsmanagement.Web/Views/Home/Plugins.cshtml
  33. 0 29
      GreenTree.Nachtragsmanagement.Web/Views/Home/Relations.cshtml
  34. 15 0
      GreenTree.Nachtragsmanagement.Web/Views/Shared/_PopupButtonPanelOption.cshtml
  35. 25 0
      GreenTree.Nachtragsmanagement.Web/Views/Shared/_PopupDialogOption.cshtml
  36. 0 0
      GreenTree.Nachtragsmanagement.Web/Views/Shared/_PopupDialogYesNo.cshtml

+ 14 - 0
GreenTree.Nachtragsmanagement.Core/Authentication/UserContext.cs

@@ -0,0 +1,14 @@
+using GreenTree.Nachtragsmanagement.Core.Domain.User;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GreenTree.Nachtragsmanagement.Core.Authentication
+{
+    public class UserContext
+    {
+        public User CurrentUser { get; set; }
+    }
+}

+ 30 - 4
GreenTree.Nachtragsmanagement.Core/CommonHelper.cs

@@ -7,11 +7,15 @@ using System.Reflection;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
+using Autofac;
+using Autofac.Integration.Mvc;
 using GreenTree.Nachtragsmanagement.Core.ComponentModel;
+using GreenTree.Nachtragsmanagement.Core.Domain.User;
+using GreenTree.Nachtragsmanagement.Core.Authentication;
 
 namespace GreenTree.Nachtragsmanagement.Core
 {
-    public class CommonHelper
+    public static class CommonHelper
     {
         private static AspNetHostingPermissionLevel? _trustLevel;
         /// <summary>
@@ -49,6 +53,8 @@ namespace GreenTree.Nachtragsmanagement.Core
             return _trustLevel.Value;
         }
 
+        #region Conversion
+
         /// <summary>
         /// Sets a property on an object to a valuae.
         /// </summary>
@@ -73,7 +79,7 @@ namespace GreenTree.Nachtragsmanagement.Core
             pi.SetValue(instance, value, new object[0]);
         }
 
-        public static TypeConverter GetNopCustomTypeConverter(Type type)
+        public static TypeConverter GetCustomTypeConverter(Type type)
         {
             //we can't use the following code in order to register our custom type descriptors
             //TypeDescriptor.AddAttributes(typeof(List<int>), new TypeConverterAttribute(typeof(GenericListTypeConverter<int>)));
@@ -113,8 +119,8 @@ namespace GreenTree.Nachtragsmanagement.Core
             {
                 var sourceType = value.GetType();
 
-                TypeConverter destinationConverter = GetNopCustomTypeConverter(destinationType);
-                TypeConverter sourceConverter = GetNopCustomTypeConverter(sourceType);
+                TypeConverter destinationConverter = GetCustomTypeConverter(destinationType);
+                TypeConverter sourceConverter = GetCustomTypeConverter(sourceType);
                 if (destinationConverter != null && destinationConverter.CanConvertFrom(value.GetType()))
                     return destinationConverter.ConvertFrom(null, culture, value);
                 if (sourceConverter != null && sourceConverter.CanConvertTo(destinationType))
@@ -155,5 +161,25 @@ namespace GreenTree.Nachtragsmanagement.Core
                     result += c.ToString();
             return result;
         }
+
+        #endregion
+
+        #region User-Handling
+
+        /// <summary>
+        /// Evaluate the user context of the current logged in user
+        /// </summary>
+        public static UserContext UserContext()
+        {
+            var container = Singleton<Autofac.IContainer>.Instance;
+            var userHelper = container.Resolve<IUserHelper>();
+
+            return new UserContext
+            {
+                CurrentUser = userHelper.FromCookies()
+            };
+        }
+
+        #endregion
     }
 }

+ 10 - 0
GreenTree.Nachtragsmanagement.Core/Domain/User/Function.cs

@@ -33,6 +33,16 @@ namespace GreenTree.Nachtragsmanagement.Core.Domain.User
         /// </summary>
         public string RouteName { get; set; }
 
+        /// <summary>
+        /// Determines if the function is displayed in function menu
+        /// </summary>
+        public bool? IsMenuMember { get; set; }
+
+        /// <summary>
+        /// Plugin which the function is created by
+        /// </summary>
+        public string Plugin { get; set; }
+
         /// <summary>
         /// Base width in pixel
         /// </summary>

+ 13 - 0
GreenTree.Nachtragsmanagement.Core/Domain/User/Role.cs

@@ -35,5 +35,18 @@ namespace GreenTree.Nachtragsmanagement.Core.Domain.User
             get { return _functions ?? (_functions = new List<Function>()); }
             protected set { _functions = value; }
         }
+
+        #region Helper
+
+        /// <summary>
+        /// Adds missing functions and removes not selected functions
+        /// </summary>
+        /// <param name="functions">Functions.</param>
+        public void SetFunctions(ICollection<Function> functions)
+        {
+            Functions = functions;
+        }
+
+        #endregion
     }
 }

+ 15 - 0
GreenTree.Nachtragsmanagement.Core/Domain/User/User.cs

@@ -82,6 +82,21 @@ namespace GreenTree.Nachtragsmanagement.Core.Domain.User
             Roles = roles;
         }
 
+        /// <summary>
+        /// Determines if the user is member of role which owns a specific function
+        /// </summary>
+        /// <param name="functionName">The name of the function.</param>
+        public bool HasFunction(string functionName)
+        {
+            if (String.IsNullOrEmpty(functionName))
+                return false;
+
+            return
+                Roles
+                    .SelectMany(s => s.Functions)
+                    .Any(f => f.Name == functionName);
+        }
+
         #endregion
     }
 }

+ 1 - 0
GreenTree.Nachtragsmanagement.Core/GreenTree.Nachtragsmanagement.Core.csproj

@@ -77,6 +77,7 @@
     <Compile Include="AppDomainTypeFinder.cs" />
     <Compile Include="AppendixVersion.cs" />
     <Compile Include="Authentication\IUserHelper.cs" />
+    <Compile Include="Authentication\UserContext.cs" />
     <Compile Include="Authentication\UserHelper.cs" />
     <Compile Include="BaseEntity.cs" />
     <Compile Include="CommonHelper.cs" />

+ 31 - 1
GreenTree.Nachtragsmanagement.Data/AppendixObjectContext.cs

@@ -236,7 +236,9 @@ namespace GreenTree.Nachtragsmanagement.Data
             {
                 Name = "Administration",
                 Description = "Administration",
-                ImageUrl = "~/Content/Images/function-Administration-32.png"
+                ImageUrl = "~/Content/Images/function-Administration-32.png",
+                IsMenuMember = true,
+                Plugin = "System"
             });
 
             var f2 = Get<Function>().Add(new Function
@@ -246,6 +248,8 @@ namespace GreenTree.Nachtragsmanagement.Data
                 ImageUrl = "~/Content/Images/function-Administration-Users-32.png",
                 GroupName = "Administration",
                 RouteName = "GreenTree.Nachtragsmanagement.Web.Administration.Users",
+                IsMenuMember = true,
+                Plugin = "System",
                 BaseWidth = 900,
                 MinWidth = 600,
                 BaseHeight = 600,
@@ -253,12 +257,24 @@ namespace GreenTree.Nachtragsmanagement.Data
                 AllowMaximize = true
             });
 
+            var f2_1 = Get<Function>().Add(new Function
+            {
+                Name = "Administration-Users-Edit",
+                Description = "Benutzer editieren",
+                GroupName = "Administration-Users",
+                IsMenuMember = false,
+                Plugin = "System"
+            });
+
             var f3 = Get<Function>().Add(new Function
             {
                 Name = "Administration-Roles",
                 Description = "Rollenverwaltung",
                 ImageUrl = "~/Content/Images/function-Administration-Roles-32.png",
                 GroupName = "Administration",
+                RouteName = "GreenTree.Nachtragsmanagement.Web.Administration.Roles",
+                IsMenuMember = true,
+                Plugin = "System",
                 BaseWidth = 800,
                 MinWidth = 600,
                 BaseHeight = 500,
@@ -266,12 +282,24 @@ namespace GreenTree.Nachtragsmanagement.Data
                 AllowMaximize = true
             });
 
+            var f3_1 = Get<Function>().Add(new Function
+            {
+                Name = "Administration-Roles-Edit",
+                Description = "Rollen editieren",
+                GroupName = "Administration-Roles",
+                IsMenuMember = false,
+                Plugin = "System"
+            });
+
             var f4 = Get<Function>().Add(new Function
             {
                 Name = "Administration-Plugins",
                 Description = "Pluginverwaltung",
                 ImageUrl = "~/Content/Images/function-Administration-Plugins-32.png",
                 GroupName = "Administration",
+                RouteName = "GreenTree.Nachtragsmanagement.Web.Administration.Plugins",
+                IsMenuMember = true,
+                Plugin = "System",
                 BaseWidth = 800,
                 MinWidth = 500,
                 BaseHeight = 450,
@@ -303,7 +331,9 @@ namespace GreenTree.Nachtragsmanagement.Data
 
             r1.Functions.Add(f1);
             r1.Functions.Add(f2);
+            r1.Functions.Add(f2_1);
             r1.Functions.Add(f3);
+            r1.Functions.Add(f3_1);
             r1.Functions.Add(f4);
 
             var u1 = Get<User>().Add(new User

+ 2 - 0
GreenTree.Nachtragsmanagement.Data/Mapping/User/FunctionMap.cs

@@ -20,6 +20,8 @@ namespace GreenTree.Nachtragsmanagement.Data.Mapping.User
             Property(f => f.GroupName);
             Property(f => f.ImageUrl);
             Property(f => f.RouteName);
+            Property(f => f.IsMenuMember);
+            Property(f => f.Plugin);
             Property(f => f.BaseWidth);
             Property(f => f.MinWidth);
             Property(f => f.BaseHeight);

+ 6 - 0
GreenTree.Nachtragsmanagement.Services/User/IUserService.cs

@@ -75,6 +75,12 @@ namespace GreenTree.Nachtragsmanagement.Services.User
         /// </summary>
         IList<Role> GetRolesByIds(int[] ids);
 
+        /// <summary>
+        /// Gets all users to the corresponding role
+        /// </summary>
+        /// <param name="roleId">Role id.</param>
+        IList<Core.Domain.User.User> GetUsersByRole(int roleId);
+
         /// <summary>
         /// Insert a user
         /// </summary>

+ 13 - 0
GreenTree.Nachtragsmanagement.Services/User/UserService.cs

@@ -135,6 +135,19 @@ namespace GreenTree.Nachtragsmanagement.Services.User
                 .ToList();
         }
 
+        /// <summary>
+        /// Gets all users to the corresponding role
+        /// </summary>
+        /// <param name="roleId">Role id.</param>
+        public IList<Core.Domain.User.User> GetUsersByRole(int roleId)
+        {
+            return _userRepository.Table
+                .Where(u => u.Roles
+                    .Select(r => r.Id)
+                    .Contains(roleId))
+                .ToList();
+        }
+
         /// <summary>
         /// Insert a user
         /// </summary>

+ 59 - 0
GreenTree.Nachtragsmanagement.Web.Framework/Extension/DevExpress/TreeViewSettingsExtension.cs

@@ -0,0 +1,59 @@
+using DevExpress.Web.Mvc;
+using GreenTree.Nachtragsmanagement.Core.Domain.User;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GreenTree.Nachtragsmanagement.Web.Framework.Extension.DevExpress
+{
+    public static class TreeViewSettingsExtension
+    {
+        /// <summary>
+        /// Extension method to build up a tree view of the available functions
+        /// </summary>
+        /// <param name="settings">The current TreeViewSettings.</param>
+        /// <param name="functionList">Available functions.</param>
+        public static void CreateGroupedFunctionList(this TreeViewSettings settings, IList<Function> functionList)
+        {
+            if (settings == null || functionList == null) return;
+
+            var dynFunctions = functionList
+                .Select(f => new
+                {
+                    Function = f,
+                    SubFunctions = new List<dynamic>()
+                })
+                .ToList();
+
+            var dictFunctions = dynFunctions.ToDictionary(g => g.Function.Name);
+            foreach (var item in dynFunctions.Where(g => g.Function.GroupName != null))
+            {
+                dictFunctions[item.Function.GroupName].SubFunctions.Add(item);
+            }
+            var groupFunctions = dynFunctions.Where(g => g.Function.GroupName == null);
+
+            foreach (var mainFunction in groupFunctions)
+            {
+                var node = settings.Nodes.Add(mainFunction.Function.Description, mainFunction.Function.Id.ToString());
+
+                foreach (var subFunction in mainFunction.SubFunctions)
+                    IterateGroupedFunction(node, subFunction);
+            }
+        }
+
+        /// <summary>
+        /// Recursive method to iterate each subFunction of a dynamic function tree and creates a corresponding node
+        /// </summary>
+        /// <param name="node">The current parent to be iterated.</param>
+        /// <param name="functionContainer">The corresponding function tree.</param>
+        private static void IterateGroupedFunction(MVCxTreeViewNode node, dynamic functionContainer)
+        {
+            var subNode = node.Nodes.Add(functionContainer.Function.Description, functionContainer.Function.Id.ToString());
+
+            foreach (var subFunction in functionContainer.SubFunctions)
+                IterateGroupedFunction(subNode, subFunction);
+        }
+    }
+}

+ 61 - 0
GreenTree.Nachtragsmanagement.Web.Framework/GreenTree.Nachtragsmanagement.Web.Framework.csproj

@@ -36,6 +36,66 @@
     <Reference Include="Autofac.Integration.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
       <HintPath>..\packages\Autofac.Mvc5.4.0.2\lib\net45\Autofac.Integration.Mvc.dll</HintPath>
     </Reference>
+    <Reference Include="DevExpress.Charts.v17.1.Core, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.CodeParser.v17.1, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.Data.v17.1, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.DataAccess.v17.1, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.Office.v17.1.Core, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.Pdf.v17.1.Core, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.PivotGrid.v17.1.Core, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.Printing.v17.1.Core, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.RichEdit.v17.1.Core, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.Sparkline.v17.1.Core, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.Utils.v17.1, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.Web.ASPxThemes.v17.1, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.Web.Mvc5.v17.1, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.Web.Resources.v17.1, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.Web.v17.1, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.Xpo.v17.1, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.XtraCharts.v17.1, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.XtraGauges.v17.1.Core, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.XtraReports.v17.1, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="DevExpress.XtraReports.v17.1.Web, Version=17.1.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
     <Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
       <HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
       <Private>True</Private>
@@ -72,6 +132,7 @@
   <ItemGroup>
     <Compile Include="ApplicationContext.cs" />
     <Compile Include="Authorization\RoleAuthorizeAttribute.cs" />
+    <Compile Include="Extension\DevExpress\TreeViewSettingsExtension.cs" />
     <Compile Include="Mvc\Routes\GuidConstraint.cs" />
     <Compile Include="Mvc\Routes\IRouteProvider.cs" />
     <Compile Include="Mvc\Routes\IRoutePublisher.cs" />

+ 4 - 1
GreenTree.Nachtragsmanagement.Web/Content/devex.css

@@ -22,4 +22,7 @@
 .devExBorderBottom { border-bottom-style: solid !important; }
 .devExBorderBottomGray { border-bottom-color: #D9D9D9 !important; }
 .devExBorderBottomSmall { border-bottom-width: 1px !important; }
-.devExAllowDrag { cursor: move; }
+.devExAllowDrag { cursor: move; }
+
+.devExDisplayHidden { display: none; }
+.devExDisplayTableRow { display: table-row; }

+ 5 - 0
GreenTree.Nachtragsmanagement.Web/Content/function.css

@@ -2,8 +2,13 @@
     background: white;
 }
 
+.editFormWrapper {
+    padding: 0 12px 18px;
+}
+
 /* Label and validation customization */
 
+
 .inlineModelPropertyContainer {
     width: 100%;
     overflow: auto;

+ 0 - 4
GreenTree.Nachtragsmanagement.Web/Content/global.css

@@ -54,10 +54,6 @@ h1, h2, h3, h4, h5, h6 {
     margin-left: 16px;
 }
 
-.editFormWrapper {
-    padding: 12px 12px 18px;
-}
-
 .popupButtonPanel {
     width: 100%;
     background-color: #e5e5e5;

+ 198 - 7
GreenTree.Nachtragsmanagement.Web/Controllers/AdminController.cs

@@ -9,6 +9,7 @@ using GreenTree.Nachtragsmanagement.Web.Models.Admin.User;
 using GreenTree.Nachtragsmanagement.Core.Domain.User;
 using Newtonsoft.Json;
 using GreenTree.Nachtragsmanagement.Core;
+using GreenTree.Nachtragsmanagement.Core.Plugins;
 
 namespace GreenTree.Nachtragsmanagement.Web.Controllers
 {
@@ -16,15 +17,19 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
     {
         private readonly IUserService _userService;
         private readonly IUserHelper _userHelper;
+        private readonly IPluginFinder _pluginFinder;
 
         public AdminController(
             IUserService userService,
-            IUserHelper userHelper)
+            IUserHelper userHelper,
+            IPluginFinder pluginFinder)
         {
             _userService = userService;
             _userHelper = userHelper;
+            _pluginFinder = pluginFinder;
 
             ViewData["AllRoles"] = _userService.GetAllRoles();
+            ViewData["AllFunctions"] = _userService.GetAllFunctions();
         }
 
         #region Users
@@ -168,21 +173,207 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         /// </summary>
         public ActionResult ViewRoles()
         {
-            return View("~/Views/Admin/Roles/View.cshtml");
+            var roles = _userService.GetAllRoles();
+            var roleModels = roles
+                .Select(r => RoleDataModel.FromRole(r, false))
+                .ToList();
+
+            return View("~/Views/Admin/Roles/View.cshtml", roleModels);
         }
 
-        #endregion
+        /// <summary>
+        /// Get JSON data of specific role
+        /// </summary>
+        /// <param name="id">Role id.</param>
+        public ActionResult GetRole(int id = -1)
+        {
+            var role = _userService.GetRoleById(id);
+            if (role == null)
+                return new JsonResult
+                {
+                    Data = "notFound",
+                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
+                };
 
-        #region Plugins
+            var roleModel = RoleDataModel.FromRole(role, false);
+
+            return new JsonResult
+            {
+                Data = JsonConvert.SerializeObject(roleModel),
+                JsonRequestBehavior = JsonRequestBehavior.AllowGet
+            };
+        }
+
+        /// <summary>
+        /// Callback result for role grid
+        /// </summary>
+        public ActionResult PartialRoles()
+        {
+            var roles = _userService.GetAllRoles();
+            var roleModels = roles
+                .Select(r => RoleDataModel.FromRole(r, false))
+                .ToList();
+
+            return PartialView("~/Views/Admin/Roles/_RoleGridPartial.cshtml", roleModels);
+        }
+
+        /// <summary>
+        /// Partial edit for editing of existing or for new role
+        /// </summary>
+        /// <param name="id">Id for existing role, otherweise -1.</param>
+        public ActionResult EditRole(int id = -1)
+        {
+            var role = _userService.GetRoleById(id);
+            var roleModel = RoleDataModel.FromRole(role, true);
+
+            return PartialView("~/Views/Admin/Roles/_RoleEditPartial.cshtml", roleModel);
+        }
+
+        /// <summary>
+        /// Partial edit result if ModelState is valid, otherwise simple JSON result for success
+        /// </summary>
+        /// <param name="roleModel">Role model to be saved.</param>
+        [HttpPost, ValidateInput(false)]
+        public ActionResult EditRole(RoleDataModel roleModel)
+        {
+            if (!ModelState.IsValid)
+            {
+                foreach (var role in roleModel.FunctionValues)
+                    roleModel.FunctionDescriptions.Add(
+                        ((IList<Role>)ViewData["AllRoles"])
+                            .First(r => r.Id == role).Description);
+
+                return PartialView("~/Views/Admin/Roles/_RoleEditPartial.cshtml", roleModel);
+            }
+
+            var selectedFunctions = _userService.GetFunctionsByIds(roleModel.FunctionValues.ToArray());
+
+            if (roleModel.Id == -1)
+            {
+                var role = roleModel.ToRole();
+
+                role.SetFunctions(selectedFunctions);
+
+                _userService.InsertRole(role);
+            }
+            else
+            {
+                var role = _userService.GetRoleById(roleModel.Id);
+
+                role.Description = roleModel.Description;
+                role.Level = roleModel.Level;
+
+                role.SetFunctions(selectedFunctions);
+
+                _userService.UpdateRole(role);
+            }
+
+            return new JsonResult
+            {
+                Data = "success"
+            };
+        }
 
         /// <summary>
-        /// Basic plugin view function
+        /// Simple JSON result for deleting a specific role
         /// </summary>
-        public ActionResult ViewPlugins()
+        /// <param name="id">Role id.</param>
+        /// <param name="replaceId">Id of role which user get in place of deleting role.</param>
+        [HttpPost]
+        public ActionResult DeleteRole(int id, int replaceId)
         {
-            return View("~/Views/Admin/Plugins/View.cshtml");
+            var role = _userService.GetRoleById(id);
+            var replaceRole = _userService.GetRoleById(replaceId);
+
+            var roleUsers = _userService.GetUsersByRole(id);
+
+            foreach (var user in roleUsers)
+            {
+                if (replaceId == -1)
+                    user.Roles.Remove(role);
+                else
+                    user.Roles.Add(replaceRole);
+
+                _userService.UpdateUser(user);
+            }
+
+            if (role != null)
+                _userService.DeleteRole(role);
+
+            return new JsonResult
+            {
+                Data = "success"
+            };
         }
 
         #endregion
+
+        #region Plugins
+
+        ///// <summary>
+        ///// Basic plugin view function
+        ///// </summary>
+        //public ActionResult ViewPlugins()
+        //{
+        //    var model = new PluginModel
+        //    {
+        //        PluginNames = new List<string[]>()
+        //    };
+
+        //    var uninstalledPlugins = _pluginFinder.GetPlugins<IPlugin>(LoadPluginsMode.NotInstalledOnly);
+        //    var installedPlugins = _pluginFinder.GetPlugins<IPlugin>(LoadPluginsMode.InstalledOnly);
+
+        //    if (installedPlugins.Any())
+        //        model.PluginNames.AddRange(new List<string[]>()
+        //        {
+        //            new [] { installedPlugins.First().PluginDescriptor.SystemName, "installed" }
+        //        });
+
+        //    if (uninstalledPlugins.Any())
+        //        model.PluginNames.AddRange(new List<string[]>()
+        //        {
+        //            new [] { uninstalledPlugins.First().PluginDescriptor.SystemName, "uninstalled" }
+        //        });
+
+        //    return View("~/Views/Admin/Plugins/View.cshtml");
+        //}
+
+        //[HttpPost]
+        //public ActionResult InstallPlugin(string pluginName)
+        //{
+        //    var pluginDescriptor = _pluginFinder.GetPluginDescriptorBySystemName(pluginName, LoadPluginsMode.All);
+        //    if (pluginDescriptor == null)
+        //        return RedirectToAction("Plugins");
+
+        //    if (pluginDescriptor.Installed)
+        //        return RedirectToAction("Plugins");
+
+        //    var routes = System.Web.Routing.RouteTable.Routes;
+
+        //    pluginDescriptor.Instance().Install();
+
+        //    _webHelper.RestartAppDomain();
+
+        //    return RedirectToAction("Plugins");
+        //}
+
+        //[HttpPost]
+        //public ActionResult UninstallPlugin(string pluginName)
+        //{
+        //    var pluginDescriptor = _pluginFinder.GetPluginDescriptorBySystemName(pluginName, LoadPluginsMode.All);
+        //    if (pluginDescriptor == null)
+        //        return RedirectToAction("Plugins");
+
+        //    if (!pluginDescriptor.Installed)
+        //        return RedirectToAction("Plugins");
+
+        //    pluginDescriptor.Instance().Uninstall();
+
+        //    _webHelper.RestartAppDomain();
+
+        //    return RedirectToAction("Plugins");
+        //}
+
+        #endregion
     }
 }

+ 3 - 65
GreenTree.Nachtragsmanagement.Web/Controllers/HomeController.cs

@@ -25,7 +25,6 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
         private readonly IConfigurationService _configurationService;
         private readonly IUserService _userService;
         private readonly IUserHelper _userHelper;
-        private readonly IPluginFinder _pluginFinder;
         private readonly IWebHelper _webHelper;
 
         public HomeController(
@@ -33,14 +32,12 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             IConfigurationService configurationService,
             IUserService userService,
             IUserHelper userHelper,
-            IPluginFinder pluginFinder,
             IWebHelper webHelper)
         {
             _dbRelationService = dbRelationService;
             _configurationService = configurationService;
             _userService = userService;
             _userHelper = userHelper;
-            _pluginFinder = pluginFinder;
             _webHelper = webHelper;
         }
 
@@ -50,7 +47,9 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
             var user = _userHelper.FromCookies();
 
             var userFunctions = user.Roles
-                .SelectMany(s => s.Functions);
+                .SelectMany(s => s.Functions)
+                .Where(f => f.IsMenuMember.HasValue && f.IsMenuMember.Value)
+                .Distinct();
 
             var groups = userFunctions
                 .GroupBy(g => g.GroupName)
@@ -80,66 +79,5 @@ namespace GreenTree.Nachtragsmanagement.Web.Controllers
 
             return View("~/Views/Home/Index.cshtml", model);
         }
-
-        public ActionResult Plugins()
-        {
-            var model = new PluginModel
-            {
-                PluginNames = new List<string[]>()
-            };
-
-            var uninstalledPlugins = _pluginFinder.GetPlugins<IPlugin>(LoadPluginsMode.NotInstalledOnly);
-            var installedPlugins = _pluginFinder.GetPlugins<IPlugin>(LoadPluginsMode.InstalledOnly);
-
-            if (installedPlugins.Any())
-                model.PluginNames.AddRange(new List<string[]>()
-                {
-                    new [] { installedPlugins.First().PluginDescriptor.SystemName, "installed" }
-                });
-
-            if (uninstalledPlugins.Any())
-                model.PluginNames.AddRange(new List<string[]>()
-                {
-                    new [] { uninstalledPlugins.First().PluginDescriptor.SystemName, "uninstalled" }
-                });
-
-            return View("~/Views/Home/Plugins.cshtml", model);
-        }
-
-        [HttpPost]
-        public ActionResult InstallPlugin(string pluginName)
-        {
-            var pluginDescriptor = _pluginFinder.GetPluginDescriptorBySystemName(pluginName, LoadPluginsMode.All);
-            if (pluginDescriptor == null)
-                return RedirectToAction("Plugins");
-
-            if (pluginDescriptor.Installed)
-                return RedirectToAction("Plugins");
-
-            var routes = System.Web.Routing.RouteTable.Routes;
-
-            pluginDescriptor.Instance().Install();
-
-            _webHelper.RestartAppDomain();
-
-            return RedirectToAction("Plugins");
-        }
-
-        [HttpPost]
-        public ActionResult UninstallPlugin(string pluginName)
-        {
-            var pluginDescriptor = _pluginFinder.GetPluginDescriptorBySystemName(pluginName, LoadPluginsMode.All);
-            if (pluginDescriptor == null)
-                return RedirectToAction("Plugins");
-
-            if (!pluginDescriptor.Installed)
-                return RedirectToAction("Plugins");
-
-            pluginDescriptor.Instance().Uninstall();
-
-            _webHelper.RestartAppDomain();
-
-            return RedirectToAction("Plugins");
-        }
     }
 }

+ 11 - 5
GreenTree.Nachtragsmanagement.Web/GreenTree.Nachtragsmanagement.Web.csproj

@@ -213,8 +213,6 @@
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     <Content Include="Views\Shared\_Layout.cshtml" />
-    <Content Include="Views\Home\Relations.cshtml" />
-    <Content Include="Views\Home\Plugins.cshtml" />
     <Content Include="Views\Shared\_HeaderNavBar.cshtml" />
     <Content Include="Views\Login\Index.cshtml" />
     <Content Include="Views\Shared\_Footer.cshtml" />
@@ -222,13 +220,17 @@
     <Content Include="Views\Global\NotAuthorized.cshtml" />
     <Content Include="Views\Shared\_FunctionLayout.cshtml" />
     <Content Include="Views\Admin\Plugins\View.cshtml" />
-    <Content Include="Views\Admin\Roles\View.cshtml" />
     <Content Include="Views\Admin\Users\View.cshtml" />
     <Content Include="Views\Admin\Users\_UserGridPartial.cshtml" />
     <Content Include="Views\Admin\Users\_UserEditPartial.cshtml" />
     <Content Include="Views\Global\SuccessMessage.cshtml" />
-    <Content Include="Views\Shared\_PopupDialog.cshtml" />
+    <Content Include="Views\Shared\_PopupDialogYesNo.cshtml" />
     <Content Include="Views\Shared\_PopupButtonPanelYesNo.cshtml" />
+    <Content Include="Views\Admin\Roles\_RoleEditPartial.cshtml" />
+    <Content Include="Views\Admin\Roles\_RoleGridPartial.cshtml" />
+    <Content Include="Views\Admin\Roles\View.cshtml" />
+    <Content Include="Views\Shared\_PopupButtonPanelOption.cshtml" />
+    <Content Include="Views\Shared\_PopupDialogOption.cshtml" />
     <None Include="Web.Debug.config">
       <DependentUpon>Web.config</DependentUpon>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -252,8 +254,12 @@
     <Compile Include="Global.asax.cs">
       <DependentUpon>Global.asax</DependentUpon>
     </Compile>
+    <Compile Include="Models\Admin\User\RoleDataModel.cs" />
     <Compile Include="Models\Admin\User\UserDataModel.cs" />
-    <Compile Include="Models\Global\DialogModel.cs" />
+    <Compile Include="Models\Global\OptionDialogItemModel.cs" />
+    <Compile Include="Models\Global\YesNoDialogModel.cs" />
+    <Compile Include="Models\Global\OptionDialogModel.cs" />
+    <Compile Include="Validation\Admin\User\RoleDataModelValidator.cs" />
     <Compile Include="Validation\Admin\User\UserDataModelValidator.cs" />
     <Compile Include="Models\Global\FooterModel.cs" />
     <Compile Include="Models\Global\PopupModel.cs" />

+ 59 - 0
GreenTree.Nachtragsmanagement.Web/Models/Admin/User/RoleDataModel.cs

@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Admin.User
+{
+    public class RoleDataModel
+    {
+        public int Id { get; set; }
+        public string Description { get; set; }
+        public int Level { get; set; }
+        public ICollection<int> FunctionValues { get; set; }
+        public ICollection<string> FunctionDescriptions { get; set; }
+
+        public RoleDataModel()
+        {
+            FunctionValues = new List<int>();
+            FunctionDescriptions = new List<string>();
+        }
+
+        public static RoleDataModel FromRole(Core.Domain.User.Role roleEntity, bool newWhenIsNull)
+        {
+            if (roleEntity == null && newWhenIsNull)
+                return new RoleDataModel
+                {
+                    Id = -1
+                };
+
+            if (roleEntity == null && !newWhenIsNull)
+                throw new ArgumentNullException("roleEntity", "Cannot create RoleDataModel from NULL role entity.");
+
+            return new RoleDataModel
+            {
+                Id = roleEntity.Id,
+                Description = roleEntity.Description,
+                Level = roleEntity.Level,
+                FunctionValues =
+                    roleEntity.Functions
+                        .Select(r => r.Id)
+                        .ToList(),
+                FunctionDescriptions =
+                    roleEntity.Functions
+                        .Select(r => r.Description)
+                        .ToList()
+            };
+        }
+
+        public Core.Domain.User.Role ToRole()
+        {
+            return new Core.Domain.User.Role
+            {
+                Id = this.Id,
+                Description  = this.Description,
+                Level = this.Level
+            };
+        }
+    }
+}

+ 3 - 3
GreenTree.Nachtragsmanagement.Web/Models/Admin/User/UserDataModel.cs

@@ -26,15 +26,15 @@ namespace GreenTree.Nachtragsmanagement.Web.Models.Admin.User
             RoleDescriptions = new List<string>();
         }
 
-        public static UserDataModel FromUser(Core.Domain.User.User userEntity, bool newWhenUserIsNull)
+        public static UserDataModel FromUser(Core.Domain.User.User userEntity, bool newWhenIsNull)
         {
-            if (userEntity == null && newWhenUserIsNull)
+            if (userEntity == null && newWhenIsNull)
                 return new UserDataModel
                 {
                     Id = -1
                 };
 
-            if (userEntity == null && !newWhenUserIsNull)
+            if (userEntity == null && !newWhenIsNull)
                 throw new ArgumentNullException("userEntity", "Cannot create UserDataModel from NULL user entity.");
 
             return new UserDataModel

+ 14 - 0
GreenTree.Nachtragsmanagement.Web/Models/Global/OptionDialogItemModel.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Global
+{
+    public class OptionDialogItemModel
+    {
+        public string Name { get; set; }
+        public string Text { get; set; }
+        public string Function { get; set; }
+    }
+}

+ 15 - 0
GreenTree.Nachtragsmanagement.Web/Models/Global/OptionDialogModel.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Models.Global
+{
+    public class OptionDialogModel
+    {
+        public string PopupName { get; set; }
+        public string HeaderText { get; set; }
+        public string Content { get; set; }
+        public List<OptionDialogItemModel> OptionItems { get; set; }
+    }
+}

+ 0 - 0
GreenTree.Nachtragsmanagement.Web/Models/Global/DialogModel.cs → GreenTree.Nachtragsmanagement.Web/Models/Global/YesNoDialogModel.cs


+ 25 - 0
GreenTree.Nachtragsmanagement.Web/Validation/Admin/User/RoleDataModelValidator.cs

@@ -0,0 +1,25 @@
+using FluentValidation;
+using GreenTree.Nachtragsmanagement.Web.Models.Admin.User;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace GreenTree.Nachtragsmanagement.Web.Validation.Admin.User
+{
+    public class RoleDataModelValidator : AbstractValidator<RoleDataModel>
+    {
+        public RoleDataModelValidator()
+        {
+            RuleFor(m => m.Description)
+                .NotEmpty()
+                    .WithMessage("Name wird benötigt")
+                .MaximumLength(50)
+                    .WithMessage("Muss unter 50 Zeichen sein");
+
+            RuleFor(m => m.Level)
+                .GreaterThanOrEqualTo(0)
+                    .WithMessage("Stufe muss größer oder gleich 0 sein.");
+        }
+    }
+}

+ 1 - 0
GreenTree.Nachtragsmanagement.Web/Validation/AppendixValidatorFactory.cs

@@ -15,6 +15,7 @@ namespace GreenTree.Nachtragsmanagement.Web.Validation
         static AppendixValidatorFactory()
         {
             validators.Add(typeof(IValidator<UserDataModel>), new UserDataModelValidator());
+            validators.Add(typeof(IValidator<RoleDataModel>), new RoleDataModelValidator());
         }
 
         public override IValidator CreateInstance(Type validatorType)

+ 174 - 3
GreenTree.Nachtragsmanagement.Web/Views/Admin/Roles/View.cshtml

@@ -1,3 +1,174 @@
-@{
-    Layout = "~/Views/Shared/_FunctionLayout.cshtml";
-}
+@using GreenTree.Nachtragsmanagement.Web.Models.Global;
+
+@{
+	Layout = "~/Views/Shared/_FunctionLayout.cshtml";
+}
+
+@model IEnumerable<GreenTree.Nachtragsmanagement.Web.Models.Admin.User.RoleDataModel>
+
+<script>
+	var deleteId;
+	var deleteReplaceId = -1;
+
+	function saveRole() {
+		var form = $("#roleEditForm");
+		$(form).submit(function (e) {
+			$.ajax({
+				type: "POST",
+				url: '@Url.Action("EditRole", "Admin")',
+				data: form.serialize(),
+				success: function (response) {
+					setTimeout(function () {
+						$(".roleEditContainer").remove();
+						if (response == "success") {
+							devGridViewRole.PerformCallback();
+						} else {
+							$("body").append(response);
+						}
+					}, 200);
+				}
+			});
+			e.preventDefault();
+		});
+		form.submit();
+	}
+
+	function editRole(id) {
+		if (!id) return;
+		$.ajax({
+			url: '@Url.Action("EditRole", "Admin")',
+			data: { id: id },
+			success: function (response) {
+				setTimeout(function () {
+					$(".roleEditContainer").remove();
+					$("body").append(response);
+				}, 200);
+			},
+			error: function () {
+				 alert("error occured");
+			}
+		});
+	}
+
+	function confirmDelete(id) {
+		if (!id) return;
+		deleteId = id;
+		$.ajax({
+			type: "GET",
+			url: '@Url.Action("GetRole", "Admin")',
+			data: { id: deleteId },
+			success: function (response) {
+				if (response == "notFound") return;
+				var role = JSON.parse(response);
+				var comboBox = MVCxClientComboBox.Cast(devComboBoxRoleDeleteReplaceRole);
+				var lastDisplayIndex = -1;
+				for (var i = 0; i < comboBox.GetItemCount(); i++) {
+					comboBox.RemoveItemCssClass(i, "devExDisplayHidden");
+					comboBox.RemoveItemCssClass(i, "devExDisplayTableRow");
+					if (comboBox.GetItem(i).value == deleteId) {
+						comboBox.AddItemCssClass(i, "devExDisplayHidden");
+					} else {
+						lastDisplayIndex = i;
+						comboBox.AddItemCssClass(i, "devExDisplayTableRow");
+					}
+				}
+				comboBox.SetSelectedIndex(lastDisplayIndex);
+				var popupControl = MVCxClientPopupControl.Cast(devPopupControlDeleteRole);
+				popupControl.SetHeaderText(popupControl.GetHeaderText().replace("{role}", role.Description));
+				$(".dialogText").text($(".dialogText").text().replace("{role}", role.Description));
+				popupControl.Show();
+			}
+		});
+	}
+
+	function deleteRole() {
+		if (devRadioButtonDeleteReplaceRole.GetChecked()) {
+			deleteReplaceId = devComboBoxRoleDeleteReplaceRole.GetValue();
+		} else {
+			deleteReplaceId = -1;
+		}
+		$.ajax({
+			type: "POST",
+			url: '@Url.Action("DeleteRole", "Admin")',
+			data: { id: deleteId, replaceId: deleteReplaceId },
+			success: function (response) {
+				var popupControl = MVCxClientPopupControl.Cast(devPopupControlDeleteRole);
+				popupControl.Hide();
+				setTimeout(function () {
+					devGridViewRole.PerformCallback();
+				}, 200);
+			},
+			error: function () {
+				 alert("error occured");
+			}
+		});
+	}
+</script>
+
+@Html.DevExpress().PopupControl(s =>
+{
+	s.Name = "devPopupControlDeleteRole";
+	s.HeaderText = "\"{role}\" löschen";
+	s.Modal = false;
+	s.Width = new Unit(350, UnitType.Pixel);
+	s.CloseAction = CloseAction.CloseButton;
+	s.PopupHorizontalAlign = PopupHorizontalAlign.WindowCenter;
+	s.PopupVerticalAlign = PopupVerticalAlign.WindowCenter;
+	s.AllowDragging = false;
+	s.AllowResize = false;
+	s.ShowFooter = false;
+	s.SetContent(() =>
+	{
+		ViewContext.Writer.Write("<div class='dialogText' style='padding: 12px'>");
+		ViewContext.Writer.Write("Falls Sie \"{role}\" löschen möchten, was soll mit den Benutzern geschehen, die sich bereits in dieser Rolle befinden?");
+		ViewContext.Writer.Write("</div>");
+
+		ViewContext.Writer.Write("<div style='padding: 0 12px 12px 12px'>");
+		Html.DevExpress().RadioButton(rb =>
+		{
+			rb.Name = "devRadioButtonDeleteReplaceRole";
+			rb.Text = "Eine neue Rolle zuweisen";
+			rb.GroupName = "roleDelete";
+			rb.Properties.ClientSideEvents.CheckedChanged =
+				"function (s, e) { " +
+					"devComboBoxRoleDeleteReplaceRole.SetEnabled(s.GetChecked()); " +
+				"}";
+		}).Render();
+
+		Html.DevExpress().ComboBox(cb =>
+		{
+			cb.Name = "devComboBoxRoleDeleteReplaceRole";
+			cb.Width = new Unit(100, UnitType.Percentage);
+			cb.Properties.ValueType = typeof(int);
+			cb.Properties.ValueField = "Id";
+			cb.Properties.TextField = "Description";
+			cb.SelectedIndex = 0;
+			cb.ClientEnabled = false;
+		}).BindList(ViewData["AllRoles"]).Render();
+
+		Html.DevExpress().RadioButton(rb =>
+		{
+			rb.Name = "devRadioButtonDeleteRemoveRole";
+			rb.Text = "Benutzer aus der Rolle entfernen";
+			rb.GroupName = "roleDelete";
+			rb.Checked = true;
+			rb.Properties.ClientSideEvents.CheckedChanged =
+				"function (s, e) { " +
+					"devComboBoxRoleDeleteReplaceRole.SetEnabled(!s.GetChecked()); " +
+				"}";
+		}).Render();
+		ViewContext.Writer.Write("</div>");
+
+		Html.RenderPartial(
+			"~/Views/Shared/_PopupButtonPanelYesNo.cshtml",
+			new YesNoDialogModel
+			{
+				PopupName = "devPopupControlDeleteRole",
+				YesFunction = "function (s, e) { deleteRole(); }"
+			}
+		);
+	});
+	s.Styles.Content.Paddings.Padding = new Unit(0, UnitType.Pixel);
+}).GetHtml()
+
+@Html.Partial("~/Views/Admin/Roles/_RoleGridPartial.cshtml", Model)

+ 140 - 0
GreenTree.Nachtragsmanagement.Web/Views/Admin/Roles/_RoleEditPartial.cshtml

@@ -0,0 +1,140 @@
+@using GreenTree.Nachtragsmanagement.Core.Domain.User;
+@using GreenTree.Nachtragsmanagement.Web.Extensions
+@using GreenTree.Nachtragsmanagement.Web.Framework.Extension.DevExpress;
+
+@model GreenTree.Nachtragsmanagement.Web.Models.Admin.User.RoleDataModel
+
+<div class="roleEditContainer">
+
+<script>
+	var textSeparator = ", ";
+	var checkedNodesText = "";
+	var checkedNodesCounter = 0;
+
+	function synchronizeTreeViewValues(s, e) {
+		var treeView = MVCxClientTreeView.Cast(s);
+		var node = treeView.GetNodeByName(e.node.name);
+		if (node.GetChecked()) {
+			while (node) {
+				node.SetChecked(true);
+				if (node.parent) {
+					node = treeView.GetNodeByName(node.parent.name);
+				} else {
+					node = null;
+				}
+			}
+		}
+		checkedNodesText = "";
+		checkedNodesCounter = 0;
+
+		$("#roleEditForm").children(".hiddenRoleVal").remove();
+		getCheckedNodesText(treeView.GetRootNode());
+		devDropDownListFunctionValues.SetText(checkedNodesText.substr(0, checkedNodesText.length - textSeparator.length));
+	}
+
+	function getCheckedNodesText(parent) {
+		for (var i = 0; i < parent.GetNodeCount(); i++) {
+			if (parent.GetNode(i).GetChecked()) {
+				checkedNodesText = checkedNodesText + parent.GetNode(i).GetText() + textSeparator;
+				$("#roleEditForm").append('<input class="hiddenRoleVal" type="hidden" name="FunctionValues[' + checkedNodesCounter + ']" value="' + parent.GetNode(i).name + '" />');
+				checkedNodesCounter++;
+			}
+			if (parent.GetNode(i).GetNodeCount() != 0) {
+				getCheckedNodesText(parent.GetNode(i));
+			}
+		}
+	}
+</script>
+
+	@Html.DevExpress().PopupControl(s =>
+{
+	s.Name = "devPopupControlEditRole";
+
+	if (Model.Id == -1)
+		s.HeaderText = "Neue Rolle erstellen";
+	else
+		s.HeaderText = "\"" + Model.Description + "\" bearbeiten";
+
+	s.Modal = true;
+	s.Width = new Unit(400, UnitType.Pixel);
+	s.CloseAction = CloseAction.CloseButton;
+	s.PopupHorizontalAlign = PopupHorizontalAlign.WindowCenter;
+	s.PopupVerticalAlign = PopupVerticalAlign.TopSides;
+	s.PopupVerticalOffset = 10;
+	s.AllowDragging = false;
+	s.AllowResize = false;
+	s.ShowFooter = false;
+	s.ShowOnPageLoad = true;
+	s.SetContent(() =>
+	{
+		using (Html.BeginForm("EditRole", "Admin", FormMethod.Post, new { id = "roleEditForm" }))
+		{
+			ViewContext.Writer.Write("<div class='editFormWrapper'>");
+
+			ViewContext.Writer.Write("<input type=\"hidden\" value=\"" + Model.Id + "\" id=\"Id\" name=\"Id\" />");
+
+			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.FunctionValues, "Funktionen:"));
+			ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.FunctionValues).ToHtmlString());
+			Html.DevExpress().DropDownEdit(t =>
+			{
+				t.Name = "devDropDownListFunctionValues";
+				t.Width = new Unit(100, UnitType.Percentage);
+
+				if (Model.FunctionDescriptions != null && Model.FunctionDescriptions.Any())
+					t.Text = String.Join(", ", Model.FunctionDescriptions);
+
+				t.SetDropDownWindowTemplateContent(l =>
+				{
+					ViewContext.Writer.Write("<div style='width: auto; overflow: auto; max-height: 200px'>");
+					Html.DevExpress().TreeView(tv =>
+					{
+						var allFunctions = ViewData["AllFunctions"] as IList<Function>;
+
+						tv.Name = "devTreeViewFunctionValues";
+						tv.AllowCheckNodes = true;
+
+						tv.CreateGroupedFunctionList(allFunctions);
+
+						foreach (var checkedFunction in Model.FunctionValues)
+						{
+							tv.Nodes.FindRecursive(n => n.Name == checkedFunction.ToString()).Checked = true;
+						}
+
+						tv.ClientSideEvents.CheckedChanged = "function (s, e) { synchronizeTreeViewValues(s, e); }";
+					}).Render();
+					ViewContext.Writer.Write("</div>");
+				});
+			}).Render();
+
+			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Description, "Beschreibung:"));
+			ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Description).ToHtmlString());
+			Html.DevExpress().TextBoxFor(m => m.Description, t =>
+			{
+				t.Width = new Unit(100, UnitType.Percentage);
+			}).Render();
+
+			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Level, "Stufe:"));
+			ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Level).ToHtmlString());
+			Html.DevExpress().SpinEditFor(m => m.Level, t =>
+			{
+				t.Width = new Unit(60, UnitType.Percentage);
+				t.Properties.NumberType = SpinEditNumberType.Integer;
+				t.Properties.MinValue = 0;
+			}).Render();
+
+			ViewContext.Writer.Write("</div>");
+
+			Html.RenderPartial(
+				"~/Views/Shared/_PopupButtonPanel.cshtml",
+				new GreenTree.Nachtragsmanagement.Web.Models.Global.PopupModel
+				{
+					PopupName = "devPopupControlEditRole",
+					AcceptFunction = "function (s, e) { saveRole(); }"
+				}
+			);
+		}
+	});
+	s.Styles.Content.Paddings.Padding = new Unit(0);
+	s.Styles.ModalBackground.Opacity = 0;
+}).GetHtml()
+</div>

+ 65 - 0
GreenTree.Nachtragsmanagement.Web/Views/Admin/Roles/_RoleGridPartial.cshtml

@@ -0,0 +1,65 @@
+@model IEnumerable<GreenTree.Nachtragsmanagement.Web.Models.Admin.User.RoleDataModel>
+
+@{ 
+	var userContext = GreenTree.Nachtragsmanagement.Core.CommonHelper.UserContext();
+}
+
+@Html.DevExpress().GridView(s =>
+{
+	s.Name = "devGridViewRole";
+	s.KeyFieldName = "Id";
+	s.CallbackRouteValues = new { Controller = "Admin", Action = "PartialRoles" };
+	s.Width = Unit.Percentage(100);
+
+	if (userContext.CurrentUser.HasFunction("Administration-Roles-Edit"))
+	{
+		s.Columns.Add(column =>
+		{
+			column.Caption = "#";
+			column.SetDataItemTemplateContent(c =>
+			{
+				ViewContext.Writer.Write(
+					"<a href=\"#\" onclick=\"editRole(" + DataBinder.Eval(c.DataItem, "Id") + ")\">Bearbeiten</a>&nbsp;" +
+					"<a href=\"#\" onclick=\"confirmDelete(" + DataBinder.Eval(c.DataItem, "Id") + ")\">Löschen</a>"
+				);
+			});
+			column.SetHeaderTemplateContent(c =>
+			{
+				ViewContext.Writer.Write(
+					"<a href=\"#\" onclick=\"editRole(-1)\">Neu</a>&nbsp;");
+			});
+			column.Settings.AllowDragDrop = DefaultBoolean.False;
+			column.Settings.AllowSort = DefaultBoolean.False;
+			column.Width = 70;
+		});
+	}
+	s.Columns.Add("Description", "Beschreibung");
+	s.Columns.Add("Level", "Stufe");
+	s.Columns.Add(column =>
+	{
+		column.Caption = "Funktionen";
+
+		column.SetDataItemTemplateContent(r =>
+		{
+			var modelItem = Model
+				.ElementAt(r.ItemIndex).FunctionDescriptions;
+
+			ViewContext.Writer.Write(
+				String.Join(", ", String.Join(", ", modelItem))
+			);
+		});
+	});
+
+	s.ClientLayout = (sender, e) =>
+	{
+		if (e.LayoutMode == ClientLayoutMode.Loading)
+		{
+			if (Session["RoleGridState"] != null)
+				e.LayoutData = (string)Session["RoleGridState"];
+		}
+		else
+			Session["RoleGridState"] = e.LayoutData;
+	};
+
+	s.Styles.AlternatingRow.BackColor = System.Drawing.Color.FromArgb(247, 247, 247);
+}).Bind(Model).GetHtml()

+ 2 - 2
GreenTree.Nachtragsmanagement.Web/Views/Admin/Users/View.cshtml

@@ -53,7 +53,7 @@
 		$.ajax({
 			type: "GET",
 			url: '@Url.Action("GetUser", "Admin")',
-			data: { Id: deleteId },
+			data: { Id: id },
 			success: function (response) {
 				if (response == "notFound") return;
 				var user = JSON.parse(response);
@@ -85,7 +85,7 @@
 </script>
 
 @Html.Partial("~/Views/Admin/Users/_UserGridPartial.cshtml", Model)
-@Html.Partial("~/Views/Shared/_PopupDialog.cshtml", new GreenTree.Nachtragsmanagement.Web.Models.Global.YesNoDialogModel
+@Html.Partial("~/Views/Shared/_PopupDialogYesNo.cshtml", new GreenTree.Nachtragsmanagement.Web.Models.Global.YesNoDialogModel
 {
 	PopupName = "devPopupControlDeleteUser",
 	Content = "<div class='dialogText' style='padding: 12px'>Sind Sie sicher, dass Sie den Benutzer \"{user}\" löschen möchten?</div>",

+ 1 - 1
GreenTree.Nachtragsmanagement.Web/Views/Admin/Users/_UserEditPartial.cshtml

@@ -111,7 +111,7 @@
 				t.Width = new Unit(100, UnitType.Percentage);
 			}).Render();
 
-			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.MailAddress, "Passwort:"));
+			ViewContext.Writer.Write(Html.CustomLabelFor(m => m.Password, "Passwort:"));
 			ViewContext.Writer.Write(Html.ValidationMessageFor(m => m.Password).ToHtmlString());
 			Html.DevExpress().TextBoxFor(m => m.Password, t =>
 			{

+ 23 - 16
GreenTree.Nachtragsmanagement.Web/Views/Admin/Users/_UserGridPartial.cshtml

@@ -1,5 +1,9 @@
 @model IEnumerable<GreenTree.Nachtragsmanagement.Web.Models.Admin.User.UserDataModel>
 
+@{ 
+	var userContext = GreenTree.Nachtragsmanagement.Core.CommonHelper.UserContext();
+}
+
 @Html.DevExpress().GridView(s =>
 {
 	s.Name = "devGridViewUser";
@@ -7,25 +11,28 @@
 	s.CallbackRouteValues = new { Controller = "Admin", Action = "PartialUsers" };
 	s.Width = Unit.Percentage(100);
 
-	s.Columns.Add(column =>
+	if (userContext.CurrentUser.HasFunction("Administration-Users-Edit"))
 	{
-		column.Caption = "#";
-		column.SetDataItemTemplateContent(c =>
-		{
-			ViewContext.Writer.Write(
-				"<a href=\"#\" onclick=\"editUser(" + DataBinder.Eval(c.DataItem, "Id") + ")\">Bearbeiten</a>&nbsp;" +
-				"<a href=\"#\" onclick=\"confirmDelete(" + DataBinder.Eval(c.DataItem, "Id") + ")\">Löschen</a>"
-			);
-		});
-		column.SetHeaderTemplateContent(c =>
+		s.Columns.Add(column =>
 		{
-			ViewContext.Writer.Write(
-				"<a href=\"#\" onclick=\"editUser(-1)\">Neu</a>&nbsp;");
+			column.Caption = "#";
+			column.SetDataItemTemplateContent(c =>
+			{
+				ViewContext.Writer.Write(
+					"<a href=\"#\" onclick=\"editUser(" + DataBinder.Eval(c.DataItem, "Id") + ")\">Bearbeiten</a>&nbsp;" +
+					"<a href=\"#\" onclick=\"confirmDelete(" + DataBinder.Eval(c.DataItem, "Id") + ")\">Löschen</a>"
+				);
+			});
+			column.SetHeaderTemplateContent(c =>
+			{
+				ViewContext.Writer.Write(
+					"<a href=\"#\" onclick=\"editUser(-1)\">Neu</a>&nbsp;");
+			});
+			column.Settings.AllowDragDrop = DefaultBoolean.False;
+			column.Settings.AllowSort = DefaultBoolean.False;
+			column.Width = 70;
 		});
-		column.Settings.AllowDragDrop = DefaultBoolean.False;
-		column.Settings.AllowSort = DefaultBoolean.False;
-		column.Width = 70;
-	});
+	}
 	s.Columns.Add("Forename", "Vorname");
 	s.Columns.Add("Lastname", "Nachname");
 	s.Columns.Add("MailAddress", "Mail-Adresse");

+ 0 - 55
GreenTree.Nachtragsmanagement.Web/Views/Home/Plugins.cshtml

@@ -1,55 +0,0 @@
-@{
-    ViewBag.Title = "Plugins";
-    Layout = "~/Views/Shared/_Layout.cshtml";
-}
-
-@model GreenTree.Nachtragsmanagement.Web.Models.Test.PluginModel
-
-@Html.Partial("~/Views/Shared/_HeaderNavBar.cshtml")
-
-<h2>Plugins</h2>
-
-<div style="width: auto; padding-top: 8px; border-top: 1px solid black">
-	<table>
-		<tbody>
-			@if (Model.PluginNames.Any())
-			{
-				foreach (var plugin in Model.PluginNames)
-				{
-					if (plugin[1] == "uninstalled")
-					{
-						<tr>
-							<td>@plugin[0]</td>
-							<td>
-								@using (Html.BeginForm("InstallPlugin", "Home", FormMethod.Post))
-								{
-									@Html.Hidden("pluginName", plugin[0])
-									<input type="submit" value="Installieren" />
-								}
-							</td>
-						</tr>
-					}
-					else
-					{
-						<tr>
-							<td>@plugin[0]</td>
-							<td>
-								@using (Html.BeginForm("UninstallPlugin", "Home", FormMethod.Post))
-								{
-									@Html.Hidden("pluginName", plugin[0])
-									<input type="submit" value="Deinstallieren" />
-								}
-							</td>
-						</tr>
-					}
-				}
-			}
-			else
-			{
-				<tr>
-					<td>Keine Plugins gefunden!</td>
-				</tr>
-			}
-		</tbody>
-	</table>
-</div>

+ 0 - 29
GreenTree.Nachtragsmanagement.Web/Views/Home/Relations.cshtml

@@ -1,29 +0,0 @@
-@{
-    ViewBag.Title = "Relationen";
-    Layout = "~/Views/Shared/_Layout.cshtml";
-}
-
-@model GreenTree.Nachtragsmanagement.Web.Models.Test.DbRelationModel
-
-@Html.Partial("~/Views/Shared/_HeaderNavBar.cshtml")
-
-<h2>Datenbank - Relationen</h2>
-
-<div style="width: auto; padding-top: 8px; border-top: 1px solid black">
-	<div style="float: left">
-		<h6>Users:</h6>
-		@Html.TextAreaFor(m => m.UserJson, new { rows = 50, cols = 60 })
-	</div>
-	<div style="float: left">
-		<h6>Deviations:</h6>
-		@Html.TextAreaFor(m => m.DeviationJson, new { rows = 50, cols = 60 })
-	</div>
-	<div style="float: left">
-		<h6>Sites:</h6>
-		@Html.TextAreaFor(m => m.SiteJson, new { rows = 50, cols = 60 })
-	</div>
-	<div style="float: left">
-		<h6>Appendices:</h6>
-		@Html.TextAreaFor(m => m.AppendixJson, new { rows = 50, cols = 60 })
-	</div>
-</div>

+ 15 - 0
GreenTree.Nachtragsmanagement.Web/Views/Shared/_PopupButtonPanelOption.cshtml

@@ -0,0 +1,15 @@
+@model GreenTree.Nachtragsmanagement.Web.Models.Global.OptionDialogModel
+
+<div class="popupButtonPanel">
+	@foreach (var optionItem in Model.OptionItems)
+	{
+		Html.DevExpress().Button(b =>
+		{
+			b.Name = "devButtonDialog_" + optionItem.Name;
+			b.Text = optionItem.Text;
+			b.ControlStyle.CssClass += "devExFloatRight devExPopupPanelButton";
+			b.UseSubmitBehavior = false;
+			b.ClientSideEvents.Click = optionItem.Function;
+		}).GetHtml();
+	}
+</div>

+ 25 - 0
GreenTree.Nachtragsmanagement.Web/Views/Shared/_PopupDialogOption.cshtml

@@ -0,0 +1,25 @@
+@model GreenTree.Nachtragsmanagement.Web.Models.Global.OptionDialogModel
+
+@Html.DevExpress().PopupControl(s =>
+{
+	s.Name = Model.PopupName;
+	s.HeaderText = Model.HeaderText;
+	s.Modal = false;
+	s.Width = new Unit(450, UnitType.Pixel);
+	s.CloseAction = CloseAction.CloseButton;
+	s.PopupHorizontalAlign = PopupHorizontalAlign.WindowCenter;
+	s.PopupVerticalAlign = PopupVerticalAlign.WindowCenter;
+	s.AllowDragging = false;
+	s.AllowResize = false;
+	s.ShowFooter = false;
+	s.SetContent(() =>
+	{
+		ViewContext.Writer.Write(Model.Content);
+
+		Html.RenderPartial(
+			"~/Views/Shared/_PopupButtonPanelOption.cshtml",
+			Model
+		);
+	});
+	s.Styles.Content.Paddings.Padding = new Unit(0, UnitType.Pixel);
+}).GetHtml()

+ 0 - 0
GreenTree.Nachtragsmanagement.Web/Views/Shared/_PopupDialog.cshtml → GreenTree.Nachtragsmanagement.Web/Views/Shared/_PopupDialogYesNo.cshtml