diff --git a/API/Controllers/SettingsController.cs b/API/Controllers/SettingsController.cs index a7896a568..abde87eec 100644 --- a/API/Controllers/SettingsController.cs +++ b/API/Controllers/SettingsController.cs @@ -33,6 +33,14 @@ namespace API.Controllers _accountService = accountService; } + [AllowAnonymous] + [HttpGet("base-url")] + public async Task> GetBaseUrl() + { + var settingsDto = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync(); + return Ok(settingsDto.BaseUrl); + } + [Authorize(Policy = "RequireAdminRole")] [HttpGet] public async Task> GetSettings() @@ -91,8 +99,6 @@ namespace API.Controllers ? $"/{updateSettingsDto.BaseUrl}" : updateSettingsDto.BaseUrl; setting.Value = path; - // BaseUrl is managed in appSetting.json - Configuration.BaseUrl = updateSettingsDto.BaseUrl; _unitOfWork.SettingsRepository.Update(setting); } diff --git a/API/DTOs/Settings/ServerSettingDTO.cs b/API/DTOs/Settings/ServerSettingDTO.cs index 957270b8b..aace57127 100644 --- a/API/DTOs/Settings/ServerSettingDTO.cs +++ b/API/DTOs/Settings/ServerSettingDTO.cs @@ -27,8 +27,8 @@ /// public bool EnableAuthentication { get; set; } /// - /// Base Url for the kavita. Defaults to "/". Managed in appsettings.json.Requires restart to take effect. + /// Base Url for the kavita. Requires restart to take effect. /// - public string BaseUrl { get; set; } = "/"; + public string BaseUrl { get; set; } } } diff --git a/API/Data/Repositories/SettingsRepository.cs b/API/Data/Repositories/SettingsRepository.cs index 4489cf3bd..168b5a21e 100644 --- a/API/Data/Repositories/SettingsRepository.cs +++ b/API/Data/Repositories/SettingsRepository.cs @@ -35,6 +35,15 @@ namespace API.Data.Repositories return _mapper.Map(settings); } + public ServerSettingDto GetSettingsDto() + { + var settings = _context.ServerSetting + .Select(x => x) + .AsNoTracking() + .ToList(); + return _mapper.Map(settings); + } + public Task GetSettingAsync(ServerSettingKey key) { return _context.ServerSetting.SingleOrDefaultAsync(x => x.Key == key); diff --git a/API/Data/Seed.cs b/API/Data/Seed.cs index f1b9d6cc5..6b62089d0 100644 --- a/API/Data/Seed.cs +++ b/API/Data/Seed.cs @@ -50,7 +50,7 @@ namespace API.Data new () {Key = ServerSettingKey.AllowStatCollection, Value = "true"}, new () {Key = ServerSettingKey.EnableOpds, Value = "false"}, new () {Key = ServerSettingKey.EnableAuthentication, Value = "true"}, - new () {Key = ServerSettingKey.BaseUrl, Value = ""},// Not used from DB, but DB is sync with appSettings.json + new () {Key = ServerSettingKey.BaseUrl, Value = "/"}, }; foreach (var defaultSetting in defaultSettings) @@ -64,20 +64,11 @@ namespace API.Data await context.SaveChangesAsync(); - if (string.IsNullOrEmpty(Configuration.BaseUrl)) - { - Configuration.BaseUrl = "/"; - } - // Port and LoggingLevel are managed in appSettings.json. Update the DB values to match context.ServerSetting.First(s => s.Key == ServerSettingKey.Port).Value = Configuration.Port + string.Empty; context.ServerSetting.First(s => s.Key == ServerSettingKey.LoggingLevel).Value = Configuration.LogLevel + string.Empty; - context.ServerSetting.First(s => s.Key == ServerSettingKey.BaseUrl).Value = - Configuration.BaseUrl; - - await context.SaveChangesAsync(); diff --git a/API/Interfaces/Repositories/ISettingsRepository.cs b/API/Interfaces/Repositories/ISettingsRepository.cs index 95178ea79..79014dce4 100644 --- a/API/Interfaces/Repositories/ISettingsRepository.cs +++ b/API/Interfaces/Repositories/ISettingsRepository.cs @@ -10,6 +10,7 @@ namespace API.Interfaces.Repositories { void Update(ServerSetting settings); Task GetSettingsDtoAsync(); + ServerSettingDto GetSettingsDto(); Task GetSettingAsync(ServerSettingKey key); Task> GetSettingsAsync(); diff --git a/API/Startup.cs b/API/Startup.cs index ee309d537..d3c63cc3b 100644 --- a/API/Startup.cs +++ b/API/Startup.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Net; using System.Net.Sockets; using API.Extensions; +using API.Interfaces; +using API.Interfaces.Repositories; using API.Middleware; using API.Services; using API.Services.HostedServices; @@ -121,7 +123,7 @@ namespace API // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IBackgroundJobClient backgroundJobs, IWebHostEnvironment env, - IHostApplicationLifetime applicationLifetime) + IHostApplicationLifetime applicationLifetime, IServiceProvider serviceProvider) { app.UseMiddleware(); @@ -160,7 +162,9 @@ namespace API app.UseDefaultFiles(); - if (!string.IsNullOrEmpty(Configuration.BaseUrl)) + var service = serviceProvider.GetRequiredService(); + var settings = service.SettingsRepository.GetSettingsDto(); + if (!string.IsNullOrEmpty(settings.BaseUrl) && !settings.BaseUrl.Equals("/")) { var path = !Configuration.BaseUrl.StartsWith("/") ? $"/{Configuration.BaseUrl}" diff --git a/UI/Web/src/app/_models/config-data.ts b/UI/Web/src/app/_models/config-data.ts new file mode 100644 index 000000000..360fc45b1 --- /dev/null +++ b/UI/Web/src/app/_models/config-data.ts @@ -0,0 +1,10 @@ +/** + * This is for base url only. Not to be used my applicaiton, only loading and bootstrapping app + */ +export class ConfigData { + baseUrl: string = '/'; + + constructor(baseUrl: string) { + this.baseUrl = baseUrl; + } +} \ No newline at end of file diff --git a/UI/Web/src/app/app.module.ts b/UI/Web/src/app/app.module.ts index 76eb54f6e..ed8074d08 100644 --- a/UI/Web/src/app/app.module.ts +++ b/UI/Web/src/app/app.module.ts @@ -31,6 +31,8 @@ import { CardsModule } from './cards/cards.module'; import { CollectionsModule } from './collections/collections.module'; import { ReadingListModule } from './reading-list/reading-list.module'; import { SAVER, getSaver } from './shared/_providers/saver.provider'; +import { ConfigData } from './_models/config-data'; + @NgModule({ declarations: [ @@ -83,7 +85,7 @@ import { SAVER, getSaver } from './shared/_providers/saver.provider'; {provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}, Title, {provide: SAVER, useFactory: getSaver}, - { provide: APP_BASE_HREF, useValue: window['_app_base' as keyof Window] || '/' }, + { provide: APP_BASE_HREF, useFactory: (config: ConfigData) => config.baseUrl, deps: [ConfigData] }, ], entryComponents: [], bootstrap: [AppComponent] diff --git a/UI/Web/src/index.html b/UI/Web/src/index.html index 834629c97..0b9f60c62 100644 --- a/UI/Web/src/index.html +++ b/UI/Web/src/index.html @@ -40,9 +40,4 @@ - diff --git a/UI/Web/src/main.ts b/UI/Web/src/main.ts index 61d77f120..9c0339e96 100644 --- a/UI/Web/src/main.ts +++ b/UI/Web/src/main.ts @@ -2,13 +2,21 @@ import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; +import { ConfigData } from './app/_models/config-data'; import { environment } from './environments/environment'; - - if (environment.production) { enableProdMode(); } -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.error(err)); +function fetchConfig(): Promise { + return fetch(environment.apiUrl + 'settings/base-url') + .then(response => response.text()) + .then(response => new ConfigData(response)); +} + +fetchConfig().then(config => { + platformBrowserDynamic([ { provide: ConfigData, useValue: config } ]) + .bootstrapModule(AppModule) + .catch(err => console.error(err)); +}); \ No newline at end of file