using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using Newtonsoft.Json; using GreenTree.Nachtragsmanagement.Core.Authentication; using GreenTree.Nachtragsmanagement.Services.User; using GreenTree.Nachtragsmanagement.Web.Models.Admin.User; using GreenTree.Nachtragsmanagement.Core.Domain.User; using GreenTree.Nachtragsmanagement.Core; using GreenTree.Nachtragsmanagement.Core.Plugins; using GreenTree.Nachtragsmanagement.Web.Framework.Authorization; using GreenTree.Nachtragsmanagement.Services.Logging; using GreenTree.Nachtragsmanagement.Web.Models.Admin.Plugins; using GreenTree.Nachtragsmanagement.Web.Models.Admin.AppInfo; using System.Reflection; using System.Net; using System.IO; using GreenTree.Nachtragsmanagement.Services.Configuration; using GreenTree.Nachtragsmanagement.Web.Extensions; using System.IO.Compression; namespace GreenTree.Nachtragsmanagement.Web.Controllers { public class AdminController : Controller { private readonly IUserService _userService; private readonly IUserHelper _userHelper; private readonly IPluginFinder _pluginFinder; private readonly ILogger _logger; private readonly IWebHelper _webHelper; private readonly IConfigurationService _configurationService; public AdminController( IUserService userService, IUserHelper userHelper, IPluginFinder pluginFinder, ILogger logger, IWebHelper webHelper, IConfigurationService configurationService) { _userService = userService; _userHelper = userHelper; _pluginFinder = pluginFinder; _logger = logger; _webHelper = webHelper; _configurationService = configurationService; ViewData["AllRoles"] = _userService.GetAllRoles(); ViewData["AllFunctions"] = _userService.GetAllFunctions(); } #region Users /// /// Basic user view function /// [FunctionAuthorize(true, "Administration-Users")] public ActionResult ViewUsers() { var users = _userService.GetAllUsers(); var userModels = users .Select(u => UserDataModel.FromUser(u, false)) .ToList(); return View("~/Views/Admin/Users/View.cshtml", userModels); } /// /// Get JSON data of specific user /// /// User id. public ActionResult GetUser(int id = -1) { var user = _userService.GetUserById(id); if (user == null) return new JsonResult { Data = "notFound", JsonRequestBehavior = JsonRequestBehavior.AllowGet }; var userModel = UserDataModel.FromUser(user, false); return new JsonResult { Data = JsonConvert.SerializeObject(userModel), JsonRequestBehavior = JsonRequestBehavior.AllowGet }; } /// /// Partial edit for searching for users in ActiveDirectory /// /// The text to be searched for. [HttpPost] public ActionResult SearchUsers(string searchValue) { var users = _userService.SearchUsers(searchValue); return PartialView("~/Views/Admin/Users/_UserSearchPartial.cshtml", users); } /// /// Partial edit for selecting a specific user /// /// The user accountName. [HttpPost] public ActionResult SelectUser(string accountName) { var user = _userService.SearchUsers(accountName) .FirstOrDefault(); if (user == null) return new EmptyResult(); return new JsonResult { Data = user }; } /// /// Callback result for user grid /// /// The height of the grid scrollable component. public ActionResult PartialUsers(int scrollHeight = -1) { var users = _userService.GetAllUsers(); var userModels = users .Select(u => UserDataModel.FromUser(u, false)) .ToList(); ViewData["ScrollHeight"] = scrollHeight; return PartialView("~/Views/Admin/Users/_UserGridPartial.cshtml", userModels); } /// /// Partial edit for editing of existing or for new user /// /// Id for existing user, otherweise -1. public ActionResult EditUser(int id = -1) { var user = _userService.GetUserById(id); var userModel = UserDataModel.FromUser(user, true); return PartialView("~/Views/Admin/Users/_UserEditPartial.cshtml", userModel); } /// /// Partial edit result if ModelState is valid, otherwise simple JSON result for success /// /// User model to be saved. [HttpPost, ValidateInput(false)] public ActionResult EditUser(UserDataModel userModel) { try { if (!ModelState.IsValid) { foreach (var role in userModel.RoleValues) userModel.RoleDescriptions.Add( ((IList)ViewData["AllRoles"]) .First(r => r.Id == role).Description); return PartialView("~/Views/Admin/Users/_UserEditPartial.cshtml", userModel); } var selectedRoles = _userService.GetRolesByIds(userModel.RoleValues.ToArray()); if (userModel.Id == -1) { var user = userModel.ToUser(); user.SetRoles(selectedRoles); user.Password = StaticHelper.GetMD5Hash(userModel.Password); _userService.InsertUser(user); _logger.Entity(user, Core.Domain.Logging.LogEntityActivity.Insert, _userHelper.FromCookiesOrSession()); } else { var user = _userService.GetUserById(userModel.Id); user.CustomNumber = userModel.CustomNumber; user.Forename = userModel.Forename; user.Lastname = userModel.Lastname; user.MailAddress = userModel.MailAddress; if (!String.IsNullOrEmpty(userModel.Password)) user.Password = StaticHelper.GetMD5Hash(userModel.Password); user.SetRoles(selectedRoles); _userService.UpdateUser(user); _logger.Entity(user, Core.Domain.Logging.LogEntityActivity.Update, _userHelper.FromCookiesOrSession()); } return new JsonResult { Data = "success" }; } catch (Exception ex) { _logger.Error("Fehler bei Speicherung eines Benutzers.", ex, _userHelper.FromCookiesOrSession()); return PartialView("~/Views/Shared/_PopupError.cshtml", ex); } } /// /// Simple JSON result for deleting a specific user /// /// User id. [HttpPost] public ActionResult DeleteUser(int id) { try { var user = _userService.GetUserById(id); if (user != null) _userService.DeleteUser(user); _logger.Entity(user, Core.Domain.Logging.LogEntityActivity.Delete, _userHelper.FromCookiesOrSession()); return new JsonResult { Data = "success" }; } catch (Exception ex) { _logger.Error("Fehler bei Löschung eines Benutzers.", ex, _userHelper.FromCookiesOrSession()); return PartialView("~/Views/Shared/_PopupError.cshtml", ex); } } #endregion #region Roles /// /// Basic role view function /// [FunctionAuthorize(true, "Administration-Roles")] public ActionResult ViewRoles() { var roles = _userService.GetAllRoles(); var roleModels = roles .Select(r => RoleDataModel.FromRole(r, false)) .ToList(); return View("~/Views/Admin/Roles/View.cshtml", roleModels); } /// /// Get JSON data of specific role /// /// Role id. public ActionResult GetRole(int id = -1) { var role = _userService.GetRoleById(id); if (role == null) return new JsonResult { Data = "notFound", JsonRequestBehavior = JsonRequestBehavior.AllowGet }; var roleModel = RoleDataModel.FromRole(role, false); return new JsonResult { Data = JsonConvert.SerializeObject(roleModel), JsonRequestBehavior = JsonRequestBehavior.AllowGet }; } /// /// Callback result for role grid /// /// The height of the grid scrollable component. public ActionResult PartialRoles(int scrollHeight = -1) { var roles = _userService.GetAllRoles(); var roleModels = roles .Select(r => RoleDataModel.FromRole(r, false)) .ToList(); ViewData["ScrollHeight"] = scrollHeight; return PartialView("~/Views/Admin/Roles/_RoleGridPartial.cshtml", roleModels); } /// /// Partial edit for editing of existing or for new role /// /// Id for existing role, otherweise -1. 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); } /// /// Partial edit result if ModelState is valid, otherwise simple JSON result for success /// /// Role model to be saved. [HttpPost, ValidateInput(false)] public ActionResult EditRole(RoleDataModel roleModel) { try { if (!ModelState.IsValid) { foreach (var role in roleModel.FunctionValues) roleModel.FunctionDescriptions.Add( ((IList)ViewData["AllFunctions"]) .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); _logger.Entity(role, Core.Domain.Logging.LogEntityActivity.Insert, _userHelper.FromCookiesOrSession()); } else { var role = _userService.GetRoleById(roleModel.Id); role.Description = roleModel.Description; role.Level = roleModel.Level; role.SetFunctions(selectedFunctions); _userService.UpdateRole(role); _logger.Entity(role, Core.Domain.Logging.LogEntityActivity.Update, _userHelper.FromCookiesOrSession()); } return new JsonResult { Data = "success" }; } catch (Exception ex) { _logger.Error("Fehler bei Speicherung einer Rolle.", ex, _userHelper.FromCookiesOrSession()); return PartialView("~/Views/Shared/_PopupError.cshtml", ex); } } /// /// Simple JSON result for deleting a specific role /// /// Role id. /// Id of role which user get in place of deleting role. [HttpPost] public ActionResult DeleteRole(int id, int replaceId) { try { 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); _logger.Entity(role, Core.Domain.Logging.LogEntityActivity.Delete, _userHelper.FromCookiesOrSession()); return new JsonResult { Data = "success" }; } catch (Exception ex) { _logger.Error("Fehler bei Löschung einer Rolle.", ex, _userHelper.FromCookiesOrSession()); return PartialView("~/Views/Shared/_PopupError.cshtml", ex); } } #endregion #region Plugins /// /// Basic plugin view function /// public ActionResult ViewPlugins() { var plugins = _pluginFinder.GetPlugins(LoadPluginsMode.All); var pluginModels = plugins .Select(p => PluginDataModel.FromPluginDesciptor(p.PluginDescriptor, _webHelper)) .ToList(); return View("~/Views/Admin/Plugins/View.cshtml", pluginModels); } /// /// Callback result for plugin grid /// /// The height of the grid scrollable component. public ActionResult PartialPlugins(int scrollHeight = -1) { var plugins = _pluginFinder.GetPlugins(LoadPluginsMode.All); var pluginModels = plugins .Select(p => PluginDataModel.FromPluginDesciptor(p.PluginDescriptor, _webHelper)) .ToList(); ViewData["ScrollHeight"] = scrollHeight; return View("~/Views/Admin/Plugins/_PluginsGridPartial.cshtml", pluginModels); } /// /// Installs a plugin /// /// SystemName of plugin. [HttpPost] public ActionResult InstallPlugin(string pluginName) { try { var pluginDescriptor = _pluginFinder.GetPluginDescriptorBySystemName(pluginName, LoadPluginsMode.All); if (pluginDescriptor == null) return RedirectToAction("Plugins"); if (pluginDescriptor.Installed) return RedirectToAction("Plugins"); pluginDescriptor.Instance().Install(); _logger.Information(String.Format("Plugin \"{0}\" erfolgreich installiert.", pluginName)); _webHelper.RestartAppDomain(); return new JsonResult { Data = "success" }; } catch (Exception ex) { _logger.Error( String.Format("Fehler bei der Installation des Plugin \"{0}\".", pluginName), ex); return PartialView("~/Views/Shared/_PopupError.cshtml", ex); } } /// /// Uninstalls a plugin /// /// SystemName of plugin. [HttpPost] public ActionResult UninstallPlugin(string pluginName) { try { var pluginDescriptor = _pluginFinder.GetPluginDescriptorBySystemName(pluginName, LoadPluginsMode.All); if (pluginDescriptor == null) return RedirectToAction("Plugins"); if (!pluginDescriptor.Installed) return RedirectToAction("Plugins"); pluginDescriptor.Instance().Uninstall(); _logger.Information(String.Format("Plugin \"{0}\" erfolgreich deinstalliert.", pluginName)); _webHelper.RestartAppDomain(); return new JsonResult { Data = "success" }; } catch (Exception ex) { _logger.Error( String.Format("Fehler bei der Installation des Plugin \"{0}\".", pluginName), ex); return PartialView("~/Views/Shared/_PopupError.cshtml", ex); } } #endregion #region AppInfo /// /// Basic appInfo view function /// public ActionResult ViewAppInfo() { var model = new AppInfoDataModel { BaseDirectory = AppDomain.CurrentDomain.BaseDirectory, IsUpdate = false }; model.GetAssemblies(); return View("~/Views/Admin/AppInfo/View.cshtml", model); } /// /// Basic appInfo view function /// public ActionResult ViewUpdateSuccess() { var model = new AppInfoDataModel { BaseDirectory = AppDomain.CurrentDomain.BaseDirectory, IsUpdate = true }; model.GetAssemblies(); return View("~/Views/Admin/AppInfo/View.cshtml", model); } /// /// Update check /// [HttpPost] public ActionResult CheckUpdate() { _logger.Information("Updateüberprüfung gestartet."); try { var model = new AppUpdateDataModel { Package = "GreenTree.Nachtragsmanagement", CurrentVersion = AppendixVersion.CurrentVersion }; var webResult = String.Empty; using (var wc = new WebClient()) { wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded"; var webData = String.Format("Package={0}&CurrentVersion={1}", model.Package, model.CurrentVersion); webResult = wc.UploadString(_configurationService.GetCurrentConfiguration().CheckUpdateUrl, webData); } var jsonResult = JsonConvert.DeserializeObject(webResult); var result = JsonConvert.DeserializeObject(jsonResult.Data.ToString()); if (result.IsUpdateAvailable) _logger.Information( String.Format( "Es ist ein Update verfügbar (Aktuell: {0} - Neu: {1})!", AppendixVersion.CurrentVersion, result.UpdateVersion)); else _logger.Information("Es kein Update verfügbar!"); return new JsonResult { Data = result }; } catch (Exception ex) { _logger.Error("Fehler bei der Überprüfung eines Updates", ex); throw; } } /// /// Update check /// [HttpPost] public ActionResult Update() { _logger.Information("Update gestartet."); try { var model = new AppUpdateDataModel { Package = "GreenTree.Nachtragsmanagement", CurrentVersion = AppendixVersion.CurrentVersion }; var currentConfig = _configurationService.GetCurrentConfiguration(); AppUpdateDataModel result; string storePath; using (var wc = new WebClient()) { wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded"; var webData = String.Format("Package={0}&CurrentVersion={1}", model.Package, model.CurrentVersion); var webResult = wc.UploadString(currentConfig.CheckUpdateUrl, webData); var jsonResult = JsonConvert.DeserializeObject(webResult); result = JsonConvert.DeserializeObject(jsonResult.Data.ToString()); storePath = Path.Combine(Server.MapPath(currentConfig.UpdateStorePath), result.PackageFilename); if (System.IO.File.Exists(storePath)) System.IO.File.Delete(storePath); wc.DownloadFile(result.PackagePath, storePath); } var hash = HashHelper.GetFileMd5(storePath); if (hash != result.PackageMd5Hash) return null; var archive = ZipFile.Open(storePath, ZipArchiveMode.Read); var applicationPath = Server.MapPath("~/"); archive.ExtractToDirectory(applicationPath, true); _logger.Information("Update erfolgreich durchgeführt - Anwendung wird neu gestartet!"); _webHelper.RestartAppDomain(true, "~/admin/viewupdatesuccess"); return new JsonResult { Data = "success" }; } catch (Exception ex) { _logger.Error("Fehler bei der Durchführung eines Updates", ex); throw; } } #endregion } }