Compare commits

...

147 Commits

Author SHA1 Message Date
Samuele Locatelli c848168552 Merge branch 'release/Jenkins2GitLab' 2021-09-02 12:11:24 +02:00
Samuele Locatelli d95a19af32 Taggato job come "win" x selezionare runners 2021-09-02 11:39:52 +02:00
Samuele Locatelli c5e4f95b94 update nav menu 2021-09-02 11:30:29 +02:00
Samuele Locatelli 35e00bdb71 Aggiunta update await x lettura in transporters 2021-09-02 11:30:25 +02:00
Samuele Locatelli 8948984b44 Merge tag 'RC11' into develop
Test modifica suppliers/transporters
2021-09-01 09:36:47 +02:00
Samuele Locatelli 58f8d2aee3 Merge branch 'release/RC11' 2021-09-01 09:36:38 +02:00
Samuele Locatelli 951a704b52 Pérova modifica reset controller per errore online 2021-09-01 09:36:23 +02:00
Samuele Locatelli d518861228 Merge tag 'RC10' into develop
Test fix catena reload data
2021-09-01 09:04:59 +02:00
Samuele Locatelli 32a0fa1287 Merge branch 'release/RC10' 2021-09-01 09:04:50 +02:00
Samuele Locatelli 33212941c8 Test modifica naming x chiamate che danno errori in OVH 2021-09-01 09:04:34 +02:00
Samuele Locatelli 59975a335d Merge tag 'RC9' into develop
Fix reanming local db context
2021-08-31 16:49:12 +02:00
Samuele Locatelli 390046a0c7 Merge branch 'release/RC9' 2021-08-31 16:49:02 +02:00
Samuele Locatelli 149f6251f7 Renaming localDbCtx 2021-08-31 16:48:48 +02:00
Samuele Locatelli 46a0efe748 Merge tag 'RC8' into develop
Fix display grafici su mobile
2021-08-31 16:32:02 +02:00
Samuele Locatelli ace620b09d Merge branch 'release/RC8' 2021-08-31 16:31:36 +02:00
Samuele Locatelli 3d87f28004 Fix QRCode size on small device 2021-08-31 16:31:06 +02:00
Samuele Locatelli b7071dcbe1 Fix display QRCode (test) 2021-08-31 16:26:11 +02:00
Samuele Locatelli fdf937131c Fix display grafici 2021-08-31 16:21:57 +02:00
Samuele Locatelli 1b8a19b036 Merge tag 'RC7' into develop
Update indicazione aggiornamento dati realtime/vecchi
2021-08-30 12:39:31 +02:00
Samuele Locatelli 86bd0f375c Merge branch 'release/RC7' 2021-08-30 12:39:06 +02:00
Samuele Locatelli 9e1d437563 Aggiunta indicazione trasmisisone RTime / vecchia 2021-08-30 12:38:20 +02:00
Samuele Locatelli 6bd54468dd Modifica logging (meno verboso) e rallentamento check UI 2021-08-30 12:13:27 +02:00
Samuele Locatelli 52a71d236d Merge tag 'RC6' into develop
Inserite trappole x log + verboso
2021-08-30 11:58:51 +02:00
Samuele Locatelli c2fd4870c7 Merge branch 'release/RC6' 2021-08-30 11:58:42 +02:00
Samuele Locatelli b67fae281b Aggiunto log livello debug x controllers IOB 2021-08-30 11:58:26 +02:00
Samuele Locatelli 22f4455356 Merge tag 'RC5' into develop
Fix problema dimensioen QRCode
2021-08-30 09:42:11 +02:00
Samuele Locatelli 8107ba51b9 Merge branch 'release/RC5' 2021-08-30 09:42:01 +02:00
Samuele Locatelli b3062b04fc pulizia varia codice x classi non impiegate 2021-08-30 09:38:49 +02:00
Samuele Locatelli 3739225a28 riduzione canvas QRCode (raw fix) 2021-08-30 09:38:37 +02:00
Samuele Locatelli 2db1fbc8d6 Merge tag 'RC4' into develop
Completata migrazione QRCode js + fix vari x check e librerie
2021-08-27 13:03:02 +02:00
Samuele Locatelli 85944da9ed Merge branch 'release/RC4' 2021-08-27 13:02:40 +02:00
Samuele Locatelli a598c6793a Refresh versione delle 13 2021-08-27 13:02:18 +02:00
Samuele Locatelli bf30e006c3 Merge branch 'feature/QrCodeUpgrade' into develop 2021-08-27 13:01:51 +02:00
Samuele Locatelli e799fdf10a Rimozione check x pagina QRCode ext 2021-08-27 13:01:31 +02:00
Samuele Locatelli 34ce093ca9 Completata modifica x riprotare QRCode js (no img ext) 2021-08-27 12:56:56 +02:00
Samuele Locatelli c1d39b73e9 Integrato localmente JQuery e Popper 2021-08-27 12:42:40 +02:00
Samuele Locatelli 567b966157 COmpleto CHartJs locale + blazorise upgrade 2021-08-27 12:34:25 +02:00
Samuele Locatelli e076bc3f6b Upgrade Blazorise NuGet + ChartJs locale 2021-08-27 12:33:50 +02:00
Samuele Locatelli fd027e424f Merge tag 'FixOvhRamCpuIssue' into develop
Fix gestione ram: parameto ServerGC collector va messo a true x linux
virtual (errore RAM/CPU/Disco di OVH)
2021-08-27 12:17:46 +02:00
Samuele Locatelli 3bd8ee233b Merge branch 'hotfix/FixOvhRamCpuIssue' 2021-08-27 12:17:00 +02:00
Samuele Locatelli bb9e9ce7d5 Refresh version 2021-08-27 12:16:53 +02:00
Samuele Locatelli a5f5a55e34 Fix configurazione GC x server (su CPU fisica OK, su OVH c'erano problemi ram/disco) 2021-08-27 12:14:19 +02:00
Samuele Locatelli 2ecc7338e6 Merge tag 'RC3' into develop
Riduzione dimensione installer (èacchetti nuget, target framework, code
analysis...)
2021-08-27 11:56:36 +02:00
Samuele Locatelli 66c069fb35 Merge branch 'release/RC3' 2021-08-27 11:56:17 +02:00
Samuele Locatelli 361d4338a6 Merge branch 'feature/CodeCleanup' into develop 2021-08-27 11:55:58 +02:00
Samuele Locatelli 9a964330e3 Aggiunta conf x GarbageCollection + restrittiva sui processi 2021-08-27 11:54:13 +02:00
Samuele Locatelli 0e65410340 update Nuget AspNetCore 2021-08-27 11:53:56 +02:00
Samuele Locatelli b0e5d54061 Rimozione componenti analisi codice 2021-08-27 11:50:12 +02:00
Samuele Locatelli 9c979582d4 test sintassi pubblicazione SOLO linux 2021-08-27 11:41:52 +02:00
Samuele Locatelli 11cae94995 Update NLog 2021-08-27 11:39:45 +02:00
Samuele Locatelli 05ca047b5c Completo profili compilazione x64 Win/Linux 2021-08-27 11:39:20 +02:00
Samuele Locatelli cd533c190b Gestione profili compilazione Win/Linux x64 2021-08-27 11:39:04 +02:00
Samuele Locatelli efd84437b5 Rimozione elmah e quartz 2021-08-27 10:15:29 +02:00
Samuele Locatelli 1c36305304 Appunti log debug linux 2021-08-27 10:14:48 +02:00
Samuele Locatelli f1f1e784da Correzione jscript x generazione img-fluid 2021-08-26 19:41:35 +02:00
Samuele Locatelli 512d25f513 Merge tag 'RC2' into develop
Fix display main x spazio orizzontale (HOPE!)
2021-08-26 19:33:13 +02:00
Samuele Locatelli f1628818f3 Merge branch 'release/RC2' 2021-08-26 19:33:00 +02:00
Samuele Locatelli b57d20420b Corretto css e main class x display! 2021-08-26 19:32:36 +02:00
Samuele Locatelli cbf97a2eb6 Fix grafici x header/footer (non ancora ok) 2021-08-26 19:24:30 +02:00
Samuele Locatelli 284f7ff241 Merge tag 'RC1' into develop
Rilascio vers produzione con fix QR, fix search user, fix graph
2021-08-26 18:38:51 +02:00
Samuele Locatelli 888c7398f7 Merge branch 'release/RC1' 2021-08-26 18:38:29 +02:00
Samuele Locatelli 4926cb4715 Merge branch 'feature/DisplayFix' into develop 2021-08-26 18:37:56 +02:00
Samuele Locatelli e2c7615826 Completato revers grafici + revisione detail 2021-08-26 18:37:46 +02:00
Samuele Locatelli dc8ce10b51 Update x ricerca utenti 2021-08-26 18:02:01 +02:00
Samuele Locatelli ffb4c9872d Aggiunta paginazione utenti 2021-08-26 17:48:59 +02:00
Samuele Locatelli a415d175d9 Update gestione QR da JScript x trasportatori 2021-08-26 17:33:42 +02:00
Samuele Locatelli 60b069cd28 Merge tag 'PageAuthManRC' into develop
Fix versione page auth
2021-08-26 13:05:25 +02:00
Samuele Locatelli 7a63caa377 Merge branch 'release/PageAuthManRC' 2021-08-26 13:04:25 +02:00
Samuele Locatelli df970e0a69 Refresh progetto 2021-08-26 13:02:34 +02:00
Samuele Locatelli c5c40f67cd Merge branch 'feature/PageRoleSetup' into develop 2021-08-26 12:59:53 +02:00
Samuele Locatelli f8d2212ff3 Completata integrazione trasportatori 2021-08-26 12:59:40 +02:00
Samuele Locatelli 38bcffe135 Nuovo ruolo ( + migrazione) 2021-08-26 12:59:34 +02:00
Samuele Locatelli 02e7224736 inizio gestione supplier page 2021-08-26 12:23:52 +02:00
Samuele Locatelli 820ae5ce11 typo + fix menu 2021-08-26 12:23:43 +02:00
Samuele Locatelli 1f645b3aa2 Fix immagini lente a scaricare 2021-08-26 12:10:28 +02:00
Samuele Locatelli 9ff00ce0b6 Completata integrazioen controllo claim x pagine User+ 2021-08-26 12:02:58 +02:00
Samuele Locatelli 586d281736 revisione menu x visualizzazione condizionata ruolo 2021-08-26 11:17:48 +02:00
Samuele Locatelli 9441ee0e66 Revisione grafica pagie auth 2021-08-26 11:17:29 +02:00
Samuele Locatelli be61e174c0 Refresh 2021-08-26 10:39:35 +02:00
Samuele Locatelli 46f70964f0 Fix conf librerie locali 2021-08-26 10:38:44 +02:00
Samuele Locatelli c337bbb7da Fix bootstrap 5--> 4 2021-08-26 10:38:29 +02:00
Samuele Locatelli c007abe4a5 Aggiunta conf librerie locali 2021-08-26 10:22:45 +02:00
Samuele Locatelli 74ffe5983b Agfgiunta libreria locale bootstrap 2021-08-26 10:20:13 +02:00
Samuele Locatelli a6642512c3 refresh pagina 2021-08-25 19:14:43 +02:00
Samuele Locatelli f5389907f0 Update pagine x user login/logout/... 2021-08-25 18:59:10 +02:00
Samuele Locatelli 37ca1d9a70 INserito profilatura preliminare permessi encessari x vari ruoli 2021-08-25 18:00:16 +02:00
Samuele Locatelli a52199d4e3 Merge tag 'UserManRC' into develop
Inclusione prima versione gestione utenti con Identity Framework
2021-08-25 17:23:29 +02:00
Samuele Locatelli a6ab150e8d Merge branch 'release/UserManRC' 2021-08-25 17:23:09 +02:00
Samuele Locatelli b2afa672fc Merge branch 'feature/MoveUserUI' into develop 2021-08-25 16:32:22 +02:00
Samuele Locatelli 41e70fab62 Refresh 2021-08-25 16:32:07 +02:00
Samuele Locatelli 8bbb114c04 Controllo presenza utente samuele in login come SuperAdmin 2021-08-25 16:32:02 +02:00
Samuele Locatelli 435d12cb5b altri fix grafici 2021-08-25 16:31:41 +02:00
Samuele Locatelli d40cb20693 Fix vari css e layout 2021-08-25 16:31:34 +02:00
Samuele Locatelli 0fd554464e Sistemazione menù TOP 2021-08-25 16:31:17 +02:00
Samuele Locatelli ea04ae6245 Bozza gest user in navBar 2021-08-25 13:26:15 +02:00
Samuele Locatelli 4d717e9237 Prima integrazione funzionante (creando user) 2021-08-25 13:16:32 +02:00
Samuele Locatelli e6589a5438 Base rebuild post spostamento classi in UI 2021-08-25 13:10:45 +02:00
Samuele Locatelli 787283d239 ripristino TableCount obj 2021-08-25 13:08:58 +02:00
Samuele Locatelli 3f97f11c41 Aggiunte lib x QR + fontawesome locale 2021-08-25 13:08:48 +02:00
Samuele Locatelli cc62039aa4 Aggiunta area Identity di base 2021-08-25 13:08:29 +02:00
Samuele Locatelli 839ef56668 Merge branch 'feature/UserAuthCompletion' into develop 2021-08-25 12:35:38 +02:00
Samuele Locatelli a86eb452de Fix metodi await x users 2021-08-25 12:35:26 +02:00
Samuele Locatelli 318be3f7e0 Fix role/claims read/display 2021-08-25 12:23:55 +02:00
Samuele Locatelli 4c1ed660b2 Continuo identit: user + roles + claims 2021-08-25 12:03:45 +02:00
Samuele Locatelli 1778dd9290 Continuo integrazione librerie client (fontawesome) 2021-08-25 09:31:40 +02:00
Samuele Locatelli fef078b3bb update readme 2021-08-25 09:31:28 +02:00
Samuele Locatelli d3ebef281b Aggiunta libreria font-awesome 2021-08-25 09:21:29 +02:00
Samuele Locatelli f9999e6900 Merge branch 'feature/UserAuth' into develop 2021-08-24 19:29:43 +02:00
Samuele Locatelli 74ba4373f3 OK editing ruolo! 2021-08-24 19:29:28 +02:00
Samuele Locatelli 79436685d7 Ok fix gestione editing ruolo 2021-08-24 18:57:37 +02:00
Samuele Locatelli e9173e9735 Bozza pagina editing utenti (DA RIVEDERE!) 2021-08-24 17:48:29 +02:00
Samuele Locatelli d59ba7525f Ancora update admin utenti 2021-08-24 17:20:51 +02:00
Samuele Locatelli 38d7f0e8a0 Update verbosità LOG 2021-08-24 17:20:43 +02:00
Samuele Locatelli b25aeaa312 refresh pagina admin 2021-08-24 17:15:36 +02:00
Samuele Locatelli 227e7ded81 Continuo implementazione gestione utenti 2021-08-24 17:15:28 +02:00
Samuele Locatelli 65c17437f8 Fix migration x nuovo ruolo senza eliminare i precedenti 2021-08-24 16:43:23 +02:00
Samuele Locatelli c14f031fc5 Aggiunta preliminare migration (da validare) 2021-08-24 16:40:24 +02:00
Samuele Locatelli f6ecbb5761 Fix gestione auth richeista + eccezione in HOME 2021-08-24 16:08:10 +02:00
Samuele Locatelli 9150df1286 Inserito migration dati, gestione ruoli testata 2021-08-24 15:46:12 +02:00
Samuele Locatelli d0ab2df2ba rimozione Table COunters 2021-08-24 15:23:46 +02:00
Samuele Locatelli d364a16a58 aggiunta view auth x testing 2021-08-24 15:18:52 +02:00
Samuele Locatelli 75ab78ace4 aggiunta preliminare conf ruoli 2021-08-24 15:18:37 +02:00
Samuele Locatelli 0d34e61940 refresh site css 2021-08-24 15:02:19 +02:00
Samuele Locatelli 104e4acd93 Modifiche x sperimentare gestione ruoli auth 2021-08-24 14:59:11 +02:00
Samuele Locatelli bf7acb2b08 update gitignore 2021-08-24 14:59:00 +02:00
Samuele Locatelli 5e6453f53e Inizio setup x gestione QRCode 2021-08-24 14:15:36 +02:00
Samuele Locatelli d0e29fa6b4 Aggiunta classi x identity 2021-08-24 14:15:28 +02:00
Samuele Locatelli 32162c66ec refresh 2021-08-24 13:18:46 +02:00
Samuele Locatelli b01703f12f Minor fix grafici aprte UI AUTH 2021-08-24 13:18:43 +02:00
Samuele Locatelli 0db3604ade Merge branch 'develop' 2021-08-24 12:58:05 +02:00
Samuele Locatelli 379723889e Fix dotnet restore 2021-08-24 12:57:03 +02:00
Samuele Locatelli 17f3aa7c6e Merge branch 'develop' 2021-08-24 12:55:34 +02:00
Samuele Locatelli ab0c242e6d udpate Yaml 2021-08-24 12:55:06 +02:00
Samuele Locatelli cdba46bc45 Merge tag 'BetaLog' into develop
Rilascio versione con 2 sln separate
2021-08-24 12:52:28 +02:00
Samuele Locatelli 40353cfc03 Merge branch 'release/BetaLog' 2021-08-24 12:52:13 +02:00
Samuele Locatelli be46d09654 Cleanup e split progetti 2021-08-24 12:51:24 +02:00
Samuele Locatelli ef54e6f0cc Merge tag 'DemoAuthAndLogSignal-r' into develop
Inserimento log x debug signal-r richeisto da Marco e prima versione
Auth identity
2021-08-24 12:44:06 +02:00
Samuele Locatelli 29b084ae0e Merge branch 'release/DemoAuthAndLogSignal-r' 2021-08-24 12:43:49 +02:00
Samuele Locatelli 6564077260 Merge branch 'feature/UserAuth' into develop 2021-08-24 12:43:15 +02:00
Samuele Locatelli 9f495197d0 Aggiunta classi x gestione auth/identity 2021-08-24 12:42:52 +02:00
Samuele Locatelli a9286062c1 Fix logging x signal-r 2021-08-24 12:42:29 +02:00
Samuele Locatelli 1ea8e13a14 Appunti classe mailsender 2021-08-24 12:42:15 +02:00
Samuele Locatelli de0e9b990c Ancora update x AUTH 2021-08-24 12:41:59 +02:00
Samuele Locatelli c63116f871 Integrato MailKIT e testato invio email ad utente 2021-08-24 12:03:57 +02:00
Samuele Locatelli f956f010c3 Merge tag 'FixWeekPlanDisplay' into develop
Correzione problema display WeekPlan (mancavano include dei vari item di
dettaglio collegati in lettura EFCore)
2021-08-24 10:14:31 +02:00
Samuele Locatelli 42e3e44cd2 Fix errore display WeekPlan 2021-08-24 10:13:06 +02:00
Samuele Locatelli 6717945249 Merge tag 'BetaTest' into develop
Inserita navigabilità x smart device + sel trasportatore libera (da
gestire auth...)
2021-08-24 09:30:35 +02:00
512 changed files with 185502 additions and 831 deletions
-90
View File
@@ -4,96 +4,6 @@
*.pdb
.vs/*
#--------------------------------
# Area VersGen
#--------------------------------
/VersGen/bin/*
/VersGen/obj/*
#--------------------------------
# area MapoDb
#--------------------------------
/MapoDb/bin/*
/MapoDb/obj/*
#--------------------------------
# area MP
#--------------------------------
/MP/bin/*
/MP/obj/*
MP/logs/*.txt
MP/logs/*.zip
MP-LAND/logs/
#--------------------------------
# Area MP-MON (MoonPro-MONitor)
#--------------------------------
/MP-MON/logs/*.zip
/MP-MON/logs/*.txt
/MP-MON/bin/*
/MP-MON/obj/*
/MP-MON/WebCharts/*.png
#--------------------------------
# Area MP-IO (MoonPro-IO)
#--------------------------------
/MP-IO/logs/*.zip
/MP-IO/logs/*.txt
/MP-IO/bin/*
/MP-IO/obj/*
/MP-IO/fileUpload/
!/MP-IO/fileUpload/.PlaceHolder.file
#--------------------------------
# Area MP-Admin
#--------------------------------
/MP-Admin/logs/*.zip
/MP-Admin/logs/*.txt
/MP-Admin/bin/*
/MP-Admin/obj/*
/MP-ADM/logs/*.zip
/MP-ADM/logs/*.txt
/MP-ADM/bin/*
/MP-ADM/obj/*
#--------------------------------
# Area ES3
#--------------------------------
/ES3/logs/*.zip
/ES3/logs/*.txt
/ES3/bin/*
/ES3/obj/*
#--------------------------------
# Area MoonProTablet
#--------------------------------
/MP-TAB/logs/*.zip
/MP-TAB/logs/*.txt
/MP-TAB/bin/*
/MP-TAB/obj/*
/MP-TAB/WebCharts/*.png
/MP-TAB/images/macchine/*.*
!/MP-TAB/images/macchine/Steamware.png
/MP-TAB/Files/Disegni/*.pdf
!/MP-TAB/Files/Disegni/ND.pdf
MP-TAB/logs/
#--------------------------------
# Area MoonPro
#--------------------------------
/MP-Site/logs/*.zip
/MP-Site/logs/*.txt
/MP-Site/bin/*
/MP-Site/obj/*
/MP-Site/WebCharts/*.png
/MP-Site/images/macchine/*.*
!/MP-Site/images/macchine/Steamware.png
# ---> VisualStudio
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
+14 -4
View File
@@ -70,19 +70,23 @@ stages:
build:
stage: build
tags:
- win
before_script:
- *nuget-fix
- dotnet restore
- dotnet restore GWMS.sln
script:
- dotnet build
- dotnet build -p:Configuration=Release GWMS.UI/GWMS.UI.csproj
test:
stage: test
tags:
- win
only:
- develop
needs: ["build"]
script:
- dotnet test
- dotnet test -p:Configuration=Release GWMS.UI/GWMS.UI.csproj
# IIS01:deploy:
# stage: deploy
@@ -110,6 +114,8 @@ test:
installer:
stage: installer
tags:
- win
only:
- develop
- master
@@ -118,13 +124,17 @@ installer:
# - *nuget-fix
# - dotnet restore
script:
- dotnet publish -p:PublishProfile=IISProfile.pubxml -p:RunCodeAnalysis=false -p:Configuration=Release GWMS.UI/GWMS.UI.csproj -o:publish
# - dotnet publish -p:PublishProfile=IISProfile.pubxml -p:RunCodeAnalysis=false -p:Configuration=Release GWMS.UI/GWMS.UI.csproj -o:publish
# pubblico solo installer Linux x64: https://docs.microsoft.com/en-us/dotnet/core/deploying/
- dotnet publish -p:PublishProfile=IISProfile.pubxml -p:RunCodeAnalysis=false -p:Configuration=Release GWMS.UI/GWMS.UI.csproj -o:publish -r linux-x64 --self-contained false
# qui il deploy su nexus...
- *hashBuild
- *nexusUpload
release:
stage: release
tags:
- win
only:
#- feature/Deploy_CI_CD
# - master
+29 -159
View File
@@ -26,117 +26,11 @@ namespace GWMS.Data.Controllers
{
_configuration = configuration;
dbCtx = new GWMSContext(configuration);
Log.Info("Avviata classe GWMSController");
//Log.Info("Avviata classe GWMSController");
}
#endregion Public Constructors
#region Private Methods
private void CreateSimData(int numDays, int stepMin, int maxHourRate)
{
// disattivazione per sicurezza
#if false
ResetController();
// generazione dati casuale
Random rnd = new Random();
foreach (var plant in GetPlants())
{
var currPlant = GetPlant(plant.PlantId);
// imposto limiti e valori attuali...
//currPlant.LevelMax = rnd.Next(24, 28) * 1000;
int simLevel = rnd.Next(1, (int)currPlant.LevelMax);
double simPress = (double)rnd.Next((int)(currPlant.PressMax - 50) * 10, (int)currPlant.PressMax * 10) / 10;
double simPressH = (double)rnd.Next((int)(currPlant.PressBHMax - 70) * 10, (int)currPlant.PressBHMax * 10) / 10;
double simPressL = (double)rnd.Next((int)(currPlant.PressBLMax - 70) * 10, (int)currPlant.PressBLMax * 10) / 10;
currPlant.LevelAct = simLevel;
currPlant.PressAct = simPress;
currPlant.PressBHAct = simPressH;
currPlant.PressBLAct = simPressL;
dbCtx.SaveChanges();
// genero random le soglie x simulare rilievi e ordini
int soglia01 = rnd.Next((int)currPlant.LevelMax * 60 / 100, (int)currPlant.LevelMax * 75 / 100);
int soglia02 = rnd.Next((int)currPlant.LevelMax * 5 / 100, (int)currPlant.LevelMax * 35 / 100);
List<PlantLogModel> LogLevels = new List<PlantLogModel>();
List<PlantLogModel> LogPressures = new List<PlantLogModel>();
List<OrderModel> LogOrders = new List<OrderModel>();
DateTime adesso = DateTime.Now;
int lastLevel = simLevel;
int lastOrder = 0;
int anticipo = 0;
double lastPress = simPress;
double lastPressH = simPressH;
double lastPressL = simPressL;
// simulo numDays gg...
for (int i = numDays * 24 * (60 / stepMin); i > 0; i--)
{
anticipo = i * stepMin;
lastLevel = lastLevel - rnd.Next(0, maxHourRate / (60 / stepMin));
// se inferiore a soglia 1 --> ordine
if (lastLevel + lastOrder < soglia01)
{
lastOrder = rnd.Next((int)currPlant.LevelMax - soglia01, (int)currPlant.LevelMax - soglia02);
LogOrders.Add(new OrderModel() { DtOrder = adesso.AddMinutes(-anticipo), OrderQty = lastOrder, PlantId = plant.PlantId, OrderCode = $"ORD{i:000000}", OrderDesc = "SIM Order", SupplierId = 1, TransporterId = 1 });
}
// se inferiore a soglia 2 --> refill
if (lastLevel < soglia02)
{
lastLevel += lastOrder;
lastOrder = 0;
}
LogLevels.Add(new PlantLogModel() { DtEvent = adesso.AddMinutes(-anticipo), FluxType = "Level", PlantId = plant.PlantId, ValNumber = lastLevel });
// pressioni!
lastPress = lastPress - (double)rnd.Next(-30, 25) / 10;
lastPressH = lastPressH - (double)rnd.Next(-25, 20) / 10;
lastPressL = lastPressL - (double)rnd.Next(-25, 20) / 10;
LogPressures.Add(new PlantLogModel() { DtEvent = adesso.AddMinutes(-anticipo), FluxType = "MainPress", PlantId = plant.PlantId, ValNumber = lastPress });
LogPressures.Add(new PlantLogModel() { DtEvent = adesso.AddMinutes(-anticipo), FluxType = "PressBH", PlantId = plant.PlantId, ValNumber = lastPressH });
LogPressures.Add(new PlantLogModel() { DtEvent = adesso.AddMinutes(-anticipo), FluxType = "PressBL", PlantId = plant.PlantId, ValNumber = lastPressL });
}
try
{
dbCtx
.DbSetPlantLog
.AddRange(LogLevels);
dbCtx
.DbSetPlantLog
.AddRange(LogPressures);
// salvo sul DB!
dbCtx.SaveChanges();
Log.Info($"Effettuato inserimento {LogLevels.Count} record PlantLog");
}
catch (Exception exc)
{
Log.Error($"Eccezione in salvataggio PlantLog{Environment.NewLine}{exc}");
}
try
{
dbCtx
.DbSetOrders
.AddRange(LogOrders);
// salvo sul DB!
dbCtx.SaveChanges();
Log.Info($"Effettuato inserimento {LogOrders.Count} record Orders");
}
catch (Exception exc)
{
Log.Error($"Eccezione in salvataggio Orders{Environment.NewLine}{exc}");
}
}
#endif
}
#endregion Private Methods
#region Public Methods
/// <summary>
@@ -156,6 +50,7 @@ namespace GWMS.Data.Controllers
{
// Clear database context
dbCtx.Dispose();
//Log.Info("Dispose di GWMSController");
}
public List<ConfigModel> GetConfig()
@@ -261,9 +156,9 @@ namespace GWMS.Data.Controllers
public List<PlantDTO> GetPlantsDTO(int maxRecords)
{
List<PlantDTO> dbResult = new List<PlantDTO>();
using (GWMSContext dbCtxMult = new GWMSContext(_configuration))
using (GWMSContext localDbCtx = new GWMSContext(_configuration))
{
var plantList = dbCtxMult
var plantList = localDbCtx
.DbSetPlant
.ToList();
@@ -327,10 +222,16 @@ namespace GWMS.Data.Controllers
public List<WeekPlanModel> GetWeekPlan()
{
var dbResult = dbCtx
.DbSetPlantSupplWeekPlan
.ToList();
List<WeekPlanModel> dbResult = new List<WeekPlanModel>();
using (GWMSContext localDbCtx = new GWMSContext(_configuration))
{
dbResult = localDbCtx
.DbSetPlantSupplWeekPlan
.Include(p => p.Plant)
.Include(s => s.Supplier)
.Include(t => t.Transporter)
.ToList();
}
return dbResult;
}
@@ -422,25 +323,9 @@ namespace GWMS.Data.Controllers
localDbCtx.Entry(updItem).State = EntityState.Modified;
localDbCtx.SaveChanges();
}
//// se ho modificato data --> cambio codice ordine!
//if (!dbCtx.Entry(updItem).OriginalValues["DtOrder"].Equals(dbCtx.Entry(updItem).CurrentValues["DtOrder"]))
//{
// updItem.OrderCode = $"O{updItem.Plant.PlantCode}{updItem.DtOrder:yyMMddHHmm}";
// updItem.OrderDesc = $"Ordine {updItem.Plant.PlantDesc} - {updItem.DtOrder}";
//}
//dbCtx.Entry(updItem).State = EntityState.Modified;
//dbCtx.SaveChanges();
}
else
{
//using (GWMSContext localDbCtx = new GWMSContext(_configuration))
//{
// localDbCtx
// .DbSetOrders
// .Add(updItem);
// localDbCtx.SaveChanges();
//}
dbCtx
.DbSetOrders
.Add(updItem);
@@ -461,6 +346,7 @@ namespace GWMS.Data.Controllers
/// <returns></returns>
public PlantDTO PlantDTO(int PlantId, int maxRecords)
{
DateTime lastRec = DateTime.Today;
var currPlant = GetPlant(PlantId);
PlantDTO answ = new PlantDTO();
List<TSData> LevelTS = new List<TSData>();
@@ -471,42 +357,47 @@ namespace GWMS.Data.Controllers
List<TSData> PressBLTS = new List<TSData>();
List<TSData> OrderTS = new List<TSData>();
using (GWMSContext dbCtxMult = new GWMSContext(_configuration))
using (GWMSContext localDbCtx = new GWMSContext(_configuration))
{
// recupero dal DB
var rawLevelData = dbCtxMult
var rawLevelData = localDbCtx
.DbSetPlantLog
.Where(x => x.FluxType == "Level" && x.PlantId == PlantId)
.OrderByDescending(x => x.DtEvent)
.Take(maxRecords)
.OrderBy(x => x.DtEvent)
.ToList();
var rawMainPressData = dbCtxMult
var rawMainPressData = localDbCtx
.DbSetPlantLog
.Where(x => x.FluxType == "MainPress" && x.PlantId == PlantId)
.OrderByDescending(x => x.DtEvent)
.Take(maxRecords)
.OrderBy(x => x.DtEvent)
.ToList();
var rawBHPressData = dbCtxMult
var rawBHPressData = localDbCtx
.DbSetPlantLog
.Where(x => x.FluxType == "PressBH" && x.PlantId == PlantId)
.OrderByDescending(x => x.DtEvent)
.Take(maxRecords)
.OrderBy(x => x.DtEvent)
.ToList();
var rawBLPressData = dbCtxMult
var rawBLPressData = localDbCtx
.DbSetPlantLog
.Where(x => x.FluxType == "PressBL" && x.PlantId == PlantId)
.OrderByDescending(x => x.DtEvent)
.Take(maxRecords)
.OrderBy(x => x.DtEvent)
.ToList();
var rawOrderData = dbCtxMult
var rawOrderData = localDbCtx
.DbSetOrders
.Where(x => x.PlantId == PlantId && x.ExecutionQty == 0)
.OrderByDescending(x => x.DtOrder)
.Take(maxRecords)
.OrderBy(x => x.DtOrder)
.ToList();
LevelTS = rawLevelData
@@ -533,6 +424,8 @@ namespace GWMS.Data.Controllers
double valBH = PressBHTS.Count > 0 ? PressBHTS.OrderByDescending(x => x.DtEvent).Take(1).FirstOrDefault().ValDouble : 0;
double valBL = PressBLTS.Count > 0 ? PressBLTS.OrderByDescending(x => x.DtEvent).Take(1).FirstOrDefault().ValDouble : 0;
lastRec = LevelTS.Count > 0 ? LevelTS.OrderByDescending(x => x.DtEvent).Take(1).FirstOrDefault().DtEvent : DateTime.Today;
PressAct.Add("Main", valMain);
PressAct.Add("BH", valBH);
PressAct.Add("BL", valBL);
@@ -540,6 +433,7 @@ namespace GWMS.Data.Controllers
// popolo valolri
answ = new PlantDTO()
{
LastUpdate = lastRec,
PlantId = PlantId,
PlantCode = currPlant.PlantCode,
PlantDesc = currPlant.PlantDesc,
@@ -614,30 +508,6 @@ namespace GWMS.Data.Controllers
return done;
}
/// <summary>
/// Rigenera intero DB se riceve ID di un plant SIM...
/// </summary>
/// <param name="PlantId"></param>
public bool RegenDB(int PlantId, int numDays, int stepMin, int maxHourRate)
{
bool answ = false;
var currPlant = GetPlant(PlantId);
if (currPlant.PlantCode.StartsWith("PIZ"))
{
Log.Info("Inizio RegenDB");
DbAdmin.resetPlantLogTable();
ResetController();
CreateSimData(numDays, stepMin, maxHourRate);
Log.Info("Dati SIM generati");
answ = true;
}
return answ;
}
public void ResetController()
{
dbCtx = new GWMSContext(_configuration);
+2
View File
@@ -18,6 +18,8 @@ namespace GWMS.Data.DTO
public string PlantCode { get; set; } = "";
public string PlantDesc { get; set; } = "";
public DateTime LastUpdate { get; set; } = DateTime.Today.AddDays(DateTime.Today.DayOfYear);
public double LevelMax { get; set; } = 99999;
public double LevelAct { get; set; } = 0;
+3
View File
@@ -7,6 +7,9 @@ using System.Threading.Tasks;
namespace GWMS.Data.DatabaseModels
{
/// <summary>
/// Classe fake x il conteggio tabelle e check preliminari
/// </summary>
[Keyless]
public class TableCount
{
+1
View File
@@ -9,6 +9,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="MailKit" Version="2.15.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="5.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.7" />
+65
View File
@@ -0,0 +1,65 @@
using MailKit.Net.Smtp;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.Extensions.Options;
using MimeKit;
using MimeKit.Text;
using System.Threading.Tasks;
namespace GWMS.Data
{
/// <summary>
/// Implementazione interfaccia email con pacchetto MailKIT
///
/// https://www.ryadel.com/en/asp-net-core-send-email-messages-smtp-mailkit/
/// </summary>
public class MailKitEmailSender : IEmailSender
{
#region Public Constructors
public MailKitEmailSender(IOptions<MailKitEmailSenderOptions> options)
{
this.Options = options.Value;
}
#endregion Public Constructors
#region Public Properties
public MailKitEmailSenderOptions Options { get; set; }
#endregion Public Properties
#region Public Methods
public Task Execute(string to, string subject, string message)
{
// create message
var email = new MimeMessage();
email.Sender = MailboxAddress.Parse(Options.Sender_EMail);
if (!string.IsNullOrEmpty(Options.Sender_Name))
email.Sender.Name = Options.Sender_Name;
email.From.Add(email.Sender);
email.To.Add(MailboxAddress.Parse(to));
email.Subject = subject;
email.Body = new TextPart(TextFormat.Html) { Text = message };
// send email
using (var smtp = new SmtpClient())
{
smtp.Connect(Options.Host_Address, Options.Host_Port, Options.Host_SecureSocketOptions);
smtp.Authenticate(Options.Host_Username, Options.Host_Password);
smtp.Send(email);
smtp.Disconnect(true);
}
return Task.FromResult(true);
}
public Task SendEmailAsync(string email, string subject, string message)
{
return Execute(email, subject, message);
}
#endregion Public Methods
}
}
+31
View File
@@ -0,0 +1,31 @@
using MailKit.Security;
namespace GWMS.Data
{
public class MailKitEmailSenderOptions
{
#region Public Constructors
public MailKitEmailSenderOptions()
{
Host_SecureSocketOptions = SecureSocketOptions.Auto;
}
#endregion Public Constructors
#region Public Properties
public string Host_Address { get; set; }
public string Host_Password { get; set; }
public int Host_Port { get; set; }
public SecureSocketOptions Host_SecureSocketOptions { get; set; }
public string Host_Username { get; set; }
public string Sender_EMail { get; set; }
public string Sender_Name { get; set; }
#endregion Public Properties
}
}
+301
View File
@@ -0,0 +1,301 @@
// <auto-generated />
using System;
using GWMS.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace GWMS.User.Migrations
{
[DbContext(typeof(UserIdentityDbContext))]
[Migration("20210824132434_RolesAdded")]
partial class RolesAdded
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 64)
.HasAnnotation("ProductVersion", "5.0.8");
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles");
b.HasData(
new
{
Id = "24a790ae-8eac-4c9f-9043-aa688b626169",
ConcurrencyStamp = "c9adff6c-ffac-48e3-899b-8549ca443071",
Name = "ExtUser",
NormalizedName = "EXTUSER"
},
new
{
Id = "7a024dca-5e5d-47be-b754-75c8921d88bf",
ConcurrencyStamp = "3b9aab89-73b6-4051-9825-d5381d2896da",
Name = "User",
NormalizedName = "USER"
},
new
{
Id = "0a5335f9-64b2-4196-9d5b-db873cb48d94",
ConcurrencyStamp = "25097cab-df45-4bdd-8616-041962c72050",
Name = "Admin",
NormalizedName = "ADMIN"
},
new
{
Id = "f6aa57e0-fac5-45b7-8e27-fd01d8eff87d",
ConcurrencyStamp = "3c222fe9-d5e5-4ba0-9767-4c1777677105",
Name = "SuperAdmin",
NormalizedName = "SUPERADMIN"
});
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255)");
b.Property<int>("AccessFailedCount")
.HasColumnType("int");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("tinyint(1)");
b.Property<bool>("LockoutEnabled")
.HasColumnType("tinyint(1)");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("datetime(6)");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("PasswordHash")
.HasColumnType("longtext");
b.Property<string>("PhoneNumber")
.HasColumnType("longtext");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("tinyint(1)");
b.Property<string>("SecurityStamp")
.HasColumnType("longtext");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("tinyint(1)");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("ProviderKey")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("ProviderDisplayName")
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255)");
b.Property<string>("RoleId")
.HasColumnType("varchar(255)");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255)");
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("Value")
.HasColumnType("longtext");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,48 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace GWMS.User.Migrations
{
public partial class RolesAdded : Migration
{
#region Protected Methods
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "0a5335f9-64b2-4196-9d5b-db873cb48d94");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "24a790ae-8eac-4c9f-9043-aa688b626169");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "7a024dca-5e5d-47be-b754-75c8921d88bf");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "f6aa57e0-fac5-45b7-8e27-fd01d8eff87d");
}
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.InsertData(
table: "AspNetRoles",
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ "24a790ae-8eac-4c9f-9043-aa688b626169", "c9adff6c-ffac-48e3-899b-8549ca443071", "ExtUser", "EXTUSER" },
{ "7a024dca-5e5d-47be-b754-75c8921d88bf", "3b9aab89-73b6-4051-9825-d5381d2896da", "User", "USER" },
{ "0a5335f9-64b2-4196-9d5b-db873cb48d94", "25097cab-df45-4bdd-8616-041962c72050", "Admin", "ADMIN" },
{ "f6aa57e0-fac5-45b7-8e27-fd01d8eff87d", "3c222fe9-d5e5-4ba0-9767-4c1777677105", "SuperAdmin", "SUPERADMIN" }
});
}
#endregion Protected Methods
}
}
@@ -0,0 +1,308 @@
// <auto-generated />
using System;
using GWMS.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace GWMS.User.Migrations
{
[DbContext(typeof(UserIdentityDbContext))]
[Migration("20210824143900_UndefRoleAdd")]
partial class UndefRoleAdd
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 64)
.HasAnnotation("ProductVersion", "5.0.8");
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles");
b.HasData(
new
{
Id = "bf698c1c-ead1-4d88-83ef-536098876807",
ConcurrencyStamp = "28d97b49-8df4-4d20-8680-1d3abbf4ed94",
Name = "Undef",
NormalizedName = "UNDEF"
},
new
{
Id = "a1280bf2-7e5a-447b-b070-3bea27ba2239",
ConcurrencyStamp = "d361332c-1ae0-486c-b1d8-1f2c9c36ad88",
Name = "ExtUser",
NormalizedName = "EXTUSER"
},
new
{
Id = "533995b8-8561-471a-b613-a03685141065",
ConcurrencyStamp = "773db769-a518-406f-9144-31e1fd9f7a76",
Name = "User",
NormalizedName = "USER"
},
new
{
Id = "d4790e4e-600b-4bae-876d-04c619adc9b0",
ConcurrencyStamp = "70529623-7648-4640-b69e-a1e0ddff10ed",
Name = "Admin",
NormalizedName = "ADMIN"
},
new
{
Id = "3e7ddc7b-94eb-4364-b4d5-311c76dad5b1",
ConcurrencyStamp = "1d59afd3-30f6-492c-87eb-cddf0b251f85",
Name = "SuperAdmin",
NormalizedName = "SUPERADMIN"
});
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255)");
b.Property<int>("AccessFailedCount")
.HasColumnType("int");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("tinyint(1)");
b.Property<bool>("LockoutEnabled")
.HasColumnType("tinyint(1)");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("datetime(6)");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("PasswordHash")
.HasColumnType("longtext");
b.Property<string>("PhoneNumber")
.HasColumnType("longtext");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("tinyint(1)");
b.Property<string>("SecurityStamp")
.HasColumnType("longtext");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("tinyint(1)");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("ProviderKey")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("ProviderDisplayName")
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255)");
b.Property<string>("RoleId")
.HasColumnType("varchar(255)");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255)");
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("Value")
.HasColumnType("longtext");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,30 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace GWMS.User.Migrations
{
public partial class UndefRoleAdd : Migration
{
#region Protected Methods
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "bf698c1c-ead1-4d88-83ef-536098876807");
}
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.InsertData(
table: "AspNetRoles",
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ "bf698c1c-ead1-4d88-83ef-536098876807", "28d97b49-8df4-4d20-8680-1d3abbf4ed94", "Undef", "UNDEF" }
});
}
#endregion Protected Methods
}
}
@@ -0,0 +1,308 @@
// <auto-generated />
using System;
using GWMS.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace GWMS.User.Migrations
{
[DbContext(typeof(UserIdentityDbContext))]
[Migration("20210824155840_FixRolesName")]
partial class FixRolesName
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 64)
.HasAnnotation("ProductVersion", "5.0.8");
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles");
b.HasData(
new
{
Id = "5287113c-6493-4419-bbc9-2cb2f6455006",
ConcurrencyStamp = "00059b0a-3e8c-406e-a578-2ae40c52435a",
Name = "Undef",
NormalizedName = "UNDEF"
},
new
{
Id = "f27a0416-02cc-4e4c-8983-29cb51eb4f9a",
ConcurrencyStamp = "b58874fc-02b5-4efa-b4d5-61bfda8b7c67",
Name = "ExtUser",
NormalizedName = "EXTUSER"
},
new
{
Id = "00e6b3ed-dd0e-4cd5-8d3d-f88d8ae5e145",
ConcurrencyStamp = "cd1f0ba9-9f42-42f3-8271-1627ef55d36f",
Name = "User",
NormalizedName = "USER"
},
new
{
Id = "5b928219-a530-49c6-be33-f65253865a98",
ConcurrencyStamp = "6de09bee-9a83-416a-90c4-27bb643519f6",
Name = "Admin",
NormalizedName = "ADMIN"
},
new
{
Id = "e9befc87-9732-4c21-b91e-7aea6a289d35",
ConcurrencyStamp = "f2bf6c1c-4043-4344-8b68-c8b2122ab88f",
Name = "SuperAdmin",
NormalizedName = "SUPERADMIN"
});
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255)");
b.Property<int>("AccessFailedCount")
.HasColumnType("int");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("tinyint(1)");
b.Property<bool>("LockoutEnabled")
.HasColumnType("tinyint(1)");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("datetime(6)");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("PasswordHash")
.HasColumnType("longtext");
b.Property<string>("PhoneNumber")
.HasColumnType("longtext");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("tinyint(1)");
b.Property<string>("SecurityStamp")
.HasColumnType("longtext");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("tinyint(1)");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("ProviderKey")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("ProviderDisplayName")
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255)");
b.Property<string>("RoleId")
.HasColumnType("varchar(255)");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255)");
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("Value")
.HasColumnType("longtext");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,91 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace GWMS.User.Migrations
{
public partial class FixRolesName : Migration
{
#region Protected Methods
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "00e6b3ed-dd0e-4cd5-8d3d-f88d8ae5e145");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "5287113c-6493-4419-bbc9-2cb2f6455006");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "5b928219-a530-49c6-be33-f65253865a98");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "e9befc87-9732-4c21-b91e-7aea6a289d35");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "f27a0416-02cc-4e4c-8983-29cb51eb4f9a");
migrationBuilder.InsertData(
table: "AspNetRoles",
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ "bf698c1c-ead1-4d88-83ef-536098876807", "28d97b49-8df4-4d20-8680-1d3abbf4ed94", "Undef", "UNDEF" },
{ "24a790ae-8eac-4c9f-9043-aa688b626169", "c9adff6c-ffac-48e3-899b-8549ca443071", "ExtUser", "EXTUSER" },
{ "7a024dca-5e5d-47be-b754-75c8921d88bf", "3b9aab89-73b6-4051-9825-d5381d2896da", "User", "USER" },
{ "0a5335f9-64b2-4196-9d5b-db873cb48d94", "25097cab-df45-4bdd-8616-041962c72050", "Admin", "ADMIN" },
{ "f6aa57e0-fac5-45b7-8e27-fd01d8eff87d", "3c222fe9-d5e5-4ba0-9767-4c1777677105", "SuperAdmin", "SUPERADMIN" }
});
}
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "0a5335f9-64b2-4196-9d5b-db873cb48d94");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "24a790ae-8eac-4c9f-9043-aa688b626169");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "7a024dca-5e5d-47be-b754-75c8921d88bf");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "bf698c1c-ead1-4d88-83ef-536098876807");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "f6aa57e0-fac5-45b7-8e27-fd01d8eff87d");
migrationBuilder.InsertData(
table: "AspNetRoles",
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ "5287113c-6493-4419-bbc9-2cb2f6455006", "00059b0a-3e8c-406e-a578-2ae40c52435a", "Undef", "UNDEF" },
{ "f27a0416-02cc-4e4c-8983-29cb51eb4f9a", "b58874fc-02b5-4efa-b4d5-61bfda8b7c67", "ExtUser", "EXTUSER" },
{ "00e6b3ed-dd0e-4cd5-8d3d-f88d8ae5e145", "cd1f0ba9-9f42-42f3-8271-1627ef55d36f", "User", "USER" },
{ "5b928219-a530-49c6-be33-f65253865a98", "6de09bee-9a83-416a-90c4-27bb643519f6", "Admin", "ADMIN" },
{ "e9befc87-9732-4c21-b91e-7aea6a289d35", "f2bf6c1c-4043-4344-8b68-c8b2122ab88f", "SuperAdmin", "SUPERADMIN" }
});
}
#endregion Protected Methods
}
}
@@ -0,0 +1,326 @@
// <auto-generated />
using System;
using GWMS.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace GWMS.User.Migrations
{
[DbContext(typeof(UserIdentityDbContext))]
[Migration("20210826102940_AddTransporterRule")]
partial class AddTransporterRule
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 64)
.HasAnnotation("ProductVersion", "5.0.7");
modelBuilder.Entity("GWMS.Data.DatabaseModels.TableCount", b =>
{
b.Property<int>("Count")
.HasColumnType("int");
b.Property<string>("TableName")
.HasColumnType("longtext");
b.ToTable("DbSetCounts");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles");
b.HasData(
new
{
Id = "339a7ac3-4fcd-4baa-bd19-a6a09d1b7c5d",
ConcurrencyStamp = "3caf0732-df97-4b81-ba2c-9fb51e34532a",
Name = "Undef",
NormalizedName = "UNDEF"
},
new
{
Id = "47c8d4fb-6925-4ef0-a830-5df33e705d7a",
ConcurrencyStamp = "9671ece6-f70a-4ca6-88db-64562e007c72",
Name = "ExtUser",
NormalizedName = "EXTUSER"
},
new
{
Id = "2d87821f-5c6d-4d9e-98d7-7ae801030100",
ConcurrencyStamp = "9ee56f2f-558f-4579-9ad7-4a6150e3d822",
Name = "ExtTransp",
NormalizedName = "EXTTRANSP"
},
new
{
Id = "db1d1ac5-905d-46a5-bcf4-ef8a5f3f715c",
ConcurrencyStamp = "3244e9d3-ab0e-45ae-97b6-c8c74f57cf64",
Name = "User",
NormalizedName = "USER"
},
new
{
Id = "7e3dc53b-c152-440f-a49d-6c3a2f6bf6eb",
ConcurrencyStamp = "a0a109e5-ab8e-4e20-9aa8-eba3c429fd12",
Name = "Admin",
NormalizedName = "ADMIN"
},
new
{
Id = "2fcd8455-143a-4ebc-b41c-e9bdf6a0315b",
ConcurrencyStamp = "549b8a8d-ba83-4b79-be88-fde0bd4cc60f",
Name = "SuperAdmin",
NormalizedName = "SUPERADMIN"
});
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("varchar(255)");
b.Property<int>("AccessFailedCount")
.HasColumnType("int");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("longtext");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("tinyint(1)");
b.Property<bool>("LockoutEnabled")
.HasColumnType("tinyint(1)");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("datetime(6)");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.Property<string>("PasswordHash")
.HasColumnType("longtext");
b.Property<string>("PhoneNumber")
.HasColumnType("longtext");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("tinyint(1)");
b.Property<string>("SecurityStamp")
.HasColumnType("longtext");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("tinyint(1)");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ClaimType")
.HasColumnType("longtext");
b.Property<string>("ClaimValue")
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("ProviderKey")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("ProviderDisplayName")
.HasColumnType("longtext");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("varchar(255)");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255)");
b.Property<string>("RoleId")
.HasColumnType("varchar(255)");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("varchar(255)");
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("varchar(128)");
b.Property<string>("Value")
.HasColumnType("longtext");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,109 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace GWMS.User.Migrations
{
public partial class AddTransporterRule : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "00e6b3ed-dd0e-4cd5-8d3d-f88d8ae5e145");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "5287113c-6493-4419-bbc9-2cb2f6455006");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "5b928219-a530-49c6-be33-f65253865a98");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "e9befc87-9732-4c21-b91e-7aea6a289d35");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "f27a0416-02cc-4e4c-8983-29cb51eb4f9a");
migrationBuilder.CreateTable(
name: "DbSetCounts",
columns: table => new
{
Count = table.Column<int>(type: "int", nullable: false),
TableName = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.InsertData(
table: "AspNetRoles",
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ "339a7ac3-4fcd-4baa-bd19-a6a09d1b7c5d", "3caf0732-df97-4b81-ba2c-9fb51e34532a", "Undef", "UNDEF" },
{ "47c8d4fb-6925-4ef0-a830-5df33e705d7a", "9671ece6-f70a-4ca6-88db-64562e007c72", "ExtUser", "EXTUSER" },
{ "2d87821f-5c6d-4d9e-98d7-7ae801030100", "9ee56f2f-558f-4579-9ad7-4a6150e3d822", "ExtTransp", "EXTTRANSP" },
{ "db1d1ac5-905d-46a5-bcf4-ef8a5f3f715c", "3244e9d3-ab0e-45ae-97b6-c8c74f57cf64", "User", "USER" },
{ "7e3dc53b-c152-440f-a49d-6c3a2f6bf6eb", "a0a109e5-ab8e-4e20-9aa8-eba3c429fd12", "Admin", "ADMIN" },
{ "2fcd8455-143a-4ebc-b41c-e9bdf6a0315b", "549b8a8d-ba83-4b79-be88-fde0bd4cc60f", "SuperAdmin", "SUPERADMIN" }
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "DbSetCounts");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "2d87821f-5c6d-4d9e-98d7-7ae801030100");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "2fcd8455-143a-4ebc-b41c-e9bdf6a0315b");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "339a7ac3-4fcd-4baa-bd19-a6a09d1b7c5d");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "47c8d4fb-6925-4ef0-a830-5df33e705d7a");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "7e3dc53b-c152-440f-a49d-6c3a2f6bf6eb");
migrationBuilder.DeleteData(
table: "AspNetRoles",
keyColumn: "Id",
keyValue: "db1d1ac5-905d-46a5-bcf4-ef8a5f3f715c");
migrationBuilder.InsertData(
table: "AspNetRoles",
columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" },
values: new object[,]
{
{ "5287113c-6493-4419-bbc9-2cb2f6455006", "00059b0a-3e8c-406e-a578-2ae40c52435a", "Undef", "UNDEF" },
{ "f27a0416-02cc-4e4c-8983-29cb51eb4f9a", "b58874fc-02b5-4efa-b4d5-61bfda8b7c67", "ExtUser", "EXTUSER" },
{ "00e6b3ed-dd0e-4cd5-8d3d-f88d8ae5e145", "cd1f0ba9-9f42-42f3-8271-1627ef55d36f", "User", "USER" },
{ "5b928219-a530-49c6-be33-f65253865a98", "6de09bee-9a83-416a-90c4-27bb643519f6", "Admin", "ADMIN" },
{ "e9befc87-9732-4c21-b91e-7aea6a289d35", "f2bf6c1c-4043-4344-8b68-c8b2122ab88f", "SuperAdmin", "SUPERADMIN" }
});
}
}
}
@@ -17,6 +17,17 @@ namespace GWMS.User.Migrations
.HasAnnotation("Relational:MaxIdentifierLength", 64)
.HasAnnotation("ProductVersion", "5.0.7");
modelBuilder.Entity("GWMS.Data.DatabaseModels.TableCount", b =>
{
b.Property<int>("Count")
.HasColumnType("int");
b.Property<string>("TableName")
.HasColumnType("longtext");
b.ToTable("DbSetCounts");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
@@ -41,6 +52,50 @@ namespace GWMS.User.Migrations
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles");
b.HasData(
new
{
Id = "339a7ac3-4fcd-4baa-bd19-a6a09d1b7c5d",
ConcurrencyStamp = "3caf0732-df97-4b81-ba2c-9fb51e34532a",
Name = "Undef",
NormalizedName = "UNDEF"
},
new
{
Id = "47c8d4fb-6925-4ef0-a830-5df33e705d7a",
ConcurrencyStamp = "9671ece6-f70a-4ca6-88db-64562e007c72",
Name = "ExtUser",
NormalizedName = "EXTUSER"
},
new
{
Id = "2d87821f-5c6d-4d9e-98d7-7ae801030100",
ConcurrencyStamp = "9ee56f2f-558f-4579-9ad7-4a6150e3d822",
Name = "ExtTransp",
NormalizedName = "EXTTRANSP"
},
new
{
Id = "db1d1ac5-905d-46a5-bcf4-ef8a5f3f715c",
ConcurrencyStamp = "3244e9d3-ab0e-45ae-97b6-c8c74f57cf64",
Name = "User",
NormalizedName = "USER"
},
new
{
Id = "7e3dc53b-c152-440f-a49d-6c3a2f6bf6eb",
ConcurrencyStamp = "a0a109e5-ab8e-4e20-9aa8-eba3c429fd12",
Name = "Admin",
NormalizedName = "ADMIN"
},
new
{
Id = "2fcd8455-143a-4ebc-b41c-e9bdf6a0315b",
ConcurrencyStamp = "549b8a8d-ba83-4b79-be88-fde0bd4cc60f",
Name = "SuperAdmin",
NormalizedName = "SUPERADMIN"
});
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+30
View File
@@ -0,0 +1,30 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GWMS.Data
{
public class RoleConfiguration : IEntityTypeConfiguration<IdentityRole>
{
#region Public Methods
public void Configure(EntityTypeBuilder<IdentityRole> builder)
{
builder.HasData(
new IdentityRole { Name = "Undef", NormalizedName = "UNDEF" },
new IdentityRole { Name = "ExtUser", NormalizedName = "EXTUSER" },
new IdentityRole { Name = "ExtTransp", NormalizedName = "EXTTRANSP" },
new IdentityRole { Name = "User", NormalizedName = "USER" },
new IdentityRole { Name = "Admin", NormalizedName = "ADMIN" },
new IdentityRole { Name = "SuperAdmin", NormalizedName = "SUPERADMIN" }
);
}
#endregion Public Methods
}
}
+25
View File
@@ -0,0 +1,25 @@
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GWMS.Data
{
/// <summary>
/// Classe generalizzaizone identity (user + roles + claims) x gestione semplificata in editing
/// </summary>
public class UserData
{
#region Public Properties
public List<System.Security.Claims.Claim> Claims { get; set; }
public IdentityUser Identity { get; set; }
public List<string> Roles { get; set; }
#endregion Public Properties
}
}
+23
View File
@@ -14,13 +14,29 @@ namespace GWMS.Data
public UserIdentityDbContext()
{
try
{
// se non ci fosse... crea o migra!
Database.Migrate();
}
catch (Exception exc)
{ }
}
public UserIdentityDbContext(DbContextOptions<UserIdentityDbContext> options)
: base(options)
{
#if false
// se non ci fosse... crea!
Database.EnsureCreated();
#endif
try
{
// se non ci fosse... crea o migra!
Database.Migrate();
}
catch (Exception exc)
{ }
}
#endregion Public Constructors
@@ -43,6 +59,13 @@ namespace GWMS.Data
}
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ApplyConfiguration(new RoleConfiguration());
}
#endregion Protected Methods
}
}
+12 -10
View File
@@ -1,10 +1,12 @@
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
+10
View File
@@ -0,0 +1,10 @@
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
@@ -0,0 +1,27 @@
using System;
using GWMS.Data;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
[assembly: HostingStartup(typeof(GWMS.UI.Areas.Identity.IdentityHostingStartup))]
namespace GWMS.UI.Areas.Identity
{
public class IdentityHostingStartup : IHostingStartup
{
#region Public Methods
public void Configure(IWebHostBuilder builder)
{
builder.ConfigureServices((context, services) =>
{
});
}
#endregion Public Methods
}
}
@@ -0,0 +1,10 @@
@page
@model AccessDeniedModel
@{
ViewData["Title"] = "Access denied";
}
<header>
<h1 class="text-danger">@ViewData["Title"]</h1>
<p class="text-danger">You do not have access to this resource.</p>
</header>
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
public class AccessDeniedModel : PageModel
{
#region Public Methods
public void OnGet()
{
}
#endregion Public Methods
}
}
@@ -0,0 +1,21 @@
@page
@model ConfirmEmailModel
@{
ViewData["Title"] = "Conferma Effettuata";
}
<div class="card">
<div class="card-header"><h1>@ViewData["Title"]</h1></div>
<div class="card-body">
<div class="alert alert-success">
<p>L'email è stata confermata! ora puoi effettuare il login all'applicazione</p>
</div>
<div class="card-footer">
<div class="row">
<div class="col-6">
<a title="LogIn" href="Identity/Account/LogIn" class="btn btn-sm btn-success btn-block"><i class="fas fa-sign-in-alt"></i> Login Page</a>
</div>
</div>
</div>
</div>
</div>
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class ConfirmEmailModel : PageModel
{
#region Private Fields
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public ConfirmEmailModel(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
#endregion Public Constructors
#region Public Properties
[TempData]
public string StatusMessage { get; set; }
#endregion Public Properties
#region Public Methods
public async Task<IActionResult> OnGetAsync(string userId, string code)
{
if (userId == null || code == null)
{
return RedirectToPage("/Index");
}
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
return NotFound($"Unable to load user with ID '{userId}'.");
}
code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
var result = await _userManager.ConfirmEmailAsync(user, code);
StatusMessage = result.Succeeded ? "Thank you for confirming your email." : "Error confirming your email.";
return Page();
}
#endregion Public Methods
}
}
@@ -0,0 +1,8 @@
@page
@model ConfirmEmailChangeModel
@{
ViewData["Title"] = "Confirm email change";
}
<h1>@ViewData["Title"]</h1>
<partial name="_StatusMessage" model="Model.StatusMessage" />
@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class ConfirmEmailChangeModel : PageModel
{
#region Private Fields
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public ConfirmEmailChangeModel(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
#endregion Public Constructors
#region Public Properties
[TempData]
public string StatusMessage { get; set; }
#endregion Public Properties
#region Public Methods
public async Task<IActionResult> OnGetAsync(string userId, string email, string code)
{
if (userId == null || email == null || code == null)
{
return RedirectToPage("/Index");
}
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
return NotFound($"Unable to load user with ID '{userId}'.");
}
code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
var result = await _userManager.ChangeEmailAsync(user, email, code);
if (!result.Succeeded)
{
StatusMessage = "Error changing email.";
return Page();
}
// In our UI email and user name are one and the same, so when we update the email
// we need to update the user name.
var setUserNameResult = await _userManager.SetUserNameAsync(user, email);
if (!setUserNameResult.Succeeded)
{
StatusMessage = "Error changing user name.";
return Page();
}
await _signInManager.RefreshSignInAsync(user);
StatusMessage = "Thank you for confirming your email change.";
return Page();
}
#endregion Public Methods
}
}
@@ -0,0 +1,33 @@
@page
@model ExternalLoginModel
@{
ViewData["Title"] = "Register";
}
<h1>@ViewData["Title"]</h1>
<h4 id="external-login-title">Associate your @Model.ProviderDisplayName account.</h4>
<hr />
<p id="external-login-description" class="text-info">
You've successfully authenticated with <strong>@Model.ProviderDisplayName</strong>.
Please enter an email address for this site below and click the Register button to finish
logging in.
</p>
<div class="row">
<div class="col-md-4">
<form asp-page-handler="Confirmation" asp-route-returnUrl="@Model.ReturnUrl" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" class="form-control" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Register</button>
</form>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,192 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class ExternalLoginModel : PageModel
{
#region Private Fields
private readonly IEmailSender _emailSender;
private readonly ILogger<ExternalLoginModel> _logger;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public ExternalLoginModel(
SignInManager<IdentityUser> signInManager,
UserManager<IdentityUser> userManager,
ILogger<ExternalLoginModel> logger,
IEmailSender emailSender)
{
_signInManager = signInManager;
_userManager = userManager;
_logger = logger;
_emailSender = emailSender;
}
#endregion Public Constructors
#region Public Properties
[TempData]
public string ErrorMessage { get; set; }
[BindProperty]
public InputModel Input { get; set; }
public string ProviderDisplayName { get; set; }
public string ReturnUrl { get; set; }
#endregion Public Properties
#region Public Methods
public IActionResult OnGetAsync()
{
return RedirectToPage("./Login");
}
public async Task<IActionResult> OnGetCallbackAsync(string returnUrl = null, string remoteError = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (remoteError != null)
{
ErrorMessage = $"Error from external provider: {remoteError}";
return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
}
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
ErrorMessage = "Error loading external login information.";
return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
}
// Sign in the user with this external login provider if the user already has a login.
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
if (result.Succeeded)
{
_logger.LogInformation("{Name} logged in with {LoginProvider} provider.", info.Principal.Identity.Name, info.LoginProvider);
return LocalRedirect(returnUrl);
}
if (result.IsLockedOut)
{
return RedirectToPage("./Lockout");
}
else
{
// If the user does not have an account, then ask the user to create an account.
ReturnUrl = returnUrl;
ProviderDisplayName = info.ProviderDisplayName;
if (info.Principal.HasClaim(c => c.Type == ClaimTypes.Email))
{
Input = new InputModel
{
Email = info.Principal.FindFirstValue(ClaimTypes.Email)
};
}
return Page();
}
}
public IActionResult OnPost(string provider, string returnUrl = null)
{
// Request a redirect to the external login provider.
var redirectUrl = Url.Page("./ExternalLogin", pageHandler: "Callback", values: new { returnUrl });
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return new ChallengeResult(provider, properties);
}
public async Task<IActionResult> OnPostConfirmationAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
// Get the information about the user from the external login provider
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
ErrorMessage = "Error loading external login information during confirmation.";
return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
}
if (ModelState.IsValid)
{
var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
var result = await _userManager.CreateAsync(user);
if (result.Succeeded)
{
result = await _userManager.AddLoginAsync(user, info);
if (result.Succeeded)
{
_logger.LogInformation("User created an account using {Name} provider.", info.LoginProvider);
var userId = await _userManager.GetUserIdAsync(user);
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = userId, code = code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
// If account confirmation is required, we need to show the link if we don't have a real email sender
if (_userManager.Options.SignIn.RequireConfirmedAccount)
{
return RedirectToPage("./RegisterConfirmation", new { Email = Input.Email });
}
await _signInManager.SignInAsync(user, isPersistent: false, info.LoginProvider);
return LocalRedirect(returnUrl);
}
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
ProviderDisplayName = info.ProviderDisplayName;
ReturnUrl = returnUrl;
return Page();
}
#endregion Public Methods
#region Public Classes
public class InputModel
{
#region Public Properties
[Required]
[EmailAddress]
public string Email { get; set; }
#endregion Public Properties
}
#endregion Public Classes
}
}
@@ -0,0 +1,30 @@
@page
@model ForgotPasswordModel
@{
ViewData["Title"] = "Password dimenticata?";
}
<div class="card">
<div class="card-header"><h1>@ViewData["Title"]</h1></div>
<div class="card-body">
<h4>Inserire l'account email registrato</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" class="form-control" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary btn-block"><i class="fas fa-envelope"></i> Inoltra richiesta reset password</button>
</form>
</div>
</div>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text.Encodings.Web;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class ForgotPasswordModel : PageModel
{
#region Private Fields
private readonly IEmailSender _emailSender;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public ForgotPasswordModel(UserManager<IdentityUser> userManager, IEmailSender emailSender)
{
_userManager = userManager;
_emailSender = emailSender;
}
#endregion Public Constructors
#region Public Properties
[BindProperty]
public InputModel Input { get; set; }
#endregion Public Properties
#region Public Methods
public async Task<IActionResult> OnPostAsync()
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(Input.Email);
if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
{
// Don't reveal that the user does not exist or is not confirmed
return RedirectToPage("./ForgotPasswordConfirmation");
}
// For more information on how to enable account confirmation and password reset please
// visit https://go.microsoft.com/fwlink/?LinkID=532713
var code = await _userManager.GeneratePasswordResetTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ResetPassword",
pageHandler: null,
values: new { area = "Identity", code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(
Input.Email,
"Reset Password",
$"Please reset your password by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
return RedirectToPage("./ForgotPasswordConfirmation");
}
return Page();
}
#endregion Public Methods
#region Public Classes
public class InputModel
{
#region Public Properties
[Required]
[EmailAddress]
public string Email { get; set; }
#endregion Public Properties
}
#endregion Public Classes
}
}
@@ -0,0 +1,21 @@
@page
@model ForgotPasswordConfirmation
@{
ViewData["Title"] = "Password dimenticata";
}
<div class="card">
<div class="card-header"><h1>@ViewData["Title"]</h1></div>
<div class="card-body">
<div class="row">
<div class="col-md-12">
<p>
Prego verificare l'account email per le istruzioni relative alla reimpostazione della password.
</p>
</div>
<div class="col-md-4">
<a title="LogIn" href="Identity/Account/LogIn" class="btn btn-primary btn-block"><i class="fas fa-sign-in-alt"></i> Login Page</a>
</div>
</div>
</div>
</div>
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class ForgotPasswordConfirmation : PageModel
{
#region Public Methods
public void OnGet()
{
}
#endregion Public Methods
}
}
@@ -0,0 +1,10 @@
@page
@model LockoutModel
@{
ViewData["Title"] = "Locked out";
}
<header>
<h1 class="text-danger">@ViewData["Title"]</h1>
<p class="text-danger">This account has been locked out, please try again later.</p>
</header>
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class LockoutModel : PageModel
{
#region Public Methods
public void OnGet()
{
}
#endregion Public Methods
}
}
@@ -1,15 +1,40 @@
@page
@using Microsoft.AspNetCore.Identity
@attribute [IgnoreAntiforgeryToken]
@inject SignInManager<IdentityUser> SignInManager
@functions {
public async Task<IActionResult> OnPost()
{
if (SignInManager.IsSignedIn(User))
{
await SignInManager.SignOutAsync();
}
return Redirect("~/");
}
@model LogoutModel
@{
ViewData["Title"] = "Log out";
}
<div class="card">
<div class="card-header"><h1>@ViewData["Title"]</h1></div>
<div class="card-body">
@{
if (User.Identity.IsAuthenticated)
{
<form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="@Url.Page("/", new { area = "" })" method="post">
<div class="row">
<div class="col-12">
<p>Premendo sul pulsante effettuerai il logout dal sistema.</p>
</div>
<div class="col-6">
<button type="submit" class="nav-link btn btn-warning"><i class="fas fa-sign-out-alt"></i> Clicca per Logout</button>
</div>
</div>
</form>
}
else
{
<div class="row">
<div class="col-12">
<p>Disconnesisone effettuata.</p>
</div>
<div class="col-6">
<a title="Home" href="~/" class="btn btn-sm btn-primary btn-block"><i class="fas fa-home"></i> Home Page</a>
</div>
<div class="col-6">
<a title="LogIn" href="Identity/Account/LogIn" class="btn btn-sm btn-success btn-block"><i class="fas fa-sign-in-alt"></i> Login Page</a>
</div>
</div>
}
}
</div>
</div>
@@ -0,0 +1,90 @@
@page
@model LoginModel
@{
ViewData["Title"] = "Log in";
}
<div class="card">
<div class="card-header"><h1>@ViewData["Title"]</h1></div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<section>
<form id="account" method="post">
<h4>Effettuare login con l'account registrato.</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" class="form-control" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Password"></label>
<input asp-for="Input.Password" class="form-control" />
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
<div class="form-group">
<div class="checkbox">
<label asp-for="Input.RememberMe">
<input asp-for="Input.RememberMe" />
@Html.DisplayNameFor(m => m.Input.RememberMe)
</label>
</div>
</div>
<div class="form-row">
<div class="col">
<button type="submit" class="btn btn-block btn-primary"><i class="fas fa-sign-in-alt"></i> Log in</button>
</div>
<div class="col">
<a asp-page="./Register" class="btn btn-block btn-outline-primary" asp-route-returnUrl="@Model.ReturnUrl"><i class="fas fa-edit"></i> Registra account</a>
</div>
</div>
<div class="form-row mt-2">
<div class="col">
<a id="forgot-password" class="btn btn-block btn-outline-info" asp-page="./ForgotPassword"><i class="far fa-life-ring"></i> Password dimenticata?</a>
</div>
<div class="col">
<a id="resend-confirmation" class="btn btn-block btn-outline-dark" asp-page="./ResendEmailConfirmation"><i class="far fa-envelope"></i> (Re)Invia email conferma</a>
</div>
</div>
</form>
</section>
</div>
@*<div class="col-md-6 col-md-offset-2">
<section>
<h4>Use another service to log in.</h4>
<hr />
@{
if ((Model.ExternalLogins?.Count ?? 0) == 0)
{
<div>
<p>
There are no external authentication services configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
for details on setting up this ASP.NET application to support logging in via external services.
</p>
</div>
}
else
{
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
<div>
<p>
@foreach (var provider in Model.ExternalLogins)
{
<button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
}
</p>
</div>
</form>
}
}
</section>
</div>*@
</div>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,182 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class LoginModel : PageModel
{
#region Private Fields
private readonly ILogger<LoginModel> _logger;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public LoginModel(SignInManager<IdentityUser> signInManager,
ILogger<LoginModel> logger,
UserManager<IdentityUser> userManager)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
}
#endregion Public Constructors
#region Public Properties
[TempData]
public string ErrorMessage { get; set; }
public IList<AuthenticationScheme> ExternalLogins { get; set; }
[BindProperty]
public InputModel Input { get; set; }
public string ReturnUrl { get; set; }
#endregion Public Properties
#region Private Methods
private async Task CheckSuperAdmin()
{
// se non ci fosse --> creo samuele come superadmin
string superUser = "samuele@steamware.net";
string superPwd = "viaDante16!";
string ADMIN_ROLE = "SuperAdmin";
var user = await _userManager.FindByEmailAsync(superUser);
if (user == null)
{
// Insert new user
var NewUser =
new IdentityUser
{
UserName = superUser,
Email = superUser,
EmailConfirmed = true
};
var CreateResult = await _userManager.CreateAsync(NewUser, superPwd);
if (CreateResult.Succeeded)
{
user = await _userManager.FindByEmailAsync(superUser);
}
}
// verifico ruoli...
if (user != null)
{
bool needCreate = true;
// Gestione salvataggio ruoli... SE VARIATO...
var UserRoles = await _userManager.GetRolesAsync(user);
if (UserRoles != null && UserRoles.Count > 0)
{
var oldRole = UserRoles.Where(x => x == ADMIN_ROLE).FirstOrDefault();
needCreate = (oldRole == null);
}
if (needCreate)
{
// aggiungo a ruolo admin
await _userManager.AddToRoleAsync(user, ADMIN_ROLE);
}
}
}
#endregion Private Methods
#region Public Methods
public async Task OnGetAsync(string returnUrl = null)
{
await CheckSuperAdmin();
if (!string.IsNullOrEmpty(ErrorMessage))
{
ModelState.AddModelError(string.Empty, ErrorMessage);
}
returnUrl ??= Url.Content("~/");
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
ReturnUrl = returnUrl;
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl ??= Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning("User account locked out.");
return RedirectToPage("./Lockout");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return Page();
}
}
// If we got this far, something failed, redisplay form
return Page();
}
#endregion Public Methods
#region Public Classes
public class InputModel
{
#region Public Properties
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
#endregion Public Properties
}
#endregion Public Classes
}
}
@@ -0,0 +1,41 @@
@page
@model LoginWith2faModel
@{
ViewData["Title"] = "Two-factor authentication";
}
<h1>@ViewData["Title"]</h1>
<hr />
<p>Your login is protected with an authenticator app. Enter your authenticator code below.</p>
<div class="row">
<div class="col-md-4">
<form method="post" asp-route-returnUrl="@Model.ReturnUrl">
<input asp-for="RememberMe" type="hidden" />
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.TwoFactorCode"></label>
<input asp-for="Input.TwoFactorCode" class="form-control" autocomplete="off" />
<span asp-validation-for="Input.TwoFactorCode" class="text-danger"></span>
</div>
<div class="form-group">
<div class="checkbox">
<label asp-for="Input.RememberMachine">
<input asp-for="Input.RememberMachine" />
@Html.DisplayNameFor(m => m.Input.RememberMachine)
</label>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Log in</button>
</div>
</form>
</div>
</div>
<p>
Don't have access to your authenticator device? You can
<a id="recovery-code-login" asp-page="./LoginWithRecoveryCode" asp-route-returnUrl="@Model.ReturnUrl">log in with a recovery code</a>.
</p>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,122 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class LoginWith2faModel : PageModel
{
#region Private Fields
private readonly ILogger<LoginWith2faModel> _logger;
private readonly SignInManager<IdentityUser> _signInManager;
#endregion Private Fields
#region Public Constructors
public LoginWith2faModel(SignInManager<IdentityUser> signInManager, ILogger<LoginWith2faModel> logger)
{
_signInManager = signInManager;
_logger = logger;
}
#endregion Public Constructors
#region Public Properties
[BindProperty]
public InputModel Input { get; set; }
public bool RememberMe { get; set; }
public string ReturnUrl { get; set; }
#endregion Public Properties
#region Public Methods
public async Task<IActionResult> OnGetAsync(bool rememberMe, string returnUrl = null)
{
// Ensure the user has gone through the username & password screen first
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
throw new InvalidOperationException($"Unable to load two-factor authentication user.");
}
ReturnUrl = returnUrl;
RememberMe = rememberMe;
return Page();
}
public async Task<IActionResult> OnPostAsync(bool rememberMe, string returnUrl = null)
{
if (!ModelState.IsValid)
{
return Page();
}
returnUrl = returnUrl ?? Url.Content("~/");
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
throw new InvalidOperationException($"Unable to load two-factor authentication user.");
}
var authenticatorCode = Input.TwoFactorCode.Replace(" ", string.Empty).Replace("-", string.Empty);
var result = await _signInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, rememberMe, Input.RememberMachine);
if (result.Succeeded)
{
_logger.LogInformation("User with ID '{UserId}' logged in with 2fa.", user.Id);
return LocalRedirect(returnUrl);
}
else if (result.IsLockedOut)
{
_logger.LogWarning("User with ID '{UserId}' account locked out.", user.Id);
return RedirectToPage("./Lockout");
}
else
{
_logger.LogWarning("Invalid authenticator code entered for user with ID '{UserId}'.", user.Id);
ModelState.AddModelError(string.Empty, "Invalid authenticator code.");
return Page();
}
}
#endregion Public Methods
#region Public Classes
public class InputModel
{
#region Public Properties
[Display(Name = "Remember this machine")]
public bool RememberMachine { get; set; }
[Required]
[StringLength(7, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Text)]
[Display(Name = "Authenticator code")]
public string TwoFactorCode { get; set; }
#endregion Public Properties
}
#endregion Public Classes
}
}
@@ -0,0 +1,29 @@
@page
@model LoginWithRecoveryCodeModel
@{
ViewData["Title"] = "Recovery code verification";
}
<h1>@ViewData["Title"]</h1>
<hr />
<p>
You have requested to log in with a recovery code. This login will not be remembered until you provide
an authenticator app code at log in or disable 2FA and log in again.
</p>
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.RecoveryCode"></label>
<input asp-for="Input.RecoveryCode" class="form-control" autocomplete="off" />
<span asp-validation-for="Input.RecoveryCode" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Log in</button>
</form>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class LoginWithRecoveryCodeModel : PageModel
{
#region Private Fields
private readonly ILogger<LoginWithRecoveryCodeModel> _logger;
private readonly SignInManager<IdentityUser> _signInManager;
#endregion Private Fields
#region Public Constructors
public LoginWithRecoveryCodeModel(SignInManager<IdentityUser> signInManager, ILogger<LoginWithRecoveryCodeModel> logger)
{
_signInManager = signInManager;
_logger = logger;
}
#endregion Public Constructors
#region Public Properties
[BindProperty]
public InputModel Input { get; set; }
public string ReturnUrl { get; set; }
#endregion Public Properties
#region Public Methods
public async Task<IActionResult> OnGetAsync(string returnUrl = null)
{
// Ensure the user has gone through the username & password screen first
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
throw new InvalidOperationException($"Unable to load two-factor authentication user.");
}
ReturnUrl = returnUrl;
return Page();
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
if (!ModelState.IsValid)
{
return Page();
}
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
throw new InvalidOperationException($"Unable to load two-factor authentication user.");
}
var recoveryCode = Input.RecoveryCode.Replace(" ", string.Empty);
var result = await _signInManager.TwoFactorRecoveryCodeSignInAsync(recoveryCode);
if (result.Succeeded)
{
_logger.LogInformation("User with ID '{UserId}' logged in with a recovery code.", user.Id);
return LocalRedirect(returnUrl ?? Url.Content("~/"));
}
if (result.IsLockedOut)
{
_logger.LogWarning("User with ID '{UserId}' account locked out.", user.Id);
return RedirectToPage("./Lockout");
}
else
{
_logger.LogWarning("Invalid recovery code entered for user with ID '{UserId}' ", user.Id);
ModelState.AddModelError(string.Empty, "Invalid recovery code entered.");
return Page();
}
}
#endregion Public Methods
#region Public Classes
public class InputModel
{
#region Public Properties
[BindProperty]
[Required]
[DataType(DataType.Text)]
[Display(Name = "Recovery Code")]
public string RecoveryCode { get; set; }
#endregion Public Properties
}
#endregion Public Classes
}
}
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class LogoutModel : PageModel
{
#region Private Fields
private readonly ILogger<LogoutModel> _logger;
private readonly SignInManager<IdentityUser> _signInManager;
#endregion Private Fields
#region Public Constructors
public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger)
{
_signInManager = signInManager;
_logger = logger;
}
#endregion Public Constructors
#region Public Methods
public void OnGet()
{
}
public async Task<IActionResult> OnPost(string returnUrl = null)
{
await _signInManager.SignOutAsync();
_logger.LogInformation("User logged out.");
if (returnUrl != null)
{
return LocalRedirect(returnUrl);
}
else
{
return RedirectToPage();
}
}
#endregion Public Methods
}
}
@@ -0,0 +1,36 @@
@page
@model ChangePasswordModel
@{
ViewData["Title"] = "Change password";
ViewData["ActivePage"] = ManageNavPages.ChangePassword;
}
<h4>@ViewData["Title"]</h4>
<partial name="_StatusMessage" for="StatusMessage" />
<div class="row">
<div class="col-md-6">
<form id="change-password-form" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.OldPassword"></label>
<input asp-for="Input.OldPassword" class="form-control" />
<span asp-validation-for="Input.OldPassword" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.NewPassword"></label>
<input asp-for="Input.NewPassword" class="form-control" />
<span asp-validation-for="Input.NewPassword" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.ConfirmPassword"></label>
<input asp-for="Input.ConfirmPassword" class="form-control" />
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Update password</button>
</form>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account.Manage
{
public class ChangePasswordModel : PageModel
{
#region Private Fields
private readonly ILogger<ChangePasswordModel> _logger;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public ChangePasswordModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
ILogger<ChangePasswordModel> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
}
#endregion Public Constructors
#region Public Properties
[BindProperty]
public InputModel Input { get; set; }
[TempData]
public string StatusMessage { get; set; }
#endregion Public Properties
#region Public Methods
public async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
var hasPassword = await _userManager.HasPasswordAsync(user);
if (!hasPassword)
{
return RedirectToPage("./SetPassword");
}
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
var changePasswordResult = await _userManager.ChangePasswordAsync(user, Input.OldPassword, Input.NewPassword);
if (!changePasswordResult.Succeeded)
{
foreach (var error in changePasswordResult.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
return Page();
}
await _signInManager.RefreshSignInAsync(user);
_logger.LogInformation("User changed their password successfully.");
StatusMessage = "Your password has been changed.";
return RedirectToPage();
}
#endregion Public Methods
#region Public Classes
public class InputModel
{
#region Public Properties
[DataType(DataType.Password)]
[Display(Name = "Confirm new password")]
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "New password")]
public string NewPassword { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Current password")]
public string OldPassword { get; set; }
#endregion Public Properties
}
#endregion Public Classes
}
}
@@ -0,0 +1,33 @@
@page
@model DeletePersonalDataModel
@{
ViewData["Title"] = "Delete Personal Data";
ViewData["ActivePage"] = ManageNavPages.PersonalData;
}
<h4>@ViewData["Title"]</h4>
<div class="alert alert-warning" role="alert">
<p>
<strong>Deleting this data will permanently remove your account, and this cannot be recovered.</strong>
</p>
</div>
<div>
<form id="delete-user" method="post" class="form-group">
<div asp-validation-summary="All" class="text-danger"></div>
@if (Model.RequirePassword)
{
<div class="form-group">
<label asp-for="Input.Password"></label>
<input asp-for="Input.Password" class="form-control" />
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
}
<button class="btn btn-danger" type="submit">Delete data and close my account</button>
</form>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,107 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account.Manage
{
public class DeletePersonalDataModel : PageModel
{
#region Private Fields
private readonly ILogger<DeletePersonalDataModel> _logger;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public DeletePersonalDataModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
ILogger<DeletePersonalDataModel> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
}
#endregion Public Constructors
#region Public Properties
[BindProperty]
public InputModel Input { get; set; }
public bool RequirePassword { get; set; }
#endregion Public Properties
#region Public Methods
public async Task<IActionResult> OnGet()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
RequirePassword = await _userManager.HasPasswordAsync(user);
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
RequirePassword = await _userManager.HasPasswordAsync(user);
if (RequirePassword)
{
if (!await _userManager.CheckPasswordAsync(user, Input.Password))
{
ModelState.AddModelError(string.Empty, "Incorrect password.");
return Page();
}
}
var result = await _userManager.DeleteAsync(user);
var userId = await _userManager.GetUserIdAsync(user);
if (!result.Succeeded)
{
throw new InvalidOperationException($"Unexpected error occurred deleting user with ID '{userId}'.");
}
await _signInManager.SignOutAsync();
_logger.LogInformation("User with ID '{UserId}' deleted themselves.", userId);
return Redirect("~/");
}
#endregion Public Methods
#region Public Classes
public class InputModel
{
#region Public Properties
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
#endregion Public Properties
}
#endregion Public Classes
}
}
@@ -0,0 +1,25 @@
@page
@model Disable2faModel
@{
ViewData["Title"] = "Disable two-factor authentication (2FA)";
ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication;
}
<partial name="_StatusMessage" for="StatusMessage" />
<h2>@ViewData["Title"]</h2>
<div class="alert alert-warning" role="alert">
<p>
<strong>This action only disables 2FA.</strong>
</p>
<p>
Disabling 2FA does not change the keys used in authenticator apps. If you wish to change the key
used in an authenticator app you should <a asp-page="./ResetAuthenticator">reset your authenticator keys.</a>
</p>
</div>
<div>
<form method="post" class="form-group">
<button class="btn btn-danger" type="submit">Disable 2FA</button>
</form>
</div>
@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account.Manage
{
public class Disable2faModel : PageModel
{
#region Private Fields
private readonly ILogger<Disable2faModel> _logger;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public Disable2faModel(
UserManager<IdentityUser> userManager,
ILogger<Disable2faModel> logger)
{
_userManager = userManager;
_logger = logger;
}
#endregion Public Constructors
#region Public Properties
[TempData]
public string StatusMessage { get; set; }
#endregion Public Properties
#region Public Methods
public async Task<IActionResult> OnGet()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
if (!await _userManager.GetTwoFactorEnabledAsync(user))
{
throw new InvalidOperationException($"Cannot disable 2FA for user with ID '{_userManager.GetUserId(User)}' as it's not currently enabled.");
}
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
var disable2faResult = await _userManager.SetTwoFactorEnabledAsync(user, false);
if (!disable2faResult.Succeeded)
{
throw new InvalidOperationException($"Unexpected error occurred disabling 2FA for user with ID '{_userManager.GetUserId(User)}'.");
}
_logger.LogInformation("User with ID '{UserId}' has disabled 2fa.", _userManager.GetUserId(User));
StatusMessage = "2fa has been disabled. You can reenable 2fa when you setup an authenticator app";
return RedirectToPage("./TwoFactorAuthentication");
}
#endregion Public Methods
}
}
@@ -0,0 +1,12 @@
@page
@model DownloadPersonalDataModel
@{
ViewData["Title"] = "Download Your Data";
ViewData["ActivePage"] = ManageNavPages.PersonalData;
}
<h4>@ViewData["Title"]</h4>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account.Manage
{
public class DownloadPersonalDataModel : PageModel
{
#region Private Fields
private readonly ILogger<DownloadPersonalDataModel> _logger;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public DownloadPersonalDataModel(
UserManager<IdentityUser> userManager,
ILogger<DownloadPersonalDataModel> logger)
{
_userManager = userManager;
_logger = logger;
}
#endregion Public Constructors
#region Public Methods
public async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
_logger.LogInformation("User with ID '{UserId}' asked for their personal data.", _userManager.GetUserId(User));
// Only include personal data for download
var personalData = new Dictionary<string, string>();
var personalDataProps = typeof(IdentityUser).GetProperties().Where(
prop => Attribute.IsDefined(prop, typeof(PersonalDataAttribute)));
foreach (var p in personalDataProps)
{
personalData.Add(p.Name, p.GetValue(user)?.ToString() ?? "null");
}
var logins = await _userManager.GetLoginsAsync(user);
foreach (var l in logins)
{
personalData.Add($"{l.LoginProvider} external login provider key", l.ProviderKey);
}
Response.Headers.Add("Content-Disposition", "attachment; filename=PersonalData.json");
return new FileContentResult(JsonSerializer.SerializeToUtf8Bytes(personalData), "application/json");
}
#endregion Public Methods
}
}
@@ -0,0 +1,43 @@
@page
@model EmailModel
@{
ViewData["Title"] = "Manage Email";
ViewData["ActivePage"] = ManageNavPages.Email;
}
<h4>@ViewData["Title"]</h4>
<partial name="_StatusMessage" model="Model.StatusMessage" />
<div class="row">
<div class="col-md-6">
<form id="email-form" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Email"></label>
@if (Model.IsEmailConfirmed)
{
<div class="input-group">
<input asp-for="Email" class="form-control" disabled />
<div class="input-group-append">
<span class="input-group-text text-success font-weight-bold">✓</span>
</div>
</div>
}
else
{
<input asp-for="Email" class="form-control" disabled />
<button id="email-verification" type="submit" asp-page-handler="SendVerificationEmail" class="btn btn-link">Send verification email</button>
}
</div>
<div class="form-group">
<label asp-for="Input.NewEmail"></label>
<input asp-for="Input.NewEmail" class="form-control" />
<span asp-validation-for="Input.NewEmail" class="text-danger"></span>
</div>
<button id="change-email-button" type="submit" asp-page-handler="ChangeEmail" class="btn btn-primary">Change email</button>
</form>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
using System.Text.Encodings.Web;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
namespace GWMS.UI.Areas.Identity.Pages.Account.Manage
{
public partial class EmailModel : PageModel
{
#region Private Fields
private readonly IEmailSender _emailSender;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public EmailModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
IEmailSender emailSender)
{
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
}
#endregion Public Constructors
#region Public Properties
public string Email { get; set; }
[BindProperty]
public InputModel Input { get; set; }
public bool IsEmailConfirmed { get; set; }
[TempData]
public string StatusMessage { get; set; }
public string Username { get; set; }
#endregion Public Properties
#region Private Methods
private async Task LoadAsync(IdentityUser user)
{
var email = await _userManager.GetEmailAsync(user);
Email = email;
Input = new InputModel
{
NewEmail = email,
};
IsEmailConfirmed = await _userManager.IsEmailConfirmedAsync(user);
}
#endregion Private Methods
#region Public Methods
public async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
await LoadAsync(user);
return Page();
}
public async Task<IActionResult> OnPostChangeEmailAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
if (!ModelState.IsValid)
{
await LoadAsync(user);
return Page();
}
var email = await _userManager.GetEmailAsync(user);
if (Input.NewEmail != email)
{
var userId = await _userManager.GetUserIdAsync(user);
var code = await _userManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ConfirmEmailChange",
pageHandler: null,
values: new { userId = userId, email = Input.NewEmail, code = code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(
Input.NewEmail,
"Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
StatusMessage = "Confirmation link to change email sent. Please check your email.";
return RedirectToPage();
}
StatusMessage = "Your email is unchanged.";
return RedirectToPage();
}
public async Task<IActionResult> OnPostSendVerificationEmailAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
if (!ModelState.IsValid)
{
await LoadAsync(user);
return Page();
}
var userId = await _userManager.GetUserIdAsync(user);
var email = await _userManager.GetEmailAsync(user);
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = userId, code = code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(
email,
"Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
StatusMessage = "Verification email sent. Please check your email.";
return RedirectToPage();
}
#endregion Public Methods
#region Public Classes
public class InputModel
{
#region Public Properties
[Required]
[EmailAddress]
[Display(Name = "New email")]
public string NewEmail { get; set; }
#endregion Public Properties
}
#endregion Public Classes
}
}
@@ -0,0 +1,63 @@
@page
@model EnableAuthenticatorModel
@{
ViewData["Title"] = "Configure authenticator app";
ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication;
}
<partial name="_StatusMessage" for="StatusMessage" />
<h4>@ViewData["Title"]</h4>
<div>
<p>To use an authenticator app go through the following steps:</p>
<ol class="list">
<li>
<p>
Download a two-factor authenticator app like Microsoft Authenticator for
<a href="https://go.microsoft.com/fwlink/?Linkid=825072">Android</a> and
<a href="https://go.microsoft.com/fwlink/?Linkid=825073">iOS</a> or
Google Authenticator for
<a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&amp;hl=en">Android</a> and
<a href="https://itunes.apple.com/us/app/google-authenticator/id388497605?mt=8">iOS</a>.
</p>
</li>
<li>
<p>Scan the QR Code or enter this key <kbd>@Model.SharedKey</kbd> into your two factor authenticator app. Spaces and casing do not matter.</p>
@*<div class="alert alert-info">Learn how to <a href="https://go.microsoft.com/fwlink/?Linkid=852423">enable QR code generation</a>.</div>*@
<div id="qrCode"></div>
<div id="qrCodeData" data-url="@Html.Raw(@Model.AuthenticatorUri)"></div>
</li>
<li>
<p>
Once you have scanned the QR code or input the key above, your two factor authentication app will provide you
with a unique code. Enter the code in the confirmation box below.
</p>
<div class="row">
<div class="col-md-6">
<form id="send-code" method="post">
<div class="form-group">
<label asp-for="Input.Code" class="control-label">Verification Code</label>
<input asp-for="Input.Code" class="form-control" autocomplete="off" />
<span asp-validation-for="Input.Code" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Verify</button>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
</form>
</div>
</div>
</li>
</ol>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
<script type="text/javascript" src="~/lib/qrcode.js"></script>
<script type="text/javascript">
new QRCode(document.getElementById("qrCode"),
{
text: "@Html.Raw(Model.AuthenticatorUri)",
width: 150,
height: 150
});
</script>
}
@@ -0,0 +1,183 @@
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using System.Text;
using System.Text.Encodings.Web;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account.Manage
{
public class EnableAuthenticatorModel : PageModel
{
#region Private Fields
private const string AuthenticatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6";
private readonly ILogger<EnableAuthenticatorModel> _logger;
private readonly UrlEncoder _urlEncoder;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public EnableAuthenticatorModel(
UserManager<IdentityUser> userManager,
ILogger<EnableAuthenticatorModel> logger,
UrlEncoder urlEncoder)
{
_userManager = userManager;
_logger = logger;
_urlEncoder = urlEncoder;
}
#endregion Public Constructors
#region Public Properties
public string AuthenticatorUri { get; set; }
[BindProperty]
public InputModel Input { get; set; }
[TempData]
public string[] RecoveryCodes { get; set; }
public string SharedKey { get; set; }
[TempData]
public string StatusMessage { get; set; }
#endregion Public Properties
#region Private Methods
private string FormatKey(string unformattedKey)
{
var result = new StringBuilder();
int currentPosition = 0;
while (currentPosition + 4 < unformattedKey.Length)
{
result.Append(unformattedKey.Substring(currentPosition, 4)).Append(" ");
currentPosition += 4;
}
if (currentPosition < unformattedKey.Length)
{
result.Append(unformattedKey.Substring(currentPosition));
}
return result.ToString().ToLowerInvariant();
}
private string GenerateQrCodeUri(string email, string unformattedKey)
{
return string.Format(
AuthenticatorUriFormat,
_urlEncoder.Encode("GWMS.UI"),
_urlEncoder.Encode(email),
unformattedKey);
}
private async Task LoadSharedKeyAndQrCodeUriAsync(IdentityUser user)
{
// Load the authenticator key & QR code URI to display on the form
var unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user);
if (string.IsNullOrEmpty(unformattedKey))
{
await _userManager.ResetAuthenticatorKeyAsync(user);
unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user);
}
SharedKey = FormatKey(unformattedKey);
var email = await _userManager.GetEmailAsync(user);
AuthenticatorUri = GenerateQrCodeUri(email, unformattedKey);
}
#endregion Private Methods
#region Public Methods
public async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
await LoadSharedKeyAndQrCodeUriAsync(user);
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
if (!ModelState.IsValid)
{
await LoadSharedKeyAndQrCodeUriAsync(user);
return Page();
}
// Strip spaces and hypens
var verificationCode = Input.Code.Replace(" ", string.Empty).Replace("-", string.Empty);
var is2faTokenValid = await _userManager.VerifyTwoFactorTokenAsync(
user, _userManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode);
if (!is2faTokenValid)
{
ModelState.AddModelError("Input.Code", "Verification code is invalid.");
await LoadSharedKeyAndQrCodeUriAsync(user);
return Page();
}
await _userManager.SetTwoFactorEnabledAsync(user, true);
var userId = await _userManager.GetUserIdAsync(user);
_logger.LogInformation("User with ID '{UserId}' has enabled 2FA with an authenticator app.", userId);
StatusMessage = "Your authenticator app has been verified.";
if (await _userManager.CountRecoveryCodesAsync(user) == 0)
{
var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10);
RecoveryCodes = recoveryCodes.ToArray();
return RedirectToPage("./ShowRecoveryCodes");
}
else
{
return RedirectToPage("./TwoFactorAuthentication");
}
}
#endregion Public Methods
#region Public Classes
public class InputModel
{
#region Public Properties
[Required]
[StringLength(7, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Text)]
[Display(Name = "Verification Code")]
public string Code { get; set; }
#endregion Public Properties
}
#endregion Public Classes
}
}
@@ -0,0 +1,53 @@
@page
@model ExternalLoginsModel
@{
ViewData["Title"] = "Manage your external logins";
ViewData["ActivePage"] = ManageNavPages.ExternalLogins;
}
<partial name="_StatusMessage" for="StatusMessage" />
@if (Model.CurrentLogins?.Count > 0)
{
<h4>Registered Logins</h4>
<table class="table">
<tbody>
@foreach (var login in Model.CurrentLogins)
{
<tr>
<td id="@($"login-provider-{login.LoginProvider}")">@login.ProviderDisplayName</td>
<td>
@if (Model.ShowRemoveButton)
{
<form id="@($"remove-login-{login.LoginProvider}")" asp-page-handler="RemoveLogin" method="post">
<div>
<input asp-for="@login.LoginProvider" name="LoginProvider" type="hidden" />
<input asp-for="@login.ProviderKey" name="ProviderKey" type="hidden" />
<button type="submit" class="btn btn-primary" title="Remove this @login.ProviderDisplayName login from your account">Remove</button>
</div>
</form>
}
else
{
@: &nbsp;
}
</td>
</tr>
}
</tbody>
</table>
}
@if (Model.OtherLogins?.Count > 0)
{
<h4>Add another service to log in.</h4>
<hr />
<form id="link-login-form" asp-page-handler="LinkLogin" method="post" class="form-horizontal">
<div id="socialLoginList">
<p>
@foreach (var provider in Model.OtherLogins)
{
<button id="@($"link-login-button-{provider.Name}")" type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
}
</p>
</div>
</form>
}
@@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace GWMS.UI.Areas.Identity.Pages.Account.Manage
{
public class ExternalLoginsModel : PageModel
{
#region Private Fields
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public ExternalLoginsModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
#endregion Public Constructors
#region Public Properties
public IList<UserLoginInfo> CurrentLogins { get; set; }
public IList<AuthenticationScheme> OtherLogins { get; set; }
public bool ShowRemoveButton { get; set; }
[TempData]
public string StatusMessage { get; set; }
#endregion Public Properties
#region Public Methods
public async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID 'user.Id'.");
}
CurrentLogins = await _userManager.GetLoginsAsync(user);
OtherLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync())
.Where(auth => CurrentLogins.All(ul => auth.Name != ul.LoginProvider))
.ToList();
ShowRemoveButton = user.PasswordHash != null || CurrentLogins.Count > 1;
return Page();
}
public async Task<IActionResult> OnGetLinkLoginCallbackAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID 'user.Id'.");
}
var info = await _signInManager.GetExternalLoginInfoAsync(user.Id);
if (info == null)
{
throw new InvalidOperationException($"Unexpected error occurred loading external login info for user with ID '{user.Id}'.");
}
var result = await _userManager.AddLoginAsync(user, info);
if (!result.Succeeded)
{
StatusMessage = "The external login was not added. External logins can only be associated with one account.";
return RedirectToPage();
}
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
StatusMessage = "The external login was added.";
return RedirectToPage();
}
public async Task<IActionResult> OnPostLinkLoginAsync(string provider)
{
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
// Request a redirect to the external login provider to link a login for the current user
var redirectUrl = Url.Page("./ExternalLogins", pageHandler: "LinkLoginCallback");
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User));
return new ChallengeResult(provider, properties);
}
public async Task<IActionResult> OnPostRemoveLoginAsync(string loginProvider, string providerKey)
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID 'user.Id'.");
}
var result = await _userManager.RemoveLoginAsync(user, loginProvider, providerKey);
if (!result.Succeeded)
{
StatusMessage = "The external login was not removed.";
return RedirectToPage();
}
await _signInManager.RefreshSignInAsync(user);
StatusMessage = "The external login was removed.";
return RedirectToPage();
}
#endregion Public Methods
}
}
@@ -0,0 +1,27 @@
@page
@model GenerateRecoveryCodesModel
@{
ViewData["Title"] = "Generate two-factor authentication (2FA) recovery codes";
ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication;
}
<partial name="_StatusMessage" for="StatusMessage" />
<h4>@ViewData["Title"]</h4>
<div class="alert alert-warning" role="alert">
<p>
<span class="glyphicon glyphicon-warning-sign"></span>
<strong>Put these codes in a safe place.</strong>
</p>
<p>
If you lose your device and don't have the recovery codes you will lose access to your account.
</p>
<p>
Generating new recovery codes does not change the keys used in authenticator apps. If you wish to change the key
used in an authenticator app you should <a asp-page="./ResetAuthenticator">reset your authenticator keys.</a>
</p>
</div>
<div>
<form method="post" class="form-group">
<button class="btn btn-danger" type="submit">Generate Recovery Codes</button>
</form>
</div>
@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account.Manage
{
public class GenerateRecoveryCodesModel : PageModel
{
#region Private Fields
private readonly ILogger<GenerateRecoveryCodesModel> _logger;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public GenerateRecoveryCodesModel(
UserManager<IdentityUser> userManager,
ILogger<GenerateRecoveryCodesModel> logger)
{
_userManager = userManager;
_logger = logger;
}
#endregion Public Constructors
#region Public Properties
[TempData]
public string[] RecoveryCodes { get; set; }
[TempData]
public string StatusMessage { get; set; }
#endregion Public Properties
#region Public Methods
public async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
var isTwoFactorEnabled = await _userManager.GetTwoFactorEnabledAsync(user);
if (!isTwoFactorEnabled)
{
var userId = await _userManager.GetUserIdAsync(user);
throw new InvalidOperationException($"Cannot generate recovery codes for user with ID '{userId}' because they do not have 2FA enabled.");
}
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
var isTwoFactorEnabled = await _userManager.GetTwoFactorEnabledAsync(user);
var userId = await _userManager.GetUserIdAsync(user);
if (!isTwoFactorEnabled)
{
throw new InvalidOperationException($"Cannot generate recovery codes for user with ID '{userId}' as they do not have 2FA enabled.");
}
var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10);
RecoveryCodes = recoveryCodes.ToArray();
_logger.LogInformation("User with ID '{UserId}' has generated new 2FA recovery codes.", userId);
StatusMessage = "You have generated new recovery codes.";
return RedirectToPage("./ShowRecoveryCodes");
}
#endregion Public Methods
}
}
@@ -0,0 +1,30 @@
@page
@model IndexModel
@{
ViewData["Title"] = "Profile";
ViewData["ActivePage"] = ManageNavPages.Index;
}
<h4>@ViewData["Title"]</h4>
<partial name="_StatusMessage" model="Model.StatusMessage" />
<div class="row">
<div class="col-md-6">
<form id="profile-form" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Username"></label>
<input asp-for="Username" class="form-control" disabled />
</div>
<div class="form-group">
<label asp-for="Input.PhoneNumber"></label>
<input asp-for="Input.PhoneNumber" class="form-control" />
<span asp-validation-for="Input.PhoneNumber" class="text-danger"></span>
</div>
<button id="update-profile-button" type="submit" class="btn btn-primary">Save</button>
</form>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace GWMS.UI.Areas.Identity.Pages.Account.Manage
{
public partial class IndexModel : PageModel
{
#region Private Fields
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public IndexModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
#endregion Public Constructors
#region Public Properties
[BindProperty]
public InputModel Input { get; set; }
[TempData]
public string StatusMessage { get; set; }
public string Username { get; set; }
#endregion Public Properties
#region Private Methods
private async Task LoadAsync(IdentityUser user)
{
var userName = await _userManager.GetUserNameAsync(user);
var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
Username = userName;
Input = new InputModel
{
PhoneNumber = phoneNumber
};
}
#endregion Private Methods
#region Public Methods
public async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
await LoadAsync(user);
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
if (!ModelState.IsValid)
{
await LoadAsync(user);
return Page();
}
var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
if (Input.PhoneNumber != phoneNumber)
{
var setPhoneResult = await _userManager.SetPhoneNumberAsync(user, Input.PhoneNumber);
if (!setPhoneResult.Succeeded)
{
StatusMessage = "Unexpected error when trying to set phone number.";
return RedirectToPage();
}
}
await _signInManager.RefreshSignInAsync(user);
StatusMessage = "Your profile has been updated";
return RedirectToPage();
}
#endregion Public Methods
#region Public Classes
public class InputModel
{
#region Public Properties
[Phone]
[Display(Name = "Phone number")]
public string PhoneNumber { get; set; }
#endregion Public Properties
}
#endregion Public Classes
}
}
@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace GWMS.UI.Areas.Identity.Pages.Account.Manage
{
public static class ManageNavPages
{
#region Public Properties
public static string ChangePassword => "ChangePassword";
public static string DeletePersonalData => "DeletePersonalData";
public static string DownloadPersonalData => "DownloadPersonalData";
public static string Email => "Email";
public static string ExternalLogins => "ExternalLogins";
public static string Index => "Index";
public static string PersonalData => "PersonalData";
public static string TwoFactorAuthentication => "TwoFactorAuthentication";
#endregion Public Properties
#region Private Methods
private static string PageNavClass(ViewContext viewContext, string page)
{
var activePage = viewContext.ViewData["ActivePage"] as string
?? System.IO.Path.GetFileNameWithoutExtension(viewContext.ActionDescriptor.DisplayName);
return string.Equals(activePage, page, StringComparison.OrdinalIgnoreCase) ? "active" : null;
}
#endregion Private Methods
#region Public Methods
public static string ChangePasswordNavClass(ViewContext viewContext) => PageNavClass(viewContext, ChangePassword);
public static string DeletePersonalDataNavClass(ViewContext viewContext) => PageNavClass(viewContext, DeletePersonalData);
public static string DownloadPersonalDataNavClass(ViewContext viewContext) => PageNavClass(viewContext, DownloadPersonalData);
public static string EmailNavClass(ViewContext viewContext) => PageNavClass(viewContext, Email);
public static string ExternalLoginsNavClass(ViewContext viewContext) => PageNavClass(viewContext, ExternalLogins);
public static string IndexNavClass(ViewContext viewContext) => PageNavClass(viewContext, Index);
public static string PersonalDataNavClass(ViewContext viewContext) => PageNavClass(viewContext, PersonalData);
public static string TwoFactorAuthenticationNavClass(ViewContext viewContext) => PageNavClass(viewContext, TwoFactorAuthentication);
#endregion Public Methods
}
}
@@ -0,0 +1,27 @@
@page
@model PersonalDataModel
@{
ViewData["Title"] = "Personal Data";
ViewData["ActivePage"] = ManageNavPages.PersonalData;
}
<h4>@ViewData["Title"]</h4>
<div class="row">
<div class="col-md-6">
<p>Your account contains personal data that you have given us. This page allows you to download or delete that data.</p>
<p>
<strong>Deleting this data will permanently remove your account, and this cannot be recovered.</strong>
</p>
<form id="download-data" asp-page="DownloadPersonalData" method="post" class="form-group">
<button class="btn btn-primary" type="submit">Download</button>
</form>
<p>
<a id="delete" asp-page="DeletePersonalData" class="btn btn-secondary">Delete</a>
</p>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,45 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account.Manage
{
public class PersonalDataModel : PageModel
{
#region Private Fields
private readonly ILogger<PersonalDataModel> _logger;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public PersonalDataModel(
UserManager<IdentityUser> userManager,
ILogger<PersonalDataModel> logger)
{
_userManager = userManager;
_logger = logger;
}
#endregion Public Constructors
#region Public Methods
public async Task<IActionResult> OnGet()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
return Page();
}
#endregion Public Methods
}
}
@@ -0,0 +1,24 @@
@page
@model ResetAuthenticatorModel
@{
ViewData["Title"] = "Reset authenticator key";
ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication;
}
<partial name="_StatusMessage" for="StatusMessage" />
<h4>@ViewData["Title"]</h4>
<div class="alert alert-warning" role="alert">
<p>
<span class="glyphicon glyphicon-warning-sign"></span>
<strong>If you reset your authenticator key your authenticator app will not work until you reconfigure it.</strong>
</p>
<p>
This process disables 2FA until you verify your authenticator app.
If you do not complete your authenticator app configuration you may lose access to your account.
</p>
</div>
<div>
<form id="reset-authenticator-form" method="post" class="form-group">
<button id="reset-authenticator-button" class="btn btn-danger" type="submit">Reset authenticator key</button>
</form>
</div>
@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account.Manage
{
public class ResetAuthenticatorModel : PageModel
{
#region Private Fields
private readonly SignInManager<IdentityUser> _signInManager;
private ILogger<ResetAuthenticatorModel> _logger;
private UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public ResetAuthenticatorModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
ILogger<ResetAuthenticatorModel> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
}
#endregion Public Constructors
#region Public Properties
[TempData]
public string StatusMessage { get; set; }
#endregion Public Properties
#region Public Methods
public async Task<IActionResult> OnGet()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
await _userManager.SetTwoFactorEnabledAsync(user, false);
await _userManager.ResetAuthenticatorKeyAsync(user);
_logger.LogInformation("User with ID '{UserId}' has reset their authentication app key.", user.Id);
await _signInManager.RefreshSignInAsync(user);
StatusMessage = "Your authenticator app key has been reset, you will need to configure your authenticator app using the new key.";
return RedirectToPage("./EnableAuthenticator");
}
#endregion Public Methods
}
}
@@ -0,0 +1,35 @@
@page
@model SetPasswordModel
@{
ViewData["Title"] = "Set password";
ViewData["ActivePage"] = ManageNavPages.ChangePassword;
}
<h4>Set your password</h4>
<partial name="_StatusMessage" for="StatusMessage" />
<p class="text-info">
You do not have a local username/password for this site. Add a local
account so you can log in without an external login.
</p>
<div class="row">
<div class="col-md-6">
<form id="set-password-form" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.NewPassword"></label>
<input asp-for="Input.NewPassword" class="form-control" />
<span asp-validation-for="Input.NewPassword" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.ConfirmPassword"></label>
<input asp-for="Input.ConfirmPassword" class="form-control" />
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Set password</button>
</form>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace GWMS.UI.Areas.Identity.Pages.Account.Manage
{
public class SetPasswordModel : PageModel
{
#region Private Fields
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public SetPasswordModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
#endregion Public Constructors
#region Public Properties
[BindProperty]
public InputModel Input { get; set; }
[TempData]
public string StatusMessage { get; set; }
#endregion Public Properties
#region Public Methods
public async Task<IActionResult> OnGetAsync()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
var hasPassword = await _userManager.HasPasswordAsync(user);
if (hasPassword)
{
return RedirectToPage("./ChangePassword");
}
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
var addPasswordResult = await _userManager.AddPasswordAsync(user, Input.NewPassword);
if (!addPasswordResult.Succeeded)
{
foreach (var error in addPasswordResult.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
return Page();
}
await _signInManager.RefreshSignInAsync(user);
StatusMessage = "Your password has been set.";
return RedirectToPage();
}
#endregion Public Methods
#region Public Classes
public class InputModel
{
#region Public Properties
[DataType(DataType.Password)]
[Display(Name = "Confirm new password")]
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "New password")]
public string NewPassword { get; set; }
#endregion Public Properties
}
#endregion Public Classes
}
}
@@ -0,0 +1,25 @@
@page
@model ShowRecoveryCodesModel
@{
ViewData["Title"] = "Recovery codes";
ViewData["ActivePage"] = "TwoFactorAuthentication";
}
<partial name="_StatusMessage" for="StatusMessage" />
<h4>@ViewData["Title"]</h4>
<div class="alert alert-warning" role="alert">
<p>
<strong>Put these codes in a safe place.</strong>
</p>
<p>
If you lose your device and don't have the recovery codes you will lose access to your account.
</p>
</div>
<div class="row">
<div class="col-md-12">
@for (var row = 0; row < Model.RecoveryCodes.Length; row += 2)
{
<code class="recovery-code">@Model.RecoveryCodes[row]</code><text>&nbsp;</text><code class="recovery-code">@Model.RecoveryCodes[row + 1]</code><br />
}
</div>
</div>
@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account.Manage
{
public class ShowRecoveryCodesModel : PageModel
{
#region Public Properties
[TempData]
public string[] RecoveryCodes { get; set; }
[TempData]
public string StatusMessage { get; set; }
#endregion Public Properties
#region Public Methods
public IActionResult OnGet()
{
if (RecoveryCodes == null || RecoveryCodes.Length == 0)
{
return RedirectToPage("./TwoFactorAuthentication");
}
return Page();
}
#endregion Public Methods
}
}
@@ -0,0 +1,57 @@
@page
@model TwoFactorAuthenticationModel
@{
ViewData["Title"] = "Two-factor authentication (2FA)";
ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication;
}
<partial name="_StatusMessage" for="StatusMessage" />
<h4>@ViewData["Title"]</h4>
@if (Model.Is2faEnabled)
{
if (Model.RecoveryCodesLeft == 0)
{
<div class="alert alert-danger">
<strong>You have no recovery codes left.</strong>
<p>You must <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a> before you can log in with a recovery code.</p>
</div>
}
else if (Model.RecoveryCodesLeft == 1)
{
<div class="alert alert-danger">
<strong>You have 1 recovery code left.</strong>
<p>You can <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a>.</p>
</div>
}
else if (Model.RecoveryCodesLeft <= 3)
{
<div class="alert alert-warning">
<strong>You have @Model.RecoveryCodesLeft recovery codes left.</strong>
<p>You should <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a>.</p>
</div>
}
if (Model.IsMachineRemembered)
{
<form method="post" style="display: inline-block">
<button type="submit" class="btn btn-warning">Forget this browser</button>
</form>
}
<a asp-page="./Disable2fa" class="btn btn-danger">Disable 2FA</a>
<a asp-page="./GenerateRecoveryCodes" class="btn btn-warning">Reset recovery codes</a>
}
<h5>Authenticator app</h5>
@if (!Model.HasAuthenticator)
{
<a id="enable-authenticator" asp-page="./EnableAuthenticator" class="btn btn-primary">Add authenticator app</a>
}
else
{
<a id="enable-authenticator" asp-page="./EnableAuthenticator" class="btn btn-primary">Setup authenticator app</a>
<a id="reset-authenticator" asp-page="./ResetAuthenticator" class="btn btn-primary">Reset authenticator app</a>
}
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account.Manage
{
public class TwoFactorAuthenticationModel : PageModel
{
#region Private Fields
private const string AuthenicatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}";
private readonly ILogger<TwoFactorAuthenticationModel> _logger;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public TwoFactorAuthenticationModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
ILogger<TwoFactorAuthenticationModel> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
}
#endregion Public Constructors
#region Public Properties
public bool HasAuthenticator { get; set; }
[BindProperty]
public bool Is2faEnabled { get; set; }
public bool IsMachineRemembered { get; set; }
public int RecoveryCodesLeft { get; set; }
[TempData]
public string StatusMessage { get; set; }
#endregion Public Properties
#region Public Methods
public async Task<IActionResult> OnGet()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
HasAuthenticator = await _userManager.GetAuthenticatorKeyAsync(user) != null;
Is2faEnabled = await _userManager.GetTwoFactorEnabledAsync(user);
IsMachineRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user);
RecoveryCodesLeft = await _userManager.CountRecoveryCodesAsync(user);
return Page();
}
public async Task<IActionResult> OnPost()
{
var user = await _userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
await _signInManager.ForgetTwoFactorClientAsync();
StatusMessage = "The current browser has been forgotten. When you login again from this browser you will be prompted for your 2fa code.";
return RedirectToPage();
}
#endregion Public Methods
}
}
@@ -0,0 +1,29 @@
@{
if (ViewData.TryGetValue("ParentLayout", out var parentLayout))
{
Layout = (string)parentLayout;
}
else
{
Layout = "/Areas/Identity/Pages/_Layout.cshtml";
}
}
<h2>Manage your account</h2>
<div>
<h4>Change your account settings</h4>
<hr />
<div class="row">
<div class="col-md-3">
<partial name="_ManageNav" />
</div>
<div class="col-md-9">
@RenderBody()
</div>
</div>
</div>
@section Scripts {
@RenderSection("Scripts", required: false)
}
@@ -0,0 +1,15 @@
@inject SignInManager<IdentityUser> SignInManager
@{
var hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any();
}
<ul class="nav nav-pills flex-column">
<li class="nav-item"><a class="nav-link @ManageNavPages.IndexNavClass(ViewContext)" id="profile" asp-page="./Index">Profile</a></li>
<li class="nav-item"><a class="nav-link @ManageNavPages.EmailNavClass(ViewContext)" id="email" asp-page="./Email">Email</a></li>
<li class="nav-item"><a class="nav-link @ManageNavPages.ChangePasswordNavClass(ViewContext)" id="change-password" asp-page="./ChangePassword">Password</a></li>
@if (hasExternalLogins)
{
<li id="external-logins" class="nav-item"><a id="external-login" class="nav-link @ManageNavPages.ExternalLoginsNavClass(ViewContext)" asp-page="./ExternalLogins">External logins</a></li>
}
<li class="nav-item"><a class="nav-link @ManageNavPages.TwoFactorAuthenticationNavClass(ViewContext)" id="two-factor" asp-page="./TwoFactorAuthentication">Two-factor authentication</a></li>
<li class="nav-item"><a class="nav-link @ManageNavPages.PersonalDataNavClass(ViewContext)" id="personal-data" asp-page="./PersonalData">Personal data</a></li>
</ul>
@@ -0,0 +1,10 @@
@model string
@if (!String.IsNullOrEmpty(Model))
{
var statusMessageClass = Model.StartsWith("Error") ? "danger" : "success";
<div class="alert alert-@statusMessageClass alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
@Model
</div>
}
@@ -0,0 +1 @@
@using GWMS.UI.Areas.Identity.Pages.Account.Manage
@@ -0,0 +1,70 @@
@page
@model RegisterModel
@{
ViewData["Title"] = "Registrazione";
}
<div class="card">
<div class="card-header"><h1>@ViewData["Title"]</h1></div>
<div class="card-body">
<div class="row">
<div class="col-md-4">
<form asp-route-returnUrl="@Model.ReturnUrl" method="post">
<h4>Creazione nuovo account.</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" class="form-control" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Password"></label>
<input asp-for="Input.Password" class="form-control" />
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.ConfirmPassword"></label>
<input asp-for="Input.ConfirmPassword" class="form-control" />
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-success btn-block"><i class="far fa-save"></i> Registra Account</button>
</form>
</div>
@*<div class="col-md-6 col-md-offset-2">
<section>
<h4>Use another service to register.</h4>
<hr />
@{
if ((Model.ExternalLogins?.Count ?? 0) == 0)
{
<div>
<p>
There are no external authentication services configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
for details on setting up this ASP.NET application to support logging in via external services.
</p>
</div>
}
else
{
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
<div>
<p>
@foreach (var provider in Model.ExternalLogins)
{
<button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
}
</p>
</div>
</form>
}
}
</section>
</div>*@
</div>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class RegisterModel : PageModel
{
#region Private Fields
private readonly IEmailSender _emailSender;
private readonly ILogger<RegisterModel> _logger;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public RegisterModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
ILogger<RegisterModel> logger,
IEmailSender emailSender)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
_emailSender = emailSender;
}
#endregion Public Constructors
#region Public Properties
public IList<AuthenticationScheme> ExternalLogins { get; set; }
[BindProperty]
public InputModel Input { get; set; }
public string ReturnUrl { get; set; }
#endregion Public Properties
#region Public Methods
public async Task OnGetAsync(string returnUrl = null)
{
ReturnUrl = returnUrl;
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl ??= Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
var result = await _userManager.CreateAsync(user, Input.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = user.Id, code = code, returnUrl = returnUrl },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(Input.Email, "GWMS: Richiesta conferma email",
$"Prego cliccare sul <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>seguente link</a> per confermare l'account registrato con questa email.");
if (_userManager.Options.SignIn.RequireConfirmedAccount)
{
return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
}
else
{
// aggiunta ruolo UNDEF (da sistemare poi)
// https://code-maze.com/using-roles-in-blazor-webassembly-hosted-applications/
await _userManager.AddToRoleAsync(user, "Undef");
// continuo come default
await _signInManager.SignInAsync(user, isPersistent: false);
return LocalRedirect(returnUrl);
}
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
}
#endregion Public Methods
#region Public Classes
public class InputModel
{
#region Public Properties
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
#endregion Public Properties
}
#endregion Public Classes
}
}
@@ -0,0 +1,24 @@
@page
@model RegisterConfirmationModel
@{
ViewData["Title"] = "Conferma richiesta";
}
<div class="card">
<div class="card-header"><h1>@ViewData["Title"]</h1></div>
<div class="card-body">
<div class="alert alert-warning">
<h4>Account creato!</h4>
<p>Ora è necessario effettuare la verifica dell'email registrata</p>
</div>
<b>Prego verifica la posta ricevuta all'account registrato per effettuare la conferma.</b>
<p>Riceverai un email da steamwarebot at gmail.com con un link da cliccare per completare la registrazione. Dopo la conferma potrai effettuare il login all'applicazione.</p>
</div>
<div class="card-footer">
<div class="row">
<div class="col-6">
<a title="LogIn" href="Identity/Account/LogIn" class="btn btn-sm btn-success btn-block"><i class="fas fa-sign-in-alt"></i> Login Page</a>
</div>
</div>
</div>
</div>
@@ -0,0 +1,61 @@
using Microsoft.AspNetCore.Authorization;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class RegisterConfirmationModel : PageModel
{
#region Private Fields
private readonly IEmailSender _sender;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public RegisterConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender sender)
{
_userManager = userManager;
_sender = sender;
}
#endregion Public Constructors
#region Public Properties
public string Email { get; set; }
public string EmailConfirmationUrl { get; set; }
#endregion Public Properties
#region Public Methods
public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
{
if (email == null)
{
return RedirectToPage("/Index");
}
var user = await _userManager.FindByEmailAsync(email);
if (user == null)
{
return NotFound($"Unable to load user with email '{email}'.");
}
Email = email;
return Page();
}
#endregion Public Methods
}
}
@@ -0,0 +1,30 @@
@page
@model ResendEmailConfirmationModel
@{
ViewData["Title"] = "Reinvia email di conferma";
}
<div class="card">
<div class="card-header"><h1>@ViewData["Title"]</h1></div>
<div class="card-body">
<h4>Inserire l'account email registrato.</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" class="form-control" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary btn-block"><i class="fas fa-envelope"></i> Invia nuovamente email</button>
</form>
</div>
</div>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,97 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class ResendEmailConfirmationModel : PageModel
{
#region Private Fields
private readonly IEmailSender _emailSender;
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public ResendEmailConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender emailSender)
{
_userManager = userManager;
_emailSender = emailSender;
}
#endregion Public Constructors
#region Public Properties
[BindProperty]
public InputModel Input { get; set; }
#endregion Public Properties
#region Public Methods
public void OnGet()
{
}
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var user = await _userManager.FindByEmailAsync(Input.Email);
if (user == null)
{
ModelState.AddModelError(string.Empty, "Verification email sent. Please check your email.");
return Page();
}
var userId = await _userManager.GetUserIdAsync(user);
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { userId = userId, code = code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(
Input.Email,
"Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
ModelState.AddModelError(string.Empty, "Verification email sent. Please check your email.");
return Page();
}
#endregion Public Methods
#region Public Classes
public class InputModel
{
#region Public Properties
[Required]
[EmailAddress]
public string Email { get; set; }
#endregion Public Properties
}
#endregion Public Classes
}
}
@@ -0,0 +1,41 @@
@page
@model ResetPasswordModel
@{
ViewData["Title"] = "Reset Password";
}
<div class="card">
<div class="card-header"><h1>@ViewData["Title"]</h1></div>
<div class="card-body">
<h4>Reset password.</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input asp-for="Input.Code" type="hidden" />
<div class="form-group">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" class="form-control" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Password"></label>
<input asp-for="Input.Password" class="form-control" />
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.ConfirmPassword"></label>
<input asp-for="Input.ConfirmPassword" class="form-control" />
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary btn-block"><i class="fas fa-envelope"></i> Reset Password</button>
</form>
</div>
</div>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class ResetPasswordModel : PageModel
{
#region Private Fields
private readonly UserManager<IdentityUser> _userManager;
#endregion Private Fields
#region Public Constructors
public ResetPasswordModel(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
#endregion Public Constructors
#region Public Properties
[BindProperty]
public InputModel Input { get; set; }
#endregion Public Properties
#region Public Methods
public IActionResult OnGet(string code = null)
{
if (code == null)
{
return BadRequest("A code must be supplied for password reset.");
}
else
{
Input = new InputModel
{
Code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code))
};
return Page();
}
}
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var user = await _userManager.FindByEmailAsync(Input.Email);
if (user == null)
{
// Don't reveal that the user does not exist
return RedirectToPage("./ResetPasswordConfirmation");
}
var result = await _userManager.ResetPasswordAsync(user, Input.Code, Input.Password);
if (result.Succeeded)
{
return RedirectToPage("./ResetPasswordConfirmation");
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
return Page();
}
#endregion Public Methods
#region Public Classes
public class InputModel
{
#region Public Properties
public string Code { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
public string Password { get; set; }
#endregion Public Properties
}
#endregion Public Classes
}
}
@@ -0,0 +1,10 @@
@page
@model ResetPasswordConfirmationModel
@{
ViewData["Title"] = "Reset password confirmation";
}
<h1>@ViewData["Title"]</h1>
<p>
Your password has been reset. Please <a asp-page="./Login">click here to log in</a>.
</p>
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace GWMS.UI.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class ResetPasswordConfirmationModel : PageModel
{
#region Public Methods
public void OnGet()
{
}
#endregion Public Methods
}
}
@@ -0,0 +1,10 @@
@model string
@if (!String.IsNullOrEmpty(Model))
{
var statusMessageClass = Model.StartsWith("Error") ? "danger" : "success";
<div class="alert alert-@statusMessageClass alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
@Model
</div>
}
@@ -0,0 +1 @@
@using GWMS.UI.Areas.Identity.Pages.Account
+23
View File
@@ -0,0 +1,23 @@
@page
@model ErrorModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>Development environment should not be enabled in deployed applications</strong>, 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 <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>, and restarting the application.
</p>
@@ -0,0 +1,29 @@
using System.Diagnostics;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace GWMS.UI.Areas.Identity.Pages
{
[AllowAnonymous]
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class ErrorModel : PageModel
{
#region Public Properties
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
#endregion Public Properties
#region Public Methods
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
#endregion Public Methods
}
}
@@ -0,0 +1,4 @@
@using Microsoft.AspNetCore.Identity
@using GWMS.UI.Areas.Identity
@using GWMS.UI.Areas.Identity.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@@ -0,0 +1,4 @@
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
+1 -1
View File
@@ -1,4 +1,4 @@
<div class="row px-1 text-light">
<div class="form-row text-light">
<div class="col-5 pr-0 text-left">
GWMS <span class="small">v.@version</span>
</div>
+5 -6
View File
@@ -6,15 +6,14 @@
@inject MessageService AppMessages
@inject AuthenticationStateProvider AuthenticationStateProvider
<div class="row pt-3">
<div class="col-3">
<i class="fas fa-user-alt"></i> <b>@userName</b>
@*<LoginDisplay />*@
<div class="form-row pt-3">
<div class="col-7 col-md-6 col-lg-4 col-xl-3">
<LoginDisplay></LoginDisplay>
</div>
<div class="col-6 text-center h4">
<div class="col-12 col-lg-4 col-xl-6 d-none d-lg-block text-center h4 text-truncate">
<span class="@PageIcon" aria-hidden="true"></span> @PageName
</div>
<div class="col-3 text-right">
<div class="col-5 col-md-6 col-lg-4 col-xl-3 text-right">
@if (ShowSearch)
{
<SearchMod></SearchMod>
+2 -2
View File
@@ -25,7 +25,7 @@
foreach (var item in _currList)
{
<div class="col-12">
<button class="btn btn-block btn-outline-dark" @onclick="() => Edit(item)">
<button class="btn btn-block btn-outline-dark px-1" @onclick="() => Edit(item)">
<div class="d-flex justify-content-between">
<div class="px-1">
<i class="fas fa-gas-pump" aria-hidden="true"></i> @item.Plant.PlantDesc
@@ -60,7 +60,7 @@
{
get
{
return _currList = null;
return _currList;
}
set
{
+57 -8
View File
@@ -1,12 +1,61 @@
<AuthorizeView>
@using Microsoft.AspNetCore.Components.Authorization
@inject AuthenticationStateProvider AuthenticationStateProvider
<AuthorizeView>
<Authorized>
<a href="Identity/Account/Manage">Hello, @context.User.Identity.Name !!!</a>
<form method="post" action="Identity/Account/LogOut">
<button type="submit" class="nav-link btn btn-link">Log out</button>
</form>
<div class="input-group text-truncate">
<div class="input-group-prepend">
<a title="LogOut" href="Identity/Account/LogOut" class="btn btn-sm btn-danger"><i class="fas fa-sign-out-alt"></i></a>
</div>
<a title="Gestione account @userName" href="Identity/Account/Manage" class="btn btn-sm btn-outline-dark mx-0 px-1">
<div class="d-none d-sm-block">
<i class="fas fa-user-alt"></i> @StringLim(userName, 30)
</div>
<div class="d-block d-sm-none">
<i class="fas fa-user-alt"></i> @StringLim(userName, 15)
</div>
</a>
</div>
</Authorized>
<NotAuthorized>
<a href="Identity/Account/Register">Register</a>
<a href="Identity/Account/Login">Log in</a>
<div class="input-group">
<div class="input-group-prepend">
<a title="LogIn" href="Identity/Account/LogIn" class="btn btn-sm btn-success"><i class="fas fa-sign-in-alt"></i></a>
</div>
<div class="form-control form-control-sm">
<i class="fas fa-user-alt"></i>&nbsp;@userName
</div>
</div>
</NotAuthorized>
</AuthorizeView>
</AuthorizeView>
@code{
private string userName = "";
protected override async Task OnInitializedAsync()
{
await forceReload();
}
private async Task forceReload()
{
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var user = authState.User;
if (user.Identity.IsAuthenticated)
{
userName = $"{user.Identity.Name}";
}
else
{
userName = "Non Autenticato";
}
}
protected string StringLim(string original, int maxLen)
{
return original.Length <= maxLen ? original : $"{original.Substring(0, maxLen - 3)}...";
}
}
+28 -13
View File
@@ -20,7 +20,8 @@
<DataAnnotationsValidator />
<div class="row">
<div class="col-12 col-lg-1">
<img src="@getImgUrl(_currItem.OrderCode)" class="img-fluid" width="85" />
<div id="qrCodeImg"></div>
@*<img src="@getImgUrl(_currItem.OrderCode)" class="img-fluid" width="85" />*@
</div>
<div class="col-12 col-lg-9 align-items-center">
<div class="row">
@@ -266,6 +267,20 @@
protected override async Task OnInitializedAsync()
{
await ReloadAllData();
await JSRuntime.InvokeVoidAsync("displayQr", "qrCodeImg", rawCode);
}
protected string rawCode
{
get
{
string answ = "";
if (_currItem != null)
{
answ = _currItem.OrderCode;
}
return answ;
}
}
protected async Task ReloadAllData()
@@ -290,17 +305,17 @@
return q[parmName] ?? "";
}
/// <summary>
/// Restituisce URL immagine QRCode
/// </summary>
/// <param name="QrValue">Parametro da renderizzare con QRCode</param>
/// <returns></returns>
protected string getImgUrl(object QrValue)
{
string baseUrl = $"{Configuration["ZCodeUrl"]}/HOME/QR_site/JSON?val=";
string payload = "{'baseUrl':'{0}','parameters':['" + $"{QrValue}" + "']}";
string answ = $"{baseUrl}{payload}";
return answ;
}
///// <summary>
///// Restituisce URL immagine QRCode
///// </summary>
///// <param name="QrValue">Parametro da renderizzare con QRCode</param>
///// <returns></returns>
//protected string getImgUrl(object QrValue)
//{
// string baseUrl = $"{Configuration["ZCodeUrl"]}/HOME/QR_site/JSON?val=";
// string payload = "{'baseUrl':'{0}','parameters':['" + $"{QrValue}" + "']}";
// string answ = $"{baseUrl}{payload}";
// return answ;
//}
}
+33 -17
View File
@@ -8,6 +8,7 @@
@inject MessageService AppMService
@inject GWMSDataService DataService
@inject IConfiguration Configuration
@inject IJSRuntime JSRuntime
<div class="card">
<div class="card-header bg-info text-light">
@@ -17,10 +18,11 @@
<EditForm Model="@_currItem">
<DataAnnotationsValidator />
<div class="row">
<div class="col-12 col-lg-2">
<img src="@getImgUrl(_currItem.OrderCode)" class="img-fluid" width="85" />
<div class="col-12 col-lg-1">
<div id="qrCodeImg"></div>
@*<img src="@getImgUrl(_currItem.OrderCode)" class="img-fluid" width="85" />*@
</div>
<div class="col-12 col-lg-8 align-items-center">
<div class="col-12 col-lg-9 align-items-center">
<div class="row">
<div class="col-8">
<div class="input-group">
@@ -66,10 +68,10 @@
</div>
<div class="col-12 col-lg-2">
<div class="mb-2">
<button type="button" class="btn btn-outline-success btn-block" value="Save" @onclick="saveUpdate">Save <i class="far fa-save"></i></button>
<button type="button" class="btn btn-success btn-block" value="Save" @onclick="saveUpdate">Save <i class="far fa-save"></i></button>
</div>
<div>
<button type="button" class="btn btn-outline-warning btn-block" value="Cancel" @onclick="cancelUpdate">Cancel <i class="fas fa-ban"></i></button>
<button type="button" class="btn btn-warning btn-block" value="Cancel" @onclick="cancelUpdate">Cancel <i class="fas fa-ban"></i></button>
</div>
</div>
</div>
@@ -138,6 +140,20 @@
protected override async Task OnInitializedAsync()
{
await ReloadAllData();
await JSRuntime.InvokeVoidAsync("displayQr", "qrCodeImg", rawCode);
}
protected string rawCode
{
get
{
string answ = "";
if (_currItem != null)
{
answ = _currItem.OrderCode;
}
return answ;
}
}
protected async Task ReloadAllData()
@@ -145,17 +161,17 @@
transpList = await DataService.TransportersGetAll();
}
/// <summary>
/// Restituisce URL immagine QRCode
/// </summary>
/// <param name="QrValue">Parametro da renderizzare con QRCode</param>
/// <returns></returns>
protected string getImgUrl(object QrValue)
{
string baseUrl = $"{Configuration["ZCodeUrl"]}/HOME/QR_site/JSON?val=";
string payload = "{'baseUrl':'{0}','parameters':['" + $"{QrValue}" + "']}";
string answ = $"{baseUrl}{payload}";
return answ;
}
///// <summary>
///// Restituisce URL immagine QRCode
///// </summary>
///// <param name="QrValue">Parametro da renderizzare con QRCode</param>
///// <returns></returns>
//protected string getImgUrl(object QrValue)
//{
// string baseUrl = $"{Configuration["ZCodeUrl"]}/HOME/QR_site/JSON?val=";
// string payload = "{'baseUrl':'{0}','parameters':['" + $"{QrValue}" + "']}";
// string answ = $"{baseUrl}{payload}";
// return answ;
//}
}

Some files were not shown because too many files have changed in this diff Show More