From 633e7357b41b5b3e99df887215bed620034eda6a Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 18 Feb 2019 00:11:24 +0800 Subject: Add todo list request service. --- .../todo-list-page/todo-list-page.component.html | 4 +- .../app/todo-list-page/todo-list-page.component.ts | 7 ++- .../ClientApp/src/app/todo-list.service.spec.ts | 12 ++++++ Timeline/ClientApp/src/app/todo-list.service.ts | 50 ++++++++++++++++++++++ 4 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 Timeline/ClientApp/src/app/todo-list.service.spec.ts create mode 100644 Timeline/ClientApp/src/app/todo-list.service.ts (limited to 'Timeline/ClientApp/src') diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html index 0d005c83..6287c14e 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html @@ -1,3 +1,3 @@ -

- todo-list-page works! +

+ {{item}}

diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts index 37de232b..6037e1ea 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts @@ -1,4 +1,5 @@ import { Component, OnInit } from '@angular/core'; +import { TodoListService } from '../todo-list.service'; @Component({ selector: 'app-todo-list-page', @@ -7,7 +8,11 @@ import { Component, OnInit } from '@angular/core'; }) export class TodoListPageComponent implements OnInit { - constructor() { } + items: string[]; + + constructor(private todoService: TodoListService) { + todoService.getWorkItemList().subscribe(result => this.items = result); + } ngOnInit() { } diff --git a/Timeline/ClientApp/src/app/todo-list.service.spec.ts b/Timeline/ClientApp/src/app/todo-list.service.spec.ts new file mode 100644 index 00000000..529ba8cc --- /dev/null +++ b/Timeline/ClientApp/src/app/todo-list.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { TodoListService } from './todo-list.service'; + +describe('TodoListServiceService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: TodoListService = TestBed.get(TodoListService); + expect(service).toBeTruthy(); + }); +}); diff --git a/Timeline/ClientApp/src/app/todo-list.service.ts b/Timeline/ClientApp/src/app/todo-list.service.ts new file mode 100644 index 00000000..e92a11c9 --- /dev/null +++ b/Timeline/ClientApp/src/app/todo-list.service.ts @@ -0,0 +1,50 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { switchMap, concatMap, map, toArray } from 'rxjs/operators'; + +interface WiqlWorkItemResult { + id: number; + url: string; +} + +interface WiqlResult { + workItems: WiqlWorkItemResult[]; +} + +interface WorkItemResult { + id: number; + fields: { [name: string]: any }; +} + +@Injectable({ + providedIn: 'root' +}) +export class TodoListService { + + private username = 'crupest'; + private pat = 'ehnmegogmk6r7qlkpy6zdl2hnfl6ntqbvggzxvvgp4a5vhr7lmnq'; + private organization = 'crupest-web'; + private project = 'Timeline'; + private fieldId = 'System.Title'; + + private headers: HttpHeaders; + + constructor(private client: HttpClient) { + this.headers = new HttpHeaders({ + 'Accept': 'application/json', + 'Authorization': `Basic ${btoa(this.username + ':' + this.pat)}` + }); + } + + getWorkItemList(): Observable { + return this.client.post(`https://dev.azure.com/${this.organization}/${this.project}/_apis/wit/wiql?api-version=5.0`, { + query: 'SELECT [System.Id] FROM workitems WHERE [System.TeamProject] = @project' + }, { headers: this.headers }).pipe( + switchMap(result => result.workItems), + concatMap(result => this.client.get(result.url, {headers: this.headers})), + map(result => (result.fields[this.fieldId])), + toArray() + ); + } +} -- cgit v1.2.3 From 9756acc50f5f228968cf45d9e73c8dd3b4eacc6a Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 18 Feb 2019 19:26:12 +0800 Subject: Beautify the todo page. --- Timeline/ClientApp/src/app/app.module.ts | 9 ++++++--- .../src/app/todo-list-page/todo-list-page.component.css | 8 ++++++++ .../src/app/todo-list-page/todo-list-page.component.html | 12 +++++++++--- .../src/app/todo-list-page/todo-list-page.component.ts | 4 ++-- Timeline/ClientApp/src/app/todo-list.service.ts | 9 +++++++-- 5 files changed, 32 insertions(+), 10 deletions(-) (limited to 'Timeline/ClientApp/src') diff --git a/Timeline/ClientApp/src/app/app.module.ts b/Timeline/ClientApp/src/app/app.module.ts index e1f45136..3247cf92 100644 --- a/Timeline/ClientApp/src/app/app.module.ts +++ b/Timeline/ClientApp/src/app/app.module.ts @@ -4,7 +4,10 @@ import { FormsModule } from '@angular/forms'; import { HttpClientModule } from '@angular/common/http'; import { RouterModule } from '@angular/router'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { MatMenuModule, MatIconModule, MatButtonModule, MatToolbarModule } from '@angular/material'; +import { + MatMenuModule, MatIconModule, MatButtonModule, MatToolbarModule, MatListModule, + MatProgressBarModule, MatCardModule +} from '@angular/material'; import { AppComponent } from './app.component'; import { HomeComponent } from './home/home.component'; @@ -21,10 +24,10 @@ import { TodoListPageComponent } from './todo-list-page/todo-list-page.component HttpClientModule, FormsModule, BrowserAnimationsModule, - MatMenuModule, MatIconModule, MatButtonModule, MatToolbarModule, + MatMenuModule, MatIconModule, MatButtonModule, MatToolbarModule, MatListModule, MatProgressBarModule, MatCardModule, RouterModule.forRoot([ { path: '', component: HomeComponent, pathMatch: 'full' }, - { path: 'todo', component: TodoListPageComponent} + { path: 'todo', component: TodoListPageComponent } ]) ], providers: [], diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.css b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.css index e69de29b..43bd26d8 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.css +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.css @@ -0,0 +1,8 @@ +.item-id { + display: inline-block; + text-align: center; + background: skyblue; + border-radius: 0.2rem; + width: 1.2rem; + height: 1.2rem; +} diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html index 6287c14e..3a80e4eb 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html @@ -1,3 +1,9 @@ -

- {{item}} -

+ + + + + + {{item.id}} {{item.title}} + + + diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts index 6037e1ea..722ecbdc 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { TodoListService } from '../todo-list.service'; +import { TodoListService, WorkItem } from '../todo-list.service'; @Component({ selector: 'app-todo-list-page', @@ -8,7 +8,7 @@ import { TodoListService } from '../todo-list.service'; }) export class TodoListPageComponent implements OnInit { - items: string[]; + items: WorkItem[]; constructor(private todoService: TodoListService) { todoService.getWorkItemList().subscribe(result => this.items = result); diff --git a/Timeline/ClientApp/src/app/todo-list.service.ts b/Timeline/ClientApp/src/app/todo-list.service.ts index e92a11c9..b1bc5ff3 100644 --- a/Timeline/ClientApp/src/app/todo-list.service.ts +++ b/Timeline/ClientApp/src/app/todo-list.service.ts @@ -17,6 +17,11 @@ interface WorkItemResult { fields: { [name: string]: any }; } +export interface WorkItem { + id: number; + title: string; +} + @Injectable({ providedIn: 'root' }) @@ -37,13 +42,13 @@ export class TodoListService { }); } - getWorkItemList(): Observable { + getWorkItemList(): Observable { return this.client.post(`https://dev.azure.com/${this.organization}/${this.project}/_apis/wit/wiql?api-version=5.0`, { query: 'SELECT [System.Id] FROM workitems WHERE [System.TeamProject] = @project' }, { headers: this.headers }).pipe( switchMap(result => result.workItems), concatMap(result => this.client.get(result.url, {headers: this.headers})), - map(result => (result.fields[this.fieldId])), + map(result => { id: result.id, title: result.fields[this.fieldId] }), toArray() ); } -- cgit v1.2.3 From 1f0a978ad2b8e5bcd57eef37baca93e00fd6b20b Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 18 Feb 2019 19:56:13 +0800 Subject: Add get pat api. --- .../todo-list-page/todo-list-page.component.css | 4 +++ Timeline/ClientApp/src/app/todo-list.service.ts | 39 ++++++++++++++-------- Timeline/Configs/TodoListConfig.cs | 12 +++++++ Timeline/Controllers/TodoListController.cs | 30 +++++++++++++++++ Timeline/Controllers/UserController.cs | 2 -- Timeline/Startup.cs | 2 ++ 6 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 Timeline/Configs/TodoListConfig.cs create mode 100644 Timeline/Controllers/TodoListController.cs (limited to 'Timeline/ClientApp/src') diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.css b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.css index 43bd26d8..c17267c5 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.css +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.css @@ -6,3 +6,7 @@ width: 1.2rem; height: 1.2rem; } + +mat-list-item { + margin: 10px; +} diff --git a/Timeline/ClientApp/src/app/todo-list.service.ts b/Timeline/ClientApp/src/app/todo-list.service.ts index b1bc5ff3..238919d3 100644 --- a/Timeline/ClientApp/src/app/todo-list.service.ts +++ b/Timeline/ClientApp/src/app/todo-list.service.ts @@ -28,28 +28,41 @@ export interface WorkItem { export class TodoListService { private username = 'crupest'; - private pat = 'ehnmegogmk6r7qlkpy6zdl2hnfl6ntqbvggzxvvgp4a5vhr7lmnq'; private organization = 'crupest-web'; private project = 'Timeline'; private fieldId = 'System.Title'; - private headers: HttpHeaders; - constructor(private client: HttpClient) { - this.headers = new HttpHeaders({ - 'Accept': 'application/json', - 'Authorization': `Basic ${btoa(this.username + ':' + this.pat)}` + constructor(private client: HttpClient) { } + + private getAzureDevOpsPat(): Observable { + return this.client.get('/api/TodoList/AzureDevOpsPat', { + headers: { + 'Accept': 'text/plain' + }, + responseType: 'text' }); } getWorkItemList(): Observable { - return this.client.post(`https://dev.azure.com/${this.organization}/${this.project}/_apis/wit/wiql?api-version=5.0`, { - query: 'SELECT [System.Id] FROM workitems WHERE [System.TeamProject] = @project' - }, { headers: this.headers }).pipe( - switchMap(result => result.workItems), - concatMap(result => this.client.get(result.url, {headers: this.headers})), - map(result => { id: result.id, title: result.fields[this.fieldId] }), - toArray() + return this.getAzureDevOpsPat().pipe( + switchMap( + pat => { + const headers = new HttpHeaders({ + 'Accept': 'application/json', + 'Authorization': `Basic ${btoa(this.username + ':' + pat)}` + }); + return this.client.post( + `https://dev.azure.com/${this.organization}/${this.project}/_apis/wit/wiql?api-version=5.0`, { + query: 'SELECT [System.Id] FROM workitems WHERE [System.TeamProject] = @project' + }, { headers: headers }).pipe( + switchMap(result => result.workItems), + concatMap(result => this.client.get(result.url, { headers: headers })), + map(result => { id: result.id, title: result.fields[this.fieldId] }), + toArray() + ); + } + ) ); } } diff --git a/Timeline/Configs/TodoListConfig.cs b/Timeline/Configs/TodoListConfig.cs new file mode 100644 index 00000000..a69e8d03 --- /dev/null +++ b/Timeline/Configs/TodoListConfig.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Timeline.Configs +{ + public class TodoListConfig + { + public string AzureDevOpsPat { get; set; } + } +} diff --git a/Timeline/Controllers/TodoListController.cs b/Timeline/Controllers/TodoListController.cs new file mode 100644 index 00000000..b773ed2e --- /dev/null +++ b/Timeline/Controllers/TodoListController.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using Timeline.Configs; + +namespace Timeline.Controllers +{ + [Route("api/[controller]")] + public class TodoListController : Controller + { + private readonly IOptionsMonitor _config; + + public TodoListController(IOptionsMonitor config) + { + _config = config; + } + + [HttpGet("[action]")] + [AllowAnonymous] + [Produces("text/plain")] + public ActionResult AzureDevOpsPat() + { + return Ok(_config.CurrentValue.AzureDevOpsPat); + } + } +} diff --git a/Timeline/Controllers/UserController.cs b/Timeline/Controllers/UserController.cs index 1ffed22b..45242ce3 100644 --- a/Timeline/Controllers/UserController.cs +++ b/Timeline/Controllers/UserController.cs @@ -1,8 +1,6 @@ using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http.Internal; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; -using System.IO; using Timeline.Entities; using Timeline.Services; diff --git a/Timeline/Startup.cs b/Timeline/Startup.cs index 6381a58a..a6bde7fd 100644 --- a/Timeline/Startup.cs +++ b/Timeline/Startup.cs @@ -41,6 +41,8 @@ namespace Timeline }); + services.Configure(Configuration.GetSection("TodoListConfig")); + services.Configure(Configuration.GetSection("JwtConfig")); var jwtConfig = Configuration.GetSection("JwtConfig").Get(); -- cgit v1.2.3