/frontend/todo/src/app/app-routing.module.ts
import { TodoComponent } from './todo/todo.component';
import { RouteGuardService } from './service/route-guard.service';
import { LogoutComponent } from './logout/logout.component';
import { ListTodosComponent } from './list-todos/list-todos.component';
import { WelcomeComponent } from './welcome/welcome.component';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { ErrorComponent } from './error/error.component';
// welcome
const routes: Routes = [
{ path: '', component: LoginComponent },//canActivate, RouteGuardService
{ path: 'login', component: LoginComponent },
{ path: 'welcome/:name', component: WelcomeComponent, canActivate:[RouteGuardService]},
{ path: 'todos', component: ListTodosComponent, canActivate:[RouteGuardService] },
{ path: 'logout', component: LogoutComponent, canActivate:[RouteGuardService] },
{ path: 'todos/:id', component: TodoComponent, canActivate:[RouteGuardService] },
{ path: '**', component: ErrorComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
/frontend/todo/src/app/app.component.css
/frontend/todo/src/app/app.component.html
<!--<app-welcome></app-welcome>-->
<!-- <app-login></app-login> -->
<!--
<div>Component Content</div>-->
< app-menu > </ app-menu >
< div class ="container ">
< router-outlet > </ router-outlet >
</ div >
< app-footer > </ app-footer >
/frontend/todo/src/app/app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
//template: '<h1>{{title}}<h1>',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'todo';
message = 'Welcome to in28Minutes';
}
/frontend/todo/src/app/app.module.ts
import { HttpIntercepterBasicAuthService } from './service/http/http-intercepter-basic-auth.service';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { WelcomeComponent } from './welcome/welcome.component';
import { LoginComponent } from './login/login.component';
import { ErrorComponent } from './error/error.component';
import { ListTodosComponent } from './list-todos/list-todos.component';
import { MenuComponent } from './menu/menu.component';
import { FooterComponent } from './footer/footer.component';
import { LogoutComponent } from './logout/logout.component';
import { TodoComponent } from './todo/todo.component';
@NgModule({
declarations: [
AppComponent,
WelcomeComponent,
LoginComponent,
ErrorComponent,
ListTodosComponent,
MenuComponent,
FooterComponent,
LogoutComponent,
TodoComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
HttpClientModule
],
providers: [
{provide: HTTP_INTERCEPTORS, useClass: HttpIntercepterBasicAuthService, multi: true }
],
bootstrap: [AppComponent]
})
export class AppModule { }
/frontend/todo/src/app/error/error.component.css
/frontend/todo/src/app/error/error.component.html
/frontend/todo/src/app/error/error.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-error',
templateUrl: './error.component.html',
styleUrls: ['./error.component.css']
})
export class ErrorComponent implements OnInit {
errorMessage = 'An Error Occured! Contact Support at *** - ***'
constructor() { }
ngOnInit() {
}
}
/frontend/todo/src/app/footer/footer.component.css
.footer {
position : absolute;
bottom : 0 ;
width : 100% ;
height : 40px ;
background-color : # 222222 ;
}
/frontend/todo/src/app/footer/footer.component.html
< footer class ="footer ">
< div class ="container ">
< span class ="text-muted "> All Rights Reserved 2018 @in28minutes</ span >
</ div >
</ footer >
/frontend/todo/src/app/footer/footer.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-footer',
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.css']
})
export class FooterComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
/frontend/todo/src/app/list-todos/list-todos.component.css
/frontend/todo/src/app/list-todos/list-todos.component.html
< h1 > Todo </ h1 >
< div class ="alert alert-success " *ngIf ='message '> {{message}}</ div >
< div class ="container ">
< table class ="table ">
< thead >
< tr >
< th > Description</ th >
< th > Target Date</ th >
< th > is Completed?</ th >
< th > Update</ th >
< th > Delete</ th >
</ tr >
</ thead >
< tbody >
<!-- for (Todo todo: todos) { -->
< tr *ngFor ="let todo of todos ">
< td > {{todo.description}}</ td >
< td > {{todo.targetDate | date | uppercase}}</ td >
< td > {{todo.done}}</ td >
< td > < button (click) ="updateTodo(todo.id) " class ="btn btn-success "> Update</ button > </ td >
< td > < button (click) ="deleteTodo(todo.id) " class ="btn btn-warning "> Delete</ button > </ td >
</ tr >
<!-- } -->
</ tbody >
</ table >
< div class ="row ">
< button (click) ="addTodo() " class ="btn btn-success "> Add</ button >
</ div >
</ div >
/frontend/todo/src/app/list-todos/list-todos.component.ts
import { TodoDataService } from './../service/data/todo-data.service';
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
export class Todo {
constructor(
public id: number,
public description: string,
public done: boolean,
public targetDate: Date
){
}
}
@Component({
selector: 'app-list-todos',
templateUrl: './list-todos.component.html',
styleUrls: ['./list-todos.component.css']
})
export class ListTodosComponent implements OnInit {
todos: Todo[]
message: string
// = [
// new Todo(1, 'Learn to Dance', false, new Date()),
// new Todo(2, 'Become an Expert at Angular', false, new Date()),
// new Todo(3, 'Visit India', false, new Date())
// // {id : 1, description : },
// // {id : 2, description : ''},
// // {id : 3, description : 'Visit India'}
// ]
// todo = {
// id : 1,
// description: 'Learn to Dance'
// }
constructor(
private todoService:TodoDataService,
private router : Router
) { }
ngOnInit() {
this.refreshTodos();
}
refreshTodos(){
this.todoService.retrieveAllTodos('in28minutes').subscribe(
response => {
console.log(response);
this.todos = response;
}
)
}
deleteTodo(id) {
console.log(`delete todo ${id}` )
this.todoService.deleteTodo('in28minutes', id).subscribe (
response => {
console.log(response);
this.message = `Delete of Todo ${id} Successful!`;
this.refreshTodos();
}
)
}
updateTodo(id) {
console.log(`update ${id}`)
this.router.navigate(['todos',id])
}
addTodo() {
this.router.navigate(['todos',-1])
}
}
/frontend/todo/src/app/login/login.component.css
/frontend/todo/src/app/login/login.component.html
< H1 > Login!</ H1 >
< div class ="container ">
< div class ="alert alert-warning " *ngIf ='invalidLogin '> {{errorMessage}}</ div >
< div >
User Name : < input type ="text " name ="username " [(ngModel)] ="username ">
Password : < input type ="password " name ="password " [(ngModel)] ="password ">
<!-- User Name : {{username}} -->
<!-- <button (click)=handleLogin() class="btn btn-success">Login</button> -->
< button (click) =handleBasicAuthLogin() class ="btn btn-success "> Login</ button >
</ div >
</ div >
/frontend/todo/src/app/login/login.component.ts
import { BasicAuthenticationService } from './../service/basic-authentication.service';
import { HardcodedAuthenticationService } from './../service/hardcoded-authentication.service';
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
username = 'in28minutes'
password = ''
errorMessage = 'Invalid Credentials'
invalidLogin = false
//Router
//Angular.giveMeRouter
//Dependency Injection
constructor(private router: Router,
private hardcodedAuthenticationService: HardcodedAuthenticationService,
private basicAuthenticationService: BasicAuthenticationService) { }
ngOnInit() {
}
handleLogin() {
// console.log(this.username);
//if(this.username==="in28minutes" && this.password === 'dummy') {
if(this.hardcodedAuthenticationService.authenticate(this.username, this.password)) {
//Redirect to Welcome Page
this.router.navigate(['welcome', this.username])
this.invalidLogin = false
} else {
this.invalidLogin = true
}
}
handleBasicAuthLogin() {
// console.log(this.username);
//if(this.username==="in28minutes" && this.password === 'dummy') {
this.basicAuthenticationService.executeAuthenticationService(this.username, this.password)
.subscribe(
data => {
console.log(data)
this.router.navigate(['welcome', this.username])
this.invalidLogin = false
},
error => {
console.log(error)
this.invalidLogin = true
}
)
}
}
/frontend/todo/src/app/logout/logout.component.css
/frontend/todo/src/app/logout/logout.component.html
< H1 > You are logged out</ H1 >
< div class ="container ">
Thank You For Using Our Application.
</ div >
/frontend/todo/src/app/logout/logout.component.ts
import { HardcodedAuthenticationService } from './../service/hardcoded-authentication.service';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-logout',
templateUrl: './logout.component.html',
styleUrls: ['./logout.component.css']
})
export class LogoutComponent implements OnInit {
constructor(
private hardcodedAuthenticationService: HardcodedAuthenticationService
) { }
ngOnInit() {
this.hardcodedAuthenticationService.logout();
}
}
/frontend/todo/src/app/menu/menu.component.css
/frontend/todo/src/app/menu/menu.component.html
< header >
< nav class ="navbar navbar-expand-md navbar-dark bg-dark ">
< div > < a href ="https://www.in28minutes.com " class ="navbar-brand ">
in28minutes</ a > </ div >
< ul class ="navbar-nav ">
< li > < a *ngIf ="hardcodedAuthenticationService.isUserLoggedIn() " routerLink ="/welcome/in28minutes " class ="nav-link "> Home</ a > </ li >
< li > < a *ngIf ="hardcodedAuthenticationService.isUserLoggedIn() " routerLink ="/todos " class ="nav-link "> Todos</ a > </ li >
</ ul >
< ul class ="navbar-nav navbar-collapse justify-content-end ">
< li > < a *ngIf ="!hardcodedAuthenticationService.isUserLoggedIn() " routerLink ="/login " class ="nav-link "> Login</ a > </ li >
< li > < a *ngIf ="hardcodedAuthenticationService.isUserLoggedIn() " routerLink ="/logout " class ="nav-link "> Logout</ a > </ li >
</ ul >
</ nav >
</ header >
/frontend/todo/src/app/menu/menu.component.ts
import { HardcodedAuthenticationService } from './../service/hardcoded-authentication.service';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-menu',
templateUrl: './menu.component.html',
styleUrls: ['./menu.component.css']
})
export class MenuComponent implements OnInit {
//isUserLoggedIn: boolean = false;
constructor(private hardcodedAuthenticationService
: HardcodedAuthenticationService) { }
ngOnInit() {
//this.isUserLoggedIn = this.hardcodedAuthenticationService.isUserLoggedIn();
}
}
/frontend/todo/src/app/service/basic-authentication.service.ts
import { HttpHeaders, HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import {map} from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class BasicAuthenticationService {
constructor(private http: HttpClient) { }
executeAuthenticationService(username, password) {
let basicAuthHeaderString = 'Basic ' + window.btoa(username + ':' + password);
let headers = new HttpHeaders({
Authorization: basicAuthHeaderString
})
return this.http.get<AuthenticationBean>(
`http://localhost:8080/basicauth`,
{headers}).pipe(
map(
data => {
sessionStorage.setItem('authenticaterUser', username);
sessionStorage.setItem('token', basicAuthHeaderString);
return data;
}
)
);
//console.log("Execute Hello World Bean Service")
}
getAuthenticatedUser() {
return sessionStorage.getItem('authenticaterUser')
}
getAuthenticatedToken() {
if(this.getAuthenticatedUser())
return sessionStorage.getItem('token')
}
isUserLoggedIn() {
let user = sessionStorage.getItem('authenticaterUser')
return !(user === null)
}
logout(){
sessionStorage.removeItem('authenticaterUser')
sessionStorage.removeItem('token')
}
}
export class AuthenticationBean{
constructor(public message:string) { }
}
/frontend/todo/src/app/service/data/todo-data.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Todo } from '../../list-todos/list-todos.component';
@Injectable({
providedIn: 'root'
})
export class TodoDataService {
constructor(
private http:HttpClient
) { }
retrieveAllTodos(username) {
return this.http.get<Todo[]>(`http://localhost:8080/users/${username}/todos`);
//console.log("Execute Hello World Bean Service")
}
deleteTodo(username, id){
return this.http.delete(`http://localhost:8080/users/${username}/todos/${id}`);
}
retrieveTodo(username, id){
return this.http.get<Todo>(`http://localhost:8080/users/${username}/todos/${id}`);
}
updateTodo(username, id, todo){
return this.http.put(
`http://localhost:8080/users/${username}/todos/${id}`
, todo);
}
createTodo(username, todo){
return this.http.post(
`http://localhost:8080/users/${username}/todos`
, todo);
}
}
/frontend/todo/src/app/service/data/welcome-data.service.ts
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
export class HelloWorldBean {
constructor(public message:string){ }
}
@Injectable({
providedIn: 'root'
})
export class WelcomeDataService {
constructor(
private http:HttpClient
) { }
executeHelloWorldBeanService() {
return this.http.get<HelloWorldBean>('http://localhost:8080/hello-world-bean');
//console.log("Execute Hello World Bean Service")
}
//http://localhost:8080/hello-world/path-variable/in28minutes
executeHelloWorldServiceWithPathVariable(name) {
// let basicAuthHeaderString = this.createBasicAuthenticationHttpHeader();
// let headers = new HttpHeaders({
// Authorization: basicAuthHeaderString
// })
return this.http.get<HelloWorldBean>(
`http://localhost:8080/hello-world/path-variable/${name}`,
//{headers}
);
//console.log("Execute Hello World Bean Service")
}
// createBasicAuthenticationHttpHeader() {
// let username = 'in28minutes'
// let password = 'dummy'
// let basicAuthHeaderString = 'Basic ' + window.btoa(username + ':' + password);
// return basicAuthHeaderString;
// }
//Access to XMLHttpRequest at
//'http://localhost:8080/hello-world/path-variable/in28minutes'
//from origin 'http://localhost:4200' has been blocked by CORS policy:
//No 'Access-Control-Allow-Origin' header is present on the requested resource.
//Access to XMLHttpRequest at 'http://localhost:8080/hello-world/path-variable/in28minutes' from origin 'http://localhost:4200'
//has been blocked by CORS policy:
//Response to preflight request doesn't pass
//access control check: It does not have HTTP ok status
}
/frontend/todo/src/app/service/hardcoded-authentication.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class HardcodedAuthenticationService {
constructor() { }
authenticate(username, password) {
//console.log('before ' + this.isUserLoggedIn());
if(username==="in28minutes" && password === 'dummy') {
sessionStorage.setItem('authenticaterUser', username);
//console.log('after ' + this.isUserLoggedIn());
return true;
}
return false;
}
isUserLoggedIn() {
let user = sessionStorage.getItem('authenticaterUser')
return !(user === null)
}
logout(){
sessionStorage.removeItem('authenticaterUser')
}
}
/frontend/todo/src/app/service/http/http-intercepter-basic-auth.service.ts
import { BasicAuthenticationService } from './../basic-authentication.service';
import { HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class HttpIntercepterBasicAuthService implements HttpInterceptor{
constructor(
private basicAuthenticationService : BasicAuthenticationService
) { }
intercept(request: HttpRequest<any>, next: HttpHandler){
// let username = 'in28minutes'
// let password = 'dummy'
//let basicAuthHeaderString = 'Basic ' + window.btoa(username + ':' + password);
let basicAuthHeaderString = this.basicAuthenticationService.getAuthenticatedToken();
let username = this.basicAuthenticationService.getAuthenticatedUser()
if(basicAuthHeaderString && username) {
request = request.clone({
setHeaders : {
Authorization : basicAuthHeaderString
}
})
}
return next.handle(request);
}
}
/frontend/todo/src/app/service/route-guard.service.ts
import { HardcodedAuthenticationService } from './hardcoded-authentication.service';
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class RouteGuardService implements CanActivate {
constructor(
private hardcodedAuthenticationService: HardcodedAuthenticationService,
private router: Router) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (this.hardcodedAuthenticationService.isUserLoggedIn())
return true;
this.router.navigate(['login']);
return false;
}
}
/frontend/todo/src/app/todo/todo.component.css
.ng-invalid : not (form ) {
border-left : 5px solid red;
}
/frontend/todo/src/app/todo/todo.component.html
< H1 > Todo</ H1 >
< div class ="container ">
< div class ="alert alert-warning " *ngIf ="todoForm.dirty && todoForm.invalid "> Enter valid values</ div >
< div class ="alert alert-warning " *ngIf ="todoForm.dirty && targetDate.invalid "> Enter valid Target Date</ div >
< div class ="alert alert-warning " *ngIf ="todoForm.dirty && description.invalid "> Enter atleast 5 characters in Description</ div >
< form (ngSubmit) ="!todoForm.invalid && saveTodo() " #todoForm ="ngForm ">
< fieldset class ="form-group ">
< label > Description</ label >
< input type ="text " #description ="ngModel "
[(ngModel)] ="todo.description " class ="form-control "
name ="description " required ="required " minlength ="5 ">
</ fieldset >
< fieldset class ="form-group ">
< label > Target Date</ label >
< input type ="date " #targetDate ="ngModel "
[ngModel] ="todo.targetDate | date:'yyyy-MM-dd' "
(ngModelChange) ="todo.targetDate = $event "
class ="form-control " name ="targetDate " required ="required " >
</ fieldset >
< button type ="submit " class ="btn btn-success "> Save</ button >
</ form >
</ div >
/frontend/todo/src/app/todo/todo.component.ts
import { ActivatedRoute, Router } from '@angular/router';
import { TodoDataService } from './../service/data/todo-data.service';
import { Component, OnInit } from '@angular/core';
import { Todo } from '../list-todos/list-todos.component';
@Component({
selector: 'app-todo',
templateUrl: './todo.component.html',
styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {
id:number
todo: Todo
constructor(
private todoService: TodoDataService,
private route: ActivatedRoute,
private router: Router
) { }
ngOnInit() {
this.id = this.route.snapshot.params['id'];
this.todo = new Todo(this.id,'',false,new Date());
if(this.id!=-1) {
this.todoService.retrieveTodo('in28minutes', this.id)
.subscribe (
data => this.todo = data
)
}
}
saveTodo() {
if(this.id === -1) {
this.todoService.createTodo('in28minutes', this.todo)
.subscribe (
data => {
console.log(data)
this.router.navigate(['todos'])
}
)
} else {
this.todoService.updateTodo('in28minutes', this.id, this.todo)
.subscribe (
data => {
console.log(data)
this.router.navigate(['todos'])
}
)
}
}
}
/frontend/todo/src/app/welcome/welcome.component.css
/frontend/todo/src/app/welcome/welcome.component.html
< H1 > Welcome!</ H1 >
< div class ="container ">
Welcome {{name}}. You can manage your todos < a routerLink ="/todos "> here</ a >
</ div >
< div class ="container ">
Click here to get a customized welcome message
< button (click) ="getWelcomeMessageWithParameter() " class ="btn btn-success "> Get Welcome Message</ button >
</ div >
< div class ="container " *ngIf ="welcomeMessageFromService ">
< H2 > Your Customized Welcome Message</ H2 >
{{welcomeMessageFromService}}
</ div >
/frontend/todo/src/app/welcome/welcome.component.ts
import { WelcomeDataService } from './../service/data/welcome-data.service';
import { ActivatedRoute } from '@angular/router';
//package com.in28minutes.springboot.web;
//import org.springframework.boot.SpringApplication;
import { Component, OnInit } from '@angular/core';//'./app.component';
//import { AppComponent } from '../app.component';
//@ComponentScan(
// value = "com.in28minutes.springboot.web")
@Component({
selector: 'app-welcome',
templateUrl: './welcome.component.html',
styleUrls: ['./welcome.component.css']
})
//public class SpringBootFirstWebApplication implements SomeInterface{
export class WelcomeComponent implements OnInit {
message = 'Some Welcome Message'
welcomeMessageFromService:string
name = ''
//String message = "Some Welcome Message"
//public SpringBootFirstWebApplication() {
//ActivatedRoute
constructor(
private route:ActivatedRoute,
private service:WelcomeDataService) {
}
// void init() {
ngOnInit(){
//COMPILATION ERROR this.message = 5
//console.log(this.message)
// console.log(this.route.snapshot.params['name'])
this.name = this.route.snapshot.params['name'];
}
getWelcomeMessage() {
//console.log(this.service.executeHelloWorldBeanService());
this.service.executeHelloWorldBeanService().subscribe(
response => this.handleSuccessfulResponse(response),
error => this.handleErrorResponse(error)
);
//console.log('last line of getWelcomeMessage')
//console.log("get welcome message");
}
getWelcomeMessageWithParameter() {
//console.log(this.service.executeHelloWorldBeanService());
this.service.executeHelloWorldServiceWithPathVariable(this.name).subscribe(
response => this.handleSuccessfulResponse(response),
error => this.handleErrorResponse(error)
);
//console.log('last line of getWelcomeMessage')
//console.log("get welcome message");
}
handleSuccessfulResponse(response){
this.welcomeMessageFromService = response.message
//console.log(response);
//console.log(response.message);
}
handleErrorResponse(error) {
//console.log(error);
//console.log(error.error);
//console.log(error.error.message);
this.welcomeMessageFromService = error.error.message
}
}
export class Class1 {
}
export class Class2 {
}
/frontend/todo/src/browserslist
# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
#
# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11
/frontend/todo/src/environments/environment.prod.ts
export const environment = {
production: true
};
/frontend/todo/src/environments/environment.ts
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false
};
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
/frontend/todo/src/index.html
<!doctype html>
< html lang ="en ">
< head >
< meta charset ="utf-8 ">
< title > My Todos Application</ title >
< base href ="/ ">
< meta name ="viewport " content ="width=device-width, initial-scale=1 ">
< link rel ="icon " type ="image/x-icon " href ="favicon.ico ">
</ head >
< body >
< app-root > </ app-root >
<!-- <div>Index HTML Content</div> -->
</ body >
</ html >
/frontend/todo/src/karma.conf.js
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module . exports = function ( config ) {
config . set ( {
basePath : '' ,
frameworks : [ 'jasmine' , '@angular-devkit/build-angular' ] ,
plugins : [
require ( 'karma-jasmine' ) ,
require ( 'karma-chrome-launcher' ) ,
require ( 'karma-jasmine-html-reporter' ) ,
require ( 'karma-coverage-istanbul-reporter' ) ,
require ( '@angular-devkit/build-angular/plugins/karma' )
] ,
client : {
clearContext : false // leave Jasmine Spec Runner output visible in browser
} ,
coverageIstanbulReporter : {
dir : require ( 'path' ) . join ( __dirname , '../coverage' ) ,
reports : [ 'html' , 'lcovonly' ] ,
fixWebpackSourcePaths : true
} ,
reporters : [ 'progress' , 'kjhtml' ] ,
port : 9876 ,
colors : true ,
logLevel : config . LOG_INFO ,
autoWatch : true ,
browsers : [ 'Chrome' ] ,
singleRun : false
} ) ;
} ;
/frontend/todo/src/main.ts
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
/frontend/todo/src/polyfills.ts
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/guide/browser-support
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
// import 'core-js/es6/symbol';
// import 'core-js/es6/object';
// import 'core-js/es6/function';
// import 'core-js/es6/parse-int';
// import 'core-js/es6/parse-float';
// import 'core-js/es6/number';
// import 'core-js/es6/math';
// import 'core-js/es6/string';
// import 'core-js/es6/date';
// import 'core-js/es6/array';
// import 'core-js/es6/regexp';
// import 'core-js/es6/map';
// import 'core-js/es6/weak-map';
// import 'core-js/es6/set';
/**
* If the application will be indexed by Google Search, the following is required.
* Googlebot uses a renderer based on Chrome 41.
* https://developers.google.com/search/docs/guides/rendering
**/
// import 'core-js/es6/array';
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/** IE10 and IE11 requires the following for the Reflect API. */
// import 'core-js/es6/reflect';
/**
* Web Animations `@angular/platform-browser/animations`
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
**/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
*/
// (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
// (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
// (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
/*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*/
// (window as any).__Zone_enable_cross_context_check = true;
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/
/frontend/todo/src/styles.css
/* You can add global styles to this file, and also import other style files */
@import url (https://unpkg.com/[email protected] /dist/css/bootstrap.min.css)
/frontend/todo/src/test.ts
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);
/frontend/todo/src/todos.txt
- <script type="text/javascript" src="runtime.js">
</script><script type="text/javascript" src="polyfills.js"></script><script type="text/javascript" src="styles.js">
</script><script type="text/javascript" src="vendor.js"></script><script type="text/javascript" src="main.js"></script>
/frontend/todo/angular.json
{
"$schema" : " ./node_modules/@angular/cli/lib/config/schema.json" ,
"version" : 1 ,
"newProjectRoot" : " projects" ,
"projects" : {
"todo" : {
"root" : " " ,
"sourceRoot" : " src" ,
"projectType" : " application" ,
"prefix" : " app" ,
"schematics" : {},
"architect" : {
"build" : {
"builder" : " @angular-devkit/build-angular:browser" ,
"options" : {
"outputPath" : " dist/todo" ,
"index" : " src/index.html" ,
"main" : " src/main.ts" ,
"polyfills" : " src/polyfills.ts" ,
"tsConfig" : " src/tsconfig.app.json" ,
"assets" : [
" src/favicon.ico" ,
" src/assets"
],
"styles" : [
" src/styles.css"
],
"scripts" : []
},
"configurations" : {
"production" : {
"fileReplacements" : [
{
"replace" : " src/environments/environment.ts" ,
"with" : " src/environments/environment.prod.ts"
}
],
"optimization" : true ,
"outputHashing" : " all" ,
"sourceMap" : false ,
"extractCss" : true ,
"namedChunks" : false ,
"aot" : true ,
"extractLicenses" : true ,
"vendorChunk" : false ,
"buildOptimizer" : true ,
"budgets" : [
{
"type" : " initial" ,
"maximumWarning" : " 2mb" ,
"maximumError" : " 5mb"
}
]
}
}
},
"serve" : {
"builder" : " @angular-devkit/build-angular:dev-server" ,
"options" : {
"browserTarget" : " todo:build"
},
"configurations" : {
"production" : {
"browserTarget" : " todo:build:production"
}
}
},
"extract-i18n" : {
"builder" : " @angular-devkit/build-angular:extract-i18n" ,
"options" : {
"browserTarget" : " todo:build"
}
},
"test" : {
"builder" : " @angular-devkit/build-angular:karma" ,
"options" : {
"main" : " src/test.ts" ,
"polyfills" : " src/polyfills.ts" ,
"tsConfig" : " src/tsconfig.spec.json" ,
"karmaConfig" : " src/karma.conf.js" ,
"styles" : [
" src/styles.css"
],
"scripts" : [],
"assets" : [
" src/favicon.ico" ,
" src/assets"
]
}
},
"lint" : {
"builder" : " @angular-devkit/build-angular:tslint" ,
"options" : {
"tsConfig" : [
" src/tsconfig.app.json" ,
" src/tsconfig.spec.json"
],
"exclude" : [
" **/node_modules/**"
]
}
}
}
},
"todo-e2e" : {
"root" : " e2e/" ,
"projectType" : " application" ,
"prefix" : " " ,
"architect" : {
"e2e" : {
"builder" : " @angular-devkit/build-angular:protractor" ,
"options" : {
"protractorConfig" : " e2e/protractor.conf.js" ,
"devServerTarget" : " todo:serve"
},
"configurations" : {
"production" : {
"devServerTarget" : " todo:serve:production"
}
}
},
"lint" : {
"builder" : " @angular-devkit/build-angular:tslint" ,
"options" : {
"tsConfig" : " e2e/tsconfig.e2e.json" ,
"exclude" : [
" **/node_modules/**"
]
}
}
}
}
},
"defaultProject" : " todo"
}
/frontend/todo/package.json
{
"name" : " todo" ,
"version" : " 0.0.0" ,
"scripts" : {
"ng" : " ng" ,
"start" : " ng serve" ,
"build" : " ng build" ,
"test" : " ng test" ,
"lint" : " ng lint" ,
"e2e" : " ng e2e"
},
"private" : true ,
"dependencies" : {
"@angular/animations" : " ~7.0.0" ,
"@angular/common" : " ~7.0.0" ,
"@angular/compiler" : " ~7.0.0" ,
"@angular/core" : " ~7.0.0" ,
"@angular/forms" : " ~7.0.0" ,
"@angular/http" : " ~7.0.0" ,
"@angular/platform-browser" : " ~7.0.0" ,
"@angular/platform-browser-dynamic" : " ~7.0.0" ,
"@angular/router" : " ~7.0.0" ,
"core-js" : " ^2.5.4" ,
"rxjs" : " ~6.3.3" ,
"zone.js" : " ~0.8.26"
},
"devDependencies" : {
"@angular-devkit/build-angular" : " ~0.10.0" ,
"@angular/cli" : " ~7.0.3" ,
"@angular/compiler-cli" : " ~7.0.0" ,
"@angular/language-service" : " ~7.0.0" ,
"@types/node" : " ~8.9.4" ,
"@types/jasmine" : " ~2.8.8" ,
"@types/jasminewd2" : " ~2.0.3" ,
"codelyzer" : " ~4.5.0" ,
"jasmine-core" : " ~2.99.1" ,
"jasmine-spec-reporter" : " ~4.2.1" ,
"karma" : " ~3.0.0" ,
"karma-chrome-launcher" : " ~2.2.0" ,
"karma-coverage-istanbul-reporter" : " ~2.0.1" ,
"karma-jasmine" : " ~1.1.2" ,
"karma-jasmine-html-reporter" : " ^0.2.2" ,
"protractor" : " ~5.4.0" ,
"ts-node" : " ~7.0.0" ,
"tslint" : " ~5.11.0" ,
"typescript" : " ~3.1.1"
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/basic/auth/AuthenticationBean.java
package com .in28minutes .rest .webservices .restfulwebservices .basic .auth ;
public class AuthenticationBean {
private String message ;
public AuthenticationBean (String message ) {
this .message = message ;
}
public String getMessage () {
return message ;
}
public void setMessage (String message ) {
this .message = message ;
}
@ Override
public String toString () {
return String .format ("HelloWorldBean [message=%s]" , message );
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/basic/auth/BasicAuthenticationController.java
package com .in28minutes .rest .webservices .restfulwebservices .basic .auth ;
import org .springframework .web .bind .annotation .CrossOrigin ;
import org .springframework .web .bind .annotation .GetMapping ;
import org .springframework .web .bind .annotation .RestController ;
//Controller
@ CrossOrigin (origins ="http://localhost:4200" )
@ RestController
public class BasicAuthenticationController {
@ GetMapping (path = "/basicauth" )
public AuthenticationBean helloWorldBean () {
//throw new RuntimeException("Some Error has Happened! Contact Support at ***-***");
return new AuthenticationBean ("You are authenticated" );
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/basic/auth/SpringSecurityConfigurationBasicAuth.java
package com .in28minutes .rest .webservices .restfulwebservices .basic .auth ;
import org .springframework .context .annotation .Configuration ;
import org .springframework .http .HttpMethod ;
import org .springframework .security .config .annotation .web .builders .HttpSecurity ;
import org .springframework .security .config .annotation .web .configuration .EnableWebSecurity ;
import org .springframework .security .config .annotation .web .configuration .WebSecurityConfigurerAdapter ;
@ Configuration
@ EnableWebSecurity
public class SpringSecurityConfigurationBasicAuth extends WebSecurityConfigurerAdapter {
@ Override
protected void configure (HttpSecurity http ) throws Exception {
http
.csrf ().disable ()
.authorizeRequests ()
.antMatchers (HttpMethod .OPTIONS ,"/**" ).permitAll ()
.anyRequest ().authenticated ()
.and ()
//.formLogin().and()
.httpBasic ();
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/helloworld/HelloWorldBean.java
package com .in28minutes .rest .webservices .restfulwebservices .helloworld ;
public class HelloWorldBean {
private String message ;
public HelloWorldBean (String message ) {
this .message = message ;
}
public String getMessage () {
return message ;
}
public void setMessage (String message ) {
this .message = message ;
}
@ Override
public String toString () {
return String .format ("HelloWorldBean [message=%s]" , message );
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/helloworld/HelloWorldController.java
package com .in28minutes .rest .webservices .restfulwebservices .helloworld ;
import org .springframework .web .bind .annotation .CrossOrigin ;
import org .springframework .web .bind .annotation .GetMapping ;
import org .springframework .web .bind .annotation .PathVariable ;
import org .springframework .web .bind .annotation .RestController ;
//Controller
@ CrossOrigin (origins ="http://localhost:4200" )
@ RestController
public class HelloWorldController {
@ GetMapping (path = "/hello-world" )
public String helloWorld () {
return "Hello World" ;
}
@ GetMapping (path = "/hello-world-bean" )
public HelloWorldBean helloWorldBean () {
//throw new RuntimeException("Some Error has Happened! Contact Support at ***-***");
return new HelloWorldBean ("Hello World - Changed" );
}
///hello-world/path-variable/in28minutes
@ GetMapping (path = "/hello-world/path-variable/{name}" )
public HelloWorldBean helloWorldPathVariable (@ PathVariable String name ) {
return new HelloWorldBean (String .format ("Hello World, %s" , name ));
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplication.java
package com .in28minutes .rest .webservices .restfulwebservices ;
import org .springframework .boot .SpringApplication ;
import org .springframework .boot .autoconfigure .SpringBootApplication ;
@ SpringBootApplication
public class RestfulWebServicesApplication {
public static void main (String [] args ) {
SpringApplication .run (RestfulWebServicesApplication .class , args );
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/Todo.java
package com .in28minutes .rest .webservices .restfulwebservices .todo ;
import java .util .Date ;
public class Todo {
private long id ;
private String username ;
private String description ;
private Date targetDate ;
private boolean isDone ;
protected Todo () {
}
public Todo (long id , String username , String description , Date targetDate , boolean isDone ) {
super ();
this .id = id ;
this .username = username ;
this .description = description ;
this .targetDate = targetDate ;
this .isDone = isDone ;
}
public long getId () {
return id ;
}
public void setId (long id ) {
this .id = id ;
}
public String getUsername () {
return username ;
}
public void setUsername (String username ) {
this .username = username ;
}
public String getDescription () {
return description ;
}
public void setDescription (String description ) {
this .description = description ;
}
public Date getTargetDate () {
return targetDate ;
}
public void setTargetDate (Date targetDate ) {
this .targetDate = targetDate ;
}
public boolean isDone () {
return isDone ;
}
public void setDone (boolean isDone ) {
this .isDone = isDone ;
}
@ Override
public int hashCode () {
final int prime = 31 ;
int result = 1 ;
result = prime * result + (int ) (id ^ (id >>> 32 ));
return result ;
}
@ Override
public boolean equals (Object obj ) {
if (this == obj )
return true ;
if (obj == null )
return false ;
if (getClass () != obj .getClass ())
return false ;
Todo other = (Todo ) obj ;
if (id != other .id )
return false ;
return true ;
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoHardcodedService.java
package com .in28minutes .rest .webservices .restfulwebservices .todo ;
import java .util .ArrayList ;
import java .util .Date ;
import java .util .List ;
import org .springframework .stereotype .Service ;
@ Service
public class TodoHardcodedService {
private static List <Todo > todos = new ArrayList <>();
private static int idCounter = 0 ;
static {
todos .add (new Todo (++idCounter , "in28minutes" ,"Learn to Dance 2" , new Date (), false ));
todos .add (new Todo (++idCounter , "in28minutes" ,"Learn about Microservices 2" , new Date (), false ));
todos .add (new Todo (++idCounter , "in28minutes" ,"Learn about Angular" , new Date (), false ));
}
public List <Todo > findAll () {
return todos ;
}
public Todo save (Todo todo ) {
if (todo .getId ()==-1 || todo .getId ()==0 ) {
todo .setId (++idCounter );
todos .add (todo );
} else {
deleteById (todo .getId ());
todos .add (todo );
}
return todo ;
}
public Todo deleteById (long id ) {
Todo todo = findById (id );
if (todo ==null ) return null ;
if (todos .remove (todo )) {
return todo ;
}
return null ;
}
public Todo findById (long id ) {
for (Todo todo :todos ) {
if (todo .getId () == id ) {
return todo ;
}
}
return null ;
}
}
/restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/todo/TodoResource.java
package com .in28minutes .rest .webservices .restfulwebservices .todo ;
import java .net .URI ;
import java .util .List ;
import org .springframework .beans .factory .annotation .Autowired ;
import org .springframework .http .HttpStatus ;
import org .springframework .http .ResponseEntity ;
import org .springframework .web .bind .annotation .CrossOrigin ;
import org .springframework .web .bind .annotation .DeleteMapping ;
import org .springframework .web .bind .annotation .GetMapping ;
import org .springframework .web .bind .annotation .PathVariable ;
import org .springframework .web .bind .annotation .PostMapping ;
import org .springframework .web .bind .annotation .PutMapping ;
import org .springframework .web .bind .annotation .RequestBody ;
import org .springframework .web .bind .annotation .RestController ;
import org .springframework .web .servlet .support .ServletUriComponentsBuilder ;
import com .in28minutes .rest .webservices .restfulwebservices .todo .Todo ;
@ CrossOrigin (origins ="http://localhost:4200" )
@ RestController
public class TodoResource {
@ Autowired
private TodoHardcodedService todoService ;
@ GetMapping ("/users/{username}/todos" )
public List <Todo > getAllTodos (@ PathVariable String username ){
return todoService .findAll ();
}
@ GetMapping ("/users/{username}/todos/{id}" )
public Todo getTodo (@ PathVariable String username , @ PathVariable long id ){
return todoService .findById (id );
}
//DELETE /users/{username}/todos/{id}
@ DeleteMapping ("/users/{username}/todos/{id}" )
public ResponseEntity <Void > deleteTodo (
@ PathVariable String username , @ PathVariable long id ){
Todo todo = todoService .deleteById (id );
if (todo !=null ) {
return ResponseEntity .noContent ().build ();
}
return ResponseEntity .notFound ().build ();
}
//Edit/Update a Todo
//PUT /users/{user_name}/todos/{todo_id}
@ PutMapping ("/users/{username}/todos/{id}" )
public ResponseEntity <Todo > updateTodo (
@ PathVariable String username ,
@ PathVariable long id , @ RequestBody Todo todo ){
Todo todoUpdated = todoService .save (todo );
return new ResponseEntity <Todo >(todo , HttpStatus .OK );
}
@ PostMapping ("/users/{username}/todos" )
public ResponseEntity <Void > updateTodo (
@ PathVariable String username , @ RequestBody Todo todo ){
Todo createdTodo = todoService .save (todo );
//Location
//Get current resource url
///{id}
URI uri = ServletUriComponentsBuilder .fromCurrentRequest ()
.path ("/{id}" ).buildAndExpand (createdTodo .getId ()).toUri ();
return ResponseEntity .created (uri ).build ();
}
}
/restful-web-services/src/main/resources/application.properties
logging.level.org.springframework = info
spring.security.user.name =in28minutes
spring.security.user.password =dummy
/restful-web-services/src/test/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplicationTests.java
package com .in28minutes .rest .webservices .restfulwebservices ;
import org .junit .Test ;
import org .junit .runner .RunWith ;
import org .springframework .boot .test .context .SpringBootTest ;
import org .springframework .test .context .junit4 .SpringRunner ;
@ RunWith (SpringRunner .class )
@ SpringBootTest
public class RestfulWebServicesApplicationTests {
@ Test
public void contextLoads () {
}
}