feat: auth page
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { provideHttpClient } from "@angular/common/http";
|
import { provideHttpClient, withFetch } from "@angular/common/http";
|
||||||
import { ApplicationConfig, isDevMode, provideZoneChangeDetection } from "@angular/core";
|
import { ApplicationConfig, isDevMode, provideZoneChangeDetection } from "@angular/core";
|
||||||
import { provideRouter } from "@angular/router";
|
import { provideRouter } from "@angular/router";
|
||||||
import { provideServiceWorker } from "@angular/service-worker";
|
import { provideServiceWorker } from "@angular/service-worker";
|
||||||
@@ -12,6 +12,6 @@ export const appConfig: ApplicationConfig = {
|
|||||||
enabled: !isDevMode(),
|
enabled: !isDevMode(),
|
||||||
registrationStrategy: "registerWhenStable:30000",
|
registrationStrategy: "registerWhenStable:30000",
|
||||||
}),
|
}),
|
||||||
provideHttpClient(),
|
provideHttpClient(withFetch()),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Route } from "@angular/router";
|
import { Route } from "@angular/router";
|
||||||
|
import { AuthComponent } from "./components/auth/auth.component";
|
||||||
import { DetailComponent } from "./components/detail/detail.component";
|
import { DetailComponent } from "./components/detail/detail.component";
|
||||||
import { HomeComponent } from "./components/home/home.component";
|
import { HomeComponent } from "./components/home/home.component";
|
||||||
import { ReaderComponent } from "./components/reader/reader.component";
|
import { ReaderComponent } from "./components/reader/reader.component";
|
||||||
@@ -10,4 +11,8 @@ export const appRoutes: Route[] = [
|
|||||||
},
|
},
|
||||||
{ path: "detail", component: DetailComponent },
|
{ path: "detail", component: DetailComponent },
|
||||||
{ path: "reader", component: ReaderComponent },
|
{ path: "reader", component: ReaderComponent },
|
||||||
|
{
|
||||||
|
path: "auth",
|
||||||
|
component: AuthComponent,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
34
apps/NwaifuAnime/src/app/components/auth/auth.component.html
Normal file
34
apps/NwaifuAnime/src/app/components/auth/auth.component.html
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<div class="flex flex-col m-6">
|
||||||
|
<div class="mangalib-auth">
|
||||||
|
<h2>Авторизация в MangaLib</h2>
|
||||||
|
<ol class="list-decimal flex flex-col gap-4">
|
||||||
|
<li>
|
||||||
|
<p class="font-bold">Авторизация через токен</p>
|
||||||
|
<div class="flex flex-row gap-4">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Token"
|
||||||
|
class="outline-none border-md border px-2"
|
||||||
|
#libSocialToken
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
(click)="setLibSocialToken()"
|
||||||
|
class="hover:bg-slate-600 bg-slate-400 p-3 rounded-md text-white"
|
||||||
|
>
|
||||||
|
Сохранить
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Вход через скрипт TamperMonkey. Если нет кнопки, значит вы не установили скрипт
|
||||||
|
<a
|
||||||
|
href="https://test-front.mangalib.me"
|
||||||
|
class="hover:bg-slate-600 bg-slate-400 p-3 rounded-md text-white tamperMonkey"
|
||||||
|
>
|
||||||
|
Вход
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.tamperMonkey {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
58
apps/NwaifuAnime/src/app/components/auth/auth.component.ts
Normal file
58
apps/NwaifuAnime/src/app/components/auth/auth.component.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { CommonModule } from "@angular/common";
|
||||||
|
import { AfterViewInit, Component, ElementRef, OnDestroy, ViewChild } from "@angular/core";
|
||||||
|
import { ActivatedRoute, Router, RouterLink } from "@angular/router";
|
||||||
|
import { Subject, takeUntil } from "rxjs";
|
||||||
|
import { RulibAuthService } from "../../services/parsers/rulib/rulib.auth.service";
|
||||||
|
import { EAuthTokenService } from "./enum";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "app-auth",
|
||||||
|
templateUrl: "./auth.component.html",
|
||||||
|
styleUrls: ["./auth.component.less"],
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule, RouterLink],
|
||||||
|
})
|
||||||
|
export class AuthComponent implements AfterViewInit, OnDestroy {
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
@ViewChild("libSocialToken") libSocialToken: ElementRef<HTMLInputElement> | null = null;
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
private rulibAuthService: RulibAuthService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
private setToken(service: EAuthTokenService, token: string) {
|
||||||
|
switch (service) {
|
||||||
|
case EAuthTokenService.RULIB:
|
||||||
|
this.rulibAuthService.setToken(token);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.router.navigate(["/", "auth"]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.router.navigate(["/"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLibSocialToken() {
|
||||||
|
if (this.libSocialToken) {
|
||||||
|
const token = this.libSocialToken.nativeElement.value;
|
||||||
|
this.setToken(EAuthTokenService.RULIB, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
this.route.queryParams.pipe(takeUntil(this.destroy$)).subscribe((params) => {
|
||||||
|
const { token, service } = params;
|
||||||
|
if (token && service) {
|
||||||
|
this.setToken(service as EAuthTokenService, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (this.libSocialToken) {
|
||||||
|
this.libSocialToken.nativeElement.value = this.rulibAuthService.getToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
3
apps/NwaifuAnime/src/app/components/auth/enum.ts
Normal file
3
apps/NwaifuAnime/src/app/components/auth/enum.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export enum EAuthTokenService {
|
||||||
|
RULIB = "rulib",
|
||||||
|
}
|
||||||
@@ -1,9 +1,14 @@
|
|||||||
<div class="flex flex-col items-center">
|
<div class="flex flex-col items-center">
|
||||||
|
@if (needAuth) {
|
||||||
|
<h1>Необходима авторизация</h1>
|
||||||
|
<a routerLink="/auth" class="text-center bg-slate-600 text-white p-3 rounded-md mb-4">Войти</a>
|
||||||
|
}
|
||||||
@if (detail_item) {
|
@if (detail_item) {
|
||||||
<h1>{{ detail_item.name }}</h1>
|
<h1>{{ detail_item.name }}</h1>
|
||||||
<h2>{{ detail_item.rus_name }}</h2>
|
<h2>{{ detail_item.rus_name }}</h2>
|
||||||
<img [src]="detail_item.cover.default" [alt]="detail_item.slug" />
|
<img [src]="detail_item.cover.default" [alt]="detail_item.slug" />
|
||||||
|
|
||||||
|
@if (!needAuth) {
|
||||||
<details class="w-full">
|
<details class="w-full">
|
||||||
<summary class="text-center sticky top-0 bg-white z-10 py-2">
|
<summary class="text-center sticky top-0 bg-white z-10 py-2">
|
||||||
<h3>Главы</h3>
|
<h3>Главы</h3>
|
||||||
@@ -35,4 +40,5 @@
|
|||||||
Читать
|
Читать
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { SearchService } from "../../services/search.service";
|
|||||||
export class DetailComponent implements AfterViewInit, OnDestroy {
|
export class DetailComponent implements AfterViewInit, OnDestroy {
|
||||||
detail_item: Data | null = null;
|
detail_item: Data | null = null;
|
||||||
chapters: IRulibChaptersResult = { data: [] };
|
chapters: IRulibChaptersResult = { data: [] };
|
||||||
|
needAuth: boolean = false;
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
@@ -27,15 +28,27 @@ export class DetailComponent implements AfterViewInit, OnDestroy {
|
|||||||
this.searchService
|
this.searchService
|
||||||
.getDetails(url)
|
.getDetails(url)
|
||||||
.pipe(takeUntil(this.destroy$))
|
.pipe(takeUntil(this.destroy$))
|
||||||
.subscribe((data) => {
|
.subscribe({
|
||||||
|
next: (data) => {
|
||||||
this.detail_item = data.data;
|
this.detail_item = data.data;
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
console.log(error);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
this.searchService
|
this.searchService
|
||||||
.getChapters(url)
|
.getChapters(url)
|
||||||
.pipe(takeUntil(this.destroy$))
|
.pipe(takeUntil(this.destroy$))
|
||||||
.subscribe((data) => {
|
.subscribe({
|
||||||
|
next: (data) => {
|
||||||
this.chapters = data;
|
this.chapters = data;
|
||||||
console.log(data);
|
if (data.data.length === 0) {
|
||||||
|
this.needAuth = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
console.log(error);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import { HttpClient } from "@angular/common/http";
|
||||||
import { Injectable } from "@angular/core";
|
import { Injectable } from "@angular/core";
|
||||||
import { Observable, catchError, map, throwError } from "rxjs";
|
import { Observable, catchError, map, throwError } from "rxjs";
|
||||||
import { Parser } from "../parser";
|
import { Parser } from "../parser";
|
||||||
|
import { RulibAuthService } from "./rulib.auth.service";
|
||||||
import { IRulibChapterResult } from "./rulib.chapter.dto";
|
import { IRulibChapterResult } from "./rulib.chapter.dto";
|
||||||
import { IRulibChaptersResult } from "./rulib.chapters.dto";
|
import { IRulibChaptersResult } from "./rulib.chapters.dto";
|
||||||
import { IRulibDetailResult } from "./rulib.detail.dto";
|
import { IRulibDetailResult } from "./rulib.detail.dto";
|
||||||
@@ -19,6 +21,13 @@ export class LibSocialParserService extends Parser {
|
|||||||
return "https://img33.imgslib.link";
|
return "https://img33.imgslib.link";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private rulibAuthService: RulibAuthService,
|
||||||
|
override http: HttpClient,
|
||||||
|
) {
|
||||||
|
super(http);
|
||||||
|
}
|
||||||
|
|
||||||
searchManga(query: string): Observable<IRulibSearchResult> {
|
searchManga(query: string): Observable<IRulibSearchResult> {
|
||||||
return this.http
|
return this.http
|
||||||
.get(
|
.get(
|
||||||
@@ -38,6 +47,7 @@ export class LibSocialParserService extends Parser {
|
|||||||
return this.http
|
return this.http
|
||||||
.get(
|
.get(
|
||||||
`${this.url}/api/manga/${slug_url}?fields[]=summary&fields[]=genres&fields[]=tags&fields[]=authors`,
|
`${this.url}/api/manga/${slug_url}?fields[]=summary&fields[]=genres&fields[]=tags&fields[]=authors`,
|
||||||
|
{ headers: { Authorization: "Bearer " + this.rulibAuthService.getToken() } },
|
||||||
)
|
)
|
||||||
.pipe(
|
.pipe(
|
||||||
map((data: object) => {
|
map((data: object) => {
|
||||||
@@ -50,7 +60,11 @@ export class LibSocialParserService extends Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getChapters(url: string): Observable<IRulibChaptersResult> {
|
getChapters(url: string): Observable<IRulibChaptersResult> {
|
||||||
return this.http.get(`${this.url}/api/manga/${url}/chapters`).pipe(
|
return this.http
|
||||||
|
.get(`${this.url}/api/manga/${url}/chapters`, {
|
||||||
|
headers: { Authorization: "Bearer " + this.rulibAuthService.getToken() },
|
||||||
|
})
|
||||||
|
.pipe(
|
||||||
map((data) => {
|
map((data) => {
|
||||||
return data as IRulibChaptersResult;
|
return data as IRulibChaptersResult;
|
||||||
}),
|
}),
|
||||||
@@ -62,7 +76,9 @@ export class LibSocialParserService extends Parser {
|
|||||||
|
|
||||||
getChapter(url: string, chapter: string, volume: string): Observable<IRulibChapterResult> {
|
getChapter(url: string, chapter: string, volume: string): Observable<IRulibChapterResult> {
|
||||||
return this.http
|
return this.http
|
||||||
.get(`${this.url}/api/manga/${url}/chapter?number=${chapter}&volume=${volume}`)
|
.get(`${this.url}/api/manga/${url}/chapter?number=${chapter}&volume=${volume}`, {
|
||||||
|
headers: { Authorization: "Bearer " + this.rulibAuthService.getToken() },
|
||||||
|
})
|
||||||
.pipe(
|
.pipe(
|
||||||
map((data) => data as IRulibChapterResult),
|
map((data) => data as IRulibChapterResult),
|
||||||
catchError((error) => throwError(() => `Now found ${error}`)),
|
catchError((error) => throwError(() => `Now found ${error}`)),
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { Injectable } from "@angular/core";
|
||||||
|
@Injectable({
|
||||||
|
providedIn: "root",
|
||||||
|
})
|
||||||
|
export class RulibAuthService {
|
||||||
|
setToken(token: string) {
|
||||||
|
localStorage.setItem("token", token);
|
||||||
|
}
|
||||||
|
|
||||||
|
getToken(): string {
|
||||||
|
return localStorage.getItem("token") ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Проверка токена
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user