Improved inital setup by adding a short wizard.
This commit is contained in:
parent
df39d6a671
commit
ec02b3d8bb
19 changed files with 345 additions and 159 deletions
|
|
@ -1,22 +1,30 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { MainLayoutComponent } from './main-layout/main-layout.component';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { AuthResolverService } from './auth-resolver.service';
|
||||
import { LoginComponent } from './login/login.component';
|
||||
import { MainLayoutComponent } from './main-layout/main-layout.component';
|
||||
import { SetupComponent } from './setup/setup.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'login',
|
||||
component: LoginComponent,
|
||||
},
|
||||
{
|
||||
path: 'setup',
|
||||
component: SetupComponent,
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: MainLayoutComponent,
|
||||
canActivate: [],
|
||||
resolve: {
|
||||
isLoggedIn: AuthResolverService,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })],
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AppRoutingModule {}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import { FileStatusPipe } from './file-status.pipe';
|
|||
import { LoginComponent } from './login/login.component';
|
||||
import { AuthInterceptor } from './auth.interceptor';
|
||||
import { curray } from 'curray';
|
||||
import { SetupComponent } from './setup/setup.component';
|
||||
|
||||
curray();
|
||||
|
||||
|
|
@ -34,6 +35,7 @@ curray();
|
|||
TorrentStatusPipe,
|
||||
FileStatusPipe,
|
||||
LoginComponent,
|
||||
SetupComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
|
|
|||
15
client/src/app/auth-resolver.service.ts
Normal file
15
client/src/app/auth-resolver.service.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Resolve } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AuthResolverService implements Resolve<Observable<any>> {
|
||||
constructor(private authService: AuthService) {}
|
||||
|
||||
resolve() {
|
||||
return this.authService.isLoggedIn();
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ import {
|
|||
HttpEvent,
|
||||
HttpHandler,
|
||||
HttpInterceptor,
|
||||
HttpRequest,
|
||||
HttpRequest
|
||||
} from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
|
@ -20,7 +20,9 @@ export class AuthInterceptor implements HttpInterceptor {
|
|||
): Observable<HttpEvent<any>> {
|
||||
return next.handle(req).pipe(
|
||||
catchError((error: HttpErrorResponse) => {
|
||||
if (error && (error.status === 401 || error.status === 403)) {
|
||||
if (error && error.status === 402) {
|
||||
this.router.navigate(['/setup']);
|
||||
} else if (error && (error.status === 401 || error.status === 403)) {
|
||||
this.router.navigate(['/login']);
|
||||
}
|
||||
return throwError(error);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
|
||||
@Injectable({
|
||||
|
|
@ -8,6 +8,17 @@ import { Observable } from 'rxjs/internal/Observable';
|
|||
export class AuthService {
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
public isLoggedIn(): Observable<void> {
|
||||
return this.http.get<void>(`/Api/Authentication/IsLoggedIn`);
|
||||
}
|
||||
|
||||
public create(userName: string, password: string): Observable<void> {
|
||||
return this.http.post<void>(`/Api/Authentication/Create`, {
|
||||
userName,
|
||||
password,
|
||||
});
|
||||
}
|
||||
|
||||
public login(userName: string, password: string): Observable<void> {
|
||||
return this.http.post<void>(`/Api/Authentication/Login`, {
|
||||
userName,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-5-tablet is-4-desktop is-3-widescreen">
|
||||
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
|
||||
<img src="../../assets/logo.png" />
|
||||
<div class="box">
|
||||
<div class="field">
|
||||
|
|
@ -41,6 +41,7 @@
|
|||
class="button is-success"
|
||||
(click)="login()"
|
||||
[ngClass]="{ 'is-loading': loggingIn }"
|
||||
[disabled]="loggingIn"
|
||||
>
|
||||
Login
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
[(ngModel)]="settingDownloadFolder"
|
||||
/>
|
||||
</div>
|
||||
<p class="help">Path on the host where Real Debrid Client is hosted.</p>
|
||||
<p class="help">Path on the host where RealDebrid Client is hosted.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Maximum parallel downloads</label>
|
||||
|
|
|
|||
143
client/src/app/setup/setup.component.html
Normal file
143
client/src/app/setup/setup.component.html
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
<section class="hero is-dark is-fullheight">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
|
||||
<img src="../../assets/logo.png" />
|
||||
<div class="box" *ngIf="step === 1">
|
||||
<div class="notification is-primary">
|
||||
Welcome to RealDebrid Client. Please create your account by
|
||||
entering a username and password.
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="" class="label">Username</label>
|
||||
<div class="control has-icons-left">
|
||||
<input
|
||||
type="text"
|
||||
placeholder=""
|
||||
class="input"
|
||||
name="userName"
|
||||
[(ngModel)]="userName"
|
||||
required
|
||||
/>
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fa fa-envelope"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="" class="label" name="password">Password</label>
|
||||
<div class="control has-icons-left">
|
||||
<input
|
||||
type="password"
|
||||
class="input"
|
||||
required
|
||||
name="password"
|
||||
[(ngModel)]="password"
|
||||
/>
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fa fa-lock"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<button
|
||||
class="button is-success"
|
||||
(click)="setup()"
|
||||
[ngClass]="{ 'is-loading': working }"
|
||||
[disabled]="working"
|
||||
>
|
||||
Setup
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="notification is-danger is-light"
|
||||
*ngIf="error?.length > 0"
|
||||
>
|
||||
{{ error }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box" *ngIf="step === 2">
|
||||
<div class="notification is-primary">
|
||||
To be able to use the RealDebrid Client you need a premium
|
||||
subscription to download torrents.
|
||||
<br /><br />
|
||||
Not premium yet?
|
||||
<a
|
||||
href="https://real-debrid.com/?id=1348683"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>Use this link to sign up to RealDebrid.</a
|
||||
>
|
||||
<br /><br />
|
||||
To connect to RealDebrid please enter your Personal Prive API
|
||||
Token found here:
|
||||
<a
|
||||
href="https://real-debrid.com/apitoken"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>https://real-debrid.com/apitoken</a
|
||||
>.
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="" class="label">API Private Token</label>
|
||||
<div class="control has-icons-left">
|
||||
<input
|
||||
type="text"
|
||||
placeholder=""
|
||||
class="input"
|
||||
name="token"
|
||||
[(ngModel)]="token"
|
||||
required
|
||||
/>
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fa fa-envelope"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<button
|
||||
class="button is-success"
|
||||
(click)="setToken()"
|
||||
[ngClass]="{ 'is-loading': working }"
|
||||
[disabled]="working"
|
||||
>
|
||||
Setup
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="notification is-danger is-light"
|
||||
*ngIf="error?.length > 0"
|
||||
>
|
||||
{{ error }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box" *ngIf="step === 3">
|
||||
<div class="notification is-primary">
|
||||
You are now connected to RealDebrid! To setup Radarr or Sonarr,
|
||||
please following the instructions here:
|
||||
<a
|
||||
href="https://github.com/rogerfar/rdt-client/"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>https://github.com/rogerfar/rdt-client/</a
|
||||
>.
|
||||
</div>
|
||||
<div class="field">
|
||||
<button
|
||||
class="button is-success"
|
||||
(click)="close()"
|
||||
[ngClass]="{ 'is-loading': working }"
|
||||
[disabled]="working"
|
||||
>
|
||||
OK
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
0
client/src/app/setup/setup.component.scss
Normal file
0
client/src/app/setup/setup.component.scss
Normal file
66
client/src/app/setup/setup.component.ts
Normal file
66
client/src/app/setup/setup.component.ts
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { AuthService } from '../auth.service';
|
||||
import { Setting } from '../models/setting.model';
|
||||
import { SettingsService } from '../settings.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-setup',
|
||||
templateUrl: './setup.component.html',
|
||||
styleUrls: ['./setup.component.scss'],
|
||||
})
|
||||
export class SetupComponent implements OnInit {
|
||||
public userName: string;
|
||||
public password: string;
|
||||
public token: string;
|
||||
|
||||
public error: string;
|
||||
public working: boolean;
|
||||
|
||||
public step: number = 1;
|
||||
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private settingsService: SettingsService,
|
||||
private router: Router
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
public setup(): void {
|
||||
this.error = null;
|
||||
this.working = true;
|
||||
|
||||
this.authService.create(this.userName, this.password).subscribe(
|
||||
() => {
|
||||
this.step = 2;
|
||||
this.working = false;
|
||||
},
|
||||
(err) => {
|
||||
this.working = false;
|
||||
this.error = err.error;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public setToken(): void {
|
||||
const setting = new Setting();
|
||||
setting.settingId = 'RealDebridApiKey';
|
||||
setting.value = this.token;
|
||||
|
||||
this.settingsService.update([setting]).subscribe(
|
||||
() => {
|
||||
this.step = 3;
|
||||
this.working = false;
|
||||
},
|
||||
(err) => {
|
||||
this.working = false;
|
||||
this.error = err.error;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using RdtClient.Data.Models.Data;
|
||||
|
|
@ -33,5 +35,42 @@ namespace RdtClient.Data.Data
|
|||
fk.DeleteBehavior = DeleteBehavior.Restrict;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Seed()
|
||||
{
|
||||
var seedSettings = new List<Setting>
|
||||
{
|
||||
new Setting
|
||||
{
|
||||
SettingId = "RealDebridApiKey",
|
||||
Type = "String",
|
||||
Value = ""
|
||||
},
|
||||
new Setting
|
||||
{
|
||||
SettingId = "DownloadFolder",
|
||||
Type = "String",
|
||||
Value = "/data/downloads"
|
||||
},
|
||||
new Setting
|
||||
{
|
||||
SettingId = "DownloadLimit",
|
||||
Type = "Int32",
|
||||
Value = "10"
|
||||
}
|
||||
};
|
||||
|
||||
var dbSettings = await Settings.ToListAsync();
|
||||
foreach (var seedSetting in seedSettings)
|
||||
{
|
||||
var dbSetting = dbSettings.FirstOrDefault(m => m.SettingId == seedSetting.SettingId);
|
||||
|
||||
if (dbSetting == null)
|
||||
{
|
||||
await Settings.AddAsync(seedSetting);
|
||||
await SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using RdtClient.Data.Models.Data;
|
||||
|
||||
namespace RdtClient.Data.Data
|
||||
{
|
||||
public static class DataMigration
|
||||
{
|
||||
private static Boolean InDocker => Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true";
|
||||
|
||||
public static void Setup(IServiceScope serviceScope)
|
||||
{
|
||||
using var scope = serviceScope.ServiceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope();
|
||||
|
||||
var dataContext = scope.ServiceProvider.GetRequiredService<DataContext>();
|
||||
|
||||
dataContext.Database.Migrate();
|
||||
|
||||
Seed(dataContext);
|
||||
}
|
||||
|
||||
private static void Seed(DataContext dataContext)
|
||||
{
|
||||
var defaultDownloadPath = "/data/downloads";
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !InDocker)
|
||||
{
|
||||
defaultDownloadPath = @"C:\Downloads";
|
||||
}
|
||||
|
||||
var configuration = dataContext.Settings.FirstOrDefault();
|
||||
|
||||
if (configuration == null)
|
||||
{
|
||||
dataContext.Settings.Add(new Setting
|
||||
{
|
||||
SettingId = "RealDebridApiKey",
|
||||
Type = "String",
|
||||
Value = ""
|
||||
});
|
||||
|
||||
dataContext.Settings.Add(new Setting
|
||||
{
|
||||
SettingId = "DownloadFolder",
|
||||
Type = "String",
|
||||
Value = defaultDownloadPath
|
||||
});
|
||||
|
||||
dataContext.Settings.Add(new Setting
|
||||
{
|
||||
SettingId = "DownloadLimit",
|
||||
Type = "Int32",
|
||||
Value = "10"
|
||||
});
|
||||
|
||||
dataContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,50 @@ namespace RdtClient.Web.Controllers
|
|||
{
|
||||
_authentication = authentication;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[Route("IsLoggedIn")]
|
||||
[HttpGet]
|
||||
public async Task<ActionResult> IsLoggedIn()
|
||||
{
|
||||
if (User.Identity?.IsAuthenticated == false)
|
||||
{
|
||||
var user = await _authentication.GetUser();
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return StatusCode(402, "Setup required");
|
||||
}
|
||||
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[Route("Create")]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult> Create([FromBody] AuthControllerLoginRequest request)
|
||||
{
|
||||
var user = await _authentication.GetUser();
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
return StatusCode(401);
|
||||
}
|
||||
|
||||
var registerResult = await _authentication.Register(request.UserName, request.Password);
|
||||
|
||||
if (!registerResult.Succeeded)
|
||||
{
|
||||
return BadRequest(registerResult.Errors.First().Description);
|
||||
}
|
||||
|
||||
await _authentication.Login(request.UserName, request.Password);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[Route("Login")]
|
||||
|
|
@ -26,12 +70,7 @@ namespace RdtClient.Web.Controllers
|
|||
|
||||
if (user == null)
|
||||
{
|
||||
var registerResult = await _authentication.Register(request.UserName, request.Password);
|
||||
|
||||
if (!registerResult.Succeeded)
|
||||
{
|
||||
return BadRequest(registerResult.Errors.First().Description);
|
||||
}
|
||||
return StatusCode(402);
|
||||
}
|
||||
|
||||
var result = await _authentication.Login(request.UserName, request.Password);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ namespace RdtClient.Web
|
|||
{
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<DataContext>();
|
||||
await dbContext.Database.MigrateAsync();
|
||||
await dbContext.Seed();
|
||||
}
|
||||
|
||||
await host.RunAsync();
|
||||
|
|
|
|||
|
|
@ -6,24 +6,6 @@
|
|||
<UserSecretsId>94c24cba-f03f-4453-a671-3640b517c573</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="serviceinstall.bat" />
|
||||
<None Remove="serviceremove.bat" />
|
||||
<None Remove="startup.bat" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="serviceinstall.bat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="serviceremove.bat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="startup.bat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="5.0.1" />
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
|
|
@ -85,7 +86,7 @@ namespace RdtClient.Web
|
|||
Service.DiConfig.Config(services);
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger, DataContext dataContext)
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
@echo off
|
||||
set installpath=%~dp0
|
||||
NET SESSION >nul 2>&1
|
||||
IF %ERRORLEVEL% EQU 0 (
|
||||
echo adding firewall rules...
|
||||
netsh.exe advfirewall firewall add rule name="RealDebridClient" dir=in action=allow program="%installpath%RdtClient.Web.exe" enable=yes > nul
|
||||
echo installing service...
|
||||
sc create RealDebridClient binPath="%installpath%RdtClient.Web.exe" start=auto
|
||||
timeout /t 5 /nobreak > NUL
|
||||
net start RealDebridClient
|
||||
) ELSE (
|
||||
echo ######## ######## ######## ####### ########
|
||||
echo ## ## ## ## ## ## ## ## ##
|
||||
echo ## ## ## ## ## ## ## ## ##
|
||||
echo ###### ######## ######## ## ## ########
|
||||
echo ## ## ## ## ## ## ## ## ##
|
||||
echo ## ## ## ## ## ## ## ## ##
|
||||
echo ######## ## ## ## ## ####### ## ##
|
||||
echo.
|
||||
echo.
|
||||
echo ####### ERROR: ADMINISTRATOR PRIVILEGES REQUIRED #########
|
||||
echo This script must be run as administrator to work properly!
|
||||
echo If you're seeing this after clicking on a start menu icon,
|
||||
echo then right click on the shortcut and select "Run As Administrator".
|
||||
echo ##########################################################
|
||||
echo.
|
||||
PAUSE
|
||||
EXIT /B 1
|
||||
)
|
||||
@echo ON
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
@echo off
|
||||
set installpath=%~dp0
|
||||
NET SESSION >nul 2>&1
|
||||
IF %ERRORLEVEL% EQU 0 (
|
||||
echo removing firewall rules...
|
||||
netsh.exe advfirewall firewall remove rule name="RealDebridClient" > nul
|
||||
echo removing service...
|
||||
net stop RealDebridClient
|
||||
timeout /t 5 /nobreak > NUL
|
||||
sc delete RealDebridClient
|
||||
) ELSE (
|
||||
echo ######## ######## ######## ####### ########
|
||||
echo ## ## ## ## ## ## ## ## ##
|
||||
echo ## ## ## ## ## ## ## ## ##
|
||||
echo ###### ######## ######## ## ## ########
|
||||
echo ## ## ## ## ## ## ## ## ##
|
||||
echo ## ## ## ## ## ## ## ## ##
|
||||
echo ######## ## ## ## ## ####### ## ##
|
||||
echo.
|
||||
echo.
|
||||
echo ####### ERROR: ADMINISTRATOR PRIVILEGES REQUIRED #########
|
||||
echo This script must be run as administrator to work properly!
|
||||
echo If you're seeing this after clicking on a start menu icon,
|
||||
echo then right click on the shortcut and select "Run As Administrator".
|
||||
echo ##########################################################
|
||||
echo.
|
||||
PAUSE
|
||||
EXIT /B 1
|
||||
)
|
||||
@echo ON
|
||||
|
|
@ -1 +0,0 @@
|
|||
dotnet RdtClient.Web.dll
|
||||
Loading…
Reference in a new issue