├── ContosoUniversity.Web
├── wwwroot
│ ├── js
│ │ ├── site.min.js
│ │ └── site.js
│ ├── favicon.ico
│ ├── lib
│ │ ├── bootstrap
│ │ │ ├── dist
│ │ │ │ ├── fonts
│ │ │ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ │ │ └── glyphicons-halflings-regular.woff2
│ │ │ │ └── js
│ │ │ │ │ └── npm.js
│ │ │ ├── .bower.json
│ │ │ └── LICENSE
│ │ ├── jquery
│ │ │ ├── .bower.json
│ │ │ └── LICENSE.txt
│ │ ├── jquery-validation
│ │ │ ├── .bower.json
│ │ │ └── LICENSE.md
│ │ └── jquery-validation-unobtrusive
│ │ │ └── .bower.json
│ └── css
│ │ ├── site.min.css
│ │ └── site.css
├── .bowerrc
├── Views
│ ├── _ViewStart.cshtml
│ ├── _ViewImports.cshtml
│ ├── Account
│ │ ├── AccessDenied.cshtml
│ │ ├── ForgotPasswordConfirmation.cshtml
│ │ ├── ExternalLoginFailure.cshtml
│ │ ├── Lockout.cshtml
│ │ ├── ResetPasswordConfirmation.cshtml
│ │ ├── ConfirmEmail.cshtml
│ │ ├── SendCode.cshtml
│ │ ├── ForgotPassword.cshtml
│ │ ├── ExternalLoginConfirmation.cshtml
│ │ ├── VerifyCode.cshtml
│ │ ├── Register.cshtml
│ │ └── ResetPassword.cshtml
│ ├── Shared
│ │ ├── Error.cshtml
│ │ ├── _LoginPartial.cshtml
│ │ └── _ValidationScriptsPartial.cshtml
│ ├── Courses
│ │ ├── UpdateCourseCredits.cshtml
│ │ ├── Details.cshtml
│ │ ├── Delete.cshtml
│ │ ├── Index.cshtml
│ │ ├── Edit.cshtml
│ │ └── Create.cshtml
│ ├── Instructors
│ │ ├── Details.cshtml
│ │ └── Delete.cshtml
│ ├── Manage
│ │ ├── AddPhoneNumber.cshtml
│ │ ├── VerifyPhoneNumber.cshtml
│ │ ├── ChangePassword.cshtml
│ │ └── Index.cshtml
│ ├── Departments
│ │ ├── Details.cshtml
│ │ ├── Delete.cshtml
│ │ ├── Index.cshtml
│ │ ├── Create.cshtml
│ │ └── Edit.cshtml
│ └── Students
│ │ ├── Delete.cshtml
│ │ ├── Details.cshtml
│ │ ├── Create.cshtml
│ │ ├── Edit.cshtml
│ │ └── Index.cshtml
├── Resources
│ └── contosoU2017_schema1.png
├── Readme.md
├── bower.json
├── Helpers
│ ├── IUrlHelperAdaptor.cs
│ └── UrlHelperAdaptor.cs
├── ViewModels
│ ├── ManageIndexViewModel.cs
│ ├── ForgotPasswordViewModel.cs
│ ├── ExternalLoginConfirmationViewModel.cs
│ ├── AddPhoneNumberViewModel.cs
│ ├── TokenViewModel.cs
│ ├── VerifyPhoneNumberViewModel.cs
│ ├── SendCodeViewModel.cs
│ ├── DepartmentEditViewModel.cs
│ ├── DepartmentCreateViewModel.cs
│ ├── RegisterViewModel.cs
│ ├── LoginViewModel.cs
│ ├── DepartmentDetailsViewModel.cs
│ ├── VerifyCodeViewModel.cs
│ ├── DepartmentBaseViewModel.cs
│ ├── ResetPasswordViewModel.cs
│ └── ChangePasswordViewModel.cs
├── Models
│ └── SchoolViewModels
│ │ ├── AssignedCourseData.cs
│ │ ├── EnrollmentDateGroup.cs
│ │ └── InstructorIndexData.cs
├── appsettings.json
├── Enums
│ └── ManageMessage.cs
├── Pages
│ ├── Contact.cshtml.cs
│ ├── Contact.cshtml
│ ├── About.cshtml
│ ├── Index.cshtml
│ └── About.cshtml.cs
├── IModelBindingHelperAdaptor.cs
├── QueryableExtensions.cs
├── bundleconfig.json
├── Properties
│ └── launchSettings.json
├── DefaultModelBindingHelperAdaptor.cs
├── WebProfile.cs
├── appsettings.Development.json
├── PaginatedList.cs
├── Program.cs
├── ScaffoldingReadMe.txt
└── ContosoUniversity.Web.csproj
├── ContosoUniversity.Data
├── Readme.md
├── Enums
│ └── Grade.cs
├── Entities
│ ├── ApplicationUser.cs
│ ├── CourseAssignment.cs
│ ├── OfficeAssignment.cs
│ ├── BaseEntity.cs
│ ├── Enrollment.cs
│ ├── Student.cs
│ ├── Instructor.cs
│ ├── Course.cs
│ ├── Person.cs
│ └── Department.cs
├── appsettings.json
├── DTO
│ ├── CourseAssignmentsDTO.cs
│ ├── OfficeAssignmentDTO.cs
│ ├── InstructorDTO.cs
│ ├── StudentDTO.cs
│ ├── CourseDTO.cs
│ └── EnrollmentDTO.cs
├── AdminIdentityOptions.cs
├── OperatingSystem.cs
├── DbContexts
│ ├── ApiContext.cs
│ ├── SecureApplicationContext.cs
│ ├── ApplicationContext.cs
│ ├── SecureApplicatonContextFactory.cs
│ ├── WebContext.cs
│ ├── ApplicationContextFactory.cs
│ └── DbContextConfig.cs
└── ContosoUniversity.Data.csproj
├── ContosoUniversity.Spa.React
├── ClientApp
│ ├── src
│ │ ├── api
│ │ │ ├── delay.js
│ │ │ └── mockDepartmentApi.js
│ │ ├── components
│ │ │ ├── common
│ │ │ │ ├── Layout.css
│ │ │ │ ├── Footer.js
│ │ │ │ ├── Layout.js
│ │ │ │ ├── LoadingDots.js
│ │ │ │ ├── TextInput.js
│ │ │ │ ├── NumberInput.js
│ │ │ │ ├── SelectInput.js
│ │ │ │ └── NavMenu.js
│ │ │ ├── about
│ │ │ │ └── AboutPage.js
│ │ │ ├── login
│ │ │ │ └── LoginPage.js
│ │ │ ├── forms
│ │ │ │ └── form.css
│ │ │ ├── selectors
│ │ │ │ └── selectors.js
│ │ │ ├── register
│ │ │ │ └── RegisterPage.js
│ │ │ ├── course
│ │ │ │ ├── CourseListRow.js
│ │ │ │ ├── CourseList.js
│ │ │ │ ├── CoursesPage.js
│ │ │ │ └── CourseForm.js
│ │ │ ├── department
│ │ │ │ ├── DepartmentListRow.js
│ │ │ │ ├── DepartmentList.js
│ │ │ │ └── DepartmentsPage.js
│ │ │ └── contact
│ │ │ │ └── ContactPage.js
│ │ ├── reducers
│ │ │ ├── initialState.js
│ │ │ ├── index.js
│ │ │ ├── departmentReducer.js
│ │ │ ├── ajaxStatusReducer.js
│ │ │ └── courseReducer.js
│ │ ├── index.css
│ │ ├── App.test.js
│ │ ├── actions
│ │ │ ├── ajaxStatusActions.js
│ │ │ ├── actionTypes.js
│ │ │ ├── departmentActions.js
│ │ │ └── courseActions.js
│ │ ├── store
│ │ │ └── configureStore.js
│ │ ├── index.js
│ │ └── App.js
│ ├── public
│ │ ├── favicon.ico
│ │ ├── manifest.json
│ │ └── index.html
│ ├── .gitignore
│ └── package.json
├── package-lock.json
├── appsettings.Development.json
├── appsettings.json
├── Properties
│ └── launchSettings.json
├── ReadMe.md
├── ReactApiProfile.cs
├── DTO
│ └── CreateDepartmentDTO.cs
├── Program.cs
└── Controllers
│ ├── CoursesController.cs
│ └── DepartmentController.cs
├── ContosoUniversity.Common
├── Readme.md
├── Interfaces
│ ├── IUnitOfWork.cs
│ ├── IDbInitializer.cs
│ ├── IPersonRepository.cs
│ └── IRepository.cs
├── ISmsSender.cs
├── AuthMessageSenderOptions.cs
├── IEmailSender.cs
├── SMSOptions.cs
├── OperatingSystem.cs
├── DTO
│ └── DepartmentDTO.cs
├── Data
│ ├── SampleData.cs
│ └── ApiInitializer.cs
├── Repositories
│ ├── PersonRepository.cs
│ └── Repository.cs
├── ContosoUniversity.Common.csproj
└── MessageServices.cs
├── ContosoUniversity.Api
├── wwwroot
│ └── swagger
│ │ └── ui
│ │ ├── css
│ │ ├── custom.css.map
│ │ └── custom.css
│ │ ├── swagger-ui.css.map
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ └── oauth2-redirect.html
├── Readme.md
├── appsettings.json
├── ApiProfile.cs
├── DTO
│ └── CreateDepartmentDTO.cs
├── appsettings.Development.json
├── Properties
│ └── launchSettings.json
├── Program.cs
└── ContosoUniversity.Api.csproj
├── ContosoUniversity.Api.Tests
├── Readme.md
├── appsettings.Testing.json
├── ApiIntegrationTests.cs
└── ContosoUniversity.Api.Tests.csproj
├── ContosoUniversity.Data.Tests
├── Readme.md
└── ContosoUniversity.Data.Tests.csproj
├── ContosoUniversity.Web.Tests
├── Readme.md
├── Views
│ └── ChromeViews.cs
└── ContosoUniversity.Web.Tests.csproj
├── global.json
├── .travis.yml
├── ContosoUniversity.Web.IntegrationTests
├── Readme.md
├── ContosoUniversity.Web.IntegrationTests.csproj
├── StaticPagesTests.cs
└── Helpers
│ └── Utilities.cs
├── .vscode
├── tasks.json
└── launch.json
├── LICENSE
├── ContosoUniversity.Test
├── ContosoUniversity.Test.csproj
└── HttpClientExtensions.cs
├── README.md
└── .gitattributes
/ContosoUniversity.Web/wwwroot/js/site.min.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/Readme.md:
--------------------------------------------------------------------------------
1 | ### ContosoUniversity.Data (WIP)
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/api/delay.js:
--------------------------------------------------------------------------------
1 | export default 1000;
--------------------------------------------------------------------------------
/ContosoUniversity.Web/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "wwwroot/lib"
3 | }
4 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/js/site.js:
--------------------------------------------------------------------------------
1 | // Write your Javascript code.
2 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "lockfileVersion": 1
3 | }
4 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "_Layout";
3 | }
4 |
--------------------------------------------------------------------------------
/ContosoUniversity.Common/Readme.md:
--------------------------------------------------------------------------------
1 | ### ContosoUniversity.Common
2 |
3 | Shared library between Api and Web projects
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/common/Layout.css:
--------------------------------------------------------------------------------
1 | .body-content {
2 | padding-top: 50px;
3 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alimon808/contoso-university/HEAD/ContosoUniversity.Web/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/ContosoUniversity.Api/wwwroot/swagger/ui/css/custom.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"swagger-ui.css","sourceRoot":""}
--------------------------------------------------------------------------------
/ContosoUniversity.Api/wwwroot/swagger/ui/swagger-ui.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"swagger-ui.css","sourceRoot":""}
--------------------------------------------------------------------------------
/ContosoUniversity.Data/Enums/Grade.cs:
--------------------------------------------------------------------------------
1 | namespace ContosoUniversity.Data.Enums
2 | {
3 | public enum Grade
4 | {
5 | A,B,C,D,F
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/reducers/initialState.js:
--------------------------------------------------------------------------------
1 | export default {
2 | departments: [],
3 | courses: [],
4 | ajaxCallsInProgress: 0
5 | };
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alimon808/contoso-university/HEAD/ContosoUniversity.Spa.React/ClientApp/public/favicon.ico
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Resources/contosoU2017_schema1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alimon808/contoso-university/HEAD/ContosoUniversity.Web/Resources/contosoU2017_schema1.png
--------------------------------------------------------------------------------
/ContosoUniversity.Api/wwwroot/swagger/ui/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alimon808/contoso-university/HEAD/ContosoUniversity.Api/wwwroot/swagger/ui/favicon-16x16.png
--------------------------------------------------------------------------------
/ContosoUniversity.Api/wwwroot/swagger/ui/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alimon808/contoso-university/HEAD/ContosoUniversity.Api/wwwroot/swagger/ui/favicon-32x32.png
--------------------------------------------------------------------------------
/ContosoUniversity.Common/Interfaces/IUnitOfWork.cs:
--------------------------------------------------------------------------------
1 | namespace ContosoUniversity.Common.Interfaces
2 | {
3 | public interface IUnitOfWork
4 | {
5 | void Commit();
6 | }
7 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Common/Interfaces/IDbInitializer.cs:
--------------------------------------------------------------------------------
1 | namespace ContosoUniversity.Common.Interfaces
2 | {
3 | public interface IDbInitializer
4 | {
5 | void Initialize();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Readme.md:
--------------------------------------------------------------------------------
1 | ## ContosoUniversity.Web
2 |
3 | ### Run Mvc App
4 | ```
5 | git clone https://github.com/alimon808/contoso-university.git
6 | cd ContosoUnversity.Web
7 | dotnet run
8 | ```
--------------------------------------------------------------------------------
/ContosoUniversity.Api/Readme.md:
--------------------------------------------------------------------------------
1 | ## ContosoUniversity.Api
2 |
3 | ### Run Api with Swagger UI
4 | ```
5 | git clone https://github.com/alimon808/contoso-university.git
6 | cd ContosoUniversity.Api
7 | dotnet run
8 | ```
--------------------------------------------------------------------------------
/ContosoUniversity.Api.Tests/Readme.md:
--------------------------------------------------------------------------------
1 | ## ContosoUniversity.Api.Tests
2 |
3 | ### Run tests
4 | ```
5 | git clone https://github.com/alimon808/contoso-university.git
6 | cd ContosoUniversity.Api.Tests
7 | dotnet test
8 | ```
--------------------------------------------------------------------------------
/ContosoUniversity.Data/Entities/ApplicationUser.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Identity;
2 |
3 | namespace ContosoUniversity.Data.Entities
4 | {
5 | public class ApplicationUser : IdentityUser
6 | {
7 | }
8 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using ContosoUniversity.Web
2 | @using ContosoUniversity.Data.Entities
3 | @using Microsoft.AspNetCore.Identity
4 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
5 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "ConnectionStrings": {
3 | "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity2020;Trusted_Connection=True;MultipleActiveResultSets=true"
4 | }
5 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Account/AccessDenied.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Access Denied";
3 | }
4 |
5 |
@ViewData["Title"]
6 | You are not authorized. Contact the administrator for assistance.
7 |
8 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alimon808/contoso-university/HEAD/ContosoUniversity.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alimon808/contoso-university/HEAD/ContosoUniversity.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/about/AboutPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function() {
4 | return(
5 |
6 |
About Page
7 |
8 | );
9 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/login/LoginPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function(){
4 | return(
5 |
6 |
Login Page
7 |
8 | );
9 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "System": "Information",
6 | "Microsoft": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alimon808/contoso-university/HEAD/ContosoUniversity.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alimon808/contoso-university/HEAD/ContosoUniversity.Web/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/index.css:
--------------------------------------------------------------------------------
1 | @media (max-width: 767px) {
2 | /* On small screens, the nav menu spans the full width of the screen. Leave a space for it. */
3 | body {
4 | padding-top: 50px;
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Account/ForgotPasswordConfirmation.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Forgot Password Confirmation";
3 | }
4 |
5 | @ViewData["Title"]
6 |
7 | Please check your email to reset your password.
8 |
--------------------------------------------------------------------------------
/ContosoUniversity.Common/ISmsSender.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace ContosoUniversity.Common
4 | {
5 | public interface ISmsSender
6 | {
7 | Task SendSmsAsync(string email, string message);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Account/ExternalLoginFailure.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Login Failure";
3 | }
4 |
5 |
9 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/DTO/CourseAssignmentsDTO.cs:
--------------------------------------------------------------------------------
1 | namespace ContosoUniversity.Data.DTO
2 | {
3 | public class CourseAssignmentsDTO
4 | {
5 | public int InstructorID { get; set; }
6 | public int CourseID { get; set; }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data.Tests/Readme.md:
--------------------------------------------------------------------------------
1 | ## ContosoUniversity.Data.Tests
2 | Test project for ContosoUniversity.Data.
3 |
4 | ### Run tests
5 | ```
6 | git clone https://github.com/alimon808/contoso-university.git
7 | cd ContosoUniversity.Data.Tests
8 | dotnet test
9 | ```
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/forms/form.css:
--------------------------------------------------------------------------------
1 | input, textarea, select {
2 | max-width: 280px;
3 | }
4 |
5 | .form-control {
6 | width: 280px !important;
7 | }
8 |
9 | .form-control-feedback {
10 | left: 265px !important;
11 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Common/AuthMessageSenderOptions.cs:
--------------------------------------------------------------------------------
1 | namespace ContosoUniversity.Common
2 | {
3 | public class AuthMessageSenderOptions
4 | {
5 | public string SendGridUser { get; set; }
6 | public string SendGridKey { get; set; }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ContosoUniversity.Common/IEmailSender.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace ContosoUniversity.Common
4 | {
5 | public interface IEmailSender
6 | {
7 | Task SendEmailAsync(string email, string subject, string message);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "asp.net",
3 | "private": true,
4 | "dependencies": {
5 | "bootstrap": "3.3.7",
6 | "jquery": "2.2.0",
7 | "jquery-validation": "1.14.0",
8 | "jquery-validation-unobtrusive": "3.2.6"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/common/Footer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function () {
4 | return (
5 |
8 | );
9 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | });
9 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Account/Lockout.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Locked Out";
3 | }
4 |
5 |
9 |
10 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/actions/ajaxStatusActions.js:
--------------------------------------------------------------------------------
1 | import * as types from './actionTypes';
2 |
3 | export function beginAjaxCall() {
4 | return {type: types.BEGIN_AJAX_CALL};
5 | }
6 |
7 | export function ajaxCallError() {
8 | return {type: types.AJAX_CALL_ERROR};
9 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Data/DTO/OfficeAssignmentDTO.cs:
--------------------------------------------------------------------------------
1 | namespace ContosoUniversity.Data.DTO
2 | {
3 | public class OfficeAssignmentDTO
4 | {
5 | public int ID { get; set; }
6 | public int InstructorID { get; set; }
7 | public string Location { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/selectors/selectors.js:
--------------------------------------------------------------------------------
1 | export function departmentsFormattedForDropdown(departments){
2 | return departments.map(department => {
3 | return {
4 | value: department.id,
5 | text: department.name
6 | };
7 | });
8 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Helpers/IUrlHelperAdaptor.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 |
3 | namespace ContosoUniversity.Web.Helpers
4 | {
5 | public interface IUrlHelperAdaptor
6 | {
7 | string Action(IUrlHelper helper, string action, string controller, object values, string protocol);
8 | }
9 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/ManageIndexViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace ContosoUniversity.Web.ViewModels
2 | {
3 | public class ManageIndexViewModel
4 | {
5 | public bool HasPassword { get; set; }
6 | public string PhoneNumber { get; set; }
7 | public bool TwoFactor { get; set; }
8 | }
9 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Data/AdminIdentityOptions.cs:
--------------------------------------------------------------------------------
1 | namespace ContosoUniversity.Data
2 | {
3 | public class AdminIdentityOptions
4 | {
5 | public string Role { get; } = "Administrator";
6 | public string UserName { get; set; }
7 | public string Password { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ContosoUniversity.Common/SMSOptions.cs:
--------------------------------------------------------------------------------
1 | namespace ContosoUniversity.Common
2 | {
3 | public class SMSOptions
4 | {
5 | public string SMSAccountIdentification { get; set; }
6 | public string SMSAccountPassword { get; set; }
7 | public string SMSAccountFrom { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Account/ResetPasswordConfirmation.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Reset password confirmation";
3 | }
4 |
5 | @ViewData["Title"]
6 |
7 |
8 | Your password has been reset. Please Click here to log in.
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "ConnectionStrings": {
3 | "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity2017;Trusted_Connection=True;MultipleActiveResultSets=true"
4 | },
5 | "Logging": {
6 | "LogLevel": {
7 | "Default": "Warning"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Account/ConfirmEmail.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Confirm Email";
3 | }
4 |
5 | @ViewData["Title"]
6 |
11 |
12 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Models/SchoolViewModels/AssignedCourseData.cs:
--------------------------------------------------------------------------------
1 | namespace ContosoUniversity.Models.SchoolViewModels
2 | {
3 | public class AssignedCourseData
4 | {
5 | public int CourseID { get; set; }
6 | public string Title { get; set; }
7 | public bool Assigned { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/ForgotPasswordViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ContosoUniversity.Web.ViewModels
4 | {
5 | public class ForgotPasswordViewModel
6 | {
7 | [Required]
8 | [EmailAddress]
9 | public string Email { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web.Tests/Readme.md:
--------------------------------------------------------------------------------
1 | ## ContosoUniversity.Web.Test
2 | Unit test project for [ContosoUniversity.Web](https://github.com/alimon808/contoso-university/tree/master/ContosoUniversity.Web)
3 |
4 | ### Run tests
5 | ```
6 | git clone https://github.com/alimon808/contoso-university.git
7 | cd ContosoUniversity.Web.Test
8 | dotnet test
9 | ```
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/register/RegisterPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import RegisterForm from '../forms/Register';
3 |
4 | export default function () {
5 | return (
6 |
7 |
Register
8 |
9 |
10 | );
11 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "ContosoUniversity": {
4 | "commandName": "Project",
5 | "launchBrowser": true,
6 | "environmentVariables": {
7 | "ASPNETCORE_ENVIRONMENT": "Development"
8 | },
9 | "applicationUrl": "http://localhost:5000"
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/ExternalLoginConfirmationViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ContosoUniversity.Web.ViewModels
4 | {
5 | public class ExternalLoginConfirmationViewModel
6 | {
7 | [Required]
8 | [EmailAddress]
9 | public string Email { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "projects": [
3 | "ContosoUniversity.Web",
4 | "ContosoUniversity.Web.Tests",
5 | "ContosoUniversity.Api",
6 | "ContosoUniversity.Api.Tests",
7 | "ContosoUniversity.Data",
8 | "ContosoUniversity.Data.Tests"
9 | ],
10 | "sdk": {
11 | "version": "2.1.300"
12 | }
13 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Api/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "ConnectionStrings": {
3 | "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity2017;Trusted_Connection=True;MultipleActiveResultSets=true"
4 | },
5 | "Logging": {
6 | "IncludeScopes": false,
7 | "LogLevel": {
8 | "Default": "Warning"
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/DTO/InstructorDTO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ContosoUniversity.Data.DTO
4 | {
5 | public class InstructorDTO
6 | {
7 | public int ID { get; set; }
8 | public string FirstMidName { get; set; }
9 | public string LastName { get; set; }
10 | public DateTime HireDate { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/DTO/StudentDTO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ContosoUniversity.Data.DTO
4 | {
5 | public class StudentDTO
6 | {
7 | public int ID { get; set; }
8 | public string FirstMidName { get; set; }
9 | public string LastName { get; set; }
10 | public DateTime EnrollmentDate { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/Entities/CourseAssignment.cs:
--------------------------------------------------------------------------------
1 | namespace ContosoUniversity.Data.Entities
2 | {
3 | public class CourseAssignment : BaseEntity
4 | {
5 | public int InstructorID { get; set; }
6 | public int CourseID { get; set; }
7 | public Instructor Instructor { get; set; }
8 | public Course Course { get; set; }
9 | }
10 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/store/configureStore.js:
--------------------------------------------------------------------------------
1 | import {createStore, applyMiddleware} from 'redux';
2 | import rootReducer from '../reducers';
3 | import thunk from 'redux-thunk';
4 |
5 | export default function configureStore(initialState){
6 | return createStore(
7 | rootReducer,
8 | initialState,
9 | applyMiddleware(thunk)
10 | );
11 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Data/DTO/CourseDTO.cs:
--------------------------------------------------------------------------------
1 | namespace ContosoUniversity.Data.DTO
2 | {
3 | public class CourseDTO
4 | {
5 | public int ID { get; set; }
6 | public int CourseNumber { get; set; }
7 | public string Title { get; set; }
8 | public int Credits { get; set; }
9 | public int DepartmentID { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/DTO/EnrollmentDTO.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Data.Enums;
2 |
3 | namespace ContosoUniversity.Data.DTO
4 | {
5 | public class EnrollmentDTO
6 | {
7 | public int ID { get; set; }
8 | public int CourseID { get; set; }
9 | public int StudentID { get; set; }
10 | public Grade? Grade { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/AddPhoneNumberViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ContosoUniversity.Web.ViewModels
4 | {
5 | public class AddPhoneNumberViewModel
6 | {
7 | [Required]
8 | [Phone]
9 | [Display(Name = "Phone number")]
10 | public string PhoneNumber { get; set; }
11 | }
12 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "ConnectionStrings": {
3 | "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity2017;Trusted_Connection=True;MultipleActiveResultSets=true"
4 | },
5 | "EnableHttps": "true",
6 | "Logging": {
7 | "IncludeScopes": false,
8 | "LogLevel": {
9 | "Default": "Warning"
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: csharp
2 | mono: none
3 | dotnet: 2.1.300
4 |
5 | install:
6 | - dotnet restore
7 |
8 | script:
9 | - dotnet build
10 | - dotnet test ContosoUniversity.Data.Tests/ContosoUniversity.Data.Tests.csproj
11 | - dotnet test ContosoUniversity.Web.Tests/ContosoUniversity.Web.Tests.csproj
12 | - dotnet test ContosoUniversity.Api.Tests/ContosoUniversity.Api.Tests.csproj
--------------------------------------------------------------------------------
/ContosoUniversity.Data/OperatingSystem.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace ContosoUniversity.Data
4 | {
5 | public static class OperatingSystem
6 | {
7 | public static bool IsWindows() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
8 | public static bool IsMacOs() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
9 | }
10 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Common/Interfaces/IPersonRepository.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Data.Entities;
2 | using Microsoft.EntityFrameworkCore;
3 | using System.Linq;
4 |
5 | namespace ContosoUniversity.Common.Interfaces
6 | {
7 | public interface IPersonRepository : IRepository where T : Person
8 | {
9 | IQueryable GetByLastName(string lastName);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ContosoUniversity.Common/OperatingSystem.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace ContosoUniversity.Common
4 | {
5 | public static class OperatingSystem
6 | {
7 | public static bool IsWindows() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
8 | public static bool IsMacOs() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
9 | }
10 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ReadMe.md:
--------------------------------------------------------------------------------
1 | ## ContosoUniversity.Spa.React
2 | Single Page Application (SPA) using React front-end framework and WebApi backend
3 |
4 | ### Prerequisites
5 | - .NET Core SDK v2.1.0 or later
6 | - Node.js v6.0 or later
7 |
8 | ### Run App
9 | ```
10 | git clone https://github.com/alimon808/contoso-university.git
11 | cd ContosoUniversity.Spa.React
12 | dotnet run
13 | ```
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | import {combineReducers} from 'redux';
2 | import courses from './courseReducer';
3 | import departments from './departmentReducer';
4 | import ajaxCallsInProgress from './ajaxStatusReducer';
5 |
6 | const rootReducer = combineReducers({
7 | courses,
8 | departments,
9 | ajaxCallsInProgress
10 | });
11 |
12 | export default rootReducer;
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Models/SchoolViewModels/EnrollmentDateGroup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel.DataAnnotations;
3 |
4 | namespace ContosoUniversity.Models.SchoolViewModels
5 | {
6 | public class EnrollmentDateGroup
7 | {
8 | [DataType(DataType.Date)]
9 | public DateTime? EnrollmentDate { get; set; }
10 | public int StudentCount { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Enums/ManageMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace ContosoUniversity.Web.Enums
7 | {
8 | public enum ManageMessage
9 | {
10 | ChangePasswordSuccess,
11 | Error,
12 | AddPhoneSuccess,
13 | RemovePhoneSuccess,
14 | SetTwoFactorSuccess
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Pages/Contact.cshtml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc.RazorPages;
2 | using System;
3 |
4 | namespace ContosoUniversity.Web.Pages
5 | {
6 | public class ContactModel : PageModel
7 | {
8 | public string Message { get; private set; } = "PageModel in C#";
9 | public void OnGet()
10 | {
11 | Message += $" Server time is {DateTime.Now}";
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/actions/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const BEGIN_AJAX_CALL = 'BEGIN_AJAX_CALL';
2 | export const AJAX_CALL_ERROR = 'AJAX_CALL_ERROR';
3 |
4 | export const LOAD_COURSES_SUCCESS = 'LOAD_COURSES_SUCCESS';
5 | export const CREATE_COURSE_SUCCESS = 'CREATE_COURSE_SUCCESS';
6 | export const UPDATE_COURSE_SUCCESS = 'UPDATE_COURSE_SUCCESS';
7 | export const LOAD_DEPARTMENTS_SUCCESS = 'LOAD_DEPARTMENTS_SUCCESS';
8 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web.IntegrationTests/Readme.md:
--------------------------------------------------------------------------------
1 | ## ContosoUniversity.Web.IntegrationTests
2 |
3 | ### Run Integration Tests from command line
4 | ```
5 | git clone https://github.com/alimon808/contoso-university.git
6 | cd ContosoUniverity.Web.IntegrationTests
7 | dotnet test
8 | ```
9 |
10 | ### References
11 | [Integration Test in Asp.Net Core](https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.1)
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/TokenViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ContosoUniversity.Web.ViewModels
4 | {
5 | public class TokenViewModel
6 | {
7 | [Required]
8 | [EmailAddress]
9 | public string Email { get; set; }
10 |
11 | [Required]
12 | [DataType(DataType.Password)]
13 | public string Password { get; set; }
14 | }
15 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/reducers/departmentReducer.js:
--------------------------------------------------------------------------------
1 | import * as types from '../actions/actionTypes';
2 | import initialState from './initialState';
3 |
4 | export default function departmentReducer(state = initialState.departments, action){
5 | switch(action.type) {
6 | case types.LOAD_DEPARTMENTS_SUCCESS:
7 | return action.departments;
8 | default:
9 | return state;
10 | }
11 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/VerifyPhoneNumberViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ContosoUniversity.Web.ViewModels
4 | {
5 | public class VerifyPhoneNumberViewModel
6 | {
7 | [Required]
8 | public string Code { get; set; }
9 |
10 | [Required]
11 | [Phone]
12 | [Display(Name = "Phone number")]
13 | public string PhoneNumber { get; set; }
14 | }
15 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "ContosoUniversity_Spa_React",
3 | "name": "ContosoUniversity_Spa_React",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ReactApiProfile.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using ContosoUniversity.Spa.React.DTO;
3 | using ContosoUniversity.Common.DTO;
4 | using ContosoUniversity.Data.Entities;
5 |
6 | namespace ContosoUniversity.Spa.React
7 | {
8 | public class ReactApiProfile : Profile
9 | {
10 | public ReactApiProfile()
11 | {
12 | CreateMap().ReverseMap();
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ContosoUniversity.Api/wwwroot/swagger/ui/css/custom.css:
--------------------------------------------------------------------------------
1 | .swagger-section #header {
2 | border-bottom: 1px solid #000000;
3 | font-style: normal;
4 | font-weight: 400;
5 | font-family: "Segoe UI Light","Segoe WP Light","Segoe UI","Segoe WP",Tahoma,Arial,sans-serif;
6 | background-color: black;
7 | }
8 |
9 | .swagger-section #header h1 {
10 | text-align: center;
11 | font-size: 20px;
12 | color: white;
13 | }
14 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Models/SchoolViewModels/InstructorIndexData.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Data.Entities;
2 | using System.Collections.Generic;
3 |
4 | namespace ContosoUniversity.Models.SchoolViewModels
5 | {
6 | public class InstructorIndexData
7 | {
8 | public IEnumerable Instructors { get; set; }
9 | public IEnumerable Courses { get; set; }
10 | public IEnumerable Enrollments { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/SendCodeViewModel.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc.Rendering;
2 | using System.Collections.Generic;
3 |
4 | namespace ContosoUniversity.Web.ViewModels
5 | {
6 | public class SendCodeViewModel
7 | {
8 | public string SelectedProvider { get; set; }
9 | public ICollection Providers { get; set; }
10 | public string ReturnUrl { get; set; }
11 | public bool RememberMe { get; set; }
12 | }
13 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/css/site.min.css:
--------------------------------------------------------------------------------
1 | body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}input,select,textarea{max-width:280px}.carousel-caption p{font-size:20px;line-height:1.4}.carousel-inner .item img[src$=".svg"]{width:100%}.btn-bracketed::before{display:inline-block;content:"[";padding-right:.5em}.btn-bracketed::after{display:inline-block;content:"]";padding-left:.5em}@media screen and (max-width:767px){.carousel-caption{display:none}}
--------------------------------------------------------------------------------
/ContosoUniversity.Common/DTO/DepartmentDTO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel.DataAnnotations;
3 |
4 | namespace ContosoUniversity.Common.DTO
5 | {
6 | public class DepartmentDTO
7 | {
8 | [Required]
9 | public int ID { get; set; }
10 | public int InstructorID { get; set; }
11 | public string Name { get; set; }
12 | public decimal Budget { get; set; }
13 | public DateTime StartDate { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/DepartmentEditViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ContosoUniversity.ViewModels
4 | {
5 | public class DepartmentEditViewModel : DepartmentBaseViewModel
6 | {
7 | [Required]
8 | public int ID { get; set; }
9 |
10 | public string RowVersion { get; set; }
11 |
12 | [Display(Name = "Administrator")]
13 | public int InstructorID { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/Entities/OfficeAssignment.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ContosoUniversity.Data.Entities
4 | {
5 | public class OfficeAssignment : BaseEntity
6 | {
7 | //[Key]
8 | public int InstructorID { get; set; }
9 |
10 | [StringLength(50)]
11 | [Display(Name = "Office Location")]
12 | public string Location { get; set; }
13 |
14 | public Instructor Instructor { get; set; }
15 | }
16 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Api/ApiProfile.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using ContosoUniversity.Api.DTO;
3 | using ContosoUniversity.Common.DTO;
4 | using ContosoUniversity.Data.Entities;
5 |
6 | namespace ContosoUniversity.Api
7 | {
8 | public class ApiProfile : Profile
9 | {
10 | public ApiProfile()
11 | {
12 | CreateMap().ReverseMap();
13 | CreateMap().ReverseMap();
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/Entities/BaseEntity.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel.DataAnnotations;
3 |
4 | namespace ContosoUniversity.Data.Entities
5 | {
6 | public abstract class BaseEntity
7 | {
8 | public int ID { get; set; }
9 | public DateTime AddedDate { get; set; } = DateTime.UtcNow;
10 | public DateTime ModifiedDate { get; set; } = DateTime.UtcNow;
11 |
12 | [Timestamp]
13 | public byte[] RowVersion { get; set; }
14 | }
15 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/DepartmentCreateViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel.DataAnnotations;
3 |
4 | namespace ContosoUniversity.ViewModels
5 | {
6 | public class DepartmentCreateViewModel : DepartmentBaseViewModel
7 | {
8 | [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
9 | public override DateTime StartDate { get; set; }
10 |
11 | public int InstructorID { get; set; } = 0;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ContosoUniversity.Api/DTO/CreateDepartmentDTO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel.DataAnnotations;
3 |
4 | namespace ContosoUniversity.Api.DTO
5 | {
6 | public class CreateDepartmentDTO
7 | {
8 | [Required]
9 | public int InstructorID { get; set; }
10 | [Required]
11 | public string Name { get; set; }
12 |
13 | public decimal Budget { get; set; } = 0;
14 | public DateTime StartDate { get; set; } = DateTime.UtcNow;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/RegisterViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ContosoUniversity.Web.ViewModels
4 | {
5 | public class RegisterViewModel
6 | {
7 | [DataType(DataType.EmailAddress)]
8 | public string Email { get; set; }
9 |
10 | [DataType(DataType.Password)]
11 | public string Password { get; set; }
12 |
13 | [DataType(DataType.Password)]
14 | public string ConfirmPassword { get; set; }
15 | }
16 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/DTO/CreateDepartmentDTO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel.DataAnnotations;
3 |
4 | namespace ContosoUniversity.Spa.React.DTO
5 | {
6 | public class CreateDepartmentDTO
7 | {
8 | [Required]
9 | public int InstructorID { get; set; }
10 | [Required]
11 | public string Name { get; set; }
12 |
13 | public decimal Budget { get; set; } = 0;
14 | public DateTime StartDate { get; set; } = DateTime.UtcNow;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/LoginViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ContosoUniversity.Web.ViewModels
4 | {
5 | public class LoginViewModel
6 | {
7 | [Required]
8 | [EmailAddress]
9 | public string Email { get; set; }
10 |
11 | [Required]
12 | [DataType(DataType.Password)]
13 | public string Password { get; set; }
14 |
15 | [Display(Name = "Remember me?")]
16 | public bool RememberMe { get; set; }
17 | }
18 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Data/Entities/Enrollment.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Data.Enums;
2 | using System.ComponentModel.DataAnnotations;
3 |
4 | namespace ContosoUniversity.Data.Entities
5 | {
6 | public class Enrollment : BaseEntity
7 | {
8 | public int CourseID { get; set; }
9 | public int StudentID { get; set; }
10 |
11 | [DisplayFormat(NullDisplayText = "No Grade")]
12 | public Grade? Grade { get; set; }
13 | public Course Course { get; set; }
14 | public Student Student { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/Entities/Student.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 |
5 | namespace ContosoUniversity.Data.Entities
6 | {
7 | public class Student : Person
8 | {
9 | [Display(Name = "Enrollment Date")]
10 | [DataType(DataType.Date)]
11 | [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
12 | public DateTime EnrollmentDate { get; set; }
13 |
14 | public ICollection Enrollments { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/DepartmentDetailsViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel.DataAnnotations;
3 |
4 | namespace ContosoUniversity.ViewModels
5 | {
6 | public class DepartmentDetailsViewModel : DepartmentBaseViewModel
7 | {
8 | public int ID { get; set; }
9 |
10 | public override string Name { get; set; }
11 |
12 | [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}")]
13 | public override DateTime StartDate { get; set; }
14 |
15 | public int InstructorID { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/lib/bootstrap/dist/js/npm.js:
--------------------------------------------------------------------------------
1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
2 | require('../../js/transition.js')
3 | require('../../js/alert.js')
4 | require('../../js/button.js')
5 | require('../../js/carousel.js')
6 | require('../../js/collapse.js')
7 | require('../../js/dropdown.js')
8 | require('../../js/modal.js')
9 | require('../../js/tooltip.js')
10 | require('../../js/popover.js')
11 | require('../../js/scrollspy.js')
12 | require('../../js/tab.js')
13 | require('../../js/affix.js')
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/course/CourseListRow.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import {Link} from 'react-router-dom';
4 |
5 | const CourseListRow = ({course}) => {
6 | return (
7 |
8 | | {course.courseNumber} |
9 | {course.title} |
10 | {course.credits} |
11 |
12 | );
13 | };
14 |
15 | CourseListRow.propTypes = {
16 | course: PropTypes.object.isRequired
17 | };
18 |
19 | export default CourseListRow;
--------------------------------------------------------------------------------
/ContosoUniversity.Web/IModelBindingHelperAdaptor.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 | using System;
3 | using System.Linq.Expressions;
4 | using System.Threading.Tasks;
5 |
6 | namespace ContosoUniversity.Web
7 | {
8 | public interface IModelBindingHelperAdaptor
9 | {
10 | Task TryUpdateModelAsync(ControllerBase controller, TModel model, string prefix, params Expression>[] includeExpressions) where TModel : class;
11 | Task TryUpdateModelAsync(ControllerBase controller, TModel model) where TModel : class;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/reducers/ajaxStatusReducer.js:
--------------------------------------------------------------------------------
1 | import * as types from '../actions/actionTypes';
2 | import initialState from './initialState';
3 |
4 | function actionTypeEndsInSuccess(type) {
5 | return type.substring(type.length - 8) === '_SUCCESS';
6 | }
7 |
8 | export default function ajaxStatusReducer(state = initialState.ajaxCallsInProgress, action) {
9 | if(action.type === types.BEGIN_AJAX_CALL) {
10 | return state + 1;
11 | } else if (action.type === types.AJAX_CALL_ERROR || actionTypeEndsInSuccess(action.type)) {
12 | return state - 1;
13 | }
14 |
15 | return state;
16 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/VerifyCodeViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ContosoUniversity.Web.ViewModels
4 | {
5 | public class VerifyCodeViewModel
6 | {
7 | [Required]
8 | public string Provider { get; set; }
9 |
10 | [Required]
11 | public string Code { get; set; }
12 |
13 |
14 | public string ReturnUrl { get; set; }
15 |
16 | [Display(Name = "Remember me?")]
17 | public bool RememberMe { get; set; }
18 |
19 | [Display(Name = "Remember this browser?")]
20 | public bool RememberBrowser { get; set; }
21 | }
22 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Data/Entities/Instructor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 |
5 | namespace ContosoUniversity.Data.Entities
6 | {
7 | public class Instructor : Person
8 | {
9 | [DataType(DataType.Date)]
10 | [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
11 | [Display(Name = "Hire Date")]
12 | public DateTime HireDate { get; set; }
13 |
14 | public ICollection CourseAssignments { get; set; }
15 | public OfficeAssignment OfficeAssignment { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/reducers/courseReducer.js:
--------------------------------------------------------------------------------
1 | import * as types from '../actions/actionTypes';
2 | import initialState from './initialState';
3 |
4 | export default function courseReducer(state = initialState.courses, action){
5 | switch(action.type){
6 | case types.LOAD_COURSES_SUCCESS:
7 | return action.courses;
8 | case types.CREATE_COURSE_SUCCESS:
9 | return [...state, Object.assign({}, action.course)];
10 | case types.UPDATE_COURSE_SUCCESS:
11 | return [...state, Object.assign({}, action.course)];
12 | default:
13 | return state;
14 | }
15 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Pages/Contact.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ContosoUniversity.Web.Pages.ContactModel
3 | @{
4 | ViewData["Title"] = "Contact";
5 | Layout = "~/Views/Shared/_Layout.cshtml";
6 | }
7 |
8 | @ViewData["Title"]
9 | @Model.Message
10 |
11 |
12 | One Microsoft Way
13 | Redmond, WA 98052-6399
14 | P:
15 | 425.555.0100
16 |
17 |
18 |
19 | Support: Support@example.com
20 | Marketing: Marketing@example.com
21 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/department/DepartmentListRow.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import Moment from 'moment';
4 | import Numeral from 'numeral';
5 |
6 | const DepartmentListRow = ({department}) => {
7 | return(
8 |
9 | | {department.name} |
10 | {Numeral(department.budget).format('$0,0.00')} |
11 | {Moment(department.startDate).format('DD/MM/YYYY')} |
12 |
13 | );
14 | };
15 |
16 | DepartmentListRow.propTypes = {
17 | department: PropTypes.object.isRequired
18 | }
19 |
20 | export default DepartmentListRow;
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/lib/jquery/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery",
3 | "main": "dist/jquery.js",
4 | "license": "MIT",
5 | "ignore": [
6 | "package.json"
7 | ],
8 | "keywords": [
9 | "jquery",
10 | "javascript",
11 | "browser",
12 | "library"
13 | ],
14 | "homepage": "https://github.com/jquery/jquery-dist",
15 | "version": "2.2.0",
16 | "_release": "2.2.0",
17 | "_resolution": {
18 | "type": "version",
19 | "tag": "2.2.0",
20 | "commit": "6fc01e29bdad0964f62ef56d01297039cdcadbe5"
21 | },
22 | "_source": "git://github.com/jquery/jquery-dist.git",
23 | "_target": "2.2.0",
24 | "_originalSource": "jquery"
25 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/actions/departmentActions.js:
--------------------------------------------------------------------------------
1 | import * as types from './actionTypes';
2 | import departmentApi from '../api/mockDepartmentApi';
3 | import {beginAjaxCall} from './ajaxStatusActions';
4 |
5 | export function loadDepartmentsSuccess(departments) {
6 | return {type: types.LOAD_DEPARTMENTS_SUCCESS, departments};
7 | }
8 |
9 | export function loadDepartments(){
10 | return function(dispatch){
11 | dispatch(beginAjaxCall());
12 | return departmentApi.getAllDepartments().then(departments => {
13 | dispatch(loadDepartmentsSuccess(departments));
14 | }).catch(error => {
15 | throw(error);
16 | });
17 | }
18 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Api/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "LogLevel": {
5 | "Default": "Debug",
6 | "System": "Information",
7 | "Microsoft": "Information"
8 | }
9 | },
10 | "Administrator": {
11 | "UserName": "abc@example.com",
12 | "Password": "DO-NOT-STORE-WEAK-P@ssw0rd!"
13 | },
14 | "Authentication": {
15 | "Google": {
16 | "ClientId": "DO-NOT-STORE-HERE",
17 | "ClientSecret": "DO-NOT-STORE-HERE"
18 | },
19 | "Tokens": {
20 | "Issuer": "https://localhost:20650/",
21 | "Audience": "http://localhost:6188/",
22 | "Key": "DO-NOT-STORE-HERE-1absa-adljkzer-zldr"
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/DepartmentBaseViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel.DataAnnotations;
3 |
4 | namespace ContosoUniversity.ViewModels
5 | {
6 | public abstract class DepartmentBaseViewModel
7 | {
8 | [StringLength(50, MinimumLength = 3)]
9 | public virtual string Name { get; set; }
10 | public virtual decimal Budget { get; set; }
11 |
12 | [DataType(DataType.Date)]
13 | [Display(Name = "Start Date")]
14 | [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
15 | public virtual DateTime StartDate { get; set; }
16 |
17 | public virtual string Administrator { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/DbContexts/ApiContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 |
3 | namespace ContosoUniversity.Data.DbContexts
4 | {
5 | public class ApiContext : DbContext
6 | {
7 | public ApiContext(DbContextOptions options) : base(options)
8 | {
9 | }
10 |
11 | protected override void OnModelCreating(ModelBuilder modelBuilder)
12 | {
13 | string schema = "Contoso";
14 | if (OperatingSystem.IsMacOs())
15 | {
16 | schema = null;
17 | }
18 |
19 | var config = new DbContextConfig();
20 | config.ApplicationContextConfig(modelBuilder, schema);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/QueryableExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Query.Internal;
3 | using System.Linq;
4 |
5 | namespace ContosoUniversity
6 | {
7 | // see issue @ https://stackoverflow.com/questions/27038253/mock-asnotracking-entity-framework
8 | // workaround @ https://github.com/aspnet/EntityFramework/issues/7937
9 | public static class QueryableExtensions
10 | {
11 | public static IQueryable AsGatedNoTracking(this IQueryable source) where T : class
12 | {
13 | if (source.Provider is EntityQueryProvider)
14 | return source.AsNoTracking();
15 | return source;
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/bundleconfig.json:
--------------------------------------------------------------------------------
1 | // Configure bundling and minification for the project.
2 | // More info at https://go.microsoft.com/fwlink/?LinkId=808241
3 | [
4 | {
5 | "outputFileName": "wwwroot/css/site.min.css",
6 | // An array of relative input file paths. Globbing patterns supported
7 | "inputFiles": [
8 | "wwwroot/css/site.css"
9 | ]
10 | },
11 | {
12 | "outputFileName": "wwwroot/js/site.min.js",
13 | "inputFiles": [
14 | "wwwroot/js/site.js"
15 | ],
16 | // Optionally specify minification options
17 | "minify": {
18 | "enabled": true,
19 | "renameLocals": true
20 | },
21 | // Optionally generate .map file
22 | "sourceMap": false
23 | }
24 | ]
25 |
--------------------------------------------------------------------------------
/ContosoUniversity.Api.Tests/appsettings.Testing.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "LogLevel": {
5 | "Default": "Debug",
6 | "System": "Information",
7 | "Microsoft": "Information"
8 | }
9 | },
10 | "IdentityUser": {
11 | "Role": "Administrator",
12 | "UserName": "abc@example.com",
13 | "Password": "DO-NOT-STORE-HERE-P@ssw0rd!"
14 | },
15 | "Authentication": {
16 | "Google": {
17 | "ClientId": "DO-NOT-STORE-HERE",
18 | "ClientSecret": "DO-NOT-STORE-HERE"
19 | },
20 | "Tokens": {
21 | "Issuer": "https://localhost/",
22 | "Audience": "https://localhost/",
23 | "Key": "DO-NOT-STORE-HERE-1absa-adljkzer-zldr"
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ContosoUniversity.Common/Interfaces/IRepository.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Data.Entities;
2 | using Microsoft.EntityFrameworkCore;
3 | using System.Data.Common;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace ContosoUniversity.Common.Interfaces
8 | {
9 | public interface IRepository where T : BaseEntity
10 | {
11 | IQueryable GetAll();
12 | IQueryable Get(int id);
13 | void Add(T entity);
14 | Task AddAsync(T entity);
15 | void Update(T entity, byte[] rowVersion);
16 | void Delete(T entity);
17 | Task ExecuteSqlCommandAsync(string queryString);
18 | Task SaveChangesAsync();
19 | DbConnection GetDbConnection();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Pages/About.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ContosoUniversity.Web.Pages.AboutModel
3 | @{
4 | Layout = "~/Views/Shared/_Layout.cshtml";
5 | ViewData["Title"] = "Student Body Statistics";
6 | }
7 |
8 | @ViewData["Title"].
9 |
10 |
11 |
12 | |
13 | Enrollment Date
14 | |
15 |
16 | Students
17 | |
18 |
19 | @foreach (var item in Model.StudentEnrollments)
20 | {
21 |
22 | |
23 | @Html.DisplayFor(modelItem => item.EnrollmentDate)
24 | |
25 |
26 | @item.StudentCount
27 | |
28 |
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/contact/ContactPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function () {
4 | return (
5 |
17 | );
18 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Logging;
10 |
11 | namespace ContosoUniversity.Spa.React
12 | {
13 | public class Program
14 | {
15 | public static void Main(string[] args)
16 | {
17 | CreateWebHostBuilder(args).Build().Run();
18 | }
19 |
20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
21 | WebHost.CreateDefaultBuilder(args)
22 | .UseStartup();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Account/SendCode.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Web.ViewModels.SendCodeViewModel
2 | @{
3 | ViewData["Title"] = "Send Code";
4 | }
5 |
6 | @ViewData["Title"]
7 |
8 |
22 |
23 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data.Tests/ContosoUniversity.Data.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/ContosoUniversity.Common/Data/SampleData.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Data.DTO;
2 | using ContosoUniversity.Common.DTO;
3 | using System.Collections.Generic;
4 |
5 | namespace ContosoUniversity.Common.Data
6 | {
7 | public class SampleData
8 | {
9 | public List Enrollments { get; set; }
10 | public List Courses { get; set; }
11 | public List CourseAssignments { get; set; }
12 | public List Departments { get; set; }
13 | public List Students { get; set; }
14 | public List OfficeAssignments { get; set; }
15 | public List Instructors { get; set; }
16 | public bool SaveToExternalFile { get; set; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/common/Layout.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Col, Grid, Row } from 'react-bootstrap';
3 | import { NavMenu } from './NavMenu';
4 | import './Layout.css';
5 | import Footer from './Footer';
6 |
7 |
8 | export class Layout extends Component {
9 | displayName = Layout.name
10 | render() {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 | {this.props.children}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Shared/Error.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Error";
3 | }
4 |
5 | Error.
6 | An error occurred while processing your request.
7 |
8 | Development Mode
9 |
10 | Swapping to Development environment will display more detailed information about the error that occurred.
11 |
12 |
13 | Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application.
14 |
15 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/course/CourseList.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types'
3 | import CourseListRow from './CourseListRow';
4 |
5 | const CourseList = ({courses}) => {
6 | return (
7 |
8 |
9 |
10 | | Number |
11 | Title |
12 | Credits |
13 |
14 |
15 |
16 | {courses.map(course => )}
17 |
18 |
19 | );
20 | };
21 |
22 | CourseList.propTypes = {
23 | courses: PropTypes.array.isRequired
24 | };
25 |
26 | export default CourseList;
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Courses/UpdateCourseCredits.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewBag.Title = "UpdateCourseCredits";
3 | }
4 |
5 | Update Course Credits
6 | @if (ViewData["RowsAffected"] == null)
7 | {
8 |
18 | }
19 |
20 | @if (ViewData["RowsAffected"] != null)
21 | {
22 |
23 | Number of rows updated: @ViewData["RowsAffected"]
24 |
25 | }
26 |
27 |
28 | @Html.ActionLink("Back to List", "Index")
29 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/Entities/Course.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.ComponentModel.DataAnnotations;
3 | using System.ComponentModel.DataAnnotations.Schema;
4 |
5 | namespace ContosoUniversity.Data.Entities
6 | {
7 | public class Course : BaseEntity
8 | {
9 | [Display(Name = "Number")]
10 | public int CourseNumber { get; set; }
11 |
12 | [StringLength(50, MinimumLength = 3)]
13 | public string Title { get; set; }
14 |
15 | [Range(0, 5)]
16 | public int Credits { get; set; }
17 |
18 | public int DepartmentID { get; set; }
19 |
20 | public Department Department { get; set; }
21 | public ICollection Enrollments { get; set; }
22 | public ICollection CourseAssignments { get; set; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/ContosoUniversity.Api/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "https://localhost:44352/",
7 | "sslPort": 44352
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "launchUrl": "departments",
15 | "environmentVariables": {
16 | "ASPNETCORE_ENVIRONMENT": "Development"
17 | }
18 | },
19 | "ContosoUniversity.Api": {
20 | "commandName": "Project",
21 | "launchBrowser": true,
22 | "launchUrl": "api/values",
23 | "environmentVariables": {
24 | "ASPNETCORE_ENVIRONMENT": "Development"
25 | },
26 | "applicationUrl": "http://localhost:6188"
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/department/DepartmentList.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import DepartmentListRow from './DepartmentListRow';
4 |
5 | const DepartmentList =({departments}) => {
6 | return(
7 |
8 |
9 |
10 | | Name |
11 | Budget |
12 | Start Date |
13 |
14 |
15 |
16 | {departments.map((department) => )}
17 |
18 |
19 | );
20 | }
21 |
22 | DepartmentList.propTypes = {
23 | departments: PropTypes.array.isRequired
24 | }
25 |
26 | export default DepartmentList;
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "label": "build-web-app",
8 | "command": "dotnet build ContosoUniversity.Web",
9 | "type": "shell",
10 | "group": "build",
11 | "presentation": {
12 | "reveal": "silent"
13 | },
14 | "problemMatcher": "$msCompile"
15 | },
16 | {
17 | "label": "build-api",
18 | "command": "dotnet build ContosoUniversity.Api",
19 | "type": "shell",
20 | "group": "build",
21 | "presentation": {
22 | "reveal": "silent"
23 | },
24 | "problemMatcher": "$msCompile"
25 | }
26 | ]
27 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/ResetPasswordViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ContosoUniversity.Web.ViewModels
4 | {
5 | public class ResetPasswordViewModel
6 | {
7 | [Required]
8 | [EmailAddress]
9 | public string Email { get; set; }
10 |
11 | [Required]
12 | [StringLength(100, ErrorMessage ="The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
13 | [DataType(DataType.Password)]
14 | public string Password { get; set; }
15 |
16 | [DataType(DataType.Password)]
17 | [Display(Name = "Confirm Password")]
18 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
19 | public string ConfirmPassword { get; set; }
20 |
21 | public string Code { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ContosoUniversity.Api.Tests/ApiIntegrationTests.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Tests;
2 | using System.Net;
3 | using System.Threading.Tasks;
4 | using Xunit;
5 |
6 | namespace ContosoUniversity.Api.Tests
7 | {
8 | public class ApiIntegrationTests : BaseIntegrationTest
9 | {
10 | [Fact(Skip = "Move to separate project")]
11 | public async Task DepartmentApi_ReturnsArrayOfDepartmentObjects()
12 | {
13 | var url = "/Departments";
14 | using (var th = InitTestServer())
15 | {
16 | var client = th.CreateClient();
17 | var response = await client.GetAsync(url);
18 |
19 | Assert.Equal(HttpStatusCode.OK, response.StatusCode);
20 |
21 | var content = await response.Content.ReadAsStringAsync();
22 | Assert.True(content.Contains("English"));
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/Entities/Person.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Data;
2 | using System.ComponentModel.DataAnnotations;
3 | using System.ComponentModel.DataAnnotations.Schema;
4 |
5 | namespace ContosoUniversity.Data.Entities
6 | {
7 | public class Person : BaseEntity
8 | {
9 | [Required]
10 | [StringLength(50)]
11 | [Display(Name = "Last Name")]
12 | public string LastName { get; set; }
13 |
14 | [Required]
15 | [StringLength(50, ErrorMessage = "First name cannot be longer than 50 characters.")]
16 | [Column("FirstName")]
17 | [Display(Name = "First Name")]
18 | public string FirstMidName { get; set; }
19 |
20 | [Display(Name = "Full Name")]
21 | public string FullName
22 | {
23 | get
24 | {
25 | return LastName + ", " + FirstMidName;
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iis": {
6 | "applicationUrl": "http://localhost/ContosoUniversity.Web",
7 | "sslPort": 0
8 | },
9 | "iisExpress": {
10 | "applicationUrl": "https://localhost:44368/",
11 | "sslPort": 44368
12 | }
13 | },
14 | "profiles": {
15 | "IIS Express": {
16 | "commandName": "IISExpress",
17 | "launchBrowser": true,
18 | "environmentVariables": {
19 | "ASPNETCORE_ENVIRONMENT": "Development"
20 | }
21 | },
22 | "ContosoUniversity": {
23 | "commandName": "Project",
24 | "launchBrowser": true,
25 | "environmentVariables": {
26 | "ASPNETCORE_ENVIRONMENT": "Development"
27 | },
28 | "applicationUrl": "http://localhost:20645;https://localhost:20650;"
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ViewModels/ChangePasswordViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace ContosoUniversity.Web.ViewModels
4 | {
5 | public class ChangePasswordViewModel
6 | {
7 | [Required]
8 | [DataType(DataType.Password)]
9 | [Display(Name = "Current Password")]
10 | public string OldPassword { get; set; }
11 |
12 | [Required]
13 | [StringLength(100, ErrorMessage ="The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
14 | [DataType(DataType.Password)]
15 | [Display(Name = "New Password")]
16 | public string NewPassword { get; set; }
17 |
18 | [DataType(DataType.Password)]
19 | [Display(Name = "Confirm new password")]
20 | [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match")]
21 | public string ConfirmPassword { get; set; }
22 | }
23 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/department/DepartmentsPage.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import DepartmentList from './DepartmentList';
3 |
4 | class DepartmentsPage extends Component {
5 | constructor(props){
6 | super(props);
7 | this.state = {departments: [], loading: true};
8 | fetch('api/department/details')
9 | .then(response => response.json())
10 | .then(data => {
11 | this.setState({departments: data, loading: false});
12 | });
13 | }
14 |
15 | render() {
16 | let contents = this.state.loading
17 | ? Loading...
18 | : ;
19 | return (
20 |
21 |
Departments
22 | {contents}
23 |
24 | );
25 | }
26 | }
27 |
28 | export default DepartmentsPage;
--------------------------------------------------------------------------------
/ContosoUniversity.Data/Entities/Department.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.ComponentModel.DataAnnotations.Schema;
5 |
6 | namespace ContosoUniversity.Data.Entities
7 | {
8 | public class Department : BaseEntity
9 | {
10 | [StringLength(50, MinimumLength = 3)]
11 | public string Name { get; set; }
12 |
13 | [DataType(DataType.Currency)]
14 | [Column(TypeName = "money")]
15 | public decimal Budget { get; set; }
16 |
17 | [DataType(DataType.Date)]
18 | [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
19 | [Display(Name = "Start Date")]
20 | public DateTime StartDate { get; set; }
21 |
22 | public int? InstructorID { get; set; }
23 |
24 | public Instructor Administrator { get; set; }
25 | public ICollection Courses { get; set; }
26 | }
27 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Common/Repositories/PersonRepository.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Data.Entities;
2 | using ContosoUniversity.Common.Interfaces;
3 | using System;
4 | using System.Linq;
5 | using ContosoUniversity.Data;
6 | using Microsoft.EntityFrameworkCore;
7 |
8 | namespace ContosoUniversity.Common.Repositories
9 | {
10 | public class PersonRepository : Repository, IPersonRepository where T : Person where TContext : DbContext
11 | {
12 | public PersonRepository(TContext context) : base(context)
13 | {
14 | }
15 |
16 | public IQueryable GetByLastName(string lastName)
17 | {
18 | return base.GetAll().Where(p => p.LastName == lastName);
19 | }
20 |
21 | private void IsEntityNull(T entity)
22 | {
23 | if (entity == null)
24 | {
25 | throw new ArgumentNullException("entity");
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/DbContexts/SecureApplicationContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Identity;
2 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
3 | using Microsoft.EntityFrameworkCore;
4 | using ContosoUniversity.Data.Entities;
5 |
6 | namespace ContosoUniversity.Data.DbContexts
7 | {
8 | public class SecureApplicationContext : IdentityDbContext
9 | {
10 | public SecureApplicationContext(DbContextOptions options) : base(options)
11 | {
12 | }
13 |
14 | protected override void OnModelCreating(ModelBuilder builder)
15 | {
16 | base.OnModelCreating(builder);
17 | string dbSchema = "Contoso";
18 | if (OperatingSystem.IsMacOs())
19 | {
20 | dbSchema = null;
21 | }
22 |
23 | var config = new DbContextConfig();
24 | config.SecureApplicationContextConfig(builder, dbSchema);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Instructors/Details.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Data.Entities.Instructor
2 |
3 | @{
4 | ViewData["Title"] = "Details";
5 | }
6 |
7 | Details
8 |
9 |
10 |
Instructor
11 |
12 |
13 | -
14 | @Html.DisplayNameFor(model => model.LastName)
15 |
16 | -
17 | @Html.DisplayFor(model => model.LastName)
18 |
19 | -
20 | @Html.DisplayNameFor(model => model.FirstMidName)
21 |
22 | -
23 | @Html.DisplayFor(model => model.FirstMidName)
24 |
25 | -
26 | @Html.DisplayNameFor(model => model.HireDate)
27 |
28 | -
29 | @Html.DisplayFor(model => model.HireDate)
30 |
31 |
32 |
33 |
37 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Shared/_LoginPartial.cshtml:
--------------------------------------------------------------------------------
1 | @using Microsoft.AspNetCore.Identity
2 | @using ContosoUniversity.Data.Entities
3 |
4 | @inject SignInManager SignInManager
5 | @inject UserManager UserManager
6 |
7 | @if (SignInManager.IsSignedIn(User))
8 | {
9 |
19 | }
20 | else
21 | {
22 |
26 | }
27 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/DefaultModelBindingHelperAdaptor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Mvc;
4 | using System.Linq.Expressions;
5 |
6 | namespace ContosoUniversity.Web
7 | {
8 | // issue with unit testing controllers that use TryUpdateModelAsync
9 | // solution @ https://stackoverflow.com/questions/39259025/asp-net-core-mvc-controller-unit-testing-when-using-tryupdatemodel
10 | public class DefaultModelBindingHelaperAdaptor : IModelBindingHelperAdaptor
11 | {
12 | public Task TryUpdateModelAsync(ControllerBase controller, TModel model, string prefix, params Expression>[] includeExpressions) where TModel : class
13 | {
14 | return controller.TryUpdateModelAsync(model, prefix, includeExpressions);
15 | }
16 |
17 | public Task TryUpdateModelAsync(ControllerBase controller, TModel model) where TModel : class
18 | {
19 | return controller.TryUpdateModelAsync(model);
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Account/ForgotPassword.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Web.ViewModels.ForgotPasswordViewModel
2 |
3 | @{
4 | ViewData["Title"] = "Forgot Password";
5 | }
6 |
7 | @ViewData["Title"]
8 |
25 |
26 | @section Scripts{
27 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
28 | }
29 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Manage/AddPhoneNumber.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Web.ViewModels.AddPhoneNumberViewModel
2 |
3 | @{
4 | ViewData["Title"] = "Add Phone Number";
5 | }
6 |
7 | @ViewData["Title"]
8 |
9 |
25 |
26 | @section Scripts{
27 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
28 | }
29 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/Controllers/CoursesController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 | using System.Collections.Generic;
3 | using System.Net.Http;
4 | using System.Threading.Tasks;
5 | using ContosoUniversity.Common.Interfaces;
6 | using ContosoUniversity.Data.Entities;
7 | using System.Linq;
8 | using ContosoUniversity.Common;
9 | using ContosoUniversity.Data.DbContexts;
10 | using ContosoUniversity.Common.DTO;
11 | using AutoMapper;
12 |
13 | namespace ContosoUniversity_Spa_React.Controllers
14 | {
15 | [Route("api/[controller]")]
16 | public class CoursesController : Controller
17 | {
18 | private readonly IRepository _coursesRepo;
19 | private readonly IMapper _mapper;
20 |
21 | public CoursesController(UnitOfWork unitOfWork, IMapper mapper)
22 | {
23 | _coursesRepo = unitOfWork.CourseRepository;
24 | _mapper = mapper;
25 | }
26 |
27 | public IEnumerable Get()
28 | {
29 | return _coursesRepo.GetAll().ToArray();
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web.IntegrationTests/ContosoUniversity.Web.IntegrationTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/lib/jquery-validation/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-validation",
3 | "homepage": "http://jqueryvalidation.org/",
4 | "repository": {
5 | "type": "git",
6 | "url": "git://github.com/jzaefferer/jquery-validation.git"
7 | },
8 | "authors": [
9 | "Jörn Zaefferer "
10 | ],
11 | "description": "Form validation made easy",
12 | "main": "dist/jquery.validate.js",
13 | "keywords": [
14 | "forms",
15 | "validation",
16 | "validate"
17 | ],
18 | "license": "MIT",
19 | "ignore": [
20 | "**/.*",
21 | "node_modules",
22 | "bower_components",
23 | "test",
24 | "demo",
25 | "lib"
26 | ],
27 | "dependencies": {
28 | "jquery": ">= 1.7.2"
29 | },
30 | "version": "1.14.0",
31 | "_release": "1.14.0",
32 | "_resolution": {
33 | "type": "version",
34 | "tag": "1.14.0",
35 | "commit": "c1343fb9823392aa9acbe1c3ffd337b8c92fed48"
36 | },
37 | "_source": "git://github.com/jzaefferer/jquery-validation.git",
38 | "_target": ">=1.8",
39 | "_originalSource": "jquery-validation"
40 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/WebProfile.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using ContosoUniversity.Data.Entities;
3 | using ContosoUniversity.ViewModels;
4 | using System.Text;
5 |
6 | namespace ContosoUniversity.Web
7 | {
8 | public class WebProfile : Profile
9 | {
10 | public WebProfile()
11 | {
12 | CreateMap()
13 | .ForMember(dest => dest.Administrator, opts => opts.MapFrom(src => src.Administrator.FullName));
14 | CreateMap()
15 | .ForMember(dest => dest.Administrator, opts => opts.Ignore());
16 | CreateMap()
17 | .ForMember(dest => dest.Administrator, opts => opts.MapFrom(src => src.Administrator.FullName));
18 | CreateMap()
19 | .ForMember(dest => dest.RowVersion, opts => opts.MapFrom(src => Encoding.ASCII.GetBytes(src.RowVersion)))
20 | .ForMember(dest => dest.Administrator, opts => opts.Ignore());
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "contoso-university-spa-react",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "bootstrap": "^3.4.1",
7 | "moment": "^2.24.0",
8 | "numeral": "^2.0.6",
9 | "react": "^16.12.0",
10 | "react-bootstrap": "^0.31.5",
11 | "react-dom": "^16.12.0",
12 | "react-redux": "^5.1.2",
13 | "react-router-bootstrap": "^0.24.4",
14 | "react-router-dom": "^4.3.1",
15 | "react-scripts": "^3.3.0",
16 | "redux": "^3.7.2",
17 | "redux-thunk": "^2.3.0",
18 | "rimraf": "^2.7.1",
19 | "toastr": "2.1.4"
20 | },
21 | "scripts": {
22 | "start": "rimraf ./build && react-scripts start",
23 | "build": "react-scripts build",
24 | "test": "react-scripts test --env=jsdom",
25 | "eject": "react-scripts eject"
26 | },
27 | "browserslist": {
28 | "production": [
29 | ">0.2%",
30 | "not dead",
31 | "not op_mini all"
32 | ],
33 | "development": [
34 | "last 1 chrome version",
35 | "last 1 firefox version",
36 | "last 1 safari version"
37 | ]
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/index.js:
--------------------------------------------------------------------------------
1 | import 'bootstrap/dist/css/bootstrap.css';
2 | import 'bootstrap/dist/css/bootstrap-theme.css';
3 | import './index.css';
4 | import React from 'react';
5 | import ReactDOM from 'react-dom';
6 | import { BrowserRouter } from 'react-router-dom';
7 | import App from './App';
8 | import registerServiceWorker from './registerServiceWorker';
9 | import {Provider} from 'react-redux';
10 | import configureStore from './store/configureStore';
11 | import { loadCourses } from './actions/courseActions';
12 | import { loadDepartments } from './actions/departmentActions';
13 | import '../node_modules/toastr/build/toastr.min.css';
14 |
15 | const store = configureStore();
16 | store.dispatch(loadCourses());
17 | store.dispatch(loadDepartments());
18 |
19 | const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href');
20 | const rootElement = document.getElementById('root');
21 |
22 | ReactDOM.render(
23 |
24 |
25 |
26 |
27 | ,
28 | rootElement);
29 |
30 | registerServiceWorker();
31 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/common/LoadingDots.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | class LoadingDots extends React.Component {
5 | constructor(props){
6 | super(props);
7 | this.state = { frame: 1};
8 | }
9 |
10 | componentDidMount() {
11 | this.interval = setInterval(() => {
12 | this.setState({
13 | frame: this.state.frame + 1
14 | });
15 | }, this.props.interval);
16 | }
17 |
18 | componentWillUnmount() {
19 | clearInterval(this.interval);
20 | }
21 |
22 | render() {
23 | let dots = this.state.frame % (this.props.dots + 1);
24 | let text = '';
25 | while(dots > 0){
26 | text += '.';
27 | dots--;
28 | }
29 | return {text} ;
30 | };
31 | }
32 |
33 | LoadingDots.defaultTypes = {
34 | interval: 300,
35 | dots: 3
36 | };
37 |
38 | LoadingDots.propTypes = {
39 | interval: PropTypes.number,
40 | dots: PropTypes.number
41 | };
42 |
43 | export default LoadingDots;
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Adrian Limon
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 |
--------------------------------------------------------------------------------
/ContosoUniversity.Common/ContosoUniversity.Common.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Manage/VerifyPhoneNumber.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Web.ViewModels.VerifyPhoneNumberViewModel
2 |
3 | @{
4 | ViewData["Title"] = "Verify Phone Number";
5 | }
6 |
7 | @ViewData["Title"]
8 |
9 |
27 |
28 | @section Scripts{
29 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
30 | }
31 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web.Tests/Views/ChromeViews.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Tests;
2 | using OpenQA.Selenium;
3 | using OpenQA.Selenium.Chrome;
4 | using System;
5 | using System.IO;
6 | using System.Reflection;
7 | using Xunit;
8 |
9 | namespace ContosoUniversity.Web.Tests.Views
10 | {
11 | public class ChromeViews : BaseIntegrationTest
12 | {
13 | private readonly Uri _baseUrl;
14 |
15 | public ChromeViews()
16 | {
17 | _baseUrl = new Uri("https://localhost:44368/");
18 | }
19 |
20 | [Fact(Skip = "Chrome UI")]
21 | public void HomeIndex_ShouldHaveAJumbotron_WithH1()
22 | {
23 | var home = _baseUrl;
24 | using (var driver = new ChromeDriver
25 | (Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)))
26 | {
27 | driver.Navigate().GoToUrl(home);
28 | var jumbotron = driver.FindElementByClassName("jumbotron");
29 | var h1 = jumbotron.FindElement(By.TagName("h1"));
30 | Assert.Equal("Contoso University", h1.Text);
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "LogLevel": {
5 | "Default": "Debug",
6 | "System": "Information",
7 | "Microsoft": "Information"
8 | }
9 | },
10 | "SMSAccountPassword": "DO-NOT-STORE-HERE",
11 | "SMSAccountIdentification": "DO-NOT-STORE-HERE",
12 | "SendGridUser": "DO-NOT-STORE-HERE",
13 | "SendGridKey": "DO-NOT-STORE-HERE",
14 | "SMSAccountFrom": "DO-NOT-STORE-HERE",
15 | "Administrator": {
16 | "UserName": "admin@example.com",
17 | "Password": "DO-NOT-STORE-Weak-P@ssw0rd!"
18 | },
19 | "Authentication": {
20 | "Google": {
21 | "ClientId": "DO-NOT-STORE-HERE",
22 | "ClientSecret": "DO-NOT-STORE-HERE"
23 | },
24 | "Facebook": {
25 | "AppId": "DO-NOT-STORE-HERE",
26 | "AppSecret": "DO-NOT-STORE-HERE"
27 | },
28 | "Tokens": {
29 | "Issuer": "https://localhost:20650/",
30 | "Audience": "http://localhost:6188/",
31 | "Audiences": [
32 | "http://localhost:20645/",
33 | "http://localhost:6188/"
34 | ],
35 | "Key": "DO-NOT-STORE-HERE-1absa-adljkzer-zldr"
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/lib/bootstrap/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bootstrap",
3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
4 | "keywords": [
5 | "css",
6 | "js",
7 | "less",
8 | "mobile-first",
9 | "responsive",
10 | "front-end",
11 | "framework",
12 | "web"
13 | ],
14 | "homepage": "http://getbootstrap.com",
15 | "license": "MIT",
16 | "moduleType": "globals",
17 | "main": [
18 | "less/bootstrap.less",
19 | "dist/js/bootstrap.js"
20 | ],
21 | "ignore": [
22 | "/.*",
23 | "_config.yml",
24 | "CNAME",
25 | "composer.json",
26 | "CONTRIBUTING.md",
27 | "docs",
28 | "js/tests",
29 | "test-infra"
30 | ],
31 | "dependencies": {
32 | "jquery": "1.9.1 - 3"
33 | },
34 | "version": "3.3.7",
35 | "_release": "3.3.7",
36 | "_resolution": {
37 | "type": "version",
38 | "tag": "v3.3.7",
39 | "commit": "0b9c4a4007c44201dce9a6cc1a38407005c26c86"
40 | },
41 | "_source": "https://github.com/twbs/bootstrap.git",
42 | "_target": "v3.3.7",
43 | "_originalSource": "bootstrap",
44 | "_direct": true
45 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Api.Tests/ContosoUniversity.Api.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp2.1
4 |
5 |
6 |
7 | PreserveNewest
8 | PreserveNewest
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/lib/bootstrap/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2016 Twitter, Inc.
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/ContosoUniversity.Test/ContosoUniversity.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 |
6 |
7 |
8 |
9 | PreserveNewest
10 | PreserveNewest
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Departments/Details.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.ViewModels.DepartmentDetailsViewModel
2 |
3 | @{
4 | ViewData["Title"] = "Details";
5 | }
6 |
7 | Details
8 |
9 |
10 |
Department
11 |
12 |
13 | -
14 | @Html.DisplayNameFor(model => model.Name)
15 |
16 | -
17 | @Html.DisplayFor(model => model.Name)
18 |
19 | -
20 | @Html.DisplayNameFor(model => model.Budget)
21 |
22 | -
23 | @Html.DisplayFor(model => model.Budget)
24 |
25 | -
26 | @Html.DisplayNameFor(model => model.StartDate)
27 |
28 | -
29 | @Html.DisplayFor(model => model.StartDate)
30 |
31 | -
32 | @Html.DisplayNameFor(model => model.Administrator)
33 |
34 | -
35 | @Html.DisplayFor(model => model.Administrator)
36 |
37 |
38 |
39 |
43 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Courses/Details.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Data.Entities.Course
2 |
3 | @{
4 | ViewData["Title"] = "Details";
5 | }
6 |
7 | Details
8 |
9 |
10 |
Course
11 |
12 |
13 | -
14 | @Html.DisplayNameFor(model => model.CourseNumber)
15 |
16 | -
17 | @Html.DisplayFor(model => model.CourseNumber)
18 |
19 | -
20 | @Html.DisplayNameFor(model => model.Title)
21 |
22 | -
23 | @Html.DisplayFor(model => model.Title)
24 |
25 | -
26 | @Html.DisplayNameFor(model => model.Credits)
27 |
28 | -
29 | @Html.DisplayFor(model => model.Credits)
30 |
31 | -
32 | @Html.DisplayNameFor(model => model.Department)
33 |
34 | @* -
35 | @Html.DisplayFor(model => model.Department.DepartmentID)
36 |
*@
37 |
38 |
39 |
43 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 50px;
3 | padding-bottom: 20px;
4 | }
5 |
6 | /* Wrapping element */
7 | /* Set some basic padding to keep content from hitting the edges */
8 | .body-content {
9 | padding-left: 15px;
10 | padding-right: 15px;
11 | }
12 |
13 | /* Set widths on the form inputs since otherwise they're 100% wide */
14 | input,
15 | select,
16 | textarea {
17 | max-width: 280px;
18 | }
19 |
20 | /* Carousel */
21 | .carousel-caption p {
22 | font-size: 20px;
23 | line-height: 1.4;
24 | }
25 |
26 | /* Make .svg files in the carousel display properly in older browsers */
27 | .carousel-inner .item img[src$=".svg"] {
28 | width: 100%;
29 | }
30 |
31 | /* buttons and links extension to use brackets: [ click me ] */
32 | .btn-bracketed::before {
33 | display: inline-block;
34 | content: "[";
35 | padding-right: 0.5em;
36 | }
37 |
38 | .btn-bracketed::after {
39 | display: inline-block;
40 | content: "]";
41 | padding-left: 0.5em;
42 | }
43 |
44 | /* Hide/rearrange for smaller screens */
45 | @media screen and (max-width: 767px) {
46 | /* Hide captions */
47 | .carousel-caption {
48 | display: none;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/lib/jquery-validation/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright Jörn Zaefferer
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Instructors/Delete.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Data.Entities.Instructor
2 |
3 | @{
4 | ViewData["Title"] = "Delete";
5 | }
6 |
7 | Delete
8 |
9 | Are you sure you want to delete this?
10 |
11 |
Instructor
12 |
13 |
14 |
15 | -
16 | @Html.DisplayNameFor(model => model.LastName)
17 |
18 | -
19 | @Html.DisplayFor(model => model.LastName)
20 |
21 | -
22 | @Html.DisplayNameFor(model => model.FirstMidName)
23 |
24 | -
25 | @Html.DisplayFor(model => model.FirstMidName)
26 |
27 | -
28 | @Html.DisplayNameFor(model => model.HireDate)
29 |
30 | -
31 | @Html.DisplayFor(model => model.HireDate)
32 |
33 |
34 |
35 |
41 |
42 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/common/TextInput.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const TextInput = ({name, label, placeholder, value, onChange, error}) => {
5 | let wrapperClass = 'form-group';
6 | if(error && error.length > 0){
7 | wrapperClass += " has-error";
8 | }
9 |
10 | return (
11 |
12 |
13 |
14 |
22 | {error &&
{error}
}
23 |
24 |
25 | );
26 | }
27 |
28 | TextInput.propTypes = {
29 | name: PropTypes.string.isRequired,
30 | label: PropTypes.string.isRequired,
31 | placeholder: PropTypes.string,
32 | value: PropTypes.string,
33 | onChange: PropTypes.func.isRequired,
34 | error: PropTypes.string
35 | };
36 |
37 | export default TextInput;
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Shared/_ValidationScriptsPartial.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
18 |
19 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/common/NumberInput.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const NumberInput = ({name, label, placeholder, value, onChange, error}) => {
5 | let wrapperClass = 'form-group';
6 | if(error && error.length > 0){
7 | wrapperClass += " has-error";
8 | }
9 |
10 | return (
11 |
12 |
13 |
14 |
22 | {error &&
{error}
}
23 |
24 |
25 | );
26 | }
27 |
28 | NumberInput.propTypes = {
29 | name: PropTypes.string.isRequired,
30 | label: PropTypes.string.isRequired,
31 | placeholder: PropTypes.string,
32 | value: PropTypes.number,
33 | onChange: PropTypes.func.isRequired,
34 | error: PropTypes.string
35 | };
36 |
37 | export default NumberInput;
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Students/Delete.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Data.Entities.Student
2 |
3 | @{
4 | ViewData["Title"] = "Delete";
5 | }
6 |
7 | Delete
8 | @ViewData["ErrorMessage"]
9 | Are you sure you want to delete this?
10 |
11 |
Student
12 |
13 |
14 |
15 | -
16 | @Html.DisplayNameFor(model => model.LastName)
17 |
18 | -
19 | @Html.DisplayFor(model => model.LastName)
20 |
21 | -
22 | @Html.DisplayNameFor(model => model.FirstMidName)
23 |
24 | -
25 | @Html.DisplayFor(model => model.FirstMidName)
26 |
27 | -
28 | @Html.DisplayNameFor(model => model.EnrollmentDate)
29 |
30 | -
31 | @Html.DisplayFor(model => model.EnrollmentDate)
32 |
33 |
34 |
35 |
41 |
42 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/DbContexts/ApplicationContext.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Data.Entities;
2 | using Microsoft.EntityFrameworkCore;
3 |
4 | namespace ContosoUniversity.Data.DbContexts
5 | {
6 | public class ApplicationContext : DbContext
7 | {
8 | public ApplicationContext(DbContextOptions options) : base(options)
9 | {
10 | }
11 |
12 | public DbSet Courses { get; set; }
13 | public DbSet Enrollments { get; set; }
14 | public DbSet Students { get; set; }
15 | public DbSet Departments { get; set; }
16 | public DbSet Instructors { get; set; }
17 | public DbSet OfficeAssignments { get; set; }
18 | public DbSet CourseAssignments { get; set; }
19 | public DbSet People { get; set; }
20 |
21 | protected override void OnModelCreating(ModelBuilder modelBuilder)
22 | {
23 | string schema = "Contoso";
24 | if (OperatingSystem.IsMacOs())
25 | {
26 | schema = null;
27 | }
28 |
29 | var config = new DbContextConfig();
30 | config.ApplicationContextConfig(modelBuilder, schema);
31 |
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Account/ExternalLoginConfirmation.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Web.ViewModels.ExternalLoginConfirmationViewModel
2 | @{
3 | ViewData["Title"] = "Register";
4 | }
5 |
6 | @ViewData["Title"]
7 | Associate your @ViewData["LoginProvider"] account.
8 |
29 |
30 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/Controllers/DepartmentController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 | using System.Collections.Generic;
3 | using System.Net.Http;
4 | using System.Threading.Tasks;
5 | using ContosoUniversity.Common.Interfaces;
6 | using ContosoUniversity.Data.Entities;
7 | using System.Linq;
8 | using ContosoUniversity.Common;
9 | using ContosoUniversity.Data.DbContexts;
10 | using ContosoUniversity.Common.DTO;
11 | using AutoMapper;
12 |
13 | namespace ContosoUniversity_Spa_React.Controllers
14 | {
15 | [Route("api/[controller]")]
16 | public class DepartmentController : Controller
17 | {
18 | private readonly IRepository _departmentRepo;
19 | private readonly IMapper _mapper;
20 |
21 | public DepartmentController(UnitOfWork unitOfWork, IMapper mapper)
22 | {
23 | _departmentRepo = unitOfWork.DepartmentRepository;
24 | _mapper = mapper;
25 | }
26 |
27 | public IEnumerable Get()
28 | {
29 | return _departmentRepo.GetAll().Select(d => d.Name).ToArray();
30 | }
31 |
32 | [HttpGet("[action]")]
33 | public IEnumerable Details()
34 | {
35 | return _departmentRepo.GetAll().Select(d => _mapper.Map(d)).ToArray();
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/lib/jquery-validation-unobtrusive/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-validation-unobtrusive",
3 | "version": "3.2.6",
4 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive",
5 | "description": "Add-on to jQuery Validation to enable unobtrusive validation options in data-* attributes.",
6 | "main": [
7 | "jquery.validate.unobtrusive.js"
8 | ],
9 | "ignore": [
10 | "**/.*",
11 | "*.json",
12 | "*.md",
13 | "*.txt",
14 | "gulpfile.js"
15 | ],
16 | "keywords": [
17 | "jquery",
18 | "asp.net",
19 | "mvc",
20 | "validation",
21 | "unobtrusive"
22 | ],
23 | "authors": [
24 | "Microsoft"
25 | ],
26 | "license": "http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm",
27 | "repository": {
28 | "type": "git",
29 | "url": "git://github.com/aspnet/jquery-validation-unobtrusive.git"
30 | },
31 | "dependencies": {
32 | "jquery-validation": ">=1.8",
33 | "jquery": ">=1.8"
34 | },
35 | "_release": "3.2.6",
36 | "_resolution": {
37 | "type": "version",
38 | "tag": "v3.2.6",
39 | "commit": "13386cd1b5947d8a5d23a12b531ce3960be1eba7"
40 | },
41 | "_source": "git://github.com/aspnet/jquery-validation-unobtrusive.git",
42 | "_target": "3.2.6",
43 | "_originalSource": "jquery-validation-unobtrusive"
44 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/actions/courseActions.js:
--------------------------------------------------------------------------------
1 | import * as types from './actionTypes';
2 | import courseApi from '../api/mockCourseApi';
3 | import {beginAjaxCall, ajaxCallError} from './ajaxStatusActions';
4 |
5 | export function loadCoursesSuccess(courses) {
6 | return {type: types.LOAD_COURSES_SUCCESS, courses};
7 | }
8 |
9 | export function createCourseSuccess(course) {
10 | return {type: types.CREATE_COURSE_SUCCESS, course};
11 | }
12 |
13 | export function updateCourseSuccess(course) {
14 | return {type: types.UPDATE_COURSE_SUCCESS, course};
15 | }
16 |
17 | export function loadCourses(){
18 | return function(dispatch){
19 | dispatch(beginAjaxCall());
20 | return courseApi.getAllCourses().then(courses => {
21 | dispatch(loadCoursesSuccess(courses));
22 | }).catch(error => {
23 | throw(error);
24 | });
25 | }
26 | }
27 |
28 | export function saveCourse(course){
29 | return function(dispatch){
30 | dispatch(beginAjaxCall());
31 | return courseApi.saveCourse(course).then(savedCourse => {
32 | course.id ? dispatch(updateCourseSuccess(savedCourse)) : dispatch(createCourseSuccess(savedCourse));
33 | }).catch(error => {
34 | dispatch(ajaxCallError(error));
35 | throw(error);
36 | });
37 | };
38 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Data/DbContexts/SecureApplicatonContextFactory.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.EntityFrameworkCore.Design;
3 | using Microsoft.Extensions.Configuration;
4 | using System;
5 | using System.IO;
6 |
7 | namespace ContosoUniversity.Data.DbContexts
8 | {
9 | public class SecureApplicationContextFactory : IDesignTimeDbContextFactory
10 | {
11 | public SecureApplicationContext CreateDbContext(string[] args)
12 | {
13 | var config = new ConfigurationBuilder()
14 | .SetBasePath(Directory.GetCurrentDirectory())
15 | .AddJsonFile("appsettings.json")
16 | .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("Hosting:Environment")}.json", true)
17 | .AddEnvironmentVariables()
18 | .Build();
19 |
20 | var builder = new DbContextOptionsBuilder();
21 |
22 | if (OperatingSystem.IsMacOs())
23 | {
24 | builder.UseSqlite("Data Source=ContosoUniversity.sqlite");
25 | }
26 | else
27 | {
28 | builder.UseSqlServer(config.GetConnectionString("DefaultConnection"));
29 |
30 | }
31 | return new SecureApplicationContext(builder.Options);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/api/mockDepartmentApi.js:
--------------------------------------------------------------------------------
1 | import delay from './delay';
2 |
3 | // original source: https://raw.githubusercontent.com/coryhouse/pluralsight-redux-starter/master/src/api/mockCourseApi.js
4 | // This file mocks a web API by working with the hard-coded data below.
5 | // It uses setTimeout to simulate the delay of an AJAX call.
6 | // All calls return promises.
7 | const departments = [
8 | {
9 | "id": 1,
10 | "instructorID": 1,
11 | "name": "English",
12 | "budget": 350000.0000,
13 | "startDate": "2007-09-01T00:00:00"
14 | },
15 | {
16 | "id": 2,
17 | "instructorID": 2,
18 | "name": "Mathematics",
19 | "budget": 100000.0000,
20 | "startDate": "2007-09-01T00:00:00"
21 | },
22 | {
23 | "id": 3,
24 | "instructorID": 3,
25 | "name": "Engineering",
26 | "budget": 350000.0000,
27 | "startDate": "2007-09-01T00:00:00"
28 | },
29 | {
30 | "id": 4,
31 | "instructorID": 4,
32 | "name": "Economics",
33 | "budget": 100000.0000,
34 | "startDate": "2007-09-01T00:00:00"
35 | }
36 | ];
37 |
38 | class departmentApi {
39 | static getAllDepartments() {
40 | return new Promise((resolve, reject) => {
41 | setTimeout(() => {
42 | resolve(Object.assign([], departments));
43 | }, delay);
44 | });
45 | }
46 |
47 | }
48 |
49 | export default departmentApi;
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Courses/Delete.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Data.Entities.Course
2 |
3 | @{
4 | ViewData["Title"] = "Delete";
5 | }
6 |
7 | Delete
8 |
9 | Are you sure you want to delete this?
10 |
11 |
Course
12 |
13 |
14 | -
15 | @Html.DisplayNameFor(model => model.CourseNumber)
16 |
17 | -
18 | @Html.DisplayFor(model => model.CourseNumber)
19 |
20 | -
21 | @Html.DisplayNameFor(model => model.Title)
22 |
23 | -
24 | @Html.DisplayFor(model => model.Title)
25 |
26 | -
27 | @Html.DisplayNameFor(model => model.Credits)
28 |
29 | -
30 | @Html.DisplayFor(model => model.Credits)
31 |
32 | -
33 | @Html.DisplayNameFor(model => model.Department)
34 |
35 | -
36 | @Html.DisplayFor(model => model.Department.Name)
37 |
38 |
39 |
40 |
46 |
47 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Account/VerifyCode.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Web.ViewModels.VerifyCodeViewModel
2 | @{
3 | ViewData["Title"] = "Verify";
4 | }
5 |
6 | @ViewData["Title"]
7 |
8 |
35 |
36 | @section Scripts{
37 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/common/SelectInput.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const SelectInput = ({label, name, value, onChange, defaultOption, options, error}) => {
5 | return (
6 |
7 |
8 |
9 |
21 | {error &&
{error}
}
22 |
23 |
24 | );
25 | }
26 |
27 | SelectInput.propTypes = {
28 | label: PropTypes.string.isRequired,
29 | name: PropTypes.string.isRequired,
30 | value: PropTypes.number,
31 | onChange: PropTypes.func.isRequired,
32 | defaultOption: PropTypes.string,
33 | options: PropTypes.arrayOf(PropTypes.object),
34 | error: PropTypes.string,
35 | }
36 |
37 | export default SelectInput;
--------------------------------------------------------------------------------
/ContosoUniversity.Web/PaginatedList.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace ContosoUniversity
8 | {
9 | public class PaginatedList : List
10 | {
11 | public int PageIndex { get; private set; }
12 | public int TotalPages { get; private set; }
13 |
14 | public PaginatedList(List items, int count, int pageIndex, int pageSize)
15 | {
16 | PageIndex = pageIndex;
17 | TotalPages = (int)Math.Ceiling(count / (double)pageSize);
18 | this.AddRange(items);
19 | }
20 |
21 | public bool HasPreviousPage
22 | {
23 | get
24 | {
25 | return (PageIndex > 1);
26 | }
27 | }
28 |
29 | public bool HasNextPage
30 | {
31 | get
32 | {
33 | return (PageIndex < TotalPages);
34 | }
35 | }
36 |
37 | public static async Task> CreateAsync(IQueryable source, int pageIndex, int pageSize)
38 | {
39 | var count = await source.CountAsync();
40 | var items = await source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
41 | return new PaginatedList(items, count, pageIndex, pageSize);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/course/CoursesPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | import {connect} from 'react-redux';
4 | import PropTypes from 'prop-types';
5 | import {bindActionCreators} from 'redux';
6 | import * as courseActions from '../../actions/courseActions';
7 | import CourseList from './CourseList';
8 | import LoadingDots from '../common/LoadingDots';
9 |
10 | class CoursesPage extends React.Component {
11 | render() {
12 | const isLoading = this.props.loading;
13 | return (
14 |
15 |
Courses {isLoading && }
16 | Add Course
17 |
18 |
19 | );
20 | }
21 | }
22 |
23 | CoursesPage.propTypes = {
24 | actions: PropTypes.object.isRequired,
25 | courses: PropTypes.array.isRequired,
26 | loading: PropTypes.bool.isRequired
27 | };
28 |
29 | function mapStateToProps(state, ownProps){
30 | return {
31 | courses: state.courses,
32 | loading: state.ajaxCallsInProgress > 0
33 | };
34 | }
35 |
36 | function mapDispatchToProps(dispatch){
37 | return {
38 | actions: bindActionCreators(courseActions,dispatch)
39 | };
40 | }
41 |
42 | export default connect(mapStateToProps, mapDispatchToProps)(CoursesPage);
--------------------------------------------------------------------------------
/ContosoUniversity.Data/DbContexts/WebContext.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Data.DbContexts;
2 | using ContosoUniversity.Data.Entities;
3 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore;
5 |
6 | namespace ContosoUniversity.Data
7 | {
8 | public class WebContext : IdentityDbContext
9 | {
10 | public WebContext(DbContextOptions options) : base(options)
11 | {
12 | }
13 |
14 | public DbSet Courses { get; set; }
15 | public DbSet Enrollments { get; set; }
16 | public DbSet Students { get; set; }
17 | public DbSet Departments { get; set; }
18 | public DbSet Instructors { get; set; }
19 | public DbSet OfficeAssignments { get; set; }
20 | public DbSet CourseAssignments { get; set; }
21 | public DbSet People { get; set; }
22 |
23 | protected override void OnModelCreating(ModelBuilder modelBuilder)
24 | {
25 | base.OnModelCreating(modelBuilder);
26 | string schema = "Contoso";
27 | if (OperatingSystem.IsMacOs())
28 | {
29 | schema = null;
30 | }
31 |
32 | var config = new DbContextConfig();
33 | config.SecureApplicationContextConfig(modelBuilder, schema);
34 | config.ApplicationContextConfig(modelBuilder, schema);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web.Tests/ContosoUniversity.Web.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp2.1
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/ContosoUniversity.Data.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Helpers/UrlHelperAdaptor.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 |
3 | namespace ContosoUniversity.Web.Helpers
4 | {
5 | public class UrlHelperAdaptor : IUrlHelperAdaptor
6 | {
7 | //
8 | // Summary:
9 | // Generates a URL with an absolute path for an action method, which contains the
10 | // specified action name, controller name, route values, and protocol to use.
11 | //
12 | // Parameters:
13 | // helper:
14 | // The Microsoft.AspNetCore.Mvc.IUrlHelper.
15 | //
16 | // action:
17 | // The name of the action method.
18 | //
19 | // controller:
20 | // The name of the controller.
21 | //
22 | // values:
23 | // An object that contains route values.
24 | //
25 | // protocol:
26 | // The protocol for the URL, such as "http" or "https".
27 | //
28 | // Returns:
29 | // The generated URL.
30 | public string Action(IUrlHelper helper, string action, string controller, object values, string protocol)
31 | {
32 | var url = GenerateUrl(helper, action, controller, values, protocol);
33 | return url;
34 | }
35 |
36 | protected virtual string GenerateUrl(IUrlHelper helper, string action, string controller, object values, string protocol)
37 | {
38 | return helper.Action(action, controller, values, protocol);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Departments/Delete.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Data.Entities.Department
2 |
3 | @{
4 | ViewData["Title"] = "Delete";
5 | }
6 |
7 | Delete
8 | @ViewData["ConcurrencyErrorMessage"]
9 | Are you sure you want to delete this?
10 |
11 |
Department
12 |
13 |
14 | -
15 | @Html.DisplayNameFor(model => model.Name)
16 |
17 | -
18 | @Html.DisplayFor(model => model.Name)
19 |
20 | -
21 | @Html.DisplayNameFor(model => model.Budget)
22 |
23 | -
24 | @Html.DisplayFor(model => model.Budget)
25 |
26 | -
27 | @Html.DisplayNameFor(model => model.StartDate)
28 |
29 | -
30 | @Html.DisplayFor(model => model.StartDate)
31 |
32 | -
33 | @Html.DisplayNameFor(model => model.Administrator)
34 |
35 | -
36 | @Html.DisplayFor(model => model.Administrator.FullName)
37 |
38 |
39 |
40 |
48 |
49 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/DbContexts/ApplicationContextFactory.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Data.DbContexts;
2 | using Microsoft.EntityFrameworkCore;
3 | using Microsoft.EntityFrameworkCore.Design;
4 | using Microsoft.Extensions.Configuration;
5 | using System;
6 | using System.IO;
7 |
8 | namespace ContosoUniversity.Data
9 | {
10 | // modeled from https://www.benday.com/2017/02/17/ef-core-migrations-without-hard-coding-a-connection-string-using-idbcontextfactory
11 | public class ApplicationContextFactory : IDesignTimeDbContextFactory
12 | {
13 | public ApplicationContext CreateDbContext(string[] args)
14 | {
15 | var config = new ConfigurationBuilder()
16 | .SetBasePath(Directory.GetCurrentDirectory())
17 | .AddJsonFile("appsettings.json")
18 | .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("Hosting:Environment")}.json", true)
19 | .AddEnvironmentVariables()
20 | .Build();
21 |
22 | var builder = new DbContextOptionsBuilder();
23 | if (OperatingSystem.IsMacOs())
24 | {
25 | builder.UseSqlite("Data Source=ContosoUniversity.sqlite");
26 | }
27 | else
28 | {
29 | builder.UseSqlServer(config.GetConnectionString("DefaultConnection"), x => x.MigrationsHistoryTable("Migration", "Contoso"));
30 | }
31 | return new ApplicationContext(builder.Options);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/ContosoUniversity.Test/HttpClientExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Net.Http;
4 | using System.Reflection;
5 | using System.Threading.Tasks;
6 |
7 | namespace ContosoUniversity.Tests
8 | {
9 | public static class HttpClientExtensions
10 | {
11 | ///
12 | /// This method provides a way to post form data to an MVC controller
13 | ///
14 | /// The view model type that will be posted.
15 | /// The HttpClient that will be posting the data.
16 | /// The url of the controller
17 | /// The view model data that will be passed in the request.
18 | ///
19 | ///
20 | public async static Task PostFormDataAsync(this HttpClient client, string url, T viewModel, KeyValuePair? antiForgeryToken = null)
21 | {
22 | var list = viewModel.GetType()
23 | .GetProperties()
24 | .Select(t => new KeyValuePair(t.Name, (t.GetValue(viewModel) ?? new object()).ToString()))
25 | .ToList();
26 | if (antiForgeryToken.HasValue)
27 | list.Add(antiForgeryToken.Value);
28 | var formData = new FormUrlEncodedContent(list);
29 | return await client.PostAsync(url, formData);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Route } from 'react-router';
3 | import PropTypes from 'prop-types';
4 | import { Layout } from './components/common/Layout';
5 | import DepartmentsPage from './components/department/DepartmentsPage';
6 | import CoursesPage from './components/course/CoursesPage';
7 | import ManageCoursePage from './components/course/ManageCoursePage';
8 | import AboutPage from './components/about/AboutPage';
9 | import ContactPage from './components/contact/ContactPage';
10 | import RegisterPage from './components/register/RegisterPage';
11 | import LoginPage from './components/login/LoginPage';
12 | import HomePage from './components/home/HomePage.js';
13 |
14 | class App extends Component {
15 | displayName = App.name
16 |
17 | render() {
18 | return (
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | );
31 | }
32 | }
33 |
34 | App.propTypes = {
35 | router: PropTypes.object
36 | }
37 |
38 | export default App;
39 |
--------------------------------------------------------------------------------
/ContosoUniversity.Common/Data/ApiInitializer.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using ContosoUniversity.Common.Interfaces;
3 | using Microsoft.Extensions.Options;
4 | using Microsoft.AspNetCore.Hosting;
5 | using ContosoUniversity.Data.DbContexts;
6 |
7 | namespace ContosoUniversity.Common.Data
8 | {
9 | public class ApiInitializer : IDbInitializer
10 | {
11 | private readonly ApiContext _context;
12 | private readonly ILogger _logger;
13 | private readonly SampleData _data;
14 | private readonly IHostingEnvironment _environment;
15 |
16 | public ApiInitializer(ApiContext context,
17 | ILoggerFactory loggerFactory,
18 | IOptions dataOptions,
19 | IHostingEnvironment env)
20 | {
21 | _context = context;
22 | _logger = loggerFactory.CreateLogger("ApiInitializer");
23 | _data = dataOptions.Value;
24 | _environment = env;
25 | }
26 | public void Initialize()
27 | {
28 | InitializeContext();
29 | }
30 |
31 | private void InitializeContext()
32 | {
33 | // create database schema if it does not exist
34 | if (_context.Database.EnsureCreated())
35 | {
36 | _logger.LogInformation("Creating database schema...");
37 | }
38 | var unitOfWork = new UnitOfWork(_context);
39 | var seedData = new SeedData(_logger, unitOfWork, _data);
40 | seedData.Initialize();
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web.IntegrationTests/StaticPagesTests.cs:
--------------------------------------------------------------------------------
1 | using Xunit;
2 | using System.Threading.Tasks;
3 |
4 | namespace ContosoUniversity.Web.IntegrationTests
5 | {
6 | public class StaticPagesTests : IClassFixture>
7 | {
8 | private readonly CustomWebApplicationFactory _factory;
9 | public StaticPagesTests(CustomWebApplicationFactory factory) => _factory = factory;
10 |
11 | #region Razor Pages
12 | [Theory]
13 | [InlineData("/")]
14 | [InlineData("/contact")]
15 | public async Task GetPages_ReturnSuccess(string url)
16 | {
17 | var client = _factory.CreateClient();
18 |
19 | var response = await client.GetAsync(url);
20 | response.EnsureSuccessStatusCode();
21 | }
22 | #endregion
23 |
24 | #region Mvc Views
25 | [Theory]
26 | [InlineData("/students")]
27 | [InlineData("/students/details/1")]
28 | [InlineData("/courses")]
29 | [InlineData("/courses/details/1")]
30 | [InlineData("/instructors")]
31 | [InlineData("/instructors/details/2")]
32 | [InlineData("/departments")]
33 | [InlineData("/departments/details/1")]
34 | public async Task GetControllersIndexAndDetails_ReturnSuccess(string url)
35 | {
36 | var client = _factory.CreateClient();
37 |
38 | var response = await client.GetAsync(url);
39 |
40 | response.EnsureSuccessStatusCode();
41 | }
42 | #endregion
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Pages/Index.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @{
3 | Layout = "~/Views/Shared/_Layout.cshtml";
4 | ViewData["Title"] = "Home Page";
5 | }
6 |
7 |
8 |
Contoso University
9 |
10 |
11 |
12 |
13 | Contoso University is a place for learning AspNetCore and related technologies. This demo application is an amalgamation of smaller demo applications found in tutorials at AspNetCore docs. The tutorials are great at demonstrating isolated concepts, but issues surfaces when applying these concepts/techniques in a larger context. The purpose of this demo application is to apply concepts/techniques learned from those tutorial into a single domain (i.e. university).
14 |
15 |
16 |
17 |
Build it from scratch
18 |
19 | You can build the initial application by following the steps in a series of tutorials.
20 |
21 |
22 |
23 | Seee the tutorial »
24 |
25 |
26 |
27 |
36 |
--------------------------------------------------------------------------------
/ContosoUniversity.Api/Program.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using Microsoft.AspNetCore.Builder;
3 | using Microsoft.AspNetCore.Hosting;
4 | using Microsoft.AspNetCore;
5 | using Microsoft.Extensions.Configuration;
6 |
7 | namespace ContosoUniversity.Api
8 | {
9 | public class Program
10 | {
11 | public static void Main(string[] args)
12 | {
13 | var host = new WebHostBuilder()
14 | .UseKestrel()
15 | .UseContentRoot(Directory.GetCurrentDirectory())
16 | .UseIISIntegration()
17 | .ConfigureAppConfiguration(ConfigConfiguration)
18 | .UseStartup()
19 | .Build();
20 |
21 | host.Run();
22 | }
23 |
24 | // use by EF Tooling
25 | public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args)
26 | .UseStartup()
27 | .Build();
28 |
29 | public static void ConfigConfiguration(WebHostBuilderContext context, IConfigurationBuilder config)
30 | {
31 | config.SetBasePath(Directory.GetCurrentDirectory())
32 | .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
33 | .AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", optional: true);
34 |
35 | if (context.HostingEnvironment.IsDevelopment())
36 | {
37 | config.AddJsonFile($"sampleData.json", optional: false, reloadOnChange: false);
38 | config.AddUserSecrets();
39 | }
40 |
41 | config.AddEnvironmentVariables();
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Courses/Index.cshtml:
--------------------------------------------------------------------------------
1 | @model IEnumerable
2 |
3 | @{
4 | ViewData["Title"] = "Courses";
5 | }
6 |
7 | Courses
8 |
9 |
10 | Create New
11 |
12 |
13 |
14 |
15 | |
16 | @Html.DisplayNameFor(model => model.CourseNumber)
17 | |
18 |
19 | @Html.DisplayNameFor(model => model.Title)
20 | |
21 |
22 | @Html.DisplayNameFor(model => model.Credits)
23 | |
24 |
25 | @Html.DisplayNameFor(model => model.Department)
26 | |
27 | |
28 |
29 |
30 |
31 | @foreach (var item in Model)
32 | {
33 |
34 | |
35 | @Html.DisplayFor(modelItem => item.CourseNumber)
36 | |
37 |
38 | @Html.DisplayFor(modelItem => item.Title)
39 | |
40 |
41 | @Html.DisplayFor(modelItem => item.Credits)
42 | |
43 |
44 | @Html.DisplayFor(modelItem => item.Department.Name)
45 | |
46 |
47 | Edit |
48 | Details |
49 | Delete
50 | |
51 |
52 | }
53 |
54 |
55 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Departments/Index.cshtml:
--------------------------------------------------------------------------------
1 | @model IEnumerable
2 |
3 | @{
4 | ViewData["Title"] = "Departments";
5 | }
6 |
7 | Departments
8 |
9 | Create New
10 |
11 |
12 |
13 |
14 | |
15 | @Html.DisplayNameFor(model => model.Name)
16 | |
17 |
18 | @Html.DisplayNameFor(model => model.Budget)
19 | |
20 |
21 | @Html.DisplayNameFor(model => model.StartDate)
22 | |
23 |
24 | @Html.DisplayNameFor(model => model.Administrator)
25 | |
26 | |
27 |
28 |
29 |
30 | @foreach (var item in Model)
31 | {
32 |
33 | |
34 | @Html.DisplayFor(modelItem => item.Name)
35 | |
36 |
37 | @Html.DisplayFor(modelItem => item.Budget)
38 | |
39 |
40 | @Html.DisplayFor(modelItem => item.StartDate)
41 | |
42 |
43 | @Html.DisplayFor(modelItem => item.Administrator)
44 | |
45 |
46 | Edit |
47 | Details |
48 | Delete
49 | |
50 |
51 | }
52 |
53 |
54 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Account/Register.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Web.ViewModels.RegisterViewModel
2 | @{
3 | ViewData["Title"] = "Register";
4 | }
5 |
6 | @ViewData["Title"]
7 |
38 |
39 | @section Scripts
40 | {
41 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Manage/ChangePassword.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Web.ViewModels.ChangePasswordViewModel
2 |
3 | @{
4 | ViewData["Title"] = "Chanage Password";
5 | }
6 |
7 | @ViewData["Title"]
8 |
9 |
40 |
41 | @section Scripts{
42 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
43 | }
44 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/wwwroot/lib/jquery/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright jQuery Foundation and other contributors, https://jquery.org/
2 |
3 | This software consists of voluntary contributions made by many
4 | individuals. For exact contribution history, see the revision history
5 | available at https://github.com/jquery/jquery
6 |
7 | The following license applies to all parts of this software except as
8 | documented below:
9 |
10 | ====
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining
13 | a copy of this software and associated documentation files (the
14 | "Software"), to deal in the Software without restriction, including
15 | without limitation the rights to use, copy, modify, merge, publish,
16 | distribute, sublicense, and/or sell copies of the Software, and to
17 | permit persons to whom the Software is furnished to do so, subject to
18 | the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be
21 | included in all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 | ====
32 |
33 | All files located in the node_modules and external directories are
34 | externally maintained libraries used by this software which have their
35 | own licenses; we recommend you read them, as their terms may differ from
36 | the terms above.
37 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Account/ResetPassword.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Web.ViewModels.ResetPasswordViewModel
2 |
3 | @{
4 | ViewData["Title"] = "Log in";
5 | }
6 |
7 | @ViewData["Title"]
8 |
9 |
41 |
42 | @section Scripts
43 | {
44 | @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Students/Details.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Data.Entities.Student
2 |
3 | @{
4 | ViewData["Title"] = "Details";
5 | }
6 |
7 | Details
8 |
9 |
10 |
Student
11 |
12 |
13 | -
14 | @Html.DisplayNameFor(model => model.LastName)
15 |
16 | -
17 | @Html.DisplayFor(model => model.LastName)
18 |
19 | -
20 | @Html.DisplayNameFor(model => model.FirstMidName)
21 |
22 | -
23 | @Html.DisplayFor(model => model.FirstMidName)
24 |
25 | -
26 | @Html.DisplayNameFor(model => model.EnrollmentDate)
27 |
28 | -
29 | @Html.DisplayFor(model => model.EnrollmentDate)
30 |
31 | -
32 | @Html.DisplayNameFor(model => model.Enrollments)
33 |
34 | -
35 |
36 |
37 | | Course Title |
38 | Grade |
39 |
40 | @foreach (var item in Model.Enrollments)
41 | {
42 |
43 | |
44 | @Html.DisplayFor(modelItem => item.Course.Title)
45 | |
46 |
47 | @Html.DisplayFor(modelItem => item.Grade)
48 | |
49 |
50 | }
51 |
52 |
53 |
54 |
55 |
59 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Program.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using Microsoft.AspNetCore;
3 | using Microsoft.AspNetCore.Hosting;
4 | using Microsoft.Extensions.Configuration;
5 | using Microsoft.Extensions.Logging;
6 |
7 | namespace ContosoUniversity
8 | {
9 | public class Program
10 | {
11 | public static void Main(string[] args)
12 | {
13 | CreateWebHostBuilder(args).Build().Run();
14 | }
15 |
16 | // netcoreapp2.1 code-based idiom to support integration test infrastructor
17 | // https://docs.microsoft.com/en-us/aspnet/core/migration/20_21?view=aspnetcore-3.1
18 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
19 | WebHost.CreateDefaultBuilder(args)
20 | .ConfigureAppConfiguration(ConfigConfiguration)
21 | .ConfigureLogging(ConfigureLogger)
22 | .UseStartup();
23 |
24 | // refs:
25 | // https://wildermuth.com/2017/07/06/Program-cs-in-ASP-NET-Core-2-0
26 | public static void ConfigConfiguration(WebHostBuilderContext context, IConfigurationBuilder config)
27 | {
28 | config.SetBasePath(Directory.GetCurrentDirectory());
29 |
30 | if (context.HostingEnvironment.IsDevelopment())
31 | {
32 | config.AddJsonFile($"sampleData.json", optional: true, reloadOnChange: false);
33 | config.AddUserSecrets();
34 | }
35 |
36 | config.AddEnvironmentVariables();
37 | }
38 |
39 | static void ConfigureLogger(WebHostBuilderContext ctx, ILoggingBuilder logging)
40 | {
41 | logging.AddConfiguration(ctx.Configuration.GetSection("Logging"));
42 | logging.AddConsole();
43 | logging.AddDebug();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
23 | Contoso University - React
24 |
25 |
26 |
29 |
30 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ScaffoldingReadMe.txt:
--------------------------------------------------------------------------------
1 |
2 | ASP.NET MVC core dependencies have been added to the project.
3 | However you may still need to do make changes to your project.
4 |
5 | 1. Suggested changes to Startup class:
6 | 1.1 Add a constructor:
7 | public IConfigurationRoot Configuration { get; }
8 |
9 | public Startup(IHostingEnvironment env)
10 | {
11 | var builder = new ConfigurationBuilder()
12 | .SetBasePath(env.ContentRootPath)
13 | .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
14 | .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
15 | .AddEnvironmentVariables();
16 | Configuration = builder.Build();
17 | }
18 | 1.2 Add MVC services:
19 | public void ConfigureServices(IServiceCollection services)
20 | {
21 | // Add framework services.
22 | services.AddMvc();
23 | }
24 |
25 | 1.3 Configure web app to use use Configuration and use MVC routing:
26 |
27 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
28 | {
29 | loggerFactory.AddConsole(Configuration.GetSection("Logging"));
30 | loggerFactory.AddDebug();
31 |
32 | if (env.IsDevelopment())
33 | {
34 | app.UseDeveloperExceptionPage();
35 | }
36 | else
37 | {
38 | app.UseExceptionHandler("/Home/Error");
39 | }
40 |
41 | app.UseStaticFiles();
42 |
43 | app.UseMvc(routes =>
44 | {
45 | routes.MapRoute(
46 | name: "default",
47 | template: "{controller=Home}/{action=Index}/{id?}");
48 | });
49 | }
50 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Students/Create.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Data.Entities.Student
2 |
3 | @{
4 | ViewData["Title"] = "Create";
5 | }
6 |
7 | Create
8 |
9 |
42 |
43 |
46 |
47 | @section Scripts {
48 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
49 | }
50 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/course/CourseForm.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import TextInput from '../common/TextInput';
4 | import SelectInput from '../common/SelectInput';
5 | import NumberInput from '../common/NumberInput';
6 | import LoadingDots from '../common/LoadingDots';
7 |
8 | const CourseForm = ({course, allDepartments, onChange, onSave, saving, errors}) => {
9 | return (
10 |
40 | );
41 | };
42 |
43 | CourseForm.propTypes = {
44 | course: PropTypes.object.isRequired,
45 | allDepartments: PropTypes.array,
46 | onChange: PropTypes.func.isRequired,
47 | onSave: PropTypes.func.isRequired,
48 | saving: PropTypes.bool,
49 | errors: PropTypes.object
50 | };
51 |
52 | export default CourseForm;
--------------------------------------------------------------------------------
/ContosoUniversity.Api/ContosoUniversity.Api.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp2.1
4 | Debug;Release;Release-Azure
5 |
6 |
7 | 494868df-30c3-4e9e-8fea-5db093fcb63f
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | custom.css
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/ContosoUniversity.Data/DbContexts/DbContextConfig.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Data.Entities;
2 | using Microsoft.AspNetCore.Identity;
3 | using Microsoft.EntityFrameworkCore;
4 |
5 | namespace ContosoUniversity.Data.DbContexts
6 | {
7 | public class DbContextConfig
8 | {
9 | public void ApplicationContextConfig(ModelBuilder modelBuilder, string schema = "")
10 | {
11 | modelBuilder.Entity().ToTable("Course", schema);
12 | modelBuilder.Entity().ToTable("Enrollment", schema);
13 | modelBuilder.Entity().ToTable("Student", schema);
14 | modelBuilder.Entity().ToTable("Department", schema);
15 | modelBuilder.Entity().ToTable("Instructor", schema);
16 | modelBuilder.Entity().ToTable("OfficeAssignment", schema);
17 | modelBuilder.Entity().ToTable("CourseAssignment", schema);
18 | modelBuilder.Entity().ToTable("Person", schema);
19 | modelBuilder.Entity().HasKey(c => new { c.CourseID, c.InstructorID });
20 | }
21 |
22 | public void SecureApplicationContextConfig(ModelBuilder modelBuilder, string schema = "")
23 | {
24 | modelBuilder.Entity().ToTable("Users", schema);
25 | modelBuilder.Entity().ToTable("Role", schema);
26 | modelBuilder.Entity>().ToTable("UserClaim", schema);
27 | modelBuilder.Entity>().ToTable("UserRole", schema);
28 | modelBuilder.Entity>().ToTable("UserLogin", schema);
29 | modelBuilder.Entity>().ToTable("RoleClaim", schema);
30 | modelBuilder.Entity>().ToTable("UserToken", schema);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Students/Edit.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Data.Entities.Student
2 |
3 | @{
4 | ViewData["Title"] = "Edit";
5 | }
6 |
7 | Edit
8 |
9 |
43 |
44 |
47 |
48 | @section Scripts {
49 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
50 | }
51 |
--------------------------------------------------------------------------------
/ContosoUniversity.Spa.React/ClientApp/src/components/common/NavMenu.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router-dom';
3 | import { Glyphicon, Nav, Navbar, NavItem, MenuItem, NavDropdown } from 'react-bootstrap';
4 | import { LinkContainer } from 'react-router-bootstrap';
5 |
6 | export class NavMenu extends Component {
7 | displayName = NavMenu.name
8 |
9 | render() {
10 | return (
11 |
12 |
13 |
14 | Contoso University
15 |
16 |
17 |
18 |
19 |
42 |
50 |
51 |
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web.IntegrationTests/Helpers/Utilities.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using ContosoUniversity.Data;
3 | using ContosoUniversity.Data.DbContexts;
4 | using ContosoUniversity.Data.Entities;
5 |
6 | namespace ContosoUniversity.Web.IntegrationTests
7 | {
8 | public static class Utilities
9 | {
10 | public static void InitializeDbForTest(ApplicationContext db)
11 | {
12 | // id = 1
13 | var student = new Student { FirstMidName = "Anna", LastName = "Garland", EnrollmentDate = DateTime.Now };
14 | db.Students.Add(student);
15 | db.SaveChanges();
16 |
17 | // id = 1
18 | var office = new OfficeAssignment();
19 | office.Location = "A";
20 | db.OfficeAssignments.Add(office);
21 | db.SaveChanges();
22 |
23 | // id = 2
24 | var instructor = new Instructor { };
25 | instructor.LastName = "Smith";
26 | instructor.FirstMidName = "John";
27 | instructor.HireDate = DateTime.Now;
28 | instructor.OfficeAssignment = office;
29 | db.Instructors.Add(instructor);
30 | db.SaveChanges();
31 |
32 | // id = 1
33 | var department = new Department();
34 | department.Administrator = instructor;
35 | department.Name = "Engineering";
36 | department.Budget = 100;
37 | db.Departments.Add(department);
38 | db.SaveChanges();
39 |
40 | // id = 1
41 | var course = new Course();
42 | course.Department = department;
43 | course.Title = "Intro to Engineering";
44 | course.Credits = 3;
45 | db.Courses.Add(course);
46 | db.SaveChanges();
47 |
48 | var courseAssignment = new CourseAssignment();
49 | courseAssignment.CourseID = 1;
50 | courseAssignment.InstructorID = 2;
51 | db.CourseAssignments.Add(courseAssignment);
52 | db.SaveChanges();
53 |
54 | }
55 | }
56 |
57 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Common/Repositories/Repository.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Data.Entities;
2 | using ContosoUniversity.Common.Interfaces;
3 | using Microsoft.EntityFrameworkCore;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using System.Data.Common;
7 | using ContosoUniversity.Data.DbContexts;
8 |
9 | namespace ContosoUniversity.Data
10 | {
11 | public class Repository : IRepository where T : BaseEntity where TContext : DbContext
12 | {
13 | private readonly TContext context;
14 | private DbSet entities;
15 | string errorMessage = string.Empty;
16 |
17 | public Repository()
18 | {
19 | }
20 |
21 | public Repository(TContext context)
22 | {
23 | this.context = context;
24 | entities = context.Set();
25 | }
26 |
27 | public IQueryable Get(int id)
28 | {
29 | return entities.Where(s => s.ID == id).AsQueryable();
30 | }
31 |
32 | public IQueryable GetAll()
33 | {
34 | return entities.AsQueryable();
35 | }
36 |
37 | public void Add(T entity)
38 | {
39 | context.Add(entity);
40 | }
41 |
42 | public async Task AddAsync(T entity)
43 | {
44 | await entities.AddAsync(entity);
45 | }
46 |
47 | public void Delete(T entity)
48 | {
49 | entities.Remove(entity);
50 | }
51 |
52 | public void Update(T entity, byte[] rowVersion)
53 | {
54 | context.Entry(entity).Property("RowVersion").OriginalValue = rowVersion;
55 | context.Update(entity);
56 | }
57 |
58 | public async Task SaveChangesAsync()
59 | {
60 | await context.SaveChangesAsync();
61 | }
62 |
63 | public async Task ExecuteSqlCommandAsync(string queryString)
64 | {
65 | return await context.Database.ExecuteSqlCommandAsync(queryString);
66 | }
67 |
68 | public DbConnection GetDbConnection()
69 | {
70 | return context.Database.GetDbConnection();
71 | }
72 |
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Contoso University [](https://travis-ci.org/alimon808/contoso-university)
2 | Contoso University is a place for learning AspNetCore and related technologies. This demo application is an amalgamation of smaller demo applications found in tutorials at [AspNetCore docs](https://docs.microsoft.com/en-us/aspnet/core/). The tutorials are great at demonstrating isolated concepts, but issues surfaces when applying these concepts/techniques in a larger context. The purpose of this demo application is to apply concepts/techniques learned from those tutorial into a single domain (i.e. university).
3 |
4 | ### ContosoUniversity.Web
5 | - Traditional Web App using MVC + Razor Pages
6 | - [Demo](http://contoso-university-web.adrianlimon.com)
7 | ### ContosoUniversity.Api
8 | - Traditional Rest Api
9 | - [Demo](http://contoso-university-api.adrianlimon.com/)
10 | - Generate JWT Token at http://contoso-university-web.adrianlimon.com/api/token to access secure api content. Requires registering via Web App.
11 | ### Testing
12 | - Unit Testing using [Moq](https://github.com/Moq/moq4/wiki/Quickstart) and [xUnit](https://xunit.github.io/docs/getting-started-dotnet-core)
13 | - Integration Testing using TestHost and InMemoryDatabase
14 | - UI Testing using Selenium
15 | ### Security
16 | - using Identity 2.0
17 | - Confirm Email using [SendGrid](sendgrid.com)
18 | - Confirm Phone using [Twilio](https://www.twilio.com/sms/api)
19 | - Two-Factor Authentication - [see tutorial](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/2fa)
20 | - OAuth 2 - Enable Google & Facebook logins
21 | - JWT (Json Web Token) - use to access secure API
22 | ### Technologies
23 | - [ASP.NET Core 2.0](https://blogs.msdn.microsoft.com/webdev/2017/08/14/announcing-asp-net-core-2-0/)
24 | - Asp.Net Core Mvc 2.0 / Razor 2.0
25 | - Entity Framework Core 2.0 / Identity 2.0
26 | - Moq
27 | - xUnit
28 | - Twilio
29 | - SendGrid
30 |
31 | ### Design Patterns
32 | - [Repository](https://social.technet.microsoft.com/wiki/contents/articles/36287.repository-pattern-in-asp-net-core.aspx)
33 | - [Unit Of Work](https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/advanced)
34 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Manage/Index.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Web.ViewModels.ManageIndexViewModel
2 |
3 | @{
4 | ViewData["Title"] = "Manage Account Settings";
5 | }
6 |
7 | @ViewData["Title"]
8 | @ViewData["StatusMessage"]
9 |
10 |
11 |
12 |
13 | - Password:
14 | -
15 | @if (Model.HasPassword)
16 | {
17 | Change
18 | }
19 |
20 | - Phone Number:
21 | -
22 | @(Model.PhoneNumber ?? "None")
23 | @if (Model.PhoneNumber != null)
24 | {
25 |
26 | Change
27 |
30 | }
31 | else
32 | {
33 | Add
34 | }
35 |
36 |
37 | @if (Model.PhoneNumber != null)
38 | {
39 | - Two-Factor Authentication
40 | -
41 | @if (Model.TwoFactor)
42 | {
43 |
46 | }
47 | else
48 | {
49 |
52 | }
53 |
54 | }
55 |
56 |
57 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Departments/Create.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.ViewModels.DepartmentCreateViewModel
2 |
3 | @{
4 | ViewData["Title"] = "Create";
5 | }
6 |
7 | Create
8 |
9 |
50 |
51 |
54 |
55 | @section Scripts {
56 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
57 | }
58 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "web-app",
6 | "type": "coreclr",
7 | "request": "launch",
8 | "preLaunchTask": "build-web-app",
9 | "program": "${workspaceRoot}/ContosoUniversity.Web/bin/Debug/netcoreapp2.1/ContosoUniversity.Web.dll",
10 | "args": [],
11 | "cwd": "${workspaceRoot}/ContosoUniversity.Web",
12 | "stopAtEntry": false,
13 | "launchBrowser": {
14 | "enabled": true,
15 | "args": "${auto-detect-url}",
16 | "windows": {
17 | "command": "cmd.exe",
18 | "args": "/C start ${auto-detect-url}"
19 | },
20 | "osx": {
21 | "command": "open"
22 | },
23 | "linux": {
24 | "command": "xdg-open"
25 | }
26 | },
27 | "env": {
28 | "ASPNETCORE_ENVIRONMENT": "Development"
29 | },
30 | "sourceFileMap": {
31 | "/Views": "${workspaceRoot}/Views"
32 | }
33 | },
34 | {
35 | "name": "api",
36 | "type": "coreclr",
37 | "request": "launch",
38 | "preLaunchTask": "build-api",
39 | "program": "${workspaceRoot}/ContosoUniversity.Api/bin/Debug/netcoreapp2.1/ContosoUniversity.Api.dll",
40 | "args": [],
41 | "cwd": "${workspaceRoot}/ContosoUniversity.Api",
42 | "stopAtEntry": false,
43 | "launchBrowser": {
44 | "enabled": true,
45 | "args": "${auto-detect-url}",
46 | "windows": {
47 | "command": "cmd.exe",
48 | "args": "/C start ${auto-detect-url}"
49 | },
50 | "osx": {
51 | "command": "open"
52 | },
53 | "linux": {
54 | "command": "xdg-open"
55 | }
56 | },
57 | "env": {
58 | "ASPNETCORE_ENVIRONMENT": "Development"
59 | },
60 | "sourceFileMap": {}
61 | }
62 | ]
63 | }
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Courses/Edit.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Data.Entities.Course
2 |
3 | @{
4 | ViewData["Title"] = "Edit";
5 | }
6 |
7 | Edit
8 |
9 |
51 |
52 |
55 |
56 | @section Scripts {
57 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
58 | }
59 |
--------------------------------------------------------------------------------
/ContosoUniversity.Api/wwwroot/swagger/ui/oauth2-redirect.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
61 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/ContosoUniversity.Web.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp2.1
4 |
5 |
6 | 494868df-30c3-4e9e-8fea-5db093fcb63f
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Courses/Create.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.Data.Entities.Course
2 |
3 | @{
4 | ViewData["Title"] = "Create";
5 | }
6 |
7 | Create
8 |
9 |
51 |
52 |
55 |
56 | @section Scripts {
57 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
58 | }
59 |
--------------------------------------------------------------------------------
/ContosoUniversity.Common/MessageServices.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Options;
2 | using SendGrid;
3 | using SendGrid.Helpers.Mail;
4 | using System.Threading.Tasks;
5 | using Twilio;
6 | using Twilio.Rest.Api.V2010.Account;
7 |
8 | namespace ContosoUniversity.Common
9 | {
10 | public class AuthMessageSender : IEmailSender, ISmsSender
11 | {
12 | public AuthMessageSender(IOptions optionsAccessor, IOptions smsOptionsAccessor)
13 | {
14 | Options = optionsAccessor.Value;
15 | SmsOptions = smsOptionsAccessor.Value;
16 | }
17 |
18 | public AuthMessageSenderOptions Options { get; }
19 | public SMSOptions SmsOptions { get; }
20 |
21 | public Task SendEmailAsync(string email, string subject, string message)
22 | {
23 | // plug in your email service here to send an email
24 | return Execute(Options.SendGridKey, subject, message, email);
25 | }
26 |
27 | public Task Execute(string apiKey, string subject, string message, string email)
28 | {
29 | var client = new SendGridClient(apiKey);
30 | var msg = new SendGridMessage()
31 | {
32 | From = new EmailAddress("no-reply@contoso.com", "Consoto University"),
33 | Subject = subject,
34 | PlainTextContent = message,
35 | HtmlContent = message
36 | };
37 |
38 | msg.AddTo(new EmailAddress(email));
39 | return client.SendEmailAsync(msg);
40 | }
41 |
42 | public Task SendSmsAsync(string number, string message)
43 | {
44 | // plug in your sms service here to send a text message
45 | // your account SID from twilio.com/console
46 | var accountSid = SmsOptions.SMSAccountIdentification;
47 | // your auth token from twilio.com/console
48 | var authToken = SmsOptions.SMSAccountPassword;
49 |
50 | TwilioClient.Init(accountSid, authToken);
51 |
52 | var msg = MessageResource.Create(
53 | to: new Twilio.Types.PhoneNumber(number),
54 | from: new Twilio.Types.PhoneNumber(SmsOptions.SMSAccountFrom),
55 | body: message);
56 |
57 | return Task.FromResult(0);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Departments/Edit.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.ViewModels.DepartmentEditViewModel
2 |
3 | @{
4 | ViewData["Title"] = "Edit";
5 | }
6 |
7 | Edit
8 |
9 |
53 |
54 |
57 |
58 | @section Scripts {
59 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
60 | }
61 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Pages/About.cshtml.cs:
--------------------------------------------------------------------------------
1 | using ContosoUniversity.Common;
2 | using ContosoUniversity.Common.Interfaces;
3 | using ContosoUniversity.Data.DbContexts;
4 | using ContosoUniversity.Data.Entities;
5 | using ContosoUniversity.Models.SchoolViewModels;
6 | using Microsoft.AspNetCore.Mvc.RazorPages;
7 | using System.Collections.Generic;
8 | using System.Data.Common;
9 | using System.Threading.Tasks;
10 |
11 | namespace ContosoUniversity.Web.Pages
12 | {
13 | public class AboutModel : PageModel
14 | {
15 | private readonly IRepository _studentRepo;
16 | public List StudentEnrollments;
17 |
18 | public AboutModel(UnitOfWork unitOfWork)
19 | {
20 | _studentRepo = unitOfWork.StudentRepository;
21 | }
22 |
23 | public void OnGet()
24 | {
25 | StudentEnrollments = Stats().Result;
26 | }
27 |
28 | private async Task> Stats()
29 | {
30 | List groups = new List();
31 | var conn = _studentRepo.GetDbConnection();
32 | try
33 | {
34 | await conn.OpenAsync();
35 | using (var command = conn.CreateCommand())
36 | {
37 | // todo: read from configuration
38 | var dbSchema = "Contoso.";
39 | if (ContosoUniversity.Common.OperatingSystem.IsMacOs())
40 | {
41 | dbSchema = string.Empty;
42 | }
43 | string query = $"SELECT EnrollmentDate, COUNT(*) AS StudentCount FROM {dbSchema}Person WHERE Discriminator = 'Student' GROUP BY EnrollmentDate";
44 | command.CommandText = query;
45 | DbDataReader reader = await command.ExecuteReaderAsync();
46 | if (reader.HasRows)
47 | {
48 | while (await reader.ReadAsync())
49 | {
50 | var row = new EnrollmentDateGroup
51 | {
52 | EnrollmentDate = reader.GetDateTime(0),
53 | StudentCount = reader.GetInt32(1)
54 | };
55 | groups.Add(row);
56 | }
57 | }
58 | reader.Dispose();
59 | }
60 | }
61 | finally
62 | {
63 | conn.Close();
64 | }
65 |
66 | return groups;
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/ContosoUniversity.Web/Views/Students/Index.cshtml:
--------------------------------------------------------------------------------
1 | @model ContosoUniversity.PaginatedList
2 |
3 | @{
4 | ViewData["Title"] = "Index";
5 | }
6 |
7 | Index
8 |
9 | Create New
10 |
11 |
21 |
22 |
23 |
24 | |
25 | Last Name
26 | |
27 |
28 | First Mid
29 | |
30 |
31 | Enrollment Date
32 | |
33 | |
34 |
35 |
36 |
37 | @foreach (var item in Model)
38 | {
39 |
40 | |
41 | @Html.DisplayFor(modelItem => item.LastName)
42 | |
43 |
44 | @Html.DisplayFor(modelItem => item.FirstMidName)
45 | |
46 |
47 | @Html.DisplayFor(modelItem => item.EnrollmentDate)
48 | |
49 |
50 | Edit |
51 | Details |
52 | Delete
53 | |
54 |
55 | }
56 |
57 |
58 | @{
59 | var prevDisabled = !Model.HasPreviousPage ? "disabled" : "";
60 | var nextDisabled = !Model.HasNextPage ? "disabled" : "";
61 | }
62 | Previous
63 | Next
--------------------------------------------------------------------------------