diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index fd78427bc..a7cc74d30 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -11,15 +11,13 @@ import { DatasetComponent } from "./dataset-view/dataset.component"; import { DatasetCreateComponent } from "./dataset-create/dataset-create.component"; import { AccountComponent } from "./auth/account/account.component"; import { GithubCallbackComponent } from "./auth/github-callback/github.callback"; -import { environment } from "../environments/environment"; import ProjectLinks from "./project-links"; import { SetTransformComponent } from "./dataset-view/additional-components/metadata-component/components/set-transform/set-transform.component"; import { LoginGuard } from "./auth/guards/login.guard"; - -const githubUrl = `https://github.com/login/oauth/authorize?scope=user:email&client_id=${environment.github_client_id}`; +import { LoginService } from "./auth/login/login.service"; export const routes: Routes = [ - { path: "", redirectTo: ProjectLinks.URL_SEARCH, pathMatch: "full" }, + { path: "", redirectTo: ProjectLinks.DEFAULT_URL, pathMatch: "full" }, { path: ProjectLinks.URL_GITHUB_CALLBACK, component: GithubCallbackComponent, @@ -30,7 +28,7 @@ export const routes: Routes = [ canLoad: [LoginGuard], loadChildren: () => new Promise(() => { - window.location.href = githubUrl; + LoginService.gotoGithub(); }), }, { diff --git a/src/app/app-routing.spec.ts b/src/app/app-routing.spec.ts index 39689c84c..beb3d11a8 100644 --- a/src/app/app-routing.spec.ts +++ b/src/app/app-routing.spec.ts @@ -1,37 +1,125 @@ -import { ComponentFixture, TestBed, fakeAsync, tick } from "@angular/core/testing"; +import { ComponentFixture, TestBed, fakeAsync, flush, tick } from "@angular/core/testing"; import { Location } from "@angular/common"; import { Router } from "@angular/router"; import { RouterTestingModule } from "@angular/router/testing"; import { routes } from "./app-routing.module"; -import { AppComponent } from "./app.component"; import ProjectLinks from "./project-links"; import { promiseWithCatch } from "./common/app.helpers"; import { ApolloTestingModule } from "apollo-angular/testing"; import { NO_ERRORS_SCHEMA } from "@angular/core"; +import { LoggedUserService } from "./auth/logged-user.service"; +import { AppConfigService } from "./app-config.service"; +import { LoginService } from "./auth/login/login.service"; +import { PageNotFoundComponent } from "./components/page-not-found/page-not-found.component"; -describe("Router: App", () => { +describe("Router", () => { let router: Router; - let fixture: ComponentFixture; + let fixture: ComponentFixture; // any component is fine, we are testing router let location: Location; + let loggedUserService: LoggedUserService; + let appConfigService: AppConfigService; beforeEach(async () => { await TestBed.configureTestingModule({ imports: [RouterTestingModule.withRoutes(routes), ApolloTestingModule], - declarations: [AppComponent], + declarations: [PageNotFoundComponent], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); router = TestBed.inject(Router); location = TestBed.inject(Location); + loggedUserService = TestBed.inject(LoggedUserService); + appConfigService = TestBed.inject(AppConfigService); - fixture = TestBed.createComponent(AppComponent); + fixture = TestBed.createComponent(PageNotFoundComponent); router.initialNavigation(); fixture.detectChanges(); }); - it('navigate to "" redirects you to search', fakeAsync(() => { + it("navigate to home redirects you to default URL", fakeAsync(() => { promiseWithCatch(router.navigate([""])); tick(); - expect(location.path()).toBe("/" + ProjectLinks.URL_SEARCH); + + expect(location.path()).toBe("/" + ProjectLinks.DEFAULT_URL); + flush(); })); + + [ + ProjectLinks.URL_GITHUB_CALLBACK, + ProjectLinks.URL_SEARCH, + `myaccount`, + `myaccount/mydataset`, + `myaccount/mydataset/${ProjectLinks.URL_BLOCK}/:someHash`, + ProjectLinks.URL_PAGE_NOT_FOUND, + "dummy", + ].forEach((url: string) => { + it(`Route to ${url} lands on the component without Login`, fakeAsync(() => { + promiseWithCatch(router.navigate([url])); + tick(); + + expect(location.path()).toBe("/" + url); + flush(); + })); + }); + + [ + ProjectLinks.URL_DATASET_CREATE, + ProjectLinks.URL_SETTINGS, + `myaccount/mydataset/${ProjectLinks.URL_PARAM_ADD_POLLING_SOURCE}`, + `myaccount/mydataset/${ProjectLinks.URL_PARAM_SET_TRANSFORM}`, + ].forEach((url: string) => { + it(`Route to ${url} fails without a login and moves to Home`, fakeAsync(() => { + promiseWithCatch(router.navigate([url])); + tick(); + + expect(location.path()).toBe("/" + ProjectLinks.DEFAULT_URL); + flush(); + })); + + it(`Route to ${url} lands on the component with active login`, fakeAsync(() => { + spyOnProperty(loggedUserService, "isAuthenticated", "get").and.returnValue(true); + + promiseWithCatch(router.navigate([url])); + tick(); + + expect(location.path()).toBe("/" + url); + flush(); + })); + }); + + describe("#login routes", () => { + it("login redirects to default page when not allowed in configuration", fakeAsync(() => { + spyOnProperty(appConfigService, "featureFlags", "get").and.returnValue({ + enableLogin: false, + enableLogout: true, + }); + + promiseWithCatch(router.navigate([ProjectLinks.URL_LOGIN])); + tick(); + + expect(location.path()).toBe("/" + ProjectLinks.URL_SEARCH); + flush(); + })); + + it("login redirects to default page when user is already logged", fakeAsync(() => { + spyOnProperty(loggedUserService, "isAuthenticated", "get").and.returnValue(true); + + promiseWithCatch(router.navigate([ProjectLinks.URL_LOGIN])); + tick(); + + expect(location.path()).toBe("/" + ProjectLinks.URL_SEARCH); + flush(); + })); + + it("login initiates GitHub redirect when allowed and not logged in", fakeAsync(() => { + spyOnProperty(loggedUserService, "isAuthenticated", "get").and.returnValue(false); + const gotoGithubSpy = spyOn(LoginService, "gotoGithub"); + + promiseWithCatch(router.navigate([ProjectLinks.URL_LOGIN])); + tick(); + + expect(gotoGithubSpy).toHaveBeenCalledWith(); + flush(); + })); + }); }); diff --git a/src/app/app.module.ts b/src/app/app.module.ts index cd5bc5fde..419e8e488 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -64,6 +64,7 @@ import { HighlightModule, HIGHLIGHT_OPTIONS } from "ngx-highlightjs"; import { ToastrModule } from "ngx-toastr"; import { LoggedUserService } from "./auth/logged-user.service"; import { firstValueFrom } from "rxjs"; +import { LoginService } from "./auth/login/login.service"; const Services = [ { @@ -78,6 +79,7 @@ const Services = [ }, Apollo, AuthApi, + LoginService, LoggedUserService, SearchApi, DatasetApi, diff --git a/src/app/auth/login/login.component.html b/src/app/auth/login/login.component.html index 470ee6931..bcead4f2e 100644 --- a/src/app/auth/login/login.component.html +++ b/src/app/auth/login/login.component.html @@ -1,2 +1,2 @@

Please login with your GitHub account.

- + diff --git a/src/app/auth/login/login.component.ts b/src/app/auth/login/login.component.ts index 10059e72c..90103b147 100644 --- a/src/app/auth/login/login.component.ts +++ b/src/app/auth/login/login.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component } from "@angular/core"; -import { environment } from "../../../environments/environment"; +import ProjectLinks from "src/app/project-links"; @Component({ selector: "app-login", @@ -8,5 +8,5 @@ import { environment } from "../../../environments/environment"; changeDetection: ChangeDetectionStrategy.OnPush, }) export class LoginComponent { - public githubUrl = `https://github.com/login/oauth/authorize?scope=user:email&client_id=${environment.github_client_id}`; + public readonly GITHUB_URL = ProjectLinks.GITHUB_URL; } diff --git a/src/app/auth/login/login.service.ts b/src/app/auth/login/login.service.ts new file mode 100644 index 000000000..3ec5367f7 --- /dev/null +++ b/src/app/auth/login/login.service.ts @@ -0,0 +1,11 @@ +import { Injectable } from "@angular/core"; +import ProjectLinks from "src/app/project-links"; + +@Injectable({ + providedIn: "root", +}) +export class LoginService { + public static gotoGithub(): void { + window.location.href = ProjectLinks.GITHUB_URL; + } +} diff --git a/src/app/project-links.ts b/src/app/project-links.ts index 34e42d25d..7bf2705c1 100644 --- a/src/app/project-links.ts +++ b/src/app/project-links.ts @@ -1,4 +1,5 @@ import { Injectable } from "@angular/core"; +import { environment } from "src/environments/environment"; @Injectable() export default class ProjectLinks { @@ -22,6 +23,8 @@ export default class ProjectLinks { ProjectLinks.URL_SETTINGS, ]; + public static readonly DEFAULT_URL = ProjectLinks.URL_SEARCH; + public static readonly URL_PARAM_ACCOUNT_NAME: string = "accountName"; public static readonly URL_PARAM_DATASET_NAME: string = "datasetName"; public static readonly URL_PARAM_CATEGORY: string = "category"; @@ -33,6 +36,8 @@ export default class ProjectLinks { public static readonly URL_QUERY_PARAM_PAGE: string = "page"; public static readonly URL_QUERY_PARAM_QUERY: string = "query"; + public static readonly GITHUB_URL = `https://github.com/login/oauth/authorize?scope=user:email&client_id=${environment.github_client_id}`; + // TODO // public static readonly URL_DATASET_CREATE_SELECT_TYPE = "select-type"; // public static readonly URL_DATASET_CREATE_ROOT = "root";