Unverified Commit 8aeff837 authored by Geovanni Perez's avatar Geovanni Perez Committed by GitHub

Merge pull request #89 from unosquare/NetCoreSupport

Net Core support
parents fa249f1e f5454e10
......@@ -196,3 +196,7 @@ FakesAssemblies/
*.opt
/src/Unosquare.PassCore.Web/wwwroot/vendor
/src/Unosquare.PassCore.Web/project.lock.json
/src/Unosquare.PassCore.Web/.vscode/launch.json
/src/Unosquare.PassCore.Web/.vscode/tasks.json
/src/Unosquare.PassCore.Web/wwwroot/**
/src/Unosquare.PassCore.Web/package-lock.json
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="Rules for StyleCop.Analyzers" Description="Code analysis rules for StyleCop.Analyzers.csproj." ToolsVersion="14.0">
<Rules AnalyzerId="AsyncUsageAnalyzers" RuleNamespace="AsyncUsageAnalyzers">
<Rule Id="UseConfigureAwait" Action="Warning" />
</Rules>
<Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
<Rule Id="CA1001" Action="Warning" />
<Rule Id="CA1009" Action="Warning" />
<Rule Id="CA1016" Action="Warning" />
<Rule Id="CA1033" Action="Warning" />
<Rule Id="CA1049" Action="Warning" />
<Rule Id="CA1060" Action="Warning" />
<Rule Id="CA1061" Action="Warning" />
<Rule Id="CA1063" Action="Warning" />
<Rule Id="CA1065" Action="Warning" />
<Rule Id="CA1301" Action="Warning" />
<Rule Id="CA1400" Action="Warning" />
<Rule Id="CA1401" Action="Warning" />
<Rule Id="CA1403" Action="Warning" />
<Rule Id="CA1404" Action="Warning" />
<Rule Id="CA1405" Action="Warning" />
<Rule Id="CA1410" Action="Warning" />
<Rule Id="CA1415" Action="Warning" />
<Rule Id="CA1821" Action="Warning" />
<Rule Id="CA1900" Action="Warning" />
<Rule Id="CA1901" Action="Warning" />
<Rule Id="CA2002" Action="Warning" />
<Rule Id="CA2100" Action="Warning" />
<Rule Id="CA2101" Action="Warning" />
<Rule Id="CA2108" Action="Warning" />
<Rule Id="CA2111" Action="Warning" />
<Rule Id="CA2112" Action="Warning" />
<Rule Id="CA2114" Action="Warning" />
<Rule Id="CA2116" Action="Warning" />
<Rule Id="CA2117" Action="Warning" />
<Rule Id="CA2122" Action="Warning" />
<Rule Id="CA2123" Action="Warning" />
<Rule Id="CA2124" Action="Warning" />
<Rule Id="CA2126" Action="Warning" />
<Rule Id="CA2131" Action="Warning" />
<Rule Id="CA2132" Action="Warning" />
<Rule Id="CA2133" Action="Warning" />
<Rule Id="CA2134" Action="Warning" />
<Rule Id="CA2137" Action="Warning" />
<Rule Id="CA2138" Action="Warning" />
<Rule Id="CA2140" Action="Warning" />
<Rule Id="CA2141" Action="Warning" />
<Rule Id="CA2146" Action="Warning" />
<Rule Id="CA2147" Action="Warning" />
<Rule Id="CA2149" Action="Warning" />
<Rule Id="CA2200" Action="Warning" />
<Rule Id="CA2202" Action="Warning" />
<Rule Id="CA2207" Action="Warning" />
<Rule Id="CA2212" Action="Warning" />
<Rule Id="CA2213" Action="Warning" />
<Rule Id="CA2214" Action="Warning" />
<Rule Id="CA2216" Action="Warning" />
<Rule Id="CA2220" Action="Warning" />
<Rule Id="CA2229" Action="Warning" />
<Rule Id="CA2231" Action="Warning" />
<Rule Id="CA2232" Action="Warning" />
<Rule Id="CA2235" Action="Warning" />
<Rule Id="CA2236" Action="Warning" />
<Rule Id="CA2237" Action="Warning" />
<Rule Id="CA2238" Action="Warning" />
<Rule Id="CA2240" Action="Warning" />
<Rule Id="CA2241" Action="Warning" />
<Rule Id="CA2242" Action="Warning" />
</Rules>
<Rules AnalyzerId="Microsoft.CodeAnalysis.CSharp.Features" RuleNamespace="Microsoft.CodeAnalysis.CSharp.Features">
<Rule Id="IDE0003" Action="None" />
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
<Rule Id="SA1305" Action="Warning" />
<Rule Id="SA1412" Action="Warning" />
<Rule Id="SA1600" Action="None" />
<Rule Id="SA1001" Action="None" />
<Rule Id="SA1003" Action="None" />
<Rule Id="SA1009" Action="None" />
<Rule Id="SA1028" Action="None" />
<Rule Id="SA1011" Action="None" />
<Rule Id="SA1012" Action="None" />
<Rule Id="SA1013" Action="None" />
<Rule Id="SA1021" Action="None" />
<Rule Id="SA1101" Action="None" />
<Rule Id="SA1208" Action="None" />
<Rule Id="SA1116" Action="None" />
<Rule Id="SA1121" Action="None" />
<Rule Id="SA1124" Action="None" />
<Rule Id="SA1123" Action="None" />
<Rule Id="SA1210" Action="None" />
<Rule Id="SA1308" Action="None" />
<Rule Id="SA1309" Action="None" />
<Rule Id="SA1402" Action="None" />
<Rule Id="SA1501" Action="None" />
<Rule Id="SA1503" Action="None" />
<Rule Id="SA1507" Action="Error" />
<Rule Id="SA1516" Action="None" />
<Rule Id="SA1633" Action="None" />
<Rule Id="SA1609" Action="None" />
<Rule Id="SA1623" Action="None" />
</Rules>
</RuleSet>
\ No newline at end of file

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24720.0
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2002
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0A003964-77CA-4779-BD97-BADDD710A745}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3EA980E1-D295-4E61-B2EE-29CFE1EDB2F1}"
ProjectSection(SolutionItems) = preProject
global.json = global.json
appveyor.yml = appveyor.yml
preview.png = preview.png
README.md = README.md
StyleCop.Analyzers.ruleset = StyleCop.Analyzers.ruleset
EndProjectSection
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Unosquare.PassCore.Web", "src\Unosquare.PassCore.Web\Unosquare.PassCore.Web.xproj", "{22E2F79B-7816-4FAB-894D-112759551796}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Unosquare.PassCore.Web", "src\Unosquare.PassCore.Web\Unosquare.PassCore.Web.csproj", "{22E2F79B-7816-4FAB-894D-112759551796}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
......@@ -29,4 +32,7 @@ Global
GlobalSection(NestedProjects) = preSolution
{22E2F79B-7816-4FAB-894D-112759551796} = {0A003964-77CA-4779-BD97-BADDD710A745}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {30FE6198-367B-44D3-97CC-50927E101F3E}
EndGlobalSection
EndGlobal
version: '3.0.{build}'
image: Visual Studio 2017
platform: Any CPU
install:
# Latest version of node and npm
- ps: Install-Product node 8
- npm -g install npm@latest
- set PATH=%APPDATA%\npm;%PATH%
before_build:
- dotnet restore
- node -v
- npm -v
build_script:
- dotnet build -f net461
{
"projects": [ "src" ],
"sdk": {
"version": "1.0.0-rc1-update1"
}
}
{
"lockfileVersion": 1
}
preview.png

50.4 KB

{
"directory": "bower_components"
}
import { NgModule } from '@angular/core';
import {
MatButtonModule,
MatIconModule,
MatCardModule,
MatInputModule,
MatProgressBarModule,
MatTooltipModule,
MatToolbarModule,
MatSnackBarModule,
MatDialogModule
} from '@angular/material';
@NgModule({
imports: [
MatButtonModule,
MatIconModule,
MatCardModule,
MatInputModule,
MatProgressBarModule,
MatTooltipModule,
MatToolbarModule,
MatSnackBarModule,
MatDialogModule
],
exports: [
MatButtonModule,
MatIconModule,
MatCardModule,
MatInputModule,
MatProgressBarModule,
MatTooltipModule,
MatToolbarModule,
MatSnackBarModule,
MatDialogModule
]
})
export class MaterialModule {}
\ No newline at end of file
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { FlexLayoutModule } from "@angular/flex-layout";
import { RecaptchaModule } from 'ng2-recaptcha';
import { MaterialModule } from './app.material-module';
import ChangePasswordComponent from './change-password/app.change-password';
import FooterComponent from './footer/app.footer';
import DialogOverview from './dialog/app.dialog';
@NgModule({
declarations: [
ChangePasswordComponent,
FooterComponent,
DialogOverview
],
imports: [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
MaterialModule,
HttpModule,
FlexLayoutModule,
RecaptchaModule.forRoot(),
ReactiveFormsModule,
],
providers: [],
bootstrap: [ChangePasswordComponent],
entryComponents: [DialogOverview]
})
export class AppModule { }
.form-container {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
border-radius: 10px;
margin-top: 10px;
background-color: white;
}
.container-footer {
height: 100px;
}
.title {
color: white;
font: bold;
padding: 0 5px 0 5px;
}
.fill-remaining-space {
flex: 1 1 auto;
}
.progress {
margin: 1px 0 5px 0;
height: 8px;
}
.margin-top {
margin-top: 20px;
}
form {
width: 95%;
max-width: 650px;
}
button {
width: 50%;
}
mat-icon:hover {
cursor: default;
}
mat-form-field,
mat-hint {
width: 100%;
}
mat-placeholder {
top: 15px;
position: relative;
}
mat-progress-bar {
height: 10%;
}
@media screen and (min-width: 600px) {
.margin-top {
margin-top: 10px;
}
form{
width: 85%;
}
button {
width: 40%;
}
}
\ No newline at end of file
import { Title } from '@angular/platform-browser';
import { Component, OnInit } from '@angular/core';
import { Http } from '@angular/http';
import { MatSnackBar, MatDialog } from '@angular/material';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import ViewOptions from '../models/view-options.model';
import Alerts from '../models/alerts.model';
import Recaptcha from '../models/recaptcha.model';
import ChangePasswordForm from '../models/change-password-form.model';
import Result from '../models/result-data.model';
import PasswordModel from '../models/password.model';
import DialogOverview from '../dialog/app.dialog'
import PasswordValidator from '../helpers/passwordValidator';
import PasswordStrength from '../helpers/passwordStrength';
import 'rxjs/add/operator/map';
const emailRegex = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
@Component({
selector: 'app-root',
templateUrl: './change-password.html',
styleUrls: ['./app.change-password.css']
})
export default class ChangePasswordComponent implements OnInit {
// Form Controls
FormGroup = new FormGroup({
username: new FormControl('', [Validators.required, Validators.pattern(emailRegex)]),
currentPassword: new FormControl('', [Validators.required]),
newPassword: new FormControl('', [Validators.required]),
newPasswordVerify: new FormControl('', [Validators.required])
}, PasswordValidator.MatchPassword);
// Variables
ViewOptions: ViewOptions;
ResultData: Result;
Loading: boolean = false;
ErrorAlertMessage: string = '';
FormData: PasswordModel;
color: string = 'warn';
value: number = 0;
constructor(private http: Http, private snackBar: MatSnackBar,
private titleService: Title, public dialog: MatDialog) {
this.FormData = new PasswordModel;
this.ViewOptions = new ViewOptions;
this.ViewOptions.alerts = new Alerts;
this.ViewOptions.recaptcha = new Recaptcha;
this.ViewOptions.changePasswordForm = new ChangePasswordForm;
this.FormGroup.valueChanges.subscribe(data => {
if (data.newPassword != null)
this.changeProgressBar(PasswordStrength.measureStrength(data.newPassword));
});
}
ngOnInit(): void {
this.GetData();
}
private changeProgressBar(strength: number) {
this.value = strength;
if (strength < 33) {
this.color = 'warn';
} else if (strength > 33 && strength < 66) {
this.color = 'accent';
} else {
this.color = 'primary';
}
}
private openSnackBar(message: string, action: string) {
this.snackBar.open(message, action, {
duration: 5000
});
}
private openDialog(title: string, message: string) {
let refDialog = this.dialog.open(DialogOverview, {
width: '300px',
data: { Title: title, Message: message }
});
}
private clean(submited: string) {
this.Loading = false;
this.ErrorAlertMessage = '';
this.color = 'warn';
this.value = 0;
if (submited === 'success') {
this.FormGroup.reset();
} else {
for (let formControl in this.FormGroup.controls) {
if (formControl != 'username')
this.FormGroup.controls[formControl].reset();
}
}
if (this.ViewOptions.recaptcha.isEnabled) {
grecaptcha.reset();
}
}
private GetData(): void {
this.http.get('api/password').subscribe(values => {
this.ViewOptions = values.json();
this.titleService.setTitle(this.ViewOptions.changePasswordTitle + " - " + this.ViewOptions.applicationTitle);
if (this.ViewOptions.recaptcha.isEnabled) {
this.FormGroup.addControl('reCaptcha', new FormControl('', [Validators.required]));
const sp = document.createElement('script');
sp.type = 'text/javascript';
sp.async = true;
sp.defer = true;
sp.src = 'https://www.google.com/recaptcha/api.js?onload=vcRecaptchaApiLoaded&render=explicit&hl=' + this.ViewOptions.recaptcha.languageCode;
}
});
}
private SetRecaptchaResponse(captchaResponse: string) {
this.FormData.Recaptcha = captchaResponse;
}
Submit() {
this.Loading = true;
this.http.post('api/password', this.FormData)
.subscribe((response) => {
this.openDialog(this.ViewOptions.alerts.successAlertTitle, this.ViewOptions.alerts.successAlertBody);
this.clean('success');
}, (error) => {
this.ResultData = error.json() as Result;
this.ResultData.errors.map(errData => {
this.ErrorAlertMessage += errData.message;
});
this.openSnackBar(this.ErrorAlertMessage, 'OK');
this.clean('error');
});
}
}
\ No newline at end of file
<div fxLayout="column" fxLayoutAlign="center" fxFlex="100">
<mat-toolbar color="primary">
<h2 class="title" fxFlex="50">{{ViewOptions.changePasswordTitle}}</h2>
<span class="fill-remaining-space"></span>
<div matTooltip="{{ViewOptions.changePasswordForm.helpText}}" matTooltipPosition="left">
<img src="/assets/images/help.png" alt="Help" />
</div>
</mat-toolbar>
<div fxLayout="column" fxLayoutAlign="center center">
<form #Form="ngForm">
<div fxLayout="column" fxLayoutAlign="center" fxLayoutGap="3%" class="form-container">
<div fxLayout="row" fxLayoutAlign="center center">
<div fxLayout="column" fxFlex="80" [formGroup]="FormGroup">
<mat-placeholder for="Username">{{ViewOptions.changePasswordForm.usernameLabel}}</mat-placeholder>
<mat-form-field hideRequiredMarker floatPlaceholder="never">
<input matInput [(ngModel)]="FormData.Username" formControlName="username" name="Username" type="email" required placeholder="{{ViewOptions.changePasswordForm.usernamePlaceholder}}">
<mat-hint><strong>{{ViewOptions.changePasswordForm.usernameHelpblock}}</strong></mat-hint>
<mat-error *ngIf="FormGroup.get('username').hasError('pattern')">
Please enter a valid email address
</mat-error>
<mat-error *ngIf="FormGroup.get('username').hasError('required')">
{{ViewOptions.changePasswordForm.usernameLabel}} is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
</div>
<div fxLayout="row" fxLayoutAlign="center center">
<div fxLayout="column" fxFlex="80" [formGroup]="FormGroup">
<mat-placeholder for="CurrentPassword">{{ViewOptions.changePasswordForm.currentPasswordLabel}}</mat-placeholder>
<mat-form-field floatPlaceholder="never">
<input matInput [(ngModel)]="FormData.CurrentPassword" formControlName="currentPassword" name="CurrentPassword" type="password"
placeholder="{{ViewOptions.changePasswordForm.currentPasswordPlaceholder}}">
<mat-hint><strong>{{ViewOptions.changePasswordForm.currentPasswordHelpblock}}</strong></mat-hint>
<mat-error *ngIf="FormGroup.get('currentPassword').hasError('required')">
{{ViewOptions.changePasswordForm.currentPasswordLabel}} is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
</div>
<div fxLayout="row" fxLayoutAlign="center center">
<div fxLayout="column" fxFlex="80" [formGroup]="FormGroup">
<mat-placeholder for="NewPassword">{{ViewOptions.changePasswordForm.newPasswordLabel}}</mat-placeholder>
<mat-form-field floatPlaceholder="never">
<input matInput [(ngModel)]="FormData.NewPassword" id="NewPassword" formControlName="newPassword" name="NewPassword" #NewPassword type="password"
placeholder="{{ViewOptions.changePasswordForm.newPasswordPlaceholder}}">
<mat-hint>
<mat-progress-bar mode="determinate" [color]="color" [value]="value" *ngIf="ViewOptions.showPasswordMeter" class="progress"></mat-progress-bar>
<strong innerHTML="{{ViewOptions.changePasswordForm.newPasswordHelpblock}}"></strong>
</mat-hint>
<mat-error *ngIf="FormGroup.get('newPassword').hasError('required')">
{{ViewOptions.changePasswordForm.newPasswordLabel}} is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
</div>
<div fxLayout="row" fxLayoutAlign="center center" class="margin-top">
<div fxLayout="column" fxFlex="80" [formGroup]="FormGroup">
<mat-placeholder for="NewPasswordVerify">{{ViewOptions.changePasswordForm.newPasswordVerifyLabel}}</mat-placeholder>
<mat-form-field floatPlaceholder="never">
<input matInput [(ngModel)]="FormData.NewPasswordVerify" id="PasswordVerify" formControlName="newPasswordVerify" name="NewPasswordVerify"
type="password" placeholder="{{ViewOptions.changePasswordForm.newPasswordVerifyPlaceholder}}">
<mat-hint><strong>{{ViewOptions.changePasswordForm.newPasswordVerifyHelpblock}}</strong></mat-hint>
<mat-error *ngIf="FormGroup.get('newPasswordVerify').hasError('required')">
Re-enter New Password is <strong>required</strong>
</mat-error>
<mat-error *ngIf="FormGroup.get('newPasswordVerify').hasError('MatchPassword')">
Passwords do not <strong>match</strong>
</mat-error>
</mat-form-field>
</div>
</div>
<div fxLayout="row" fxLayoutAlign="center center" [formGroup]="FormGroup" *ngIf="ViewOptions.recaptcha.isEnabled">
<recaptcha (resolved)="SetRecaptchaResponse($event)" siteKey="{{ViewOptions.recaptcha.siteKey}}" formControlName="reCaptcha"></recaptcha>
</div>
<div fxLayout="column" fxLayoutAlign="center center" class="container-footer">
<button mat-raised-button color="primary" (click)="Submit()" [disabled]="FormGroup.invalid" *ngIf="!Loading">
<span>{{ViewOptions.changePasswordForm.changePasswordButtonLabel}}</span>
</button>
<mat-progress-bar mode="indeterminate" *ngIf="Loading"></mat-progress-bar>
</div>
</div>
</form>
</div>
<app-footer></app-footer>
</div>
\ No newline at end of file
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { Component, Inject } from '@angular/core';
@Component({
selector: 'dialog-overview',
templateUrl: './dialog.html'
})
export default class DialogOverview {
constructor(
public dialogRef: MatDialogRef<DialogOverview>,
@Inject(MAT_DIALOG_DATA) public data: any) { }
close(): void {
this.dialogRef.close();
}
}
\ No newline at end of file
<div fxLayout="column" fxLayoutAlign="start">