mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-31 12:00:06 -07:00
Finsihed adding preset themes.
Added query string support for api key #1689 Added swedish lang #1691
This commit is contained in:
parent
9252bbf110
commit
aad5a71c98
11 changed files with 106 additions and 114 deletions
|
@ -19,7 +19,7 @@ namespace Ombi.Api.Github
|
||||||
|
|
||||||
public async Task<List<CakeThemes>> GetCakeThemes()
|
public async Task<List<CakeThemes>> GetCakeThemes()
|
||||||
{
|
{
|
||||||
var request = new Request("repos/leram84/layer.Cake/contents/ombi/themes", BaseUrl, HttpMethod.Get);
|
var request = new Request("repos/tidusjar/layer.Cake/contents/ombi/themes", BaseUrl, HttpMethod.Get);
|
||||||
request.AddHeader("Accept", "application/vnd.github.v3+json");
|
request.AddHeader("Accept", "application/vnd.github.v3+json");
|
||||||
request.AddHeader("User-Agent", "Ombi");
|
request.AddHeader("User-Agent", "Ombi");
|
||||||
return await _api.Request<List<CakeThemes>>(request);
|
return await _api.Request<List<CakeThemes>>(request);
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace Ombi.Settings.Settings.Models
|
||||||
public string PresetThemeContent { get; set; }
|
public string PresetThemeContent { get; set; }
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public string PresetThemeVersionVersion
|
public string PresetThemeVersion
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,13 +26,13 @@ export class AppComponent implements OnInit {
|
||||||
private readonly settingsService: SettingsService,
|
private readonly settingsService: SettingsService,
|
||||||
private readonly jobService: JobService,
|
private readonly jobService: JobService,
|
||||||
public readonly translate: TranslateService) {
|
public readonly translate: TranslateService) {
|
||||||
this.translate.addLangs(["en", "de", "fr","da","es","it","nl"]);
|
this.translate.addLangs(["en", "de", "fr","da","es","it","nl","sv"]);
|
||||||
// this language will be used as a fallback when a translation isn't found in the current language
|
// this language will be used as a fallback when a translation isn't found in the current language
|
||||||
this.translate.setDefaultLang("en");
|
this.translate.setDefaultLang("en");
|
||||||
|
|
||||||
// See if we can match the supported langs with the current browser lang
|
// See if we can match the supported langs with the current browser lang
|
||||||
const browserLang: string = translate.getBrowserLang();
|
const browserLang: string = translate.getBrowserLang();
|
||||||
this.translate.use(browserLang.match(/en|fr|da|de|es|it|nl/) ? browserLang : "en");
|
this.translate.use(browserLang.match(/en|fr|da|de|es|it|nl|sv/) ? browserLang : "en");
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnInit() {
|
public ngOnInit() {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
<fieldset *ngIf="settings">
|
<fieldset *ngIf="settings">
|
||||||
<legend>Customization</legend>
|
<legend>Customization</legend>
|
||||||
<div class="col-md-6">
|
<div class="col-md-5">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="applicationName" class="control-label">Application Name</label>
|
<label for="applicationName" class="control-label">Application Name</label>
|
||||||
<div>
|
<div>
|
||||||
|
@ -27,6 +27,12 @@
|
||||||
tooltipPosition="top" pTooltip="Use a URL e.g. www.google.com/logo.png">
|
tooltipPosition="top" pTooltip="Use a URL e.g. www.google.com/logo.png">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div *ngIf="settings.logo" class="form-group">
|
||||||
|
<label for="logo" class="control-label">Logo Preview:</label>
|
||||||
|
<div>
|
||||||
|
<img [src]="settings.logo" style="width: 300px" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -46,7 +52,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="col-md-6">
|
<div class="col-md-7">
|
||||||
<div *ngIf="themes">
|
<div *ngIf="themes">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="presetTheme" class="control-label">Preset Themes</label>
|
<label for="presetTheme" class="control-label">Preset Themes</label>
|
||||||
|
@ -56,19 +62,14 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group" *ngIf="settings.presetThemeContent">
|
||||||
<textarea rows="4" type="text" class="form-control-custom form-control " id="themeContent" name="themeContent" [(ngModel)]="settings.presetThemeContent"> {{settings.presetThemeContent}} </textarea>
|
<textarea rows="25" type="text" class="form-control-custom form-control " id="themeContent" name="themeContent" [(ngModel)]="settings.presetThemeContent"> {{settings.presetThemeContent}} </textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div> -->
|
|
||||||
|
|
||||||
|
|
||||||
<div *ngIf="settings.logo" class="form-group">
|
|
||||||
<label for="logo" class="control-label">Logo Preview:</label>
|
|
||||||
<div>
|
|
||||||
<img [src]="settings.logo" style="width: 300px" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</fieldset>
|
</fieldset>
|
|
@ -19,6 +19,18 @@ export class CustomizationComponent implements OnInit {
|
||||||
this.settings = x;
|
this.settings = x;
|
||||||
this.settingsService.getThemes().subscribe(t => {
|
this.settingsService.getThemes().subscribe(t => {
|
||||||
this.themes = t;
|
this.themes = t;
|
||||||
|
|
||||||
|
const existingTheme = this.themes.filter((item) => {
|
||||||
|
return item.fullName === this.settings.presetThemeName;
|
||||||
|
})[0];
|
||||||
|
|
||||||
|
if(existingTheme) {
|
||||||
|
const index = this.themes.indexOf(existingTheme, 0);
|
||||||
|
if (index > -1) {
|
||||||
|
this.themes.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(x.hasPresetTheme) {
|
if(x.hasPresetTheme) {
|
||||||
this.themes.unshift({displayName: x.presetThemeDisplayName, fullName: x.presetThemeName, url: "", version: x.presetThemeVersion});
|
this.themes.unshift({displayName: x.presetThemeDisplayName, fullName: x.presetThemeName, url: "", version: x.presetThemeVersion});
|
||||||
} else {
|
} else {
|
||||||
|
@ -45,9 +57,9 @@ export class CustomizationComponent implements OnInit {
|
||||||
return val.fullName === selectedThemeFullName;
|
return val.fullName === selectedThemeFullName;
|
||||||
});
|
});
|
||||||
|
|
||||||
// if(selectedTheme[0].fullName === this.settings.presetThemeName) {
|
if(selectedTheme[0].fullName === this.settings.presetThemeName) {
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
this.settings.presetThemeName = selectedThemeFullName;
|
this.settings.presetThemeName = selectedThemeFullName;
|
||||||
this.settingsService.getThemeContent(selectedTheme[0].url).subscribe(x => {
|
this.settingsService.getThemeContent(selectedTheme[0].url).subscribe(x => {
|
||||||
|
|
|
@ -259,6 +259,7 @@ namespace Ombi.Controllers
|
||||||
/// <param name="url"></param>
|
/// <param name="url"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpGet("themecontent")]
|
[HttpGet("themecontent")]
|
||||||
|
[AllowAnonymous]
|
||||||
public async Task<string> GetThemeContent([FromQuery]string url)
|
public async Task<string> GetThemeContent([FromQuery]string url)
|
||||||
{
|
{
|
||||||
var content = await _githubApi.GetThemesRawContent(url);
|
var content = await _githubApi.GetThemesRawContent(url);
|
||||||
|
|
|
@ -194,7 +194,7 @@ namespace Ombi
|
||||||
|
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
|
|
||||||
ApiKeyMiddlewear(app, serviceProvider);
|
app.ApiKeyMiddlewear(serviceProvider);
|
||||||
app.UseSwagger();
|
app.UseSwagger();
|
||||||
app.UseSwaggerUI(c =>
|
app.UseSwaggerUI(c =>
|
||||||
{
|
{
|
||||||
|
@ -213,46 +213,6 @@ namespace Ombi
|
||||||
defaults: new { controller = "Home", action = "Index" });
|
defaults: new { controller = "Home", action = "Index" });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ApiKeyMiddlewear(IApplicationBuilder app, IServiceProvider serviceProvider)
|
|
||||||
{
|
|
||||||
app.Use(async (context, next) =>
|
|
||||||
{
|
|
||||||
if (context.Request.Path.StartsWithSegments(new PathString("/api")))
|
|
||||||
{
|
|
||||||
// Let's check if this is an API Call
|
|
||||||
if (context.Request.Headers["ApiKey"].Any())
|
|
||||||
{
|
|
||||||
// validate the supplied API key
|
|
||||||
// Validate it
|
|
||||||
var headerKey = context.Request.Headers["ApiKey"].FirstOrDefault();
|
|
||||||
var settingsProvider = serviceProvider.GetService<ISettingsService<OmbiSettings>>();
|
|
||||||
var ombiSettings = settingsProvider.GetSettings();
|
|
||||||
var valid = ombiSettings.ApiKey.Equals(headerKey, StringComparison.CurrentCultureIgnoreCase);
|
|
||||||
if (!valid)
|
|
||||||
{
|
|
||||||
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
|
||||||
await context.Response.WriteAsync("Invalid API Key");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var identity = new GenericIdentity("API");
|
|
||||||
var principal = new GenericPrincipal(identity, new[] { "Admin", "ApiUser" });
|
|
||||||
context.User = principal;
|
|
||||||
await next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await next();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HangfireAuthorizationFilter : IDashboardAuthorizationFilter
|
public class HangfireAuthorizationFilter : IDashboardAuthorizationFilter
|
||||||
|
|
|
@ -1,14 +1,23 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Security.Principal;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.PlatformAbstractions;
|
using Microsoft.Extensions.PlatformAbstractions;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using Ombi.Config;
|
using Ombi.Config;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
using Ombi.Models.Identity;
|
using Ombi.Models.Identity;
|
||||||
|
using Ombi.Settings.Settings.Models;
|
||||||
using Swashbuckle.AspNetCore.Swagger;
|
using Swashbuckle.AspNetCore.Swagger;
|
||||||
|
|
||||||
namespace Ombi
|
namespace Ombi
|
||||||
|
@ -103,5 +112,58 @@ namespace Ombi
|
||||||
x.TokenValidationParameters = tokenValidationParameters;
|
x.TokenValidationParameters = tokenValidationParameters;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void ApiKeyMiddlewear(this IApplicationBuilder app, IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
app.Use(async (context, next) =>
|
||||||
|
{
|
||||||
|
if (context.Request.Path.StartsWithSegments(new PathString("/api")))
|
||||||
|
{
|
||||||
|
// Let's check if this is an API Call
|
||||||
|
if (context.Request.Headers["ApiKey"].Any())
|
||||||
|
{
|
||||||
|
// validate the supplied API key
|
||||||
|
// Validate it
|
||||||
|
var headerKey = context.Request.Headers["ApiKey"].FirstOrDefault();
|
||||||
|
await ValidateApiKey(serviceProvider, context, next, headerKey);
|
||||||
|
}
|
||||||
|
else if (context.Request.Query.ContainsKey("apikey"))
|
||||||
|
{
|
||||||
|
if (context.Request.Query.TryGetValue("apikey", out var queryKey))
|
||||||
|
{
|
||||||
|
await ValidateApiKey(serviceProvider, context, next, queryKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task ValidateApiKey(IServiceProvider serviceProvider, HttpContext context, Func<Task> next, string key)
|
||||||
|
{
|
||||||
|
var settingsProvider = serviceProvider.GetService<ISettingsService<OmbiSettings>>();
|
||||||
|
var ombiSettings = settingsProvider.GetSettings();
|
||||||
|
var valid = ombiSettings.ApiKey.Equals(key, StringComparison.CurrentCultureIgnoreCase);
|
||||||
|
if (!valid)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||||
|
await context.Response.WriteAsync("Invalid API Key");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var identity = new GenericIdentity("API");
|
||||||
|
var principal = new GenericPrincipal(identity, new[] { "Admin", "ApiUser" });
|
||||||
|
context.User = principal;
|
||||||
|
await next();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -56,6 +56,13 @@
|
||||||
|
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
@{
|
@{
|
||||||
|
if (customization.HasPresetTheme)
|
||||||
|
{
|
||||||
|
<style>
|
||||||
|
@Html.Raw(customization.PresetThemeContent)
|
||||||
|
</style>
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(customization.CustomCssLink))
|
if (!string.IsNullOrEmpty(customization.CustomCssLink))
|
||||||
{
|
{
|
||||||
<link rel="stylesheet" href="@customization.CustomCssLink" asp-append-version="true"/>
|
<link rel="stylesheet" href="@customization.CustomCssLink" asp-append-version="true"/>
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
{
|
|
||||||
"Login": {
|
|
||||||
"SignInButton": "crwdns37:0crwdne37:0",
|
|
||||||
"UsernamePlaceholder": "crwdns38:0crwdne38:0",
|
|
||||||
"PasswordPlaceholder": "crwdns39:0crwdne39:0",
|
|
||||||
"RememberMe": "crwdns40:0crwdne40:0",
|
|
||||||
"ForgottenPassword": "crwdns41:0crwdne41:0",
|
|
||||||
"Errors": {
|
|
||||||
"IncorrectCredentials": "crwdns71:0crwdne71:0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Common": {
|
|
||||||
"ContinueButton": "crwdns42:0crwdne42:0",
|
|
||||||
"Errors": {
|
|
||||||
"Validation": "crwdns72:0crwdne72:0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PasswordReset": {
|
|
||||||
"EmailAddressPlaceholder": "crwdns43:0crwdne43:0",
|
|
||||||
"ResetPasswordButton": "crwdns44:0crwdne44:0"
|
|
||||||
},
|
|
||||||
"LandingPage": {
|
|
||||||
"OnlineHeading": "crwdns45:0crwdne45:0",
|
|
||||||
"OnlineParagraph": "crwdns46:0crwdne46:0",
|
|
||||||
"PartiallyOnlineHeading": "crwdns47:0crwdne47:0",
|
|
||||||
"PartiallyOnlineParagraph": "crwdns48:0crwdne48:0",
|
|
||||||
"MultipleServersUnavailable": "crwdns49:0{{serversUnavailable}}crwdnd49:0{{totalServers}}crwdne49:0",
|
|
||||||
"SingleServerUnavailable": "crwdns50:0{{serversUnavailable}}crwdnd50:0{{totalServers}}crwdne50:0",
|
|
||||||
"OfflineHeading": "crwdns51:0crwdne51:0",
|
|
||||||
"OfflineParagraph": "crwdns52:0crwdne52:0",
|
|
||||||
"CheckPageForUpdates": "crwdns73:0crwdne73:0"
|
|
||||||
},
|
|
||||||
"NavigationBar": {
|
|
||||||
"Search": "crwdns54:0crwdne54:0",
|
|
||||||
"Requests": "crwdns55:0crwdne55:0",
|
|
||||||
"UserManagement": "crwdns56:0crwdne56:0",
|
|
||||||
"Donate": "crwdns57:0crwdne57:0",
|
|
||||||
"DonateTooltip": "crwdns58:0crwdne58:0",
|
|
||||||
"UpdateAvailableTooltip": "crwdns59:0crwdne59:0",
|
|
||||||
"Settings": "crwdns60:0crwdne60:0",
|
|
||||||
"Welcome": "crwdns61:0{{username}}crwdne61:0",
|
|
||||||
"UpdateDetails": "crwdns62:0crwdne62:0",
|
|
||||||
"Logout": "crwdns63:0crwdne63:0",
|
|
||||||
"Language": {
|
|
||||||
"English": "crwdns64:0crwdne64:0",
|
|
||||||
"French": "crwdns65:0crwdne65:0",
|
|
||||||
"Spanish": "crwdns66:0crwdne66:0",
|
|
||||||
"German": "crwdns67:0crwdne67:0",
|
|
||||||
"Italian": "crwdns68:0crwdne68:0",
|
|
||||||
"Danish": "crwdns69:0crwdne69:0",
|
|
||||||
"Dutch": "crwdns70:0crwdne70:0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
3
src/Ombi/wwwroot/translations/sv.json
Normal file
3
src/Ombi/wwwroot/translations/sv.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue