From 2abb968fc1f4a8b620048c8989cdeb8cdd9f53ad Mon Sep 17 00:00:00 2001 From: Gardient Date: Sat, 6 Jan 2018 18:22:02 +0200 Subject: [PATCH] intermediate commit --- package.json | 4 ++ src/app/app-routing.module.ts | 11 +++- src/app/app.component.html | 23 +------ src/app/app.module.ts | 9 ++- src/app/auth.guard.spec.ts | 15 +++++ src/app/auth.guard.ts | 19 ++++++ src/app/gapi.service.spec.ts | 15 +++++ src/app/gapi.service.ts | 84 +++++++++++++++++++++++++ src/app/header/header.component.css | 0 src/app/header/header.component.html | 11 ++++ src/app/header/header.component.spec.ts | 25 ++++++++ src/app/header/header.component.ts | 26 ++++++++ src/app/home/home.component.css | 0 src/app/home/home.component.html | 3 + src/app/home/home.component.spec.ts | 25 ++++++++ src/app/home/home.component.ts | 15 +++++ src/index.html | 12 +++- tslint.json | 3 +- yarn.lock | 20 ++++++ 19 files changed, 295 insertions(+), 25 deletions(-) create mode 100644 src/app/auth.guard.spec.ts create mode 100644 src/app/auth.guard.ts create mode 100644 src/app/gapi.service.spec.ts create mode 100644 src/app/gapi.service.ts create mode 100644 src/app/header/header.component.css create mode 100644 src/app/header/header.component.html create mode 100644 src/app/header/header.component.spec.ts create mode 100644 src/app/header/header.component.ts create mode 100644 src/app/home/home.component.css create mode 100644 src/app/home/home.component.html create mode 100644 src/app/home/home.component.spec.ts create mode 100644 src/app/home/home.component.ts diff --git a/package.json b/package.json index 0241efa..472fe66 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,10 @@ "@angular/cli": "1.6.3", "@angular/compiler-cli": "^5.0.0", "@angular/language-service": "^5.0.0", + "@types/gapi": "^0.0.35", + "@types/gapi.auth2": "^0.0.46", + "@types/gapi.client": "^1.0.0", + "@types/gapi.client.sheets": "^4.0.0", "@types/jasmine": "~2.5.53", "@types/jasminewd2": "~2.0.2", "@types/node": "~6.0.60", diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index d425c6f..dc8c2d1 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,7 +1,16 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; -const routes: Routes = []; +import { HomeComponent } from './home/home.component'; + +import { AuthGuard } from './auth.guard'; + +const routes: Routes = [ + { + path: '', + component: HomeComponent + } +]; @NgModule({ imports: [RouterModule.forRoot(routes)], diff --git a/src/app/app.component.html b/src/app/app.component.html index 1094e7e..0d4a7b9 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,21 +1,4 @@ - -
-

- Welcome to {{ title }}! -

- Angular Logo + +
+
-

Here are some links to help you start:

- - - diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 2c5e1ac..4a7ba58 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -4,17 +4,22 @@ import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; +import { HeaderComponent } from './header/header.component'; +import { HomeComponent } from './home/home.component'; +import { GApiService } from './gapi.service'; @NgModule({ declarations: [ - AppComponent + AppComponent, + HeaderComponent, + HomeComponent ], imports: [ BrowserModule, AppRoutingModule ], - providers: [], + providers: [GApiService], bootstrap: [AppComponent] }) export class AppModule { } diff --git a/src/app/auth.guard.spec.ts b/src/app/auth.guard.spec.ts new file mode 100644 index 0000000..7ed05ee --- /dev/null +++ b/src/app/auth.guard.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, async, inject } from '@angular/core/testing'; + +import { AuthGuard } from './auth.guard'; + +describe('AuthGuard', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [AuthGuard] + }); + }); + + it('should ...', inject([AuthGuard], (guard: AuthGuard) => { + expect(guard).toBeTruthy(); + })); +}); diff --git a/src/app/auth.guard.ts b/src/app/auth.guard.ts new file mode 100644 index 0000000..d05535a --- /dev/null +++ b/src/app/auth.guard.ts @@ -0,0 +1,19 @@ +import { Injectable } from '@angular/core'; +import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; +import { Observable } from 'rxjs/Observable'; +import { GApiService } from './gapi.service'; + +@Injectable() +export class AuthGuard implements CanActivate { + constructor (private gapiService: GApiService, private router: Router) { } + + canActivate ( + next: ActivatedRouteSnapshot, + state: RouterStateSnapshot): Observable | Promise | boolean { + const authenticated = this.gapiService.isAuthenticated(); + if (!authenticated) { + this.router.navigate(['/']); + } + return authenticated; + } +} diff --git a/src/app/gapi.service.spec.ts b/src/app/gapi.service.spec.ts new file mode 100644 index 0000000..ab3cca8 --- /dev/null +++ b/src/app/gapi.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { GApiService } from './gapi.service'; + +describe('GapiService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [GApiService] + }); + }); + + it('should be created', inject([GApiService], (service: GApiService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/src/app/gapi.service.ts b/src/app/gapi.service.ts new file mode 100644 index 0000000..3e7a814 --- /dev/null +++ b/src/app/gapi.service.ts @@ -0,0 +1,84 @@ +import { bindCallback } from 'rxjs/Observable/bindCallback'; +import { fromPromise } from 'rxjs/Observable/fromPromise'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/map'; + +const API_KEY = 'AIzaSyA9BX0C-ku3NBkTSeHY59DiJi02U-DbCe0'; +const CLIENT_ID = '505888163689-q01h4puni0e74t36m04mcksr0g7pti5v.apps.googleusercontent.com'; + +const DISCOVERY_DOCS: string[] = ['https://sheets.googleapis.com/$discovery/rest?version=v4']; +const SCOPES = 'https://www.googleapis.com/auth/spreadsheets.readonly'; + +function gapiRequestToObservable(request: gapi.client.Request): Observable { + return fromPromise>(request).map(res => res.result); +} + +/** + * Takes a positive integer and returns the corresponding column name. + * @param {number} num The positive integer to convert to a column name. + * @return {string} The column name. + */ +function numberToColumnName(num: number): string { + let ret = ''; + for (; num > 0; num = Math.floor(num % 26)) { + num--; // because nobody starts counting columns at 0 and A needs to be 1 + ret = String.fromCharCode(Math.floor(num % 26) + 65) + ret; + } + return ret; +} + +@Injectable() +export class GApiService { + private observableGetAuthInstance: () => Observable; + private authInstance: gapi.auth2.GoogleAuth; + + constructor () { + gapi.load('client:auth2', () => { + gapi.client.init({ + apiKey: API_KEY, + clientId: CLIENT_ID, + discoveryDocs: DISCOVERY_DOCS, + scope: SCOPES + }).then(() => { + this.authInstance = gapi.auth2.getAuthInstance(); + // Listen for sign-in state changes. + this.observableGetAuthInstance = bindCallback(this.authInstance.isSignedIn.listen); + }); + }); + } + + get authStatusChange(): Observable { return this.observableGetAuthInstance(); } + + isAuthenticated (): boolean { + return this.authInstance.isSignedIn.get(); + } + + signIn (): void { + gapi.auth2.getAuthInstance().signIn(); + } + + signOut (): void { + gapi.auth2.getAuthInstance().signOut(); + } + + getSpreadsheet (id: string): Observable { + return gapiRequestToObservable(gapi.client.spreadsheets.get({ + spreadsheetId: id + })); + } + + getDataOnSheet (spreadsheetId: string, sheet: gapi.client.sheets.Sheet) { + gapi.client.spreadsheets.values.get({ + spreadsheetId, + range: sheet.properties.title + '!A1:1', + majorDimension: 'ROWS' + }).then(firstRowResponse => { + const firstRow = firstRowResponse.result.values[0]; + gapi.client.spreadsheets.values.get({ + spreadsheetId, + range: sheet.properties.title + '!A1:' + numberToColumnName(firstRow.length) + }); + }); + } +} diff --git a/src/app/header/header.component.css b/src/app/header/header.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html new file mode 100644 index 0000000..d7db7ba --- /dev/null +++ b/src/app/header/header.component.html @@ -0,0 +1,11 @@ + diff --git a/src/app/header/header.component.spec.ts b/src/app/header/header.component.spec.ts new file mode 100644 index 0000000..2d0479d --- /dev/null +++ b/src/app/header/header.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HeaderComponent } from './header.component'; + +describe('HeaderComponent', () => { + let component: HeaderComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HeaderComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HeaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts new file mode 100644 index 0000000..137e18b --- /dev/null +++ b/src/app/header/header.component.ts @@ -0,0 +1,26 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { GApiService } from '../gapi.service'; +import { Subscription } from 'rxjs/Subscription'; + +@Component({ + selector: 'app-header', + templateUrl: './header.component.html', + styleUrls: ['./header.component.css'] +}) +export class HeaderComponent implements OnInit, OnDestroy { + private sub: Subscription; + constructor(private gapiService: GApiService) { + } + + loggedIn = false; + + ngOnInit(): void { + this.loggedIn = this.gapiService.isAuthenticated(); + this.sub = this.gapiService.authStatusChange.subscribe(newValue => this.loggedIn = newValue); + } + + ngOnDestroy(): void { + this.sub.unsubscribe(); + } +} diff --git a/src/app/home/home.component.css b/src/app/home/home.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html new file mode 100644 index 0000000..afc16a3 --- /dev/null +++ b/src/app/home/home.component.html @@ -0,0 +1,3 @@ +

+ home works! +

diff --git a/src/app/home/home.component.spec.ts b/src/app/home/home.component.spec.ts new file mode 100644 index 0000000..490e81b --- /dev/null +++ b/src/app/home/home.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HomeComponent } from './home.component'; + +describe('HomeComponent', () => { + let component: HomeComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HomeComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HomeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts new file mode 100644 index 0000000..33fd770 --- /dev/null +++ b/src/app/home/home.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-home', + templateUrl: './home.component.html', + styleUrls: ['./home.component.css'] +}) +export class HomeComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/src/index.html b/src/index.html index d148cc4..0cb7b47 100644 --- a/src/index.html +++ b/src/index.html @@ -5,8 +5,18 @@ QContacts - + + + + + + + + + + + diff --git a/tslint.json b/tslint.json index a2e30ef..2852bfa 100644 --- a/tslint.json +++ b/tslint.json @@ -24,7 +24,8 @@ "import-spacing": true, "indent": [ true, - "spaces" + "spaces", + 2 ], "interface-over-type-literal": true, "label-position": true, diff --git a/yarn.lock b/yarn.lock index 07b8aa5..615a61c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -185,6 +185,26 @@ version "0.0.11" resolved "https://registry.yarnpkg.com/@schematics/schematics/-/schematics-0.0.11.tgz#c8f70f270ed38f29b2873248126fd59abd635862" +"@types/gapi.auth2@^0.0.46": + version "0.0.46" + resolved "https://registry.yarnpkg.com/@types/gapi.auth2/-/gapi.auth2-0.0.46.tgz#5c929d3e66d74b84293c65aaa0ce12e0f8d4fb36" + dependencies: + "@types/gapi" "*" + +"@types/gapi.client.sheets@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/gapi.client.sheets/-/gapi.client.sheets-4.0.0.tgz#bfc4f4f24a0292da3b4d7b561d6d67ded7b11ebb" + dependencies: + "@types/gapi.client" "*" + +"@types/gapi.client@*", "@types/gapi.client@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/gapi.client/-/gapi.client-1.0.0.tgz#aa42501465fcf6440421050da70ec724d4c4c4df" + +"@types/gapi@*", "@types/gapi@^0.0.35": + version "0.0.35" + resolved "https://registry.yarnpkg.com/@types/gapi/-/gapi-0.0.35.tgz#8e0d672d66d8c6ce8493f5e8e550344f7ff500dc" + "@types/jasmine@*": version "2.8.3" resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.3.tgz#f910edc67d69393d562d10f8f3d205ea3f3306bf"