From e4b09f7bb8cc26c49402c7d9ca601db78c51c4c2 Mon Sep 17 00:00:00 2001 From: metal079 Date: Mon, 18 Dec 2023 00:54:38 -0600 Subject: [PATCH] discord auth and upscale button support --- src/app/app.module.ts | 9 +++- src/app/home/faq/faq.component.css | 14 +++++++ src/app/home/faq/faq.component.html | 10 +++++ src/app/home/faq/faq.component.ts | 43 +++++++++++++++++++- src/app/home/options/options.component.html | 25 +++++++++++- src/app/home/options/options.component.ts | 17 +++++++- src/app/shared.service.ts | 15 +++++++ src/app/stable-diffusion.service.ts | 11 ++++- src/assets/DiscordLogin.png | Bin 0 -> 18854 bytes src/environments/environment.prod.ts | 6 +++ src/environments/environment.ts | 6 +++ src/modules/home.module.ts | 5 ++- 12 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 src/assets/DiscordLogin.png create mode 100644 src/environments/environment.prod.ts create mode 100644 src/environments/environment.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 5f7ee5b..9b7dc8c 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -4,11 +4,17 @@ import { BrowserModule } from '@angular/platform-browser'; import { HomeModule } from '../modules/home.module'; // updated import import { FormsModule } from '@angular/forms'; import { SharedService } from 'src/app/shared.service'; - +import { RouterModule, Routes } from '@angular/router'; import { AppComponent } from './app.component'; import { ServiceWorkerModule } from '@angular/service-worker'; +import { FaqComponent } from './home/faq/faq.component'; + +const routes: Routes = [ + { path: 'faq', component: FaqComponent }, +]; + @NgModule({ declarations: [ AppComponent, @@ -18,6 +24,7 @@ import { ServiceWorkerModule } from '@angular/service-worker'; HttpClientModule, FormsModule, HomeModule, + RouterModule.forRoot(routes), ServiceWorkerModule.register('ngsw-worker.js', { enabled: true, // Register the ServiceWorker as soon as the application is stable diff --git a/src/app/home/faq/faq.component.css b/src/app/home/faq/faq.component.css index 8b5cbb3..63e230b 100644 --- a/src/app/home/faq/faq.component.css +++ b/src/app/home/faq/faq.component.css @@ -29,3 +29,17 @@ } } + +button img { + height: 50px; + width: auto; + margin-right: 10px; + border: 0; + padding: 0; +} + +button { + background-color: #2fa5e9; + border: 0; + padding: 0; +} \ No newline at end of file diff --git a/src/app/home/faq/faq.component.html b/src/app/home/faq/faq.component.html index 6f95975..34cfd14 100644 --- a/src/app/home/faq/faq.component.html +++ b/src/app/home/faq/faq.component.html @@ -5,6 +5,16 @@

FAQ

+
+
+ Login with Discord! Supporters get access to more features! (Upscaling images with more detail!) +
+
+
+ +
What are some tips for good images? diff --git a/src/app/home/faq/faq.component.ts b/src/app/home/faq/faq.component.ts index 3d4d530..664b0fc 100644 --- a/src/app/home/faq/faq.component.ts +++ b/src/app/home/faq/faq.component.ts @@ -1,6 +1,10 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { Subscription } from 'rxjs'; import { SharedService } from 'src/app/shared.service'; +import { ActivatedRoute } from '@angular/router'; +import { HttpClient } from '@angular/common/http'; +import { StableDiffusionService } from 'src/app/stable-diffusion.service'; +import { environment } from 'src/environments/environment'; @Component({ selector: 'app-faq', @@ -8,7 +12,10 @@ import { SharedService } from 'src/app/shared.service'; styleUrls: ['./faq.component.css'] }) export class FaqComponent implements OnInit, OnDestroy { + private clientId = '1186062405168549949'; + private redirectUri = encodeURIComponent(environment.discordRedirectUri); prompt!: string; + serverMember: boolean = false; characterNames: string[] = [ 'Amy Rose', 'Barry the quokka', 'Big the cat', 'Blaze the cat', 'Bunnie Rabbot', 'Charmy the bee', 'Cosmo the seedrian', 'Cream the rabbit', 'Eggman', 'Espio the chameleon', 'Fiona Fox', 'Honey the cat', @@ -25,12 +32,31 @@ export class FaqComponent implements OnInit, OnDestroy { private subscription: Subscription = new Subscription(); - constructor(private sharedService: SharedService) { } + constructor(private sharedService: SharedService + , private route: ActivatedRoute + , private http: HttpClient + , private stableDiffusionService: StableDiffusionService) { } ngOnInit() { this.subscription = this.sharedService.getPrompt().subscribe(value => { this.prompt = value; }); + + + this.route.queryParams.subscribe(params => { + console.log('Query Params:', params); // Add this to check if queryParams are received + const code = params['code']; + if (code) { + this.exchangeCode(code); + } + }); + + // Discord userdata check + this.sharedService.getUserData().subscribe(userData => { + if (userData) { + this.serverMember = userData.is_member_of_your_guild; + } + }); } changePrompt(newPrompt: string) { @@ -53,4 +79,19 @@ export class FaqComponent implements OnInit, OnDestroy { ngOnDestroy() { this.subscription.unsubscribe(); } + + authenticateWithDiscord() { + window.location.href = `https://discord.com/api/oauth2/authorize?client_id=${this.clientId}&redirect_uri=${this.redirectUri}&response_type=code&scope=identify%20guilds`; + } + + private exchangeCode(code: string) { + this.stableDiffusionService.discordLogin({ code: code }) + .subscribe(response => { + console.log(response); + this.sharedService.setUserData(response); // Assuming response contains user data + }, error => { + console.error(error); + }); +} + } diff --git a/src/app/home/options/options.component.html b/src/app/home/options/options.component.html index 4c9f2d7..9e928f3 100644 --- a/src/app/home/options/options.component.html +++ b/src/app/home/options/options.component.html @@ -12,8 +12,9 @@
- +
+ ? + + + + + + ? + +
@@ -175,4 +191,11 @@
+ + + \ No newline at end of file diff --git a/src/app/home/options/options.component.ts b/src/app/home/options/options.component.ts index a3a2d08..d0340b8 100644 --- a/src/app/home/options/options.component.ts +++ b/src/app/home/options/options.component.ts @@ -55,6 +55,8 @@ export class OptionsComponent { API_URL: string = ""; referenceImage?: MobiansImage; currentSeed?: number; + supporter: boolean = false; + serverMember: boolean = false; @Input() inpaintMask?: string; @@ -98,6 +100,15 @@ export class OptionsComponent { this.referenceImage = undefined; } }); + + // Discord userdata check + this.sharedService.getUserData().subscribe(userData => { + if (userData) { + this.supporter = userData.has_required_role; + this.serverMember = userData.is_member_of_your_guild; + console.log('premium member!'); + } + }); } ngOnDestroy() { @@ -239,7 +250,11 @@ export class OptionsComponent { } // Send job to django api and retrieve job id. - submitJob() { + submitJob(upscale: boolean = false) { + if (upscale) { + this.generationRequest.job_type = "upscale"; + } + // Disable generation button this.enableGenerationButton = false; diff --git a/src/app/shared.service.ts b/src/app/shared.service.ts index e9b6048..2d6e924 100644 --- a/src/app/shared.service.ts +++ b/src/app/shared.service.ts @@ -10,6 +10,8 @@ export class SharedService { private _generationRequest: BehaviorSubject = new BehaviorSubject(null); private _images: BehaviorSubject = new BehaviorSubject([]); private _referenceImage: BehaviorSubject = new BehaviorSubject(null); + private _userData: BehaviorSubject = new BehaviorSubject(null); + constructor() { } @@ -75,4 +77,17 @@ export class SharedService { getReferenceImageValue(): MobiansImage | null { return this._referenceImage.getValue(); } + + setUserData(value: any) { + this._userData.next(value); + } + + getUserData(): Observable { + return this._userData.asObservable(); + } + + getUserDataValue(): any { + return this._userData.getValue(); + } + } diff --git a/src/app/stable-diffusion.service.ts b/src/app/stable-diffusion.service.ts index af0b160..efc6b8b 100644 --- a/src/app/stable-diffusion.service.ts +++ b/src/app/stable-diffusion.service.ts @@ -1,13 +1,13 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; +import { environment } from 'src/environments/environment'; @Injectable({ providedIn: 'root', }) export class StableDiffusionService { - // private apiBaseUrl = 'http://76.157.184.213:9000'; - private apiBaseUrl = 'https://mobians.azurewebsites.net' + private apiBaseUrl = environment.apiBaseUrl; constructor(private http: HttpClient) {} @@ -31,4 +31,11 @@ export class StableDiffusionService { const body = JSON.stringify(data); return this.http.post(url, body, {'headers':headers}); } + + discordLogin(data: any): Observable { + const url = `${this.apiBaseUrl}/discord_auth/`; // note the trailing slash + const headers = { 'content-type': 'application/json' }; + const body = JSON.stringify(data); + return this.http.post(url, body, {'headers':headers}); + } } diff --git a/src/assets/DiscordLogin.png b/src/assets/DiscordLogin.png new file mode 100644 index 0000000000000000000000000000000000000000..a67d605f6a1c848b873c7b3404b35c6fa92d30e8 GIT binary patch literal 18854 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