dev into staging #442
| @@ -12,6 +12,9 @@ from bot_api.logging.api_logger import ApiLogger | ||||
| from bot_api.model.settings_dto import SettingsDTO | ||||
| from bot_api.model.version_dto import VersionDTO | ||||
| from bot_api.route.route import Route | ||||
| from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum | ||||
| from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings | ||||
| from bot_data.model.technician_config import TechnicianConfig | ||||
|  | ||||
|  | ||||
| class GuiController: | ||||
| @@ -82,3 +85,11 @@ class GuiController: | ||||
|         ) | ||||
|         self._mailer.send_mail(mail) | ||||
|         return "", 200 | ||||
|  | ||||
|     @Route.get(f"{BasePath}/has-feature-flag/<flag>") | ||||
|     async def has_feature_flag(self, flag: str): | ||||
|         settings: TechnicianConfig = self._config.get_configuration(TechnicianConfig) | ||||
|         return { | ||||
|             "key": flag, | ||||
|             "value": FeatureFlagsSettings.get_flag_from_dict(settings.feature_flags, FeatureFlagsEnum(flag)), | ||||
|         } | ||||
|   | ||||
| @@ -28,3 +28,5 @@ class FeatureFlagsEnum(Enum): | ||||
|     technician_full_access = "TechnicianFullAccess" | ||||
|     steam_special_offers = "SteamSpecialOffers" | ||||
|     scheduled_events = "ScheduledEvents" | ||||
|     basic_registration = "BasicRegistration" | ||||
|     basic_login = "BasicLogin" | ||||
|   | ||||
| @@ -30,6 +30,8 @@ class FeatureFlagsSettings(ConfigurationModelABC): | ||||
|         FeatureFlagsEnum.technician_full_access.value: False,  # 03.10.2023 #393 | ||||
|         FeatureFlagsEnum.steam_special_offers.value: False,  # 11.10.2023 #188 | ||||
|         FeatureFlagsEnum.scheduled_events.value: False,  # 14.11.2023 #410 | ||||
|         FeatureFlagsEnum.basic_registration.value: False,  # 19.11.2023 #440 | ||||
|         FeatureFlagsEnum.basic_login.value: False,  # 19.11.2023 #440 | ||||
|     } | ||||
|  | ||||
|     def __init__(self, **kwargs: dict): | ||||
|   | ||||
| @@ -50,4 +50,6 @@ type Query { | ||||
|     technicianConfig: TechnicianConfig | ||||
|     possibleFeatureFlags: [String] | ||||
|     discord: Discord | ||||
|  | ||||
|     hasFeatureFlag(flag: String): FeatureFlag | ||||
| } | ||||
| @@ -1,7 +1,9 @@ | ||||
| from cpl_core.configuration import ConfigurationABC | ||||
| from cpl_discord.service import DiscordBotServiceABC | ||||
| from cpl_query.extension import List | ||||
|  | ||||
| from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum | ||||
| from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings | ||||
| from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC | ||||
| from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC | ||||
| from bot_data.abc.client_repository_abc import ClientRepositoryABC | ||||
| @@ -22,6 +24,7 @@ from bot_data.abc.user_joined_voice_channel_repository_abc import ( | ||||
| from bot_data.abc.user_repository_abc import UserRepositoryABC | ||||
| from bot_data.abc.user_warnings_repository_abc import UserWarningsRepositoryABC | ||||
| from bot_data.model.short_role_name_position_enum import ShortRoleNamePositionEnum | ||||
| from bot_data.model.technician_config import TechnicianConfig | ||||
| from bot_graphql.abc.query_abc import QueryABC | ||||
| from bot_graphql.filter.achievement_filter import AchievementFilter | ||||
| from bot_graphql.filter.auto_role_filter import AutoRoleFilter | ||||
| @@ -45,6 +48,7 @@ from modules.achievements.achievement_service import AchievementService | ||||
| class Query(QueryABC): | ||||
|     def __init__( | ||||
|         self, | ||||
|         config: ConfigurationABC, | ||||
|         bot: DiscordBotServiceABC, | ||||
|         auto_roles: AutoRoleRepositoryABC, | ||||
|         clients: ClientRepositoryABC, | ||||
| @@ -65,6 +69,8 @@ class Query(QueryABC): | ||||
|     ): | ||||
|         QueryABC.__init__(self, "Query") | ||||
|  | ||||
|         self._config = config | ||||
|  | ||||
|         self.add_collection("autoRole", lambda *_: auto_roles.get_auto_roles(), AutoRoleFilter) | ||||
|         self.add_collection( | ||||
|             "autoRoleRule", | ||||
| @@ -120,3 +126,17 @@ class Query(QueryABC): | ||||
|  | ||||
|         self.set_field("possibleFeatureFlags", lambda *_: [e.value for e in FeatureFlagsEnum]) | ||||
|         self.set_field("discord", lambda *_: Discord(bot.guilds, List(any).extend(bot.users))) | ||||
|  | ||||
|         self.set_field( | ||||
|             "hasFeatureFlag", | ||||
|             lambda *_, **kwargs: self._resolve_has_feature_flag(*_, **kwargs), | ||||
|         ) | ||||
|  | ||||
|     def _resolve_has_feature_flag(self, *_, **kwargs): | ||||
|         settings: TechnicianConfig = self._config.get_configuration(TechnicianConfig) | ||||
|         if "flag" not in kwargs: | ||||
|             return False | ||||
|         return { | ||||
|             "key": kwargs["flag"], | ||||
|             "value": FeatureFlagsSettings.get_flag_from_dict(settings.feature_flags, FeatureFlagsEnum(kwargs["flag"])), | ||||
|         } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "web", | ||||
|     "version": "1.2.dev410", | ||||
|     "version": "1.2.dev440", | ||||
|     "scripts": { | ||||
|         "ng": "ng", | ||||
|         "update-version": "ts-node update-version.ts", | ||||
|   | ||||
| @@ -108,6 +108,15 @@ export class Queries { | ||||
|     } | ||||
|   `; | ||||
|  | ||||
|   static hasFeatureFlag = ` | ||||
|     query HasFeatureFlag($flag: String) { | ||||
|       hasFeatureFlag(flag: $flag) { | ||||
|         key | ||||
|         value | ||||
|       } | ||||
|     } | ||||
|   `; | ||||
|  | ||||
|   static hasServerFeatureFlag = ` | ||||
|     query HasServerFeatureFlag($filter: ServerFilter, $flag: String) { | ||||
|       servers(filter: $filter) { | ||||
|   | ||||
| @@ -4,7 +4,9 @@ | ||||
|       <form [formGroup]="loginForm"> | ||||
|         <h1>{{'auth.header' | translate}}</h1> | ||||
|         <div class="input-field"> | ||||
|           <input type="email" pInputText formControlName="email" placeholder="{{'common.email' | translate}}" [ngClass]="{ 'invalid-feedback-input': submitted && ( | ||||
|           <input [disabled]="!basicLoginFeatureFlags" type="email" pInputText formControlName="email" | ||||
|                  placeholder="{{'common.email' | translate}}" | ||||
|                  [ngClass]="{ 'invalid-feedback-input': submitted && ( | ||||
|                             (loginForm.controls.email.errors && loginForm.controls.email.errors['required'] || authUserAtrErrors.email.required) || | ||||
|                             (authUserAtrErrors.email.wrongData) || | ||||
|                             (authUserAtrErrors.email.notConfirmed) | ||||
| @@ -24,7 +26,8 @@ | ||||
|               styleClass="p-password p-component p-inputwrapper p-input-icon-right" | ||||
|               Remove after update! | ||||
|           --> | ||||
|           <p-password formControlName="password" placeholder="{{'auth.login.password' | translate}}" [ngClass]="{ 'invalid-feedback-input': submitted && ( | ||||
|           <p-password [disabled]="!basicLoginFeatureFlags" formControlName="password" | ||||
|                       placeholder="{{'auth.login.password' | translate}}" [ngClass]="{ 'invalid-feedback-input': submitted && ( | ||||
|                             (loginForm.controls.password.errors && loginForm.controls.password.errors['required'] || authUserAtrErrors.password.required) || | ||||
|                             (authUserAtrErrors.password.wrongData) | ||||
|                         )}" [toggleMask]="true" [feedback]="false" | ||||
| @@ -39,17 +42,18 @@ | ||||
|         </div> | ||||
|         <div class="login-form-submit"> | ||||
|           <button pButton label="{{'auth.login.login' | translate}}" class="btn login-form-submit-btn" (click)="login()" | ||||
|                   [disabled]="loginForm.invalid"></button> | ||||
|                   [disabled]="loginForm.invalid || !basicLoginFeatureFlags"></button> | ||||
|         </div> | ||||
|         <div class="login-form-sub-button-wrapper" *ngIf="!code && !state"> | ||||
|           <div class="login-form-sub-btn-wrapper"> | ||||
|             <button pButton label="{{'auth.login.login_with_discord' | translate}}" class="btn login-form-sub-btn" (click)="discordLogin()"></button> | ||||
|             <button pButton label="{{'auth.login.login_with_discord' | translate}}" class="btn login-form-sub-btn" | ||||
|                     (click)="discordLogin()"></button> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="login-form-sub-button-wrapper"> | ||||
|           <div class="login-form-sub-btn-wrapper"> | ||||
|             <button pButton label="{{'auth.login.register' | translate}}" class="btn login-form-sub-btn" | ||||
|                     (click)="register()"></button> | ||||
|                     (click)="register()" [disabled]="!basicRegistrationFeatureFlags"></button> | ||||
|           </div> | ||||
|           <div class="login-form-sub-btn-wrapper"> | ||||
|             <button pButton label="{{'auth.login.forgot_password' | translate}}" | ||||
|   | ||||
| @@ -13,6 +13,7 @@ import { ThemeService } from "src/app/services/theme/theme.service"; | ||||
| import { throwError } from "rxjs"; | ||||
| import { TranslateService } from "@ngx-translate/core"; | ||||
| import { ConfirmationDialogService } from "../../../../services/confirmation-dialog/confirmation-dialog.service"; | ||||
| import { GuiService } from "../../../../services/gui/gui.service"; | ||||
|  | ||||
| @Component({ | ||||
|   selector: "app-login", | ||||
| @@ -32,6 +33,8 @@ export class LoginComponent implements OnInit { | ||||
|   state!: string; | ||||
|   user!: AuthUserDTO; | ||||
|   oAuthId!: string; | ||||
|   public basicLoginFeatureFlags = false; | ||||
|   public basicRegistrationFeatureFlags = false; | ||||
|  | ||||
|   constructor( | ||||
|     private authService: AuthService, | ||||
| @@ -41,11 +44,19 @@ export class LoginComponent implements OnInit { | ||||
|     private themeService: ThemeService, | ||||
|     private route: ActivatedRoute, | ||||
|     private confirmDialog: ConfirmationDialogService, | ||||
|     private translate: TranslateService | ||||
|     private translate: TranslateService, | ||||
|     private gui: GuiService | ||||
|   ) { | ||||
|   } | ||||
|  | ||||
|   ngOnInit(): void { | ||||
|     this.gui.hasFeatureFlag("BasicLogin").subscribe(flag => { | ||||
|       this.basicLoginFeatureFlags = flag.value; | ||||
|     }); | ||||
|     this.gui.hasFeatureFlag("BasicRegistration").subscribe(flag => { | ||||
|       this.basicRegistrationFeatureFlags = flag.value; | ||||
|     }); | ||||
|  | ||||
|     this.initLoginForm(); | ||||
|     this.spinnerService.showSpinner(); | ||||
|     if (this.authService.isLoggedIn$.value) { | ||||
| @@ -107,8 +118,8 @@ export class LoginComponent implements OnInit { | ||||
|  | ||||
|   initLoginForm(): void { | ||||
|     this.loginForm = this.formBuilder.group({ | ||||
|       email: ["", [Validators.required, Validators.email]], | ||||
|       password: ["", [Validators.required, Validators.minLength(8)]] | ||||
|       email: [{ value: "", disabled: !this.basicLoginFeatureFlags }, [Validators.required, Validators.email]], | ||||
|       password: [{ value: "", disabled: !this.basicLoginFeatureFlags }, [Validators.required, Validators.minLength(8)]] | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -2,9 +2,10 @@ | ||||
|   <div class="login-form-wrapper register-form-wrapper"> | ||||
|     <div class="login-form"> | ||||
|       <form [formGroup]="loginForm"> | ||||
|         <h1>sh-edraft.de</h1> | ||||
|         <h1>{{'auth.header' | translate}}</h1> | ||||
|         <div class="input-field"> | ||||
|           <input type="text" pInputText formControlName="firstName" placeholder="{{'auth.register.first_name' | translate}}" | ||||
|           <input type="text" pInputText formControlName="firstName" | ||||
|                  placeholder="{{'auth.register.first_name' | translate}}" | ||||
|                  autocomplete="given-name"> | ||||
|           <div *ngIf="submitted" class="invalid-feedback"> | ||||
|             <div | ||||
| @@ -15,7 +16,8 @@ | ||||
|         </div> | ||||
|  | ||||
|         <div class="input-field"> | ||||
|           <input type="text" pInputText formControlName="lastName" placeholder="{{'auth.register.last_name' | translate}}" | ||||
|           <input type="text" pInputText formControlName="lastName" | ||||
|                  placeholder="{{'auth.register.last_name' | translate}}" | ||||
|                  autocomplete="family-name"> | ||||
|           <div *ngIf="submitted" class="invalid-feedback"> | ||||
|             <div | ||||
| @@ -74,12 +76,14 @@ | ||||
|         </div> | ||||
|  | ||||
|         <div class="login-form-submit"> | ||||
|           <button pButton label="{{'auth.register.register' | translate}}" class="btn login-form-submit-btn" (click)="register()" | ||||
|           <button pButton label="{{'auth.register.register' | translate}}" class="btn login-form-submit-btn" | ||||
|                   (click)="register()" | ||||
|                   [disabled]="loginForm.invalid"></button> | ||||
|         </div> | ||||
|         <div class="login-form-sub-button-wrapper"> | ||||
|           <div class="login-form-sub-btn-wrapper"> | ||||
|             <button pButton label="{{'auth.register.login' | translate}}" class="btn login-form-sub-btn" (click)="login()"></button> | ||||
|             <button pButton label="{{'auth.register.login' | translate}}" class="btn login-form-sub-btn" | ||||
|                     (click)="login()"></button> | ||||
|           </div> | ||||
|         </div> | ||||
|       </form> | ||||
|   | ||||
| @@ -12,6 +12,7 @@ import { SpinnerService } from "src/app/services/spinner/spinner.service"; | ||||
| import { Subject, throwError } from "rxjs"; | ||||
| import { TranslateService } from "@ngx-translate/core"; | ||||
| import { SettingsService } from "../../../../services/settings/settings.service"; | ||||
| import { GuiService } from "../../../../services/gui/gui.service"; | ||||
|  | ||||
| @Component({ | ||||
|   selector: "app-registration", | ||||
| @@ -46,7 +47,8 @@ export class RegistrationComponent implements OnInit, OnDestroy { | ||||
|     private spinnerService: SpinnerService, | ||||
|     private route: ActivatedRoute, | ||||
|     private translate: TranslateService, | ||||
|     private settings: SettingsService | ||||
|     private settings: SettingsService, | ||||
|     private gui: GuiService | ||||
|   ) { | ||||
|     this.spinnerService.showSpinner(); | ||||
|     if (this.authService.isLoggedIn$.value) { | ||||
| @@ -56,6 +58,14 @@ export class RegistrationComponent implements OnInit, OnDestroy { | ||||
|   } | ||||
|  | ||||
|   ngOnInit(): void { | ||||
|     this.gui.hasFeatureFlag("BasicRegistration").subscribe(flag => { | ||||
|       if (flag.value) { | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       this.router.navigate(["/auth/login"]); | ||||
|     }); | ||||
|  | ||||
|     this.translate.onLangChange.pipe(takeUntil(this.unsubscriber)).subscribe(lang => { | ||||
|       this.confirmPrivacyString = this.translate.instant("auth.register.confirm_privacy", { url: this.settings.getPrivacyURL() }); | ||||
|     }); | ||||
|   | ||||
| @@ -1,24 +1,25 @@ | ||||
| import { HttpClient, HttpHeaders } from '@angular/common/http'; | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { Observable, Subscribable } from 'rxjs'; | ||||
| import { SettingsDTO } from 'src/app/models/config/settings.dto'; | ||||
| import { SoftwareVersionDTO } from 'src/app/models/config/software-version.dto'; | ||||
| import { SettingsService } from '../settings/settings.service'; | ||||
| import { HttpClient, HttpHeaders } from "@angular/common/http"; | ||||
| import { Injectable } from "@angular/core"; | ||||
| import { Observable } from "rxjs"; | ||||
| import { SettingsDTO } from "src/app/models/config/settings.dto"; | ||||
| import { SoftwareVersionDTO } from "src/app/models/config/software-version.dto"; | ||||
| import { SettingsService } from "../settings/settings.service"; | ||||
|  | ||||
| @Injectable({ | ||||
|   providedIn: 'root' | ||||
|   providedIn: "root" | ||||
| }) | ||||
| export class GuiService { | ||||
|  | ||||
|   constructor( | ||||
|     private appsettings: SettingsService, | ||||
|     private http: HttpClient, | ||||
|   ) { } | ||||
|     private http: HttpClient | ||||
|   ) { | ||||
|   } | ||||
|  | ||||
|   getApiVersion(): Observable<SoftwareVersionDTO> { | ||||
|     return this.http.get<SoftwareVersionDTO>(`${this.appsettings.getApiURL()}/api/gui/api-version`, { | ||||
|       headers: new HttpHeaders({ | ||||
|         'Content-Type': 'application/json' | ||||
|         "Content-Type": "application/json" | ||||
|       }) | ||||
|     }); | ||||
|   } | ||||
| @@ -26,7 +27,7 @@ export class GuiService { | ||||
|   getSettings(): Observable<SettingsDTO> { | ||||
|     return this.http.get<SettingsDTO>(`${this.appsettings.getApiURL()}/api/gui/settings`, { | ||||
|       headers: new HttpHeaders({ | ||||
|         'Content-Type': 'application/json' | ||||
|         "Content-Type": "application/json" | ||||
|       }) | ||||
|     }); | ||||
|   } | ||||
| @@ -34,7 +35,18 @@ export class GuiService { | ||||
|   sendTestMail(mail: string): Observable<unknown> { | ||||
|     return this.http.post(`${this.appsettings.getApiURL()}/api/gui/send-test-mail/${mail}`, { | ||||
|       headers: new HttpHeaders({ | ||||
|         'Content-Type': 'application/json' | ||||
|         "Content-Type": "application/json" | ||||
|       }) | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   hasFeatureFlag(flag: string): Observable<{ key: string, value: boolean }> { | ||||
|     return this.http.get<{ | ||||
|       key: string, | ||||
|       value: boolean | ||||
|     }>(`${this.appsettings.getApiURL()}/api/gui/has-feature-flag/${flag}`, { | ||||
|       headers: new HttpHeaders({ | ||||
|         "Content-Type": "application/json" | ||||
|       }) | ||||
|     }); | ||||
|   } | ||||
|   | ||||
| @@ -2,6 +2,6 @@ | ||||
|     "WebVersion": { | ||||
|         "Major": "1", | ||||
|         "Minor": "2", | ||||
|         "Micro": "dev410" | ||||
|         "Micro": "dev440" | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user