├── .gitignore └── src └── dotnetGigs ├── .angular-cli.json ├── .editorconfig ├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── Auth ├── IJwtFactory.cs └── JwtFactory.cs ├── Controllers ├── AccountsController.cs ├── AuthController.cs └── DashboardController.cs ├── Data └── ApplicationDbContext.cs ├── Extensions └── ResponseExtensions.cs ├── Helpers ├── Constants.cs └── Errors.cs ├── Migrations ├── 20170420021732_inital.Designer.cs ├── 20170420021732_inital.cs └── ApplicationDbContextModelSnapshot.cs ├── Models ├── Entities │ ├── AppUser.cs │ └── JobSeeker.cs └── JwtIssuerOptions.cs ├── Program.cs ├── README.md ├── Startup.cs ├── ViewModels ├── CredentialsViewModel.cs ├── Mappings │ └── ViewModelToEntityMappingProfile.cs ├── RegistrationViewModel.cs └── Validations │ ├── CredentialsViewModelValidator.cs │ └── RegistrationViewModelValidator.cs ├── appsettings.json ├── dotnetGigs.csproj ├── e2e ├── app.e2e-spec.ts ├── app.po.ts └── tsconfig.e2e.json ├── karma.conf.js ├── package.json ├── protractor.conf.js ├── src ├── app │ ├── account │ │ ├── account.module.ts │ │ ├── account.routing.ts │ │ ├── login-form │ │ │ ├── login-form.component.html │ │ │ ├── login-form.component.scss │ │ │ ├── login-form.component.spec.ts │ │ │ └── login-form.component.ts │ │ └── registration-form │ │ │ ├── registration-form.component.html │ │ │ ├── registration-form.component.scss │ │ │ ├── registration-form.component.spec.ts │ │ │ └── registration-form.component.ts │ ├── app.component.html │ ├── app.component.scss │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.module.ts │ ├── app.routing.ts │ ├── auth.guard.ts │ ├── authenticate-xhr.backend.ts │ ├── dashboard │ │ ├── dashboard.module.ts │ │ ├── dashboard.routing.ts │ │ ├── home │ │ │ ├── home.component.html │ │ │ ├── home.component.scss │ │ │ ├── home.component.spec.ts │ │ │ └── home.component.ts │ │ ├── models │ │ │ └── home.details.interface.ts │ │ ├── root │ │ │ ├── root.component.html │ │ │ ├── root.component.scss │ │ │ ├── root.component.spec.ts │ │ │ └── root.component.ts │ │ └── services │ │ │ └── dashboard.service.ts │ ├── directives │ │ ├── email.validator.directive.ts │ │ └── focus.directive.ts │ ├── header │ │ ├── header.component.html │ │ ├── header.component.scss │ │ ├── header.component.spec.ts │ │ └── header.component.ts │ ├── home │ │ ├── home.component.html │ │ ├── home.component.scss │ │ ├── home.component.spec.ts │ │ └── home.component.ts │ ├── rxjs-operators.js │ ├── shared │ │ ├── models │ │ │ ├── credentials.interface.ts │ │ │ └── user.registration.interface.ts │ │ ├── modules │ │ │ └── shared.module.ts │ │ ├── services │ │ │ ├── base.service.ts │ │ │ └── user.service.ts │ │ └── utils │ │ │ └── config.service.ts │ └── spinner │ │ ├── spinner.component.html │ │ ├── spinner.component.scss │ │ ├── spinner.component.spec.ts │ │ └── spinner.component.ts ├── assets │ └── .gitkeep ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts ├── styles.scss ├── test.ts ├── tsconfig.app.json ├── tsconfig.spec.json └── typings.d.ts ├── tsconfig.json ├── tslint.json └── wwwroot ├── favicon.ico ├── index.html ├── inline.bundle.js ├── inline.bundle.js.map ├── main.bundle.js ├── main.bundle.js.map ├── polyfills.bundle.js ├── polyfills.bundle.js.map ├── scripts.bundle.js ├── scripts.bundle.js.map ├── styles.bundle.js ├── styles.bundle.js.map ├── vendor.bundle.js └── vendor.bundle.js.map /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # Visual Studio code coverage results 114 | *.coverage 115 | *.coveragexml 116 | 117 | # NCrunch 118 | _NCrunch_* 119 | .*crunch*.local.xml 120 | nCrunchTemp_* 121 | 122 | # MightyMoose 123 | *.mm.* 124 | AutoTest.Net/ 125 | 126 | # Web workbench (sass) 127 | .sass-cache/ 128 | 129 | # Installshield output folder 130 | [Ee]xpress/ 131 | 132 | # DocProject is a documentation generator add-in 133 | DocProject/buildhelp/ 134 | DocProject/Help/*.HxT 135 | DocProject/Help/*.HxC 136 | DocProject/Help/*.hhc 137 | DocProject/Help/*.hhk 138 | DocProject/Help/*.hhp 139 | DocProject/Help/Html2 140 | DocProject/Help/html 141 | 142 | # Click-Once directory 143 | publish/ 144 | 145 | # Publish Web Output 146 | *.[Pp]ublish.xml 147 | *.azurePubxml 148 | # TODO: Comment the next line if you want to checkin your web deploy settings 149 | # but database connection strings (with potential passwords) will be unencrypted 150 | *.pubxml 151 | *.publishproj 152 | 153 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 154 | # checkin your Azure Web App publish settings, but sensitive information contained 155 | # in these scripts will be unencrypted 156 | PublishScripts/ 157 | 158 | # NuGet Packages 159 | *.nupkg 160 | # The packages folder can be ignored because of Package Restore 161 | **/packages/* 162 | # except build/, which is used as an MSBuild target. 163 | !**/packages/build/ 164 | # Uncomment if necessary however generally it will be regenerated when needed 165 | #!**/packages/repositories.config 166 | # NuGet v3's project.json files produces more ignoreable files 167 | *.nuget.props 168 | *.nuget.targets 169 | 170 | # Microsoft Azure Build Output 171 | csx/ 172 | *.build.csdef 173 | 174 | # Microsoft Azure Emulator 175 | ecf/ 176 | rcf/ 177 | 178 | # Windows Store app package directories and files 179 | AppPackages/ 180 | BundleArtifacts/ 181 | Package.StoreAssociation.xml 182 | _pkginfo.txt 183 | 184 | # Visual Studio cache files 185 | # files ending in .cache can be ignored 186 | *.[Cc]ache 187 | # but keep track of directories ending in .cache 188 | !*.[Cc]ache/ 189 | 190 | # Others 191 | ClientBin/ 192 | ~$* 193 | *~ 194 | *.dbmdl 195 | *.dbproj.schemaview 196 | *.jfm 197 | *.pfx 198 | *.publishsettings 199 | node_modules/ 200 | orleans.codegen.cs 201 | 202 | # Since there are multiple workflows, uncomment next line to ignore bower_components 203 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 204 | #bower_components/ 205 | 206 | # RIA/Silverlight projects 207 | Generated_Code/ 208 | 209 | # Backup & report files from converting an old project file 210 | # to a newer Visual Studio version. Backup files are not needed, 211 | # because we have git ;-) 212 | _UpgradeReport_Files/ 213 | Backup*/ 214 | UpgradeLog*.XML 215 | UpgradeLog*.htm 216 | 217 | # SQL Server files 218 | *.mdf 219 | *.ldf 220 | 221 | # Business Intelligence projects 222 | *.rdl.data 223 | *.bim.layout 224 | *.bim_*.settings 225 | 226 | # Microsoft Fakes 227 | FakesAssemblies/ 228 | 229 | # GhostDoc plugin setting file 230 | *.GhostDoc.xml 231 | 232 | # Node.js Tools for Visual Studio 233 | .ntvs_analysis.dat 234 | 235 | # Visual Studio 6 build log 236 | *.plg 237 | 238 | # Visual Studio 6 workspace options file 239 | *.opt 240 | 241 | # Visual Studio LightSwitch build output 242 | **/*.HTMLClient/GeneratedArtifacts 243 | **/*.DesktopClient/GeneratedArtifacts 244 | **/*.DesktopClient/ModelManifest.xml 245 | **/*.Server/GeneratedArtifacts 246 | **/*.Server/ModelManifest.xml 247 | _Pvt_Extensions 248 | 249 | # Paket dependency manager 250 | .paket/paket.exe 251 | paket-files/ 252 | 253 | # FAKE - F# Make 254 | .fake/ 255 | 256 | # JetBrains Rider 257 | .idea/ 258 | *.sln.iml 259 | 260 | # CodeRush 261 | .cr/ 262 | 263 | # Python Tools for Visual Studio (PTVS) 264 | __pycache__/ 265 | *.pyc 266 | 267 | # Cake - Uncomment if you are using it 268 | # tools/ 269 | 270 | # Created by https://www.gitignore.io/api/visualstudiocode 271 | 272 | ### VisualStudioCode ### 273 | .vscode/* 274 | !.vscode/settings.json 275 | !.vscode/tasks.json 276 | !.vscode/launch.json 277 | !.vscode/extensions.json 278 | .history 279 | 280 | # End of https://www.gitignore.io/api/visualstudiocode -------------------------------------------------------------------------------- /src/dotnetGigs/.angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "project": { 4 | "name": "dotnet-gigs" 5 | }, 6 | "apps": [ 7 | { 8 | "root": "src", 9 | "outDir": "wwwroot", 10 | "assets": [ 11 | "assets", 12 | "favicon.ico" 13 | ], 14 | "index": "index.html", 15 | "main": "main.ts", 16 | "polyfills": "polyfills.ts", 17 | "test": "test.ts", 18 | "tsconfig": "tsconfig.app.json", 19 | "testTsconfig": "tsconfig.spec.json", 20 | "prefix": "app", 21 | "styles": [ 22 | "../node_modules/bootstrap/dist/css/bootstrap.css", 23 | "styles.scss" 24 | ], 25 | "scripts": [ 26 | "../node_modules/jquery/dist/jquery.js", 27 | "../node_modules/tether/dist/js/tether.js", 28 | "../node_modules/bootstrap/dist/js/bootstrap.js" 29 | ], 30 | "environmentSource": "environments/environment.ts", 31 | "environments": { 32 | "dev": "environments/environment.ts", 33 | "prod": "environments/environment.prod.ts" 34 | } 35 | } 36 | ], 37 | "e2e": { 38 | "protractor": { 39 | "config": "./protractor.conf.js" 40 | } 41 | }, 42 | "lint": [ 43 | { 44 | "project": "src/tsconfig.app.json" 45 | }, 46 | { 47 | "project": "src/tsconfig.spec.json" 48 | }, 49 | { 50 | "project": "e2e/tsconfig.e2e.json" 51 | } 52 | ], 53 | "test": { 54 | "karma": { 55 | "config": "./karma.conf.js" 56 | } 57 | }, 58 | "defaults": { 59 | "styleExt": "scss", 60 | "component": {} 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/dotnetGigs/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /src/dotnetGigs/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /src/dotnetGigs/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": ".NET Core Launch (web)", 6 | "type": "coreclr", 7 | "request": "launch", 8 | "preLaunchTask": "build", 9 | "program": "${workspaceRoot}\\bin\\Debug\\netcoreapp1.1\\dotnetGigs.dll", 10 | "args": [], 11 | "cwd": "${workspaceRoot}", 12 | "stopAtEntry": false, 13 | "internalConsoleOptions": "openOnSessionStart", 14 | "launchBrowser": { 15 | "enabled": true, 16 | "args": "${auto-detect-url}", 17 | "windows": { 18 | "command": "cmd.exe", 19 | "args": "/C start ${auto-detect-url}" 20 | }, 21 | "osx": { 22 | "command": "open" 23 | }, 24 | "linux": { 25 | "command": "xdg-open" 26 | } 27 | }, 28 | "env": { 29 | "ASPNETCORE_ENVIRONMENT": "Development" 30 | }, 31 | "sourceFileMap": { 32 | "/Views": "${workspaceRoot}/Views" 33 | } 34 | }, 35 | { 36 | "name": ".NET Core Attach", 37 | "type": "coreclr", 38 | "request": "attach", 39 | "processId": "${command:pickProcess}" 40 | } 41 | ] 42 | } -------------------------------------------------------------------------------- /src/dotnetGigs/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "command": "dotnet", 4 | "isShellCommand": true, 5 | "args": [], 6 | "tasks": [ 7 | { 8 | "taskName": "build", 9 | "args": [ 10 | "${workspaceRoot}\\dotnetGigs.csproj" 11 | ], 12 | "isBuildCommand": true, 13 | "problemMatcher": "$msCompile" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /src/dotnetGigs/Auth/IJwtFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using System.Security.Claims; 3 | 4 | namespace DotNetGigs.Auth 5 | { 6 | public interface IJwtFactory 7 | { 8 | Task GenerateEncodedToken(string userName, ClaimsIdentity identity); 9 | ClaimsIdentity GenerateClaimsIdentity(string userName,string id); 10 | } 11 | } -------------------------------------------------------------------------------- /src/dotnetGigs/Auth/JwtFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IdentityModel.Tokens.Jwt; 3 | using System.Security.Claims; 4 | using System.Security.Principal; 5 | using System.Threading.Tasks; 6 | using DotNetGigs.Models; 7 | using Microsoft.Extensions.Options; 8 | 9 | namespace DotNetGigs.Auth 10 | { 11 | public class JwtFactory : IJwtFactory 12 | { 13 | private readonly JwtIssuerOptions _jwtOptions; 14 | 15 | public JwtFactory(IOptions jwtOptions) 16 | { 17 | _jwtOptions = jwtOptions.Value; 18 | ThrowIfInvalidOptions(_jwtOptions); 19 | } 20 | 21 | public async Task GenerateEncodedToken(string userName, ClaimsIdentity identity) 22 | { 23 | var claims = new[] 24 | { 25 | new Claim(JwtRegisteredClaimNames.Sub, userName), 26 | new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()), 27 | new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64), 28 | identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Rol), 29 | identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Id) 30 | }; 31 | 32 | // Create the JWT security token and encode it. 33 | var jwt = new JwtSecurityToken( 34 | issuer: _jwtOptions.Issuer, 35 | audience: _jwtOptions.Audience, 36 | claims: claims, 37 | notBefore: _jwtOptions.NotBefore, 38 | expires: _jwtOptions.Expiration, 39 | signingCredentials: _jwtOptions.SigningCredentials); 40 | 41 | var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt); 42 | 43 | return encodedJwt; 44 | } 45 | 46 | public ClaimsIdentity GenerateClaimsIdentity(string userName,string id) 47 | { 48 | return new ClaimsIdentity(new GenericIdentity(userName, "Token"), new[] 49 | { 50 | new Claim(Helpers.Constants.Strings.JwtClaimIdentifiers.Id, id), 51 | new Claim(Helpers.Constants.Strings.JwtClaimIdentifiers.Rol, Helpers.Constants.Strings.JwtClaims.ApiAccess) 52 | }); 53 | } 54 | 55 | /// Date converted to seconds since Unix epoch (Jan 1, 1970, midnight UTC). 56 | private static long ToUnixEpochDate(DateTime date) 57 | => (long)Math.Round((date.ToUniversalTime() - 58 | new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)) 59 | .TotalSeconds); 60 | 61 | private static void ThrowIfInvalidOptions(JwtIssuerOptions options) 62 | { 63 | if (options == null) throw new ArgumentNullException(nameof(options)); 64 | 65 | if (options.ValidFor <= TimeSpan.Zero) 66 | { 67 | throw new ArgumentException("Must be a non-zero TimeSpan.", nameof(JwtIssuerOptions.ValidFor)); 68 | } 69 | 70 | if (options.SigningCredentials == null) 71 | { 72 | throw new ArgumentNullException(nameof(JwtIssuerOptions.SigningCredentials)); 73 | } 74 | 75 | if (options.JtiGenerator == null) 76 | { 77 | throw new ArgumentNullException(nameof(JwtIssuerOptions.JtiGenerator)); 78 | } 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /src/dotnetGigs/Controllers/AccountsController.cs: -------------------------------------------------------------------------------- 1 | 2 | using Microsoft.AspNetCore.Mvc; 3 | using DotNetGigs.ViewModels; 4 | using AutoMapper; 5 | using DotNetGigs.Models.Entities; 6 | using Microsoft.AspNetCore.Identity; 7 | using DotNetGigs.Helpers; 8 | using System.Threading.Tasks; 9 | using DotNetGigs.Data; 10 | 11 | namespace DotNetGigs.Controllers 12 | { 13 | [Route("api/[controller]")] 14 | public class AccountsController : Controller 15 | { 16 | private readonly ApplicationDbContext _appDbContext; 17 | private readonly UserManager _userManager; 18 | private readonly IMapper _mapper; 19 | 20 | public AccountsController(UserManager userManager,IMapper mapper,ApplicationDbContext appDbContext) 21 | { 22 | _userManager = userManager; 23 | _mapper=mapper; 24 | _appDbContext=appDbContext; 25 | } 26 | 27 | // POST api/accounts 28 | [HttpPost] 29 | public async Task Post([FromBody]RegistrationViewModel model) 30 | { 31 | if (!ModelState.IsValid) 32 | { 33 | return BadRequest(ModelState); 34 | } 35 | 36 | var userIdentity=_mapper.Map(model); 37 | 38 | var result = await _userManager.CreateAsync(userIdentity, model.Password); 39 | 40 | if (!result.Succeeded) return new BadRequestObjectResult(Errors.AddErrorsToModelState(result, ModelState)); 41 | 42 | await _appDbContext.JobSeekers.AddAsync(new JobSeeker{IdentityId=userIdentity.Id, Location=model.Location}); 43 | await _appDbContext.SaveChangesAsync(); 44 | 45 | return new OkObjectResult("Account created"); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/dotnetGigs/Controllers/AuthController.cs: -------------------------------------------------------------------------------- 1 | 2 | 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.AspNetCore.Identity; 5 | using Newtonsoft.Json; 6 | using DotNetGigs.Models.Entities; 7 | using DotNetGigs.Models; 8 | using DotNetGigs.Auth; 9 | using Microsoft.Extensions.Options; 10 | using System.Threading.Tasks; 11 | using DotNetGigs.Helpers; 12 | using System.Security.Claims; 13 | using System.Linq; 14 | 15 | namespace DotNetGigs.Controllers 16 | { 17 | 18 | [Route("api/[controller]")] 19 | public class AuthController : Controller 20 | { 21 | private readonly UserManager _userManager; 22 | private readonly IJwtFactory _jwtFactory; 23 | private readonly JsonSerializerSettings _serializerSettings; 24 | private readonly JwtIssuerOptions _jwtOptions; 25 | 26 | public AuthController(UserManager userManager, IJwtFactory jwtFactory, IOptions jwtOptions) 27 | { 28 | _userManager = userManager; 29 | _jwtFactory = jwtFactory; 30 | _jwtOptions = jwtOptions.Value; 31 | 32 | _serializerSettings = new JsonSerializerSettings 33 | { 34 | Formatting = Formatting.Indented 35 | }; 36 | } 37 | 38 | // POST api/auth/login 39 | [HttpPost("login")] 40 | public async Task Post([FromBody]CredentialsViewModel credentials) 41 | { 42 | if (!ModelState.IsValid) 43 | { 44 | return BadRequest(ModelState); 45 | } 46 | 47 | var identity = await GetClaimsIdentity(credentials.UserName, credentials.Password); 48 | if (identity == null) 49 | { 50 | return BadRequest(Errors.AddErrorToModelState("login_failure", "Invalid username or password.", ModelState)); 51 | } 52 | 53 | // Serialize and return the response 54 | var response = new 55 | { 56 | id=identity.Claims.Single(c=>c.Type=="id").Value, 57 | auth_token = await _jwtFactory.GenerateEncodedToken(credentials.UserName, identity), 58 | expires_in = (int)_jwtOptions.ValidFor.TotalSeconds 59 | }; 60 | 61 | var json = JsonConvert.SerializeObject(response, _serializerSettings); 62 | return new OkObjectResult(json); 63 | } 64 | 65 | private async Task GetClaimsIdentity(string userName, string password) 66 | { 67 | if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password)) 68 | { 69 | // get the user to verifty 70 | var userToVerify = await _userManager.FindByNameAsync(userName); 71 | 72 | if (userToVerify != null) 73 | { 74 | // check the credentials 75 | if (await _userManager.CheckPasswordAsync(userToVerify, password)) 76 | { 77 | return await Task.FromResult(_jwtFactory.GenerateClaimsIdentity(userName,userToVerify.Id)); 78 | } 79 | } 80 | } 81 | 82 | // Credentials are invalid, or account doesn't exist 83 | return await Task.FromResult(null); 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /src/dotnetGigs/Controllers/DashboardController.cs: -------------------------------------------------------------------------------- 1 | 2 | using Microsoft.AspNetCore.Authorization; 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | namespace DotNetGigs 6 | { 7 | 8 | [Authorize(Policy = "ApiUser")] 9 | [Route("api/[controller]")] 10 | public class DashboardController : Controller 11 | { 12 | public DashboardController() 13 | { 14 | 15 | } 16 | 17 | // GET api/dashboard/home 18 | [HttpGet("home")] 19 | public IActionResult GetHome() 20 | { 21 | return new OkObjectResult(new { Message = "This is secure data!" }); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/dotnetGigs/Data/ApplicationDbContext.cs: -------------------------------------------------------------------------------- 1 | 2 | 3 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 4 | using DotNetGigs.Models.Entities; 5 | using Microsoft.EntityFrameworkCore; 6 | 7 | namespace DotNetGigs.Data 8 | { 9 | public class ApplicationDbContext : IdentityDbContext 10 | { 11 | public ApplicationDbContext(DbContextOptions options) 12 | : base(options) 13 | { 14 | } 15 | 16 | public DbSet JobSeekers { get; set; } 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/dotnetGigs/Extensions/ResponseExtensions.cs: -------------------------------------------------------------------------------- 1 | 2 | using Microsoft.AspNetCore.Http; 3 | 4 | namespace DotNetGigs.Extensions 5 | { 6 | public static class ResponseExtensions 7 | { 8 | public static void AddApplicationError(this HttpResponse response, string message) 9 | { 10 | response.Headers.Add("Application-Error", message); 11 | // CORS 12 | response.Headers.Add("access-control-expose-headers", "Application-Error"); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/dotnetGigs/Helpers/Constants.cs: -------------------------------------------------------------------------------- 1 | 2 | 3 | namespace DotNetGigs.Helpers{ 4 | 5 | public static class Constants 6 | { 7 | public static class Strings 8 | { 9 | public static class JwtClaimIdentifiers 10 | { 11 | public const string Rol = "rol", Id = "id"; 12 | } 13 | 14 | public static class JwtClaims 15 | { 16 | public const string ApiAccess = "api_access"; 17 | } 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/dotnetGigs/Helpers/Errors.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | using Microsoft.AspNetCore.Mvc.ModelBinding; 3 | 4 | namespace DotNetGigs.Helpers 5 | { 6 | 7 | public static class Errors 8 | { 9 | public static ModelStateDictionary AddErrorsToModelState(IdentityResult identityResult, ModelStateDictionary modelState) 10 | { 11 | foreach (var e in identityResult.Errors) 12 | { 13 | modelState.TryAddModelError(e.Code, e.Description); 14 | } 15 | 16 | return modelState; 17 | } 18 | 19 | public static ModelStateDictionary AddErrorToModelState(string code, string description, ModelStateDictionary modelState) 20 | { 21 | modelState.TryAddModelError(code, description); 22 | return modelState; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/dotnetGigs/Migrations/20170420021732_inital.Designer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using Microsoft.EntityFrameworkCore.Migrations; 6 | using DotNetGigs.Data; 7 | 8 | namespace DotNetGigs.Migrations 9 | { 10 | [DbContext(typeof(ApplicationDbContext))] 11 | [Migration("20170420021732_inital")] 12 | partial class inital 13 | { 14 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 15 | { 16 | modelBuilder 17 | .HasAnnotation("ProductVersion", "1.1.1") 18 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 19 | 20 | modelBuilder.Entity("DotNetGigs.Models.Entities.AppUser", b => 21 | { 22 | b.Property("Id") 23 | .ValueGeneratedOnAdd(); 24 | 25 | b.Property("AccessFailedCount"); 26 | 27 | b.Property("ConcurrencyStamp") 28 | .IsConcurrencyToken(); 29 | 30 | b.Property("Email") 31 | .HasMaxLength(256); 32 | 33 | b.Property("EmailConfirmed"); 34 | 35 | b.Property("FirstName"); 36 | 37 | b.Property("LastName"); 38 | 39 | b.Property("LockoutEnabled"); 40 | 41 | b.Property("LockoutEnd"); 42 | 43 | b.Property("NormalizedEmail") 44 | .HasMaxLength(256); 45 | 46 | b.Property("NormalizedUserName") 47 | .HasMaxLength(256); 48 | 49 | b.Property("PasswordHash"); 50 | 51 | b.Property("PhoneNumber"); 52 | 53 | b.Property("PhoneNumberConfirmed"); 54 | 55 | b.Property("SecurityStamp"); 56 | 57 | b.Property("TwoFactorEnabled"); 58 | 59 | b.Property("UserName") 60 | .HasMaxLength(256); 61 | 62 | b.HasKey("Id"); 63 | 64 | b.HasIndex("NormalizedEmail") 65 | .HasName("EmailIndex"); 66 | 67 | b.HasIndex("NormalizedUserName") 68 | .IsUnique() 69 | .HasName("UserNameIndex"); 70 | 71 | b.ToTable("AspNetUsers"); 72 | }); 73 | 74 | modelBuilder.Entity("DotNetGigs.Models.Entities.JobSeeker", b => 75 | { 76 | b.Property("Id") 77 | .ValueGeneratedOnAdd(); 78 | 79 | b.Property("IdentityId"); 80 | 81 | b.Property("Location"); 82 | 83 | b.HasKey("Id"); 84 | 85 | b.HasIndex("IdentityId"); 86 | 87 | b.ToTable("JobSeekers"); 88 | }); 89 | 90 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b => 91 | { 92 | b.Property("Id") 93 | .ValueGeneratedOnAdd(); 94 | 95 | b.Property("ConcurrencyStamp") 96 | .IsConcurrencyToken(); 97 | 98 | b.Property("Name") 99 | .HasMaxLength(256); 100 | 101 | b.Property("NormalizedName") 102 | .HasMaxLength(256); 103 | 104 | b.HasKey("Id"); 105 | 106 | b.HasIndex("NormalizedName") 107 | .IsUnique() 108 | .HasName("RoleNameIndex"); 109 | 110 | b.ToTable("AspNetRoles"); 111 | }); 112 | 113 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b => 114 | { 115 | b.Property("Id") 116 | .ValueGeneratedOnAdd(); 117 | 118 | b.Property("ClaimType"); 119 | 120 | b.Property("ClaimValue"); 121 | 122 | b.Property("RoleId") 123 | .IsRequired(); 124 | 125 | b.HasKey("Id"); 126 | 127 | b.HasIndex("RoleId"); 128 | 129 | b.ToTable("AspNetRoleClaims"); 130 | }); 131 | 132 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b => 133 | { 134 | b.Property("Id") 135 | .ValueGeneratedOnAdd(); 136 | 137 | b.Property("ClaimType"); 138 | 139 | b.Property("ClaimValue"); 140 | 141 | b.Property("UserId") 142 | .IsRequired(); 143 | 144 | b.HasKey("Id"); 145 | 146 | b.HasIndex("UserId"); 147 | 148 | b.ToTable("AspNetUserClaims"); 149 | }); 150 | 151 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b => 152 | { 153 | b.Property("LoginProvider"); 154 | 155 | b.Property("ProviderKey"); 156 | 157 | b.Property("ProviderDisplayName"); 158 | 159 | b.Property("UserId") 160 | .IsRequired(); 161 | 162 | b.HasKey("LoginProvider", "ProviderKey"); 163 | 164 | b.HasIndex("UserId"); 165 | 166 | b.ToTable("AspNetUserLogins"); 167 | }); 168 | 169 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b => 170 | { 171 | b.Property("UserId"); 172 | 173 | b.Property("RoleId"); 174 | 175 | b.HasKey("UserId", "RoleId"); 176 | 177 | b.HasIndex("RoleId"); 178 | 179 | b.ToTable("AspNetUserRoles"); 180 | }); 181 | 182 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", b => 183 | { 184 | b.Property("UserId"); 185 | 186 | b.Property("LoginProvider"); 187 | 188 | b.Property("Name"); 189 | 190 | b.Property("Value"); 191 | 192 | b.HasKey("UserId", "LoginProvider", "Name"); 193 | 194 | b.ToTable("AspNetUserTokens"); 195 | }); 196 | 197 | modelBuilder.Entity("DotNetGigs.Models.Entities.JobSeeker", b => 198 | { 199 | b.HasOne("DotNetGigs.Models.Entities.AppUser", "Identity") 200 | .WithMany() 201 | .HasForeignKey("IdentityId"); 202 | }); 203 | 204 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b => 205 | { 206 | b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole") 207 | .WithMany("Claims") 208 | .HasForeignKey("RoleId") 209 | .OnDelete(DeleteBehavior.Cascade); 210 | }); 211 | 212 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b => 213 | { 214 | b.HasOne("DotNetGigs.Models.Entities.AppUser") 215 | .WithMany("Claims") 216 | .HasForeignKey("UserId") 217 | .OnDelete(DeleteBehavior.Cascade); 218 | }); 219 | 220 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b => 221 | { 222 | b.HasOne("DotNetGigs.Models.Entities.AppUser") 223 | .WithMany("Logins") 224 | .HasForeignKey("UserId") 225 | .OnDelete(DeleteBehavior.Cascade); 226 | }); 227 | 228 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b => 229 | { 230 | b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole") 231 | .WithMany("Users") 232 | .HasForeignKey("RoleId") 233 | .OnDelete(DeleteBehavior.Cascade); 234 | 235 | b.HasOne("DotNetGigs.Models.Entities.AppUser") 236 | .WithMany("Roles") 237 | .HasForeignKey("UserId") 238 | .OnDelete(DeleteBehavior.Cascade); 239 | }); 240 | } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /src/dotnetGigs/Migrations/20170420021732_inital.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.EntityFrameworkCore.Migrations; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | 6 | namespace DotNetGigs.Migrations 7 | { 8 | public partial class inital : Migration 9 | { 10 | protected override void Up(MigrationBuilder migrationBuilder) 11 | { 12 | migrationBuilder.CreateTable( 13 | name: "AspNetUsers", 14 | columns: table => new 15 | { 16 | Id = table.Column(nullable: false), 17 | AccessFailedCount = table.Column(nullable: false), 18 | ConcurrencyStamp = table.Column(nullable: true), 19 | Email = table.Column(maxLength: 256, nullable: true), 20 | EmailConfirmed = table.Column(nullable: false), 21 | FirstName = table.Column(nullable: true), 22 | LastName = table.Column(nullable: true), 23 | LockoutEnabled = table.Column(nullable: false), 24 | LockoutEnd = table.Column(nullable: true), 25 | NormalizedEmail = table.Column(maxLength: 256, nullable: true), 26 | NormalizedUserName = table.Column(maxLength: 256, nullable: true), 27 | PasswordHash = table.Column(nullable: true), 28 | PhoneNumber = table.Column(nullable: true), 29 | PhoneNumberConfirmed = table.Column(nullable: false), 30 | SecurityStamp = table.Column(nullable: true), 31 | TwoFactorEnabled = table.Column(nullable: false), 32 | UserName = table.Column(maxLength: 256, nullable: true) 33 | }, 34 | constraints: table => 35 | { 36 | table.PrimaryKey("PK_AspNetUsers", x => x.Id); 37 | }); 38 | 39 | migrationBuilder.CreateTable( 40 | name: "AspNetRoles", 41 | columns: table => new 42 | { 43 | Id = table.Column(nullable: false), 44 | ConcurrencyStamp = table.Column(nullable: true), 45 | Name = table.Column(maxLength: 256, nullable: true), 46 | NormalizedName = table.Column(maxLength: 256, nullable: true) 47 | }, 48 | constraints: table => 49 | { 50 | table.PrimaryKey("PK_AspNetRoles", x => x.Id); 51 | }); 52 | 53 | migrationBuilder.CreateTable( 54 | name: "AspNetUserTokens", 55 | columns: table => new 56 | { 57 | UserId = table.Column(nullable: false), 58 | LoginProvider = table.Column(nullable: false), 59 | Name = table.Column(nullable: false), 60 | Value = table.Column(nullable: true) 61 | }, 62 | constraints: table => 63 | { 64 | table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); 65 | }); 66 | 67 | migrationBuilder.CreateTable( 68 | name: "JobSeekers", 69 | columns: table => new 70 | { 71 | Id = table.Column(nullable: false) 72 | .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), 73 | IdentityId = table.Column(nullable: true), 74 | Location = table.Column(nullable: true) 75 | }, 76 | constraints: table => 77 | { 78 | table.PrimaryKey("PK_JobSeekers", x => x.Id); 79 | table.ForeignKey( 80 | name: "FK_JobSeekers_AspNetUsers_IdentityId", 81 | column: x => x.IdentityId, 82 | principalTable: "AspNetUsers", 83 | principalColumn: "Id", 84 | onDelete: ReferentialAction.Restrict); 85 | }); 86 | 87 | migrationBuilder.CreateTable( 88 | name: "AspNetUserClaims", 89 | columns: table => new 90 | { 91 | Id = table.Column(nullable: false) 92 | .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), 93 | ClaimType = table.Column(nullable: true), 94 | ClaimValue = table.Column(nullable: true), 95 | UserId = table.Column(nullable: false) 96 | }, 97 | constraints: table => 98 | { 99 | table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); 100 | table.ForeignKey( 101 | name: "FK_AspNetUserClaims_AspNetUsers_UserId", 102 | column: x => x.UserId, 103 | principalTable: "AspNetUsers", 104 | principalColumn: "Id", 105 | onDelete: ReferentialAction.Cascade); 106 | }); 107 | 108 | migrationBuilder.CreateTable( 109 | name: "AspNetUserLogins", 110 | columns: table => new 111 | { 112 | LoginProvider = table.Column(nullable: false), 113 | ProviderKey = table.Column(nullable: false), 114 | ProviderDisplayName = table.Column(nullable: true), 115 | UserId = table.Column(nullable: false) 116 | }, 117 | constraints: table => 118 | { 119 | table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); 120 | table.ForeignKey( 121 | name: "FK_AspNetUserLogins_AspNetUsers_UserId", 122 | column: x => x.UserId, 123 | principalTable: "AspNetUsers", 124 | principalColumn: "Id", 125 | onDelete: ReferentialAction.Cascade); 126 | }); 127 | 128 | migrationBuilder.CreateTable( 129 | name: "AspNetRoleClaims", 130 | columns: table => new 131 | { 132 | Id = table.Column(nullable: false) 133 | .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), 134 | ClaimType = table.Column(nullable: true), 135 | ClaimValue = table.Column(nullable: true), 136 | RoleId = table.Column(nullable: false) 137 | }, 138 | constraints: table => 139 | { 140 | table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); 141 | table.ForeignKey( 142 | name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", 143 | column: x => x.RoleId, 144 | principalTable: "AspNetRoles", 145 | principalColumn: "Id", 146 | onDelete: ReferentialAction.Cascade); 147 | }); 148 | 149 | migrationBuilder.CreateTable( 150 | name: "AspNetUserRoles", 151 | columns: table => new 152 | { 153 | UserId = table.Column(nullable: false), 154 | RoleId = table.Column(nullable: false) 155 | }, 156 | constraints: table => 157 | { 158 | table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); 159 | table.ForeignKey( 160 | name: "FK_AspNetUserRoles_AspNetRoles_RoleId", 161 | column: x => x.RoleId, 162 | principalTable: "AspNetRoles", 163 | principalColumn: "Id", 164 | onDelete: ReferentialAction.Cascade); 165 | table.ForeignKey( 166 | name: "FK_AspNetUserRoles_AspNetUsers_UserId", 167 | column: x => x.UserId, 168 | principalTable: "AspNetUsers", 169 | principalColumn: "Id", 170 | onDelete: ReferentialAction.Cascade); 171 | }); 172 | 173 | migrationBuilder.CreateIndex( 174 | name: "EmailIndex", 175 | table: "AspNetUsers", 176 | column: "NormalizedEmail"); 177 | 178 | migrationBuilder.CreateIndex( 179 | name: "UserNameIndex", 180 | table: "AspNetUsers", 181 | column: "NormalizedUserName", 182 | unique: true); 183 | 184 | migrationBuilder.CreateIndex( 185 | name: "IX_JobSeekers_IdentityId", 186 | table: "JobSeekers", 187 | column: "IdentityId"); 188 | 189 | migrationBuilder.CreateIndex( 190 | name: "RoleNameIndex", 191 | table: "AspNetRoles", 192 | column: "NormalizedName", 193 | unique: true); 194 | 195 | migrationBuilder.CreateIndex( 196 | name: "IX_AspNetRoleClaims_RoleId", 197 | table: "AspNetRoleClaims", 198 | column: "RoleId"); 199 | 200 | migrationBuilder.CreateIndex( 201 | name: "IX_AspNetUserClaims_UserId", 202 | table: "AspNetUserClaims", 203 | column: "UserId"); 204 | 205 | migrationBuilder.CreateIndex( 206 | name: "IX_AspNetUserLogins_UserId", 207 | table: "AspNetUserLogins", 208 | column: "UserId"); 209 | 210 | migrationBuilder.CreateIndex( 211 | name: "IX_AspNetUserRoles_RoleId", 212 | table: "AspNetUserRoles", 213 | column: "RoleId"); 214 | } 215 | 216 | protected override void Down(MigrationBuilder migrationBuilder) 217 | { 218 | migrationBuilder.DropTable( 219 | name: "JobSeekers"); 220 | 221 | migrationBuilder.DropTable( 222 | name: "AspNetRoleClaims"); 223 | 224 | migrationBuilder.DropTable( 225 | name: "AspNetUserClaims"); 226 | 227 | migrationBuilder.DropTable( 228 | name: "AspNetUserLogins"); 229 | 230 | migrationBuilder.DropTable( 231 | name: "AspNetUserRoles"); 232 | 233 | migrationBuilder.DropTable( 234 | name: "AspNetUserTokens"); 235 | 236 | migrationBuilder.DropTable( 237 | name: "AspNetRoles"); 238 | 239 | migrationBuilder.DropTable( 240 | name: "AspNetUsers"); 241 | } 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /src/dotnetGigs/Migrations/ApplicationDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using Microsoft.EntityFrameworkCore.Migrations; 6 | using DotNetGigs.Data; 7 | 8 | namespace DotNetGigs.Migrations 9 | { 10 | [DbContext(typeof(ApplicationDbContext))] 11 | partial class ApplicationDbContextModelSnapshot : ModelSnapshot 12 | { 13 | protected override void BuildModel(ModelBuilder modelBuilder) 14 | { 15 | modelBuilder 16 | .HasAnnotation("ProductVersion", "1.1.1") 17 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 18 | 19 | modelBuilder.Entity("DotNetGigs.Models.Entities.AppUser", b => 20 | { 21 | b.Property("Id") 22 | .ValueGeneratedOnAdd(); 23 | 24 | b.Property("AccessFailedCount"); 25 | 26 | b.Property("ConcurrencyStamp") 27 | .IsConcurrencyToken(); 28 | 29 | b.Property("Email") 30 | .HasMaxLength(256); 31 | 32 | b.Property("EmailConfirmed"); 33 | 34 | b.Property("FirstName"); 35 | 36 | b.Property("LastName"); 37 | 38 | b.Property("LockoutEnabled"); 39 | 40 | b.Property("LockoutEnd"); 41 | 42 | b.Property("NormalizedEmail") 43 | .HasMaxLength(256); 44 | 45 | b.Property("NormalizedUserName") 46 | .HasMaxLength(256); 47 | 48 | b.Property("PasswordHash"); 49 | 50 | b.Property("PhoneNumber"); 51 | 52 | b.Property("PhoneNumberConfirmed"); 53 | 54 | b.Property("SecurityStamp"); 55 | 56 | b.Property("TwoFactorEnabled"); 57 | 58 | b.Property("UserName") 59 | .HasMaxLength(256); 60 | 61 | b.HasKey("Id"); 62 | 63 | b.HasIndex("NormalizedEmail") 64 | .HasName("EmailIndex"); 65 | 66 | b.HasIndex("NormalizedUserName") 67 | .IsUnique() 68 | .HasName("UserNameIndex"); 69 | 70 | b.ToTable("AspNetUsers"); 71 | }); 72 | 73 | modelBuilder.Entity("DotNetGigs.Models.Entities.JobSeeker", b => 74 | { 75 | b.Property("Id") 76 | .ValueGeneratedOnAdd(); 77 | 78 | b.Property("IdentityId"); 79 | 80 | b.Property("Location"); 81 | 82 | b.HasKey("Id"); 83 | 84 | b.HasIndex("IdentityId"); 85 | 86 | b.ToTable("JobSeekers"); 87 | }); 88 | 89 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", b => 90 | { 91 | b.Property("Id") 92 | .ValueGeneratedOnAdd(); 93 | 94 | b.Property("ConcurrencyStamp") 95 | .IsConcurrencyToken(); 96 | 97 | b.Property("Name") 98 | .HasMaxLength(256); 99 | 100 | b.Property("NormalizedName") 101 | .HasMaxLength(256); 102 | 103 | b.HasKey("Id"); 104 | 105 | b.HasIndex("NormalizedName") 106 | .IsUnique() 107 | .HasName("RoleNameIndex"); 108 | 109 | b.ToTable("AspNetRoles"); 110 | }); 111 | 112 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b => 113 | { 114 | b.Property("Id") 115 | .ValueGeneratedOnAdd(); 116 | 117 | b.Property("ClaimType"); 118 | 119 | b.Property("ClaimValue"); 120 | 121 | b.Property("RoleId") 122 | .IsRequired(); 123 | 124 | b.HasKey("Id"); 125 | 126 | b.HasIndex("RoleId"); 127 | 128 | b.ToTable("AspNetRoleClaims"); 129 | }); 130 | 131 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b => 132 | { 133 | b.Property("Id") 134 | .ValueGeneratedOnAdd(); 135 | 136 | b.Property("ClaimType"); 137 | 138 | b.Property("ClaimValue"); 139 | 140 | b.Property("UserId") 141 | .IsRequired(); 142 | 143 | b.HasKey("Id"); 144 | 145 | b.HasIndex("UserId"); 146 | 147 | b.ToTable("AspNetUserClaims"); 148 | }); 149 | 150 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b => 151 | { 152 | b.Property("LoginProvider"); 153 | 154 | b.Property("ProviderKey"); 155 | 156 | b.Property("ProviderDisplayName"); 157 | 158 | b.Property("UserId") 159 | .IsRequired(); 160 | 161 | b.HasKey("LoginProvider", "ProviderKey"); 162 | 163 | b.HasIndex("UserId"); 164 | 165 | b.ToTable("AspNetUserLogins"); 166 | }); 167 | 168 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b => 169 | { 170 | b.Property("UserId"); 171 | 172 | b.Property("RoleId"); 173 | 174 | b.HasKey("UserId", "RoleId"); 175 | 176 | b.HasIndex("RoleId"); 177 | 178 | b.ToTable("AspNetUserRoles"); 179 | }); 180 | 181 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", b => 182 | { 183 | b.Property("UserId"); 184 | 185 | b.Property("LoginProvider"); 186 | 187 | b.Property("Name"); 188 | 189 | b.Property("Value"); 190 | 191 | b.HasKey("UserId", "LoginProvider", "Name"); 192 | 193 | b.ToTable("AspNetUserTokens"); 194 | }); 195 | 196 | modelBuilder.Entity("DotNetGigs.Models.Entities.JobSeeker", b => 197 | { 198 | b.HasOne("DotNetGigs.Models.Entities.AppUser", "Identity") 199 | .WithMany() 200 | .HasForeignKey("IdentityId"); 201 | }); 202 | 203 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", b => 204 | { 205 | b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole") 206 | .WithMany("Claims") 207 | .HasForeignKey("RoleId") 208 | .OnDelete(DeleteBehavior.Cascade); 209 | }); 210 | 211 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim", b => 212 | { 213 | b.HasOne("DotNetGigs.Models.Entities.AppUser") 214 | .WithMany("Claims") 215 | .HasForeignKey("UserId") 216 | .OnDelete(DeleteBehavior.Cascade); 217 | }); 218 | 219 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin", b => 220 | { 221 | b.HasOne("DotNetGigs.Models.Entities.AppUser") 222 | .WithMany("Logins") 223 | .HasForeignKey("UserId") 224 | .OnDelete(DeleteBehavior.Cascade); 225 | }); 226 | 227 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole", b => 228 | { 229 | b.HasOne("Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole") 230 | .WithMany("Users") 231 | .HasForeignKey("RoleId") 232 | .OnDelete(DeleteBehavior.Cascade); 233 | 234 | b.HasOne("DotNetGigs.Models.Entities.AppUser") 235 | .WithMany("Roles") 236 | .HasForeignKey("UserId") 237 | .OnDelete(DeleteBehavior.Cascade); 238 | }); 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /src/dotnetGigs/Models/Entities/AppUser.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 2 | 3 | namespace DotNetGigs.Models.Entities 4 | { 5 | // Add profile data for application users by adding properties to this class 6 | public class AppUser : IdentityUser 7 | { 8 | // Extended Properties 9 | public string FirstName { get; set; } 10 | public string LastName { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/dotnetGigs/Models/Entities/JobSeeker.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace DotNetGigs.Models.Entities 3 | { 4 | public class JobSeeker 5 | { 6 | public int Id { get; set; } 7 | public string IdentityId { get; set; } 8 | public AppUser Identity { get; set; } // navigation property 9 | public string Location {get;set;} 10 | } 11 | } -------------------------------------------------------------------------------- /src/dotnetGigs/Models/JwtIssuerOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.IdentityModel.Tokens; 4 | 5 | namespace DotNetGigs.Models 6 | { 7 | public class JwtIssuerOptions 8 | { 9 | /// 10 | /// 4.1.1. "iss" (Issuer) Claim - The "iss" (issuer) claim identifies the principal that issued the JWT. 11 | /// 12 | public string Issuer { get; set; } 13 | 14 | /// 15 | /// 4.1.2. "sub" (Subject) Claim - The "sub" (subject) claim identifies the principal that is the subject of the JWT. 16 | /// 17 | public string Subject { get; set; } 18 | 19 | /// 20 | /// 4.1.3. "aud" (Audience) Claim - The "aud" (audience) claim identifies the recipients that the JWT is intended for. 21 | /// 22 | public string Audience { get; set; } 23 | 24 | /// 25 | /// 4.1.4. "exp" (Expiration Time) Claim - The "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing. 26 | /// 27 | public DateTime Expiration => IssuedAt.Add(ValidFor); 28 | 29 | /// 30 | /// 4.1.5. "nbf" (Not Before) Claim - The "nbf" (not before) claim identifies the time before which the JWT MUST NOT be accepted for processing. 31 | /// 32 | public DateTime NotBefore { get; set; } = DateTime.UtcNow; 33 | 34 | /// 35 | /// 4.1.6. "iat" (Issued At) Claim - The "iat" (issued at) claim identifies the time at which the JWT was issued. 36 | /// 37 | public DateTime IssuedAt { get; set; } = DateTime.UtcNow; 38 | 39 | /// 40 | /// Set the timespan the token will be valid for (default is 120 min) 41 | /// 42 | public TimeSpan ValidFor { get; set; } = TimeSpan.FromMinutes(120); 43 | 44 | 45 | 46 | /// 47 | /// "jti" (JWT ID) Claim (default ID is a GUID) 48 | /// 49 | public Func> JtiGenerator => 50 | () => Task.FromResult(Guid.NewGuid().ToString()); 51 | 52 | /// 53 | /// The signing key to use when generating tokens. 54 | /// 55 | public SigningCredentials SigningCredentials { get; set; } 56 | } 57 | } -------------------------------------------------------------------------------- /src/dotnetGigs/Program.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.IO; 3 | using Microsoft.AspNetCore.Hosting; 4 | 5 | namespace DotNetGigs 6 | { 7 | public class Program 8 | { 9 | public static void Main(string[] args) 10 | { 11 | var host = new WebHostBuilder() 12 | .UseKestrel() 13 | .UseContentRoot(Directory.GetCurrentDirectory()) 14 | .UseIISIntegration() 15 | .UseStartup() 16 | .Build(); 17 | 18 | host.Run(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/dotnetGigs/README.md: -------------------------------------------------------------------------------- 1 | # DotnetGigs 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.0.0. 4 | 5 | ## Development server 6 | 7 | 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. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class/module`. 12 | 13 | ## Build 14 | 15 | 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. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | Before running the tests make sure you are serving the app via `ng serve`. 25 | 26 | ## Further help 27 | 28 | 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). 29 | -------------------------------------------------------------------------------- /src/dotnetGigs/Startup.cs: -------------------------------------------------------------------------------- 1 |  2 | using System; 3 | using Microsoft.AspNetCore.Builder; 4 | using Microsoft.AspNetCore.Hosting; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Microsoft.Extensions.Logging; 8 | using DotNetGigs.Data; 9 | using Microsoft.EntityFrameworkCore; 10 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 11 | using FluentValidation.AspNetCore; 12 | using DotNetGigs.Models.Entities; 13 | using AutoMapper; 14 | using DotNetGigs.Auth; 15 | using DotNetGigs.Models; 16 | using Microsoft.IdentityModel.Tokens; 17 | using System.Text; 18 | using System.Net; 19 | using DotNetGigs.Helpers; 20 | using Microsoft.AspNetCore.Diagnostics; 21 | using DotNetGigs.Extensions; 22 | using Microsoft.AspNetCore.Http; 23 | 24 | namespace DotNetGigs 25 | { 26 | public class Startup 27 | { 28 | private const string SecretKey = "iNivDmHLpUA223sqsfhqGbMRdRj1PVkH"; // todo: get this from somewhere secure 29 | private readonly SymmetricSecurityKey _signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(SecretKey)); 30 | 31 | public Startup(IHostingEnvironment env) 32 | { 33 | var builder = new ConfigurationBuilder() 34 | .SetBasePath(env.ContentRootPath) 35 | .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 36 | .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) 37 | .AddEnvironmentVariables(); 38 | Configuration = builder.Build(); 39 | } 40 | public IConfigurationRoot Configuration { get; } 41 | 42 | // This method gets called by the runtime. Use this method to add services to the container. 43 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 44 | public void ConfigureServices(IServiceCollection services) 45 | { 46 | // Add framework services. 47 | services.AddDbContext(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), 48 | b => b.MigrationsAssembly("dotnetGigs"))); 49 | 50 | services.AddSingleton(); 51 | 52 | // jwt wire up 53 | // Get options from app settings 54 | var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions)); 55 | 56 | // Configure JwtIssuerOptions 57 | services.Configure(options => 58 | { 59 | options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; 60 | options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)]; 61 | options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256); 62 | }); 63 | 64 | // api user claim policy 65 | services.AddAuthorization(options => 66 | { 67 | options.AddPolicy("ApiUser", policy => policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess)); 68 | }); 69 | 70 | services.AddIdentity 71 | (o => 72 | { 73 | // configure identity options 74 | o.Password.RequireDigit = false; 75 | o.Password.RequireLowercase = false; 76 | o.Password.RequireUppercase = false; 77 | o.Password.RequireNonAlphanumeric = false; 78 | o.Password.RequiredLength = 6; 79 | }) 80 | .AddEntityFrameworkStores() 81 | .AddDefaultTokenProviders(); 82 | 83 | services.AddMvc().AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining()); 84 | 85 | services.AddAutoMapper(); 86 | } 87 | 88 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 89 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 90 | { 91 | loggerFactory.AddConsole(); 92 | 93 | if (env.IsDevelopment()) 94 | { 95 | app.UseDeveloperExceptionPage(); 96 | } 97 | 98 | app.UseExceptionHandler( 99 | builder => 100 | { 101 | builder.Run( 102 | async context => 103 | { 104 | context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; 105 | context.Response.Headers.Add("Access-Control-Allow-Origin", "*"); 106 | 107 | var error = context.Features.Get(); 108 | if (error != null) 109 | { 110 | context.Response.AddApplicationError(error.Error.Message); 111 | await context.Response.WriteAsync(error.Error.Message).ConfigureAwait(false); 112 | } 113 | }); 114 | }); 115 | 116 | var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions)); 117 | var tokenValidationParameters = new TokenValidationParameters 118 | { 119 | ValidateIssuer = true, 120 | ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)], 121 | 122 | ValidateAudience = true, 123 | ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)], 124 | 125 | ValidateIssuerSigningKey = true, 126 | IssuerSigningKey = _signingKey, 127 | 128 | RequireExpirationTime = false, 129 | ValidateLifetime = false, 130 | ClockSkew = TimeSpan.Zero 131 | }; 132 | 133 | app.UseJwtBearerAuthentication(new JwtBearerOptions 134 | { 135 | AutomaticAuthenticate = true, 136 | AutomaticChallenge = true, 137 | TokenValidationParameters = tokenValidationParameters 138 | }); 139 | 140 | app.UseDefaultFiles(); 141 | app.UseStaticFiles(); 142 | app.UseMvc(); 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/dotnetGigs/ViewModels/CredentialsViewModel.cs: -------------------------------------------------------------------------------- 1 | 2 | using FluentValidation.Attributes; 3 | using DotNetGigs.ViewModels.Validations; 4 | 5 | [Validator(typeof(CredentialsViewModelValidator))] 6 | public class CredentialsViewModel 7 | { 8 | public string UserName { get; set; } 9 | public string Password { get; set; } 10 | } -------------------------------------------------------------------------------- /src/dotnetGigs/ViewModels/Mappings/ViewModelToEntityMappingProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using DotNetGigs.Models.Entities; 3 | 4 | namespace DotNetGigs.ViewModels.Mappings 5 | { 6 | public class ViewModelToEntityMappingProfile : Profile 7 | { 8 | public ViewModelToEntityMappingProfile() 9 | { 10 | CreateMap().ForMember(au => au.UserName, map => map.MapFrom(vm => vm.Email)); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/dotnetGigs/ViewModels/RegistrationViewModel.cs: -------------------------------------------------------------------------------- 1 | 2 | using FluentValidation.Attributes; 3 | using DotNetGigs.ViewModels.Validations; 4 | 5 | namespace DotNetGigs.ViewModels 6 | { 7 | [Validator(typeof(RegistrationViewModelValidator))] 8 | public class RegistrationViewModel 9 | { 10 | public string Email { get; set; } 11 | public string Password { get; set; } 12 | public string FirstName {get;set;} 13 | public string LastName {get;set;} 14 | public string Location { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/dotnetGigs/ViewModels/Validations/CredentialsViewModelValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | 3 | namespace DotNetGigs.ViewModels.Validations 4 | { 5 | public class CredentialsViewModelValidator : AbstractValidator 6 | { 7 | public CredentialsViewModelValidator() 8 | { 9 | RuleFor(vm => vm.UserName).NotEmpty().WithMessage("Username cannot be empty"); 10 | RuleFor(vm => vm.Password).NotEmpty().WithMessage("Password cannot be empty"); 11 | RuleFor(vm => vm.Password).Length(6, 12).WithMessage("Password must be between 6 and 12 characters"); 12 | } 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/dotnetGigs/ViewModels/Validations/RegistrationViewModelValidator.cs: -------------------------------------------------------------------------------- 1 | 2 | 3 | using FluentValidation; 4 | 5 | namespace DotNetGigs.ViewModels.Validations 6 | { 7 | public class RegistrationViewModelValidator : AbstractValidator 8 | { 9 | public RegistrationViewModelValidator() 10 | { 11 | RuleFor(vm => vm.Email).NotEmpty().WithMessage("Email cannot be empty"); 12 | RuleFor(vm => vm.Password).NotEmpty().WithMessage("Password cannot be empty"); 13 | RuleFor(vm => vm.FirstName).NotEmpty().WithMessage("FirstName cannot be empty"); 14 | RuleFor(vm => vm.LastName).NotEmpty().WithMessage("LastName cannot be empty"); 15 | RuleFor(vm => vm.Location).NotEmpty().WithMessage("Location cannot be empty"); 16 | } 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/dotnetGigs/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DefaultConnection": "Server=.\\SQLExpress;Database=AngularASPNETCoreAuth;Trusted_Connection=True;MultipleActiveResultSets=true" 4 | }, 5 | "JwtIssuerOptions": { 6 | "Issuer": "dotNetGigs", 7 | "Audience": "http://localhost:5000/" 8 | } 9 | } -------------------------------------------------------------------------------- /src/dotnetGigs/dotnetGigs.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netcoreapp1.1 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/dotnetGigs/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { DotnetGigsPage } from './app.po'; 2 | 3 | describe('dotnet-gigs App', () => { 4 | let page: DotnetGigsPage; 5 | 6 | beforeEach(() => { 7 | page = new DotnetGigsPage(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('app works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/dotnetGigs/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class DotnetGigsPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/dotnetGigs/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types":[ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/dotnetGigs/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/0.13/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular/cli'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular/cli/plugins/karma') 14 | ], 15 | client:{ 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | files: [ 19 | { pattern: './src/test.ts', watched: false } 20 | ], 21 | preprocessors: { 22 | './src/test.ts': ['@angular/cli'] 23 | }, 24 | mime: { 25 | 'text/x-typescript': ['ts','tsx'] 26 | }, 27 | coverageIstanbulReporter: { 28 | reports: [ 'html', 'lcovonly' ], 29 | fixWebpackSourcePaths: true 30 | }, 31 | angularCli: { 32 | environment: 'dev' 33 | }, 34 | reporters: config.angularCli && config.angularCli.codeCoverage 35 | ? ['progress', 'coverage-istanbul'] 36 | : ['progress', 'kjhtml'], 37 | port: 9876, 38 | colors: true, 39 | logLevel: config.LOG_INFO, 40 | autoWatch: true, 41 | browsers: ['Chrome'], 42 | singleRun: false 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /src/dotnetGigs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dotnet-gigs", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "ng": "ng", 7 | "start": "ng serve", 8 | "build": "ng build", 9 | "test": "ng test", 10 | "lint": "ng lint", 11 | "e2e": "ng e2e" 12 | }, 13 | "private": true, 14 | "dependencies": { 15 | "@angular/common": "^4.0.0", 16 | "@angular/compiler": "^4.0.0", 17 | "@angular/core": "^4.0.0", 18 | "@angular/forms": "^4.0.0", 19 | "@angular/http": "^4.0.0", 20 | "@angular/platform-browser": "^4.0.0", 21 | "@angular/platform-browser-dynamic": "^4.0.0", 22 | "@angular/router": "^4.0.0", 23 | "bootstrap": "^4.0.0-beta.2", 24 | "core-js": "^2.4.1", 25 | "rxjs": "^5.1.0", 26 | "zone.js": "^0.8.4", 27 | "tether": "^1.4.2", 28 | "bootstrap-loader": "^2.2.0", 29 | "jquery": "3.2.1" 30 | }, 31 | "devDependencies": { 32 | "@angular/cli": "1.0.0", 33 | "@angular/compiler-cli": "^4.0.0", 34 | "@types/jasmine": "2.5.38", 35 | "@types/node": "~6.0.60", 36 | "codelyzer": "~2.0.0", 37 | "jasmine-core": "~2.5.2", 38 | "jasmine-spec-reporter": "~3.2.0", 39 | "karma": "~1.4.1", 40 | "karma-chrome-launcher": "~2.0.0", 41 | "karma-cli": "~1.0.1", 42 | "karma-jasmine": "~1.1.0", 43 | "karma-jasmine-html-reporter": "^0.2.2", 44 | "karma-coverage-istanbul-reporter": "^0.2.0", 45 | "protractor": "~5.1.0", 46 | "ts-node": "~2.0.0", 47 | "tslint": "~4.5.0", 48 | "typescript": "~2.2.0" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/dotnetGigs/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | beforeLaunch: function() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | }, 27 | onPrepare() { 28 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/account/account.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { SharedModule } from '../shared/modules/shared.module'; 5 | 6 | import { UserService } from '../shared/services/user.service'; 7 | 8 | import { EmailValidator } from '../directives/email.validator.directive'; 9 | 10 | import { routing } from './account.routing'; 11 | import { RegistrationFormComponent } from './registration-form/registration-form.component'; 12 | import { LoginFormComponent } from './login-form/login-form.component'; 13 | 14 | @NgModule({ 15 | imports: [ 16 | CommonModule,FormsModule,routing,SharedModule 17 | ], 18 | declarations: [RegistrationFormComponent,EmailValidator, LoginFormComponent], 19 | providers: [ UserService ] 20 | }) 21 | export class AccountModule { } 22 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/account/account.routing.ts: -------------------------------------------------------------------------------- 1 | import { ModuleWithProviders } from '@angular/core'; 2 | import { RouterModule } from '@angular/router'; 3 | 4 | import { RegistrationFormComponent } from './registration-form/registration-form.component'; 5 | import { LoginFormComponent } from './login-form/login-form.component'; 6 | 7 | export const routing: ModuleWithProviders = RouterModule.forChild([ 8 | { path: 'register', component: RegistrationFormComponent}, 9 | { path: 'login', component: LoginFormComponent} 10 | ]); 11 | 12 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/account/login-form/login-form.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 | 7 | 10 | 11 |

Login

12 | 13 |
14 | 15 |
16 | 17 | 19 | 20 | 21 | Please enter a valid email 22 | 23 | 24 |
25 | 26 |
27 | 28 | 29 |
30 | 31 |
32 | 33 | 34 |
35 | 36 | 39 |
40 | 41 |
42 |
43 |
-------------------------------------------------------------------------------- /src/dotnetGigs/src/app/account/login-form/login-form.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmacneil/AngularASPNETCoreAuthentication/11ca6ddf40daf9a6ba59b9f6d3da8e28f6228382/src/dotnetGigs/src/app/account/login-form/login-form.component.scss -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/account/login-form/login-form.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginFormComponent } from './login-form.component'; 4 | 5 | describe('LoginFormComponent', () => { 6 | let component: LoginFormComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LoginFormComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoginFormComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/account/login-form/login-form.component.ts: -------------------------------------------------------------------------------- 1 | import { Subscription } from 'rxjs'; 2 | import { Component, OnInit,OnDestroy } from '@angular/core'; 3 | import { Router, ActivatedRoute } from '@angular/router'; 4 | 5 | import { Credentials } from '../../shared/models/credentials.interface'; 6 | import { UserService } from '../../shared/services/user.service'; 7 | 8 | @Component({ 9 | selector: 'app-login-form', 10 | templateUrl: './login-form.component.html', 11 | styleUrls: ['./login-form.component.scss'] 12 | }) 13 | export class LoginFormComponent implements OnInit, OnDestroy { 14 | 15 | private subscription: Subscription; 16 | 17 | brandNew: boolean; 18 | errors: string; 19 | isRequesting: boolean; 20 | submitted: boolean = false; 21 | credentials: Credentials = { email: '', password: '' }; 22 | 23 | constructor(private userService: UserService, private router: Router,private activatedRoute: ActivatedRoute) { } 24 | 25 | ngOnInit() { 26 | 27 | // subscribe to router event 28 | this.subscription = this.activatedRoute.queryParams.subscribe( 29 | (param: any) => { 30 | this.brandNew = param['brandNew']; 31 | this.credentials.email = param['email']; 32 | }); 33 | } 34 | 35 | ngOnDestroy() { 36 | // prevent memory leak by unsubscribing 37 | this.subscription.unsubscribe(); 38 | } 39 | 40 | login({ value, valid }: { value: Credentials, valid: boolean }) { 41 | this.submitted = true; 42 | this.isRequesting = true; 43 | this.errors=''; 44 | if (valid) { 45 | this.userService.login(value.email, value.password) 46 | .finally(() => this.isRequesting = false) 47 | .subscribe( 48 | result => { 49 | if (result) { 50 | this.router.navigate(['/dashboard/home']); 51 | } 52 | }, 53 | error => this.errors = error); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/account/registration-form/registration-form.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 6 |
7 | 8 |
9 |

Create your account

10 |
11 | 12 |
13 | 14 |
15 | 16 | 17 |
18 | 19 | 20 |
21 | 22 |
23 | 24 | 25 |
26 | 27 |
28 | 29 | 30 | Please enter a valid email 31 |
32 | 33 |
34 | 35 | 36 |
37 | 38 |
39 | 40 | 41 |
42 | 43 |
44 | 45 | 46 |
47 | 48 | 51 | 52 |
53 |
54 | 55 |
56 |
-------------------------------------------------------------------------------- /src/dotnetGigs/src/app/account/registration-form/registration-form.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmacneil/AngularASPNETCoreAuthentication/11ca6ddf40daf9a6ba59b9f6d3da8e28f6228382/src/dotnetGigs/src/app/account/registration-form/registration-form.component.scss -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/account/registration-form/registration-form.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RegistrationFormComponent } from './registration-form.component'; 4 | 5 | describe('RegistrationFormComponent', () => { 6 | let component: RegistrationFormComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RegistrationFormComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RegistrationFormComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/account/registration-form/registration-form.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | 4 | import { UserRegistration } from '../../shared/models/user.registration.interface'; 5 | import { UserService } from '../../shared/services/user.service'; 6 | 7 | @Component({ 8 | selector: 'app-registration-form', 9 | templateUrl: './registration-form.component.html', 10 | styleUrls: ['./registration-form.component.scss'] 11 | }) 12 | export class RegistrationFormComponent implements OnInit { 13 | 14 | errors: string; 15 | isRequesting: boolean; 16 | submitted: boolean = false; 17 | 18 | constructor(private userService: UserService,private router: Router) { 19 | 20 | } 21 | 22 | ngOnInit() { 23 | 24 | } 25 | 26 | registerUser({ value, valid }: { value: UserRegistration, valid: boolean }) { 27 | this.submitted = true; 28 | this.isRequesting = true; 29 | this.errors=''; 30 | if(valid) 31 | { 32 | this.userService.register(value.email,value.password,value.firstName,value.lastName,value.location) 33 | .finally(() => this.isRequesting = false) 34 | .subscribe( 35 | result => {if(result){ 36 | this.router.navigate(['/login'],{queryParams: {brandNew: true,email:value.email}}); 37 | }}, 38 | errors => this.errors = errors); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 |
8 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | body { 2 | background-color:#f9f9f9 3 | } 4 | 5 | .container-fluid { 6 | padding-left: 1.25rem; 7 | padding-right: 1.25rem; 8 | max-width: 920px; 9 | margin-left: auto; 10 | margin-right: auto 11 | } 12 | 13 | .card { 14 | box-shadow: 0 2px 3px rgba(0,0,0,.05); 15 | position: relative; 16 | background-color: #fff; 17 | border: 1px solid #eee; 18 | border-radius: 3px; 19 | padding:10px 20 | } 21 | 22 | .card-title { 23 | margin: 0 !important; 24 | font-size: 1.25rem 25 | } 26 | 27 | .bg-white{background: #fff} -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | declarations: [ 9 | AppComponent 10 | ], 11 | }).compileComponents(); 12 | })); 13 | 14 | it('should create the app', async(() => { 15 | const fixture = TestBed.createComponent(AppComponent); 16 | const app = fixture.debugElement.componentInstance; 17 | expect(app).toBeTruthy(); 18 | })); 19 | 20 | it(`should have as title 'app works!'`, async(() => { 21 | const fixture = TestBed.createComponent(AppComponent); 22 | const app = fixture.debugElement.componentInstance; 23 | expect(app.title).toEqual('app works!'); 24 | })); 25 | 26 | it('should render title in a h1 tag', async(() => { 27 | const fixture = TestBed.createComponent(AppComponent); 28 | fixture.detectChanges(); 29 | const compiled = fixture.debugElement.nativeElement; 30 | expect(compiled.querySelector('h1').textContent).toContain('app works!'); 31 | })); 32 | }); 33 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component,ViewEncapsulation } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | encapsulation: ViewEncapsulation.None, 6 | templateUrl: './app.component.html', 7 | styleUrls: ['./app.component.scss'] 8 | }) 9 | export class AppComponent { 10 | title = 'app works!'; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { HttpModule, XHRBackend } from '@angular/http'; 5 | import { AuthenticateXHRBackend } from './authenticate-xhr.backend'; 6 | 7 | import { routing } from './app.routing'; 8 | 9 | /* App Root */ 10 | import { AppComponent } from './app.component'; 11 | import { HeaderComponent } from './header/header.component'; 12 | import { HomeComponent } from './home/home.component'; 13 | 14 | /* Account Imports */ 15 | import { AccountModule } from './account/account.module'; 16 | /* Dashboard Imports */ 17 | import { DashboardModule } from './dashboard/dashboard.module'; 18 | 19 | import { ConfigService } from './shared/utils/config.service'; 20 | 21 | 22 | @NgModule({ 23 | declarations: [ 24 | AppComponent, 25 | HeaderComponent, 26 | HomeComponent 27 | ], 28 | imports: [ 29 | AccountModule, 30 | DashboardModule, 31 | BrowserModule, 32 | FormsModule, 33 | HttpModule, 34 | routing 35 | ], 36 | providers: [ConfigService, { 37 | provide: XHRBackend, 38 | useClass: AuthenticateXHRBackend 39 | }], 40 | bootstrap: [AppComponent] 41 | }) 42 | export class AppModule { } 43 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/app.routing.ts: -------------------------------------------------------------------------------- 1 | import { ModuleWithProviders } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { HomeComponent } from './home/home.component'; 5 | 6 | const appRoutes: Routes = [ 7 | { path: '', component: HomeComponent }, 8 | { path: 'account', loadChildren: 'app/account/account.module#AccountModule' } 9 | ]; 10 | 11 | export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes); -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/auth.guard.ts: -------------------------------------------------------------------------------- 1 | // auth.guard.ts 2 | import { Injectable } from '@angular/core'; 3 | import { Router, CanActivate } from '@angular/router'; 4 | import { UserService } from './shared/services/user.service'; 5 | 6 | @Injectable() 7 | export class AuthGuard implements CanActivate { 8 | constructor(private user: UserService,private router: Router) {} 9 | 10 | canActivate() { 11 | 12 | if(!this.user.isLoggedIn()) 13 | { 14 | this.router.navigate(['/account/login']); 15 | return false; 16 | } 17 | 18 | return true; 19 | } 20 | } -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/authenticate-xhr.backend.ts: -------------------------------------------------------------------------------- 1 | import { Request, XHRBackend, BrowserXhr, ResponseOptions, XSRFStrategy, Response } from '@angular/http'; 2 | import { Observable } from 'rxjs/Observable'; 3 | import 'rxjs/add/operator/catch'; 4 | import 'rxjs/add/observable/throw'; 5 | import { Injectable } from '@angular/core'; 6 | 7 | // sweet global way to handle 401s - works in tandem with existing AuthGuard route checks 8 | // http://stackoverflow.com/questions/34934009/handling-401s-globally-with-angular-2 9 | 10 | @Injectable() 11 | export class AuthenticateXHRBackend extends XHRBackend { 12 | 13 | constructor(_browserXhr: BrowserXhr, _baseResponseOptions: ResponseOptions, _xsrfStrategy: XSRFStrategy) { 14 | super(_browserXhr, _baseResponseOptions, _xsrfStrategy); 15 | } 16 | 17 | createConnection(request: Request) { 18 | let xhrConnection = super.createConnection(request); 19 | xhrConnection.response = xhrConnection.response.catch((error: Response) => { 20 | if ((error.status === 401 || error.status === 403) && (window.location.href.match(/\?/g) || []).length < 2) { 21 | 22 | console.log('The authentication session expired or the user is not authorized. Force refresh of the current page.'); 23 | /* Great solution for bundling with Auth Guard! 24 | 1. Auth Guard checks authorized user (e.g. by looking into LocalStorage). 25 | 2. On 401/403 response you clean authorized user for the Guard (e.g. by removing coresponding parameters in LocalStorage). 26 | 3. As at this early stage you can't access the Router for forwarding to the login page, 27 | 4. refreshing the same page will trigger the Guard checks, which will forward you to the login screen */ 28 | localStorage.removeItem('auth_token'); 29 | window.location.href = window.location.href + '?' + new Date().getMilliseconds(); 30 | } 31 | return Observable.throw(error); 32 | }); 33 | return xhrConnection; 34 | } 35 | } -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/dashboard/dashboard.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { SharedModule } from '../shared/modules/shared.module'; 5 | 6 | import { routing } from './dashboard.routing'; 7 | import { RootComponent } from './root/root.component'; 8 | import { HomeComponent } from './home/home.component'; 9 | import { DashboardService } from './services/dashboard.service'; 10 | 11 | import { AuthGuard } from '../auth.guard'; 12 | 13 | @NgModule({ 14 | imports: [ 15 | CommonModule, 16 | FormsModule, 17 | routing, 18 | SharedModule], 19 | declarations: [RootComponent,HomeComponent], 20 | exports: [ ], 21 | providers: [AuthGuard,DashboardService] 22 | }) 23 | export class DashboardModule { } 24 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/dashboard/dashboard.routing.ts: -------------------------------------------------------------------------------- 1 | import { ModuleWithProviders } from '@angular/core'; 2 | import { RouterModule } from '@angular/router'; 3 | 4 | import { RootComponent } from './root/root.component'; 5 | import { HomeComponent } from './home/home.component'; 6 | 7 | import { AuthGuard } from '../auth.guard'; 8 | 9 | export const routing: ModuleWithProviders = RouterModule.forChild([ 10 | { 11 | path: 'dashboard', 12 | component: RootComponent, canActivate: [AuthGuard], 13 | 14 | children: [ 15 | { path: '', component: HomeComponent }, 16 | { path: 'home', component: HomeComponent }, 17 | ] 18 | } 19 | ]); 20 | 21 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/dashboard/home/home.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Welcome home!

4 |

{{homeDetails?.message}}

5 |
6 |
-------------------------------------------------------------------------------- /src/dotnetGigs/src/app/dashboard/home/home.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmacneil/AngularASPNETCoreAuthentication/11ca6ddf40daf9a6ba59b9f6d3da8e28f6228382/src/dotnetGigs/src/app/dashboard/home/home.component.scss -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/dashboard/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HomeComponent } from './home.component'; 4 | 5 | describe('HomeComponent', () => { 6 | let component: HomeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ HomeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HomeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/dashboard/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | import { HomeDetails } from '../models/home.details.interface'; 4 | import { DashboardService } from '../services/dashboard.service'; 5 | 6 | @Component({ 7 | selector: 'app-home', 8 | templateUrl: './home.component.html', 9 | styleUrls: ['./home.component.scss'] 10 | }) 11 | export class HomeComponent implements OnInit { 12 | 13 | homeDetails: HomeDetails; 14 | 15 | constructor(private dashboardService: DashboardService) { } 16 | 17 | ngOnInit() { 18 | 19 | this.dashboardService.getHomeDetails() 20 | .subscribe((homeDetails: HomeDetails) => { 21 | this.homeDetails = homeDetails; 22 | }, 23 | error => { 24 | //this.notificationService.printErrorMessage(error); 25 | }); 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/dashboard/models/home.details.interface.ts: -------------------------------------------------------------------------------- 1 | export interface HomeDetails { 2 | message: string; 3 | } -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/dashboard/root/root.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 10 | 11 |
12 | 13 |
14 |
-------------------------------------------------------------------------------- /src/dotnetGigs/src/app/dashboard/root/root.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmacneil/AngularASPNETCoreAuthentication/11ca6ddf40daf9a6ba59b9f6d3da8e28f6228382/src/dotnetGigs/src/app/dashboard/root/root.component.scss -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/dashboard/root/root.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RootComponent } from './root.component'; 4 | 5 | describe('RootComponent', () => { 6 | let component: RootComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RootComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RootComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/dashboard/root/root.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './root.component.html', 6 | styleUrls: ['./root.component.scss'] 7 | }) 8 | export class RootComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/dashboard/services/dashboard.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http, Response, Headers } from '@angular/http'; 3 | 4 | import { HomeDetails } from '../models/home.details.interface'; 5 | import { ConfigService } from '../../shared/utils/config.service'; 6 | 7 | import {BaseService} from '../../shared/services/base.service'; 8 | 9 | import { Observable } from 'rxjs/Rx'; 10 | 11 | //import * as _ from 'lodash'; 12 | 13 | // Add the RxJS Observable operators we need in this app. 14 | import '../../rxjs-operators'; 15 | 16 | @Injectable() 17 | 18 | export class DashboardService extends BaseService { 19 | 20 | baseUrl: string = ''; 21 | 22 | constructor(private http: Http, private configService: ConfigService) { 23 | super(); 24 | this.baseUrl = configService.getApiURI(); 25 | } 26 | 27 | getHomeDetails(): Observable { 28 | let headers = new Headers(); 29 | headers.append('Content-Type', 'application/json'); 30 | let authToken = localStorage.getItem('auth_token'); 31 | headers.append('Authorization', `Bearer ${authToken}`); 32 | 33 | return this.http.get(this.baseUrl + "/dashboard/home",{headers}) 34 | .map(response => response.json()) 35 | .catch(this.handleError); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/directives/email.validator.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, forwardRef } from '@angular/core'; 2 | import { NG_VALIDATORS, FormControl } from '@angular/forms'; 3 | 4 | function validateEmailFactory() { 5 | return (c: FormControl) => { 6 | let EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i; 7 | 8 | return EMAIL_REGEXP.test(c.value) ? null : { 9 | validateEmail: { 10 | valid: false 11 | } 12 | }; 13 | }; 14 | } 15 | 16 | @Directive({ 17 | selector: '[validateEmail][ngModel],[validateEmail][formControl]', 18 | providers: [ 19 | { provide: NG_VALIDATORS, useExisting: forwardRef(() => EmailValidator), multi: true } 20 | ] 21 | }) 22 | export class EmailValidator { 23 | 24 | validator: Function; 25 | 26 | constructor() { 27 | this.validator = validateEmailFactory(); 28 | } 29 | 30 | validate(c: FormControl) { 31 | return this.validator(c); 32 | } 33 | } -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/directives/focus.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, ElementRef, Renderer, OnInit } from "@angular/core"; 2 | 3 | @Directive({ selector: '[tmFocus]' }) 4 | 5 | export class myFocus implements OnInit { 6 | constructor(private el: ElementRef, private renderer: Renderer) { 7 | // focus won't work at construction time - too early 8 | } 9 | 10 | ngOnInit() { 11 | this.renderer.invokeElementMethod(this.el.nativeElement, 'focus', []); 12 | } 13 | } -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/header/header.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/header/header.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmacneil/AngularASPNETCoreAuthentication/11ca6ddf40daf9a6ba59b9f6d3da8e28f6228382/src/dotnetGigs/src/app/header/header.component.scss -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/header/header.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HeaderComponent } from './header.component'; 4 | 5 | describe('HeaderComponent', () => { 6 | let component: HeaderComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ HeaderComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HeaderComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/header/header.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit,OnDestroy } from '@angular/core'; 2 | import {Subscription} from 'rxjs/Subscription'; 3 | 4 | import { UserService } from '../shared/services/user.service'; 5 | 6 | @Component({ 7 | selector: 'app-header', 8 | templateUrl: './header.component.html', 9 | styleUrls: ['./header.component.scss'] 10 | }) 11 | export class HeaderComponent implements OnInit,OnDestroy { 12 | 13 | status: boolean; 14 | subscription:Subscription; 15 | 16 | constructor(private userService:UserService) { 17 | } 18 | 19 | logout() { 20 | this.userService.logout(); 21 | } 22 | 23 | ngOnInit() { 24 | this.subscription = this.userService.authNavStatus$.subscribe(status => this.status = status); 25 | } 26 | 27 | ngOnDestroy() { 28 | // prevent memory leak when component is destroyed 29 | this.subscription.unsubscribe(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/home/home.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

DotNetGigs

4 |

Welcome, please signup or login to your account below.

5 |

6 | Signup 7 | Login 8 |

9 |
10 |
-------------------------------------------------------------------------------- /src/dotnetGigs/src/app/home/home.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmacneil/AngularASPNETCoreAuthentication/11ca6ddf40daf9a6ba59b9f6d3da8e28f6228382/src/dotnetGigs/src/app/home/home.component.scss -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HomeComponent } from './home.component'; 4 | 5 | describe('HomeComponent', () => { 6 | let component: HomeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ HomeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HomeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-home', 5 | templateUrl: './home.component.html', 6 | styleUrls: ['./home.component.scss'] 7 | }) 8 | export class HomeComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/rxjs-operators.js: -------------------------------------------------------------------------------- 1 | // import 'rxjs/Rx'; // adds ALL RxJS statics & operators to Observable 2 | 3 | // See node_module/rxjs/Rxjs.js 4 | // Import just the rxjs statics and operators we need for THIS app. 5 | 6 | // Statics 7 | import 'rxjs/add/observable/throw'; 8 | 9 | // Operators 10 | import 'rxjs/add/operator/catch'; 11 | import 'rxjs/add/operator/debounceTime'; 12 | import 'rxjs/add/operator/distinctUntilChanged'; 13 | import 'rxjs/add/operator/map'; 14 | import 'rxjs/add/operator/switchMap'; 15 | import 'rxjs/add/operator/toPromise'; -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/shared/models/credentials.interface.ts: -------------------------------------------------------------------------------- 1 | export interface Credentials { 2 | email: string; 3 | password: string; 4 | } -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/shared/models/user.registration.interface.ts: -------------------------------------------------------------------------------- 1 | export interface UserRegistration { 2 | email: string; 3 | password: string; 4 | firstName: string; 5 | lastName: string; 6 | location: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/shared/modules/shared.module.ts: -------------------------------------------------------------------------------- 1 | // include directives/components commonly used in features modules in this shared modules 2 | // and import me into the feature module 3 | // importing them individually results in: Type xxx is part of the declarations of 2 modules: ... Please consider moving to a higher module... 4 | // https://github.com/angular/angular/issues/10646 5 | 6 | import { NgModule } from '@angular/core'; 7 | import { CommonModule } from '@angular/common'; 8 | 9 | import { myFocus } from '../../directives/focus.directive'; 10 | import {SpinnerComponent} from '../../spinner/spinner.component'; 11 | 12 | 13 | @NgModule({ 14 | imports: [CommonModule], 15 | declarations: [myFocus,SpinnerComponent], 16 | exports: [myFocus,SpinnerComponent], 17 | providers: [] 18 | }) 19 | export class SharedModule { } 20 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/shared/services/base.service.ts: -------------------------------------------------------------------------------- 1 | import { Observable } from 'rxjs/Rx'; 2 | 3 | 4 | export abstract class BaseService { 5 | 6 | constructor() { } 7 | 8 | protected handleError(error: any) { 9 | var applicationError = error.headers.get('Application-Error'); 10 | 11 | // either applicationError in header or model error in body 12 | if (applicationError) { 13 | return Observable.throw(applicationError); 14 | } 15 | 16 | var modelStateErrors: string = ''; 17 | var serverError = error.json(); 18 | 19 | if (!serverError.type) { 20 | for (var key in serverError) { 21 | if (serverError[key]) 22 | modelStateErrors += serverError[key] + '\n'; 23 | } 24 | } 25 | 26 | modelStateErrors = modelStateErrors = '' ? null : modelStateErrors; 27 | return Observable.throw(modelStateErrors || 'Server error'); 28 | } 29 | } -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/shared/services/user.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http, Response, Headers, RequestOptions } from '@angular/http'; 3 | 4 | import { UserRegistration } from '../models/user.registration.interface'; 5 | import { ConfigService } from '../utils/config.service'; 6 | 7 | import {BaseService} from "./base.service"; 8 | 9 | import { Observable } from 'rxjs/Rx'; 10 | import { BehaviorSubject } from 'rxjs/Rx'; 11 | 12 | //import * as _ from 'lodash'; 13 | 14 | // Add the RxJS Observable operators we need in this app. 15 | import '../../rxjs-operators'; 16 | 17 | @Injectable() 18 | 19 | export class UserService extends BaseService { 20 | 21 | baseUrl: string = ''; 22 | 23 | // Observable navItem source 24 | private _authNavStatusSource = new BehaviorSubject(false); 25 | // Observable navItem stream 26 | authNavStatus$ = this._authNavStatusSource.asObservable(); 27 | 28 | private loggedIn = false; 29 | 30 | constructor(private http: Http, private configService: ConfigService) { 31 | super(); 32 | this.loggedIn = !!localStorage.getItem('auth_token'); 33 | // ?? not sure if this the best way to broadcast the status but seems to resolve issue on page refresh where auth status is lost in 34 | // header component resulting in authed user nav links disappearing despite the fact user is still logged in 35 | this._authNavStatusSource.next(this.loggedIn); 36 | this.baseUrl = configService.getApiURI(); 37 | } 38 | 39 | register(email: string, password: string, firstName: string, lastName: string,location: string): Observable { 40 | let body = JSON.stringify({ email, password, firstName, lastName,location }); 41 | let headers = new Headers({ 'Content-Type': 'application/json' }); 42 | let options = new RequestOptions({ headers: headers }); 43 | 44 | return this.http.post(this.baseUrl + "/accounts", body, options) 45 | .map(res => true) 46 | .catch(this.handleError); 47 | } 48 | 49 | login(userName, password) { 50 | let headers = new Headers(); 51 | headers.append('Content-Type', 'application/json'); 52 | 53 | return this.http 54 | .post( 55 | this.baseUrl + '/auth/login', 56 | JSON.stringify({ userName, password }),{ headers } 57 | ) 58 | .map(res => res.json()) 59 | .map(res => { 60 | localStorage.setItem('auth_token', res.auth_token); 61 | this.loggedIn = true; 62 | this._authNavStatusSource.next(true); 63 | return true; 64 | }) 65 | .catch(this.handleError); 66 | } 67 | 68 | logout() { 69 | localStorage.removeItem('auth_token'); 70 | this.loggedIn = false; 71 | this._authNavStatusSource.next(false); 72 | } 73 | 74 | isLoggedIn() { 75 | return this.loggedIn; 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/shared/utils/config.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable() 4 | export class ConfigService { 5 | 6 | _apiURI : string; 7 | 8 | constructor() { 9 | this._apiURI = 'http://localhost:5000/api'; 10 | } 11 | 12 | getApiURI() { 13 | return this._apiURI; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/spinner/spinner.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
-------------------------------------------------------------------------------- /src/dotnetGigs/src/app/spinner/spinner.component.scss: -------------------------------------------------------------------------------- 1 | .spinner { 2 | width: 40px; 3 | height: 40px; 4 | 5 | position: relative; 6 | margin: 30px auto; 7 | } 8 | 9 | .double-bounce1, .double-bounce2 { 10 | width: 100%; 11 | height: 100%; 12 | border-radius: 50%; 13 | background-color: #333; 14 | opacity: 0.6; 15 | position: absolute; 16 | top: 0; 17 | left: 0; 18 | 19 | -webkit-animation: sk-bounce 2.0s infinite ease-in-out; 20 | animation: sk-bounce 2.0s infinite ease-in-out; 21 | } 22 | 23 | .double-bounce2 { 24 | -webkit-animation-delay: -1.0s; 25 | animation-delay: -1.0s; 26 | } 27 | 28 | @-webkit-keyframes sk-bounce { 29 | 0%, 100% { -webkit-transform: scale(0.0) } 30 | 50% { -webkit-transform: scale(1.0) } 31 | } 32 | 33 | @keyframes sk-bounce { 34 | 0%, 100% { 35 | transform: scale(0.0); 36 | -webkit-transform: scale(0.0); 37 | } 50% { 38 | transform: scale(1.0); 39 | -webkit-transform: scale(1.0); 40 | } 41 | } -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/spinner/spinner.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SpinnerComponent } from './spinner.component'; 4 | 5 | describe('SpinnerComponent', () => { 6 | let component: SpinnerComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SpinnerComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SpinnerComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/app/spinner/spinner.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnDestroy } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-spinner', 5 | templateUrl: './spinner.component.html', 6 | styleUrls: ['./spinner.component.scss'] 7 | }) 8 | 9 | 10 | export class SpinnerComponent implements OnDestroy { 11 | private currentTimeout: number; 12 | private isDelayedRunning: boolean = false; 13 | 14 | @Input() 15 | public delay: number = 150; 16 | 17 | @Input() 18 | public set isRunning(value: boolean) { 19 | if (!value) { 20 | this.cancelTimeout(); 21 | this.isDelayedRunning = false; 22 | return; 23 | } 24 | 25 | if (this.currentTimeout) { 26 | return; 27 | } 28 | 29 | // specify window to side-step conflict with node types: https://github.com/mgechev/angular2-seed/issues/901 30 | this.currentTimeout = window.setTimeout(() => { 31 | this.isDelayedRunning = value; 32 | this.cancelTimeout(); 33 | }, this.delay); 34 | } 35 | 36 | private cancelTimeout(): void { 37 | clearTimeout(this.currentTimeout); 38 | this.currentTimeout = undefined; 39 | } 40 | 41 | ngOnDestroy(): any { 42 | this.cancelTimeout(); 43 | } 44 | } -------------------------------------------------------------------------------- /src/dotnetGigs/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmacneil/AngularASPNETCoreAuthentication/11ca6ddf40daf9a6ba59b9f6d3da8e28f6228382/src/dotnetGigs/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/dotnetGigs/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmacneil/AngularASPNETCoreAuthentication/11ca6ddf40daf9a6ba59b9f6d3da8e28f6228382/src/dotnetGigs/src/favicon.ico -------------------------------------------------------------------------------- /src/dotnetGigs/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | DotnetGigs 9 | 10 | 11 | 12 | 13 | Loading... 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/set'; 35 | 36 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 37 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 38 | 39 | /** IE10 and IE11 requires the following to support `@angular/animation`. */ 40 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 41 | 42 | 43 | /** Evergreen browsers require these. **/ 44 | import 'core-js/es6/reflect'; 45 | import 'core-js/es7/reflect'; 46 | 47 | 48 | /** ALL Firefox browsers require the following to support `@angular/animation`. **/ 49 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 50 | 51 | 52 | 53 | /*************************************************************************************************** 54 | * Zone JS is required by Angular itself. 55 | */ 56 | import 'zone.js/dist/zone'; // Included with Angular CLI. 57 | 58 | 59 | 60 | /*************************************************************************************************** 61 | * APPLICATION IMPORTS 62 | */ 63 | 64 | /** 65 | * Date, currency, decimal and percent pipes. 66 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 67 | */ 68 | // import 'intl'; // Run `npm install --save intl`. 69 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/long-stack-trace-zone'; 4 | import 'zone.js/dist/proxy.js'; 5 | import 'zone.js/dist/sync-test'; 6 | import 'zone.js/dist/jasmine-patch'; 7 | import 'zone.js/dist/async-test'; 8 | import 'zone.js/dist/fake-async-test'; 9 | import { getTestBed } from '@angular/core/testing'; 10 | import { 11 | BrowserDynamicTestingModule, 12 | platformBrowserDynamicTesting 13 | } from '@angular/platform-browser-dynamic/testing'; 14 | 15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. 16 | declare var __karma__: any; 17 | declare var require: any; 18 | 19 | // Prevent Karma from running prematurely. 20 | __karma__.loaded = function () {}; 21 | 22 | // First, initialize the Angular testing environment. 23 | getTestBed().initTestEnvironment( 24 | BrowserDynamicTestingModule, 25 | platformBrowserDynamicTesting() 26 | ); 27 | // Then we find all the tests. 28 | const context = require.context('./', true, /\.spec\.ts$/); 29 | // And load the modules. 30 | context.keys().map(context); 31 | // Finally, start Karma to run the tests. 32 | __karma__.start(); 33 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "baseUrl": "", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/dotnetGigs/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/dotnetGigs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "baseUrl": "src", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2016", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/dotnetGigs/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "callable-types": true, 7 | "class-name": true, 8 | "comment-format": [ 9 | true, 10 | "check-space" 11 | ], 12 | "curly": true, 13 | "eofline": true, 14 | "forin": true, 15 | "import-blacklist": [true, "rxjs"], 16 | "import-spacing": true, 17 | "indent": [ 18 | true, 19 | "spaces" 20 | ], 21 | "interface-over-type-literal": true, 22 | "label-position": true, 23 | "max-line-length": [ 24 | true, 25 | 140 26 | ], 27 | "member-access": false, 28 | "member-ordering": [ 29 | true, 30 | "static-before-instance", 31 | "variables-before-functions" 32 | ], 33 | "no-arg": true, 34 | "no-bitwise": true, 35 | "no-console": [ 36 | true, 37 | "debug", 38 | "info", 39 | "time", 40 | "timeEnd", 41 | "trace" 42 | ], 43 | "no-construct": true, 44 | "no-debugger": true, 45 | "no-duplicate-variable": true, 46 | "no-empty": false, 47 | "no-empty-interface": true, 48 | "no-eval": true, 49 | "no-inferrable-types": [true, "ignore-params"], 50 | "no-shadowed-variable": true, 51 | "no-string-literal": false, 52 | "no-string-throw": true, 53 | "no-switch-case-fall-through": true, 54 | "no-trailing-whitespace": true, 55 | "no-unused-expression": true, 56 | "no-use-before-declare": true, 57 | "no-var-keyword": true, 58 | "object-literal-sort-keys": false, 59 | "one-line": [ 60 | true, 61 | "check-open-brace", 62 | "check-catch", 63 | "check-else", 64 | "check-whitespace" 65 | ], 66 | "prefer-const": true, 67 | "quotemark": [ 68 | true, 69 | "single" 70 | ], 71 | "radix": true, 72 | "semicolon": [ 73 | "always" 74 | ], 75 | "triple-equals": [ 76 | true, 77 | "allow-null-check" 78 | ], 79 | "typedef-whitespace": [ 80 | true, 81 | { 82 | "call-signature": "nospace", 83 | "index-signature": "nospace", 84 | "parameter": "nospace", 85 | "property-declaration": "nospace", 86 | "variable-declaration": "nospace" 87 | } 88 | ], 89 | "typeof-compare": true, 90 | "unified-signatures": true, 91 | "variable-name": false, 92 | "whitespace": [ 93 | true, 94 | "check-branch", 95 | "check-decl", 96 | "check-operator", 97 | "check-separator", 98 | "check-type" 99 | ], 100 | 101 | "directive-selector": [true, "attribute", "app", "camelCase"], 102 | "component-selector": [true, "element", "app", "kebab-case"], 103 | "use-input-property-decorator": true, 104 | "use-output-property-decorator": true, 105 | "use-host-property-decorator": true, 106 | "no-input-rename": true, 107 | "no-output-rename": true, 108 | "use-life-cycle-interface": true, 109 | "use-pipe-transform-interface": true, 110 | "component-class-suffix": true, 111 | "directive-class-suffix": true, 112 | "no-access-missing-member": true, 113 | "templates-use-public": true, 114 | "invoke-injectable": true 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/dotnetGigs/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmacneil/AngularASPNETCoreAuthentication/11ca6ddf40daf9a6ba59b9f6d3da8e28f6228382/src/dotnetGigs/wwwroot/favicon.ico -------------------------------------------------------------------------------- /src/dotnetGigs/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | DotnetGigs 9 | 10 | 11 | 12 | 13 | Loading... 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/dotnetGigs/wwwroot/inline.bundle.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // install a JSONP callback for chunk loading 3 | /******/ var parentJsonpFunction = window["webpackJsonp"]; 4 | /******/ window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) { 5 | /******/ // add "moreModules" to the modules object, 6 | /******/ // then flag all "chunkIds" as loaded and fire callback 7 | /******/ var moduleId, chunkId, i = 0, resolves = [], result; 8 | /******/ for(;i < chunkIds.length; i++) { 9 | /******/ chunkId = chunkIds[i]; 10 | /******/ if(installedChunks[chunkId]) 11 | /******/ resolves.push(installedChunks[chunkId][0]); 12 | /******/ installedChunks[chunkId] = 0; 13 | /******/ } 14 | /******/ for(moduleId in moreModules) { 15 | /******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { 16 | /******/ modules[moduleId] = moreModules[moduleId]; 17 | /******/ } 18 | /******/ } 19 | /******/ if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules); 20 | /******/ while(resolves.length) 21 | /******/ resolves.shift()(); 22 | /******/ if(executeModules) { 23 | /******/ for(i=0; i < executeModules.length; i++) { 24 | /******/ result = __webpack_require__(__webpack_require__.s = executeModules[i]); 25 | /******/ } 26 | /******/ } 27 | /******/ return result; 28 | /******/ }; 29 | /******/ 30 | /******/ // The module cache 31 | /******/ var installedModules = {}; 32 | /******/ 33 | /******/ // objects to store loaded and loading chunks 34 | /******/ var installedChunks = { 35 | /******/ 5: 0 36 | /******/ }; 37 | /******/ 38 | /******/ // The require function 39 | /******/ function __webpack_require__(moduleId) { 40 | /******/ 41 | /******/ // Check if module is in cache 42 | /******/ if(installedModules[moduleId]) 43 | /******/ return installedModules[moduleId].exports; 44 | /******/ 45 | /******/ // Create a new module (and put it into the cache) 46 | /******/ var module = installedModules[moduleId] = { 47 | /******/ i: moduleId, 48 | /******/ l: false, 49 | /******/ exports: {} 50 | /******/ }; 51 | /******/ 52 | /******/ // Execute the module function 53 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 54 | /******/ 55 | /******/ // Flag the module as loaded 56 | /******/ module.l = true; 57 | /******/ 58 | /******/ // Return the exports of the module 59 | /******/ return module.exports; 60 | /******/ } 61 | /******/ 62 | /******/ // This file contains only the entry chunk. 63 | /******/ // The chunk loading function for additional chunks 64 | /******/ __webpack_require__.e = function requireEnsure(chunkId) { 65 | /******/ if(installedChunks[chunkId] === 0) 66 | /******/ return Promise.resolve(); 67 | /******/ 68 | /******/ // an Promise means "currently loading". 69 | /******/ if(installedChunks[chunkId]) { 70 | /******/ return installedChunks[chunkId][2]; 71 | /******/ } 72 | /******/ // start chunk loading 73 | /******/ var head = document.getElementsByTagName('head')[0]; 74 | /******/ var script = document.createElement('script'); 75 | /******/ script.type = 'text/javascript'; 76 | /******/ script.charset = 'utf-8'; 77 | /******/ script.async = true; 78 | /******/ script.timeout = 120000; 79 | /******/ 80 | /******/ if (__webpack_require__.nc) { 81 | /******/ script.setAttribute("nonce", __webpack_require__.nc); 82 | /******/ } 83 | /******/ script.src = __webpack_require__.p + "" + chunkId + ".chunk.js"; 84 | /******/ var timeout = setTimeout(onScriptComplete, 120000); 85 | /******/ script.onerror = script.onload = onScriptComplete; 86 | /******/ function onScriptComplete() { 87 | /******/ // avoid mem leaks in IE. 88 | /******/ script.onerror = script.onload = null; 89 | /******/ clearTimeout(timeout); 90 | /******/ var chunk = installedChunks[chunkId]; 91 | /******/ if(chunk !== 0) { 92 | /******/ if(chunk) chunk[1](new Error('Loading chunk ' + chunkId + ' failed.')); 93 | /******/ installedChunks[chunkId] = undefined; 94 | /******/ } 95 | /******/ }; 96 | /******/ 97 | /******/ var promise = new Promise(function(resolve, reject) { 98 | /******/ installedChunks[chunkId] = [resolve, reject]; 99 | /******/ }); 100 | /******/ installedChunks[chunkId][2] = promise; 101 | /******/ 102 | /******/ head.appendChild(script); 103 | /******/ return promise; 104 | /******/ }; 105 | /******/ 106 | /******/ // expose the modules object (__webpack_modules__) 107 | /******/ __webpack_require__.m = modules; 108 | /******/ 109 | /******/ // expose the module cache 110 | /******/ __webpack_require__.c = installedModules; 111 | /******/ 112 | /******/ // identity function for calling harmony imports with the correct context 113 | /******/ __webpack_require__.i = function(value) { return value; }; 114 | /******/ 115 | /******/ // define getter function for harmony exports 116 | /******/ __webpack_require__.d = function(exports, name, getter) { 117 | /******/ if(!__webpack_require__.o(exports, name)) { 118 | /******/ Object.defineProperty(exports, name, { 119 | /******/ configurable: false, 120 | /******/ enumerable: true, 121 | /******/ get: getter 122 | /******/ }); 123 | /******/ } 124 | /******/ }; 125 | /******/ 126 | /******/ // getDefaultExport function for compatibility with non-harmony modules 127 | /******/ __webpack_require__.n = function(module) { 128 | /******/ var getter = module && module.__esModule ? 129 | /******/ function getDefault() { return module['default']; } : 130 | /******/ function getModuleExports() { return module; }; 131 | /******/ __webpack_require__.d(getter, 'a', getter); 132 | /******/ return getter; 133 | /******/ }; 134 | /******/ 135 | /******/ // Object.prototype.hasOwnProperty.call 136 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 137 | /******/ 138 | /******/ // __webpack_public_path__ 139 | /******/ __webpack_require__.p = ""; 140 | /******/ 141 | /******/ // on error function for async loading 142 | /******/ __webpack_require__.oe = function(err) { console.error(err); throw err; }; 143 | /******/ }) 144 | /************************************************************************/ 145 | /******/ ([]); 146 | //# sourceMappingURL=inline.bundle.js.map -------------------------------------------------------------------------------- /src/dotnetGigs/wwwroot/inline.bundle.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///webpack/bootstrap 484ec6dbef87b51d5f58"],"names":[],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAQ,oBAAoB;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAY,2BAA2B;AACvC;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,YAAI;AACJ;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA,mDAA2C,cAAc;;AAEzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA,kDAA0C,oBAAoB,WAAW","file":"inline.bundle.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, resolves = [], result;\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId])\n \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);\n \t\twhile(resolves.length)\n \t\t\tresolves.shift()();\n \t\tif(executeModules) {\n \t\t\tfor(i=0; i < executeModules.length; i++) {\n \t\t\t\tresult = __webpack_require__(__webpack_require__.s = executeModules[i]);\n \t\t\t}\n \t\t}\n \t\treturn result;\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// objects to store loaded and loading chunks\n \tvar installedChunks = {\n \t\t5: 0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n \t// This file contains only the entry chunk.\n \t// The chunk loading function for additional chunks\n \t__webpack_require__.e = function requireEnsure(chunkId) {\n \t\tif(installedChunks[chunkId] === 0)\n \t\t\treturn Promise.resolve();\n\n \t\t// an Promise means \"currently loading\".\n \t\tif(installedChunks[chunkId]) {\n \t\t\treturn installedChunks[chunkId][2];\n \t\t}\n \t\t// start chunk loading\n \t\tvar head = document.getElementsByTagName('head')[0];\n \t\tvar script = document.createElement('script');\n \t\tscript.type = 'text/javascript';\n \t\tscript.charset = 'utf-8';\n \t\tscript.async = true;\n \t\tscript.timeout = 120000;\n\n \t\tif (__webpack_require__.nc) {\n \t\t\tscript.setAttribute(\"nonce\", __webpack_require__.nc);\n \t\t}\n \t\tscript.src = __webpack_require__.p + \"\" + chunkId + \".chunk.js\";\n \t\tvar timeout = setTimeout(onScriptComplete, 120000);\n \t\tscript.onerror = script.onload = onScriptComplete;\n \t\tfunction onScriptComplete() {\n \t\t\t// avoid mem leaks in IE.\n \t\t\tscript.onerror = script.onload = null;\n \t\t\tclearTimeout(timeout);\n \t\t\tvar chunk = installedChunks[chunkId];\n \t\t\tif(chunk !== 0) {\n \t\t\t\tif(chunk) chunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));\n \t\t\t\tinstalledChunks[chunkId] = undefined;\n \t\t\t}\n \t\t};\n\n \t\tvar promise = new Promise(function(resolve, reject) {\n \t\t\tinstalledChunks[chunkId] = [resolve, reject];\n \t\t});\n \t\tinstalledChunks[chunkId][2] = promise;\n\n \t\thead.appendChild(script);\n \t\treturn promise;\n \t};\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// on error function for async loading\n \t__webpack_require__.oe = function(err) { console.error(err); throw err; };\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 484ec6dbef87b51d5f58"],"sourceRoot":""} -------------------------------------------------------------------------------- /src/dotnetGigs/wwwroot/main.bundle.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///./src/app/shared/services/base.service.ts","webpack:///./src/app/rxjs-operators.js","webpack:///./src async","webpack:///./src/main.ts","webpack:///./src/app/account/account.routing.ts","webpack:///./src/app/app.component.ts","webpack:///./src/app/app.module.ts","webpack:///./src/app/app.routing.ts","webpack:///./src/app/authenticate-xhr.backend.ts","webpack:///./src/app/dashboard/dashboard.module.ts","webpack:///./src/app/dashboard/dashboard.routing.ts","webpack:///./src/app/directives/email.validator.directive.ts","webpack:///./src/app/directives/focus.directive.ts","webpack:///./src/app/header/header.component.ts","webpack:///./src/app/spinner/spinner.component.ts","webpack:///./src/environments/environment.ts","webpack:///./src/app/account/login-form/login-form.component.scss","webpack:///./src/app/account/registration-form/registration-form.component.scss","webpack:///./src/app/app.component.scss","webpack:///./src/app/dashboard/home/home.component.scss","webpack:///./src/app/dashboard/root/root.component.scss","webpack:///./src/app/header/header.component.scss","webpack:///./src/app/home/home.component.scss","webpack:///./src/app/spinner/spinner.component.scss","webpack:///./src/app/account/login-form/login-form.component.html","webpack:///./src/app/account/registration-form/registration-form.component.html","webpack:///./src/app/app.component.html","webpack:///./src/app/dashboard/home/home.component.html","webpack:///./src/app/dashboard/root/root.component.html","webpack:///./src/app/header/header.component.html","webpack:///./src/app/home/home.component.html","webpack:///./src/app/spinner/spinner.component.html","webpack:///./src/app/shared/services/user.service.ts","webpack:///./src/app/shared/utils/config.service.ts","webpack:///./src/app/account/account.module.ts","webpack:///./src/app/account/login-form/login-form.component.ts","webpack:///./src/app/account/registration-form/registration-form.component.ts","webpack:///./src/app/auth.guard.ts","webpack:///./src/app/dashboard/home/home.component.ts","webpack:///./src/app/dashboard/root/root.component.ts","webpack:///./src/app/dashboard/services/dashboard.service.ts","webpack:///./src/app/home/home.component.ts","webpack:///./src/app/shared/modules/shared.module.ts"],"names":[],"mappings":";;;;;;;;;AAAqC;AAGrC;IAEI;IAAgB,CAAC;IAEP,iCAAW,GAArB,UAAsB,KAAU;QAChC,IAAI,gBAAgB,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QAE9D,2DAA2D;QAC3D,EAAE,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;YACrB,MAAM,CAAC,mDAAU,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAC5C,CAAC;QAED,IAAI,gBAAgB,GAAW,EAAE,CAAC;QAClC,IAAI,WAAW,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAE/B,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;YACtB,GAAG,CAAC,CAAC,IAAI,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC;gBAC5B,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;oBACnB,gBAAgB,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YAChD,CAAC;QACH,CAAC;QAED,gBAAgB,GAAG,gBAAgB,GAAG,EAAE,GAAG,IAAI,GAAG,gBAAgB,CAAC;QACnE,MAAM,CAAC,mDAAU,CAAC,KAAK,CAAC,gBAAgB,IAAI,cAAc,CAAC,CAAC;IAC9D,CAAC;IACH,kBAAC;AAAD,CAAC;;;;;;;;;;;;;;;;;;;;;;AC5BD;AAAA;AAAA,oBAAoB;;AAEpB;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;;;;;;;ACbA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB;AACpB;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;AChB+C;AAC4B;AAE9B;AACY;AAEzD,EAAE,CAAC,CAAC,8EAAW,CAAC,UAAU,CAAC,CAAC,CAAC;IAC3B,4FAAc,EAAE,CAAC;AACnB,CAAC;AAED,wHAAsB,EAAE,CAAC,eAAe,CAAC,kEAAS,CAAC,CAAC;;;;;;;;;;;;;ACTE;AAEyC;AACrB;AAEnE,IAAM,OAAO,GAAwB,qEAAY,CAAC,QAAQ,CAAC;IAChE,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,iHAAyB,EAAC;IACzD,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,4FAAkB,EAAC;CAChD,CAAC,CAAC;;;;;;;;;;;;;;;;;ACTyD;AAQ5D,IAAa,YAAY;IANzB;QAOE,UAAK,GAAG,YAAY,CAAC;IACvB,CAAC;IAAD,mBAAC;AAAD,CAAC;AAFY,YAAY;IANxB,uFAAS,CAAC;QACT,QAAQ,EAAE,UAAU;QACpB,aAAa,EAAE,yEAAiB,CAAC,IAAI;QACrC,kCAAmC;QACnC,kCAAmC;KACpC,CAAC;GACW,YAAY,CAExB;AAFwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACRiC;AACjB;AACI;AACU;AACa;AAE5B;AAExC,cAAc;AACiC;AACa;AACN;AAEtD,qBAAqB;AACqC;AAC1D,uBAAuB;AACyC;AAEF;AAuB9D,IAAa,SAAS;IAAtB;IAAyB,CAAC;IAAD,gBAAC;AAAD,CAAC;AAAb,SAAS;IApBrB,sFAAQ,CAAC;QACR,YAAY,EAAE;YACZ,oEAAY;YACZ,iFAAe;YACf,2EAAa;SACd;QACD,OAAO,EAAE;YACP,sEAAa;YACb,qFAAe;YACf,gFAAa;YACb,mEAAW;YACX,iEAAU;YACV,6DAAO;SACR;QACD,SAAS,EAAE,CAAC,oFAAa,EAAE;gBACzB,OAAO,EAAE,iEAAU;gBACnB,QAAQ,EAAE,yFAAsB;aACjC,CAAC;QACF,SAAS,EAAE,CAAC,oEAAY,CAAC;KAC1B,CAAC;GACW,SAAS,CAAI;AAAJ;;;;;;;;;;;;ACxCiC;AAEA;AAEvD,IAAM,SAAS,GAAW;IACxB,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,2EAAa,EAAE;IACtC,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,0CAA0C,EAAE;CAC9E,CAAC;AAEK,IAAM,OAAO,GAAwB,qEAAY,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACV6B;AAC5D;AACZ;AACE;AACQ;AAE3C,yFAAyF;AACzF,oFAAoF;AAGpF,IAAa,sBAAsB;IAAS,0CAAU;IAElD,gCAAY,WAAuB,EAAE,oBAAqC,EAAE,aAA2B;eACnG,kBAAM,WAAW,EAAE,oBAAoB,EAAE,aAAa,CAAC;IAC3D,CAAC;IAED,iDAAgB,GAAhB,UAAiB,OAAgB;QAC7B,IAAI,aAAa,GAAG,iBAAM,gBAAgB,YAAC,OAAO,CAAC,CAAC;QACpD,aAAa,CAAC,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAC,KAAe;YAClE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;gBAEzG,OAAO,CAAC,GAAG,CAAC,sGAAsG,CAAC,CAAC;gBACpH;;;;wHAIwG;gBACxG,YAAY,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;gBACtC,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,eAAe,EAAE,CAAC;YACrF,CAAC;YACD,MAAM,CAAC,2DAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,aAAa,CAAC;IACzB,CAAC;IACL,6BAAC;AAAD,CAAC,CAxB2C,iEAAU,GAwBrD;AAxBY,sBAAsB;IADlC,wFAAU,EAAE;yDAGgB,iEAAU,oBAAV,iEAAU,sDAAwB,sEAAe,oBAAf,sEAAe,sDAAiB,mEAAY,oBAAZ,mEAAY;GAF9F,sBAAsB,CAwBlC;AAxBkC;;;;;;;;;;;;;;;;;;;;;;;;;;ACVgB;AACE;AACD;AACiB;AAEtB;AACO;AACA;AACU;AAEtB;AAY1C,IAAa,eAAe;IAA5B;IAA+B,CAAC;IAAD,sBAAC;AAAD,CAAC;AAAnB,eAAe;IAV3B,sFAAQ,CAAC;QACR,OAAO,EAAO;YACZ,qEAAY;YACZ,mEAAW;YACX,mEAAO;YACP,mFAAY;SAAC;QACf,YAAY,EAAE,CAAC,2EAAa,EAAC,2EAAa,CAAC;QAC3C,OAAO,EAAO,EAAG;QACjB,SAAS,EAAK,CAAC,8DAAS,EAAC,qFAAgB,CAAC;KAC3C,CAAC;GACW,eAAe,CAAI;AAAJ;;;;;;;;;;;;;;ACrB0B;AAEG;AACA;AAEf;AAEnC,IAAM,OAAO,GAAwB,qEAAY,CAAC,QAAQ,CAAC;IAChE;QACI,IAAI,EAAE,WAAW;QACjB,SAAS,EAAE,2EAAa,EAAE,WAAW,EAAE,CAAC,8DAAS,CAAC;QAElD,QAAQ,EAAE;YACT,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,2EAAa,EAAE;YACtC,EAAE,IAAI,EAAE,MAAM,EAAG,SAAS,EAAE,2EAAa,EAAE;SAC3C;KACF;CACJ,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;AClBmD;AACM;AAE5D;IACE,MAAM,CAAC,UAAC,CAAc;QACpB,IAAI,YAAY,GAAG,mGAAmG,CAAC;QAEvH,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG;YACzC,aAAa,EAAE;gBACb,KAAK,EAAE,KAAK;aACb;SACF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAQD,IAAa,cAAc;IAIzB;QACE,IAAI,CAAC,SAAS,GAAG,oBAAoB,EAAE,CAAC;IAC1C,CAAC;IAED,iCAAQ,GAAR,UAAS,CAAc;QACrB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;IACH,qBAAC;AAAD,CAAC;AAXY,cAAc;IAN1B,uFAAS,CAAC;QACT,QAAQ,EAAE,uDAAuD;QACjE,SAAS,EAAE;YACT,EAAE,OAAO,EAAE,qEAAa,EAAE,WAAW,EAAE,wFAAU,CAAC,cAAM,uBAAc,EAAd,CAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;SACvF;KACF,CAAC;;GACW,cAAc,CAW1B;AAX0B;;;;;;;;;;;;;;;;;;;;;ACrB6C;AAIxE,IAAa,OAAO;IAChB,iBAAoB,EAAc,EAAU,QAAkB;QAA1C,OAAE,GAAF,EAAE,CAAY;QAAU,aAAQ,GAAR,QAAQ,CAAU;QAC1D,oDAAoD;IACxD,CAAC;IAED,0BAAQ,GAAR;QACI,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IAC1E,CAAC;IACL,cAAC;AAAD,CAAC;AARY,OAAO;IAFnB,uFAAS,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;yDAGT,iEAAU,oBAAV,iEAAU,sDAAoB,+DAAQ,oBAAR,+DAAQ;GADrD,OAAO,CAQnB;AARmB;;;;;;;;;;;;;;;;;;;;;;ACJwC;AAGE;AAO9D,IAAa,eAAe;IAK1B,yBAAoB,WAAuB;QAAvB,gBAAW,GAAX,WAAW,CAAY;IAC1C,CAAC;IAED,gCAAM,GAAN;QACE,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;IAC7B,CAAC;IAED,kCAAQ,GAAR;QAAA,iBAEC;QADC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,SAAS,CAAC,gBAAM,IAAI,YAAI,CAAC,MAAM,GAAG,MAAM,EAApB,CAAoB,CAAC,CAAC;IAChG,CAAC;IAEA,qCAAW,GAAX;QACC,kDAAkD;QAClD,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;IAClC,CAAC;IACH,sBAAC;AAAD,CAAC;AApBY,eAAe;IAL3B,uFAAS,CAAC;QACT,QAAQ,EAAE,YAAY;QACtB,kCAAsC;QACtC,kCAAsC;KACvC,CAAC;yDAMgC,kFAAW,oBAAX,kFAAW;GALhC,eAAe,CAoB3B;AApB2B;;;;;;;;;;;;;;;;;;;;;ACVgC;AAS5D,IAAa,gBAAgB;IAP7B;QASY,qBAAgB,GAAY,KAAK,CAAC;QAGnC,UAAK,GAAW,GAAG,CAAC;IA6B/B;IA1BI,sBAAW,uCAAS;aAApB,UAAqB,KAAc;YADnC,iBAiBC;YAfG,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;gBACT,IAAI,CAAC,aAAa,EAAE,CAAC;gBACrB,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;gBAC9B,MAAM,CAAC;YACX,CAAC;YAED,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;gBACtB,MAAM,CAAC;YACX,CAAC;YAED,4GAA4G;YAC5G,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC;gBACpC,KAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;gBAC9B,KAAI,CAAC,aAAa,EAAE,CAAC;YACzB,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;;;OAAA;IAEO,wCAAa,GAArB;QACI,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAClC,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;IACpC,CAAC;IAED,sCAAW,GAAX;QACI,IAAI,CAAC,aAAa,EAAE,CAAC;IACzB,CAAC;IACL;AAAA;AA7BI;IADC,mFAAK,EAAE;;+CACmB;AAG3B;IADC,mFAAK,EAAE;;;iDAiBP;AAxBQ,gBAAgB;IAP5B,uFAAS,CAAC;QACT,QAAQ,EAAE,aAAa;QACvB,kCAAuC;QACvC,kCAAuC;KACxC,CAAC;GAGW,gBAAgB,CAkC7B;AAlC6B;;;;;;;;;ACT7B;AAAA,mFAAmF;AACnF,8FAA8F;AAC9F,yEAAyE;AACzE,gFAAgF;AAEhF,mFALmF;AAK5E,IAAM,WAAW,GAAG;IACzB,UAAU,EAAE,KAAK;CAClB,CAAC;;;;;;;;ACPF;AACA;;;AAGA;AACA;;AAEA;;;AAGA;AACA,2C;;;;;;;ACXA;AACA;;;AAGA;AACA;;AAEA;;;AAGA;AACA,2C;;;;;;;ACXA;AACA;;;AAGA;AACA,+BAAgC,sBAAsB,8BAA8B,EAAE,sBAAsB,0BAA0B,2BAA2B,qBAAqB,sBAAsB,uBAAuB,EAAE,WAAW,8CAA8C,uBAAuB,2BAA2B,2BAA2B,uBAAuB,EAAE,iBAAiB,yBAAyB,uBAAuB,EAAE,eAAe,qBAAqB,EAAE;;AAE7e;;;AAGA;AACA,2C;;;;;;;ACXA;AACA;;;AAGA;AACA;;AAEA;;;AAGA;AACA,2C;;;;;;;ACXA;AACA;;;AAGA;AACA;;AAEA;;;AAGA;AACA,2C;;;;;;;ACXA;AACA;;;AAGA;AACA;;AAEA;;;AAGA;AACA,2C;;;;;;;ACXA;AACA;;;AAGA;AACA;;AAEA;;;AAGA;AACA,2C;;;;;;;ACXA;AACA;;;AAGA;AACA,mCAAoC,gBAAgB,iBAAiB,uBAAuB,sBAAsB,EAAE,sCAAsC,gBAAgB,iBAAiB,uBAAuB,2BAA2B,iBAAiB,uBAAuB,WAAW,YAAY,2DAA2D,mDAAmD,EAAE,qBAAqB,mCAAmC,2BAA2B,EAAE,kCAAkC,cAAc,kCAAkC,EAAE,SAAS,kCAAkC,EAAE,EAAE,0BAA0B,cAAc,0BAA0B,kCAAkC,EAAE,SAAS,0BAA0B,kCAAkC,EAAE,EAAE;;AAEnyB;;;AAGA;AACA,2C;;;;;;;ACXA,u8CAAu8C,QAAQ,0E;;;;;;;ACA/8C,glEAAglE,QAAQ,4E;;;;;;;ACAxlE,2M;;;;;;;ACAA,2GAA2G,sBAAsB,2B;;;;;;;ACAjI,qgB;;;;;;;ACAA,+vC;;;;;;;ACAA,+b;;;;;;;ACAA,wK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACA2C;AAC6B;AAGhB;AAEb;AAGD;AAE1C,8BAA8B;AAE9B,yDAAyD;AAC3B;AAI9B,IAAa,WAAW;IAAS,+BAAW;IAW1C,qBAAoB,IAAU,EAAU,aAA4B;QAApE,YACE,iBAAO,SAMR;QAPmB,UAAI,GAAJ,IAAI,CAAM;QAAU,mBAAa,GAAb,aAAa,CAAe;QATpE,aAAO,GAAW,EAAE,CAAC;QAErB,4BAA4B;QACpB,0BAAoB,GAAG,IAAI,wDAAe,CAAU,KAAK,CAAC,CAAC;QACnE,4BAA4B;QAC5B,oBAAc,GAAG,KAAI,CAAC,oBAAoB,CAAC,YAAY,EAAE,CAAC;QAElD,cAAQ,GAAG,KAAK,CAAC;QAIvB,KAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACrD,mIAAmI;QACnI,4GAA4G;QAC5G,KAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAI,CAAC,QAAQ,CAAC,CAAC;QAC9C,KAAI,CAAC,OAAO,GAAG,aAAa,CAAC,SAAS,EAAE,CAAC;;IAC3C,CAAC;IAEC,8BAAQ,GAAR,UAAS,KAAa,EAAE,QAAgB,EAAE,SAAiB,EAAE,QAAgB,EAAC,QAAgB;QAC9F,IAAI,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,SAAE,QAAQ,YAAE,SAAS,aAAE,QAAQ,YAAC,QAAQ,YAAE,CAAC,CAAC;QAC7E,IAAI,OAAO,GAAG,IAAI,8DAAO,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAClE,IAAI,OAAO,GAAG,IAAI,qEAAc,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAEvD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC;aAC7D,GAAG,CAAC,aAAG,IAAI,WAAI,EAAJ,CAAI,CAAC;aAChB,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC7B,CAAC;IAEA,2BAAK,GAAL,UAAM,QAAQ,EAAE,QAAQ;QAAxB,iBAiBA;QAhBC,IAAI,OAAO,GAAG,IAAI,8DAAO,EAAE,CAAC;QAC5B,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;QAEnD,MAAM,CAAC,IAAI,CAAC,IAAI;aACb,IAAI,CACL,IAAI,CAAC,OAAO,GAAG,aAAa,EAC5B,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,YAAE,QAAQ,YAAE,CAAC,EAAC,EAAE,OAAO,WAAE,CACjD;aACA,GAAG,CAAC,aAAG,IAAI,UAAG,CAAC,IAAI,EAAE,EAAV,CAAU,CAAC;aACtB,GAAG,CAAC,aAAG;YACN,YAAY,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;YACnD,KAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrB,KAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrC,MAAM,CAAC,IAAI,CAAC;QACd,CAAC,CAAC;aACD,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC7B,CAAC;IAED,4BAAM,GAAN;QACE,YAAY,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QACtC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC;IAED,gCAAU,GAAV;QACE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IACH,kBAAC;AAAD,CAAC,CA1DgC,kEAAW,GA0D3C;AA1DY,WAAW;IAFvB,wFAAU,EAAE;yDAae,2DAAI,oBAAJ,2DAAI,sDAAyB,4EAAa,oBAAb,4EAAa;GAXzD,WAAW,CA0DvB;AA1DuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClBmB;AAG3C,IAAa,aAAa;IAItB;QACI,IAAI,CAAC,OAAO,GAAG,2BAA2B,CAAC;IAC9C,CAAC;IAED,iCAAS,GAAT;QACI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;IACN,oBAAC;AAAD,CAAC;AAXY,aAAa;IADzB,wFAAU,EAAE;;GACA,aAAa,CAWzB;AAXyB;;;;;;;;;;;;;;;;;;;;;;;;;;ACHe;AACM;AACD;AACuB;AAEN;AAEU;AAE5B;AACiD;AACvB;AASvE,IAAa,aAAa;IAA1B;IAA6B,CAAC;IAAD,oBAAC;AAAD,CAAC;AAAjB,aAAa;IAPzB,sFAAQ,CAAC;QACR,OAAO,EAAE;YACP,qEAAY,EAAC,mEAAW,EAAC,iEAAO,EAAC,mFAAY;SAC9C;QACD,YAAY,EAAE,CAAC,iHAAyB,EAAC,6FAAc,EAAE,4FAAkB,CAAC;QAC5E,SAAS,EAAK,CAAE,kFAAW,CAAE;KAC9B,CAAC;GACW,aAAa,CAAI;AAAJ;;;;;;;;;;;;;;;;;;;;;;ACnBkC;AACH;AAGQ;AAOjE,IAAa,kBAAkB;IAU7B,4BAAoB,WAAwB,EAAU,MAAc,EAAS,cAA8B;QAAvF,gBAAW,GAAX,WAAW,CAAa;QAAU,WAAM,GAAN,MAAM,CAAQ;QAAS,mBAAc,GAAd,cAAc,CAAgB;QAH3G,cAAS,GAAY,KAAK,CAAC;QAC3B,gBAAW,GAAgB,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAEwD,CAAC;IAE9G,qCAAQ,GAAR;QAAA,iBAQD;QANC,4BAA4B;QAC5B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,SAAS,CAC3D,UAAC,KAAU;YACR,KAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC;YAClC,KAAI,CAAC,WAAW,CAAC,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACP,CAAC;IAEA,wCAAW,GAAX;QACC,uCAAuC;QACvC,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;IAClC,CAAC;IAED,kCAAK,GAAL,UAAM,EAAwD;QAA9D,iBAeC;YAfO,gBAAK,EAAE,gBAAK;QAClB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,MAAM,GAAC,EAAE,CAAC;QACf,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YACV,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC;iBAChD,OAAO,CAAC,cAAM,YAAI,CAAC,YAAY,GAAG,KAAK,EAAzB,CAAyB,CAAC;iBACxC,SAAS,CACV,gBAAM;gBACJ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;oBACV,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC;gBAC7C,CAAC;YACH,CAAC,EACD,eAAK,IAAI,YAAI,CAAC,MAAM,GAAG,KAAK,EAAnB,CAAmB,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IACH,yBAAC;AAAD,CAAC;AA3CY,kBAAkB;IAL9B,uFAAS,CAAC;QACT,QAAQ,EAAE,gBAAgB;QAC1B,kCAA0C;QAC1C,kCAA0C;KAC3C,CAAC;yDAWiC,kFAAW,oBAAX,kFAAW,sDAAkB,+DAAM,oBAAN,+DAAM,sDAAyB,uEAAc,oBAAd,uEAAc;GAVhG,kBAAkB,CA2C9B;AA3C8B;;;;;;;;;;;;;;;;;;;;;;;ACZmB;AACT;AAGwB;AAOjE,IAAa,yBAAyB;IAMrC,mCAAoB,WAAwB,EAAS,MAAc;QAA/C,gBAAW,GAAX,WAAW,CAAa;QAAS,WAAM,GAAN,MAAM,CAAQ;QAFnE,cAAS,GAAY,KAAK,CAAC;IAI3B,CAAC;IAEA,4CAAQ,GAAR;IAEA,CAAC;IAED,gDAAY,GAAZ,UAAa,EAA6D;QAA1E,iBAcC;YAdc,gBAAK,EAAE,gBAAK;QACxB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,MAAM,GAAC,EAAE,CAAC;QACf,EAAE,EAAC,KAAK,CAAC,CACT,CAAC;YACG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAC,KAAK,CAAC,QAAQ,EAAC,KAAK,CAAC,SAAS,EAAC,KAAK,CAAC,QAAQ,EAAC,KAAK,CAAC,QAAQ,CAAC;iBACxF,OAAO,CAAC,cAAM,YAAI,CAAC,YAAY,GAAG,KAAK,EAAzB,CAAyB,CAAC;iBACxC,SAAS,CACR,gBAAM;gBAAM,EAAE,EAAC,MAAM,CAAC,EAAC;oBACnB,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAC,EAAC,WAAW,EAAE,EAAC,QAAQ,EAAE,IAAI,EAAC,KAAK,EAAC,KAAK,CAAC,KAAK,EAAC,EAAC,CAAC,CAAC;gBACvF,CAAC;YAAA,CAAC,EACF,gBAAM,IAAK,YAAI,CAAC,MAAM,GAAG,MAAM,EAApB,CAAoB,CAAC,CAAC;QACjD,CAAC;IACJ,CAAC;IACH,gCAAC;AAAD,CAAC;AA7BY,yBAAyB;IALrC,uFAAS,CAAC;QACT,QAAQ,EAAE,uBAAuB;QACjC,kCAAiD;QACjD,kCAAiD;KAClD,CAAC;yDAOgC,kFAAW,oBAAX,kFAAW,sDAAiB,+DAAM,oBAAN,+DAAM;GANvD,yBAAyB,CA6BrC;AA7BqC;;;;;;;;;;;;;;;;;;;;;;;ACXtC,gBAAgB;AAC2B;AACW;AACO;AAG7D,IAAa,SAAS;IACpB,mBAAoB,IAAiB,EAAS,MAAc;QAAxC,SAAI,GAAJ,IAAI,CAAa;QAAS,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAEhE,+BAAW,GAAX;QAEE,EAAE,EAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAC3B,CAAC;YACE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;YACzC,MAAM,CAAC,KAAK,CAAC;QAChB,CAAC;QAED,MAAM,CAAC,IAAI,CAAC;IACd,CAAC;IACH,gBAAC;AAAD,CAAC;AAbY,SAAS;IADrB,wFAAU,EAAE;yDAEe,kFAAW,oBAAX,kFAAW,sDAAiB,+DAAM,oBAAN,+DAAM;GADjD,SAAS,CAarB;AAbqB;;;;;;;;;;;;;;;;;;;;;;ACN4B;AAGe;AAOjE,IAAa,aAAa;IAIxB,uBAAoB,gBAAkC;QAAlC,qBAAgB,GAAhB,gBAAgB,CAAkB;IAAI,CAAC;IAE3D,gCAAQ,GAAR;QAAA,iBAUC;QARC,IAAI,CAAC,gBAAgB,CAAC,cAAc,EAAE;aACnC,SAAS,CAAC,UAAC,WAAwB;YAClC,KAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QACjC,CAAC,EACD,eAAK;YACH,oDAAoD;QACtD,CAAC,CAAC,CAAC;IAEP,CAAC;IACH,oBAAC;AAAD,CAAC;AAjBY,aAAa;IALzB,uFAAS,CAAC;QACT,QAAQ,EAAE,UAAU;QACpB,kCAAoC;QACpC,kCAAoC;KACrC,CAAC;yDAKsC,qFAAgB,oBAAhB,qFAAgB;GAJ3C,aAAa,CAiBzB;AAjByB;;;;;;;;;;;;;;;;;;;;;ACVwB;AAOlD,IAAa,aAAa;IAExB;IAAgB,CAAC;IAEjB,gCAAQ,GAAR;IACA,CAAC;IAEH,oBAAC;AAAD,CAAC;AAPY,aAAa;IALzB,uFAAS,CAAC;QACT,QAAQ,EAAE,UAAU;QACpB,kCAAoC;QACpC,kCAAoC;KACrC,CAAC;;GACW,aAAa,CAOzB;AAPyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACPiB;AACa;AAGU;AAEH;AAI/D,8BAA8B;AAE9B,yDAAyD;AAC3B;AAI9B,IAAa,gBAAgB;IAAS,oCAAW;IAI/C,0BAAoB,IAAU,EAAU,aAA4B;QAApE,YACG,iBAAO,SAET;QAHmB,UAAI,GAAJ,IAAI,CAAM;QAAU,mBAAa,GAAb,aAAa,CAAe;QAFpE,aAAO,GAAW,EAAE,CAAC;QAIlB,KAAI,CAAC,OAAO,GAAG,aAAa,CAAC,SAAS,EAAE,CAAC;;IAC5C,CAAC;IAED,yCAAc,GAAd;QACI,IAAI,OAAO,GAAG,IAAI,8DAAO,EAAE,CAAC;QAC5B,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;QACnD,IAAI,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACnD,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,YAAU,SAAW,CAAC,CAAC;QAEzD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,iBAAiB,EAAC,EAAC,OAAO,WAAC,CAAC;aAC7D,GAAG,CAAC,kBAAQ,IAAI,eAAQ,CAAC,IAAI,EAAE,EAAf,CAAe,CAAC;aAChC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC7B,CAAC;IACH,uBAAC;AAAD,CAAC,CAnBqC,kFAAW,GAmBhD;AAnBY,gBAAgB;IAF5B,wFAAU,EAAE;yDAMe,2DAAI,oBAAJ,2DAAI,sDAAyB,mFAAa,oBAAb,mFAAa;GAJzD,gBAAgB,CAmB5B;AAnB4B;;;;;;;;;;;;;;;;;;;;;ACjBqB;AAOlD,IAAa,aAAa;IAExB;IAAgB,CAAC;IAEjB,gCAAQ,GAAR;IACA,CAAC;IAEH,oBAAC;AAAD,CAAC;AAPY,aAAa;IALzB,uFAAS,CAAC;QACT,QAAQ,EAAE,UAAU;QACpB,kCAAoC;QACpC,kCAAoC;KACrC,CAAC;;GACW,aAAa,CAOzB;AAPyB;;;;;;;;;;;;;ACP1B;AAAA,yFAAyF;AACzF,wCAAwC;AACxC,8IAA8I;AAC9I,oDAAoD;;;;;;;AAED;AACE;AAEM;AACM;AASjE,IAAa,YAAY;IAAzB;IAA4B,CAAC;IAAD,mBAAC;AAAD,CAAC;AAAhB,YAAY;IANxB,sFAAQ,CAAC;QACR,OAAO,EAAO,CAAC,qEAAY,CAAC;QAC5B,YAAY,EAAE,CAAC,4EAAO,EAAC,oFAAgB,CAAC;QACxC,OAAO,EAAO,CAAC,4EAAO,EAAC,oFAAgB,CAAC;QACxC,SAAS,EAAK,EAAE;KACjB,CAAC;GACW,YAAY,CAAI;AAAJ","file":"main.bundle.js","sourcesContent":["import { Observable } from 'rxjs/Rx';\r\n\r\n\r\nexport abstract class BaseService { \r\n \r\n constructor() { }\r\n\r\n protected handleError(error: any) {\r\n var applicationError = error.headers.get('Application-Error');\r\n\r\n // either applicationError in header or model error in body\r\n if (applicationError) {\r\n return Observable.throw(applicationError);\r\n }\r\n\r\n var modelStateErrors: string = '';\r\n var serverError = error.json();\r\n\r\n if (!serverError.type) {\r\n for (var key in serverError) {\r\n if (serverError[key])\r\n modelStateErrors += serverError[key] + '\\n';\r\n }\r\n }\r\n\r\n modelStateErrors = modelStateErrors = '' ? null : modelStateErrors;\r\n return Observable.throw(modelStateErrors || 'Server error');\r\n }\r\n}\n\n\n// WEBPACK FOOTER //\n// ./src/app/shared/services/base.service.ts","// import 'rxjs/Rx'; // adds ALL RxJS statics & operators to Observable\r\n\r\n// See node_module/rxjs/Rxjs.js\r\n// Import just the rxjs statics and operators we need for THIS app.\r\n\r\n// Statics\r\nimport 'rxjs/add/observable/throw';\r\n\r\n// Operators\r\nimport 'rxjs/add/operator/catch';\r\nimport 'rxjs/add/operator/debounceTime';\r\nimport 'rxjs/add/operator/distinctUntilChanged';\r\nimport 'rxjs/add/operator/map';\r\nimport 'rxjs/add/operator/switchMap';\r\nimport 'rxjs/add/operator/toPromise';\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/rxjs-operators.js\n// module id = 155\n// module chunks = 1","var map = {\n\t\"app/account/account.module\": [\n\t\t91\n\t]\n};\nfunction webpackAsyncContext(req) {\n\tvar ids = map[req];\tif(!ids)\n\t\treturn Promise.reject(new Error(\"Cannot find module '\" + req + \"'.\"));\n\treturn Promise.all(ids.slice(1).map(__webpack_require__.e)).then(function() {\n\t\treturn __webpack_require__(ids[0]);\n\t});\n};\nwebpackAsyncContext.keys = function webpackAsyncContextKeys() {\n\treturn Object.keys(map);\n};\nmodule.exports = webpackAsyncContext;\nwebpackAsyncContext.id = 157;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src async\n// module id = 157\n// module chunks = 1","import { enableProdMode } from '@angular/core';\nimport { platformBrowserDynamic } from '@angular/platform-browser-dynamic';\n\nimport { AppModule } from './app/app.module';\nimport { environment } from './environments/environment';\n\nif (environment.production) {\n enableProdMode();\n}\n\nplatformBrowserDynamic().bootstrapModule(AppModule);\n\n\n\n// WEBPACK FOOTER //\n// ./src/main.ts","import { ModuleWithProviders } from '@angular/core';\r\nimport { RouterModule } from '@angular/router';\r\n\r\nimport { RegistrationFormComponent } from './registration-form/registration-form.component';\r\nimport { LoginFormComponent } from './login-form/login-form.component';\r\n\r\nexport const routing: ModuleWithProviders = RouterModule.forChild([\r\n { path: 'register', component: RegistrationFormComponent},\r\n { path: 'login', component: LoginFormComponent}\r\n]);\r\n\r\n \n\n\n// WEBPACK FOOTER //\n// ./src/app/account/account.routing.ts","import { Component,ViewEncapsulation } from '@angular/core';\n\n@Component({\n selector: 'app-root',\n encapsulation: ViewEncapsulation.None,\n templateUrl: './app.component.html',\n styleUrls: ['./app.component.scss']\n})\nexport class AppComponent {\n title = 'app works!';\n}\n\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/app.component.ts","import { BrowserModule } from '@angular/platform-browser';\nimport { NgModule } from '@angular/core';\nimport { FormsModule } from '@angular/forms'; \nimport { HttpModule, XHRBackend } from '@angular/http';\nimport { AuthenticateXHRBackend } from './authenticate-xhr.backend';\n\nimport { routing } from './app.routing';\n\n/* App Root */\nimport { AppComponent } from './app.component';\nimport { HeaderComponent } from './header/header.component';\nimport { HomeComponent } from './home/home.component';\n\n/* Account Imports */\nimport { AccountModule } from './account/account.module';\n/* Dashboard Imports */\nimport { DashboardModule } from './dashboard/dashboard.module';\n\nimport { ConfigService } from './shared/utils/config.service';\n\n\n@NgModule({\n declarations: [\n AppComponent,\n HeaderComponent,\n HomeComponent\n ],\n imports: [\n AccountModule,\n DashboardModule,\n BrowserModule,\n FormsModule,\n HttpModule,\n routing\n ],\n providers: [ConfigService, { \n provide: XHRBackend, \n useClass: AuthenticateXHRBackend\n }],\n bootstrap: [AppComponent]\n})\nexport class AppModule { }\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/app.module.ts","import { ModuleWithProviders } from '@angular/core';\r\nimport { Routes, RouterModule } from '@angular/router';\r\n\r\nimport { HomeComponent } from './home/home.component';\r\n\r\nconst appRoutes: Routes = [\r\n { path: '', component: HomeComponent },\r\n { path: 'account', loadChildren: 'app/account/account.module#AccountModule' }\r\n];\r\n\r\nexport const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);\n\n\n// WEBPACK FOOTER //\n// ./src/app/app.routing.ts","import { Request, XHRBackend, BrowserXhr, ResponseOptions, XSRFStrategy, Response } from '@angular/http';\r\nimport { Observable } from 'rxjs/Observable';\r\nimport 'rxjs/add/operator/catch';\r\nimport 'rxjs/add/observable/throw';\r\nimport { Injectable } from '@angular/core';\r\n\r\n// sweet global way to handle 401s - works in tandem with existing AuthGuard route checks\r\n// http://stackoverflow.com/questions/34934009/handling-401s-globally-with-angular-2\r\n\r\n@Injectable()\r\nexport class AuthenticateXHRBackend extends XHRBackend {\r\n\r\n constructor(_browserXhr: BrowserXhr, _baseResponseOptions: ResponseOptions, _xsrfStrategy: XSRFStrategy) {\r\n super(_browserXhr, _baseResponseOptions, _xsrfStrategy);\r\n }\r\n\r\n createConnection(request: Request) {\r\n let xhrConnection = super.createConnection(request);\r\n xhrConnection.response = xhrConnection.response.catch((error: Response) => {\r\n if ((error.status === 401 || error.status === 403) && (window.location.href.match(/\\?/g) || []).length < 2) {\r\n \r\n console.log('The authentication session expired or the user is not authorized. Force refresh of the current page.');\r\n /* Great solution for bundling with Auth Guard! \r\n 1. Auth Guard checks authorized user (e.g. by looking into LocalStorage). \r\n 2. On 401/403 response you clean authorized user for the Guard (e.g. by removing coresponding parameters in LocalStorage). \r\n 3. As at this early stage you can't access the Router for forwarding to the login page,\r\n 4. refreshing the same page will trigger the Guard checks, which will forward you to the login screen */\r\n localStorage.removeItem('auth_token'); \r\n window.location.href = window.location.href + '?' + new Date().getMilliseconds(); \r\n }\r\n return Observable.throw(error);\r\n });\r\n return xhrConnection;\r\n }\r\n}\n\n\n// WEBPACK FOOTER //\n// ./src/app/authenticate-xhr.backend.ts","import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { SharedModule } from '../shared/modules/shared.module';\n\nimport { routing } from './dashboard.routing';\nimport { RootComponent } from './root/root.component';\nimport { HomeComponent } from './home/home.component';\nimport { DashboardService } from './services/dashboard.service';\n\nimport { AuthGuard } from '../auth.guard';\n\n@NgModule({\n imports: [\n CommonModule, \n FormsModule,\n routing,\n SharedModule],\n declarations: [RootComponent,HomeComponent],\n exports: [ ],\n providers: [AuthGuard,DashboardService]\n})\nexport class DashboardModule { }\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/dashboard/dashboard.module.ts","import { ModuleWithProviders } from '@angular/core';\r\nimport { RouterModule } from '@angular/router';\r\n\r\nimport { RootComponent } from './root/root.component';\r\nimport { HomeComponent } from './home/home.component'; \r\n\r\nimport { AuthGuard } from '../auth.guard';\r\n\r\nexport const routing: ModuleWithProviders = RouterModule.forChild([\r\n {\r\n path: 'dashboard',\r\n component: RootComponent, canActivate: [AuthGuard],\r\n\r\n children: [ \r\n { path: '', component: HomeComponent },\r\n { path: 'home', component: HomeComponent },\r\n ] \r\n } \r\n]);\r\n\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/dashboard/dashboard.routing.ts","import { Directive, forwardRef } from '@angular/core';\r\nimport { NG_VALIDATORS, FormControl } from '@angular/forms';\r\n\r\nfunction validateEmailFactory() {\r\n return (c: FormControl) => {\r\n let EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;\r\n\r\n return EMAIL_REGEXP.test(c.value) ? null : {\r\n validateEmail: {\r\n valid: false\r\n }\r\n };\r\n };\r\n}\r\n\r\n@Directive({\r\n selector: '[validateEmail][ngModel],[validateEmail][formControl]',\r\n providers: [\r\n { provide: NG_VALIDATORS, useExisting: forwardRef(() => EmailValidator), multi: true }\r\n ]\r\n})\r\nexport class EmailValidator {\r\n\r\n validator: Function;\r\n\r\n constructor() {\r\n this.validator = validateEmailFactory();\r\n }\r\n\r\n validate(c: FormControl) {\r\n return this.validator(c);\r\n }\r\n}\n\n\n// WEBPACK FOOTER //\n// ./src/app/directives/email.validator.directive.ts","import { Directive, ElementRef, Renderer, OnInit } from \"@angular/core\";\r\n\r\n@Directive({ selector: '[tmFocus]' })\r\n\r\nexport class myFocus implements OnInit {\r\n constructor(private el: ElementRef, private renderer: Renderer) {\r\n // focus won't work at construction time - too early\r\n }\r\n\r\n ngOnInit() {\r\n this.renderer.invokeElementMethod(this.el.nativeElement, 'focus', []);\r\n }\r\n}\n\n\n// WEBPACK FOOTER //\n// ./src/app/directives/focus.directive.ts","import { Component, OnInit,OnDestroy } from '@angular/core';\nimport {Subscription} from 'rxjs/Subscription';\n\nimport { UserService } from '../shared/services/user.service';\n\n@Component({\n selector: 'app-header',\n templateUrl: './header.component.html',\n styleUrls: ['./header.component.scss']\n})\nexport class HeaderComponent implements OnInit,OnDestroy {\n\n status: boolean;\n subscription:Subscription;\n\n constructor(private userService:UserService) { \n }\n\n logout() {\n this.userService.logout(); \n }\n\n ngOnInit() {\n this.subscription = this.userService.authNavStatus$.subscribe(status => this.status = status);\n }\n\n ngOnDestroy() {\n // prevent memory leak when component is destroyed\n this.subscription.unsubscribe();\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/header/header.component.ts","import { Component, Input, OnDestroy } from '@angular/core';\n\n@Component({\n selector: 'app-spinner',\n templateUrl: './spinner.component.html',\n styleUrls: ['./spinner.component.scss']\n})\n\n\nexport class SpinnerComponent implements OnDestroy { \n private currentTimeout: number;\n private isDelayedRunning: boolean = false;\n\n @Input()\n public delay: number = 150;\n\n @Input()\n public set isRunning(value: boolean) {\n if (!value) {\n this.cancelTimeout();\n this.isDelayedRunning = false;\n return;\n }\n\n if (this.currentTimeout) {\n return;\n }\n\n // specify window to side-step conflict with node types: https://github.com/mgechev/angular2-seed/issues/901\n this.currentTimeout = window.setTimeout(() => {\n this.isDelayedRunning = value;\n this.cancelTimeout();\n }, this.delay);\n }\n\n private cancelTimeout(): void {\n clearTimeout(this.currentTimeout);\n this.currentTimeout = undefined;\n }\n\n ngOnDestroy(): any {\n this.cancelTimeout();\n }\n}\n\n\n// WEBPACK FOOTER //\n// ./src/app/spinner/spinner.component.ts","// The file contents for the current environment will overwrite these during build.\n// The build system defaults to the dev environment which uses `environment.ts`, but if you do\n// `ng build --env=prod` then `environment.prod.ts` will be used instead.\n// The list of which env maps to which file can be found in `.angular-cli.json`.\n\nexport const environment = {\n production: false\n};\n\n\n\n// WEBPACK FOOTER //\n// ./src/environments/environment.ts","exports = module.exports = require(\"../../../../node_modules/css-loader/lib/css-base.js\")();\n// imports\n\n\n// module\nexports.push([module.id, \"\", \"\"]);\n\n// exports\n\n\n/*** EXPORTS FROM exports-loader ***/\nmodule.exports = module.exports.toString();\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/account/login-form/login-form.component.scss\n// module id = 233\n// module chunks = 1","exports = module.exports = require(\"../../../../node_modules/css-loader/lib/css-base.js\")();\n// imports\n\n\n// module\nexports.push([module.id, \"\", \"\"]);\n\n// exports\n\n\n/*** EXPORTS FROM exports-loader ***/\nmodule.exports = module.exports.toString();\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/account/registration-form/registration-form.component.scss\n// module id = 234\n// module chunks = 1","exports = module.exports = require(\"../../node_modules/css-loader/lib/css-base.js\")();\n// imports\n\n\n// module\nexports.push([module.id, \"body {\\n padding-top: 5rem;\\n background-color: #f9f9f9; }\\n\\n.container-fluid {\\n padding-left: 1.25rem;\\n padding-right: 1.25rem;\\n max-width: 920px;\\n margin-left: auto;\\n margin-right: auto; }\\n\\n.card {\\n box-shadow: 0 2px 3px rgba(0, 0, 0, 0.05);\\n position: relative;\\n background-color: #fff;\\n border: 1px solid #eee;\\n border-radius: 3px; }\\n\\n.card-title {\\n margin: 0 !important;\\n font-size: 1.25rem; }\\n\\n.bg-white {\\n background: #fff; }\\n\", \"\"]);\n\n// exports\n\n\n/*** EXPORTS FROM exports-loader ***/\nmodule.exports = module.exports.toString();\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/app.component.scss\n// module id = 235\n// module chunks = 1","exports = module.exports = require(\"../../../../node_modules/css-loader/lib/css-base.js\")();\n// imports\n\n\n// module\nexports.push([module.id, \"\", \"\"]);\n\n// exports\n\n\n/*** EXPORTS FROM exports-loader ***/\nmodule.exports = module.exports.toString();\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/dashboard/home/home.component.scss\n// module id = 236\n// module chunks = 1","exports = module.exports = require(\"../../../../node_modules/css-loader/lib/css-base.js\")();\n// imports\n\n\n// module\nexports.push([module.id, \"\", \"\"]);\n\n// exports\n\n\n/*** EXPORTS FROM exports-loader ***/\nmodule.exports = module.exports.toString();\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/dashboard/root/root.component.scss\n// module id = 237\n// module chunks = 1","exports = module.exports = require(\"../../../node_modules/css-loader/lib/css-base.js\")();\n// imports\n\n\n// module\nexports.push([module.id, \"\", \"\"]);\n\n// exports\n\n\n/*** EXPORTS FROM exports-loader ***/\nmodule.exports = module.exports.toString();\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/header/header.component.scss\n// module id = 238\n// module chunks = 1","exports = module.exports = require(\"../../../node_modules/css-loader/lib/css-base.js\")();\n// imports\n\n\n// module\nexports.push([module.id, \"\", \"\"]);\n\n// exports\n\n\n/*** EXPORTS FROM exports-loader ***/\nmodule.exports = module.exports.toString();\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/home/home.component.scss\n// module id = 239\n// module chunks = 1","exports = module.exports = require(\"../../../node_modules/css-loader/lib/css-base.js\")();\n// imports\n\n\n// module\nexports.push([module.id, \".spinner {\\n width: 40px;\\n height: 40px;\\n position: relative;\\n margin: 30px auto; }\\n\\n.double-bounce1, .double-bounce2 {\\n width: 100%;\\n height: 100%;\\n border-radius: 50%;\\n background-color: #333;\\n opacity: 0.6;\\n position: absolute;\\n top: 0;\\n left: 0;\\n -webkit-animation: sk-bounce 2.0s infinite ease-in-out;\\n animation: sk-bounce 2.0s infinite ease-in-out; }\\n\\n.double-bounce2 {\\n -webkit-animation-delay: -1.0s;\\n animation-delay: -1.0s; }\\n\\n@-webkit-keyframes sk-bounce {\\n 0%, 100% {\\n -webkit-transform: scale(0); }\\n 50% {\\n -webkit-transform: scale(1); } }\\n\\n@keyframes sk-bounce {\\n 0%, 100% {\\n transform: scale(0);\\n -webkit-transform: scale(0); }\\n 50% {\\n transform: scale(1);\\n -webkit-transform: scale(1); } }\\n\", \"\"]);\n\n// exports\n\n\n/*** EXPORTS FROM exports-loader ***/\nmodule.exports = module.exports.toString();\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/spinner/spinner.component.scss\n// module id = 240\n// module chunks = 1","module.exports = \"
\\n\\t
\\n\\n\\t\\t
\\n\\t\\t\\t
\\n\\n\\t\\t\\t\\t
\\n\\t\\t\\t\\t\\tAll set! Please login with your account\\n\\t\\t\\t\\t
\\n\\n\\t\\t\\t\\t

Login

\\n\\n\\t\\t\\t\\t
\\n\\n\\t\\t\\t\\t\\t
\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\t\\n\\n\\t\\t\\t\\t\\t\\t\\n Please enter a valid email\\n \\n\\n\\t\\t\\t\\t\\t
\\n\\n\\t\\t\\t\\t\\t
\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t
\\n\\n\\t\\t\\t\\t\\t
\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t
\\n\\n\\t\\t\\t\\t\\t
\\n\\t\\t\\t\\t\\t\\tOops! {{errors}}\\n\\t\\t\\t\\t\\t
\\n\\t\\t\\t\\t
\\n\\n\\t\\t\\t
\\n\\t\\t
\\n\\t
\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/account/login-form/login-form.component.html\n// module id = 245\n// module chunks = 1","module.exports = \"\\n\\n
\\n\\t
\\n\\n\\t\\t
\\n\\n\\t\\t\\t
\\n\\t\\t\\t\\t

Create your account

\\n\\t\\t\\t
\\n\\n\\t\\t\\t
\\n\\n\\t\\t\\t\\t
\\n\\n\\n\\t\\t\\t\\t\\t
\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t
\\n\\n \\t
\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t
\\n \\n
\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\tPlease enter a valid email\\n\\t\\t\\t\\t\\t
\\n\\n\\t\\t\\t\\t\\t
\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t
\\n \\n
\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t
\\n \\n\\t\\t\\t\\t
\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t\\t\\n\\t\\t\\t\\t\\t
\\n\\n\\t\\t\\t\\t\\t
\\n\\t\\t\\t\\t\\t\\tOops! {{errors}}\\n\\t\\t\\t\\t\\t
\\n\\n\\t\\t\\t\\t
\\n\\t\\t\\t
\\n\\n\\t\\t
\\n\\t
\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/account/registration-form/registration-form.component.html\n// module id = 246\n// module chunks = 1","module.exports = \"\\n\\n\\n
\\n\\t\\n\\t\\n
\\n\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/app.component.html\n// module id = 247\n// module chunks = 1","module.exports = \"
\\n\\t
\\n\\t\\t

Welcome home!

\\n\\t\\t

{{homeDetails?.message}}

\\n\\t
\\n
\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/dashboard/home/home.component.html\n// module id = 248\n// module chunks = 1","module.exports = \"
\\n\\n
\\n \\n
\\n\\n
\\n \\n
\\n
\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/dashboard/root/root.component.html\n// module id = 249\n// module chunks = 1","module.exports = \" \\n\\n\\n \"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/header/header.component.html\n// module id = 250\n// module chunks = 1","module.exports = \"
\\n
\\n

DotNetGigs

\\n

Welcome, please signup or login to your account below.

\\n

\\n Signup\\n Login\\n

\\n
\\n
\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/home/home.component.html\n// module id = 251\n// module chunks = 1","module.exports = \"
\\n
\\n
\\n
\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/spinner/spinner.component.html\n// module id = 252\n// module chunks = 1","import { Injectable } from '@angular/core';\r\nimport { Http, Response, Headers, RequestOptions } from '@angular/http';\r\n\r\nimport { UserRegistration } from '../models/user.registration.interface';\r\nimport { ConfigService } from '../utils/config.service';\r\n\r\nimport {BaseService} from \"./base.service\";\r\n\r\nimport { Observable } from 'rxjs/Rx';\r\nimport { BehaviorSubject } from 'rxjs/Rx';\r\n\r\n//import * as _ from 'lodash';\r\n\r\n// Add the RxJS Observable operators we need in this app.\r\nimport '../../rxjs-operators';\r\n\r\n@Injectable()\r\n\r\nexport class UserService extends BaseService {\r\n\r\n baseUrl: string = '';\r\n\r\n // Observable navItem source\r\n private _authNavStatusSource = new BehaviorSubject(false);\r\n // Observable navItem stream\r\n authNavStatus$ = this._authNavStatusSource.asObservable();\r\n\r\n private loggedIn = false;\r\n\r\n constructor(private http: Http, private configService: ConfigService) {\r\n super();\r\n this.loggedIn = !!localStorage.getItem('auth_token');\r\n // ?? not sure if this the best way to broadcast the status but seems to resolve issue on page refresh where auth status is lost in\r\n // header component resulting in authed user nav links disappearing despite the fact user is still logged in\r\n this._authNavStatusSource.next(this.loggedIn);\r\n this.baseUrl = configService.getApiURI();\r\n }\r\n\r\n register(email: string, password: string, firstName: string, lastName: string,location: string): Observable {\r\n let body = JSON.stringify({ email, password, firstName, lastName,location });\r\n let headers = new Headers({ 'Content-Type': 'application/json' });\r\n let options = new RequestOptions({ headers: headers });\r\n\r\n return this.http.post(this.baseUrl + \"/accounts\", body, options)\r\n .map(res => true)\r\n .catch(this.handleError);\r\n } \r\n\r\n login(userName, password) {\r\n let headers = new Headers();\r\n headers.append('Content-Type', 'application/json');\r\n\r\n return this.http\r\n .post(\r\n this.baseUrl + '/auth/login',\r\n JSON.stringify({ userName, password }),{ headers }\r\n )\r\n .map(res => res.json())\r\n .map(res => {\r\n localStorage.setItem('auth_token', res.auth_token);\r\n this.loggedIn = true;\r\n this._authNavStatusSource.next(true);\r\n return true;\r\n })\r\n .catch(this.handleError);\r\n }\r\n\r\n logout() {\r\n localStorage.removeItem('auth_token');\r\n this.loggedIn = false;\r\n this._authNavStatusSource.next(false);\r\n }\r\n\r\n isLoggedIn() {\r\n return this.loggedIn;\r\n } \r\n}\r\n\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/shared/services/user.service.ts","import { Injectable } from '@angular/core';\r\n \r\n@Injectable()\r\nexport class ConfigService {\r\n \r\n _apiURI : string;\r\n \r\n constructor() {\r\n this._apiURI = 'http://localhost:5000/api';\r\n }\r\n \r\n getApiURI() {\r\n return this._apiURI;\r\n } \r\n}\r\n \n\n\n// WEBPACK FOOTER //\n// ./src/app/shared/utils/config.service.ts","import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { SharedModule } from '../shared/modules/shared.module';\n\nimport { UserService } from '../shared/services/user.service';\n\nimport { EmailValidator } from '../directives/email.validator.directive';\n\nimport { routing } from './account.routing';\nimport { RegistrationFormComponent } from './registration-form/registration-form.component';\nimport { LoginFormComponent } from './login-form/login-form.component';\n\n@NgModule({\n imports: [\n CommonModule,FormsModule,routing,SharedModule\n ],\n declarations: [RegistrationFormComponent,EmailValidator, LoginFormComponent],\n providers: [ UserService ]\n})\nexport class AccountModule { }\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/account/account.module.ts","import { Subscription } from 'rxjs';\nimport { Component, OnInit,OnDestroy } from '@angular/core';\nimport { Router, ActivatedRoute } from '@angular/router';\n\nimport { Credentials } from '../../shared/models/credentials.interface';\nimport { UserService } from '../../shared/services/user.service';\n\n@Component({\n selector: 'app-login-form',\n templateUrl: './login-form.component.html',\n styleUrls: ['./login-form.component.scss']\n})\nexport class LoginFormComponent implements OnInit, OnDestroy {\n\n private subscription: Subscription;\n\n brandNew: boolean;\n errors: string;\n isRequesting: boolean;\n submitted: boolean = false;\n credentials: Credentials = { email: '', password: '' };\n\n constructor(private userService: UserService, private router: Router,private activatedRoute: ActivatedRoute) { }\n\n ngOnInit() {\n\n // subscribe to router event\n this.subscription = this.activatedRoute.queryParams.subscribe(\n (param: any) => {\n this.brandNew = param['brandNew']; \n this.credentials.email = param['email']; \n }); \n }\n\n ngOnDestroy() {\n // prevent memory leak by unsubscribing\n this.subscription.unsubscribe();\n }\n\n login({ value, valid }: { value: Credentials, valid: boolean }) {\n this.submitted = true;\n this.isRequesting = true;\n this.errors='';\n if (valid) {\n this.userService.login(value.email, value.password)\n .finally(() => this.isRequesting = false)\n .subscribe(\n result => { \n if (result) {\n this.router.navigate(['/dashboard/home']); \n }\n },\n error => this.errors = error);\n }\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/account/login-form/login-form.component.ts","import { Component, OnInit } from '@angular/core';\nimport { Router } from '@angular/router';\n\nimport { UserRegistration } from '../../shared/models/user.registration.interface';\nimport { UserService } from '../../shared/services/user.service';\n\n@Component({\n selector: 'app-registration-form',\n templateUrl: './registration-form.component.html',\n styleUrls: ['./registration-form.component.scss']\n})\nexport class RegistrationFormComponent implements OnInit {\n\n errors: string; \n isRequesting: boolean;\n submitted: boolean = false;\n \n constructor(private userService: UserService,private router: Router) { \n \n }\n\n ngOnInit() {\n \n }\n\n registerUser({ value, valid }: { value: UserRegistration, valid: boolean }) {\n this.submitted = true;\n this.isRequesting = true;\n this.errors='';\n if(valid)\n {\n this.userService.register(value.email,value.password,value.firstName,value.lastName,value.location)\n .finally(() => this.isRequesting = false)\n .subscribe(\n result => {if(result){\n this.router.navigate(['/login'],{queryParams: {brandNew: true,email:value.email}}); \n }},\n errors => this.errors = errors);\n } \n } \n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/account/registration-form/registration-form.component.ts","// auth.guard.ts\r\nimport { Injectable } from '@angular/core';\r\nimport { Router, CanActivate } from '@angular/router';\r\nimport { UserService } from './shared/services/user.service';\r\n\r\n@Injectable()\r\nexport class AuthGuard implements CanActivate {\r\n constructor(private user: UserService,private router: Router) {}\r\n\r\n canActivate() {\r\n\r\n if(!this.user.isLoggedIn())\r\n {\r\n this.router.navigate(['/account/login']);\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n}\n\n\n// WEBPACK FOOTER //\n// ./src/app/auth.guard.ts","import { Component, OnInit } from '@angular/core';\n\nimport { HomeDetails } from '../models/home.details.interface';\nimport { DashboardService } from '../services/dashboard.service';\n\n@Component({\n selector: 'app-home',\n templateUrl: './home.component.html',\n styleUrls: ['./home.component.scss']\n})\nexport class HomeComponent implements OnInit {\n\n homeDetails: HomeDetails;\n \n constructor(private dashboardService: DashboardService) { }\n\n ngOnInit() {\n\n this.dashboardService.getHomeDetails()\n .subscribe((homeDetails: HomeDetails) => {\n this.homeDetails = homeDetails;\n },\n error => {\n //this.notificationService.printErrorMessage(error);\n });\n\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/dashboard/home/home.component.ts","import { Component, OnInit } from '@angular/core';\n\n@Component({\n selector: 'app-root',\n templateUrl: './root.component.html',\n styleUrls: ['./root.component.scss']\n})\nexport class RootComponent implements OnInit {\n\n constructor() { }\n\n ngOnInit() {\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/dashboard/root/root.component.ts","import { Injectable } from '@angular/core';\r\nimport { Http, Response, Headers } from '@angular/http';\r\n\r\nimport { HomeDetails } from '../models/home.details.interface'; \r\nimport { ConfigService } from '../../shared/utils/config.service';\r\n\r\nimport {BaseService} from '../../shared/services/base.service';\r\n\r\nimport { Observable } from 'rxjs/Rx';\r\n\r\n//import * as _ from 'lodash';\r\n\r\n// Add the RxJS Observable operators we need in this app.\r\nimport '../../rxjs-operators';\r\n\r\n@Injectable()\r\n\r\nexport class DashboardService extends BaseService {\r\n\r\n baseUrl: string = ''; \r\n\r\n constructor(private http: Http, private configService: ConfigService) {\r\n super();\r\n this.baseUrl = configService.getApiURI();\r\n }\r\n\r\n getHomeDetails(): Observable {\r\n let headers = new Headers();\r\n headers.append('Content-Type', 'application/json');\r\n let authToken = localStorage.getItem('auth_token');\r\n headers.append('Authorization', `Bearer ${authToken}`);\r\n \r\n return this.http.get(this.baseUrl + \"/dashboard/home\",{headers})\r\n .map(response => response.json())\r\n .catch(this.handleError);\r\n } \r\n}\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/dashboard/services/dashboard.service.ts","import { Component, OnInit } from '@angular/core';\n\n@Component({\n selector: 'app-home',\n templateUrl: './home.component.html',\n styleUrls: ['./home.component.scss']\n})\nexport class HomeComponent implements OnInit {\n\n constructor() { }\n\n ngOnInit() {\n }\n\n}\n\n \n\n\n\n// WEBPACK FOOTER //\n// ./src/app/home/home.component.ts","// include directives/components commonly used in features modules in this shared modules\r\n// and import me into the feature module\r\n// importing them individually results in: Type xxx is part of the declarations of 2 modules: ... Please consider moving to a higher module...\r\n// https://github.com/angular/angular/issues/10646 \r\n\r\nimport { NgModule } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\n \r\nimport { myFocus } from '../../directives/focus.directive';\r\nimport {SpinnerComponent} from '../../spinner/spinner.component'; \r\n\r\n\r\n@NgModule({\r\n imports: [CommonModule],\r\n declarations: [myFocus,SpinnerComponent],\r\n exports: [myFocus,SpinnerComponent],\r\n providers: []\r\n})\r\nexport class SharedModule { }\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/shared/modules/shared.module.ts"],"sourceRoot":""} --------------------------------------------------------------------------------