diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 6a03cf3a2..8c9062acf 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -8,11 +8,6 @@ import { setupGuard } from './guards/setup.guard'; const routes: Routes = [ { path: '', redirectTo: '/connections-list', pathMatch: 'full' }, - { - path: 'registration', - loadChildren: () => import('./routes/registration.routes').then((m) => m.REGISTRATION_ROUTES), - canActivate: [noAuthGuard], - }, { path: 'setup', loadComponent: () => import('./components/setup/setup.component').then((m) => m.SetupComponent), diff --git a/frontend/src/app/app.component.css b/frontend/src/app/app.component.css index 47eda27f3..81187f0b4 100644 --- a/frontend/src/app/app.component.css +++ b/frontend/src/app/app.component.css @@ -226,16 +226,6 @@ gap: 20px; } -.actions .action { - --mat-button-outlined-outline-color: #fff; - --mat-toolbar-container-text-color: #fff; - width: 96px; -} - -.actions .action { - margin-left: 0.5em; -} - @media screen and (max-width: 600px) { .menu, .actions_auth { diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html index d0e0a4af2..db109ef1c 100644 --- a/frontend/src/app/app.component.html +++ b/frontend/src/app/app.component.html @@ -174,16 +174,6 @@ Upgrade - - Create account - - - - - - - Login - - - Sign up - - - - - Login - - - Sign up - - - - - diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index ae0ccfcaa..dbc770560 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -359,18 +359,6 @@ export class AppComponent { this.changeDetector.detectChanges(); } - logoutAndRedirectToRegistration() { - this._auth.logOutUser().subscribe(() => { - this.setUserLoggedIn(false); - this.isDemo = false; - this._user.setIsDemo(false); - this.currentUser = null; - localStorage.removeItem('token_expiration'); - this._auth.setAuthenticated(false); - this.router.navigate(['/registration']); - }); - } - logOut(isTokenExpired?: boolean) { try { // @ts-expect-error diff --git a/frontend/src/app/components/registration/registration.component.css b/frontend/src/app/components/registration/registration.component.css deleted file mode 100644 index 58bb920cf..000000000 --- a/frontend/src/app/components/registration/registration.component.css +++ /dev/null @@ -1,213 +0,0 @@ -.register-form-box > app-alert { - display: block; - position: sticky; - top: calc(var(--mat-toolbar-standard-height) + 24px); - margin: 0 0 24px; - z-index: 2; -} - -.wrapper { - display: grid; - grid-template-columns: auto 62.5%; - grid-column-gap: 24px; - height: 100%; - padding: 40px 24px; -} - -@media (width <= 600px) { - .wrapper { - display: flex; - flex-direction: column; - padding: 0; - } -} - -.registrationTitle { - font-weight: 700 !important; - margin-top: -4px !important; - margin-bottom: 32px !important; -} - -.registrationTitle_mobile { - display: none; -} - -@media (width <= 600px) { - .registrationTitle_desktop { - display: none; - } - - .registrationTitle_mobile { - display: initial; - } -} - -.registrationTitle__emphasis { - color: var(--color-accentedPalette-500); -} - -.register-form-box { - display: flex; - flex-direction: column; - /* justify-content: space-between; */ - padding-bottom: 20px; -} - -@media (width <= 600px) { - .register-form-box { - height: 100%; - } -} - -.register-form { - display: flex; - flex-direction: column; - height: 100%; - margin: auto; - padding: 0 48px; - width: 496px; -} - -@media (width <= 600px) { - .register-form { - padding: 40px 9vw 0; - width: 100%; - } -} - -.mat-h1 { - align-self: center; - margin-top: 20px; - font-weight: 500; - text-align: center; - width: 75%; -} - -@media screen and (max-width: 600px) { - .mat-h1 { - margin-top: 32px; - margin-bottom: 32px; - width: 100%; - } -} - -.divider { - position: relative; - background-color: #e8e8e8; - height: 1px; - margin: 24px 0; - width: 100%; -} - -.divider__label { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background-color: var(--mat-sidenav-content-background-color); - font-size: 14px; - padding: 0 16px; -} - -@media screen and (max-width: 600px) { - #google_registration_button ::ng-deep iframe { - width: 100% !important; - } -} - -.password-field { - margin-top: 8px; -} - -.turnstile-widget { - margin-top: 24px; -} - -.submit-button { - margin-top: 40px; -} - -.register-image-box { - display: flex; - justify-content: flex-end; - align-items: flex-end; - background-color: var(--image-box-bg); - border-radius: 12px; - height: calc(100vh - 120px); - overflow: hidden; - padding-top: 3vw; -} - -@media (prefers-color-scheme: light) { - .register-image-box { - --image-box-bg: rgba(229, 237, 254, 1); - } -} - -@media (prefers-color-scheme: dark) { - .register-image-box { - --image-box-bg: rgba(36, 41, 51, 1); - } -} - -@media screen and (max-width: 600px) { - .register-image-box { - display: none; - } -} - -.password-visibility-button { - cursor: pointer; -} - -.register-image { - height: 104vh; - margin-bottom: -13vh; - margin-right: -38vh; -} - -.register-form .agreement { - margin-top: auto !important; -} - -.link { - color: var(--color-accentedPalette-500); -} - -.register-form__github-button { - background-color: #24292f; - margin-top: 20px; - padding: 6px; - width: 400px; -} - -@media (width <= 600px) { - .register-form__github-button { - width: auto; - } -} - -.register-form__github-button ::ng-deep .mdc-button__label { - display: flex; - justify-content: space-between; - width: 100%; -} - -.register-form__github-caption { - flex: 1 0 auto; - color: #fff; - margin-top: 2px; - text-align: center; -} - -.register-form__github-icon { - --mat-button-outlined-icon-spacing: 0; - --mat-button-outlined-icon-offset: 0; - - height: 24px !important; - width: 24px !important; -} - -.register-form__github-icon ::ng-deep svg path { - fill: #fff; -} diff --git a/frontend/src/app/components/registration/registration.component.html b/frontend/src/app/components/registration/registration.component.html deleted file mode 100644 index 960b8741f..000000000 --- a/frontend/src/app/components/registration/registration.component.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - Create an Account to - Manage Your Database - - - - Create an Account on - Rocketadmin - - - - - - - - Continue with GitHub - - - or - - - Email - - Invalid email format. - - - - - - - - - - {{ submitting ? 'Submitting' : 'Create account'}} - - - By creating this account, you agree to Rocketadmin's - Privacy Policy - and - Terms and Conditions. - - - - - - - - - - - diff --git a/frontend/src/app/components/registration/registration.component.spec.ts b/frontend/src/app/components/registration/registration.component.spec.ts deleted file mode 100644 index 58a9db7f8..000000000 --- a/frontend/src/app/components/registration/registration.component.spec.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { provideHttpClient } from '@angular/common/http'; -import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { FormsModule } from '@angular/forms'; -import { MatIconTestingModule } from '@angular/material/icon/testing'; -import { MatSnackBarModule } from '@angular/material/snack-bar'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { provideRouter } from '@angular/router'; -import { IPasswordStrengthMeterService } from 'angular-password-strength-meter'; -import { Angulartics2Module } from 'angulartics2'; -import { of } from 'rxjs'; -import { AuthService } from 'src/app/services/auth.service'; -import { RegistrationComponent } from './registration.component'; - -describe('RegistrationComponent', () => { - let component: RegistrationComponent; - let fixture: ComponentFixture; - let authService: AuthService; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - FormsModule, - MatSnackBarModule, - MatIconTestingModule, - Angulartics2Module.forRoot(), - BrowserAnimationsModule, - RegistrationComponent, - ], - providers: [provideHttpClient(), provideRouter([]), { provide: IPasswordStrengthMeterService, useValue: {} }], - }).compileComponents(); - - // @ts-expect-error - global.window.gtag = vi.fn(); - - (global.window as any).google = { - accounts: { - id: { - initialize: vi.fn(), - renderButton: vi.fn(), - prompt: vi.fn(), - }, - }, - }; - - // Mock Turnstile - window.turnstile = { - render: vi.fn().mockReturnValue('mock-widget-id'), - reset: vi.fn(), - getResponse: vi.fn(), - remove: vi.fn(), - }; - }); - - beforeEach(() => { - fixture = TestBed.createComponent(RegistrationComponent); - component = fixture.componentInstance; - authService = TestBed.inject(AuthService); - fixture.detectChanges(); - }); - - afterEach(() => { - delete window.turnstile; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should sign a user in without turnstile token when not SaaS', () => { - component.isSaas = false; - component.user = { - email: 'john@smith.com', - password: 'kK123456789', - }; - - const fakeSignUpUser = vi.spyOn(authService, 'signUpUser').mockReturnValue(of()); - - component.registerUser(); - expect(fakeSignUpUser).toHaveBeenCalledWith({ - email: 'john@smith.com', - password: 'kK123456789', - }); - expect(component.submitting).toBe(false); - }); - - it('should include turnstile token in registration request when SaaS', () => { - component.isSaas = true; - component.user = { - email: 'john@smith.com', - password: 'kK123456789', - }; - component.turnstileToken = 'test-turnstile-token'; - - const fakeSignUpUser = vi.spyOn(authService, 'signUpUser').mockReturnValue(of()); - - component.registerUser(); - expect(fakeSignUpUser).toHaveBeenCalledWith({ - email: 'john@smith.com', - password: 'kK123456789', - turnstileToken: 'test-turnstile-token', - }); - }); - - it('should set turnstileToken when onTurnstileToken is called', () => { - component.onTurnstileToken('new-token'); - expect(component.turnstileToken).toBe('new-token'); - }); - - it('should clear turnstileToken when onTurnstileError is called', () => { - component.turnstileToken = 'existing-token'; - component.onTurnstileError(); - expect(component.turnstileToken).toBeNull(); - }); - - it('should clear turnstileToken when onTurnstileExpired is called', () => { - component.turnstileToken = 'existing-token'; - component.onTurnstileExpired(); - expect(component.turnstileToken).toBeNull(); - }); -}); diff --git a/frontend/src/app/components/registration/registration.component.ts b/frontend/src/app/components/registration/registration.component.ts deleted file mode 100644 index 7a24e964a..000000000 --- a/frontend/src/app/components/registration/registration.component.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { AfterViewInit, Component, CUSTOM_ELEMENTS_SCHEMA, NgZone, OnInit, ViewChild } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { MatButtonModule } from '@angular/material/button'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatIconModule } from '@angular/material/icon'; -import { MatInputModule } from '@angular/material/input'; -import { Router } from '@angular/router'; -import { Angulartics2, Angulartics2OnModule } from 'angulartics2'; -import posthog from 'posthog-js'; -import { EmailValidationDirective } from 'src/app/directives/emailValidator.directive'; -import { AlertActionType, AlertType } from 'src/app/models/alert'; -import { NewAuthUser } from 'src/app/models/user'; -import { AuthService } from 'src/app/services/auth.service'; -import { NotificationsService } from 'src/app/services/notifications.service'; -import { environment } from 'src/environments/environment'; -import { AlertComponent } from '../ui-components/alert/alert.component'; -import { TurnstileComponent } from '../ui-components/turnstile/turnstile.component'; -import { UserPasswordComponent } from '../ui-components/user-password/user-password.component'; - -@Component({ - selector: 'app-registration', - templateUrl: './registration.component.html', - styleUrls: ['./registration.component.css'], - imports: [ - CommonModule, - FormsModule, - MatFormFieldModule, - MatInputModule, - MatButtonModule, - MatIconModule, - EmailValidationDirective, - AlertComponent, - TurnstileComponent, - UserPasswordComponent, - Angulartics2OnModule, - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], -}) -export class RegistrationComponent implements OnInit, AfterViewInit { - protected posthog = posthog; - @ViewChild(TurnstileComponent) turnstileWidget: TurnstileComponent; - - public isSaas = (environment as any).saas; - public user: NewAuthUser = { - email: '', - password: '', - }; - public submitting: boolean; - public turnstileToken: string | null = null; - public errors = { - 'User_with_this_email_is_already_registered.': 'User with this email is already registered', - 'GitHub_registration_failed._Please_contact_our_support_team.': - 'GitHub registration failed. Please contact our support team.', - }; - - constructor( - private ngZone: NgZone, - private angulartics2: Angulartics2, - public router: Router, - private _auth: AuthService, - private _notifications: NotificationsService, - ) {} - - ngOnInit(): void { - this.angulartics2.eventTrack.next({ - action: 'Reg: Registration page (component) is loaded', - }); - posthog.capture('Reg: Registration page (component) is loaded'); - - const error = new URLSearchParams(location.search).get('error'); - if (error) - this._notifications.showAlert(AlertType.Error, this.errors[error] || error, [ - { - type: AlertActionType.Button, - caption: 'Dismiss', - action: (_id: number) => this._notifications.dismissAlert(), - }, - ]); - } - - ngAfterViewInit() { - //@ts-expect-error - gtag('event', 'conversion', { send_to: 'AW-419937947/auKoCOvwgoYDEJv9nsgB' }); - - //@ts-expect-error - google.accounts.id.initialize({ - client_id: '681163285738-e4l0lrv5vv7m616ucrfhnhso9r396lum.apps.googleusercontent.com', - callback: (authUser) => { - this.ngZone.run(() => { - this._auth.signUpWithGoogle(authUser.credential).subscribe(() => { - this.angulartics2.eventTrack.next({ - action: 'Reg: google register success', - }); - posthog.capture('Reg: google register success'); - }); - }); - }, - }); - //@ts-expect-error - google.accounts.id.renderButton(document.getElementById('google_registration_button'), { - theme: 'filled_blue', - size: 'large', - width: 400, - text: 'signup_with', - }); - //@ts-expect-error - google.accounts.id.prompt(); - } - - updatePasswordField(updatedValue: string) { - this.user.password = updatedValue; - } - - registerUser() { - this.submitting = true; - - const userData: NewAuthUser = { - ...this.user, - ...(this.isSaas && this.turnstileToken ? { turnstileToken: this.turnstileToken } : {}), - }; - - this._auth.signUpUser(userData).subscribe( - () => { - this.angulartics2.eventTrack.next({ - action: 'Reg: sing up success', - }); - posthog.capture('Reg: sing up success'); - }, - (_error) => { - this.angulartics2.eventTrack.next({ - action: 'Reg: sing up unsuccessful', - }); - posthog.capture('Reg: sing up unsuccessful'); - this.submitting = false; - this._resetTurnstile(); - }, - () => (this.submitting = false), - ); - } - - onTurnstileToken(token: string) { - this.turnstileToken = token; - } - - onTurnstileError() { - this.turnstileToken = null; - } - - onTurnstileExpired() { - this.turnstileToken = null; - } - - private _resetTurnstile(): void { - if (this.isSaas && this.turnstileWidget) { - this.turnstileWidget.reset(); - this.turnstileToken = null; - } - } - - registerWithGithub() { - this._auth.signUpWithGithub(); - this.angulartics2.eventTrack.next({ - action: 'Reg: github register redirect', - }); - posthog.capture('Reg: github register redirect'); - } -} diff --git a/frontend/src/app/guards/no-auth.guard.ts b/frontend/src/app/guards/no-auth.guard.ts index 743e7518e..026069d35 100644 --- a/frontend/src/app/guards/no-auth.guard.ts +++ b/frontend/src/app/guards/no-auth.guard.ts @@ -3,7 +3,7 @@ import { CanActivateFn, Router } from '@angular/router'; import { differenceInMilliseconds } from 'date-fns'; /** - * Guard that prevents logged-in users from accessing auth pages (login, registration). + * Guard that prevents logged-in users from accessing auth pages (login). * Redirects authenticated users to /connections-list. */ export const noAuthGuard: CanActivateFn = () => { diff --git a/frontend/src/app/models/user.ts b/frontend/src/app/models/user.ts index 7f5fd60a0..83e241c66 100644 --- a/frontend/src/app/models/user.ts +++ b/frontend/src/app/models/user.ts @@ -1,12 +1,6 @@ import { CompanyMemberRole } from './company'; import { TablePermissions } from './table'; -export interface NewAuthUser { - email: string; - password: string; - turnstileToken?: string; -} - export interface ExistingAuthUser { email: string; password: string; diff --git a/frontend/src/app/routes/registration.routes.ts b/frontend/src/app/routes/registration.routes.ts deleted file mode 100644 index 4ad6679d2..000000000 --- a/frontend/src/app/routes/registration.routes.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Routes } from '@angular/router'; -import { provideZxvbnServiceForPSM } from 'angular-password-strength-meter/zxcvbn'; - -export const REGISTRATION_ROUTES: Routes = [ - { - path: '', - loadComponent: () => - import('../components/registration/registration.component').then((m) => m.RegistrationComponent), - title: 'Sign up | Rocketadmin', - providers: [provideZxvbnServiceForPSM()], - }, -]; diff --git a/frontend/src/app/services/auth.service.spec.ts b/frontend/src/app/services/auth.service.spec.ts index 4080b86c5..748ce1d2c 100644 --- a/frontend/src/app/services/auth.service.spec.ts +++ b/frontend/src/app/services/auth.service.spec.ts @@ -50,59 +50,6 @@ describe('AuthService', () => { expect(service).toBeTruthy(); }); - it('should call signUpUser', () => { - let isSignUpUserCalled = false; - - const userData = { - email: 'john@smith.com', - password: 'mM87654321', - }; - - const signUpResponse = { - expires: '2022-04-11T15:56:51.599Z', - }; - - // @ts-expect-error - global.window.fbq = vi.fn(); - - service.signUpUser(userData).subscribe((res) => { - expect(res).toEqual(signUpResponse); - isSignUpUserCalled = true; - }); - - const req = httpMock.expectOne('/saas/user/register'); - expect(req.request.method).toBe('POST'); - expect(req.request.body).toEqual(userData); - req.flush(signUpResponse); - - expect(isSignUpUserCalled).toBe(true); - }); - - it('should fall for signUpUser and show Error alert', async () => { - const userData = { - email: 'john@smith.com', - password: 'mM87654321', - }; - - const tokenExpiration = service.signUpUser(userData).toPromise(); - - const req = httpMock.expectOne('/saas/user/register'); - expect(req.request.method).toBe('POST'); - req.flush(fakeError, { status: 400, statusText: '' }); - await tokenExpiration; - - expect(fakeNotifications.showAlert).toHaveBeenCalledWith( - AlertType.Error, - { abstract: fakeError.message, details: fakeError.originalMessage }, - [ - expect.objectContaining({ - type: AlertActionType.Button, - caption: 'Dismiss', - }), - ], - ); - }); - it('should call loginUser', () => { let isSignUpUserCalled = false; diff --git a/frontend/src/app/services/auth.service.ts b/frontend/src/app/services/auth.service.ts index c5bd37c71..7052bf605 100644 --- a/frontend/src/app/services/auth.service.ts +++ b/frontend/src/app/services/auth.service.ts @@ -3,9 +3,8 @@ import { Injectable, signal } from '@angular/core'; import * as Sentry from '@sentry/angular'; import { BehaviorSubject, EMPTY } from 'rxjs'; import { catchError, map } from 'rxjs/operators'; -import { environment } from 'src/environments/environment'; import { AlertActionType, AlertType } from '../models/alert'; -import { ExistingAuthUser, NewAuthUser } from '../models/user'; +import { ExistingAuthUser } from '../models/user'; import { ConfigurationService } from './configuration.service'; import { NotificationsService } from './notifications.service'; @@ -29,69 +28,6 @@ export class AuthService { this._isAuthenticated.set(value); } - signUpUser(userData: NewAuthUser) { - const config = this._configuration.getConfig(); - return this._http.post(config.saasURL + '/saas/user/register', userData).pipe( - map((res) => { - if ((environment as any).saas) { - // @ts-expect-error - window.fbq?.('trackCustom', 'Signup'); - } - this._notifications.showSuccessSnackbar(`Confirmation email has been sent to you.`); - this.auth.next(res); - return res; - }), - catchError((err) => { - console.log(err); - this._notifications.showAlert( - AlertType.Error, - { abstract: err.error?.message || err.message, details: err.error?.originalMessage }, - [ - { - type: AlertActionType.Button, - caption: 'Dismiss', - action: () => this._notifications.dismissAlert(), - }, - ], - ); - return EMPTY; - }), - ); - } - - signUpWithGoogle(token: string) { - const config = this._configuration.getConfig(); - - return this._http.post(config.saasURL + '/saas/user/google/register', { token }).pipe( - map((res) => { - this.auth.next(res); - return res; - }), - catchError((err) => { - console.log(err); - Sentry.captureException(err); - this._notifications.showAlert( - AlertType.Error, - { abstract: err.error?.message || err.message, details: err.error?.originalMessage }, - [ - { - type: AlertActionType.Button, - caption: 'Dismiss', - action: (_id: number) => this._notifications.dismissAlert(), - }, - ], - ); - return EMPTY; - }), - ); - } - - signUpWithGithub() { - const config = this._configuration.getConfig(); - - location.assign(config.saasURL + '/saas/user/github/registration/request'); - } - loginUser(userData: ExistingAuthUser) { if (userData.companyId === '') { delete userData.companyId;
- By creating this account, you agree to Rocketadmin's - Privacy Policy - and - Terms and Conditions. -