public async Task <IActionResult> Settings() { var config = await ConfigStore.GetConfigAsync(); try { if (TempData["check-settings"] is bool b && b) { // This doesn't check if the access token is valid... var inst = await DiscoveryClient.GetDiscoveryInfo(); // ... but this does. var entities = await EntityClient.GetEntities(); ViewBag.Instance = $"Home Assistant instance: <b>{inst.LocationName} (Version {inst.Version}) [{inst.BaseUrl}]</b>"; } } catch (Exception ex) { await ConfigStore.ManipulateConfig(c => c.Settings.AccessToken = c.Settings.BaseUri = null); config = await ConfigStore.GetConfigAsync(); TempData.Remove(AlertManager.GRP_SUCCESS); Logger.LogError(ex, "Invalid system settings entered, or unable to reach Home Assistant with the specified information."); TempData.AddError("The settings entered are not valid. HACC is unable to reach your Home Assistant instance. Try your entries again, consult the <a target=\"_blank\" href=\"https://github.com/qJake/HADotNet.CommandCenter/wiki/Initial-System-Setup\">setup guide</a> for help, or check the logs (console) for more information."); // Reloads the request showing the error (TempData doesn't commit until a reload). return(RedirectToAction("Settings")); } return(View(config.Settings)); }
public async Task <IActionResult> Settings([FromForm] SystemSettings newSettings) { try { if (ModelState.IsValid) { newSettings ??= new SystemSettings(); newSettings.BaseUri = newSettings.BaseUri?.TrimEnd('/'); newSettings.AccessToken = newSettings.AccessToken?.Trim(); await ConfigStore.ManipulateConfig(c => c.Settings = newSettings); ClientFactory.Reset(); TempData["check-settings"] = true; return(RedirectToAction("Settings")); } } catch (Exception ex) { Logger.LogError(ex, "Saving system settings failed."); TempData.AddError("Unable to save system settings. See log output (console) for more information."); } return(View(newSettings)); }
public async Task <IActionResult> AddPage([FromForm] Page newPage) { if (ModelState.IsValid) { var defaultLayout = (await ConfigStore.GetConfigAsync()).Pages.FirstOrDefault(p => p.IsDefaultPage)?.LayoutSettings; if (newPage.IsDefaultPage) { await ConfigStore.ManipulateConfig(c => c.Pages.ForEach(p => p.IsDefaultPage = false)); } newPage.TileLayout = new List <TileLayout>(); newPage.Tiles = new List <BaseTile>(); newPage.LayoutSettings = new LayoutSettings { BaseTileSizePx = defaultLayout?.BaseTileSizePx ?? 100, TileSpacingPx = defaultLayout?.TileSpacingPx ?? 6, DeviceHeightPx = defaultLayout?.DeviceHeightPx ?? 860, DeviceWidthPx = defaultLayout?.DeviceWidthPx ?? 965 }; await ConfigStore.ManipulateConfig(c => c.Pages.Add(newPage)); TempData.AddSuccess($"Successfully added page '{newPage.Description}'!"); return(RedirectToAction("Index")); } return(View()); }
public async Task <IActionResult> Settings([FromForm] SystemSettings newSettings) { try { if (ModelState.IsValid) { newSettings ??= new SystemSettings(); if (newSettings.IsHassIo) { newSettings.BaseUri = "http://hassio/homeassistant"; } else { newSettings.BaseUri = newSettings.BaseUri.TrimEnd('/'); } await ConfigStore.ManipulateConfig(c => c.Settings = newSettings); TempData["check-settings"] = true; return(RedirectToAction("Settings")); } } catch (Exception ex) { Logger.LogError(ex, "Saving system settings failed."); TempData.AddError("Unable to save system settings. See log output (console) for more information."); } return(View(newSettings)); }
public async Task <IActionResult> ImportTheme([FromForm] IFormFile file) { if (file == null) { TempData.AddWarning("No file was uploaded. Please try again."); return(RedirectToAction("Themes")); } string contents; using (var sr = new StreamReader(file.OpenReadStream())) { contents = await sr.ReadToEndAsync(); } try { var newTheme = JsonConvert.DeserializeObject <Theme>(contents); var config = await ConfigStore.GetConfigAsync(); await ConfigStore.ManipulateConfig(c => c.CurrentTheme = newTheme); TempData.AddSuccess($"Successfully imported theme file '{file.FileName}' successfully! <a href=\"/\">Go check out your dashboard!</a>"); } catch { TempData.AddError("Import file was not a theme file or could not otherwise be imported. Check that the file is not malformed and try again."); } return(RedirectToAction("Themes")); }
public async Task InvokeAsync(HttpContext context) { var config = await ConfigStore.GetConfigAsync(); if (!string.IsNullOrWhiteSpace(config?.Settings?.BaseUri) && (!string.IsNullOrWhiteSpace(config?.Settings?.AccessToken) || !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("HASSIO_TOKEN")))) { if (!ClientFactory.IsInitialized) { if (config.Settings.IsHassIo) { Log.LogInformation($"Auto-initializing HACC via Hass.io addon."); ClientFactory.Initialize(config.Settings.BaseUri, Environment.GetEnvironmentVariable("HASSIO_TOKEN")); } else { Log.LogInformation($"Initializing HACC API with URL {config?.Settings?.BaseUri ?? "[NULL]"} and access token [{new string(config?.Settings?.AccessToken.Take(6).ToArray())}•••••••••••{new string(config?.Settings?.AccessToken.TakeLast(6).ToArray())}]."); ClientFactory.Initialize(config.Settings.BaseUri, config.Settings.AccessToken); } } } else { ClientFactory.Reset(); } if (!ClientFactory.IsInitialized) { // If we're in Hass.io mode, set the base URI and redirect to the admin homepage. if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("HASSIO_TOKEN"))) { await ConfigStore.ManipulateConfig(c => { c.Settings = new SystemSettings { BaseUri = "http://hassio/homeassistant", AccessToken = null, IsHassIo = true }; context.Response.StatusCode = 303; context.Response.Redirect("/admin"); }); } // Otherwise, if we aren't on one of the approved pages, redirect to the settings page and prompt for setup. if (context.Request.Path.ToString().ToLower() != "/admin/settings" && context.Request.Path.ToString().ToLower() != "/admin") { Log.LogInformation($"Client factory is not initialized, redirecting user to settings area..."); context.Response.Redirect("/admin/settings?setup=1"); return; } } await Next(context); }
public async Task <IActionResult> ResetConfig() { await ConfigStore.SaveConfigAsync(new ConfigRoot()); // This will reset defaults and initialize collections, even if no actions are passed in. await ConfigStore.ManipulateConfig(); TempData.AddSuccess("Successfully reset HACC configuration."); return(RedirectToAction("Index")); }
private async Task MigrateLegacyPagesConfig(HttpContext context, ConfigRoot config) { #pragma warning disable CS0612 if ((config.TileLayout?.Count > 0 || config.Tiles?.Count > 0) && (config.Pages?.Count ?? 0) == 0) { await ConfigStore.ManipulateConfig(config => { config.Pages ??= new List <Page>(); config.Pages.Add(new Page { Name = "default", Description = "[Automatically generated from previous configuration.]", IsDefaultPage = true, Tiles = config.Tiles, TileLayout = config.TileLayout, LayoutSettings = config.LayoutSettings }); config.TileLayout = null; config.Tiles = null; config.LayoutSettings = null; }); context.Response.Redirect("/admin/pageMigration"); } else if ((config.Pages?.Count ?? 0) == 0) { await ConfigStore.ManipulateConfig(config => { config.Pages = new List <Page> { new Page { Name = "default", Description = "Default Page", IsDefaultPage = true, Tiles = new List <BaseTile>(), TileLayout = new List <TileLayout>(), LayoutSettings = new LayoutSettings { DeviceHeightPx = 1280, DeviceWidthPx = 720, BaseTileSizePx = 92, TileSpacingPx = 6, } } }; }); } #pragma warning restore CS0612 }
public async Task <IActionResult> UpdateLayoutSettings(LayoutSettings settings) { if (ModelState.IsValid) { TempData.AddSuccess("Saved layout settings successfully!"); await ConfigStore.ManipulateConfig(c => c.LayoutSettings = settings); } else { TempData.AddError("Unable to save layout settings."); } return(RedirectToAction("Layout")); }
public async Task <IActionResult> Settings(SystemSettings newSettings) { if (ModelState.IsValid) { newSettings.BaseUri = newSettings.BaseUri.TrimEnd('/'); await ConfigStore.ManipulateConfig(c => c.Settings = newSettings); TempData.AddSuccess("Saved settings successfully!"); return(RedirectToAction("Settings")); } return(View(newSettings)); }
public async Task <IActionResult> SaveTheme([FromForm] Theme newTheme) { if (ModelState.IsValid) { var config = await ConfigStore.GetConfigAsync(); await ConfigStore.ManipulateConfig(c => c.CurrentTheme = newTheme); TempData.AddSuccess("Saved theme settings successfully!"); return(RedirectToAction("Themes")); } return(View("Themes", newTheme)); }
public async Task <IActionResult> ImportConfig([FromForm] IFormFile file) { try { if (file == null) { TempData.AddWarning("No file was uploaded. Please try again."); return(RedirectToAction("Index")); } string contents; using (var sr = new StreamReader(file.OpenReadStream())) { contents = await sr.ReadToEndAsync(); } try { var newConfig = JsonConvert.DeserializeObject <ConfigRoot>(contents); newConfig.Settings = null; var config = await ConfigStore.GetConfigAsync(); var oldSettings = config.Settings; newConfig.Settings = oldSettings; await ConfigStore.SaveConfigAsync(newConfig); // Ensures arrays are non-null even if no actions are performed. await ConfigStore.ManipulateConfig(); TempData.AddSuccess($"Successfully imported system configuration file '{file.FileName}'!"); } catch { Logger.LogWarning("File selected was not able to be parsed into a config object. Check file contents and try again."); TempData.AddError("Import file was not a configuration file or could not otherwise be imported. Check that the file is not malformed and try again."); } } catch (Exception ex) { Logger.LogError(ex, "Importing system config settings failed."); TempData.AddError("Unable to import system configuration. See log output (console) for more information."); } return(RedirectToAction("Index")); }
public async Task <IActionResult> EditPage([FromForm] Page page) { if (ModelState.IsValid) { if (page.IsDefaultPage) { await ConfigStore.ManipulateConfig(c => c.Pages.ForEach(p => p.IsDefaultPage = false)); } await ConfigStore.ManipulateConfig(c => { c[page.Name].Description = page.Description; c[page.Name].IsDefaultPage = page.IsDefaultPage; c[page.Name].AutoReturnSeconds = page.AutoReturnSeconds; }); TempData.AddSuccess($"Successfully edited page '{page.Description}'!"); return(RedirectToAction("Index")); } return(View(page)); }
public async Task <IActionResult> ImportTheme([FromForm] IFormFile file) { try { if (file == null) { TempData.AddWarning("No file was uploaded. Please try again."); return(RedirectToAction("Themes")); } string contents; using (var sr = new StreamReader(file.OpenReadStream())) { contents = await sr.ReadToEndAsync(); } try { var newTheme = JsonConvert.DeserializeObject <Theme>(contents); var config = await ConfigStore.GetConfigAsync(); await ConfigStore.ManipulateConfig(c => c.CurrentTheme = newTheme); TempData.AddSuccess($"Successfully imported theme file '{file.FileName}' successfully! <a href=\"/d\" target=\"_blank\">Go check out your dashboard!</a>"); } catch { Logger.LogWarning("File selected was not able to be parsed into a theme. Check file contents and try again."); TempData.AddError("Import file was not a theme file or could not otherwise be imported. Check that the file is not malformed and try again."); } } catch (Exception ex) { Logger.LogError(ex, "Importing theme settings failed."); TempData.AddError("Unable to import theme. See log output (console) for more information."); } return(RedirectToAction("Themes")); }
public async Task <IActionResult> UpdateLayout() { var val = Request.Form["tilelayout"][0]; try { var layout = JsonConvert.DeserializeObject <List <TileLayout> >(val); // Multiply the X and Y by 2 since the preview is at 50%. layout.ForEach(l => { l.XPos *= 2; l.YPos *= 2; }); await ConfigStore.ManipulateConfig(c => c.TileLayout = layout); TempData.AddSuccess("Tile layout saved successfully!"); } catch { TempData.AddError("Unable to read tile layout from page. Cannot write to config file."); } return(RedirectToAction("Layout")); }
public async Task <IActionResult> SaveTheme([FromForm] Theme newTheme) { try { if (ModelState.IsValid) { var config = await ConfigStore.GetConfigAsync(); await ConfigStore.ManipulateConfig(c => c.CurrentTheme = newTheme); TempData.AddSuccess("Saved theme settings successfully!"); return(RedirectToAction("Themes")); } } catch (Exception ex) { Logger.LogError(ex, "Saving theme settings failed."); TempData.AddError("Unable to save theme changes. See log output (console) for more information."); } return(View("Themes", newTheme)); }
private async Task AttemptBaseUrlDiscovery() { // Temporary while we fetch some stuff... ClientFactory.Initialize(SupervisorEnvironment.GetBaseUrl(), SupervisorEnvironment.GetSupervisorToken()); var discovery = ClientFactory.GetClient <DiscoveryClient>(); var discInfo = await discovery.GetDiscoveryInfo(); if (string.IsNullOrWhiteSpace(discInfo?.BaseUrl)) { Log.LogError("Unable to read discovery info from Home Assistant. Do you have the HTTP component configured in Home Assistant with a \"base_url\" set?"); ClientFactory.Reset(); } else { await ConfigStore.ManipulateConfig(c => { c.Settings = new SystemSettings { BaseUri = discInfo.BaseUrl }; }); } }
public async Task <IActionResult> DeletePage([FromRoute] string page) { var cfg = await ConfigStore.GetConfigAsync(); var p = cfg[page]; if (cfg.Pages.Count == 1 || (p?.IsDefaultPage ?? false)) { TempData.AddWarning("You have to have at least one page, and you can't delete the default page."); return(RedirectToAction("Index")); } if (p == null) { TempData.AddWarning($"The specified page '{page}' does not exist in the configuration."); return(RedirectToAction("Index")); } await ConfigStore.ManipulateConfig(c => c.Pages.Remove(c[page])); TempData.AddSuccess($"The page '{page}' was successfully deleted."); return(RedirectToAction("Index")); }
public async Task InvokeAsync(HttpContext context) { var config = await ConfigStore.GetConfigAsync(); if (!string.IsNullOrWhiteSpace(config?.Settings?.BaseUri) && (!string.IsNullOrWhiteSpace(config?.Settings?.AccessToken) || !string.IsNullOrWhiteSpace(SupervisorEnvironment.GetSupervisorToken()))) { if (!ClientFactory.IsInitialized) { if (config.Settings.IsHassIo) { Log.LogInformation($"Auto-initializing HACC via Hass.io addon."); ClientFactory.Initialize(config.Settings.BaseUri, SupervisorEnvironment.GetSupervisorToken()); var discovery = ClientFactory.GetClient <DiscoveryClient>(); var discInfo = await discovery.GetDiscoveryInfo(); await ConfigStore.ManipulateConfig(c => c.Settings.ExternalBaseUri = discInfo.BaseUrl); } else { Log.LogInformation($"Initializing HACC API with URL {config?.Settings?.BaseUri ?? "[NULL]"} and access token [{new string(config?.Settings?.AccessToken.Take(6).ToArray())}•••••••••••{new string(config?.Settings?.AccessToken.TakeLast(6).ToArray())}]."); ClientFactory.Initialize(config.Settings.BaseUri, config.Settings.AccessToken); } } } else { ClientFactory.Reset(); } if (!ClientFactory.IsInitialized) { // If we're in Hass.io mode, set the base URI and redirect to the admin homepage. if (!string.IsNullOrWhiteSpace(SupervisorEnvironment.GetSupervisorToken())) { await ConfigStore.ManipulateConfig(c => { c.Settings = new SystemSettings { BaseUri = "http://hassio/homeassistant", AccessToken = null, IsHassIo = true }; context.Response.StatusCode = 303; context.Response.Redirect("/admin"); }); } // Otherwise, if we aren't on one of the approved pages, redirect to the settings page and prompt for setup. if (context.Request.Path.ToString().ToLower() != "/admin/settings" && context.Request.Path.ToString().ToLower() != "/admin") { Log.LogInformation($"Client factory is not initialized, redirecting user to settings area..."); context.Response.Redirect("/admin/settings?setup=1"); return; } } // Pages Migration #pragma warning disable CS0612 if ((config.TileLayout?.Count > 0 || config.Tiles?.Count > 0) && (config.Pages?.Count ?? 0) == 0) { await ConfigStore.ManipulateConfig(config => { config.Pages ??= new List <Page>(); config.Pages.Add(new Page { Name = "default", Description = "[Automatically generated from previous configuration.]", IsDefaultPage = true, Tiles = config.Tiles, TileLayout = config.TileLayout, LayoutSettings = config.LayoutSettings }); config.TileLayout = null; config.Tiles = null; config.LayoutSettings = null; }); context.Response.Redirect("/admin/pageMigration"); } else if (config.Pages.Count == 0) { await ConfigStore.ManipulateConfig(config => { config.Pages = new List <Page> { new Page { Name = "default", Description = "Default Page", IsDefaultPage = true, Tiles = new List <BaseTile>(), TileLayout = new List <TileLayout>(), LayoutSettings = new LayoutSettings { DeviceHeightPx = 1280, DeviceWidthPx = 720, BaseTileSizePx = 92, TileSpacingPx = 6, } } }; }); } #pragma warning restore CS0612 await Next(context); }