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"));
        }
Ejemplo n.º 6
0
        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"));
        }
Ejemplo n.º 8
0
        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"));
 }
Ejemplo n.º 10
0
        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));
        }
Ejemplo n.º 11
0
        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));
        }
Ejemplo n.º 14
0
        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));
        }
Ejemplo n.º 17
0
        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);
        }