├── .gitattributes ├── .gitignore ├── PhotoGallery.sln ├── README.md ├── appveyor.yml ├── licence └── src └── PhotoGallery ├── .bowerrc ├── Controllers ├── AccountController.cs ├── AlbumsController.cs ├── HomeController.cs └── PhotosController.cs ├── Entities ├── Album.cs ├── Error.cs ├── IEntityBase.cs ├── Photo.cs ├── Role.cs ├── User.cs └── UserRole.cs ├── Infrastructure ├── Core │ ├── AuthMiddleware.cs │ ├── GenericResult.cs │ ├── MembershipContext.cs │ ├── PaginationSet.cs │ └── StatusCodeResult.cs ├── DbInitializer.cs ├── Mappings │ ├── AutoMapperConfiguration.cs │ └── DomainToViewModelMappingProfile.cs ├── PhotoGalleryContext.cs ├── Repositories │ ├── Abstract │ │ ├── IEntityBaseRepository.cs │ │ └── IRepositories.cs │ ├── AlbumRepository.cs │ ├── EntityBaseRepository.cs │ ├── ErrorRepository.cs │ ├── PhotoRepository.cs │ ├── RoleRepository.cs │ ├── UserRepository.cs │ └── UserRoleRepository.cs └── Services │ ├── Abstract │ ├── IEncryptionService.cs │ └── IMembershipService.cs │ ├── EncryptionService.cs │ └── MembershipService.cs ├── PhotoGallery.csproj ├── Project_Readme.html ├── Properties └── launchSettings.json ├── Startup.cs ├── ViewModels ├── AlbumViewModel.cs ├── LoginViewModel.cs ├── PhotoViewModel.cs └── RegistrationViewModel.cs ├── Views ├── Home │ └── Index.cshtml ├── Shared │ └── _Layout.cshtml └── _ViewStart.cshtml ├── appsettings.json ├── bower.json ├── gulpfile.js ├── package-lock.json ├── package.json ├── runtimeconfig.template.json ├── systemjs.config.js ├── web.config └── wwwroot ├── app ├── app.component.html ├── app.component.ts ├── app.module.ts ├── components │ ├── account │ │ ├── account.component.html │ │ ├── account.component.ts │ │ ├── account.module.ts │ │ ├── login.component.html │ │ ├── login.component.ts │ │ ├── register.component.html │ │ ├── register.component.ts │ │ └── routes.ts │ ├── album-photos.component.html │ ├── album-photos.component.ts │ ├── albums.component.html │ ├── albums.component.ts │ ├── home.component.html │ ├── home.component.ts │ ├── photos.component.html │ └── photos.component.ts ├── core │ ├── common │ │ └── paginated.ts │ ├── domain │ │ ├── album.ts │ │ ├── operationResult.ts │ │ ├── photo.ts │ │ ├── registration.ts │ │ └── user.ts │ └── services │ │ ├── data.service.ts │ │ ├── membership.service.ts │ │ ├── notification.service.ts │ │ └── utility.service.ts ├── main.ts └── routes.ts ├── css └── site.css ├── images ├── 80k_pluto-wallpaper-800x600.jpg ├── above-wallpaper-800x600.jpg ├── armeni_teghut_mery_tree_lilac-wallpaper-800x600.jpg ├── armenia_teghut_2-wallpaper-800x600.jpg ├── aspcorerc2.png ├── aspnet5-agnular2-03.png ├── autumn_california-wallpaper-800x600.jpg ├── beautiful_autumn_3-wallpaper-800x600.jpg ├── blue_mountains_mist-wallpaper-800x600.jpg ├── business-wallpaper-800x600.jpg ├── butterfly_95-wallpaper-800x600.jpg ├── by_the_river-wallpaper-800x600.jpg ├── country_road_summer-wallpaper-800x600.jpg ├── dark_clouds_2-wallpaper-800x600.jpg ├── dark_storm_clouds-wallpaper-800x600.jpg ├── dirt_road_through_forest-wallpaper-800x600.jpg ├── finland_forest_lake-wallpaper-800x600.jpg ├── fog_at_the_pink_house-wallpaper-800x600.jpg ├── forest-wallpaper-800x600.jpg ├── forest_in_dam_no__1_woods_2-wallpaper-800x600.jpg ├── forest_stream_2-wallpaper-800x600.jpg ├── forest_sunrise-wallpaper-800x600.jpg ├── green_ginkgo_trees-wallpaper-800x600.jpg ├── hawthorns_leaf-wallpaper-800x600.jpg ├── hidden_lake-wallpaper-800x600.jpg ├── high_speed_photography-wallpaper-800x600.jpg ├── hong_kong_harbour_night_lights-wallpaper-800x600.jpg ├── island-wallpaper-800x600.jpg ├── landscape_5-wallpaper-800x600.jpg ├── london_6-wallpaper-800x600.jpg ├── marguerite_daisy_flower-wallpaper-800x600.jpg ├── mist_rising-wallpaper-800x600.jpg ├── morning_sun-wallpaper-800x600.jpg ├── mountain_landscape-wallpaper-800x600.jpg ├── pier-wallpaper-800x600.jpg ├── planet_earth_at_night-wallpaper-800x600.jpg ├── pyrenees_mountain_range-wallpaper-800x600.jpg ├── red_autumn_4-wallpaper-800x600.jpg ├── road_12-wallpaper-800x600.jpg ├── road_through_forest_hdr-wallpaper-800x600.jpg ├── save_the_earth-wallpaper-800x600.jpg ├── scotland_coast_lighthouse-wallpaper-800x600.jpg ├── scotland_road_landscape-wallpaper-800x600.jpg ├── skyline_new_york_city_2015-wallpaper-800x600.jpg ├── storm_is_coming_2-wallpaper-800x600.jpg ├── sunlight_through_tree-wallpaper-800x600.jpg ├── sunset_222-wallpaper-800x600.jpg ├── surfing_8-wallpaper-800x600.jpg ├── the_day_before_halloween-wallpaper-800x600.jpg ├── thumbnail-default.png ├── tokyo_at_sunset-wallpaper-800x600.jpg ├── tree_7-wallpaper-800x600.jpg ├── tree_summer_storm-wallpaper-800x600.jpg └── walk_into_fall-wallpaper-800x600.jpg ├── tsconfig.json └── web.config /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.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 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | # DNX 42 | project.lock.json 43 | artifacts/ 44 | 45 | *_i.c 46 | *_p.c 47 | *_i.h 48 | *.ilk 49 | *.meta 50 | *.obj 51 | *.pch 52 | *.pdb 53 | *.pgc 54 | *.pgd 55 | *.rsp 56 | *.sbr 57 | *.tlb 58 | *.tli 59 | *.tlh 60 | *.tmp 61 | *.tmp_proj 62 | *.log 63 | *.vspscc 64 | *.vssscc 65 | .builds 66 | *.pidb 67 | *.svclog 68 | *.scc 69 | 70 | # Chutzpah Test files 71 | _Chutzpah* 72 | 73 | # Visual C++ cache files 74 | ipch/ 75 | *.aps 76 | *.ncb 77 | *.opensdf 78 | *.sdf 79 | *.cachefile 80 | 81 | # Visual Studio profiler 82 | *.psess 83 | *.vsp 84 | *.vspx 85 | 86 | # TFS 2012 Local Workspace 87 | $tf/ 88 | 89 | # Guidance Automation Toolkit 90 | *.gpState 91 | 92 | # ReSharper is a .NET coding add-in 93 | _ReSharper*/ 94 | *.[Rr]e[Ss]harper 95 | *.DotSettings.user 96 | 97 | # JustCode is a .NET coding add-in 98 | .JustCode 99 | 100 | # TeamCity is a build add-in 101 | _TeamCity* 102 | 103 | # DotCover is a Code Coverage Tool 104 | *.dotCover 105 | 106 | # NCrunch 107 | _NCrunch_* 108 | .*crunch*.local.xml 109 | 110 | # MightyMoose 111 | *.mm.* 112 | AutoTest.Net/ 113 | 114 | # Web workbench (sass) 115 | .sass-cache/ 116 | 117 | # Installshield output folder 118 | [Ee]xpress/ 119 | 120 | # DocProject is a documentation generator add-in 121 | DocProject/buildhelp/ 122 | DocProject/Help/*.HxT 123 | DocProject/Help/*.HxC 124 | DocProject/Help/*.hhc 125 | DocProject/Help/*.hhk 126 | DocProject/Help/*.hhp 127 | DocProject/Help/Html2 128 | DocProject/Help/html 129 | 130 | # Click-Once directory 131 | publish/ 132 | src/PhotoGallery/Properties/PublishProfiles/ 133 | 134 | # Publish Web Output 135 | *.[Pp]ublish.xml 136 | *.azurePubxml 137 | ## TODO: Comment the next line if you want to checkin your 138 | ## web deploy settings but do note that will include unencrypted 139 | ## passwords 140 | #*.pubxml 141 | 142 | *.publishproj 143 | 144 | # NuGet Packages 145 | *.nupkg 146 | # The packages folder can be ignored because of Package Restore 147 | **/packages/* 148 | # except build/, which is used as an MSBuild target. 149 | !**/packages/build/ 150 | # Uncomment if necessary however generally it will be regenerated when needed 151 | #!**/packages/repositories.config 152 | 153 | # Windows Azure Build Output 154 | csx/ 155 | *.build.csdef 156 | 157 | # Windows Store app package directory 158 | AppPackages/ 159 | 160 | # Visual Studio cache files 161 | # files ending in .cache can be ignored 162 | *.[Cc]ache 163 | # but keep track of directories ending in .cache 164 | !*.[Cc]ache/ 165 | 166 | # Others 167 | ClientBin/ 168 | [Ss]tyle[Cc]op.* 169 | ~$* 170 | *~ 171 | *.dbmdl 172 | *.dbproj.schemaview 173 | *.pfx 174 | *.publishsettings 175 | node_modules/ 176 | bower_components/ 177 | src/PhotoGallery/wwwroot/lib/ 178 | orleans.codegen.cs 179 | 180 | # RIA/Silverlight projects 181 | Generated_Code/ 182 | 183 | # Backup & report files from converting an old project file 184 | # to a newer Visual Studio version. Backup files are not needed, 185 | # because we have git ;-) 186 | _UpgradeReport_Files/ 187 | Backup*/ 188 | UpgradeLog*.XML 189 | UpgradeLog*.htm 190 | 191 | # SQL Server files 192 | *.mdf 193 | *.ldf 194 | 195 | # Business Intelligence projects 196 | *.rdl.data 197 | *.bim.layout 198 | *.bim_*.settings 199 | 200 | # Microsoft Fakes 201 | FakesAssemblies/ 202 | 203 | # Node.js Tools for Visual Studio 204 | .ntvs_analysis.dat 205 | 206 | # Visual Studio 6 build log 207 | *.plg 208 | 209 | # Visual Studio 6 workspace options file 210 | *.opt 211 | 212 | # LightSwitch generated files 213 | GeneratedArtifacts/ 214 | _Pvt_Extensions/ 215 | ModelManifest.xml 216 | /src/PhotoGallery/wwwroot/app/app.js 217 | /src/PhotoGallery/wwwroot/app/**/*.js 218 | /src/PhotoGallery/wwwroot/app/**/*.js.map 219 | /src/PhotoGallery/typings 220 | /src/PhotoGallery/migrations -------------------------------------------------------------------------------- /PhotoGallery.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26403.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F621D8AC-5C86-4E79-82DE-EACEF55FED93}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F551A3A3-A4C2-42F5-A98E-E52C6EE69365}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PhotoGallery", "src\PhotoGallery\PhotoGallery.csproj", "{33F89712-732C-4800-9051-3D89A2E5A1D9}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {33F89712-732C-4800-9051-3D89A2E5A1D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {33F89712-732C-4800-9051-3D89A2E5A1D9}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {33F89712-732C-4800-9051-3D89A2E5A1D9}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {33F89712-732C-4800-9051-3D89A2E5A1D9}.Release|Any CPU.Build.0 = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | GlobalSection(NestedProjects) = preSolution 27 | {33F89712-732C-4800-9051-3D89A2E5A1D9} = {F621D8AC-5C86-4E79-82DE-EACEF55FED93} 28 | EndGlobalSection 29 | EndGlobal 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ASP.NET Core, Angular 4 & TypeScript 2 | [![Build status](https://ci.appveyor.com/api/projects/status/github/chsakell/aspnet5-angular2-typescript?branch=master&svg=true)](https://ci.appveyor.com/project/chsakell/aspnet5-angular2-typescript/branch/master) [![License](https://img.shields.io/github/license/chsakell/aspnet5-angular2-typescript.svg)](https://github.com/chsakell/aspnet5-angular2-typescript/blob/master/licence) 3 | 4 | Blog post:Cross-platform Single Page Applications using ASP.NET Core, Angular 2 and Typescript

5 | aspnet5-agnular2-03 6 | 7 |

Frameworks - Tools - Libraries

8 | 18 | 19 |

Installation instructions - Part 1 (Applied for Windows/Linux/MAC)

20 |
    21 |
  1. Install ASP.NET Core according to your development environment from here.
  2. 22 |
  3. Install NPM by installing Node.js.
  4. 23 |
  5. Install Bower, Gulp, Typescript and Typescript Definition Manager globally by typing the following commands on the console/terminal: 24 | 30 |
  6. 31 | 32 |

    Installation instructions - Part 2 (Run application in Visual Studio 2017, only for Windows users)

    33 |
      34 |
    1. Download and install Visual Studio 2017 from here.
    2. 35 |
    3. Open Visual Studio 2017 and install any update related to ASP.NET Core (check the notifications).
    4. 36 |
    5. Download the source code and open the solution.
    6. 37 |
    7. By the time you open the solution, VS 2017 will try to restore Nuget, NPM and Bower packages.
    8. 38 |
    9. In case it fails to restore NPM and Bower packages, open a console and navigate at the src/PhotoGallery path where the package.json and bower.json files exist. Run the following commands: 39 |
        40 |
      • npm install
      • 41 |
      • bower install
      • 42 |
      • gulp build-spa
      • 43 |
      44 |
    10. 45 |
    11. Open appsettings.json file and alter the database connection string to reflect your SQL Server environment.
    12. 46 |
    13. Open a console and navigate to src/PhotoGallery where the project.json exists. Run the following commands to enable migrations and create the database: 47 |
        48 |
      1. dotnet ef migrations add initial
      2. 49 |
      3. dotnet ef database update
      4. 50 |
      51 |
    14. 52 |
    15. Build your application and run it. You can use username: chsakell and password: photogallery to sign in or register a new user.
    16. 53 |
    54 | 55 |

    Installation instructions - Part 2 (Run application in Visual Studio Code, recommended for Linux/MAC users)

    56 |
      57 |
    1. Download and install Visual Studio Code from here.
    2. 58 |
    3. Install the csharp extension from here
    4. 59 |
    5. Download the source code and open the src/PhotoGallery folder in Visual Studio Code.
    6. 60 |
    7. Open a console/terminal and navigate at the src/PhotoGallery path where the package.json and bower.json files exist. Run the following commands: 61 |
        62 |
      • npm install
      • 63 |
      • bower install
      • 64 |
      • gulp build-spa
      • 65 |
      66 |
    8. 67 |
    9. Run the following command to restore Nuget Packages (dependencies) 68 |
        69 |
      • dotnet restore
      • 70 |
      71 |
    10. 72 |
    11. Application uses SQL Server so in case you want to run the app in Linux or MAC simply set "InMemoryProvider": true in appsettings.json and skip to the last 3 steps to run the app.
    12. 73 |
    13. Open appsettings.json file and alter the database connection string to reflect your SQL Server environment.
    14. 74 |
    15. Open a console/terminal and navigate to src/PhotoGallery where the project.json exists. Run the following commands to enable migrations and create the database: 75 |
        76 |
      1. dotnet ef migrations add initial
      2. 77 |
      3. dotnet ef database update
      4. 78 |
      79 |
    16. 80 |
    17. Host your application using Kestrel by typing the following command while at src/PhotoGallery: 81 |
        82 |
      • dotnet run
      • 83 |
      84 |
    18. 85 |
    19. Open a browser and navigate to http://localhost:5000/
    20. 86 |
    21. You can use username: chsakell and password: photogallery to sign in or register a new user.
    22. 87 |
    88 |

    Microsoft Azure Deployment

    89 | Learn how to deploy the PhotoGallery app on Microsoft Azure here. 90 |

    Donations

    91 | For being part of open source projects and documenting my work here and on chsakell's blog I really do not charge anything. I try to avoid any type of ads also. 92 | 93 | If you think that any information you obtained here is worth of some money and are willing to pay for it, feel free to send any amount through paypal. 94 | 95 | 96 | 97 | 98 | 99 | 102 | 103 | 104 |
    Paypal
    100 | Buy me a beer 101 |
    105 | 106 |

    Follow chsakell's Blog

    107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 124 | 127 | 128 | 129 |
    FacebookTwitter
    Microsoft Web Application Development
    122 | facebook 123 | 125 | twitter-small 126 |
    130 |

    License

    131 | Code released under the MIT license. 132 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | - 2 | branches: 3 | only: 4 | - master 5 | image: Visual Studio 2017 6 | # Test against the latest version of this Node.js version 7 | environment: 8 | nodejs_version: "6" 9 | DOTNET_CLI_TELEMETRY_OPTOUT: true 10 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true 11 | 12 | # Install scripts. (runs after repo cloning) 13 | install: 14 | # Get the latest stable version of Node.js or io.js 15 | - ps: Install-Product node $env:nodejs_version 16 | - ps: cd "src/PhotoGallery" 17 | # install modules 18 | - npm install 19 | 20 | version: 1.0.{build} 21 | configuration: Release 22 | platform: Any CPU 23 | skip_branch_with_pr: false 24 | before_build: 25 | - cmd: dotnet restore 26 | -------------------------------------------------------------------------------- /licence: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2016 Christos Sakellarios 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/PhotoGallery/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /src/PhotoGallery/Controllers/AccountController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Mvc; 5 | using PhotoGallery.Infrastructure.Services; 6 | using PhotoGallery.Infrastructure.Repositories; 7 | using PhotoGallery.Entities; 8 | using PhotoGallery.ViewModels; 9 | using PhotoGallery.Infrastructure.Core; 10 | using PhotoGallery.Infrastructure; 11 | using System.Security.Claims; 12 | using Microsoft.AspNetCore.Authentication.Cookies; 13 | 14 | // For more information on enabling Web API for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860 15 | 16 | namespace PhotoGallery.Controllers 17 | { 18 | [Route("api/[controller]")] 19 | public class AccountController : Controller 20 | { 21 | private readonly IMembershipService _membershipService; 22 | private readonly IUserRepository _userRepository; 23 | private readonly ILoggingRepository _loggingRepository; 24 | 25 | public AccountController(IMembershipService membershipService, 26 | IUserRepository userRepository, 27 | ILoggingRepository _errorRepository) 28 | { 29 | _membershipService = membershipService; 30 | _userRepository = userRepository; 31 | _loggingRepository = _errorRepository; 32 | } 33 | 34 | 35 | [HttpPost("authenticate")] 36 | public async Task Login([FromBody] LoginViewModel user) 37 | { 38 | IActionResult _result = new ObjectResult(false); 39 | GenericResult _authenticationResult = null; 40 | 41 | try 42 | { 43 | MembershipContext _userContext = _membershipService.ValidateUser(user.Username, user.Password); 44 | 45 | if (_userContext.User != null) 46 | { 47 | IEnumerable _roles = _userRepository.GetUserRoles(user.Username); 48 | List _claims = new List(); 49 | foreach (Role role in _roles) 50 | { 51 | Claim _claim = new Claim(ClaimTypes.Role, "Admin", ClaimValueTypes.String, user.Username); 52 | _claims.Add(_claim); 53 | } 54 | await HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, 55 | new ClaimsPrincipal(new ClaimsIdentity(_claims, CookieAuthenticationDefaults.AuthenticationScheme)), 56 | new Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties {IsPersistent = user.RememberMe }); 57 | 58 | 59 | _authenticationResult = new GenericResult() 60 | { 61 | Succeeded = true, 62 | Message = "Authentication succeeded" 63 | }; 64 | } 65 | else 66 | { 67 | _authenticationResult = new GenericResult() 68 | { 69 | Succeeded = false, 70 | Message = "Authentication failed" 71 | }; 72 | } 73 | } 74 | catch (Exception ex) 75 | { 76 | _authenticationResult = new GenericResult() 77 | { 78 | Succeeded = false, 79 | Message = ex.Message 80 | }; 81 | 82 | _loggingRepository.Add(new Error() { Message = ex.Message, StackTrace = ex.StackTrace, DateCreated = DateTime.Now }); 83 | _loggingRepository.Commit(); 84 | } 85 | 86 | _result = new ObjectResult(_authenticationResult); 87 | return _result; 88 | } 89 | 90 | [HttpPost("logout")] 91 | public async Task Logout() 92 | { 93 | try 94 | { 95 | await HttpContext.Authentication.SignOutAsync("Cookies"); 96 | return Ok(); 97 | } 98 | catch (Exception ex) 99 | { 100 | _loggingRepository.Add(new Error() { Message = ex.Message, StackTrace = ex.StackTrace, DateCreated = DateTime.Now }); 101 | _loggingRepository.Commit(); 102 | 103 | return BadRequest(); 104 | } 105 | 106 | } 107 | 108 | [Route("register")] 109 | [HttpPost] 110 | public IActionResult Register([FromBody] RegistrationViewModel user) 111 | { 112 | IActionResult _result = new ObjectResult(false); 113 | GenericResult _registrationResult = null; 114 | 115 | try 116 | { 117 | if (ModelState.IsValid) 118 | { 119 | User _user = _membershipService.CreateUser(user.Username, user.Email, user.Password, new int[] { 1 }); 120 | 121 | if (_user != null) 122 | { 123 | _registrationResult = new GenericResult() 124 | { 125 | Succeeded = true, 126 | Message = "Registration succeeded" 127 | }; 128 | } 129 | } 130 | else 131 | { 132 | _registrationResult = new GenericResult() 133 | { 134 | Succeeded = false, 135 | Message = "Invalid fields." 136 | }; 137 | } 138 | } 139 | catch (Exception ex) 140 | { 141 | _registrationResult = new GenericResult() 142 | { 143 | Succeeded = false, 144 | Message = ex.Message 145 | }; 146 | 147 | _loggingRepository.Add(new Error() { Message = ex.Message, StackTrace = ex.StackTrace, DateCreated = DateTime.Now }); 148 | _loggingRepository.Commit(); 149 | } 150 | 151 | _result = new ObjectResult(_registrationResult); 152 | return _result; 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/PhotoGallery/Controllers/AlbumsController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using PhotoGallery.Entities; 7 | using PhotoGallery.ViewModels; 8 | using AutoMapper; 9 | using PhotoGallery.Infrastructure.Repositories; 10 | using PhotoGallery.Infrastructure.Core; 11 | using Microsoft.AspNetCore.Authorization; 12 | 13 | // For more information on enabling Web API for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860 14 | 15 | namespace PhotoGallery.Controllers 16 | { 17 | [Route("api/[controller]")] 18 | public class AlbumsController : Controller 19 | { 20 | private readonly IAuthorizationService _authorizationService; 21 | IAlbumRepository _albumRepository; 22 | ILoggingRepository _loggingRepository; 23 | public AlbumsController(IAuthorizationService authorizationService, 24 | IAlbumRepository albumRepository, 25 | ILoggingRepository loggingRepository) 26 | { 27 | _authorizationService = authorizationService; 28 | _albumRepository = albumRepository; 29 | _loggingRepository = loggingRepository; 30 | } 31 | 32 | [Authorize(Policy = "AdminOnly")] 33 | [HttpGet("{page:int=0}/{pageSize=12}")] 34 | public async Task Get(int? page, int? pageSize) 35 | { 36 | PaginationSet pagedSet = new PaginationSet(); 37 | 38 | try 39 | { 40 | if (await _authorizationService.AuthorizeAsync(User, "AdminOnly")) 41 | { 42 | int currentPage = page.Value; 43 | int currentPageSize = pageSize.Value; 44 | 45 | List _albums = null; 46 | int _totalAlbums = new int(); 47 | 48 | 49 | _albums = _albumRepository 50 | .AllIncluding(a => a.Photos) 51 | .OrderBy(a => a.Id) 52 | .Skip(currentPage * currentPageSize) 53 | .Take(currentPageSize) 54 | .ToList(); 55 | 56 | _totalAlbums = _albumRepository.GetAll().Count(); 57 | 58 | IEnumerable _albumsVM = Mapper.Map, IEnumerable>(_albums); 59 | 60 | pagedSet = new PaginationSet() 61 | { 62 | Page = currentPage, 63 | TotalCount = _totalAlbums, 64 | TotalPages = (int)Math.Ceiling((decimal)_totalAlbums / currentPageSize), 65 | Items = _albumsVM 66 | }; 67 | } 68 | else 69 | { 70 | CodeResultStatus _codeResult = new CodeResultStatus(401); 71 | return new ObjectResult(_codeResult); 72 | } 73 | } 74 | catch (Exception ex) 75 | { 76 | _loggingRepository.Add(new Error() { Message = ex.Message, StackTrace = ex.StackTrace, DateCreated = DateTime.Now }); 77 | _loggingRepository.Commit(); 78 | } 79 | 80 | return new ObjectResult(pagedSet); 81 | } 82 | 83 | 84 | [Authorize(Policy = "AdminOnly")] 85 | [HttpGet("{id:int}/photos/{page:int=0}/{pageSize=12}")] 86 | public PaginationSet Get(int id, int? page, int? pageSize) 87 | { 88 | PaginationSet pagedSet = null; 89 | 90 | try 91 | { 92 | int currentPage = page.Value; 93 | int currentPageSize = pageSize.Value; 94 | 95 | List _photos = null; 96 | int _totalPhotos = new int(); 97 | 98 | Album _album = _albumRepository.GetSingle(a => a.Id == id, a => a.Photos); 99 | 100 | _photos = _album 101 | .Photos 102 | .OrderBy(p => p.Id) 103 | .Skip(currentPage * currentPageSize) 104 | .Take(currentPageSize) 105 | .ToList(); 106 | 107 | _totalPhotos = _album.Photos.Count(); 108 | 109 | IEnumerable _photosVM = Mapper.Map, IEnumerable>(_photos); 110 | 111 | pagedSet = new PaginationSet() 112 | { 113 | Page = currentPage, 114 | TotalCount = _totalPhotos, 115 | TotalPages = (int)Math.Ceiling((decimal)_totalPhotos / currentPageSize), 116 | Items = _photosVM 117 | }; 118 | } 119 | catch (Exception ex) 120 | { 121 | _loggingRepository.Add(new Error() { Message = ex.Message, StackTrace = ex.StackTrace, DateCreated = DateTime.Now }); 122 | _loggingRepository.Commit(); 123 | } 124 | 125 | return pagedSet; 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/PhotoGallery/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | 3 | // For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860 4 | 5 | namespace PhotoGallery.Controllers 6 | { 7 | public class HomeController : Controller 8 | { 9 | // GET: // 10 | public IActionResult Index() 11 | { 12 | return View(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/PhotoGallery/Controllers/PhotosController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.AspNetCore.Mvc; 5 | using PhotoGallery.Entities; 6 | using PhotoGallery.ViewModels; 7 | using AutoMapper; 8 | using PhotoGallery.Infrastructure.Repositories; 9 | using PhotoGallery.Infrastructure.Core; 10 | 11 | // For more information on enabling Web API for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860 12 | 13 | namespace PhotoGallery.Controllers 14 | { 15 | [Route("api/[controller]")] 16 | public class PhotosController : Controller 17 | { 18 | IPhotoRepository _photoRepository; 19 | ILoggingRepository _loggingRepository; 20 | public PhotosController(IPhotoRepository photoRepository, ILoggingRepository loggingRepository) 21 | { 22 | _photoRepository = photoRepository; 23 | _loggingRepository = loggingRepository; 24 | } 25 | 26 | [HttpGet("{page:int=0}/{pageSize=12}")] 27 | public PaginationSet Get(int? page, int? pageSize) 28 | { 29 | PaginationSet pagedSet = null; 30 | 31 | try 32 | { 33 | int currentPage = page.Value; 34 | int currentPageSize = pageSize.Value; 35 | 36 | List _photos = null; 37 | int _totalPhotos = new int(); 38 | 39 | 40 | _photos = _photoRepository 41 | .AllIncluding(p => p.Album) 42 | .OrderBy(p => p.Id) 43 | .Skip(currentPage * currentPageSize) 44 | .Take(currentPageSize) 45 | .ToList(); 46 | 47 | _totalPhotos = _photoRepository.GetAll().Count(); 48 | 49 | IEnumerable _photosVM = Mapper.Map, IEnumerable>(_photos); 50 | 51 | pagedSet = new PaginationSet() 52 | { 53 | Page = currentPage, 54 | TotalCount = _totalPhotos, 55 | TotalPages = (int)Math.Ceiling((decimal)_totalPhotos / currentPageSize), 56 | Items = _photosVM 57 | }; 58 | } 59 | catch (Exception ex) 60 | { 61 | _loggingRepository.Add(new Error() { Message = ex.Message, StackTrace = ex.StackTrace, DateCreated = DateTime.Now }); 62 | _loggingRepository.Commit(); 63 | } 64 | 65 | return pagedSet; 66 | } 67 | 68 | [HttpDelete("{id:int}")] 69 | public IActionResult Delete(int id) 70 | { 71 | IActionResult _result = new ObjectResult(false); 72 | GenericResult _removeResult = null; 73 | 74 | try 75 | { 76 | Photo _photoToRemove = this._photoRepository.GetSingle(id); 77 | this._photoRepository.Delete(_photoToRemove); 78 | this._photoRepository.Commit(); 79 | 80 | _removeResult = new GenericResult() 81 | { 82 | Succeeded = true, 83 | Message = "Photo removed." 84 | }; 85 | } 86 | catch (Exception ex) 87 | { 88 | _removeResult = new GenericResult() 89 | { 90 | Succeeded = false, 91 | Message = ex.Message 92 | }; 93 | 94 | _loggingRepository.Add(new Error() { Message = ex.Message, StackTrace = ex.StackTrace, DateCreated = DateTime.Now }); 95 | _loggingRepository.Commit(); 96 | } 97 | 98 | _result = new ObjectResult(_removeResult); 99 | return _result; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/PhotoGallery/Entities/Album.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace PhotoGallery.Entities 5 | { 6 | public class Album : IEntityBase 7 | { 8 | public Album() 9 | { 10 | Photos = new List(); 11 | } 12 | public int Id { get; set; } 13 | public string Title { get; set; } 14 | 15 | public string Description { get; set; } 16 | public DateTime DateCreated { get; set; } 17 | public virtual ICollection Photos { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/PhotoGallery/Entities/Error.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PhotoGallery.Entities 4 | { 5 | public class Error : IEntityBase 6 | { 7 | public int Id { get; set; } 8 | public string Message { get; set; } 9 | public string StackTrace { get; set; } 10 | public DateTime DateCreated { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/PhotoGallery/Entities/IEntityBase.cs: -------------------------------------------------------------------------------- 1 | namespace PhotoGallery.Entities 2 | { 3 | public interface IEntityBase 4 | { 5 | int Id { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/PhotoGallery/Entities/Photo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PhotoGallery.Entities 4 | { 5 | public class Photo : IEntityBase 6 | { 7 | public int Id { get; set; } 8 | public string Title { get; set; } 9 | public string Uri { get; set; } 10 | public virtual Album Album { get; set; } 11 | public int AlbumId { get; set; } 12 | public DateTime DateUploaded { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/PhotoGallery/Entities/Role.cs: -------------------------------------------------------------------------------- 1 | namespace PhotoGallery.Entities 2 | { 3 | public class Role : IEntityBase 4 | { 5 | public int Id { get; set; } 6 | public string Name { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/PhotoGallery/Entities/User.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace PhotoGallery.Entities 5 | { 6 | public class User : IEntityBase 7 | { 8 | public User() 9 | { 10 | UserRoles = new List(); 11 | } 12 | public int Id { get; set; } 13 | public string Username { get; set; } 14 | public string Email { get; set; } 15 | public string HashedPassword { get; set; } 16 | public string Salt { get; set; } 17 | public bool IsLocked { get; set; } 18 | public DateTime DateCreated { get; set; } 19 | 20 | public virtual ICollection UserRoles { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/PhotoGallery/Entities/UserRole.cs: -------------------------------------------------------------------------------- 1 | namespace PhotoGallery.Entities 2 | { 3 | public class UserRole : IEntityBase 4 | { 5 | public int Id { get; set; } 6 | public int UserId { get; set; } 7 | public int RoleId { get; set; } 8 | public virtual Role Role { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Core/AuthMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using PhotoGallery.Entities; 3 | using PhotoGallery.Infrastructure.Repositories; 4 | using PhotoGallery.Infrastructure.Services; 5 | using System; 6 | using System.Linq; 7 | using System.Security.Claims; 8 | using System.Threading.Tasks; 9 | using Microsoft.AspNetCore.Authentication.Cookies; 10 | 11 | namespace PhotoGallery.Infrastructure.Core 12 | { 13 | public class AuthMiddleware 14 | { 15 | private readonly RequestDelegate _next; 16 | private readonly ILoggingRepository _loggingRepository; 17 | private readonly IMembershipService _membershipService; 18 | 19 | public AuthMiddleware(RequestDelegate next, 20 | IMembershipService membershipService, 21 | ILoggingRepository loggingRepository) 22 | { 23 | _next = next; 24 | _membershipService = membershipService; 25 | _loggingRepository = loggingRepository; 26 | } 27 | 28 | public async Task Invoke(HttpContext context) 29 | { 30 | var request = context.Request; 31 | 32 | try 33 | { 34 | if (!context.User.Identities.Any(identity => identity.IsAuthenticated)) 35 | { 36 | Claim _claim = new Claim(ClaimTypes.Role, "Admin", ClaimValueTypes.String, "chsakell"); 37 | await context.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, 38 | new ClaimsPrincipal(new ClaimsIdentity(new[] { _claim }, CookieAuthenticationDefaults.AuthenticationScheme))); 39 | } 40 | } 41 | catch (Exception ex) 42 | { 43 | _loggingRepository.Add(new Error() { Message = ex.Message, StackTrace = ex.StackTrace, DateCreated = DateTime.Now }); 44 | _loggingRepository.Commit(); 45 | } 46 | 47 | await _next.Invoke(context); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Core/GenericResult.cs: -------------------------------------------------------------------------------- 1 | namespace PhotoGallery.Infrastructure.Core 2 | { 3 | public class GenericResult 4 | { 5 | public bool Succeeded { get; set; } 6 | public string Message { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Core/MembershipContext.cs: -------------------------------------------------------------------------------- 1 | using PhotoGallery.Entities; 2 | using System.Security.Principal; 3 | 4 | namespace PhotoGallery.Infrastructure 5 | { 6 | public class MembershipContext 7 | { 8 | public IPrincipal Principal { get; set; } 9 | public User User { get; set; } 10 | public bool IsValid() 11 | { 12 | return Principal != null; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Core/PaginationSet.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace PhotoGallery.Infrastructure.Core 5 | { 6 | public class PaginationSet 7 | { 8 | public int Page { get; set; } 9 | 10 | public int Count 11 | { 12 | get 13 | { 14 | return (null != this.Items) ? this.Items.Count() : 0; 15 | } 16 | } 17 | 18 | public int TotalPages { get; set; } 19 | public int TotalCount { get; set; } 20 | 21 | public IEnumerable Items { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Core/StatusCodeResult.cs: -------------------------------------------------------------------------------- 1 | namespace PhotoGallery.Infrastructure.Core 2 | { 3 | public class CodeResultStatus 4 | { 5 | private int _status; 6 | private string _message; 7 | public int Status { 8 | get 9 | { 10 | return _status; 11 | } 12 | private set { } 13 | } 14 | public string Message 15 | { 16 | get 17 | { 18 | return _message; 19 | } 20 | private set { } 21 | } 22 | 23 | public CodeResultStatus(int status) 24 | { 25 | if (status == 401) 26 | _message = "Unauthorized access. Login required"; 27 | 28 | _status = status; 29 | } 30 | 31 | public CodeResultStatus(int code, string message) 32 | { 33 | _status = code; 34 | _message = message; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/DbInitializer.cs: -------------------------------------------------------------------------------- 1 | using PhotoGallery.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.IO; 6 | 7 | namespace PhotoGallery.Infrastructure 8 | { 9 | public static class DbInitializer 10 | { 11 | private static PhotoGalleryContext context; 12 | public static void Initialize(IServiceProvider serviceProvider, string imagesPath) 13 | { 14 | context = (PhotoGalleryContext)serviceProvider.GetService(typeof(PhotoGalleryContext)); 15 | 16 | InitializePhotoAlbums(imagesPath); 17 | InitializeUserRoles(); 18 | 19 | } 20 | 21 | private static void InitializePhotoAlbums(string imagesPath) 22 | { 23 | if (!context.Albums.Any()) 24 | { 25 | List _albums = new List(); 26 | 27 | var _album1 = context.Albums.Add( 28 | new Album 29 | { 30 | DateCreated = DateTime.Now, 31 | Title = "Album 1", 32 | Description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." 33 | }).Entity; 34 | var _album2 = context.Albums.Add( 35 | new Album 36 | { 37 | DateCreated = DateTime.Now, 38 | Title = "Album 2", 39 | Description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." 40 | }).Entity; 41 | var _album3 = context.Albums.Add( 42 | new Album 43 | { 44 | DateCreated = DateTime.Now, 45 | Title = "Album 3", 46 | Description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." 47 | }).Entity; 48 | var _album4 = context.Albums.Add( 49 | new Album 50 | { 51 | DateCreated = DateTime.Now, 52 | Title = "Album 4", 53 | Description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." 54 | }).Entity; 55 | 56 | _albums.Add(_album1); _albums.Add(_album2); _albums.Add(_album3); _albums.Add(_album4); 57 | 58 | string[] _images = Directory.GetFiles(Path.Combine(imagesPath, "images")); 59 | Random rnd = new Random(); 60 | 61 | foreach (string _image in _images) 62 | { 63 | int _selectedAlbum = rnd.Next(1, 4); 64 | string _fileName = Path.GetFileName(_image); 65 | 66 | context.Photos.Add( 67 | new Photo() 68 | { 69 | Title = _fileName, 70 | DateUploaded = DateTime.Now, 71 | Uri = _fileName, 72 | Album = _albums.ElementAt(_selectedAlbum) 73 | } 74 | ); 75 | } 76 | 77 | context.SaveChanges(); 78 | } 79 | } 80 | 81 | private static void InitializeUserRoles() 82 | { 83 | if (!context.Roles.Any()) 84 | { 85 | // create roles 86 | context.Roles.AddRange(new Role[] 87 | { 88 | new Role() 89 | { 90 | Name="Admin" 91 | } 92 | }); 93 | 94 | context.SaveChanges(); 95 | } 96 | 97 | if (!context.Users.Any()) 98 | { 99 | context.Users.Add(new User() 100 | { 101 | Email = "chsakells.blog@gmail.com", 102 | Username = "chsakell", 103 | HashedPassword = "9wsmLgYM5Gu4zA/BSpxK2GIBEWzqMPKs8wl2WDBzH/4=", 104 | Salt = "GTtKxJA6xJuj3ifJtTXn9Q==", 105 | IsLocked = false, 106 | DateCreated = DateTime.Now 107 | }); 108 | 109 | // create user-admin for chsakell 110 | context.UserRoles.AddRange(new UserRole[] { 111 | new UserRole() { 112 | RoleId = 1, // admin 113 | UserId = 1 // chsakell 114 | } 115 | }); 116 | context.SaveChanges(); 117 | } 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Mappings/AutoMapperConfiguration.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | 3 | namespace PhotoGallery.Infrastructure.Mappings 4 | { 5 | public class AutoMapperConfiguration 6 | { 7 | public static void Configure() 8 | { 9 | Mapper.Initialize(x => 10 | { 11 | x.AddProfile(); 12 | //x.AddProfile(); 13 | }); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Mappings/DomainToViewModelMappingProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using PhotoGallery.Entities; 3 | using PhotoGallery.ViewModels; 4 | using System.Linq; 5 | 6 | namespace PhotoGallery.Infrastructure.Mappings 7 | { 8 | public class DomainToViewModelMappingProfile : Profile 9 | { 10 | protected override void Configure() 11 | { 12 | Mapper.CreateMap() 13 | .ForMember(vm => vm.Uri, map => map.MapFrom(p => "/images/" + p.Uri)); 14 | 15 | Mapper.CreateMap() 16 | .ForMember(vm => vm.TotalPhotos, map => map.MapFrom(a => a.Photos.Count)) 17 | .ForMember(vm => vm.Thumbnail, map => 18 | map.MapFrom(a => (a.Photos != null && a.Photos.Count > 0) ? 19 | "/images/" + a.Photos.First().Uri : 20 | "/images/thumbnail-default.png")); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/PhotoGalleryContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using PhotoGallery.Entities; 3 | using Microsoft.EntityFrameworkCore.Internal; 4 | using Microsoft.EntityFrameworkCore.Metadata.Internal; 5 | 6 | namespace PhotoGallery.Infrastructure 7 | { 8 | public class PhotoGalleryContext : DbContext 9 | { 10 | public DbSet Photos { get; set; } 11 | public DbSet Albums { get; set; } 12 | public DbSet Users { get; set; } 13 | public DbSet Roles { get; set; } 14 | public DbSet UserRoles { get; set; } 15 | public DbSet Errors { get; set; } 16 | 17 | public PhotoGalleryContext(DbContextOptions options) : base(options) 18 | { 19 | } 20 | 21 | protected override void OnModelCreating(ModelBuilder modelBuilder) 22 | { 23 | foreach (var entity in modelBuilder.Model.GetEntityTypes()) 24 | { 25 | entity.Relational().TableName = entity.DisplayName(); 26 | } 27 | 28 | // Photos 29 | modelBuilder.Entity().Property(p => p.Title).HasMaxLength(100); 30 | modelBuilder.Entity().Property(p => p.AlbumId).IsRequired(); 31 | 32 | // Album 33 | modelBuilder.Entity().Property(a => a.Title).HasMaxLength(100); 34 | modelBuilder.Entity().Property(a => a.Description).HasMaxLength(500); 35 | modelBuilder.Entity().HasMany(a => a.Photos).WithOne(p => p.Album); 36 | 37 | // User 38 | modelBuilder.Entity().Property(u => u.Username).IsRequired().HasMaxLength(100); 39 | modelBuilder.Entity().Property(u => u.Email).IsRequired().HasMaxLength(200); 40 | modelBuilder.Entity().Property(u => u.HashedPassword).IsRequired().HasMaxLength(200); 41 | modelBuilder.Entity().Property(u => u.Salt).IsRequired().HasMaxLength(200); 42 | 43 | // UserRole 44 | modelBuilder.Entity().Property(ur => ur.UserId).IsRequired(); 45 | modelBuilder.Entity().Property(ur => ur.RoleId).IsRequired(); 46 | 47 | // Role 48 | modelBuilder.Entity().Property(r => r.Name).IsRequired().HasMaxLength(50); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Repositories/Abstract/IEntityBaseRepository.cs: -------------------------------------------------------------------------------- 1 | using PhotoGallery.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq.Expressions; 5 | using System.Threading.Tasks; 6 | 7 | namespace PhotoGallery.Infrastructure.Repositories 8 | { 9 | public interface IEntityBaseRepository where T : class, IEntityBase, new() 10 | { 11 | IEnumerable AllIncluding(params Expression>[] includeProperties); 12 | Task> AllIncludingAsync(params Expression>[] includeProperties); 13 | IEnumerable GetAll(); 14 | Task> GetAllAsync(); 15 | T GetSingle(int id); 16 | T GetSingle(Expression> predicate); 17 | T GetSingle(Expression> predicate, params Expression>[] includeProperties); 18 | Task GetSingleAsync(int id); 19 | IEnumerable FindBy(Expression> predicate); 20 | Task> FindByAsync(Expression> predicate); 21 | void Add(T entity); 22 | void Delete(T entity); 23 | void Edit(T entity); 24 | void Commit(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Repositories/Abstract/IRepositories.cs: -------------------------------------------------------------------------------- 1 | using PhotoGallery.Entities; 2 | using System.Collections.Generic; 3 | 4 | namespace PhotoGallery.Infrastructure.Repositories 5 | { 6 | public interface IAlbumRepository : IEntityBaseRepository { } 7 | 8 | public interface ILoggingRepository : IEntityBaseRepository { } 9 | 10 | public interface IPhotoRepository : IEntityBaseRepository { } 11 | 12 | public interface IRoleRepository : IEntityBaseRepository { } 13 | 14 | public interface IUserRepository : IEntityBaseRepository 15 | { 16 | User GetSingleByUsername(string username); 17 | IEnumerable GetUserRoles(string username); 18 | } 19 | 20 | public interface IUserRoleRepository : IEntityBaseRepository { } 21 | } 22 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Repositories/AlbumRepository.cs: -------------------------------------------------------------------------------- 1 | using PhotoGallery.Entities; 2 | 3 | namespace PhotoGallery.Infrastructure.Repositories 4 | { 5 | public class AlbumRepository : EntityBaseRepository, IAlbumRepository 6 | { 7 | public AlbumRepository(PhotoGalleryContext context) 8 | : base(context) 9 | { } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Repositories/EntityBaseRepository.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.ChangeTracking; 3 | using PhotoGallery.Entities; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Linq.Expressions; 8 | using System.Threading.Tasks; 9 | 10 | namespace PhotoGallery.Infrastructure.Repositories 11 | { 12 | public class EntityBaseRepository : IEntityBaseRepository 13 | where T : class, IEntityBase, new() 14 | { 15 | 16 | private PhotoGalleryContext _context; 17 | 18 | #region Properties 19 | public EntityBaseRepository(PhotoGalleryContext context) 20 | { 21 | _context = context; 22 | } 23 | #endregion 24 | public virtual IEnumerable GetAll() 25 | { 26 | return _context.Set().AsEnumerable(); 27 | } 28 | 29 | public virtual async Task> GetAllAsync() 30 | { 31 | return await _context.Set().ToListAsync(); 32 | } 33 | public virtual IEnumerable AllIncluding(params Expression>[] includeProperties) 34 | { 35 | IQueryable query = _context.Set(); 36 | foreach (var includeProperty in includeProperties) 37 | { 38 | query = query.Include(includeProperty); 39 | } 40 | return query.AsEnumerable(); 41 | } 42 | 43 | public virtual async Task> AllIncludingAsync(params Expression>[] includeProperties) 44 | { 45 | IQueryable query = _context.Set(); 46 | foreach (var includeProperty in includeProperties) 47 | { 48 | query = query.Include(includeProperty); 49 | } 50 | return await query.ToListAsync(); 51 | } 52 | public T GetSingle(int id) 53 | { 54 | return _context.Set().FirstOrDefault(x => x.Id == id); 55 | } 56 | 57 | public T GetSingle(Expression> predicate) 58 | { 59 | return _context.Set().FirstOrDefault(predicate); 60 | } 61 | 62 | public T GetSingle(Expression> predicate, params Expression>[] includeProperties) 63 | { 64 | IQueryable query = _context.Set(); 65 | foreach (var includeProperty in includeProperties) 66 | { 67 | query = query.Include(includeProperty); 68 | } 69 | 70 | return query.Where(predicate).FirstOrDefault(); 71 | } 72 | 73 | public async Task GetSingleAsync(int id) 74 | { 75 | return await _context.Set().FirstOrDefaultAsync(e => e.Id == id); 76 | } 77 | public virtual IEnumerable FindBy(Expression> predicate) 78 | { 79 | return _context.Set().Where(predicate); 80 | } 81 | 82 | public virtual async Task> FindByAsync(Expression> predicate) 83 | { 84 | return await _context.Set().Where(predicate).ToListAsync(); 85 | } 86 | 87 | public virtual void Add(T entity) 88 | { 89 | EntityEntry dbEntityEntry = _context.Entry(entity); 90 | _context.Set().Add(entity); 91 | } 92 | 93 | public virtual void Edit(T entity) 94 | { 95 | EntityEntry dbEntityEntry = _context.Entry(entity); 96 | dbEntityEntry.State = EntityState.Modified; 97 | } 98 | public virtual void Delete(T entity) 99 | { 100 | EntityEntry dbEntityEntry = _context.Entry(entity); 101 | dbEntityEntry.State = EntityState.Deleted; 102 | } 103 | 104 | public virtual void Commit() 105 | { 106 | _context.SaveChanges(); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Repositories/ErrorRepository.cs: -------------------------------------------------------------------------------- 1 | using PhotoGallery.Entities; 2 | 3 | namespace PhotoGallery.Infrastructure.Repositories 4 | { 5 | public class LoggingRepository : EntityBaseRepository, ILoggingRepository 6 | { 7 | public LoggingRepository(PhotoGalleryContext context) 8 | : base(context) 9 | { } 10 | 11 | public override void Commit() 12 | { 13 | try 14 | { 15 | base.Commit(); 16 | } 17 | catch { } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Repositories/PhotoRepository.cs: -------------------------------------------------------------------------------- 1 | using PhotoGallery.Entities; 2 | 3 | namespace PhotoGallery.Infrastructure.Repositories 4 | { 5 | public class PhotoRepository : EntityBaseRepository, IPhotoRepository 6 | { 7 | public PhotoRepository(PhotoGalleryContext context) 8 | : base(context) 9 | { } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Repositories/RoleRepository.cs: -------------------------------------------------------------------------------- 1 | using PhotoGallery.Entities; 2 | 3 | namespace PhotoGallery.Infrastructure.Repositories 4 | { 5 | public class RoleRepository : EntityBaseRepository, IRoleRepository 6 | { 7 | public RoleRepository(PhotoGalleryContext context) 8 | : base(context) 9 | { } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Repositories/UserRepository.cs: -------------------------------------------------------------------------------- 1 | using PhotoGallery.Entities; 2 | using System.Collections.Generic; 3 | 4 | namespace PhotoGallery.Infrastructure.Repositories 5 | { 6 | public class UserRepository : EntityBaseRepository, IUserRepository 7 | { 8 | IRoleRepository _roleReposistory; 9 | public UserRepository(PhotoGalleryContext context, IRoleRepository roleReposistory) 10 | : base(context) 11 | { 12 | _roleReposistory = roleReposistory; 13 | } 14 | 15 | public User GetSingleByUsername(string username) 16 | { 17 | return this.GetSingle(x => x.Username == username); 18 | } 19 | 20 | public IEnumerable GetUserRoles(string username) 21 | { 22 | List _roles = null; 23 | 24 | User _user = this.GetSingle(u => u.Username == username, u => u.UserRoles); 25 | if(_user != null) 26 | { 27 | _roles = new List(); 28 | foreach (var _userRole in _user.UserRoles) 29 | _roles.Add(_roleReposistory.GetSingle(_userRole.RoleId)); 30 | } 31 | 32 | return _roles; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Repositories/UserRoleRepository.cs: -------------------------------------------------------------------------------- 1 | using PhotoGallery.Entities; 2 | 3 | namespace PhotoGallery.Infrastructure.Repositories 4 | { 5 | public class UserRoleRepository : EntityBaseRepository, IUserRoleRepository 6 | { 7 | public UserRoleRepository(PhotoGalleryContext context) 8 | : base(context) 9 | { } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Services/Abstract/IEncryptionService.cs: -------------------------------------------------------------------------------- 1 | namespace PhotoGallery.Infrastructure.Services 2 | { 3 | public interface IEncryptionService 4 | { 5 | /// 6 | /// Creates a random salt 7 | /// 8 | /// 9 | string CreateSalt(); 10 | /// 11 | /// Generates a Hashed password 12 | /// 13 | /// 14 | /// 15 | /// 16 | string EncryptPassword(string password, string salt); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Services/Abstract/IMembershipService.cs: -------------------------------------------------------------------------------- 1 | using PhotoGallery.Entities; 2 | using System.Collections.Generic; 3 | 4 | namespace PhotoGallery.Infrastructure.Services 5 | { 6 | public interface IMembershipService 7 | { 8 | MembershipContext ValidateUser(string username, string password); 9 | User CreateUser(string username, string email, string password, int[] roles); 10 | User GetUser(int userId); 11 | List GetUserRoles(string username); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Services/EncryptionService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | using System.Text; 4 | 5 | namespace PhotoGallery.Infrastructure.Services 6 | { 7 | public class EncryptionService : IEncryptionService 8 | { 9 | public string CreateSalt() 10 | { 11 | var data = new byte[0x10]; 12 | 13 | var cryptoServiceProvider = System.Security.Cryptography.RandomNumberGenerator.Create(); 14 | cryptoServiceProvider.GetBytes(data); 15 | return Convert.ToBase64String(data); 16 | } 17 | 18 | public string EncryptPassword(string password, string salt) 19 | { 20 | using (var sha256 = SHA256.Create()) 21 | { 22 | var saltedPassword = string.Format("{0}{1}", salt, password); 23 | byte[] saltedPasswordAsBytes = Encoding.UTF8.GetBytes(saltedPassword); 24 | return Convert.ToBase64String(sha256.ComputeHash(saltedPasswordAsBytes)); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/PhotoGallery/Infrastructure/Services/MembershipService.cs: -------------------------------------------------------------------------------- 1 | using PhotoGallery.Entities; 2 | using PhotoGallery.Infrastructure.Repositories; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Security.Principal; 7 | 8 | namespace PhotoGallery.Infrastructure.Services 9 | { 10 | public class MembershipService : IMembershipService 11 | { 12 | #region Variables 13 | private readonly IUserRepository _userRepository; 14 | private readonly IRoleRepository _roleRepository; 15 | private readonly IUserRoleRepository _userRoleRepository; 16 | private readonly IEncryptionService _encryptionService; 17 | #endregion 18 | public MembershipService(IUserRepository userRepository, IRoleRepository roleRepository, 19 | IUserRoleRepository userRoleRepository, IEncryptionService encryptionService) 20 | { 21 | _userRepository = userRepository; 22 | _roleRepository = roleRepository; 23 | _userRoleRepository = userRoleRepository; 24 | _encryptionService = encryptionService; 25 | } 26 | 27 | #region IMembershipService Implementation 28 | 29 | public MembershipContext ValidateUser(string username, string password) 30 | { 31 | var membershipCtx = new MembershipContext(); 32 | 33 | var user = _userRepository.GetSingleByUsername(username); 34 | if (user != null && isUserValid(user, password)) 35 | { 36 | var userRoles = GetUserRoles(user.Username); 37 | membershipCtx.User = user; 38 | 39 | var identity = new GenericIdentity(user.Username); 40 | membershipCtx.Principal = new GenericPrincipal( 41 | identity, 42 | userRoles.Select(x => x.Name).ToArray()); 43 | } 44 | 45 | return membershipCtx; 46 | } 47 | public User CreateUser(string username, string email, string password, int[] roles) 48 | { 49 | var existingUser = _userRepository.GetSingleByUsername(username); 50 | 51 | if (existingUser != null) 52 | { 53 | throw new Exception("Username is already in use"); 54 | } 55 | 56 | var passwordSalt = _encryptionService.CreateSalt(); 57 | 58 | var user = new User() 59 | { 60 | Username = username, 61 | Salt = passwordSalt, 62 | Email = email, 63 | IsLocked = false, 64 | HashedPassword = _encryptionService.EncryptPassword(password, passwordSalt), 65 | DateCreated = DateTime.Now 66 | }; 67 | 68 | _userRepository.Add(user); 69 | 70 | _userRepository.Commit(); 71 | 72 | if (roles != null || roles.Length > 0) 73 | { 74 | foreach (var role in roles) 75 | { 76 | addUserToRole(user, role); 77 | } 78 | } 79 | 80 | _userRepository.Commit(); 81 | 82 | return user; 83 | } 84 | 85 | public User GetUser(int userId) 86 | { 87 | return _userRepository.GetSingle(userId); 88 | } 89 | 90 | public List GetUserRoles(string username) 91 | { 92 | List _result = new List(); 93 | 94 | var existingUser = _userRepository.GetSingleByUsername(username); 95 | 96 | if (existingUser != null) 97 | { 98 | foreach (var userRole in existingUser.UserRoles) 99 | { 100 | _result.Add(userRole.Role); 101 | } 102 | } 103 | 104 | return _result.Distinct().ToList(); 105 | } 106 | #endregion 107 | 108 | #region Helper methods 109 | private void addUserToRole(User user, int roleId) 110 | { 111 | var role = _roleRepository.GetSingle(roleId); 112 | if (role == null) 113 | throw new Exception("Role doesn't exist."); 114 | 115 | var userRole = new UserRole() 116 | { 117 | RoleId = role.Id, 118 | UserId = user.Id 119 | }; 120 | _userRoleRepository.Add(userRole); 121 | 122 | _userRepository.Commit(); 123 | } 124 | 125 | private bool isPasswordValid(User user, string password) 126 | { 127 | return string.Equals(_encryptionService.EncryptPassword(password, user.Salt), user.HashedPassword); 128 | } 129 | 130 | private bool isUserValid(User user, string password) 131 | { 132 | if (isPasswordValid(user, password)) 133 | { 134 | return !user.IsLocked; 135 | } 136 | 137 | return false; 138 | } 139 | #endregion 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/PhotoGallery/PhotoGallery.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 1.1.0 5 | netcoreapp1.1 6 | portable 7 | true 8 | PhotoGallery 9 | Exe 10 | PhotoGallery 11 | PhotoGallery 12 | win10-x64;win81-x64;win8-x64;win7-x64 13 | 1.1.1 14 | $(PackageTargetFallback);dotnet5.6;dnxcore50;portable-net45+win8 15 | 3.1 16 | 17 | 18 | PhotoGallery 19 | 20 | 21 | 22 | 23 | PreserveNewest 24 | 25 | 26 | Never 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | All 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/PhotoGallery/Project_Readme.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Welcome to ASP.NET 5 6 | 127 | 128 | 129 | 130 | 138 | 139 |
    140 |
    141 |

    This application consists of:

    142 |
      143 |
    • Sample pages using ASP.NET MVC 6
    • 144 |
    • Gulp and Bower for managing client-side libraries
    • 145 |
    • Theming using Bootstrap
    • 146 |
    147 |
    148 | 160 | 172 | 181 | 182 | 185 |
    186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /src/PhotoGallery/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:9823/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "$safeprojectname$": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "launchUrl": "http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/PhotoGallery/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Configuration; 5 | using PhotoGallery.Infrastructure; 6 | using Microsoft.EntityFrameworkCore; 7 | using PhotoGallery.Infrastructure.Repositories; 8 | using PhotoGallery.Infrastructure.Services; 9 | using PhotoGallery.Infrastructure.Mappings; 10 | using System.Security.Claims; 11 | using System.IO; 12 | using Newtonsoft.Json.Serialization; 13 | 14 | namespace PhotoGallery 15 | { 16 | public class Startup 17 | { 18 | private static string _applicationPath = string.Empty; 19 | private static string _contentRootPath = string.Empty; 20 | public Startup(IHostingEnvironment env) 21 | { 22 | _applicationPath = env.WebRootPath; 23 | _contentRootPath = env.ContentRootPath; 24 | // Setup configuration sources. 25 | 26 | var builder = new ConfigurationBuilder() 27 | .SetBasePath(_contentRootPath) 28 | .AddJsonFile("appsettings.json") 29 | .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); 30 | 31 | if (env.IsDevelopment()) 32 | { 33 | // This reads the configuration keys from the secret store. 34 | // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709 35 | builder.AddUserSecrets(); 36 | } 37 | builder.AddEnvironmentVariables(); 38 | Configuration = builder.Build(); 39 | } 40 | 41 | public IConfigurationRoot Configuration { get; set; } 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 http://go.microsoft.com/fwlink/?LinkID=398940 44 | public void ConfigureServices(IServiceCollection services) 45 | { 46 | string sqlConnectionString = Configuration["ConnectionStrings:DefaultConnection"]; 47 | bool useInMemoryProvider = bool.Parse(Configuration["Data:PhotoGalleryConnection:InMemoryProvider"]); 48 | 49 | services.AddDbContext(options => { 50 | switch (useInMemoryProvider) 51 | { 52 | case true: 53 | options.UseInMemoryDatabase(); 54 | break; 55 | default: 56 | options.UseSqlServer(sqlConnectionString); 57 | break; 58 | } 59 | }); 60 | 61 | // Repositories 62 | services.AddScoped(); 63 | services.AddScoped(); 64 | services.AddScoped(); 65 | services.AddScoped(); 66 | services.AddScoped(); 67 | services.AddScoped(); 68 | 69 | // Services 70 | services.AddScoped(); 71 | services.AddScoped(); 72 | 73 | services.AddAuthentication(); 74 | 75 | // Polices 76 | services.AddAuthorization(options => 77 | { 78 | // inline policies 79 | options.AddPolicy("AdminOnly", policy => 80 | { 81 | policy.RequireClaim(ClaimTypes.Role, "Admin"); 82 | }); 83 | 84 | }); 85 | 86 | // Add MVC services to the services container. 87 | services.AddMvc() 88 | .AddJsonOptions(opt => 89 | { 90 | var resolver = opt.SerializerSettings.ContractResolver; 91 | if (resolver != null) 92 | { 93 | var res = resolver as DefaultContractResolver; 94 | res.NamingStrategy = null; 95 | } 96 | }); 97 | } 98 | 99 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 100 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 101 | { 102 | // this will serve up wwwroot 103 | app.UseStaticFiles(); 104 | 105 | AutoMapperConfiguration.Configure(); 106 | 107 | app.UseCookieAuthentication(new CookieAuthenticationOptions 108 | { 109 | AutomaticAuthenticate = true, 110 | AutomaticChallenge = true 111 | }); 112 | 113 | // Custom authentication middleware 114 | //app.UseMiddleware(); 115 | 116 | // Add MVC to the request pipeline. 117 | app.UseMvc(routes => 118 | { 119 | routes.MapRoute( 120 | name: "default", 121 | template: "{controller=Home}/{action=Index}/{id?}"); 122 | 123 | // Uncomment the following line to add a route for porting Web API 2 controllers. 124 | //routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}"); 125 | }); 126 | 127 | DbInitializer.Initialize(app.ApplicationServices, _applicationPath); 128 | } 129 | 130 | // Entry point for the application. 131 | public static void Main(string[] args) 132 | { 133 | var host = new WebHostBuilder() 134 | .UseKestrel() 135 | .UseContentRoot(Directory.GetCurrentDirectory()) 136 | .UseIISIntegration() 137 | .UseStartup() 138 | .Build(); 139 | 140 | host.Run(); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/PhotoGallery/ViewModels/AlbumViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PhotoGallery.ViewModels 4 | { 5 | public class AlbumViewModel 6 | { 7 | public int Id { get; set; } 8 | public string Title { get; set; } 9 | public string Description { get; set; } 10 | public string Thumbnail { get; set; } 11 | public DateTime DateCreated { get; set; } 12 | public int TotalPhotos { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/PhotoGallery/ViewModels/LoginViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace PhotoGallery.ViewModels 2 | { 3 | public class LoginViewModel 4 | { 5 | public string Username { get; set; } 6 | public string Password { get; set; } 7 | public bool RememberMe { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/PhotoGallery/ViewModels/PhotoViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PhotoGallery.ViewModels 4 | { 5 | public class PhotoViewModel 6 | { 7 | public int Id { get; set; } 8 | public string Title { get; set; } 9 | public string Uri { get; set; } 10 | public int AlbumId { get; set; } 11 | public string AlbumTitle { get; set; } 12 | 13 | public DateTime DateUploaded { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/PhotoGallery/ViewModels/RegistrationViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace PhotoGallery.ViewModels 4 | { 5 | public class RegistrationViewModel 6 | { 7 | [Required] 8 | public string Username { get; set; } 9 | [Required] 10 | public string Password { get; set; } 11 | [Required] 12 | [EmailAddress] 13 | public string Email { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/PhotoGallery/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "PhotoGallery"; 3 | } 4 | 5 | @section styles 6 | { 7 | 8 | 9 | 10 | 11 | 12 | @**@ 13 | } 14 | 15 | 16 | 17 | 18 |
    Loading
    19 |
    20 | 21 | @section scripts 22 | { 23 | 24 | 25 | } 26 | 27 | @section customScript 28 | { 29 | System.import('app').catch(console.log.bind(console)); 30 | $(document).ready(function() { 31 | $('.fancybox').fancybox(); 32 | }); 33 | } -------------------------------------------------------------------------------- /src/PhotoGallery/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | @ViewBag.Title 9 | 10 | 11 | 12 | 13 | @RenderSection("styles", required: false) 14 | 15 | @*Solve IE 11 issues *@ 16 | @* 17 | 18 | *@ 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
    33 | @RenderBody() 34 |
    35 | 36 | @RenderSection("scripts", required: false) 37 | 40 | 41 | -------------------------------------------------------------------------------- /src/PhotoGallery/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /src/PhotoGallery/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=PhotoGallery;Trusted_Connection=True;MultipleActiveResultSets=true" 4 | }, 5 | "Data": { 6 | "PhotoGalleryConnection": { 7 | "InMemoryProvider": false 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/PhotoGallery/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ASP.NET", 3 | "private": true, 4 | "dependencies": { 5 | "bootstrap": "3.3.6", 6 | "components-font-awesome": "4.5.0", 7 | "alertify.js": "0.3.11" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/PhotoGallery/gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | ts = require('gulp-typescript'), 3 | merge = require('merge'), 4 | fs = require("fs"), 5 | del = require('del'), 6 | path = require('path'); 7 | 8 | var lib = "./wwwroot/lib/"; 9 | 10 | var paths = { 11 | npm: './node_modules/', 12 | tsSource: './wwwroot/app/**/*.ts', 13 | tsOutput: lib + 'spa/', 14 | tsDef: lib + 'definitions/', 15 | jsVendors: lib + 'js', 16 | jsRxJSVendors: lib + 'js/rxjs', 17 | cssVendors: lib + 'css', 18 | imgVendors: lib + 'img', 19 | fontsVendors: lib + 'fonts' 20 | }; 21 | 22 | 23 | var tsProject = ts.createProject('./wwwroot/tsconfig.json'); 24 | 25 | gulp.task('setup-vendors', function (done) { 26 | gulp.src([ 27 | 'node_modules/jquery/dist/jquery.*js', 28 | 'bower_components/bootstrap/dist/js/bootstrap*.js', 29 | 'node_modules/fancybox/dist/js/jquery.fancybox.pack.js', 30 | 'bower_components/alertify.js/lib/alertify.min.js', 31 | 'systemjs.config.js' 32 | ]).pipe(gulp.dest(paths.jsVendors)); 33 | 34 | gulp.src([ 35 | 'bower_components/bootstrap/dist/css/bootstrap.css', 36 | 'node_modules/fancybox/dist/css/jquery.fancybox.css', 37 | 'bower_components/components-font-awesome/css/font-awesome.css', 38 | 'bower_components/alertify.js/themes/alertify.core.css', 39 | 'bower_components/alertify.js/themes/alertify.bootstrap.css', 40 | 'bower_components/alertify.js/themes/alertify.default.css' 41 | ]).pipe(gulp.dest(paths.cssVendors)); 42 | 43 | gulp.src([ 44 | 'node_modules/fancybox/dist/img/blank.gif', 45 | 'node_modules/fancybox/dist/img/fancybox_loading.gif', 46 | 'node_modules/fancybox/dist/img/fancybox_loading@2x.gif', 47 | 'node_modules/fancybox/dist/img/fancybox_overlay.png', 48 | 'node_modules/fancybox/dist/img/fancybox_sprite.png', 49 | 'node_modules/fancybox/dist/img/fancybox_sprite@2x.png' 50 | ]).pipe(gulp.dest(paths.imgVendors)); 51 | 52 | gulp.src([ 53 | 'node_modules/bootstrap/fonts/glyphicons-halflings-regular.eot', 54 | 'node_modules/bootstrap/fonts/glyphicons-halflings-regular.svg', 55 | 'node_modules/bootstrap/fonts/glyphicons-halflings-regular.ttf', 56 | 'node_modules/bootstrap/fonts/glyphicons-halflings-regular.woff', 57 | 'node_modules/bootstrap/fonts/glyphicons-halflings-regular.woff2', 58 | 'bower_components/components-font-awesome/fonts/FontAwesome.otf', 59 | 'bower_components/components-font-awesome/fonts/fontawesome-webfont.eot', 60 | 'bower_components/components-font-awesome/fonts/fontawesome-webfont.svg', 61 | 'bower_components/components-font-awesome/fonts/fontawesome-webfont.ttf', 62 | 'bower_components/components-font-awesome/fonts/fontawesome-webfont.woff', 63 | 'bower_components/components-font-awesome/fonts/fontawesome-webfont.woff2', 64 | ]).pipe(gulp.dest(paths.fontsVendors)); 65 | 66 | gulp.src('node_modules/' + "@angular/**/*.js", 67 | { base: 'node_modules/' + "@angular/" }) 68 | .pipe(gulp.dest(lib + "@angular/")); 69 | 70 | gulp.src('node_modules/' + "angular2-in-memory-web-api/*.js", 71 | { base: 'node_modules/' }) 72 | .pipe(gulp.dest(lib)); 73 | 74 | gulp.src('node_modules/' + "core-js/client/shim*.js", 75 | { base: 'node_modules/' }) 76 | .pipe(gulp.dest(lib)); 77 | 78 | gulp.src('node_modules/' + "zone.js/dist/zone*.js", 79 | { base: 'node_modules/' }) 80 | .pipe(gulp.dest(lib)); 81 | 82 | gulp.src('node_modules/' + "reflect-metadata/Reflect*.js", 83 | { base: 'node_modules/' }) 84 | .pipe(gulp.dest(lib)); 85 | 86 | gulp.src('node_modules/' + "systemjs/dist/*.js", 87 | { base: 'node_modules/' }) 88 | .pipe(gulp.dest(lib)); 89 | 90 | gulp.src('node_modules/' + "rxjs/**/*.js", 91 | { base: 'node_modules/' }) 92 | .pipe(gulp.dest(lib)); 93 | }); 94 | 95 | gulp.task('compile-typescript', function (done) { 96 | var tsResult = gulp.src([ 97 | "wwwroot/app/**/*.ts" 98 | ]) 99 | .pipe((tsProject()), undefined, ts.reporter.fullReporter()); 100 | return tsResult.js.pipe(gulp.dest(paths.tsOutput)); 101 | }); 102 | 103 | gulp.task('watch.ts', ['compile-typescript'], function () { 104 | return gulp.watch('wwwroot/app/**/*.ts', ['compile-typescript']); 105 | }); 106 | 107 | gulp.task('watch', ['watch.ts']); 108 | 109 | gulp.task('clean-lib', function () { 110 | return del([lib]); 111 | }); 112 | 113 | gulp.task('build-spa', ['setup-vendors', 'compile-typescript']); -------------------------------------------------------------------------------- /src/PhotoGallery/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0", 3 | "name": "photogallery", 4 | "author": "Chris Sakellarios", 5 | "license": "MIT", 6 | "repository": "https://github.com/chsakell/aspnet5-angular2-typescript", 7 | "private": true, 8 | "dependencies": { 9 | "@angular/common": "4.0.2", 10 | "@angular/compiler": "4.0.2", 11 | "@angular/core": "4.0.2", 12 | "@angular/forms": "4.0.2", 13 | "@angular/http": "4.0.2", 14 | "@angular/platform-browser": "4.0.2", 15 | "@angular/platform-browser-dynamic": "4.0.2", 16 | "@angular/router": "4.0.2", 17 | "body-parser": "1.14.1", 18 | "bootstrap": "3.3.5", 19 | "es6-shim": "^0.35.0", 20 | "fancybox": "3.0.0", 21 | "jquery": "2.1.4", 22 | "angular-in-memory-web-api": "~0.2.4", 23 | "systemjs": "0.19.40", 24 | "core-js": "^2.4.1", 25 | "rxjs": "5.4.2", 26 | "zone.js": "^0.8.5", 27 | "reflect-metadata": "^0.1.8" 28 | }, 29 | "devDependencies": { 30 | "@types/node": "^6.0.46", 31 | "del": "2.1.0", 32 | "gulp": "^3.9.1", 33 | "gulp-typescript": "^3.1.6", 34 | "gulp-watch": "4.3.11", 35 | "merge": "1.2.0", 36 | "typescript": "2.4.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/PhotoGallery/runtimeconfig.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "gcServer": true, 3 | "gcConcurrent": true 4 | } -------------------------------------------------------------------------------- /src/PhotoGallery/systemjs.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * System configuration for Angular 2 samples 3 | * Adjust as necessary for your application needs. 4 | */ 5 | (function (global) { 6 | System.config({ 7 | paths: { 8 | // paths serve as alias 9 | 'npm:': 'lib/' 10 | }, 11 | // map tells the System loader where to look for things 12 | map: { 13 | // our app is within the app folder 14 | app: 'lib/spa', 15 | // angular bundles 16 | '@angular/core': 'npm:@angular/core/bundles/core.umd.js', 17 | '@angular/common': 'npm:@angular/common/bundles/common.umd.js', 18 | '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', 19 | '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', 20 | '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', 21 | '@angular/http': 'npm:@angular/http/bundles/http.umd.js', 22 | '@angular/router': 'npm:@angular/router/bundles/router.umd.js', 23 | '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', 24 | // other libraries 25 | 'rxjs': 'npm:rxjs', 26 | 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js' 27 | }, 28 | // packages tells the System loader how to load when no filename and/or no extension 29 | packages: { 30 | app: { 31 | main: './main.js', 32 | defaultExtension: 'js' 33 | }, 34 | rxjs: { 35 | defaultExtension: 'js' 36 | }, 37 | 'angular2-in-memory-web-api': { 38 | main: './index.js', 39 | defaultExtension: 'js' 40 | } 41 | } 42 | }); 43 | })(this); 44 | -------------------------------------------------------------------------------- /src/PhotoGallery/web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/app.component.html: -------------------------------------------------------------------------------- 1 |  2 | 55 | 56 |
    57 | 58 |
    -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Location } from '@angular/common'; 3 | import 'rxjs/add/operator/map'; 4 | import {enableProdMode} from '@angular/core'; 5 | 6 | enableProdMode(); 7 | import { MembershipService } from './core/services/membership.service'; 8 | import { User } from './core/domain/user'; 9 | 10 | @Component({ 11 | selector: 'photogallery-app', 12 | templateUrl: './app/app.component.html' 13 | }) 14 | export class AppComponent implements OnInit { 15 | 16 | constructor(public membershipService: MembershipService, 17 | public location: Location) { } 18 | 19 | ngOnInit() { } 20 | 21 | isUserLoggedIn(): boolean { 22 | return this.membershipService.isUserAuthenticated(); 23 | } 24 | 25 | getUserName(): string { 26 | if (this.isUserLoggedIn()) { 27 | var _user = this.membershipService.getLoggedInUser(); 28 | return _user.Username; 29 | } 30 | else 31 | return 'Account'; 32 | } 33 | 34 | logout(): void { 35 | this.membershipService.logout() 36 | .subscribe(res => { 37 | localStorage.removeItem('user'); 38 | }, 39 | error => console.error('Error: ' + error), 40 | () => { }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { HttpModule } from '@angular/http'; 4 | import { FormsModule } from '@angular/forms'; 5 | import { Location, LocationStrategy, HashLocationStrategy } from '@angular/common'; 6 | import { Headers, RequestOptions, BaseRequestOptions} from '@angular/http'; 7 | 8 | import { AccountModule } from './components/account/account.module'; 9 | import { AppComponent } from './app.component'; 10 | import { AlbumPhotosComponent } from './components/album-photos.component'; 11 | import { HomeComponent } from './components/home.component'; 12 | import { PhotosComponent } from './components/photos.component'; 13 | import { AlbumsComponent } from './components/albums.component'; 14 | import { routing } from './routes'; 15 | 16 | import { DataService } from './core/services/data.service'; 17 | import { MembershipService } from './core/services/membership.service'; 18 | import { UtilityService } from './core/services/utility.service'; 19 | import { NotificationService } from './core/services/notification.service'; 20 | 21 | class AppBaseRequestOptions extends BaseRequestOptions { 22 | headers: Headers = new Headers(); 23 | 24 | constructor() { 25 | super(); 26 | this.headers.append('Content-Type', 'application/json'); 27 | this.body = ''; 28 | } 29 | } 30 | 31 | @NgModule({ 32 | imports: [ 33 | BrowserModule, 34 | FormsModule, 35 | HttpModule, 36 | routing, 37 | AccountModule 38 | ], 39 | declarations: [AppComponent, AlbumPhotosComponent, HomeComponent, PhotosComponent, AlbumsComponent], 40 | providers: [DataService, MembershipService, UtilityService, NotificationService, 41 | { provide: LocationStrategy, useClass: HashLocationStrategy }, 42 | { provide: RequestOptions, useClass: AppBaseRequestOptions }], 43 | bootstrap: [AppComponent] 44 | }) 45 | export class AppModule { } 46 | 47 | -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/account/account.component.html: -------------------------------------------------------------------------------- 1 | 
    2 | 3 |
    -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/account/account.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core' 2 | 3 | @Component({ 4 | selector: 'account', 5 | templateUrl: './app/components/account/account.component.html' 6 | }) 7 | 8 | export class AccountComponent { 9 | constructor() { 10 | 11 | } 12 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/account/account.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { FormsModule } from '@angular/forms'; 3 | import { CommonModule } from '@angular/common'; 4 | 5 | import { DataService } from '../../core/services/data.service'; 6 | import { MembershipService } from '../../core/services/membership.service'; 7 | import { NotificationService } from '../../core/services/notification.service'; 8 | 9 | import { AccountComponent } from './account.component'; 10 | import { LoginComponent } from './login.component'; 11 | import { RegisterComponent } from './register.component'; 12 | 13 | import { accountRouting } from './routes'; 14 | 15 | @NgModule({ 16 | imports: [ 17 | CommonModule, 18 | FormsModule, 19 | accountRouting 20 | ], 21 | declarations: [ 22 | AccountComponent, 23 | LoginComponent, 24 | RegisterComponent 25 | ], 26 | 27 | providers: [ 28 | DataService, 29 | MembershipService, 30 | NotificationService 31 | ] 32 | }) 33 | export class AccountModule { } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/account/login.component.html: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/account/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { User } from '../../core/domain/user'; 4 | import { OperationResult } from '../../core/domain/operationResult'; 5 | import { MembershipService } from '../../core/services/membership.service'; 6 | import { NotificationService } from '../../core/services/notification.service'; 7 | 8 | @Component({ 9 | selector: 'albums', 10 | templateUrl: './app/components/account/login.component.html' 11 | }) 12 | export class LoginComponent implements OnInit { 13 | private _user: User; 14 | 15 | constructor(public membershipService: MembershipService, 16 | public notificationService: NotificationService, 17 | public router: Router) { } 18 | 19 | ngOnInit() { 20 | this._user = new User('', ''); 21 | } 22 | 23 | login(): void { 24 | var _authenticationResult: OperationResult = new OperationResult(false, ''); 25 | 26 | this.membershipService.login(this._user) 27 | .subscribe((res:any) => { 28 | _authenticationResult.Succeeded = res.Succeeded; 29 | _authenticationResult.Message = res.Message; 30 | }, 31 | error => console.error('Error: ' + error), 32 | () => { 33 | if (_authenticationResult.Succeeded) { 34 | this.notificationService.printSuccessMessage('Welcome back ' + this._user.Username + '!'); 35 | localStorage.setItem('user', JSON.stringify(this._user)); 36 | this.router.navigate(['home']); 37 | } 38 | else { 39 | this.notificationService.printErrorMessage(_authenticationResult.Message); 40 | } 41 | }); 42 | }; 43 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/account/register.component.html: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/account/register.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit} from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { Registration } from '../../core/domain/registration'; 4 | import { OperationResult } from '../../core/domain/operationResult'; 5 | import { MembershipService } from '../../core/services/membership.service'; 6 | import { NotificationService } from '../../core/services/notification.service'; 7 | 8 | @Component({ 9 | selector: 'register', 10 | providers: [MembershipService, NotificationService], 11 | templateUrl: './app/components/account/register.component.html' 12 | }) 13 | export class RegisterComponent implements OnInit { 14 | 15 | private _newUser: Registration; 16 | 17 | constructor(public membershipService: MembershipService, 18 | public notificationService: NotificationService, 19 | public router: Router) { } 20 | 21 | ngOnInit() { 22 | this._newUser = new Registration('', '', ''); 23 | } 24 | 25 | register(): void { 26 | var _registrationResult: OperationResult = new OperationResult(false, ''); 27 | this.membershipService.register(this._newUser) 28 | .subscribe((res:any) => { 29 | _registrationResult.Succeeded = res.Succeeded; 30 | _registrationResult.Message = res.Message; 31 | 32 | }, 33 | error => console.error('Error: ' + error), 34 | () => { 35 | if (_registrationResult.Succeeded) { 36 | this.notificationService.printSuccessMessage('Dear ' + this._newUser.Username + ', please login with your credentials'); 37 | this.router.navigate(['account/login']); 38 | } 39 | else { 40 | this.notificationService.printErrorMessage(_registrationResult.Message); 41 | } 42 | }); 43 | }; 44 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/account/routes.ts: -------------------------------------------------------------------------------- 1 | import { ModuleWithProviders } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { AccountComponent } from './account.component'; 5 | import { LoginComponent } from './login.component'; 6 | import { RegisterComponent } from './register.component'; 7 | 8 | export const accountRoutes: Routes = [ 9 | { 10 | path: 'account', 11 | component: AccountComponent, 12 | children: [ 13 | { path: 'register', component: RegisterComponent }, 14 | { path: 'login', component: LoginComponent } 15 | ] 16 | } 17 | ]; 18 | 19 | export const accountRouting: ModuleWithProviders = RouterModule.forChild(accountRoutes); -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/album-photos.component.html: -------------------------------------------------------------------------------- 1 | 
    2 |
    3 |
    4 |

    5 | {{_albumTitle}} 6 | Page {{_page + 1}} of {{_pagesCount}} 7 |

    8 | 18 |
    19 |
    20 | 21 |
    22 |
    23 |
    24 | 25 | 26 | 27 |
    28 |
    29 |
    {{convertDateTime(image.DateUploaded)}}
    30 |
    31 | 36 |
    37 |
    38 | {{image.Title}} 39 |
    40 |
    41 |
    42 |
    43 |
    44 | 45 |
    46 |
    47 |
    48 |
      49 |
    • <<
    • 50 |
    • <
    • 51 |
    • 52 | {{n+1}} 53 | {{n+1}} 54 |
    • 55 |
    • >
    • 56 |
    • >>
    • 57 |
    58 |
    59 |
    60 |
    -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/album-photos.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router, ActivatedRoute } from '@angular/router'; 3 | import { Photo } from '../core/domain/photo'; 4 | import { Paginated } from '../core/common/paginated'; 5 | import { DataService } from '../core/services/data.service'; 6 | import { UtilityService } from '../core/services/utility.service'; 7 | import { NotificationService } from '../core/services/notification.service'; 8 | import { OperationResult } from '../core/domain/operationResult'; 9 | import { Subscription } from 'rxjs/Subscription'; 10 | 11 | @Component({ 12 | selector: 'album-photo', 13 | providers: [NotificationService], 14 | templateUrl: './app/components/album-photos.component.html' 15 | }) 16 | export class AlbumPhotosComponent extends Paginated implements OnInit { 17 | private _albumsAPI: string = 'api/albums/'; 18 | private _photosAPI: string = 'api/photos/'; 19 | private _albumId: string; 20 | private _photos: Array; 21 | private _displayingTotal: number; 22 | private _albumTitle: string; 23 | private sub: Subscription; 24 | 25 | constructor(public dataService: DataService, 26 | public utilityService: UtilityService, 27 | public notificationService: NotificationService, 28 | private route: ActivatedRoute, 29 | private router: Router) { 30 | super(0, 0, 0); 31 | } 32 | 33 | ngOnInit() { 34 | 35 | this.sub = this.route.params.subscribe(params => { 36 | this._albumId = params['id']; // (+) converts string 'id' to a number 37 | this._albumsAPI += this._albumId + '/photos/'; 38 | this.dataService.set(this._albumsAPI, 12); 39 | this.getAlbumPhotos(); 40 | }); 41 | } 42 | 43 | getAlbumPhotos(): void { 44 | this.dataService.get(this._page) 45 | .subscribe(res => { 46 | 47 | var data: any = res.json(); 48 | 49 | this._photos = data.Items; 50 | this._displayingTotal = this._photos.length; 51 | this._page = data.Page; 52 | this._pagesCount = data.TotalPages; 53 | this._totalCount = data.TotalCount; 54 | this._albumTitle = this._photos[0].AlbumTitle; 55 | }, 56 | error => { 57 | 58 | if (error.status == 401 || error.status == 302) { 59 | this.utilityService.navigateToSignIn(); 60 | } 61 | 62 | console.error('Error: ' + error) 63 | }, 64 | () => console.log(this._photos)); 65 | } 66 | 67 | search(i: any): void { 68 | super.search(i); 69 | this.getAlbumPhotos(); 70 | }; 71 | 72 | convertDateTime(date: Date) { 73 | return this.utilityService.convertDateTime(date); 74 | } 75 | 76 | delete(photo: Photo) { 77 | var _removeResult: OperationResult = new OperationResult(false, ''); 78 | 79 | this.notificationService.printConfirmationDialog('Are you sure you want to delete the photo?', 80 | () => { 81 | this.dataService.deleteResource(this._photosAPI + photo.Id) 82 | .subscribe(res => { 83 | _removeResult.Succeeded = res.Succeeded; 84 | _removeResult.Message = res.Message; 85 | }, 86 | error => console.error('Error: ' + error), 87 | () => { 88 | if (_removeResult.Succeeded) { 89 | this.notificationService.printSuccessMessage(photo.Title + ' removed from gallery.'); 90 | this.getAlbumPhotos(); 91 | } 92 | else { 93 | this.notificationService.printErrorMessage('Failed to remove photo'); 94 | } 95 | }); 96 | }); 97 | } 98 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/albums.component.html: -------------------------------------------------------------------------------- 1 | 
    2 |
    3 |
    4 |

    5 | Photo Gallery albums 6 | Page {{_page + 1}} of {{_pagesCount}} 7 |

    8 | 14 |
    15 |
    16 | 17 |
    18 |
    19 |

    20 | 21 |

    22 |

    {{convertDateTime(album.DateCreated)}}

    23 |
    24 |
    25 | 26 | 27 | 28 |
    29 |
    30 |

    31 | {{album.Title}} 32 |

    33 |

    34 | Photos: {{album.TotalPhotos}} 35 |

    36 |

    {{album.Description}}

    37 | View photos 38 |
    39 |
    40 |
    41 |
    42 |
    43 | 44 |
    45 |
    46 |
    47 |
      48 |
    • <<
    • 49 |
    • <
    • 50 |
    • 51 | {{n+1}} 52 | {{n+1}} 53 |
    • 54 |
    • >
    • 55 |
    • >>
    • 56 |
    57 |
    58 |
    59 |
    60 | -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/albums.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Album } from '../core/domain/album'; 3 | import { Paginated } from '../core/common/paginated'; 4 | import { DataService } from '../core/services/data.service'; 5 | import { UtilityService } from '../core/services/utility.service'; 6 | import { NotificationService } from '../core/services/notification.service'; 7 | 8 | @Component({ 9 | selector: 'albums', 10 | templateUrl: './app/components/albums.component.html' 11 | }) 12 | export class AlbumsComponent extends Paginated implements OnInit { 13 | private _albumsAPI: string = 'api/albums/'; 14 | private _albums: Array; 15 | 16 | constructor(public albumsService: DataService, 17 | public utilityService: UtilityService, 18 | public notificationService: NotificationService) { 19 | super(0, 0, 0); 20 | } 21 | 22 | ngOnInit() { 23 | this.albumsService.set(this._albumsAPI, 3); 24 | this.getAlbums(); 25 | } 26 | 27 | getAlbums(): void { 28 | this.albumsService.get(this._page) 29 | .subscribe(res => { 30 | var data: any = res.json(); 31 | this._albums = data.Items; 32 | this._page = data.Page; 33 | this._pagesCount = data.TotalPages; 34 | this._totalCount = data.TotalCount; 35 | }, 36 | error => { 37 | 38 | if (error.status == 401 || error.status == 404) { 39 | this.notificationService.printErrorMessage('Authentication required'); 40 | this.utilityService.navigateToSignIn(); 41 | } 42 | }); 43 | } 44 | 45 | search(i: any): void { 46 | super.search(i); 47 | this.getAlbums(); 48 | }; 49 | 50 | convertDateTime(date: Date) { 51 | return this.utilityService.convertDateTime(date); 52 | } 53 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/home.component.html: -------------------------------------------------------------------------------- 1 | 
    2 |
    3 |
    4 | 5 |
    6 |
    7 |

    Building Single Page Applications using ASP.NET Core, Angular 2 & TypeScript

    8 |

    Step by step walkthrough on how to build clean, scallable Single Page Applications using the latest ASP.NET Core framework as middleware and Angular 2 with TypeScript on the front-end side.

    9 |  Read post 10 |
    11 |
    12 |
    13 | 14 |
    15 |
    16 |
    17 | The project is a chsakell's Blog's genuine contribution and distributed under MIT licence 18 |
    19 |
    20 |
    21 |
    22 |
    23 |
    24 |
    25 | 26 | 27 | 28 | 29 |
    30 |
    31 |

    ASP.NET Core

    32 |

    ASP.NET Core is a new open-source and cross-platform framework for building modern cloud-based Web applications using .NET.

    33 | More Info 34 |
    35 |
    36 |
    37 |
    38 |
    39 |
    40 | 41 | 42 | 43 | 44 |
    45 |
    46 |

    Angular 2

    47 |

    Angular is a development platform for creating applications using modern web standards. It includes essential features such as mobile gestures, animations, routing and data binding.

    48 | More Info 49 |
    50 |
    51 |
    52 |
    53 |
    54 |
    55 | 56 | 57 | 58 | 59 |
    60 |
    61 |

    TypeScript

    62 |

    TypeScript lets you write JavaScript the way you really want to. TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. Any browser. Any host. Any OS. Open Source.

    63 | More Info 64 |
    65 |
    66 |
    67 |
    68 |
    69 |
    70 | 71 | 72 | 73 | 74 |
    75 |
    76 |

    Entity Framework 7

    77 |

    EF7 is a lightweight and extensible version of Entity Framework that enables new platforms and new data stores.

    78 | More info 79 |
    80 |
    81 |
    82 |
    83 | 84 | 91 | 92 |
    -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/home.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'home', 5 | templateUrl: './app/components/home.component.html' 6 | }) 7 | export class HomeComponent { 8 | 9 | constructor() { 10 | 11 | } 12 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/photos.component.html: -------------------------------------------------------------------------------- 1 | 
    2 | 3 |
    4 |
    5 |

    6 | Photo Gallery photos 7 | (all albums displayed) 8 |

    9 | 15 |
    16 |
    17 | 18 |
    19 |
    20 | 21 | {{image.Title}} 22 | 23 |
    24 |
    25 |
    26 | 27 |
    28 |
    29 |
    30 |
      31 |
    • <<
    • 32 |
    • <
    • 33 |
    • 34 | {{n+1}} 35 | {{n+1}} 36 |
    • 37 |
    • >
    • 38 |
    • >>
    • 39 |
    40 |
    41 |
    42 |
    43 | 44 | -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/components/photos.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Photo } from '../core/domain/photo'; 3 | import { Paginated } from '../core/common/paginated'; 4 | import { DataService } from '../core/services/data.service'; 5 | 6 | @Component({ 7 | selector: 'photos', 8 | templateUrl: './app/components/photos.component.html' 9 | }) 10 | export class PhotosComponent extends Paginated implements OnInit { 11 | private _photosAPI: string = 'api/photos/'; 12 | private _photos: Array; 13 | 14 | constructor(public photosService: DataService) { 15 | super(0, 0, 0); 16 | } 17 | 18 | ngOnInit() { 19 | this.photosService.set(this._photosAPI, 12); 20 | this.getPhotos(); 21 | } 22 | 23 | getPhotos(): void { 24 | let self = this; 25 | self.photosService.get(self._page) 26 | .subscribe(res => { 27 | 28 | var data: any = res.json(); 29 | 30 | self._photos = data.Items; 31 | self._page = data.Page; 32 | self._pagesCount = data.TotalPages; 33 | self._totalCount = data.TotalCount; 34 | }, 35 | error => console.error('Error: ' + error)); 36 | } 37 | 38 | search(i: any): void { 39 | super.search(i); 40 | this.getPhotos(); 41 | }; 42 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/core/common/paginated.ts: -------------------------------------------------------------------------------- 1 | export class Paginated { 2 | public _page: number = 0; 3 | public _pagesCount: number = 0; 4 | public _totalCount: number = 0; 5 | 6 | constructor(page: number, pagesCount: number, totalCount: number) { 7 | this._page = page; 8 | this._pagesCount = pagesCount; 9 | this._totalCount = totalCount; 10 | } 11 | 12 | range(): Array { 13 | if (!this._pagesCount) { return []; } 14 | var step = 2; 15 | var doubleStep = step * 2; 16 | var start = Math.max(0, this._page - step); 17 | var end = start + 1 + doubleStep; 18 | if (end > this._pagesCount) { end = this._pagesCount; } 19 | 20 | var ret = []; 21 | for (var i = start; i != end; ++i) { 22 | ret.push(i); 23 | } 24 | 25 | return ret; 26 | }; 27 | 28 | pagePlus(count: number): number { 29 | return + this._page + count; 30 | } 31 | 32 | search(i: any): void { 33 | this._page = i; 34 | }; 35 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/core/domain/album.ts: -------------------------------------------------------------------------------- 1 | export class Album { 2 | Id: number; 3 | Title: string; 4 | Description: string; 5 | Thumbnail: string; 6 | DateCreated: Date; 7 | TotalPhotos: number; 8 | 9 | constructor(id: number, 10 | title: string, 11 | description: string, 12 | thumbnail: string, 13 | dateCreated: Date, 14 | totalPhotos: number) { 15 | this.Id = id; 16 | this.Title = title; 17 | this.Description = description; 18 | this.Thumbnail = thumbnail; 19 | this.DateCreated = dateCreated; 20 | this.TotalPhotos = totalPhotos; 21 | } 22 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/core/domain/operationResult.ts: -------------------------------------------------------------------------------- 1 | export class OperationResult { 2 | Succeeded: boolean; 3 | Message: string; 4 | 5 | constructor(succeeded: boolean, message: string) { 6 | this.Succeeded = succeeded; 7 | this.Message = message; 8 | } 9 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/core/domain/photo.ts: -------------------------------------------------------------------------------- 1 | export class Photo { 2 | Id: number; 3 | Title: string; 4 | Uri: string; 5 | AlbumId: number; 6 | AlbumTitle: string; 7 | DateUploaded: Date 8 | 9 | constructor(id: number, 10 | title: string, 11 | uri: string, 12 | albumId: number, 13 | albumTitle: string, 14 | dateUploaded: Date) { 15 | this.Id = id; 16 | this.Title = title; 17 | this.Uri = uri; 18 | this.AlbumId = albumId; 19 | this.AlbumTitle = albumTitle; 20 | this.DateUploaded = dateUploaded; 21 | } 22 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/core/domain/registration.ts: -------------------------------------------------------------------------------- 1 | export class Registration { 2 | Username: string; 3 | Password: string; 4 | Email: string; 5 | 6 | constructor(username: string, 7 | password: string, 8 | email: string) { 9 | this.Username = username; 10 | this.Password = password; 11 | this.Email = email; 12 | } 13 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/core/domain/user.ts: -------------------------------------------------------------------------------- 1 | export class User { 2 | Username: string; 3 | Password: string; 4 | RememberMe: boolean; 5 | 6 | constructor(username: string, 7 | password: string) { 8 | this.Username = username; 9 | this.Password = password; 10 | this.RememberMe = false; 11 | } 12 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/core/services/data.service.ts: -------------------------------------------------------------------------------- 1 | import { Http, Response } from '@angular/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Observable } from 'rxjs/Observable'; 4 | 5 | @Injectable() 6 | export class DataService { 7 | 8 | public _pageSize: number; 9 | public _baseUri: string; 10 | 11 | constructor(public http: Http) { 12 | 13 | } 14 | 15 | set(baseUri: string, pageSize?: number): void { 16 | this._baseUri = baseUri; 17 | this._pageSize = pageSize; 18 | } 19 | 20 | get(page: number) { 21 | var uri = this._baseUri + page.toString() + '/' + this._pageSize.toString(); 22 | 23 | return this.http.get(uri) 24 | .map(response => (response)); 25 | } 26 | 27 | post(data?: any, mapJson: boolean = true) { 28 | if (mapJson) 29 | return this.http.post(this._baseUri, data) 30 | .map(response => (response).json()); 31 | else 32 | return this.http.post(this._baseUri, data); 33 | } 34 | 35 | delete(id: number) { 36 | return this.http.delete(this._baseUri + '/' + id.toString()) 37 | .map(response => (response).json()) 38 | } 39 | 40 | deleteResource(resource: string) { 41 | return this.http.delete(resource) 42 | .map(response => (response).json()) 43 | } 44 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/core/services/membership.service.ts: -------------------------------------------------------------------------------- 1 | import { Http, Response, Request } from '@angular/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { DataService } from './data.service'; 4 | import { Registration } from '../domain/registration'; 5 | import { User } from '../domain/user'; 6 | 7 | @Injectable() 8 | export class MembershipService { 9 | 10 | private _accountRegisterAPI: string = 'api/account/register/'; 11 | private _accountLoginAPI: string = 'api/account/authenticate/'; 12 | private _accountLogoutAPI: string = 'api/account/logout/'; 13 | 14 | constructor(public accountService: DataService) { } 15 | 16 | register(newUser: Registration) { 17 | 18 | this.accountService.set(this._accountRegisterAPI); 19 | 20 | return this.accountService.post(JSON.stringify(newUser)); 21 | } 22 | 23 | login(creds: User) { 24 | this.accountService.set(this._accountLoginAPI); 25 | return this.accountService.post(JSON.stringify(creds)); 26 | } 27 | 28 | logout() { 29 | this.accountService.set(this._accountLogoutAPI); 30 | return this.accountService.post(null, false); 31 | } 32 | 33 | isUserAuthenticated(): boolean { 34 | var _user: any = localStorage.getItem('user'); 35 | if (_user != null) 36 | return true; 37 | else 38 | return false; 39 | } 40 | 41 | getLoggedInUser(): User { 42 | var _user: User; 43 | 44 | if (this.isUserAuthenticated()) { 45 | var _userData = JSON.parse(localStorage.getItem('user')); 46 | _user = new User(_userData.Username, _userData.Password); 47 | } 48 | 49 | return _user; 50 | } 51 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/core/services/notification.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | declare var alertify: any; 4 | 5 | @Injectable() 6 | export class NotificationService { 7 | private _notifier: any = alertify; 8 | constructor() { 9 | } 10 | 11 | printSuccessMessage(message: string) { 12 | 13 | this._notifier.success(message); 14 | } 15 | 16 | printErrorMessage(message: string) { 17 | this._notifier.error(message); 18 | } 19 | 20 | printConfirmationDialog(message: string, okCallback: () => any) { 21 | this._notifier.confirm(message, function (e:any) { 22 | if (e) { 23 | okCallback(); 24 | } else { 25 | } 26 | }); 27 | } 28 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/core/services/utility.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import {Router} from '@angular/router'; 3 | 4 | @Injectable() 5 | export class UtilityService { 6 | 7 | private _router: Router; 8 | 9 | constructor(router: Router) { 10 | this._router = router; 11 | } 12 | 13 | convertDateTime(date: Date) { 14 | var _formattedDate = new Date(date.toString()); 15 | return _formattedDate.toDateString(); 16 | } 17 | 18 | navigate(path: string) { 19 | this._router.navigate([path]); 20 | } 21 | 22 | navigateToSignIn() { 23 | this.navigate('/account/login'); 24 | } 25 | } -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/main.ts: -------------------------------------------------------------------------------- 1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 2 | import { AppModule } from './app.module'; 3 | 4 | platformBrowserDynamic().bootstrapModule(AppModule); -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/app/routes.ts: -------------------------------------------------------------------------------- 1 | import { ModuleWithProviders } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { HomeComponent } from './components/home.component'; 5 | import { PhotosComponent } from './components/photos.component'; 6 | import { AlbumsComponent } from './components/albums.component'; 7 | import { AlbumPhotosComponent } from './components/album-photos.component'; 8 | import { accountRoutes, accountRouting } from './components/account/routes'; 9 | 10 | 11 | const appRoutes: Routes = [ 12 | { 13 | path: '', 14 | redirectTo: '/home', 15 | pathMatch: 'full' 16 | }, 17 | { 18 | path: 'home', 19 | component: HomeComponent 20 | }, 21 | { 22 | path: 'photos', 23 | component: PhotosComponent 24 | }, 25 | { 26 | path: 'albums', 27 | component: AlbumsComponent 28 | }, 29 | { 30 | path: 'albums/:id/photos', 31 | component: AlbumPhotosComponent 32 | } 33 | ]; 34 | 35 | export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes); 36 | -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | /* TOP BAR - Footer Styles */ 2 | .navbar-inverse .navbar-brand { 3 | color: #ddd; 4 | } 5 | 6 | .navbar-inverse { 7 | border-color: #080808; 8 | background-color: #31708f; 9 | } 10 | 11 | .navbar-inverse .navbar-nav > li > a { 12 | color: #ddd; 13 | } 14 | 15 | #nav-separator { 16 | margin-top: 60px; 17 | } 18 | 19 | footer { 20 | background-color: #F8F8F8; 21 | } 22 | 23 | #account-menu { 24 | margin-right: 35px; 25 | } 26 | 27 | /* END */ 28 | 29 | /**/ 30 | .picture-box { 31 | margin-bottom: 30px; 32 | } 33 | 34 | .album-thumbnail { 35 | height: 300px; 36 | } 37 | 38 | .album-box { 39 | margin-bottom: 30px; 40 | } 41 | 42 | .pagination > li { 43 | cursor: pointer; 44 | } 45 | 46 | #loginModal { 47 | margin-top: 80px; 48 | } 49 | 50 | #registerModal { 51 | margin-top: 40px; 52 | } 53 | 54 | .blue-thumb { 55 | border: 1px solid #31708F; 56 | } 57 | 58 | /* validation form controls */ 59 | .ng-valid[required] { 60 | border-left: 5px solid #42A948; /* green */ 61 | } 62 | 63 | .ng-invalid { 64 | border-left: 5px solid #a94442; /* red */ 65 | } 66 | 67 | .img-caption { 68 | margin: 0; 69 | background-color: whitesmoke; 70 | } 71 | 72 | .remove-caption { 73 | border-bottom: 1px solid #e6e6e6; 74 | padding: 2px; 75 | margin: 0 0 10px 0; 76 | } 77 | 78 | .dateCaption { 79 | padding: 6px 0; 80 | } 81 | 82 | .buttonCaption { 83 | padding: 0 !important; 84 | } 85 | 86 | /*loader*/ 87 | /* Absolute Center Spinner */ 88 | .loading { 89 | position: fixed; 90 | z-index: 999; 91 | height: 2em; 92 | width: 2em; 93 | overflow: show; 94 | margin: auto; 95 | top: 0; 96 | left: 0; 97 | bottom: 0; 98 | right: 0; 99 | } 100 | 101 | /* Transparent Overlay */ 102 | .loading:before { 103 | content: ''; 104 | display: block; 105 | position: fixed; 106 | top: 0; 107 | left: 0; 108 | width: 100%; 109 | height: 100%; 110 | background-color: white; 111 | } 112 | 113 | /* :not(:required) hides these rules from IE9 and below */ 114 | .loading:not(:required) { 115 | /* hide "loading..." text */ 116 | font: 0/0 a; 117 | color: transparent; 118 | text-shadow: none; 119 | background-color: transparent; 120 | border: 0; 121 | } 122 | 123 | .loading:not(:required):after { 124 | content: ''; 125 | display: block; 126 | font-size: 10px; 127 | width: 1em; 128 | height: 1em; 129 | margin-top: -0.5em; 130 | -webkit-animation: spinner 1500ms infinite linear; 131 | -moz-animation: spinner 1500ms infinite linear; 132 | -ms-animation: spinner 1500ms infinite linear; 133 | -o-animation: spinner 1500ms infinite linear; 134 | animation: spinner 1500ms infinite linear; 135 | border-radius: 0.5em; 136 | -webkit-box-shadow: #31708f 1.5em 0 0 0, #31708f 1.1em 1.1em 0 0, #31708f 0 1.5em 0 0, #31708f -1.1em 1.1em 0 0, rgba(0, 0, 0, 0.5) -1.5em 0 0 0, rgba(0, 0, 0, 0.5) -1.1em -1.1em 0 0, #31708f 0 -1.5em 0 0, #31708f 1.1em -1.1em 0 0; 137 | box-shadow: #31708f 1.5em 0 0 0, #31708f 1.1em 1.1em 0 0, #31708f 0 1.5em 0 0, #31708f -1.1em 1.1em 0 0, #31708f -1.5em 0 0 0, #31708f -1.1em -1.1em 0 0, #31708f 0 -1.5em 0 0, #31708f 1.1em -1.1em 0 0; 138 | } 139 | 140 | /* Animation */ 141 | 142 | @-webkit-keyframes spinner { 143 | 0% { 144 | -webkit-transform: rotate(0deg); 145 | -moz-transform: rotate(0deg); 146 | -ms-transform: rotate(0deg); 147 | -o-transform: rotate(0deg); 148 | transform: rotate(0deg); 149 | } 150 | 151 | 100% { 152 | -webkit-transform: rotate(360deg); 153 | -moz-transform: rotate(360deg); 154 | -ms-transform: rotate(360deg); 155 | -o-transform: rotate(360deg); 156 | transform: rotate(360deg); 157 | } 158 | } 159 | 160 | @-moz-keyframes spinner { 161 | 0% { 162 | -webkit-transform: rotate(0deg); 163 | -moz-transform: rotate(0deg); 164 | -ms-transform: rotate(0deg); 165 | -o-transform: rotate(0deg); 166 | transform: rotate(0deg); 167 | } 168 | 169 | 100% { 170 | -webkit-transform: rotate(360deg); 171 | -moz-transform: rotate(360deg); 172 | -ms-transform: rotate(360deg); 173 | -o-transform: rotate(360deg); 174 | transform: rotate(360deg); 175 | } 176 | } 177 | 178 | @-o-keyframes spinner { 179 | 0% { 180 | -webkit-transform: rotate(0deg); 181 | -moz-transform: rotate(0deg); 182 | -ms-transform: rotate(0deg); 183 | -o-transform: rotate(0deg); 184 | transform: rotate(0deg); 185 | } 186 | 187 | 100% { 188 | -webkit-transform: rotate(360deg); 189 | -moz-transform: rotate(360deg); 190 | -ms-transform: rotate(360deg); 191 | -o-transform: rotate(360deg); 192 | transform: rotate(360deg); 193 | } 194 | } 195 | 196 | @keyframes spinner { 197 | 0% { 198 | -webkit-transform: rotate(0deg); 199 | -moz-transform: rotate(0deg); 200 | -ms-transform: rotate(0deg); 201 | -o-transform: rotate(0deg); 202 | transform: rotate(0deg); 203 | } 204 | 205 | 100% { 206 | -webkit-transform: rotate(360deg); 207 | -moz-transform: rotate(360deg); 208 | -ms-transform: rotate(360deg); 209 | -o-transform: rotate(360deg); 210 | transform: rotate(360deg); 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/80k_pluto-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/80k_pluto-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/above-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/above-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/armeni_teghut_mery_tree_lilac-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/armeni_teghut_mery_tree_lilac-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/armenia_teghut_2-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/armenia_teghut_2-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/aspcorerc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/aspcorerc2.png -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/aspnet5-agnular2-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/aspnet5-agnular2-03.png -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/autumn_california-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/autumn_california-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/beautiful_autumn_3-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/beautiful_autumn_3-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/blue_mountains_mist-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/blue_mountains_mist-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/business-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/business-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/butterfly_95-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/butterfly_95-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/by_the_river-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/by_the_river-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/country_road_summer-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/country_road_summer-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/dark_clouds_2-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/dark_clouds_2-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/dark_storm_clouds-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/dark_storm_clouds-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/dirt_road_through_forest-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/dirt_road_through_forest-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/finland_forest_lake-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/finland_forest_lake-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/fog_at_the_pink_house-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/fog_at_the_pink_house-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/forest-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/forest-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/forest_in_dam_no__1_woods_2-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/forest_in_dam_no__1_woods_2-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/forest_stream_2-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/forest_stream_2-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/forest_sunrise-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/forest_sunrise-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/green_ginkgo_trees-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/green_ginkgo_trees-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/hawthorns_leaf-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/hawthorns_leaf-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/hidden_lake-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/hidden_lake-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/high_speed_photography-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/high_speed_photography-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/hong_kong_harbour_night_lights-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/hong_kong_harbour_night_lights-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/island-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/island-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/landscape_5-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/landscape_5-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/london_6-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/london_6-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/marguerite_daisy_flower-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/marguerite_daisy_flower-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/mist_rising-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/mist_rising-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/morning_sun-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/morning_sun-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/mountain_landscape-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/mountain_landscape-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/pier-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/pier-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/planet_earth_at_night-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/planet_earth_at_night-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/pyrenees_mountain_range-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/pyrenees_mountain_range-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/red_autumn_4-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/red_autumn_4-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/road_12-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/road_12-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/road_through_forest_hdr-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/road_through_forest_hdr-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/save_the_earth-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/save_the_earth-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/scotland_coast_lighthouse-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/scotland_coast_lighthouse-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/scotland_road_landscape-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/scotland_road_landscape-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/skyline_new_york_city_2015-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/skyline_new_york_city_2015-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/storm_is_coming_2-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/storm_is_coming_2-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/sunlight_through_tree-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/sunlight_through_tree-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/sunset_222-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/sunset_222-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/surfing_8-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/surfing_8-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/the_day_before_halloween-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/the_day_before_halloween-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/thumbnail-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/thumbnail-default.png -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/tokyo_at_sunset-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/tokyo_at_sunset-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/tree_7-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/tree_7-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/tree_summer_storm-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/tree_summer_storm-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/images/walk_into_fall-wallpaper-800x600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/aspnet5-angular2-typescript/c64af4bf298c4b90b20fbbcef45c2694c7cb7784/src/PhotoGallery/wwwroot/images/walk_into_fall-wallpaper-800x600.jpg -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "lib": [ "es2015", "dom" ], 10 | "noImplicitAny": true, 11 | "suppressImplicitAnyIndexErrors": true 12 | }, 13 | "exclude": ["node_modules"] 14 | } 15 | -------------------------------------------------------------------------------- /src/PhotoGallery/wwwroot/web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | --------------------------------------------------------------------------------