Jelajahi Sumber

Add ToDoManagementCode

Sample test projecct for login registration and add delete update get list data
Jishnu Haridas 4 tahun lalu
melakukan
7c10f09cf2
66 mengubah file dengan 15797 tambahan dan 0 penghapusan
  1. 9 0
      .gitignore
  2. 36 0
      .vscode/launch.json
  3. 42 0
      .vscode/tasks.json
  4. 34 0
      ToDoManagementSystem.sln
  5. 231 0
      ToDoManagementSystem/.gitignore
  6. 13 0
      ToDoManagementSystem/ClientApp/.editorconfig
  7. 40 0
      ToDoManagementSystem/ClientApp/.gitignore
  8. 27 0
      ToDoManagementSystem/ClientApp/README.md
  9. 150 0
      ToDoManagementSystem/ClientApp/angular.json
  10. 9 0
      ToDoManagementSystem/ClientApp/browserslist
  11. 28 0
      ToDoManagementSystem/ClientApp/e2e/protractor.conf.js
  12. 14 0
      ToDoManagementSystem/ClientApp/e2e/src/app.e2e-spec.ts
  13. 11 0
      ToDoManagementSystem/ClientApp/e2e/src/app.po.ts
  14. 13 0
      ToDoManagementSystem/ClientApp/e2e/tsconfig.e2e.json
  15. 13675 0
      ToDoManagementSystem/ClientApp/package-lock.json
  16. 59 0
      ToDoManagementSystem/ClientApp/package.json
  17. 5 0
      ToDoManagementSystem/ClientApp/src/app/Interfaces/ToDoItem.ts
  18. 6 0
      ToDoManagementSystem/ClientApp/src/app/app.component.html
  19. 9 0
      ToDoManagementSystem/ClientApp/src/app/app.component.ts
  20. 27 0
      ToDoManagementSystem/ClientApp/src/app/app.module.ts
  21. 11 0
      ToDoManagementSystem/ClientApp/src/app/app.server.module.ts
  22. 3 0
      ToDoManagementSystem/ClientApp/src/app/components/home/home.component.css
  23. 45 0
      ToDoManagementSystem/ClientApp/src/app/components/home/home.component.html
  24. 78 0
      ToDoManagementSystem/ClientApp/src/app/components/home/home.component.ts
  25. 18 0
      ToDoManagementSystem/ClientApp/src/app/components/nav-menu/nav-menu.component.css
  26. 18 0
      ToDoManagementSystem/ClientApp/src/app/components/nav-menu/nav-menu.component.html
  27. 18 0
      ToDoManagementSystem/ClientApp/src/app/components/nav-menu/nav-menu.component.ts
  28. 12 0
      ToDoManagementSystem/ClientApp/src/app/services/todo.service.spec.ts
  29. 45 0
      ToDoManagementSystem/ClientApp/src/app/services/todo.service.ts
  30. 0 0
      ToDoManagementSystem/ClientApp/src/assets/.gitkeep
  31. 3 0
      ToDoManagementSystem/ClientApp/src/environments/environment.prod.ts
  32. 15 0
      ToDoManagementSystem/ClientApp/src/environments/environment.ts
  33. 17 0
      ToDoManagementSystem/ClientApp/src/index.html
  34. 31 0
      ToDoManagementSystem/ClientApp/src/karma.conf.js
  35. 20 0
      ToDoManagementSystem/ClientApp/src/main.ts
  36. 63 0
      ToDoManagementSystem/ClientApp/src/polyfills.ts
  37. 16 0
      ToDoManagementSystem/ClientApp/src/styles.css
  38. 20 0
      ToDoManagementSystem/ClientApp/src/test.ts
  39. 11 0
      ToDoManagementSystem/ClientApp/src/tsconfig.app.json
  40. 9 0
      ToDoManagementSystem/ClientApp/src/tsconfig.server.json
  41. 18 0
      ToDoManagementSystem/ClientApp/src/tsconfig.spec.json
  42. 17 0
      ToDoManagementSystem/ClientApp/src/tslint.json
  43. 21 0
      ToDoManagementSystem/ClientApp/tsconfig.json
  44. 130 0
      ToDoManagementSystem/ClientApp/tslint.json
  45. 96 0
      ToDoManagementSystem/Controllers/ToDoController.cs
  46. 58 0
      ToDoManagementSystem/Data/AppDbContext.cs
  47. 12 0
      ToDoManagementSystem/Domain/BaseEntity.cs
  48. 8 0
      ToDoManagementSystem/Domain/Entities/ToDoItem.cs
  49. 16 0
      ToDoManagementSystem/Interfaces/IRepository.cs
  50. 52 0
      ToDoManagementSystem/Migrations/20200616090218_intial-1.Designer.cs
  51. 33 0
      ToDoManagementSystem/Migrations/20200616090218_intial-1.cs
  52. 50 0
      ToDoManagementSystem/Migrations/AppDbContextModelSnapshot.cs
  53. 9 0
      ToDoManagementSystem/Models/DTO/ToDoItemDTO.cs
  54. 14 0
      ToDoManagementSystem/Models/Mapping/MappingProfile.cs
  55. 14 0
      ToDoManagementSystem/Models/Validation/ToDoItemValidator.cs
  56. 26 0
      ToDoManagementSystem/Pages/Error.cshtml
  57. 31 0
      ToDoManagementSystem/Pages/Error.cshtml.cs
  58. 3 0
      ToDoManagementSystem/Pages/_ViewImports.cshtml
  59. 26 0
      ToDoManagementSystem/Program.cs
  60. 27 0
      ToDoManagementSystem/Properties/launchSettings.json
  61. 57 0
      ToDoManagementSystem/Repository/EfRepository.cs
  62. 99 0
      ToDoManagementSystem/Startup.cs
  63. 67 0
      ToDoManagementSystem/ToDoManagementSystem.csproj
  64. 9 0
      ToDoManagementSystem/appsettings.Development.json
  65. 13 0
      ToDoManagementSystem/appsettings.json
  66. TEMPAT SAMPAH
      ToDoManagementSystem/wwwroot/favicon.ico

+ 9 - 0
.gitignore

@@ -0,0 +1,9 @@
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+*.code-workspace
+
+# Local History for Visual Studio Code
+.history/

+ 36 - 0
.vscode/launch.json

@@ -0,0 +1,36 @@
+{
+   // Use IntelliSense to find out which attributes exist for C# debugging
+   // Use hover for the description of the existing attributes
+   // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
+   "version": "0.2.0",
+   "configurations": [
+        {
+            "name": ".NET Core Launch (web)",
+            "type": "coreclr",
+            "request": "launch",
+            "preLaunchTask": "build",
+            // If you have changed target frameworks, make sure to update the program path.
+            "program": "${workspaceFolder}/ToDoManagementSystem/bin/Debug/netcoreapp3.1/ToDoManagementSystem.dll",
+            "args": [],
+            "cwd": "${workspaceFolder}/ToDoManagementSystem",
+            "stopAtEntry": false,
+            // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
+            "serverReadyAction": {
+                "action": "openExternally",
+                "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
+            },
+            "env": {
+                "ASPNETCORE_ENVIRONMENT": "Development"
+            },
+            "sourceFileMap": {
+                "/Views": "${workspaceFolder}/Views"
+            }
+        },
+        {
+            "name": ".NET Core Attach",
+            "type": "coreclr",
+            "request": "attach",
+            "processId": "${command:pickProcess}"
+        }
+    ]
+}

+ 42 - 0
.vscode/tasks.json

@@ -0,0 +1,42 @@
+{
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "build",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "build",
+                "${workspaceFolder}/ToDoManagementSystem/ToDoManagementSystem.csproj",
+                "/property:GenerateFullPaths=true",
+                "/consoleloggerparameters:NoSummary"
+            ],
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "publish",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "publish",
+                "${workspaceFolder}/ToDoManagementSystem/ToDoManagementSystem.csproj",
+                "/property:GenerateFullPaths=true",
+                "/consoleloggerparameters:NoSummary"
+            ],
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "watch",
+            "command": "dotnet",
+            "type": "process",
+            "args": [
+                "watch",
+                "run",
+                "${workspaceFolder}/ToDoManagementSystem/ToDoManagementSystem.csproj",
+                "/property:GenerateFullPaths=true",
+                "/consoleloggerparameters:NoSummary"
+            ],
+            "problemMatcher": "$msCompile"
+        }
+    ]
+}

+ 34 - 0
ToDoManagementSystem.sln

@@ -0,0 +1,34 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26124.0
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ToDoManagementSystem", "ToDoManagementSystem\ToDoManagementSystem.csproj", "{742FB458-7C79-465F-B00C-3D953124F078}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{742FB458-7C79-465F-B00C-3D953124F078}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{742FB458-7C79-465F-B00C-3D953124F078}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{742FB458-7C79-465F-B00C-3D953124F078}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{742FB458-7C79-465F-B00C-3D953124F078}.Debug|x64.Build.0 = Debug|Any CPU
+		{742FB458-7C79-465F-B00C-3D953124F078}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{742FB458-7C79-465F-B00C-3D953124F078}.Debug|x86.Build.0 = Debug|Any CPU
+		{742FB458-7C79-465F-B00C-3D953124F078}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{742FB458-7C79-465F-B00C-3D953124F078}.Release|Any CPU.Build.0 = Release|Any CPU
+		{742FB458-7C79-465F-B00C-3D953124F078}.Release|x64.ActiveCfg = Release|Any CPU
+		{742FB458-7C79-465F-B00C-3D953124F078}.Release|x64.Build.0 = Release|Any CPU
+		{742FB458-7C79-465F-B00C-3D953124F078}.Release|x86.ActiveCfg = Release|Any CPU
+		{742FB458-7C79-465F-B00C-3D953124F078}.Release|x86.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal

+ 231 - 0
ToDoManagementSystem/.gitignore

@@ -0,0 +1,231 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+build/
+bld/
+bin/
+Bin/
+obj/
+Obj/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Microsoft Azure ApplicationInsights config file
+ApplicationInsights.config
+
+# Windows Store app package directory
+AppPackages/
+BundleArtifacts/
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+/node_modules
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+
+# FAKE - F# Make
+.fake/

+ 13 - 0
ToDoManagementSystem/ClientApp/.editorconfig

@@ -0,0 +1,13 @@
+# Editor configuration, see http://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+max_line_length = off
+trim_trailing_whitespace = false

+ 40 - 0
ToDoManagementSystem/ClientApp/.gitignore

@@ -0,0 +1,40 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+
+# compiled output
+/dist
+/dist-server
+/tmp
+/out-tsc
+
+# dependencies
+/node_modules
+
+# IDEs and editors
+/.idea
+.project
+.classpath
+.c9/
+*.launch
+.settings/
+*.sublime-workspace
+
+# IDE - VSCode
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+
+# misc
+/.sass-cache
+/connect.lock
+/coverage
+/libpeerconnection.log
+npm-debug.log
+yarn-error.log
+testem.log
+/typings
+
+# System Files
+.DS_Store
+Thumbs.db

+ 27 - 0
ToDoManagementSystem/ClientApp/README.md

@@ -0,0 +1,27 @@
+# ToDoManagementSystem.Web
+
+This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 6.0.0.
+
+## Development server
+
+Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
+
+## Code scaffolding
+
+Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
+
+## Build
+
+Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
+
+## Running unit tests
+
+Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
+
+## Running end-to-end tests
+
+Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
+
+## Further help
+
+To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).

+ 150 - 0
ToDoManagementSystem/ClientApp/angular.json

@@ -0,0 +1,150 @@
+{
+  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+  "version": 1,
+  "newProjectRoot": "projects",
+  "projects": {
+    "ToDoManagementSystem.Web": {
+      "root": "",
+      "sourceRoot": "src",
+      "projectType": "application",
+      "prefix": "app",
+      "schematics": {},
+      "architect": {
+        "build": {
+          "builder": "@angular-devkit/build-angular:browser",
+          "options": {
+            "progress": false,
+            "extractCss": true,
+            "outputPath": "dist",
+            "index": "src/index.html",
+            "main": "src/main.ts",
+            "polyfills": "src/polyfills.ts",
+            "tsConfig": "src/tsconfig.app.json",
+            "assets": [
+              "src/assets"
+            ],
+            "styles": [
+              "node_modules/bootstrap/dist/css/bootstrap.min.css",
+              "src/styles.css",
+              "node_modules/font-awesome/css/font-awesome.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
+            }
+          }
+        },
+        "serve": {
+          "builder": "@angular-devkit/build-angular:dev-server",
+          "options": {
+            "browserTarget": "ToDoManagementSystem.Web:build"
+          },
+          "configurations": {
+            "production": {
+              "browserTarget": "ToDoManagementSystem.Web:build:production"
+            }
+          }
+        },
+        "extract-i18n": {
+          "builder": "@angular-devkit/build-angular:extract-i18n",
+          "options": {
+            "browserTarget": "ToDoManagementSystem.Web: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/assets"
+            ]
+          }
+        },
+        "lint": {
+          "builder": "@angular-devkit/build-angular:tslint",
+          "options": {
+            "tsConfig": [
+              "src/tsconfig.app.json",
+              "src/tsconfig.spec.json"
+            ],
+            "exclude": [
+              "**/node_modules/**"
+            ]
+          }
+        },
+        "server": {
+          "builder": "@angular-devkit/build-angular:server",
+          "options": {
+            "outputPath": "dist-server",
+            "main": "src/main.ts",
+            "tsConfig": "src/tsconfig.server.json"
+          },
+          "configurations": {
+            "dev": {
+              "optimization": true,
+              "outputHashing": "all",
+              "sourceMap": false,
+              "namedChunks": false,
+              "extractLicenses": true,
+              "vendorChunk": true
+            },
+            "production": {
+              "optimization": true,
+              "outputHashing": "all",
+              "sourceMap": false,
+              "namedChunks": false,
+              "extractLicenses": true,
+              "vendorChunk": false
+            }
+          }
+        }
+      }
+    },
+    "ToDoManagementSystem.Web-e2e": {
+      "root": "e2e/",
+      "projectType": "application",
+      "architect": {
+        "e2e": {
+          "builder": "@angular-devkit/build-angular:protractor",
+          "options": {
+            "protractorConfig": "e2e/protractor.conf.js",
+            "devServerTarget": "ToDoManagementSystem.Web:serve"
+          }
+        },
+        "lint": {
+          "builder": "@angular-devkit/build-angular:tslint",
+          "options": {
+            "tsConfig": "e2e/tsconfig.e2e.json",
+            "exclude": [
+              "**/node_modules/**"
+            ]
+          }
+        }
+      }
+    }
+  },
+  "defaultProject": "ToDoManagementSystem.Web"
+}

+ 9 - 0
ToDoManagementSystem/ClientApp/browserslist

@@ -0,0 +1,9 @@
+# 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 uncomment the last line of the file and adjust as needed
+> 0.5%
+last 2 versions
+Firefox ESR
+not dead
+# IE 9-11

+ 28 - 0
ToDoManagementSystem/ClientApp/e2e/protractor.conf.js

@@ -0,0 +1,28 @@
+// Protractor configuration file, see link for more information
+// https://github.com/angular/protractor/blob/master/lib/config.ts
+
+const { SpecReporter } = require("jasmine-spec-reporter");
+
+exports.config = {
+  allScriptsTimeout: 11000,
+  specs: ["./src/**/*.e2e-spec.ts"],
+  capabilities: {
+    browserName: "chrome"
+  },
+  directConnect: true,
+  baseUrl: "http://localhost:4200/",
+  framework: "jasmine",
+  jasmineNodeOpts: {
+    showColors: true,
+    defaultTimeoutInterval: 30000,
+    print: function() {}
+  },
+  onPrepare() {
+    require("ts-node").register({
+      project: require("path").join(__dirname, "./tsconfig.e2e.json")
+    });
+    jasmine
+      .getEnv()
+      .addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
+  }
+};

+ 14 - 0
ToDoManagementSystem/ClientApp/e2e/src/app.e2e-spec.ts

@@ -0,0 +1,14 @@
+import { AppPage } from './app.po';
+
+describe('App', () => {
+  let page: AppPage;
+
+  beforeEach(() => {
+    page = new AppPage();
+  });
+
+  it('should display welcome message', () => {
+    page.navigateTo();
+    expect(page.getMainHeading()).toEqual('Hello, world!');
+  });
+});

+ 11 - 0
ToDoManagementSystem/ClientApp/e2e/src/app.po.ts

@@ -0,0 +1,11 @@
+import { browser, by, element } from 'protractor';
+
+export class AppPage {
+  navigateTo() {
+    return browser.get('/');
+  }
+
+  getMainHeading() {
+    return element(by.css('app-root h1')).getText();
+  }
+}

+ 13 - 0
ToDoManagementSystem/ClientApp/e2e/tsconfig.e2e.json

@@ -0,0 +1,13 @@
+{
+  "extends": "../tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../out-tsc/app",
+    "module": "commonjs",
+    "target": "es5",
+    "types": [
+      "jasmine",
+      "jasminewd2",
+      "node"
+    ]
+  }
+}

File diff ditekan karena terlalu besar
+ 13675 - 0
ToDoManagementSystem/ClientApp/package-lock.json


+ 59 - 0
ToDoManagementSystem/ClientApp/package.json

@@ -0,0 +1,59 @@
+{
+  "name": "todomanagementsystem.web",
+  "version": "0.0.0",
+  "scripts": {
+    "ng": "ng",
+    "start": "ng serve",
+    "build": "ng build",
+    "build:ssr": "ng run ToDoManagementSystem.Web:server:dev",
+    "test": "ng test",
+    "lint": "ng lint",
+    "e2e": "ng e2e"
+  },
+  "private": true,
+  "dependencies": {
+    "@angular/animations": "8.2.12",
+    "@angular/common": "8.2.12",
+    "@angular/compiler": "8.2.12",
+    "@angular/core": "8.2.12",
+    "@angular/forms": "8.2.12",
+    "@angular/platform-browser": "8.2.12",
+    "@angular/platform-browser-dynamic": "8.2.12",
+    "@angular/platform-server": "8.2.12",
+    "@angular/router": "8.2.12",
+    "@nguniversal/module-map-ngfactory-loader": "8.1.1",
+    "aspnet-prerendering": "^3.0.1",
+    "bootstrap": "^4.3.1",
+    "core-js": "^3.3.3",
+    "font-awesome": "^4.7.0",
+    "jquery": "3.4.1",
+    "oidc-client": "^1.9.1",
+    "popper.js": "^1.16.0",
+    "rxjs": "^6.5.3",
+    "zone.js": "0.9.1"
+  },
+  "devDependencies": {
+    "@angular-devkit/build-angular": "^0.803.14",
+    "@angular/cli": "8.3.14",
+    "@angular/compiler-cli": "8.2.12",
+    "@angular/language-service": "8.2.12",
+    "@types/jasmine": "~3.4.4",
+    "@types/jasminewd2": "~2.0.8",
+    "@types/node": "~12.11.6",
+    "codelyzer": "^5.2.0",
+    "jasmine-core": "~3.5.0",
+    "jasmine-spec-reporter": "~4.2.1",
+    "karma": "^4.4.1",
+    "karma-chrome-launcher": "~3.1.0",
+    "karma-coverage-istanbul-reporter": "~2.1.0",
+    "karma-jasmine": "~2.0.1",
+    "karma-jasmine-html-reporter": "^1.4.2",
+    "typescript": "3.5.3"
+  },
+  "optionalDependencies": {
+    "node-sass": "^4.12.0",
+    "protractor": "~5.4.2",
+    "ts-node": "~8.4.1",
+    "tslint": "~5.20.0"
+  }
+}

+ 5 - 0
ToDoManagementSystem/ClientApp/src/app/Interfaces/ToDoItem.ts

@@ -0,0 +1,5 @@
+export interface ToDoItem {
+  id: number;
+  description: string;
+  isDone: boolean;
+}

+ 6 - 0
ToDoManagementSystem/ClientApp/src/app/app.component.html

@@ -0,0 +1,6 @@
+<body>
+  <app-nav-menu></app-nav-menu>
+  <div class="container">
+    <router-outlet></router-outlet>
+  </div>
+</body>

+ 9 - 0
ToDoManagementSystem/ClientApp/src/app/app.component.ts

@@ -0,0 +1,9 @@
+import { Component } from "@angular/core";
+
+@Component({
+  selector: "app-root",
+  templateUrl: "./app.component.html",
+})
+export class AppComponent {
+  title = "app";
+}

+ 27 - 0
ToDoManagementSystem/ClientApp/src/app/app.module.ts

@@ -0,0 +1,27 @@
+import { BrowserModule } from "@angular/platform-browser";
+import { NgModule } from "@angular/core";
+import { FormsModule } from "@angular/forms";
+import { HttpClientModule, HTTP_INTERCEPTORS } from "@angular/common/http";
+import { RouterModule } from "@angular/router";
+
+import { AppComponent } from "./app.component";
+import { NavMenuComponent } from "./components/nav-menu/nav-menu.component";
+import { HomeComponent } from "./components/home/home.component";
+
+//services
+import { TodoService } from "./services/todo.service";
+
+@NgModule({
+  declarations: [AppComponent, NavMenuComponent, HomeComponent],
+  imports: [
+    BrowserModule.withServerTransition({ appId: "ng-cli-universal" }),
+    HttpClientModule,
+    FormsModule,
+    RouterModule.forRoot([
+      { path: "", component: HomeComponent, pathMatch: "full" },
+    ]),
+  ],
+  providers: [TodoService],
+  bootstrap: [AppComponent],
+})
+export class AppModule {}

+ 11 - 0
ToDoManagementSystem/ClientApp/src/app/app.server.module.ts

@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { ServerModule } from '@angular/platform-server';
+import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader';
+import { AppComponent } from './app.component';
+import { AppModule } from './app.module';
+
+@NgModule({
+    imports: [AppModule, ServerModule, ModuleMapLoaderModule],
+    bootstrap: [AppComponent]
+})
+export class AppServerModule { }

+ 3 - 0
ToDoManagementSystem/ClientApp/src/app/components/home/home.component.css

@@ -0,0 +1,3 @@
+.todos-complete {
+  text-decoration: line-through;
+}

+ 45 - 0
ToDoManagementSystem/ClientApp/src/app/components/home/home.component.html

@@ -0,0 +1,45 @@
+<h3>ToDo List</h3>
+
+<section class="inputarea">
+  <form name="formTodos" action="" method="POST">
+    <div class="row">
+      <div class="col-md-1" *ngIf="tempTodo.id==0"></div>
+      <div class="col-md-8">
+        <input type="text" class="form-control capitalize" id="description" name="description"
+          [(ngModel)]="tempTodo.description" placeholder="" (keyup.escape)="cancelEdit()" maxlength="80" required
+          autofocus>
+      </div>
+      <div class="col-md-2">
+        <button class="btn btn-success btn-md btn-block" (click)="saveTodo(tempTodo)" (keyup.enter)="saveTodo(tempTodo)"
+          type="submit">{{tempTodo.id == 0? "Save" : "Update"}} </button>
+      </div>
+      <div class="col-sm-2" *ngIf="tempTodo.id>0">
+        <button class="btn btn-secondary btn-md btn-block" (click)="cancelEdit()" type="button">Cancel</button>
+      </div>
+      <div class="col-md-1" *ngIf="tempTodo.id==0"></div>
+    </div>
+  </form>
+</section>
+
+<br />
+<section class="listarea">
+  <div class="row">
+    <div class="col-md-12">
+      <div ng-cloak *ngIf="todoItems.length == 0">You have 0 ToDo's.</div>
+      <ul class="list-group" *ngIf="todoItems.length > 0">
+        <li class="list-group-item" *ngFor="let todo of todoItems;">
+          <div class="pull-left">
+            <label [ngClass]="{'todos-complete': todo.isDone}">
+              <input type="checkbox" (change)="saveTodo(todo)" [checked]="todo.isDone" [(ngModel)]="todo.isDone">
+              &nbsp;{{todo.description}}
+            </label>
+          </div>
+          <div class="pull-right">
+            <button class="btn btn-primary btn-sm fa fa-pencil" (click)="editTodo(todo)"></button> &nbsp;
+            <button class="btn btn-danger btn-sm fa fa-trash-o" (click)="deleteTodo(todo)"></button>
+          </div>
+        </li>
+      </ul>
+    </div>
+  </div>
+</section>

+ 78 - 0
ToDoManagementSystem/ClientApp/src/app/components/home/home.component.ts

@@ -0,0 +1,78 @@
+import { Component, OnInit } from "@angular/core";
+import { ToDoItem } from "../../Interfaces/ToDoItem";
+import { TodoService } from "../../services/todo.service";
+
+@Component({
+  selector: "app-home",
+  templateUrl: "./home.component.html",
+  styleUrls: ["./home.component.css"],
+})
+export class HomeComponent implements OnInit {
+  public todoItems: ToDoItem[] = [];
+  public tempTodo: ToDoItem;
+
+  constructor(private service: TodoService) {}
+
+  ngOnInit() {
+    this.getTodo();
+  }
+
+  editTodo(todo: ToDoItem): void {
+    this.tempTodo = {
+      id: todo.id,
+      description: todo.description,
+      isDone: todo.isDone,
+    };
+  }
+
+  cancelEdit(): void {
+    this.tempTodo = {
+      id: 0,
+      description: "",
+      isDone: false,
+    };
+  }
+
+  getTodo(): void {
+    this.service.getAll().subscribe(
+      (data) => {
+        this.todoItems = data;
+      },
+      (error) => console.error(error)
+    );
+    this.cancelEdit();
+  }
+
+  saveTodo(todo: ToDoItem): void {
+    if (todo.id != 0) {
+      this.service.update(todo).subscribe(
+        (data) => {
+          const index = this.todoItems.findIndex((e) => e.id === todo.id);
+          this.todoItems[index] = todo;
+          this.cancelEdit();
+          //this.getTodo();
+        },
+        (error) => console.error(error)
+      );
+    } else {
+      todo.id = 0;
+      this.service.add(todo).subscribe(
+        (data: ToDoItem) => {
+          this.todoItems.push(data);
+          this.cancelEdit();
+          //this.getTodo();
+        },
+        (error) => console.error(error)
+      );
+    }
+  }
+
+  deleteTodo(todo: ToDoItem): void {
+    this.service.remove(todo).subscribe(
+      (data) => {
+        this.todoItems = this.todoItems.filter((t) => t !== todo);
+      },
+      (error) => console.error(error)
+    );
+  }
+}

+ 18 - 0
ToDoManagementSystem/ClientApp/src/app/components/nav-menu/nav-menu.component.css

@@ -0,0 +1,18 @@
+a.navbar-brand {
+  white-space: normal;
+  text-align: center;
+  word-break: break-all;
+}
+
+html {
+  font-size: 14px;
+}
+@media (min-width: 768px) {
+  html {
+    font-size: 16px;
+  }
+}
+
+.box-shadow {
+  box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
+}

+ 18 - 0
ToDoManagementSystem/ClientApp/src/app/components/nav-menu/nav-menu.component.html

@@ -0,0 +1,18 @@
+<header>
+  <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
+    <div class="container">
+      <a class="navbar-brand" [routerLink]="['/']">ToDo Management System</a>
+      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse"
+        aria-label="Toggle navigation" [attr.aria-expanded]="isExpanded" (click)="toggle()">
+        <span class="navbar-toggler-icon"></span>
+      </button>
+      <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse" [ngClass]="{ show: isExpanded }">
+        <ul class="navbar-nav flex-grow">
+          <li class="nav-item" [routerLinkActive]="['link-active']" [routerLinkActiveOptions]="{ exact: true }">
+            <a class="nav-link text-dark" [routerLink]="['/']">Home</a>
+          </li>
+        </ul>
+      </div>
+    </div>
+  </nav>
+</header>

+ 18 - 0
ToDoManagementSystem/ClientApp/src/app/components/nav-menu/nav-menu.component.ts

@@ -0,0 +1,18 @@
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-nav-menu',
+  templateUrl: './nav-menu.component.html',
+  styleUrls: ['./nav-menu.component.css']
+})
+export class NavMenuComponent {
+  isExpanded = false;
+
+  collapse() {
+    this.isExpanded = false;
+  }
+
+  toggle() {
+    this.isExpanded = !this.isExpanded;
+  }
+}

+ 12 - 0
ToDoManagementSystem/ClientApp/src/app/services/todo.service.spec.ts

@@ -0,0 +1,12 @@
+import { TestBed } from '@angular/core/testing';
+
+import { TodoService } from './todo.service';
+
+describe('TodoService', () => {
+  beforeEach(() => TestBed.configureTestingModule({}));
+
+  it('should be created', () => {
+    const service: TodoService = TestBed.get(TodoService);
+    expect(service).toBeTruthy();
+  });
+});

+ 45 - 0
ToDoManagementSystem/ClientApp/src/app/services/todo.service.ts

@@ -0,0 +1,45 @@
+import { Injectable, Inject } from "@angular/core";
+import { HttpClient, HttpHeaders } from "@angular/common/http";
+import { ToDoItem } from "../Interfaces/ToDoItem";
+
+@Injectable({
+  providedIn: "root",
+})
+export class TodoService {
+  private headers: HttpHeaders;
+  private accessPointUrl: string = "";
+
+  constructor(private http: HttpClient, @Inject("BASE_URL") baseUrl: string) {
+    this.accessPointUrl = baseUrl + "api/ToDo";
+  }
+
+  public getAll() {
+    return this.http.get<ToDoItem[]>(this.accessPointUrl, {
+      headers: this.headers,
+    });
+  }
+
+  public get(id: number) {
+    return this.http.get<ToDoItem>(this.accessPointUrl + "/" + id, {
+      headers: this.headers,
+    });
+  }
+
+  public add(payload: ToDoItem) {
+    return this.http.post(this.accessPointUrl, payload, {
+      headers: this.headers,
+    });
+  }
+
+  public remove(payload: ToDoItem) {
+    return this.http.delete(this.accessPointUrl + "/" + payload.id, {
+      headers: this.headers,
+    });
+  }
+
+  public update(payload: ToDoItem) {
+    return this.http.put(this.accessPointUrl, payload, {
+      headers: this.headers,
+    });
+  }
+}

+ 0 - 0
ToDoManagementSystem/ClientApp/src/assets/.gitkeep


+ 3 - 0
ToDoManagementSystem/ClientApp/src/environments/environment.prod.ts

@@ -0,0 +1,3 @@
+export const environment = {
+  production: true
+};

+ 15 - 0
ToDoManagementSystem/ClientApp/src/environments/environment.ts

@@ -0,0 +1,15 @@
+// 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
+};
+
+/*
+ * In development mode, to ignore zone related error stack frames such as
+ * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can
+ * import the following file, but please comment it out in production mode
+ * because it will have performance impact when throw error
+ */
+// import 'zone.js/dist/zone-error';  // Included with Angular CLI.

+ 17 - 0
ToDoManagementSystem/ClientApp/src/index.html

@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="utf-8" />
+  <title>ToDo Management System</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>Loading...</app-root>
+</body>
+
+</html>

+ 31 - 0
ToDoManagementSystem/ClientApp/src/karma.conf.js

@@ -0,0 +1,31 @@
+// 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
+  });
+};

+ 20 - 0
ToDoManagementSystem/ClientApp/src/main.ts

@@ -0,0 +1,20 @@
+import { enableProdMode } from '@angular/core';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+
+import { AppModule } from './app/app.module';
+import { environment } from './environments/environment';
+
+export function getBaseUrl() {
+  return document.getElementsByTagName('base')[0].href;
+}
+
+const providers = [
+  { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] }
+];
+
+if (environment.production) {
+  enableProdMode();
+}
+
+platformBrowserDynamic(providers).bootstrapModule(AppModule)
+  .catch(err => console.log(err));

+ 63 - 0
ToDoManagementSystem/ClientApp/src/polyfills.ts

@@ -0,0 +1,63 @@
+/**
+ * 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
+ */
+
+/** IE10 and IE11 requires the following for NgClass support on SVG elements */
+// import 'classlist.js';  // Run `npm install --save classlist.js`.
+
+/**
+ * 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
+ * because those flags need to be set before `zone.js` being loaded, and webpack
+ * will put import in the top of bundle, so user need to create a separate file
+ * in this directory (for example: zone-flags.ts), and put the following flags
+ * into that file, and then add the following code before importing zone.js.
+ * import './zone-flags.ts';
+ *
+ * The flags allowed in zone-flags.ts are listed here.
+ *
+ * The following flags will work for all browsers.
+ *
+ * (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__UNPATCHED_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
+ */

+ 16 - 0
ToDoManagementSystem/ClientApp/src/styles.css

@@ -0,0 +1,16 @@
+/* You can add global styles to this file, and also import other style files */
+
+/* Provide sufficient contrast against white background */
+a {
+  color: #0366d6;
+}
+
+code {
+  color: #e01a76;
+}
+
+.btn-primary {
+  color: #fff;
+  background-color: #1b6ec2;
+  border-color: #1861ac;
+}

+ 20 - 0
ToDoManagementSystem/ClientApp/src/test.ts

@@ -0,0 +1,20 @@
+// 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);

+ 11 - 0
ToDoManagementSystem/ClientApp/src/tsconfig.app.json

@@ -0,0 +1,11 @@
+{
+  "extends": "../tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../out-tsc/app",
+    "types": []
+  },
+  "exclude": [
+    "src/test.ts",
+    "**/*.spec.ts"
+  ]
+}

+ 9 - 0
ToDoManagementSystem/ClientApp/src/tsconfig.server.json

@@ -0,0 +1,9 @@
+{
+  "extends": "../tsconfig.json",
+  "compilerOptions": {
+    "module": "commonjs"
+  },
+  "angularCompilerOptions": {
+    "entryModule": "app/app.server.module#AppServerModule"
+  }
+}

+ 18 - 0
ToDoManagementSystem/ClientApp/src/tsconfig.spec.json

@@ -0,0 +1,18 @@
+{
+  "extends": "../tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../out-tsc/spec",
+    "types": [
+      "jasmine",
+      "node"
+    ]
+  },
+  "files": [
+    "test.ts",
+    "polyfills.ts"
+  ],
+  "include": [
+    "**/*.spec.ts",
+    "**/*.d.ts"
+  ]
+}

+ 17 - 0
ToDoManagementSystem/ClientApp/src/tslint.json

@@ -0,0 +1,17 @@
+{
+    "extends": "../tslint.json",
+    "rules": {
+        "directive-selector": [
+            true,
+            "attribute",
+            "app",
+            "camelCase"
+        ],
+        "component-selector": [
+            true,
+            "element",
+            "app",
+            "kebab-case"
+        ]
+    }
+}

+ 21 - 0
ToDoManagementSystem/ClientApp/tsconfig.json

@@ -0,0 +1,21 @@
+{
+  "compileOnSave": false,
+  "compilerOptions": {
+    "baseUrl": "./",
+    "module": "esnext",
+    "outDir": "./dist/out-tsc",
+    "sourceMap": true,
+    "declaration": false,
+    "moduleResolution": "node",
+    "emitDecoratorMetadata": true,
+    "experimentalDecorators": true,
+    "target": "es2015",
+    "typeRoots": [
+      "node_modules/@types"
+    ],
+    "lib": [
+      "es2017",
+      "dom"
+    ]
+  }
+}

+ 130 - 0
ToDoManagementSystem/ClientApp/tslint.json

@@ -0,0 +1,130 @@
+{
+  "rulesDirectory": [
+    "node_modules/codelyzer"
+  ],
+  "rules": {
+    "arrow-return-shorthand": true,
+    "callable-types": true,
+    "class-name": true,
+    "comment-format": [
+      true,
+      "check-space"
+    ],
+    "curly": true,
+    "deprecation": {
+      "severity": "warn"
+    },
+    "eofline": true,
+    "forin": true,
+    "import-blacklist": [
+      true,
+      "rxjs/Rx"
+    ],
+    "import-spacing": true,
+    "indent": [
+      true,
+      "spaces"
+    ],
+    "interface-over-type-literal": true,
+    "label-position": true,
+    "max-line-length": [
+      true,
+      140
+    ],
+    "member-access": false,
+    "member-ordering": [
+      true,
+      {
+        "order": [
+          "static-field",
+          "instance-field",
+          "static-method",
+          "instance-method"
+        ]
+      }
+    ],
+    "no-arg": true,
+    "no-bitwise": true,
+    "no-console": [
+      true,
+      "debug",
+      "info",
+      "time",
+      "timeEnd",
+      "trace"
+    ],
+    "no-construct": true,
+    "no-debugger": true,
+    "no-duplicate-super": true,
+    "no-empty": false,
+    "no-empty-interface": true,
+    "no-eval": true,
+    "no-inferrable-types": [
+      true,
+      "ignore-params"
+    ],
+    "no-misused-new": true,
+    "no-non-null-assertion": true,
+    "no-shadowed-variable": true,
+    "no-string-literal": false,
+    "no-string-throw": true,
+    "no-switch-case-fall-through": true,
+    "no-trailing-whitespace": true,
+    "no-unnecessary-initializer": true,
+    "no-unused-expression": true,
+    "no-use-before-declare": true,
+    "no-var-keyword": true,
+    "object-literal-sort-keys": false,
+    "one-line": [
+      true,
+      "check-open-brace",
+      "check-catch",
+      "check-else",
+      "check-whitespace"
+    ],
+    "prefer-const": true,
+    "quotemark": [
+      true,
+      "single"
+    ],
+    "radix": true,
+    "semicolon": [
+      true,
+      "always"
+    ],
+    "triple-equals": [
+      true,
+      "allow-null-check"
+    ],
+    "typedef-whitespace": [
+      true,
+      {
+        "call-signature": "nospace",
+        "index-signature": "nospace",
+        "parameter": "nospace",
+        "property-declaration": "nospace",
+        "variable-declaration": "nospace"
+      }
+    ],
+    "unified-signatures": true,
+    "variable-name": false,
+    "whitespace": [
+      true,
+      "check-branch",
+      "check-decl",
+      "check-operator",
+      "check-separator",
+      "check-type"
+    ],
+    "no-output-on-prefix": true,
+    "no-inputs-metadata-property": true,
+    "no-outputs-metadata-property": true,
+    "no-host-metadata-property": true,
+    "no-input-rename": true,
+    "no-output-rename": true,
+    "use-lifecycle-interface": true,
+    "use-pipe-transform-interface": true,
+    "component-class-suffix": true,
+    "directive-class-suffix": true
+  }
+}

+ 96 - 0
ToDoManagementSystem/Controllers/ToDoController.cs

@@ -0,0 +1,96 @@
+using System.Linq;
+using System.Threading.Tasks;
+using AutoMapper;
+using Microsoft.AspNetCore.Mvc;
+using ToDoManagementSystem.Domain.Entities;
+using ToDoManagementSystem.Interfaces;
+using ToDoManagementSystem.Models.DTO;
+
+namespace ToDoManagementSystem.Controllers
+{
+    [Route("api/[controller]")]
+    [ApiController]
+    public class ToDoController : ControllerBase
+    {
+        private readonly IRepository _repository;
+        private readonly IMapper _mapper;
+
+        public ToDoController(IRepository repository, IMapper mapper)
+        {
+            _repository = repository;
+            _mapper = mapper;
+        }
+
+        [HttpGet()]
+        public async Task<IActionResult> List()
+        {
+            var items = await _repository.List<ToDoItem>();
+            //items = items?.OrderBy(x => x.IsDone).ThenByDescending(y => y.CreatedDate)?.ToList();
+
+            var model = items?.Select(x => _mapper.Map<ToDoItem, ToDoItemDTO>(x));
+            return Ok(model);
+        }
+
+        [HttpGet("{id}")]
+        public async Task<IActionResult> GetById([FromRoute] int id)
+        {
+            var item = await _repository.GetById<ToDoItem>(id);
+
+            var model = _mapper.Map<ToDoItem, ToDoItemDTO>(item);
+            return Ok(model);
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> Post([FromBody] ToDoItemDTO item)
+        {
+            if (!ModelState.IsValid)
+            {
+                return new BadRequestObjectResult(ModelState);
+            }
+
+            item.Id = 0;
+            var data = _mapper.Map<ToDoItemDTO, ToDoItem>(item);
+
+            var model = await _repository.Add(data);
+            return Ok(_mapper.Map<ToDoItem, ToDoItemDTO>(model));
+        }
+
+        [HttpPut]
+        public async Task<IActionResult> Put([FromBody] ToDoItemDTO item)
+        {
+            if (item.Id == 0)
+                ModelState.AddModelError(nameof(item.Id), "This is required.");
+
+            if (!ModelState.IsValid)
+                return new BadRequestObjectResult(ModelState);
+
+            var data = await _repository.GetById<ToDoItem>(item.Id);
+            if (data == null)
+                return NotFound();
+
+            //To do : include automapper here
+            data.Description = item.Description;
+            data.IsDone = item.IsDone;
+            await _repository.Update(data);
+
+            // var temp = _mapper.Map<ToDoItemDTO, ToDoItem>(item);
+            // await _repository.Update(temp);
+
+            var model = _mapper.Map<ToDoItem, ToDoItemDTO>(data);
+            return Ok(model);
+        }
+
+        [HttpDelete("{id}")]
+        public async Task<IActionResult> Delete([FromRoute] int id)
+        {
+            var item = await _repository.GetById<ToDoItem>(id);
+            if (item == null)
+            {
+                return NotFound();
+            }
+
+            await _repository.Delete(item);
+            return Ok();
+        }
+    }
+}

+ 58 - 0
ToDoManagementSystem/Data/AppDbContext.cs

@@ -0,0 +1,58 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using ToDoManagementSystem.Domain;
+using ToDoManagementSystem.Domain.Entities;
+
+namespace ToDoManagementSystem.Data
+{
+    public class AppDbContext : DbContext
+    {
+        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
+        {
+        }
+
+        public DbSet<ToDoItem> ToDoItems { get; set; }
+
+        protected override void OnModelCreating(ModelBuilder modelBuilder)
+        {
+            modelBuilder.Entity<ToDoItem>(entity =>
+            {
+                entity.ToTable("ToDoItems");
+                entity.HasKey(prop => new { prop.Id });
+                entity.Property(prop => prop.Description).IsRequired().HasMaxLength(200);
+            });
+
+            base.OnModelCreating(modelBuilder);
+        }
+
+        public override int SaveChanges()
+        {
+            AddAuditInfo();
+            return base.SaveChanges();
+        }
+
+        public async Task<int> SaveChangesAsync()
+        {
+            AddAuditInfo();
+            return await base.SaveChangesAsync();
+        }
+
+        private void AddAuditInfo()
+        {
+            var entries = ChangeTracker.Entries().Where(x => x.Entity is BaseEntity
+            && (x.State == EntityState.Added || x.State == EntityState.Modified));
+
+            foreach (var entry in entries)
+            {
+                var utcNow = DateTime.UtcNow;
+                if (entry.State == EntityState.Added)
+                {
+                    ((BaseEntity)entry.Entity).CreatedDate = utcNow;
+                }
+                ((BaseEntity)entry.Entity).ModifiedDate = utcNow;
+            }
+        }
+    }
+}

+ 12 - 0
ToDoManagementSystem/Domain/BaseEntity.cs

@@ -0,0 +1,12 @@
+
+using System;
+
+namespace ToDoManagementSystem.Domain
+{
+    public abstract class BaseEntity
+    {
+        public int Id { get; set; }
+        public DateTime CreatedDate { get; set; }
+        public DateTime ModifiedDate { get; set; }
+    }
+}

+ 8 - 0
ToDoManagementSystem/Domain/Entities/ToDoItem.cs

@@ -0,0 +1,8 @@
+namespace ToDoManagementSystem.Domain.Entities
+{
+    public class ToDoItem : BaseEntity
+    {
+        public string Description { get; set; }
+        public bool IsDone { get; set; }
+    }
+}

+ 16 - 0
ToDoManagementSystem/Interfaces/IRepository.cs

@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using ToDoManagementSystem.Domain;
+
+namespace ToDoManagementSystem.Interfaces
+{
+    public interface IRepository
+    {
+        Task<T> GetById<T>(int id) where T : BaseEntity;
+        Task<List<T>> List<T>() where T : BaseEntity;
+        Task<List<T>> ListPaginated<T>(int page, int size) where T : BaseEntity;
+        Task<T> Add<T>(T entity) where T : BaseEntity;
+        Task Update<T>(T entity) where T : BaseEntity;
+        Task Delete<T>(T entity) where T : BaseEntity;
+    }
+}

+ 52 - 0
ToDoManagementSystem/Migrations/20200616090218_intial-1.Designer.cs

@@ -0,0 +1,52 @@
+// <auto-generated />
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using ToDoManagementSystem.Data;
+
+namespace ToDoManagementSystem.Migrations
+{
+    [DbContext(typeof(AppDbContext))]
+    [Migration("20200616090218_intial-1")]
+    partial class intial1
+    {
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("ProductVersion", "3.1.5")
+                .HasAnnotation("Relational:MaxIdentifierLength", 128)
+                .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+            modelBuilder.Entity("ToDoManagementSystem.Domain.Entities.ToDoItem", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int")
+                        .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+                    b.Property<DateTime>("CreatedDate")
+                        .HasColumnType("datetime2");
+
+                    b.Property<string>("Description")
+                        .IsRequired()
+                        .HasColumnType("nvarchar(200)")
+                        .HasMaxLength(200);
+
+                    b.Property<bool>("IsDone")
+                        .HasColumnType("bit");
+
+                    b.Property<DateTime>("ModifiedDate")
+                        .HasColumnType("datetime2");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("ToDoItems");
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}

+ 33 - 0
ToDoManagementSystem/Migrations/20200616090218_intial-1.cs

@@ -0,0 +1,33 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace ToDoManagementSystem.Migrations
+{
+    public partial class intial1 : Migration
+    {
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.CreateTable(
+                name: "ToDoItems",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("SqlServer:Identity", "1, 1"),
+                    CreatedDate = table.Column<DateTime>(nullable: false),
+                    ModifiedDate = table.Column<DateTime>(nullable: false),
+                    Description = table.Column<string>(maxLength: 200, nullable: false),
+                    IsDone = table.Column<bool>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ToDoItems", x => x.Id);
+                });
+        }
+
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropTable(
+                name: "ToDoItems");
+        }
+    }
+}

+ 50 - 0
ToDoManagementSystem/Migrations/AppDbContextModelSnapshot.cs

@@ -0,0 +1,50 @@
+// <auto-generated />
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using ToDoManagementSystem.Data;
+
+namespace ToDoManagementSystem.Migrations
+{
+    [DbContext(typeof(AppDbContext))]
+    partial class AppDbContextModelSnapshot : ModelSnapshot
+    {
+        protected override void BuildModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("ProductVersion", "3.1.5")
+                .HasAnnotation("Relational:MaxIdentifierLength", 128)
+                .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+            modelBuilder.Entity("ToDoManagementSystem.Domain.Entities.ToDoItem", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int")
+                        .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+                    b.Property<DateTime>("CreatedDate")
+                        .HasColumnType("datetime2");
+
+                    b.Property<string>("Description")
+                        .IsRequired()
+                        .HasColumnType("nvarchar(200)")
+                        .HasMaxLength(200);
+
+                    b.Property<bool>("IsDone")
+                        .HasColumnType("bit");
+
+                    b.Property<DateTime>("ModifiedDate")
+                        .HasColumnType("datetime2");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("ToDoItems");
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}

+ 9 - 0
ToDoManagementSystem/Models/DTO/ToDoItemDTO.cs

@@ -0,0 +1,9 @@
+namespace ToDoManagementSystem.Models.DTO
+{
+    public class ToDoItemDTO
+    {
+        public int Id { get; set; }
+        public string Description { get; set; }
+        public bool IsDone { get; set; }
+    }
+}

+ 14 - 0
ToDoManagementSystem/Models/Mapping/MappingProfile.cs

@@ -0,0 +1,14 @@
+using AutoMapper;
+using ToDoManagementSystem.Domain.Entities;
+using ToDoManagementSystem.Models.DTO;
+
+namespace ToDoManagementSystem.Web.Models.Mapping
+{
+    public class MappingProfile : Profile
+    {
+        public MappingProfile()
+        {
+            CreateMap<ToDoItemDTO, ToDoItem>().ReverseMap();
+        }
+    }
+}

+ 14 - 0
ToDoManagementSystem/Models/Validation/ToDoItemValidator.cs

@@ -0,0 +1,14 @@
+using FluentValidation;
+using ToDoManagementSystem.Models.DTO;
+
+namespace ToDoManagementSystem.Web.Models.Validation
+{
+    public class ToDoItemValidator : AbstractValidator<ToDoItemDTO>
+    {
+        public ToDoItemValidator()
+        {
+            RuleFor(x => x.Description).NotNull().WithMessage("This is required.")
+                                .Length(2, 250).WithMessage("Description must be between 2 and 250.");
+        }
+    }
+}

+ 26 - 0
ToDoManagementSystem/Pages/Error.cshtml

@@ -0,0 +1,26 @@
+@page
+@model ErrorModel
+@{
+    ViewData["Title"] = "Error";
+}
+
+<h1 class="text-danger">Error.</h1>
+<h2 class="text-danger">An error occurred while processing your request.</h2>
+
+@if (Model.ShowRequestId)
+{
+    <p>
+        <strong>Request ID:</strong> <code>@Model.RequestId</code>
+    </p>
+}
+
+<h3>Development Mode</h3>
+<p>
+    Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
+</p>
+<p>
+    <strong>The Development environment shouldn't be enabled for deployed applications.</strong>
+    It can result in displaying sensitive information from exceptions to end users.
+    For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
+    and restarting the app.
+</p>

+ 31 - 0
ToDoManagementSystem/Pages/Error.cshtml.cs

@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+using Microsoft.Extensions.Logging;
+
+namespace ToDoManagementSystem.Pages
+{
+    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
+    public class ErrorModel : PageModel
+    {
+        private readonly ILogger<ErrorModel> _logger;
+
+        public ErrorModel(ILogger<ErrorModel> logger)
+        {
+            _logger = logger;
+        }
+
+        public string RequestId { get; set; }
+
+        public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
+
+        public void OnGet()
+        {
+            RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
+        }
+    }
+}

+ 3 - 0
ToDoManagementSystem/Pages/_ViewImports.cshtml

@@ -0,0 +1,3 @@
+@using ToDoManagementSystem
+@namespace ToDoManagementSystem.Pages
+@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

+ 26 - 0
ToDoManagementSystem/Program.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace ToDoManagementSystem
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            CreateHostBuilder(args).Build().Run();
+        }
+
+        public static IHostBuilder CreateHostBuilder(string[] args) =>
+            Host.CreateDefaultBuilder(args)
+                .ConfigureWebHostDefaults(webBuilder =>
+                {
+                    webBuilder.UseStartup<Startup>();
+                });
+    }
+}

+ 27 - 0
ToDoManagementSystem/Properties/launchSettings.json

@@ -0,0 +1,27 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:23693",
+      "sslPort": 44350
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "ToDoManagementSystem": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "applicationUrl": "https://localhost:5001;http://localhost:5000",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 57 - 0
ToDoManagementSystem/Repository/EfRepository.cs

@@ -0,0 +1,57 @@
+using Microsoft.EntityFrameworkCore;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using ToDoManagementSystem.Interfaces;
+using ToDoManagementSystem.Domain;
+
+namespace ToDoManagementSystem.Data
+{
+    public class EfRepository : IRepository
+    {
+        private readonly AppDbContext _dbContext;
+
+        public EfRepository(AppDbContext dbContext)
+        {
+            _dbContext = dbContext;
+        }
+
+        public async Task<T> GetById<T>(int id) where T : BaseEntity
+        {
+            return await _dbContext.Set<T>().SingleOrDefaultAsync(e => e.Id == id);
+        }
+
+        public async Task<List<T>> List<T>() where T : BaseEntity
+        {
+            return await _dbContext.Set<T>().ToListAsync();
+        }
+
+        public async Task<List<T>> ListPaginated<T>(int page, int size) where T : BaseEntity
+        {
+            return await _dbContext.Set<T>()
+                .Skip((page - 1) * size)
+                .Take(size)
+                .ToListAsync();
+        }
+
+        public async Task<T> Add<T>(T entity) where T : BaseEntity
+        {
+            await _dbContext.Set<T>().AddAsync(entity);
+            await _dbContext.SaveChangesAsync();
+
+            return entity;
+        }
+
+        public async Task Delete<T>(T entity) where T : BaseEntity
+        {
+            _dbContext.Set<T>().Remove(entity);
+            await _dbContext.SaveChangesAsync();
+        }
+
+        public async Task Update<T>(T entity) where T : BaseEntity
+        {
+            _dbContext.Entry(entity).State = EntityState.Modified;
+            await _dbContext.SaveChangesAsync();
+        }
+    }
+}

+ 99 - 0
ToDoManagementSystem/Startup.cs

@@ -0,0 +1,99 @@
+using AutoMapper;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.SpaServices.AngularCli;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.OpenApi.Models;
+using ToDoManagementSystem.Data;
+using ToDoManagementSystem.Interfaces;
+using ToDoManagementSystem.Web.Models.Mapping;
+
+namespace ToDoManagementSystem
+{
+    public class Startup
+    {
+        public Startup(IConfiguration configuration)
+        {
+            Configuration = configuration;
+        }
+
+        public IConfiguration Configuration { get; }
+
+        // This method gets called by the runtime. Use this method to add services to the container.
+        public void ConfigureServices(IServiceCollection services)
+        {
+            services.AddControllersWithViews();
+            // In production, the Angular files will be served from this directory
+            services.AddSpaStaticFiles(configuration =>
+            {
+                configuration.RootPath = "ClientApp/dist";
+            });
+
+            services.AddScoped(typeof(IRepository), typeof(EfRepository));
+            services.AddDbContext<AppDbContext>(item => item.UseSqlServer(Configuration.GetConnectionString("portalConnection")));
+            services.AddAutoMapper(typeof(MappingProfile));
+
+            services.AddSwaggerGen(c =>
+            {
+                c.SwaggerDoc("v1", new OpenApiInfo { Title = "ToDo API", Version = "V1" });
+            });
+        }
+
+        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+        {
+            if (env.IsDevelopment())
+            {
+                app.UseDeveloperExceptionPage();
+                app.UseSwagger();
+                app.UseSwaggerUI(c =>
+                {
+                    c.SwaggerEndpoint("v1/swagger.json", "ToDo API V1");
+                });
+            }
+            else
+            {
+                app.UseExceptionHandler("/Error");
+                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+                app.UseHsts();
+            }
+
+            app.UseHttpsRedirection();
+            app.UseStaticFiles();
+            if (!env.IsDevelopment())
+            {
+                app.UseSpaStaticFiles();
+            }
+
+            app.UseRouting();
+
+            app.UseEndpoints(endpoints =>
+            {
+                endpoints.MapControllerRoute(
+                    name: "default",
+                    pattern: "{controller}/{action=Index}/{id?}");
+            });
+
+            app.UseSwaggerUI(c =>
+            {
+                c.SwaggerEndpoint("/swagger/v1/swagger.json", "ToDo API V1");
+            });
+
+            app.UseSpa(spa =>
+            {
+                // To learn more about options for serving an Angular SPA from ASP.NET Core,
+                // see https://go.microsoft.com/fwlink/?linkid=864501
+
+                spa.Options.SourcePath = "ClientApp";
+
+                if (env.IsDevelopment())
+                {
+                    spa.UseAngularCliServer(npmScript: "start");
+                }
+            });
+        }
+    }
+}

+ 67 - 0
ToDoManagementSystem/ToDoManagementSystem.csproj

@@ -0,0 +1,67 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+    <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
+    <TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
+    <IsPackable>false</IsPackable>
+    <SpaRoot>ClientApp\</SpaRoot>
+    <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
+
+    <!-- Set this to true if you enable server-side prerendering -->
+    <BuildServerSideRenderer>false</BuildServerSideRenderer>
+  </PropertyGroup>
+
+   <ItemGroup>  
+    <PackageReference Include="AutoMapper" Version="9.0.0" />
+    <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="7.0.0" />
+    <PackageReference Include="FluentValidation.AspNetCore" Version="9.0.0-preview3" />
+    <PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="3.1.2" />
+    <PackageReference Include="Swashbuckle.AspNetCore" Version="5.4.1" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.2" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.2">
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+      <PrivateAssets>all</PrivateAssets>
+    </PackageReference>
+     <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.5">
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+      <PrivateAssets>all</PrivateAssets>
+    </PackageReference>
+  </ItemGroup>
+
+  <ItemGroup>
+    <!-- Don't publish the SPA source files, but do show them in the project files list -->
+    <Content Remove="$(SpaRoot)**" />
+    <None Remove="$(SpaRoot)**" />
+    <None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
+  </ItemGroup>
+
+  <Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
+    <!-- Ensure Node.js is installed -->
+    <Exec Command="node --version" ContinueOnError="true">
+      <Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
+    </Exec>
+    <Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
+    <Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
+    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
+  </Target>
+
+  <Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
+    <!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
+    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
+    <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build -- --prod" />
+    <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build:ssr -- --prod" Condition=" '$(BuildServerSideRenderer)' == 'true' " />
+
+    <!-- Include the newly-built files in the publish output -->
+    <ItemGroup>
+      <DistFiles Include="$(SpaRoot)dist\**; $(SpaRoot)dist-server\**" />
+      <DistFiles Include="$(SpaRoot)node_modules\**" Condition="'$(BuildServerSideRenderer)' == 'true'" />
+      <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
+        <RelativePath>%(DistFiles.Identity)</RelativePath>
+        <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
+        <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
+      </ResolvedFileToPublish>
+    </ItemGroup>
+  </Target>
+
+</Project>

+ 9 - 0
ToDoManagementSystem/appsettings.Development.json

@@ -0,0 +1,9 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft": "Warning",
+      "Microsoft.Hosting.Lifetime": "Information"
+    }
+  }
+}

+ 13 - 0
ToDoManagementSystem/appsettings.json

@@ -0,0 +1,13 @@
+{
+  "ConnectionStrings": {
+    "portalConnection": "server=35.231.96.110; database=SopTest;User ID=webdevsop; Password=websop@2019;"
+  },
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft": "Warning",
+      "Microsoft.Hosting.Lifetime": "Information"
+    }
+  },
+  "AllowedHosts": "*"
+}

TEMPAT SAMPAH
ToDoManagementSystem/wwwroot/favicon.ico