Add option to set the base href.
This commit is contained in:
parent
dbfc348945
commit
8418b26d70
12 changed files with 107 additions and 39 deletions
|
|
@ -1,44 +1,45 @@
|
||||||
|
import { APP_BASE_HREF } from '@angular/common';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Inject, Injectable } from '@angular/core';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
constructor(private http: HttpClient) {}
|
constructor(private http: HttpClient, @Inject(APP_BASE_HREF) private baseHref: string) {}
|
||||||
|
|
||||||
public isLoggedIn(): Observable<boolean> {
|
public isLoggedIn(): Observable<boolean> {
|
||||||
return this.http.get<boolean>(`/Api/Authentication/IsLoggedIn`);
|
return this.http.get<boolean>(`${this.baseHref}Api/Authentication/IsLoggedIn`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public create(userName: string, password: string): Observable<void> {
|
public create(userName: string, password: string): Observable<void> {
|
||||||
return this.http.post<void>(`/Api/Authentication/Create`, {
|
return this.http.post<void>(`${this.baseHref}Api/Authentication/Create`, {
|
||||||
userName,
|
userName,
|
||||||
password,
|
password,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public setupProvider(provider: string, token: string): Observable<void> {
|
public setupProvider(provider: string, token: string): Observable<void> {
|
||||||
return this.http.post<void>(`/Api/Authentication/SetupProvider`, {
|
return this.http.post<void>(`${this.baseHref}Api/Authentication/SetupProvider`, {
|
||||||
provider,
|
provider,
|
||||||
token,
|
token,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public login(userName: string, password: string): Observable<void> {
|
public login(userName: string, password: string): Observable<void> {
|
||||||
return this.http.post<void>(`/Api/Authentication/Login`, {
|
return this.http.post<void>(`${this.baseHref}Api/Authentication/Login`, {
|
||||||
userName,
|
userName,
|
||||||
password,
|
password,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public logout() {
|
public logout() {
|
||||||
return this.http.post<void>(`/Api/Authentication/Logout`, {});
|
return this.http.post<void>(`${this.baseHref}Api/Authentication/Logout`, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
public update(userName: string, password: string): Observable<void> {
|
public update(userName: string, password: string): Observable<void> {
|
||||||
return this.http.post<void>(`/Api/Authentication/Update`, {
|
return this.http.post<void>(`${this.baseHref}Api/Authentication/Update`, {
|
||||||
userName,
|
userName,
|
||||||
password,
|
password,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="columns is-centered">
|
<div class="columns is-centered">
|
||||||
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
|
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
|
||||||
<img src="../../assets/logo.png" />
|
<img src="assets/logo.png" />
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<form (ngSubmit)="login()">
|
<form (ngSubmit)="login()">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<nav class="navbar is-dark is-fixed-top" role="navigation" aria-label="main navigation">
|
<nav class="navbar is-dark is-fixed-top" role="navigation" aria-label="main navigation">
|
||||||
<div class="navbar-brand">
|
<div class="navbar-brand">
|
||||||
<a class="navbar-item" routerLink="/">
|
<a class="navbar-item" routerLink="/">
|
||||||
<img src="../../assets/logo.png" />
|
<img src="assets/logo.png" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,42 @@
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Inject, Injectable } from '@angular/core';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { Profile } from './models/profile.model';
|
import { Profile } from './models/profile.model';
|
||||||
import { Setting } from './models/setting.model';
|
import { Setting } from './models/setting.model';
|
||||||
|
import { APP_BASE_HREF } from '@angular/common';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class SettingsService {
|
export class SettingsService {
|
||||||
constructor(private http: HttpClient) {}
|
constructor(private http: HttpClient, @Inject(APP_BASE_HREF) private baseHref: string) {}
|
||||||
|
|
||||||
public get(): Observable<Setting[]> {
|
public get(): Observable<Setting[]> {
|
||||||
return this.http.get<Setting[]>(`/Api/Settings`);
|
return this.http.get<Setting[]>(`${this.baseHref}Api/Settings`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public update(settings: Setting[]): Observable<void> {
|
public update(settings: Setting[]): Observable<void> {
|
||||||
return this.http.put<void>(`/Api/Settings`, settings);
|
return this.http.put<void>(`${this.baseHref}Api/Settings`, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getProfile(): Observable<Profile> {
|
public getProfile(): Observable<Profile> {
|
||||||
return this.http.get<Profile>(`/Api/Settings/Profile`);
|
return this.http.get<Profile>(`${this.baseHref}Api/Settings/Profile`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public testPath(path: string): Observable<void> {
|
public testPath(path: string): Observable<void> {
|
||||||
return this.http.post<void>(`/Api/Settings/TestPath`, { path });
|
return this.http.post<void>(`${this.baseHref}Api/Settings/TestPath`, { path });
|
||||||
}
|
}
|
||||||
|
|
||||||
public testDownloadSpeed(): Observable<number> {
|
public testDownloadSpeed(): Observable<number> {
|
||||||
return this.http.get<number>(`/Api/Settings/TestDownloadSpeed`);
|
return this.http.get<number>(`${this.baseHref}Api/Settings/TestDownloadSpeed`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public testWriteSpeed(): Observable<number> {
|
public testWriteSpeed(): Observable<number> {
|
||||||
return this.http.get<number>(`/Api/Settings/TestWriteSpeed`);
|
return this.http.get<number>(`${this.baseHref}Api/Settings/TestWriteSpeed`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public testAria2cConnection(url: string, secret: string): Observable<{ version: string }> {
|
public testAria2cConnection(url: string, secret: string): Observable<{ version: string }> {
|
||||||
return this.http.post<{ version: string }>(`/Api/Settings/TestAria2cConnection`, {
|
return this.http.post<{ version: string }>(`${this.baseHref}Api/Settings/TestAria2cConnection`, {
|
||||||
url,
|
url,
|
||||||
secret,
|
secret,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="columns is-centered">
|
<div class="columns is-centered">
|
||||||
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
|
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
|
||||||
<img src="../../assets/logo.png" />
|
<img src="assets/logo.png" />
|
||||||
<div class="box" *ngIf="step === 1">
|
<div class="box" *ngIf="step === 1">
|
||||||
<div class="notification is-primary">
|
<div class="notification is-primary">
|
||||||
Welcome to Real-Debrid Client. Please create your account by entering a username and password.
|
Welcome to Real-Debrid Client. Please create your account by entering a username and password.
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
>Use this link to sign up to AllDebrid.</a
|
>Use this link to sign up to AllDebrid.</a
|
||||||
>
|
>
|
||||||
<br />
|
<br />
|
||||||
<a href="https://www.premiumize.me/" target="_blank" rel="noopener"
|
<a href="https://www.premiumize.me/" target="_blank" rel="noopener"
|
||||||
>Use this link to sign up to Premiumize.</a
|
>Use this link to sign up to Premiumize.</a
|
||||||
>
|
>
|
||||||
<br />
|
<br />
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
<select [(ngModel)]="provider">
|
<select [(ngModel)]="provider">
|
||||||
<option [value]="0">Real-Debrid</option>
|
<option [value]="0">Real-Debrid</option>
|
||||||
<option [value]="1">AllDebrid</option>
|
<option [value]="1">AllDebrid</option>
|
||||||
<option [value]="2">Premiumize</option>
|
<option [value]="2">Premiumize</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -85,7 +85,7 @@
|
||||||
>https://alldebrid.com/apikeys/</a
|
>https://alldebrid.com/apikeys/</a
|
||||||
>.
|
>.
|
||||||
</p>
|
</p>
|
||||||
<p class="help" *ngIf="provider === 'Premiumize'">
|
<p class="help" *ngIf="provider === 'Premiumize'">
|
||||||
You can find your API key here:
|
You can find your API key here:
|
||||||
<a href="https://www.premiumize.me/account" target="_blank" rel="noopener"
|
<a href="https://www.premiumize.me/account" target="_blank" rel="noopener"
|
||||||
>https://www.premiumize.me/account</a
|
>https://www.premiumize.me/account</a
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Inject, Injectable } from '@angular/core';
|
||||||
import * as signalR from '@microsoft/signalr';
|
import * as signalR from '@microsoft/signalr';
|
||||||
import { Observable, Subject } from 'rxjs';
|
import { Observable, Subject } from 'rxjs';
|
||||||
import { Torrent, TorrentFileAvailability } from './models/torrent.model';
|
import { Torrent, TorrentFileAvailability } from './models/torrent.model';
|
||||||
|
import { APP_BASE_HREF } from '@angular/common';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
|
|
@ -12,7 +13,7 @@ export class TorrentService {
|
||||||
|
|
||||||
private connection: signalR.HubConnection;
|
private connection: signalR.HubConnection;
|
||||||
|
|
||||||
constructor(private http: HttpClient) {
|
constructor(private http: HttpClient, @Inject(APP_BASE_HREF) private baseHref: string) {
|
||||||
this.connect();
|
this.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -21,7 +22,10 @@ export class TorrentService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.connection = new signalR.HubConnectionBuilder().withUrl('/hub').withAutomaticReconnect().build();
|
this.connection = new signalR.HubConnectionBuilder()
|
||||||
|
.withUrl(`${this.baseHref}hub`)
|
||||||
|
.withAutomaticReconnect()
|
||||||
|
.build();
|
||||||
this.connection.start().catch((err) => console.error(err));
|
this.connection.start().catch((err) => console.error(err));
|
||||||
|
|
||||||
this.connection.on('update', (torrents: Torrent[]) => {
|
this.connection.on('update', (torrents: Torrent[]) => {
|
||||||
|
|
@ -30,15 +34,15 @@ export class TorrentService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public getList(): Observable<Torrent[]> {
|
public getList(): Observable<Torrent[]> {
|
||||||
return this.http.get<Torrent[]>(`/Api/Torrents`);
|
return this.http.get<Torrent[]>(`${this.baseHref}Api/Torrents`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(torrentId: string): Observable<Torrent> {
|
public get(torrentId: string): Observable<Torrent> {
|
||||||
return this.http.get<Torrent>(`/Api/Torrents/Get/${torrentId}`);
|
return this.http.get<Torrent>(`${this.baseHref}Api/Torrents/Get/${torrentId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public uploadMagnet(magnetLink: string, torrent: Torrent): Observable<void> {
|
public uploadMagnet(magnetLink: string, torrent: Torrent): Observable<void> {
|
||||||
return this.http.post<void>(`/Api/Torrents/UploadMagnet`, {
|
return this.http.post<void>(`${this.baseHref}Api/Torrents/UploadMagnet`, {
|
||||||
magnetLink,
|
magnetLink,
|
||||||
torrent,
|
torrent,
|
||||||
});
|
});
|
||||||
|
|
@ -48,11 +52,11 @@ export class TorrentService {
|
||||||
const formData: FormData = new FormData();
|
const formData: FormData = new FormData();
|
||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
formData.append('formData', JSON.stringify({ torrent }));
|
formData.append('formData', JSON.stringify({ torrent }));
|
||||||
return this.http.post<void>(`/Api/Torrents/UploadFile`, formData);
|
return this.http.post<void>(`${this.baseHref}Api/Torrents/UploadFile`, formData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkFilesMagnet(magnetLink: string): Observable<TorrentFileAvailability[]> {
|
public checkFilesMagnet(magnetLink: string): Observable<TorrentFileAvailability[]> {
|
||||||
return this.http.post<TorrentFileAvailability[]>(`/Api/Torrents/CheckFilesMagnet`, {
|
return this.http.post<TorrentFileAvailability[]>(`${this.baseHref}Api/Torrents/CheckFilesMagnet`, {
|
||||||
magnetLink,
|
magnetLink,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +64,7 @@ export class TorrentService {
|
||||||
public checkFiles(file: File): Observable<TorrentFileAvailability[]> {
|
public checkFiles(file: File): Observable<TorrentFileAvailability[]> {
|
||||||
const formData: FormData = new FormData();
|
const formData: FormData = new FormData();
|
||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
return this.http.post<TorrentFileAvailability[]>(`/Api/Torrents/CheckFiles`, formData);
|
return this.http.post<TorrentFileAvailability[]>(`${this.baseHref}Api/Torrents/CheckFiles`, formData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public delete(
|
public delete(
|
||||||
|
|
@ -69,7 +73,7 @@ export class TorrentService {
|
||||||
deleteRdTorrent: boolean,
|
deleteRdTorrent: boolean,
|
||||||
deleteLocalFiles: boolean
|
deleteLocalFiles: boolean
|
||||||
): Observable<void> {
|
): Observable<void> {
|
||||||
return this.http.post<void>(`/Api/Torrents/Delete/${torrentId}`, {
|
return this.http.post<void>(`${this.baseHref}Api/Torrents/Delete/${torrentId}`, {
|
||||||
deleteData,
|
deleteData,
|
||||||
deleteRdTorrent,
|
deleteRdTorrent,
|
||||||
deleteLocalFiles,
|
deleteLocalFiles,
|
||||||
|
|
@ -77,14 +81,14 @@ export class TorrentService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public retry(torrentId: string): Observable<void> {
|
public retry(torrentId: string): Observable<void> {
|
||||||
return this.http.post<void>(`/Api/Torrents/Retry/${torrentId}`, {});
|
return this.http.post<void>(`${this.baseHref}Api/Torrents/Retry/${torrentId}`, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
public retryDownload(downloadId: string): Observable<void> {
|
public retryDownload(downloadId: string): Observable<void> {
|
||||||
return this.http.post<void>(`/Api/Torrents/RetryDownload/${downloadId}`, {});
|
return this.http.post<void>(`${this.baseHref}Api/Torrents/RetryDownload/${downloadId}`, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
public update(torrent: Torrent): Observable<void> {
|
public update(torrent: Torrent): Observable<void> {
|
||||||
return this.http.put<void>(`/Api/Torrents/Update`, torrent);
|
return this.http.put<void>(`${this.baseHref}Api/Torrents/Update`, torrent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@
|
||||||
<base href="/" />
|
<base href="/" />
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
window["_app_base"] = "/" + window.location.pathname.split("/")[1];
|
var pathSegment = window.location.pathname.split("/")[1];
|
||||||
|
window["_app_base"] = pathSegment ? "/" + pathSegment + "/" : "/";
|
||||||
console.log("setting base href to " + window["_app_base"]);
|
console.log("setting base href to " + window["_app_base"]);
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ public class AppSettings
|
||||||
public AppSettingsDatabase? Database { get; set; }
|
public AppSettingsDatabase? Database { get; set; }
|
||||||
|
|
||||||
public Int32 Port { get; set; }
|
public Int32 Port { get; set; }
|
||||||
|
public String? BasePath { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AppSettingsLogging
|
public class AppSettingsLogging
|
||||||
|
|
|
||||||
54
server/RdtClient.Service/Middleware/BaseHrefMiddleware.cs
Normal file
54
server/RdtClient.Service/Middleware/BaseHrefMiddleware.cs
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using RdtClient.Data.Models.Internal;
|
||||||
|
|
||||||
|
namespace RdtClient.Service.Middleware;
|
||||||
|
|
||||||
|
public class BaseHrefMiddleware
|
||||||
|
{
|
||||||
|
private readonly RequestDelegate _next;
|
||||||
|
|
||||||
|
public BaseHrefMiddleware(RequestDelegate next)
|
||||||
|
{
|
||||||
|
_next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InvokeAsync(HttpContext context, AppSettings appSettings)
|
||||||
|
{
|
||||||
|
var originalBody = context.Response.Body;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var newBody = new MemoryStream();
|
||||||
|
|
||||||
|
context.Response.Body = newBody;
|
||||||
|
|
||||||
|
await _next(context);
|
||||||
|
|
||||||
|
context.Response.Body = originalBody;
|
||||||
|
newBody.Seek(0, SeekOrigin.Begin);
|
||||||
|
var responseBody = await new StreamReader(newBody).ReadToEndAsync();
|
||||||
|
|
||||||
|
// ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
|
||||||
|
if (context.Response.ContentType?.Contains("text/html") == true)
|
||||||
|
{
|
||||||
|
var basePath = $"/{appSettings.BasePath!.TrimStart('/').TrimEnd('/')}/";
|
||||||
|
|
||||||
|
responseBody = Regex.Replace(responseBody, @"<base href=""/""", @$"<base href=""{basePath}""");
|
||||||
|
|
||||||
|
responseBody = Regex.Replace(responseBody, "(<script.*?src=\")(.*?)(\".*?</script>)", $"$1{basePath}$2$3");
|
||||||
|
responseBody = Regex.Replace(responseBody, "(<link.*?href=\")(.*?)(\".*?>)", $"$1{basePath}$2$3");
|
||||||
|
|
||||||
|
await context.Response.WriteAsync(responseBody);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await context.Response.BodyWriter.WriteAsync(newBody.ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
context.Response.Body = originalBody;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -164,6 +164,11 @@ try
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!String.IsNullOrWhiteSpace(appSettings.BasePath))
|
||||||
|
{
|
||||||
|
app.UseMiddleware<BaseHrefMiddleware>();
|
||||||
|
}
|
||||||
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
},
|
},
|
||||||
"RdtClient.Web": {
|
"RdtClient.Web": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"launchUrl": "weatherforecast",
|
"launchUrl": "",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -9,5 +9,6 @@
|
||||||
"Database": {
|
"Database": {
|
||||||
"Path": "/data/db/rdtclient.db"
|
"Path": "/data/db/rdtclient.db"
|
||||||
},
|
},
|
||||||
"Port": "6500"
|
"Port": "6500",
|
||||||
|
"BasePath": null
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue