From 3ba39b58d1959894aac02217b5596c558b8ecea8 Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Tue, 15 Nov 2022 19:17:34 -0300 Subject: [PATCH 01/18] Firt Commit: BookManeger --- BookManager/.gitignore | 454 +++++++++++++++++++++ BookManager/.vscode/launch.json | 35 ++ BookManager/.vscode/tasks.json | 41 ++ BookManager/BookManager.csproj | 23 ++ BookManager/Controllers/AuthContoller.cs | 18 + BookManager/Controllers/BookController.cs | 45 ++ BookManager/Data/DataContext.cs | 14 + BookManager/Model/Book.cs | 20 + BookManager/Model/Category.cs | 13 + BookManager/Model/Credential.cs | 14 + BookManager/Model/Publisher.cs | 14 + BookManager/Model/Token.cs | 10 + BookManager/Model/User.cs | 15 + BookManager/Model/stock.cs | 13 + BookManager/Program.cs | 33 ++ BookManager/Properties/launchSettings.json | 31 ++ BookManager/README.md | 19 + BookManager/appsettings.Development.json | 8 + BookManager/appsettings.json | 13 + CurriculoDantas.pdf | Bin 0 -> 50719 bytes Diagrama.md | 53 +++ 21 files changed, 886 insertions(+) create mode 100644 BookManager/.gitignore create mode 100644 BookManager/.vscode/launch.json create mode 100644 BookManager/.vscode/tasks.json create mode 100644 BookManager/BookManager.csproj create mode 100644 BookManager/Controllers/AuthContoller.cs create mode 100644 BookManager/Controllers/BookController.cs create mode 100644 BookManager/Data/DataContext.cs create mode 100644 BookManager/Model/Book.cs create mode 100644 BookManager/Model/Category.cs create mode 100644 BookManager/Model/Credential.cs create mode 100644 BookManager/Model/Publisher.cs create mode 100644 BookManager/Model/Token.cs create mode 100644 BookManager/Model/User.cs create mode 100644 BookManager/Model/stock.cs create mode 100644 BookManager/Program.cs create mode 100644 BookManager/Properties/launchSettings.json create mode 100644 BookManager/README.md create mode 100644 BookManager/appsettings.Development.json create mode 100644 BookManager/appsettings.json create mode 100644 CurriculoDantas.pdf create mode 100644 Diagrama.md diff --git a/BookManager/.gitignore b/BookManager/.gitignore new file mode 100644 index 00000000..2afa2e27 --- /dev/null +++ b/BookManager/.gitignore @@ -0,0 +1,454 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# JetBrains Rider +.idea/ +*.sln.iml + +## +## Visual Studio Code +## +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json diff --git a/BookManager/.vscode/launch.json b/BookManager/.vscode/launch.json new file mode 100644 index 00000000..0feb31ca --- /dev/null +++ b/BookManager/.vscode/launch.json @@ -0,0 +1,35 @@ +{ + "version": "0.2.0", + "configurations": [ + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "name": ".NET Core Launch (web)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/net6.0/BookManager.dll", + "args": [], + "cwd": "${workspaceFolder}", + "stopAtEntry": false, + // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser + "serverReadyAction": { + "action": "openExternally", + "pattern": "\\bNow listening on:\\s+(https?://\\S+)" + }, + "env": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "sourceFileMap": { + "/Views": "${workspaceFolder}/Views" + } + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach" + } + ] +} \ No newline at end of file diff --git a/BookManager/.vscode/tasks.json b/BookManager/.vscode/tasks.json new file mode 100644 index 00000000..3d1b17a6 --- /dev/null +++ b/BookManager/.vscode/tasks.json @@ -0,0 +1,41 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/BookManager.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/BookManager.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "--project", + "${workspaceFolder}/BookManager.csproj" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/BookManager/BookManager.csproj b/BookManager/BookManager.csproj new file mode 100644 index 00000000..7d7e4159 --- /dev/null +++ b/BookManager/BookManager.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + enable + enable + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + diff --git a/BookManager/Controllers/AuthContoller.cs b/BookManager/Controllers/AuthContoller.cs new file mode 100644 index 00000000..f0d5672a --- /dev/null +++ b/BookManager/Controllers/AuthContoller.cs @@ -0,0 +1,18 @@ +using BookManager.Model; +using Microsoft.AspNetCore.Mvc; + +namespace BookManager.Controllers +{ + [ApiController] + [Route("api/[controller]")] + public class AuthController : ControllerBase + { + [HttpPost] + public Token login(Credential param) + { + //TODO:Implementar JWT + return new Token() { token = "dddd" }; + } + + } +} \ No newline at end of file diff --git a/BookManager/Controllers/BookController.cs b/BookManager/Controllers/BookController.cs new file mode 100644 index 00000000..055ae7c7 --- /dev/null +++ b/BookManager/Controllers/BookController.cs @@ -0,0 +1,45 @@ +using BookManager.Model; +using Microsoft.AspNetCore.Mvc; + +namespace BookManager.Controllers +{ + [ApiController] + [Route("api/[controller]")] + public class BookController : ControllerBase + { + + //TODO:Implementar Entity + [HttpGet] + public IActionResult get() + { + return Ok("ok"); + } + + // [HttpGet] + // public IActionResult getById(int id) + // { + // return Ok("ok"); + // } + + [HttpPut] + public IActionResult put(int id) + { + return Ok("ok"); + } + + + [HttpDelete] + public IActionResult delete(int id) + { + return Ok("ok"); + } + + + [HttpPost] + public IActionResult post(Book book) + { + return Ok(book); + } + + } +} \ No newline at end of file diff --git a/BookManager/Data/DataContext.cs b/BookManager/Data/DataContext.cs new file mode 100644 index 00000000..25918a41 --- /dev/null +++ b/BookManager/Data/DataContext.cs @@ -0,0 +1,14 @@ +using BookManager.Model; +using Microsoft.EntityFrameworkCore; + +namespace BookManager.Data +{ + public class DataContext : DbContext + { + public DataContext(DbContextOptions options) : base(options) + { + } + public DbSet book { get; set; } + + } +} \ No newline at end of file diff --git a/BookManager/Model/Book.cs b/BookManager/Model/Book.cs new file mode 100644 index 00000000..cd8d8691 --- /dev/null +++ b/BookManager/Model/Book.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BookManager.Model +{ + public class Book + { + public int id { get; set; } + public string title { get; set; } + public string decription { get; set; } + public string idAuthor { get; set; } + public int idCategory { get; set; } + public string isnb { get; set; } + public int year { get; set; } + public int idPublisher { get; set; } + + } +} \ No newline at end of file diff --git a/BookManager/Model/Category.cs b/BookManager/Model/Category.cs new file mode 100644 index 00000000..5846de38 --- /dev/null +++ b/BookManager/Model/Category.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BookManager.Model +{ + public class Category + { + public int id { get; set; } + public string desciption { get; set; } + } +} \ No newline at end of file diff --git a/BookManager/Model/Credential.cs b/BookManager/Model/Credential.cs new file mode 100644 index 00000000..2adc5f71 --- /dev/null +++ b/BookManager/Model/Credential.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BookManager.Model +{ + public class Credential + { + + public string email { get; set; } + public string password { get; set; } + } +} diff --git a/BookManager/Model/Publisher.cs b/BookManager/Model/Publisher.cs new file mode 100644 index 00000000..ce476878 --- /dev/null +++ b/BookManager/Model/Publisher.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BookManager.Model +{ + public class Publisher + { + + public int id { get; set; } + public string desciption { get; set; } + } +} \ No newline at end of file diff --git a/BookManager/Model/Token.cs b/BookManager/Model/Token.cs new file mode 100644 index 00000000..e215a0f3 --- /dev/null +++ b/BookManager/Model/Token.cs @@ -0,0 +1,10 @@ +using System; + +namespace BookManager.Model +{ + public class Token + { + public string token { get; set; } + public DateTime expires { get; set; } + } +} \ No newline at end of file diff --git a/BookManager/Model/User.cs b/BookManager/Model/User.cs new file mode 100644 index 00000000..7041a540 --- /dev/null +++ b/BookManager/Model/User.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BookManager.Model +{ + public class User + { + public int id { get; set; } + public string name { get; set; } + public string email { get; set; } + public string password { get; set; } + } +} \ No newline at end of file diff --git a/BookManager/Model/stock.cs b/BookManager/Model/stock.cs new file mode 100644 index 00000000..2fd74125 --- /dev/null +++ b/BookManager/Model/stock.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BookManager.Model +{ + public class stock + { + public int idBook { get; set; } + public int quantity { get; set; } + } +} \ No newline at end of file diff --git a/BookManager/Program.cs b/BookManager/Program.cs new file mode 100644 index 00000000..333eebe6 --- /dev/null +++ b/BookManager/Program.cs @@ -0,0 +1,33 @@ +using BookManager.Data; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +builder.Services.AddDbContext(options => +{ + //options.useNpgsql(); +}); + + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/BookManager/Properties/launchSettings.json b/BookManager/Properties/launchSettings.json new file mode 100644 index 00000000..ecf3b0fe --- /dev/null +++ b/BookManager/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:10226", + "sslPort": 44355 + } + }, + "profiles": { + "BookManager": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7102;http://localhost:5153", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/BookManager/README.md b/BookManager/README.md new file mode 100644 index 00000000..dba83808 --- /dev/null +++ b/BookManager/README.md @@ -0,0 +1,19 @@ +## Desafio Back-End + +#### Check list + +- Modelagem DR -OK +- Swagger - OK +- Jwt -OK +- SOLID +- Factory +- Singleton +- gitignore +- injeção de dependencia +- Princípio de responsabilidade única +- Entity +- Crud +- Log +- Banco Postegre +- Migrates +- Seeds - Carga diff --git a/BookManager/appsettings.Development.json b/BookManager/appsettings.Development.json new file mode 100644 index 00000000..0c208ae9 --- /dev/null +++ b/BookManager/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/BookManager/appsettings.json b/BookManager/appsettings.json new file mode 100644 index 00000000..4d278e59 --- /dev/null +++ b/BookManager/appsettings.json @@ -0,0 +1,13 @@ +{ + "ConnectionStrings": { + "Default": "User Id; Password= Host=localhost;Porta=5432;database=bookmaneger" + }, + + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/CurriculoDantas.pdf b/CurriculoDantas.pdf new file mode 100644 index 0000000000000000000000000000000000000000..efcc34c8d4662d31f31e92d514d59b4a32c5c067 GIT binary patch literal 50719 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 L@Zsa9l^6XVZSVx< literal 0 HcmV?d00001 diff --git a/Diagrama.md b/Diagrama.md new file mode 100644 index 00000000..0e2327dd --- /dev/null +++ b/Diagrama.md @@ -0,0 +1,53 @@ +# Diagrama + +```mermaid +classDiagram + +Book --> Publisher +Book --> Category +stock --> Book + +class User { + +number id [pk] + +string name + +string email + +string password +} + +class Credential{ + +string email + +string password +} + + +class Book { + +number id [pk] + +string title + +string description + +string autor + +string category + +string isnb + +string yaer + +number idPublisher +} + + +class Publisher { + +number id [pk] + +string description +} + +class Category { + +number id [pk] + +string description +} + +class stock { + +number idBook [pk] + +number quantity +} + + + + +``` From 57c8b6e94801a0320aac4dda5533a1e340bcdcb3 Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Tue, 15 Nov 2022 19:37:34 -0300 Subject: [PATCH 02/18] Clear --- BookManager/.gitignore | 9 -------- BookManager/.vscode/launch.json | 35 ---------------------------- BookManager/.vscode/tasks.json | 41 --------------------------------- 3 files changed, 85 deletions(-) delete mode 100644 BookManager/.vscode/launch.json delete mode 100644 BookManager/.vscode/tasks.json diff --git a/BookManager/.gitignore b/BookManager/.gitignore index 2afa2e27..51bab6d6 100644 --- a/BookManager/.gitignore +++ b/BookManager/.gitignore @@ -443,12 +443,3 @@ $RECYCLE.BIN/ # JetBrains Rider .idea/ *.sln.iml - -## -## Visual Studio Code -## -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json diff --git a/BookManager/.vscode/launch.json b/BookManager/.vscode/launch.json deleted file mode 100644 index 0feb31ca..00000000 --- a/BookManager/.vscode/launch.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - // Use IntelliSense to find out which attributes exist for C# debugging - // Use hover for the description of the existing attributes - // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md - "name": ".NET Core Launch (web)", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/bin/Debug/net6.0/BookManager.dll", - "args": [], - "cwd": "${workspaceFolder}", - "stopAtEntry": false, - // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser - "serverReadyAction": { - "action": "openExternally", - "pattern": "\\bNow listening on:\\s+(https?://\\S+)" - }, - "env": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "sourceFileMap": { - "/Views": "${workspaceFolder}/Views" - } - }, - { - "name": ".NET Core Attach", - "type": "coreclr", - "request": "attach" - } - ] -} \ No newline at end of file diff --git a/BookManager/.vscode/tasks.json b/BookManager/.vscode/tasks.json deleted file mode 100644 index 3d1b17a6..00000000 --- a/BookManager/.vscode/tasks.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "build", - "command": "dotnet", - "type": "process", - "args": [ - "build", - "${workspaceFolder}/BookManager.csproj", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "problemMatcher": "$msCompile" - }, - { - "label": "publish", - "command": "dotnet", - "type": "process", - "args": [ - "publish", - "${workspaceFolder}/BookManager.csproj", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" - ], - "problemMatcher": "$msCompile" - }, - { - "label": "watch", - "command": "dotnet", - "type": "process", - "args": [ - "watch", - "run", - "--project", - "${workspaceFolder}/BookManager.csproj" - ], - "problemMatcher": "$msCompile" - } - ] -} \ No newline at end of file From ff6d8fc329d3077edbd42040dc23be2521badf07 Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Wed, 16 Nov 2022 20:13:59 -0300 Subject: [PATCH 03/18] =?UTF-8?q?Cria=C3=A7=C3=A3o=20do=20contexto=20e=20r?= =?UTF-8?q?epositorios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BookManager/.gitignore | 11 +++ BookManager/BookManager.csproj | 1 + .../{BookController.cs => BooksController.cs} | 23 +++++-- BookManager/Data/DataContext.cs | 12 +++- BookManager/Model/Book.cs | 13 ++-- BookManager/Model/Category.cs | 7 +- BookManager/Model/Credential.cs | 9 +-- BookManager/Model/Publisher.cs | 7 +- BookManager/Model/Token.cs | 2 +- BookManager/Model/User.cs | 11 +-- BookManager/Model/stock.cs | 7 +- BookManager/Program.cs | 10 +-- BookManager/Repository/BookRepository.cs | 69 +++++++++++++++++++ BookManager/Repository/IBaseRepository.cs | 10 +++ BookManager/Repository/IBookRepository.cs | 7 ++ BookManager/appsettings.json | 2 +- 16 files changed, 147 insertions(+), 54 deletions(-) rename BookManager/Controllers/{BookController.cs => BooksController.cs} (50%) create mode 100644 BookManager/Repository/BookRepository.cs create mode 100644 BookManager/Repository/IBaseRepository.cs create mode 100644 BookManager/Repository/IBookRepository.cs diff --git a/BookManager/.gitignore b/BookManager/.gitignore index 51bab6d6..f2bf2899 100644 --- a/BookManager/.gitignore +++ b/BookManager/.gitignore @@ -443,3 +443,14 @@ $RECYCLE.BIN/ # JetBrains Rider .idea/ *.sln.iml + +## +## Visual Studio Code +## +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.vscode +vscode \ No newline at end of file diff --git a/BookManager/BookManager.csproj b/BookManager/BookManager.csproj index 7d7e4159..9fd14795 100644 --- a/BookManager/BookManager.csproj +++ b/BookManager/BookManager.csproj @@ -17,6 +17,7 @@ all + diff --git a/BookManager/Controllers/BookController.cs b/BookManager/Controllers/BooksController.cs similarity index 50% rename from BookManager/Controllers/BookController.cs rename to BookManager/Controllers/BooksController.cs index 055ae7c7..0d86f83c 100644 --- a/BookManager/Controllers/BookController.cs +++ b/BookManager/Controllers/BooksController.cs @@ -1,13 +1,21 @@ using BookManager.Model; +using BookManager.Repository; using Microsoft.AspNetCore.Mvc; namespace BookManager.Controllers { [ApiController] [Route("api/[controller]")] - public class BookController : ControllerBase + public class BooksController : ControllerBase { + private readonly IBookRepository _repository; + // private readonly IMapper _mapper; + public BooksController(IBookRepository repository) + { + _repository = repository; + } + //TODO:Implementar Entity [HttpGet] public IActionResult get() @@ -15,12 +23,17 @@ public IActionResult get() return Ok("ok"); } - // [HttpGet] - // public IActionResult getById(int id) + // [HttpGet("{id}")] + // public async Task GetById(int id) // { - // return Ok("ok"); - // } + // var book = await _repository.GetBooksByIdAsync(id); + + // // var pacienteRetorno = _mapper.Map(paciente); + // return book != null + // ? Ok(book) + // : BadRequest("Book not found"); + // } [HttpPut] public IActionResult put(int id) { diff --git a/BookManager/Data/DataContext.cs b/BookManager/Data/DataContext.cs index 25918a41..ea2119d3 100644 --- a/BookManager/Data/DataContext.cs +++ b/BookManager/Data/DataContext.cs @@ -8,7 +8,17 @@ public class DataContext : DbContext public DataContext(DbContextOptions options) : base(options) { } - public DbSet book { get; set; } + public DbSet Categorys { get; set; } + public DbSet Publishers { get; set; } + public DbSet Books { get; set; } + public DbSet Stocks { get; set; } + public DbSet Users { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly); + } } } \ No newline at end of file diff --git a/BookManager/Model/Book.cs b/BookManager/Model/Book.cs index cd8d8691..47065e79 100644 --- a/BookManager/Model/Book.cs +++ b/BookManager/Model/Book.cs @@ -1,18 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - namespace BookManager.Model { public class Book { public int id { get; set; } - public string title { get; set; } - public string decription { get; set; } - public string idAuthor { get; set; } + public string? title { get; set; } + public string? decription { get; set; } + public string? idAuthor { get; set; } public int idCategory { get; set; } - public string isnb { get; set; } + public string? isnb { get; set; } public int year { get; set; } public int idPublisher { get; set; } diff --git a/BookManager/Model/Category.cs b/BookManager/Model/Category.cs index 5846de38..c31d69e4 100644 --- a/BookManager/Model/Category.cs +++ b/BookManager/Model/Category.cs @@ -1,13 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - namespace BookManager.Model { public class Category { public int id { get; set; } - public string desciption { get; set; } + public string? desciption { get; set; } } } \ No newline at end of file diff --git a/BookManager/Model/Credential.cs b/BookManager/Model/Credential.cs index 2adc5f71..15227fa3 100644 --- a/BookManager/Model/Credential.cs +++ b/BookManager/Model/Credential.cs @@ -1,14 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - namespace BookManager.Model { public class Credential { - public string email { get; set; } - public string password { get; set; } + public string? email { get; set; } + public string? password { get; set; } } } diff --git a/BookManager/Model/Publisher.cs b/BookManager/Model/Publisher.cs index ce476878..fdfe313c 100644 --- a/BookManager/Model/Publisher.cs +++ b/BookManager/Model/Publisher.cs @@ -1,14 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - namespace BookManager.Model { public class Publisher { public int id { get; set; } - public string desciption { get; set; } + public string? desciption { get; set; } } } \ No newline at end of file diff --git a/BookManager/Model/Token.cs b/BookManager/Model/Token.cs index e215a0f3..5df7bd24 100644 --- a/BookManager/Model/Token.cs +++ b/BookManager/Model/Token.cs @@ -4,7 +4,7 @@ namespace BookManager.Model { public class Token { - public string token { get; set; } + public string? token { get; set; } public DateTime expires { get; set; } } } \ No newline at end of file diff --git a/BookManager/Model/User.cs b/BookManager/Model/User.cs index 7041a540..33072a03 100644 --- a/BookManager/Model/User.cs +++ b/BookManager/Model/User.cs @@ -1,15 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - namespace BookManager.Model { public class User { public int id { get; set; } - public string name { get; set; } - public string email { get; set; } - public string password { get; set; } + public string? name { get; set; } + public string? email { get; set; } + public string? password { get; set; } } } \ No newline at end of file diff --git a/BookManager/Model/stock.cs b/BookManager/Model/stock.cs index 2fd74125..af8b9e80 100644 --- a/BookManager/Model/stock.cs +++ b/BookManager/Model/stock.cs @@ -1,11 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - namespace BookManager.Model { - public class stock + public class Stock { public int idBook { get; set; } public int quantity { get; set; } diff --git a/BookManager/Program.cs b/BookManager/Program.cs index 333eebe6..ab75b292 100644 --- a/BookManager/Program.cs +++ b/BookManager/Program.cs @@ -1,4 +1,5 @@ using BookManager.Data; +using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); @@ -9,11 +10,12 @@ builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); -builder.Services.AddDbContext(options => -{ - //options.useNpgsql(); -}); +builder.Services.AddEntityFrameworkNpgsql() + .AddDbContext(options => + options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))); +// builder.Configuration.GetConnectionString("DefaultConnection") +//"Host=localhost;Port=5432;Pooling=true;Database=book_maneger;User Id=postgres;Password=1234;" var app = builder.Build(); diff --git a/BookManager/Repository/BookRepository.cs b/BookManager/Repository/BookRepository.cs new file mode 100644 index 00000000..fe127ba9 --- /dev/null +++ b/BookManager/Repository/BookRepository.cs @@ -0,0 +1,69 @@ +using BookManager.Data; +using BookManager.Model; +using Microsoft.EntityFrameworkCore; + +namespace BookManager.Repository +{ + public class BookRepository : IBookRepository + { + private readonly DataContext _dataContext; + + public BookRepository(DataContext dataContext) //: base(dataContext) + { + _dataContext = dataContext; + } + + public void Add(T entity) where T : class + { + throw new NotImplementedException(); + } + + public void Delete(T entity) where T : class + { + throw new NotImplementedException(); + } + + public Task SaveChangesAsync() + { + throw new NotImplementedException(); + } + + public void Update(T entity) where T : class + { + throw new NotImplementedException(); + } + + public async Task> GetBookAsync() + { + return await _dataContext.Books + .Select(x => new Book { id = x.id, title = x.title }) + .ToListAsync(); + } + + public async Task GetBooksByIdAsync(int id) + { + var ret = await _dataContext.Books.Where(x => x.id == id).FirstOrDefaultAsync(); + if (ret != null) + { + return ret; + } + return new Book(); + + } + + Task IBookRepository.GetBooksByIdAsync(int id) + { + throw new NotImplementedException(); + } + + + // public async Task GetBooksByIdAsync(int id) + // { + // return await _dataContext.Books.Include(x => x.Books) + // .ThenInclude(c => c.Categorys) + // .ThenInclude(c => c.Publishers) + // .ThenInclude(c => c.Stocks) + // .Where(x => x.id == id).FirstOrDefaultAsync(); + // } + } +} \ No newline at end of file diff --git a/BookManager/Repository/IBaseRepository.cs b/BookManager/Repository/IBaseRepository.cs new file mode 100644 index 00000000..ed5fdd21 --- /dev/null +++ b/BookManager/Repository/IBaseRepository.cs @@ -0,0 +1,10 @@ +namespace BookManager.Repository +{ + public interface IBaseRepository + { + public void Add(T entity) where T : class; + public void Update(T entity) where T : class; + public void Delete(T entity) where T : class; + Task SaveChangesAsync(); + } +} \ No newline at end of file diff --git a/BookManager/Repository/IBookRepository.cs b/BookManager/Repository/IBookRepository.cs new file mode 100644 index 00000000..dfd785c1 --- /dev/null +++ b/BookManager/Repository/IBookRepository.cs @@ -0,0 +1,7 @@ +namespace BookManager.Repository +{ + public interface IBookRepository : IBaseRepository + { + Task GetBooksByIdAsync(int id); + } +} \ No newline at end of file diff --git a/BookManager/appsettings.json b/BookManager/appsettings.json index 4d278e59..980325a8 100644 --- a/BookManager/appsettings.json +++ b/BookManager/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "Default": "User Id; Password= Host=localhost;Porta=5432;database=bookmaneger" + "DefaultConnection": "Host=localhost;Port=5432;Pooling=true;Database=book_maneger;User Id=postgres;Password=1234;" }, "Logging": { From 006a8a1c120e99fbacb21afa6f2ce7be58b7e6d5 Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Wed, 16 Nov 2022 20:30:27 -0300 Subject: [PATCH 04/18] Update scope contexto Entity --- BookManager/Controllers/BooksController.cs | 18 +++++++++--------- BookManager/Program.cs | 3 +++ BookManager/Repository/BookRepository.cs | 6 +----- BookManager/Repository/IBookRepository.cs | 5 ++++- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/BookManager/Controllers/BooksController.cs b/BookManager/Controllers/BooksController.cs index 0d86f83c..c71f352d 100644 --- a/BookManager/Controllers/BooksController.cs +++ b/BookManager/Controllers/BooksController.cs @@ -23,17 +23,17 @@ public IActionResult get() return Ok("ok"); } - // [HttpGet("{id}")] - // public async Task GetById(int id) - // { - // var book = await _repository.GetBooksByIdAsync(id); + [HttpGet("{id}")] + public async Task GetById(int id) + { + var book = await _repository.GetBooksByIdAsync(id); - // // var pacienteRetorno = _mapper.Map(paciente); + // var pacienteRetorno = _mapper.Map(paciente); - // return book != null - // ? Ok(book) - // : BadRequest("Book not found"); - // } + return book != null + ? Ok(book) + : BadRequest("Book not found"); + } [HttpPut] public IActionResult put(int id) { diff --git a/BookManager/Program.cs b/BookManager/Program.cs index ab75b292..6012c631 100644 --- a/BookManager/Program.cs +++ b/BookManager/Program.cs @@ -1,4 +1,5 @@ using BookManager.Data; +using BookManager.Repository; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); @@ -17,6 +18,8 @@ // builder.Configuration.GetConnectionString("DefaultConnection") //"Host=localhost;Port=5432;Pooling=true;Database=book_maneger;User Id=postgres;Password=1234;" +builder.Services.AddScoped(); + var app = builder.Build(); // Configure the HTTP request pipeline. diff --git a/BookManager/Repository/BookRepository.cs b/BookManager/Repository/BookRepository.cs index fe127ba9..1df03cfd 100644 --- a/BookManager/Repository/BookRepository.cs +++ b/BookManager/Repository/BookRepository.cs @@ -33,7 +33,7 @@ public void Update(T entity) where T : class throw new NotImplementedException(); } - public async Task> GetBookAsync() + public async Task> GetBooksAsync() { return await _dataContext.Books .Select(x => new Book { id = x.id, title = x.title }) @@ -51,10 +51,6 @@ public async Task GetBooksByIdAsync(int id) } - Task IBookRepository.GetBooksByIdAsync(int id) - { - throw new NotImplementedException(); - } // public async Task GetBooksByIdAsync(int id) diff --git a/BookManager/Repository/IBookRepository.cs b/BookManager/Repository/IBookRepository.cs index dfd785c1..c51240af 100644 --- a/BookManager/Repository/IBookRepository.cs +++ b/BookManager/Repository/IBookRepository.cs @@ -1,7 +1,10 @@ +using BookManager.Model; + namespace BookManager.Repository { public interface IBookRepository : IBaseRepository { - Task GetBooksByIdAsync(int id); + public Task> GetBooksAsync(); + public Task GetBooksByIdAsync(int id); } } \ No newline at end of file From e9863c313c98d2fe0fa37f446af2a57149dd8af6 Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Thu, 17 Nov 2022 20:26:33 -0300 Subject: [PATCH 05/18] Add context,Entity, Interface --- BookManager/Controllers/BooksController.cs | 24 +++- BookManager/Data/DataContext.cs | 10 +- ...0221117214404_MyFirstMigration.Designer.cs | 136 ++++++++++++++++++ .../20221117214404_MyFirstMigration.cs | 108 ++++++++++++++ .../Migrations/DataContextModelSnapshot.cs | 133 +++++++++++++++++ BookManager/Model/Publisher.cs | 1 - BookManager/Model/Token.cs | 3 +- BookManager/Model/stock.cs | 1 + BookManager/Program.cs | 6 +- BookManager/README.md | 7 + BookManager/Repository/BaseRepository.cs | 35 +++++ BookManager/Repository/BookRepository.cs | 44 +----- .../{ => Interfaces}/IBaseRepository.cs | 2 +- .../{ => Interfaces}/IBookRepository.cs | 2 +- .../Repository/Interfaces/IUserRepository.cs | 7 + BookManager/Repository/UserRepository.cs | 19 +++ BookManager/appsettings.json | 9 +- 17 files changed, 490 insertions(+), 57 deletions(-) create mode 100644 BookManager/Migrations/20221117214404_MyFirstMigration.Designer.cs create mode 100644 BookManager/Migrations/20221117214404_MyFirstMigration.cs create mode 100644 BookManager/Migrations/DataContextModelSnapshot.cs create mode 100644 BookManager/Repository/BaseRepository.cs rename BookManager/Repository/{ => Interfaces}/IBaseRepository.cs (85%) rename BookManager/Repository/{ => Interfaces}/IBookRepository.cs (82%) create mode 100644 BookManager/Repository/Interfaces/IUserRepository.cs create mode 100644 BookManager/Repository/UserRepository.cs diff --git a/BookManager/Controllers/BooksController.cs b/BookManager/Controllers/BooksController.cs index c71f352d..c064798f 100644 --- a/BookManager/Controllers/BooksController.cs +++ b/BookManager/Controllers/BooksController.cs @@ -1,5 +1,5 @@ using BookManager.Model; -using BookManager.Repository; +using BookManager.Repository.Interfaces; using Microsoft.AspNetCore.Mvc; namespace BookManager.Controllers @@ -18,11 +18,16 @@ public BooksController(IBookRepository repository) //TODO:Implementar Entity [HttpGet] - public IActionResult get() + public async Task Get() { - return Ok("ok"); + var books = await _repository.GetBooksAsync(); + + return books.Any() + ? Ok(books) + : BadRequest("Paciente não encontrado."); } + [HttpGet("{id}")] public async Task GetById(int id) { @@ -49,9 +54,18 @@ public IActionResult delete(int id) [HttpPost] - public IActionResult post(Book book) + public async Task Post(Book book) { - return Ok(book); + if (book == null) return BadRequest("Dados Inválidos"); + + // var pacienteAdicionar = _mapper.Map(paciente); + + _repository.Add(book); + + return await _repository.SaveChangesAsync() + ? Ok("Book adicionado com sucesso") + : BadRequest("Erro ao salvar o book"); + } } diff --git a/BookManager/Data/DataContext.cs b/BookManager/Data/DataContext.cs index ea2119d3..ec87619f 100644 --- a/BookManager/Data/DataContext.cs +++ b/BookManager/Data/DataContext.cs @@ -14,11 +14,11 @@ public DataContext(DbContextOptions options) : base(options) public DbSet Stocks { get; set; } public DbSet Users { get; set; } - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly); - } + // protected override void OnModelCreating(ModelBuilder modelBuilder) + // { + // base.OnModelCreating(modelBuilder); + // modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly); + // } } } \ No newline at end of file diff --git a/BookManager/Migrations/20221117214404_MyFirstMigration.Designer.cs b/BookManager/Migrations/20221117214404_MyFirstMigration.Designer.cs new file mode 100644 index 00000000..0e478695 --- /dev/null +++ b/BookManager/Migrations/20221117214404_MyFirstMigration.Designer.cs @@ -0,0 +1,136 @@ +// +using BookManager.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace BookManager.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20221117214404_MyFirstMigration")] + partial class MyFirstMigration + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("BookManager.Model.Book", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("decription") + .HasColumnType("text"); + + b.Property("idAuthor") + .HasColumnType("text"); + + b.Property("idCategory") + .HasColumnType("integer"); + + b.Property("idPublisher") + .HasColumnType("integer"); + + b.Property("isnb") + .HasColumnType("text"); + + b.Property("title") + .HasColumnType("text"); + + b.Property("year") + .HasColumnType("integer"); + + b.HasKey("id"); + + b.ToTable("Books"); + }); + + modelBuilder.Entity("BookManager.Model.Category", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("desciption") + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("Categorys"); + }); + + modelBuilder.Entity("BookManager.Model.Publisher", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("desciption") + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("Publishers"); + }); + + modelBuilder.Entity("BookManager.Model.Stock", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("idBook") + .HasColumnType("integer"); + + b.Property("quantity") + .HasColumnType("integer"); + + b.HasKey("id"); + + b.ToTable("Stocks"); + }); + + modelBuilder.Entity("BookManager.Model.User", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("email") + .HasColumnType("text"); + + b.Property("name") + .HasColumnType("text"); + + b.Property("password") + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/BookManager/Migrations/20221117214404_MyFirstMigration.cs b/BookManager/Migrations/20221117214404_MyFirstMigration.cs new file mode 100644 index 00000000..ffca4847 --- /dev/null +++ b/BookManager/Migrations/20221117214404_MyFirstMigration.cs @@ -0,0 +1,108 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace BookManager.Migrations +{ + /// + public partial class MyFirstMigration : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Books", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + title = table.Column(type: "text", nullable: true), + decription = table.Column(type: "text", nullable: true), + idAuthor = table.Column(type: "text", nullable: true), + idCategory = table.Column(type: "integer", nullable: false), + isnb = table.Column(type: "text", nullable: true), + year = table.Column(type: "integer", nullable: false), + idPublisher = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Books", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "Categorys", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + desciption = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Categorys", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "Publishers", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + desciption = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Publishers", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "Stocks", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + idBook = table.Column(type: "integer", nullable: false), + quantity = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Stocks", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "Users", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + name = table.Column(type: "text", nullable: true), + email = table.Column(type: "text", nullable: true), + password = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Users", x => x.id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Books"); + + migrationBuilder.DropTable( + name: "Categorys"); + + migrationBuilder.DropTable( + name: "Publishers"); + + migrationBuilder.DropTable( + name: "Stocks"); + + migrationBuilder.DropTable( + name: "Users"); + } + } +} diff --git a/BookManager/Migrations/DataContextModelSnapshot.cs b/BookManager/Migrations/DataContextModelSnapshot.cs new file mode 100644 index 00000000..835c0571 --- /dev/null +++ b/BookManager/Migrations/DataContextModelSnapshot.cs @@ -0,0 +1,133 @@ +// +using BookManager.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace BookManager.Migrations +{ + [DbContext(typeof(DataContext))] + partial class DataContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("BookManager.Model.Book", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("decription") + .HasColumnType("text"); + + b.Property("idAuthor") + .HasColumnType("text"); + + b.Property("idCategory") + .HasColumnType("integer"); + + b.Property("idPublisher") + .HasColumnType("integer"); + + b.Property("isnb") + .HasColumnType("text"); + + b.Property("title") + .HasColumnType("text"); + + b.Property("year") + .HasColumnType("integer"); + + b.HasKey("id"); + + b.ToTable("Books"); + }); + + modelBuilder.Entity("BookManager.Model.Category", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("desciption") + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("Categorys"); + }); + + modelBuilder.Entity("BookManager.Model.Publisher", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("desciption") + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("Publishers"); + }); + + modelBuilder.Entity("BookManager.Model.Stock", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("idBook") + .HasColumnType("integer"); + + b.Property("quantity") + .HasColumnType("integer"); + + b.HasKey("id"); + + b.ToTable("Stocks"); + }); + + modelBuilder.Entity("BookManager.Model.User", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("email") + .HasColumnType("text"); + + b.Property("name") + .HasColumnType("text"); + + b.Property("password") + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/BookManager/Model/Publisher.cs b/BookManager/Model/Publisher.cs index fdfe313c..7b21f0b8 100644 --- a/BookManager/Model/Publisher.cs +++ b/BookManager/Model/Publisher.cs @@ -2,7 +2,6 @@ namespace BookManager.Model { public class Publisher { - public int id { get; set; } public string? desciption { get; set; } } diff --git a/BookManager/Model/Token.cs b/BookManager/Model/Token.cs index 5df7bd24..0eded270 100644 --- a/BookManager/Model/Token.cs +++ b/BookManager/Model/Token.cs @@ -1,9 +1,8 @@ -using System; - namespace BookManager.Model { public class Token { + public int id { get; set; } public string? token { get; set; } public DateTime expires { get; set; } } diff --git a/BookManager/Model/stock.cs b/BookManager/Model/stock.cs index af8b9e80..86eb6b1e 100644 --- a/BookManager/Model/stock.cs +++ b/BookManager/Model/stock.cs @@ -2,6 +2,7 @@ namespace BookManager.Model { public class Stock { + public int id { get; set; } public int idBook { get; set; } public int quantity { get; set; } } diff --git a/BookManager/Program.cs b/BookManager/Program.cs index 6012c631..b23080a9 100644 --- a/BookManager/Program.cs +++ b/BookManager/Program.cs @@ -1,5 +1,6 @@ using BookManager.Data; using BookManager.Repository; +using BookManager.Repository.Interfaces; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); @@ -7,7 +8,7 @@ // Add services to the container. builder.Services.AddControllers(); -// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); @@ -15,9 +16,6 @@ .AddDbContext(options => options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))); -// builder.Configuration.GetConnectionString("DefaultConnection") -//"Host=localhost;Port=5432;Pooling=true;Database=book_maneger;User Id=postgres;Password=1234;" - builder.Services.AddScoped(); var app = builder.Build(); diff --git a/BookManager/README.md b/BookManager/README.md index dba83808..52c0398d 100644 --- a/BookManager/README.md +++ b/BookManager/README.md @@ -17,3 +17,10 @@ - Banco Postegre - Migrates - Seeds - Carga + +TODO: FK Migration,seeds + +> dotnet ef migrations add MyFirstMigration --context BloggingContext +> dotnet ef database update --context BloggingContext + +//>Base All diff --git a/BookManager/Repository/BaseRepository.cs b/BookManager/Repository/BaseRepository.cs new file mode 100644 index 00000000..1e37ffa4 --- /dev/null +++ b/BookManager/Repository/BaseRepository.cs @@ -0,0 +1,35 @@ + +using BookManager.Data; +using BookManager.Repository.Interfaces; + +namespace BookManager.Repository +{ + public class BaseRepository : IBaseRepository + { + private readonly DataContext _context; + + public BaseRepository(DataContext context) + { + _context = context; + } + public void Add(T entity) where T : class + { + _context.Add(entity); + } + + public void Delete(T entity) where T : class + { + _context.Remove(entity); + } + + public async Task SaveChangesAsync() + { + return await _context.SaveChangesAsync() > 0; + } + + public void Update(T entity) where T : class + { + _context.Update(entity); + } + } +} \ No newline at end of file diff --git a/BookManager/Repository/BookRepository.cs b/BookManager/Repository/BookRepository.cs index 1df03cfd..fd0c2df7 100644 --- a/BookManager/Repository/BookRepository.cs +++ b/BookManager/Repository/BookRepository.cs @@ -1,48 +1,28 @@ using BookManager.Data; using BookManager.Model; +using BookManager.Repository.Interfaces; using Microsoft.EntityFrameworkCore; namespace BookManager.Repository { - public class BookRepository : IBookRepository + public class BookRepository : BaseRepository, IBookRepository { - private readonly DataContext _dataContext; - - public BookRepository(DataContext dataContext) //: base(dataContext) - { - _dataContext = dataContext; - } - - public void Add(T entity) where T : class + private readonly DataContext _context; + public BookRepository(DataContext context) : base(context) { - throw new NotImplementedException(); - } - - public void Delete(T entity) where T : class - { - throw new NotImplementedException(); - } - - public Task SaveChangesAsync() - { - throw new NotImplementedException(); - } - - public void Update(T entity) where T : class - { - throw new NotImplementedException(); + _context = context; } public async Task> GetBooksAsync() { - return await _dataContext.Books + return await _context.Books .Select(x => new Book { id = x.id, title = x.title }) .ToListAsync(); } public async Task GetBooksByIdAsync(int id) { - var ret = await _dataContext.Books.Where(x => x.id == id).FirstOrDefaultAsync(); + var ret = await _context.Books.Where(x => x.id == id).FirstOrDefaultAsync(); if (ret != null) { return ret; @@ -51,15 +31,5 @@ public async Task GetBooksByIdAsync(int id) } - - - // public async Task GetBooksByIdAsync(int id) - // { - // return await _dataContext.Books.Include(x => x.Books) - // .ThenInclude(c => c.Categorys) - // .ThenInclude(c => c.Publishers) - // .ThenInclude(c => c.Stocks) - // .Where(x => x.id == id).FirstOrDefaultAsync(); - // } } } \ No newline at end of file diff --git a/BookManager/Repository/IBaseRepository.cs b/BookManager/Repository/Interfaces/IBaseRepository.cs similarity index 85% rename from BookManager/Repository/IBaseRepository.cs rename to BookManager/Repository/Interfaces/IBaseRepository.cs index ed5fdd21..5a6fc1a5 100644 --- a/BookManager/Repository/IBaseRepository.cs +++ b/BookManager/Repository/Interfaces/IBaseRepository.cs @@ -1,4 +1,4 @@ -namespace BookManager.Repository +namespace BookManager.Repository.Interfaces { public interface IBaseRepository { diff --git a/BookManager/Repository/IBookRepository.cs b/BookManager/Repository/Interfaces/IBookRepository.cs similarity index 82% rename from BookManager/Repository/IBookRepository.cs rename to BookManager/Repository/Interfaces/IBookRepository.cs index c51240af..d92b1e3e 100644 --- a/BookManager/Repository/IBookRepository.cs +++ b/BookManager/Repository/Interfaces/IBookRepository.cs @@ -1,6 +1,6 @@ using BookManager.Model; -namespace BookManager.Repository +namespace BookManager.Repository.Interfaces { public interface IBookRepository : IBaseRepository { diff --git a/BookManager/Repository/Interfaces/IUserRepository.cs b/BookManager/Repository/Interfaces/IUserRepository.cs new file mode 100644 index 00000000..fce5f7aa --- /dev/null +++ b/BookManager/Repository/Interfaces/IUserRepository.cs @@ -0,0 +1,7 @@ +namespace BookManager.Repository.Interfaces +{ + public interface IUserRepository : IBaseRepository + { + + } +} \ No newline at end of file diff --git a/BookManager/Repository/UserRepository.cs b/BookManager/Repository/UserRepository.cs new file mode 100644 index 00000000..17cb4f4a --- /dev/null +++ b/BookManager/Repository/UserRepository.cs @@ -0,0 +1,19 @@ +using BookManager.Data; +using BookManager.Model; +using BookManager.Repository.Interfaces; +using Microsoft.EntityFrameworkCore; + + +namespace BookManager.Repository +{ + public class UserRepository : BaseRepository, IUserRepository + { + + private readonly DataContext _context; + public UserRepository(DataContext context) : base(context) + { + _context = context; + } + + } +} \ No newline at end of file diff --git a/BookManager/appsettings.json b/BookManager/appsettings.json index 980325a8..b4b66303 100644 --- a/BookManager/appsettings.json +++ b/BookManager/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "DefaultConnection": "Host=localhost;Port=5432;Pooling=true;Database=book_maneger;User Id=postgres;Password=1234;" + "DefaultConnection": "Host=localhost;Port=5432;Pooling=true;Database=db_book_manager;User Id=playfast;Password=playfast01;" }, "Logging": { @@ -11,3 +11,10 @@ }, "AllowedHosts": "*" } + +// # Database Settings +// DB_HOST=localhost +// DB_PORT=5432 +// DB_USER=playfast +// DB_PASSWORD=playfast01 +// DB_DATABASE=playfast From f6034f86bc47d733a565e343eff213d80b8a3d19 Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Fri, 18 Nov 2022 20:50:18 -0300 Subject: [PATCH 06/18] Add Create token --- BookManager/BookManager.csproj | 4 ++ BookManager/Model/User.cs | 1 + BookManager/Program.cs | 60 +++++++++++++++- BookManager/README.md | 2 +- BookManager/Services/JWTService.cs | 104 +++++++++++++++++++++++++++ BookManager/Services/Settins.cs | 7 ++ BookManager/Services/TokenService.cs | 69 ++++++++++++++++++ 7 files changed, 244 insertions(+), 3 deletions(-) create mode 100644 BookManager/Services/JWTService.cs create mode 100644 BookManager/Services/Settins.cs create mode 100644 BookManager/Services/TokenService.cs diff --git a/BookManager/BookManager.csproj b/BookManager/BookManager.csproj index 9fd14795..82d94e45 100644 --- a/BookManager/BookManager.csproj +++ b/BookManager/BookManager.csproj @@ -4,9 +4,11 @@ net6.0 enable enable + enable + runtime; build; native; contentfiles; analyzers; buildtransitive @@ -19,6 +21,8 @@ + + diff --git a/BookManager/Model/User.cs b/BookManager/Model/User.cs index 33072a03..c13e72ac 100644 --- a/BookManager/Model/User.cs +++ b/BookManager/Model/User.cs @@ -6,5 +6,6 @@ public class User public string? name { get; set; } public string? email { get; set; } public string? password { get; set; } + public string? role { get; set; } } } \ No newline at end of file diff --git a/BookManager/Program.cs b/BookManager/Program.cs index b23080a9..54a471e8 100644 --- a/BookManager/Program.cs +++ b/BookManager/Program.cs @@ -2,20 +2,73 @@ using BookManager.Repository; using BookManager.Repository.Interfaces; using Microsoft.EntityFrameworkCore; +using System.Text.Json.Serialization; +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; + var builder = WebApplication.CreateBuilder(args); // Add services to the container. -builder.Services.AddControllers(); +//builder.Services.AddControllers(); + +builder.Services.AddControllers().AddJsonOptions(options => +{ + options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; +}); builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); +//builder.Services.AddSwaggerGen(); +builder.Services.AddSwaggerGen(c => +{ + c.SwaggerDoc("v1", new OpenApiInfo { Title = "APIContagem", Version = "v1" }); + + c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + Description = + "JWT Authorization Header - utilizado com Bearer Authentication.\r\n\r\n" + + "Digite 'Bearer' [espaço] e então seu token no campo abaixo.\r\n\r\n" + + "Exemplo (informar sem as aspas): 'Bearer 12345abcdef'", + Name = "Authorization", + In = ParameterLocation.Header, + Type = SecuritySchemeType.ApiKey, + Scheme = "Bearer", + BearerFormat = "JWT", + }); + + c.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "Bearer" + } + }, + Array.Empty() + } + }); +}); builder.Services.AddEntityFrameworkNpgsql() .AddDbContext(options => options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))); +//TODO: + +// var tokenConfigurations = new TokenConfigurations(); +// new ConfigureFromConfigurationOptions( +// builder.Configuration.GetSection("TokenConfigurations")) +// .Configure(tokenConfigurations); + +// // Aciona a extensão que irá configurar o uso de +// // autenticação e autorização via tokens +// builder.Services.AddJwtSecurity(tokenConfigurations); + + builder.Services.AddScoped(); var app = builder.Build(); @@ -29,6 +82,9 @@ app.UseHttpsRedirection(); + + + app.UseAuthorization(); app.MapControllers(); diff --git a/BookManager/README.md b/BookManager/README.md index 52c0398d..d2aeddf4 100644 --- a/BookManager/README.md +++ b/BookManager/README.md @@ -18,7 +18,7 @@ - Migrates - Seeds - Carga -TODO: FK Migration,seeds +TODO: FK Migration,seeds,id incremental > dotnet ef migrations add MyFirstMigration --context BloggingContext > dotnet ef database update --context BloggingContext diff --git a/BookManager/Services/JWTService.cs b/BookManager/Services/JWTService.cs new file mode 100644 index 00000000..f6f485b2 --- /dev/null +++ b/BookManager/Services/JWTService.cs @@ -0,0 +1,104 @@ +// using System; +// using System.Collections.Generic; +// using System.Security.Claims; +// using Microsoft.IdentityModel.Tokens; +// using System.IdentityModel.Tokens.Jwt; +// using VegeFood.Models.JWTModels; +// using Microsoft.Extensions.Options; + +// namespace VegeFood.Services.JWTServices +// { +// public class JWTService: IAuthService +// { +// public string SecretKey { get; set; } +// public JWTService(string secretKey) +// { +// SecretKey = secretKey; +// } + +// public bool IsTokenValid(string token) +// { +// if (string.IsNullOrEmpty(token)) +// throw new ArgumentException("Given token is null or empty."); +// TokenValidationParameters tokenValidationParameters = GetTokenValidationParameters(); +// JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); +// try +// { +// ClaimsPrincipal tokenValid = jwtSecurityTokenHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken); +// return true; +// } +// catch (Exception) +// { +// return false; +// } +// } + +// public string GenerateToken(IAuthContainerModel model) +// { +// if (model == null || model.Claims == null || model.Claims.Length == 0) +// throw new ArgumentException("Arguments to create token are not valid."); + +// SecurityTokenDescriptor securityTokenDescriptor = new SecurityTokenDescriptor +// { +// Subject = new ClaimsIdentity(model.Claims), +// Expires = DateTime.UtcNow.AddMinutes(Convert.ToInt32(model.ExpireMinutes)), +// SigningCredentials = new SigningCredentials(GetSymmetricSecurityKey(), model.SecurityAlgorithm) +// }; + +// JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); +// SecurityToken securityToken = jwtSecurityTokenHandler.CreateToken(securityTokenDescriptor); +// string token = jwtSecurityTokenHandler.WriteToken(securityToken); +// return token; +// } + +// public IEnumerable GetTokenClaims(string token) +// { +// if (string.IsNullOrEmpty(token)) +// throw new ArgumentException("Given token is null or empty."); + +// TokenValidationParameters tokenValidationParameters = GetTokenValidationParameters(); + +// JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); +// try +// { +// ClaimsPrincipal tokenValid = jwtSecurityTokenHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken); +// return tokenValid.Claims; +// } +// catch (Exception ex) +// { +// throw ex; +// } +// } + +// private SecurityKey GetSymmetricSecurityKey() +// { +// byte[] symmetricKey = Convert.FromBase64String(SecretKey); +// return new SymmetricSecurityKey(symmetricKey); +// } + +// private TokenValidationParameters GetTokenValidationParameters() +// { +// return new TokenValidationParameters() +// { +// ValidateIssuer = false, +// ValidateAudience = false, +// IssuerSigningKey = GetSymmetricSecurityKey() +// }; +// } +// } + +// public static class JWTHelper +// { +// public static JWTContainerModel GetJWTContainerModel(string username, string password, IOptions config) +// { +// return new JWTContainerModel(config) +// { +// Claims = new Claim[] +// { +// new Claim("Password", password), +// new Claim(ClaimTypes.Name, username) +// } +// }; +// } +// } +// } \ No newline at end of file diff --git a/BookManager/Services/Settins.cs b/BookManager/Services/Settins.cs new file mode 100644 index 00000000..58af3b5d --- /dev/null +++ b/BookManager/Services/Settins.cs @@ -0,0 +1,7 @@ +namespace BookManager.Services +{ + public static class Settins + { + public static string secret = "3NzaC1yc2EAAAADAQABAAABAQCXsM9ycbHV6E6t2"; + } +} \ No newline at end of file diff --git a/BookManager/Services/TokenService.cs b/BookManager/Services/TokenService.cs new file mode 100644 index 00000000..935c9cdb --- /dev/null +++ b/BookManager/Services/TokenService.cs @@ -0,0 +1,69 @@ +using System.Text; +using BookManager.Model; + +// namespace BookManager.Services +// { +// public static class TokenService +// { + +// public static string generateToken(User user) +// { +// var tokenHandler = new JwtSecurityTokenHandler(); +// var key = Encoding.ASCII.GetBytes(Settins.secret); +// var TokenDescriptor = new SecurityTokenDescriptor +// { +// expires=DateTime.UtcNow.AddHours(1), +// signingCredentials( new SymmetricSecuritYKey(key), SecurityAlgorithms.) +// } +// } + + +// } +// } + +//using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +// using System.Text; +// // using Blog.Extensions; +// // using Blog.Models; +// using Microsoft.IdentityModel.Tokens; + +using System.IdentityModel.Tokens.Jwt; +using Microsoft.IdentityModel.Tokens; + + +namespace BookManager.Services; + +public class TokenService +{ + public string GenerateToken(User user) + { + var tokenHandler = new JwtSecurityTokenHandler(); + var key = Encoding.ASCII.GetBytes(Settins.secret); + + var tokenDescriptor = new SecurityTokenDescriptor + { + Subject = this.GetClaims(user), + Expires = DateTime.UtcNow.AddHours(8), + SigningCredentials = new SigningCredentials( + new SymmetricSecurityKey(key), + SecurityAlgorithms.HmacSha256Signature) + }; + var token = tokenHandler.CreateToken(tokenDescriptor); + return tokenHandler.WriteToken(token); + } + + private ClaimsIdentity GetClaims(User user) + { + //todo: + + + var obj = new ClaimsIdentity(new[] + { + new Claim(ClaimTypes.Name,user.name.ToString()), + new Claim(ClaimTypes.Email,user.email.ToString()), + new Claim(ClaimTypes.Role,user.role.ToString()) + }); + return obj; + } +} \ No newline at end of file From a19dd2dd2f95a50e417be77a5eae711f137a3f40 Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Sat, 19 Nov 2022 15:14:08 -0300 Subject: [PATCH 07/18] Refactory Clear code --- BookManager/Controllers/AuthContoller.cs | 39 ++++++++++++-- BookManager/Controllers/BooksController.cs | 42 ++++++++------- BookManager/Model/Book.cs | 5 ++ BookManager/Model/Credential.cs | 10 ++-- BookManager/Model/User.cs | 19 ++++++- BookManager/Program.cs | 15 ++---- BookManager/README.md | 7 +++ .../Repository/Interfaces/IUserRepository.cs | 4 +- BookManager/Repository/UserRepository.cs | 17 ++++++ BookManager/Services/TokenService.cs | 52 +++++-------------- 10 files changed, 132 insertions(+), 78 deletions(-) diff --git a/BookManager/Controllers/AuthContoller.cs b/BookManager/Controllers/AuthContoller.cs index f0d5672a..cd9359f3 100644 --- a/BookManager/Controllers/AuthContoller.cs +++ b/BookManager/Controllers/AuthContoller.cs @@ -1,4 +1,6 @@ using BookManager.Model; +using BookManager.Repository.Interfaces; +using BookManager.Services; using Microsoft.AspNetCore.Mvc; namespace BookManager.Controllers @@ -7,12 +9,43 @@ namespace BookManager.Controllers [Route("api/[controller]")] public class AuthController : ControllerBase { + + private readonly IUserRepository repository; + + public AuthController(IUserRepository pRepository) + { + repository = pRepository; + } + [HttpPost] - public Token login(Credential param) + public async Task login(Credential param) { - //TODO:Implementar JWT - return new Token() { token = "dddd" }; + var user = await repository.login(param); + if (user != null && string.IsNullOrWhiteSpace(user.name)) + { + Token token = new TokenService().GenerateToken(user); + return Ok(token); + } + else + { + + return BadRequest("Book not found"); + } + } + + // [HttpPost] + // public async Task signup1(User param) + // { + // repository.Add(param); + + // return await repository.SaveChangesAsync() + // ? Ok("Uaser adicionado com sucesso") + // : BadRequest("Erro ao salvar o Usuario"); + + // } + + } } \ No newline at end of file diff --git a/BookManager/Controllers/BooksController.cs b/BookManager/Controllers/BooksController.cs index c064798f..e434ccbd 100644 --- a/BookManager/Controllers/BooksController.cs +++ b/BookManager/Controllers/BooksController.cs @@ -9,18 +9,17 @@ namespace BookManager.Controllers public class BooksController : ControllerBase { - private readonly IBookRepository _repository; - // private readonly IMapper _mapper; - public BooksController(IBookRepository repository) + private readonly IBookRepository repository; + + public BooksController(IBookRepository pRepository) { - _repository = repository; + repository = pRepository; } - //TODO:Implementar Entity [HttpGet] public async Task Get() { - var books = await _repository.GetBooksAsync(); + var books = await repository.GetBooksAsync(); return books.Any() ? Ok(books) @@ -31,25 +30,34 @@ public async Task Get() [HttpGet("{id}")] public async Task GetById(int id) { - var book = await _repository.GetBooksByIdAsync(id); - - // var pacienteRetorno = _mapper.Map(paciente); - + var book = await repository.GetBooksByIdAsync(id); return book != null ? Ok(book) : BadRequest("Book not found"); } [HttpPut] - public IActionResult put(int id) + public async Task put(Book book) { - return Ok("ok"); + if (book == null) return BadRequest("Dados Inválidos"); + + repository.Update(book); + + return await repository.SaveChangesAsync() + ? Ok("Book adicionado com sucesso") + : BadRequest("Erro ao salvar o book"); } [HttpDelete] - public IActionResult delete(int id) + public async Task delete(Book book) { - return Ok("ok"); + repository.Delete(book); + + return await repository.SaveChangesAsync() + ? Ok("Book adicionado com sucesso") + : BadRequest("Erro ao salvar o book"); + + } @@ -58,11 +66,9 @@ public async Task Post(Book book) { if (book == null) return BadRequest("Dados Inválidos"); - // var pacienteAdicionar = _mapper.Map(paciente); - - _repository.Add(book); + repository.Add(book); - return await _repository.SaveChangesAsync() + return await repository.SaveChangesAsync() ? Ok("Book adicionado com sucesso") : BadRequest("Erro ao salvar o book"); diff --git a/BookManager/Model/Book.cs b/BookManager/Model/Book.cs index 47065e79..86634ba9 100644 --- a/BookManager/Model/Book.cs +++ b/BookManager/Model/Book.cs @@ -1,7 +1,12 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + namespace BookManager.Model { public class Book { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int id { get; set; } public string? title { get; set; } public string? decription { get; set; } diff --git a/BookManager/Model/Credential.cs b/BookManager/Model/Credential.cs index 15227fa3..83bb6412 100644 --- a/BookManager/Model/Credential.cs +++ b/BookManager/Model/Credential.cs @@ -2,8 +2,12 @@ namespace BookManager.Model { public class Credential { - - public string? email { get; set; } - public string? password { get; set; } + public Credential() + { + email = string.Empty; + password = string.Empty; + } + public string email { get; set; } + public string password { get; set; } } } diff --git a/BookManager/Model/User.cs b/BookManager/Model/User.cs index c13e72ac..38be1c8a 100644 --- a/BookManager/Model/User.cs +++ b/BookManager/Model/User.cs @@ -1,11 +1,26 @@ +using System.ComponentModel.DataAnnotations; + namespace BookManager.Model { public class User { + + public User() + { + email = string.Empty; + password = string.Empty; + role = string.Empty; + } + + [Key] public int id { get; set; } + [Required] public string? name { get; set; } - public string? email { get; set; } - public string? password { get; set; } + [Required] + public string email { get; set; } + [Required] + public string password { get; set; } + [Required] public string? role { get; set; } } } \ No newline at end of file diff --git a/BookManager/Program.cs b/BookManager/Program.cs index 54a471e8..5a1c31ff 100644 --- a/BookManager/Program.cs +++ b/BookManager/Program.cs @@ -18,6 +18,9 @@ options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; }); + +builder.Services.AddControllers(); + builder.Services.AddEndpointsApiExplorer(); //builder.Services.AddSwaggerGen(); builder.Services.AddSwaggerGen(c => @@ -57,18 +60,6 @@ .AddDbContext(options => options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))); -//TODO: - -// var tokenConfigurations = new TokenConfigurations(); -// new ConfigureFromConfigurationOptions( -// builder.Configuration.GetSection("TokenConfigurations")) -// .Configure(tokenConfigurations); - -// // Aciona a extensão que irá configurar o uso de -// // autenticação e autorização via tokens -// builder.Services.AddJwtSecurity(tokenConfigurations); - - builder.Services.AddScoped(); var app = builder.Build(); diff --git a/BookManager/README.md b/BookManager/README.md index d2aeddf4..395ecf63 100644 --- a/BookManager/README.md +++ b/BookManager/README.md @@ -24,3 +24,10 @@ TODO: FK Migration,seeds,id incremental > dotnet ef database update --context BloggingContext //>Base All + + +https://www.youtube.com/watch?v=vAUXU0YIWlU +https://github.com/renatogroffe/ASPNETCore6-REST_API-JWT-Postman_ContagemAcessos/blob/main/APIContagem/Program.cs + +https://www.youtube.com/watch?v=ccVmPgxNE6c + diff --git a/BookManager/Repository/Interfaces/IUserRepository.cs b/BookManager/Repository/Interfaces/IUserRepository.cs index fce5f7aa..db420c62 100644 --- a/BookManager/Repository/Interfaces/IUserRepository.cs +++ b/BookManager/Repository/Interfaces/IUserRepository.cs @@ -1,7 +1,9 @@ +using BookManager.Model; + namespace BookManager.Repository.Interfaces { public interface IUserRepository : IBaseRepository { - + public Task login(Credential credential); } } \ No newline at end of file diff --git a/BookManager/Repository/UserRepository.cs b/BookManager/Repository/UserRepository.cs index 17cb4f4a..b530ae1b 100644 --- a/BookManager/Repository/UserRepository.cs +++ b/BookManager/Repository/UserRepository.cs @@ -15,5 +15,22 @@ public UserRepository(DataContext context) : base(context) _context = context; } + + public async Task login(Credential credential) + { + + + + var ret = await _context.Users.Where(user => user.email.ToLower().Trim().Equals(credential.email.ToLower().Trim()) && + user.password.Equals(credential.password)).FirstOrDefaultAsync(); + if (ret != null) + { + ret.password = string.Empty; + return ret; + } + return new User(); + + } + } } \ No newline at end of file diff --git a/BookManager/Services/TokenService.cs b/BookManager/Services/TokenService.cs index 935c9cdb..c1e71525 100644 --- a/BookManager/Services/TokenService.cs +++ b/BookManager/Services/TokenService.cs @@ -1,68 +1,42 @@ using System.Text; using BookManager.Model; - -// namespace BookManager.Services -// { -// public static class TokenService -// { - -// public static string generateToken(User user) -// { -// var tokenHandler = new JwtSecurityTokenHandler(); -// var key = Encoding.ASCII.GetBytes(Settins.secret); -// var TokenDescriptor = new SecurityTokenDescriptor -// { -// expires=DateTime.UtcNow.AddHours(1), -// signingCredentials( new SymmetricSecuritYKey(key), SecurityAlgorithms.) -// } -// } - - -// } -// } - -//using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; -// using System.Text; -// // using Blog.Extensions; -// // using Blog.Models; -// using Microsoft.IdentityModel.Tokens; - using System.IdentityModel.Tokens.Jwt; using Microsoft.IdentityModel.Tokens; - - namespace BookManager.Services; public class TokenService { - public string GenerateToken(User user) + public Token GenerateToken(User user) { var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes(Settins.secret); - + var token = new Token(); + token.expires = DateTime.UtcNow.AddHours(8); var tokenDescriptor = new SecurityTokenDescriptor { Subject = this.GetClaims(user), - Expires = DateTime.UtcNow.AddHours(8), + Expires = token.expires, SigningCredentials = new SigningCredentials( new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) }; - var token = tokenHandler.CreateToken(tokenDescriptor); - return tokenHandler.WriteToken(token); + var tokenKey = tokenHandler.CreateToken(tokenDescriptor); + token.token = tokenHandler.WriteToken(tokenKey); + return token; } private ClaimsIdentity GetClaims(User user) { - //todo: - + string name = string.IsNullOrWhiteSpace(user.name) ? string.Empty : user.name; + string email = string.IsNullOrWhiteSpace(user.email) ? string.Empty : user.email; + string role = string.IsNullOrWhiteSpace(user.role) ? string.Empty : user.role; var obj = new ClaimsIdentity(new[] { - new Claim(ClaimTypes.Name,user.name.ToString()), - new Claim(ClaimTypes.Email,user.email.ToString()), - new Claim(ClaimTypes.Role,user.role.ToString()) + new Claim(ClaimTypes.Name,name), + new Claim(ClaimTypes.Email,email), + new Claim(ClaimTypes.Role,role) }); return obj; } From c53cae7dc15b3e384bc43d0193ae2242b817665b Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Sat, 19 Nov 2022 17:14:04 -0300 Subject: [PATCH 08/18] Add validacao --- BookManager/Controllers/AuthContoller.cs | 41 +++-- BookManager/Controllers/BooksController.cs | 45 ++++-- ...221119183036_MyFirstMigration2.Designer.cs | 143 +++++++++++++++++ .../20221119183036_MyFirstMigration2.cs | 83 ++++++++++ ...221119184147_MyFirstMigration3.Designer.cs | 147 ++++++++++++++++++ .../20221119184147_MyFirstMigration3.cs | 93 +++++++++++ .../Migrations/DataContextModelSnapshot.cs | 15 +- BookManager/Model/Book.cs | 26 +++- BookManager/Model/User.cs | 7 +- BookManager/Model/stock.cs | 8 + BookManager/Program.cs | 1 + BookManager/README.md | 4 +- BookManager/Repository/BookRepository.cs | 9 ++ .../Repository/Interfaces/IBookRepository.cs | 1 + .../Repository/Interfaces/IUserRepository.cs | 1 + BookManager/Repository/UserRepository.cs | 11 +- 16 files changed, 601 insertions(+), 34 deletions(-) create mode 100644 BookManager/Migrations/20221119183036_MyFirstMigration2.Designer.cs create mode 100644 BookManager/Migrations/20221119183036_MyFirstMigration2.cs create mode 100644 BookManager/Migrations/20221119184147_MyFirstMigration3.Designer.cs create mode 100644 BookManager/Migrations/20221119184147_MyFirstMigration3.cs diff --git a/BookManager/Controllers/AuthContoller.cs b/BookManager/Controllers/AuthContoller.cs index cd9359f3..eba144e0 100644 --- a/BookManager/Controllers/AuthContoller.cs +++ b/BookManager/Controllers/AuthContoller.cs @@ -1,6 +1,7 @@ using BookManager.Model; using BookManager.Repository.Interfaces; using BookManager.Services; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace BookManager.Controllers @@ -17,11 +18,18 @@ public AuthController(IUserRepository pRepository) repository = pRepository; } - [HttpPost] + [AllowAnonymous] + [HttpPost("login")] public async Task login(Credential param) { + if (param == null || + string.IsNullOrWhiteSpace(param.email) || + string.IsNullOrWhiteSpace(param.password)) + return BadRequest("Dados Inválidos"); + var user = await repository.login(param); - if (user != null && string.IsNullOrWhiteSpace(user.name)) + + if (user != null && !string.IsNullOrWhiteSpace(user.name)) { Token token = new TokenService().GenerateToken(user); return Ok(token); @@ -29,22 +37,33 @@ public async Task login(Credential param) else { - return BadRequest("Book not found"); + return BadRequest("User not found."); } } - // [HttpPost] - // public async Task signup1(User param) - // { - // repository.Add(param); + [AllowAnonymous] + [HttpPost("signup")] + public async Task signup(User user) + { + + if (user == null || + string.IsNullOrWhiteSpace(user.name) || + string.IsNullOrWhiteSpace(user.email) || + string.IsNullOrWhiteSpace(user.password) || + string.IsNullOrWhiteSpace(user.role)) + return BadRequest("Dados Inválidos"); + if (await repository.checkUserExists(user)) + return BadRequest("User exists."); + + repository.Add(user); - // return await repository.SaveChangesAsync() - // ? Ok("Uaser adicionado com sucesso") - // : BadRequest("Erro ao salvar o Usuario"); + return await repository.SaveChangesAsync() + ? Ok("User adicionado com sucesso") + : BadRequest("Erro ao salvar o Usuario"); - // } + } } diff --git a/BookManager/Controllers/BooksController.cs b/BookManager/Controllers/BooksController.cs index e434ccbd..09f0ab6a 100644 --- a/BookManager/Controllers/BooksController.cs +++ b/BookManager/Controllers/BooksController.cs @@ -1,5 +1,6 @@ using BookManager.Model; using BookManager.Repository.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace BookManager.Controllers @@ -15,18 +16,26 @@ public BooksController(IBookRepository pRepository) { repository = pRepository; } - + [AllowAnonymous] [HttpGet] public async Task Get() { var books = await repository.GetBooksAsync(); + if (books != null && books.Any()) + { + books = books.OrderByDescending(b => b.title); + return Ok(books); + } + else + { + return NotFound("Books not exiists"); - return books.Any() - ? Ok(books) - : BadRequest("Paciente não encontrado."); - } + } + } + + [AllowAnonymous] [HttpGet("{id}")] public async Task GetById(int id) { @@ -35,6 +44,7 @@ public async Task GetById(int id) ? Ok(book) : BadRequest("Book not found"); } + [Authorize] [HttpPut] public async Task put(Book book) { @@ -47,7 +57,7 @@ public async Task put(Book book) : BadRequest("Erro ao salvar o book"); } - + [Authorize] [HttpDelete] public async Task delete(Book book) { @@ -60,12 +70,29 @@ public async Task delete(Book book) } - + [Authorize] [HttpPost] public async Task Post(Book book) { - if (book == null) return BadRequest("Dados Inválidos"); - + if (book == null || + string.IsNullOrWhiteSpace(book.title) || + string.IsNullOrWhiteSpace(book.Author) || + string.IsNullOrWhiteSpace(book.decription) || + string.IsNullOrWhiteSpace(book.isnb) || + string.IsNullOrWhiteSpace(book.Author) || + book.idCategory <= 0 || + book.idPublisher <= 0 || + book.year <= 0 + ) + { + return BadRequest("Dados Inválidos"); + } + + var checkExists = await repository.bookCheckExists(book); + if (checkExists) + { + return BadRequest("Book exists."); + } repository.Add(book); return await repository.SaveChangesAsync() diff --git a/BookManager/Migrations/20221119183036_MyFirstMigration2.Designer.cs b/BookManager/Migrations/20221119183036_MyFirstMigration2.Designer.cs new file mode 100644 index 00000000..46caa275 --- /dev/null +++ b/BookManager/Migrations/20221119183036_MyFirstMigration2.Designer.cs @@ -0,0 +1,143 @@ +// +using BookManager.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace BookManager.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20221119183036_MyFirstMigration2")] + partial class MyFirstMigration2 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("BookManager.Model.Book", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("decription") + .HasColumnType("text"); + + b.Property("idAuthor") + .HasColumnType("text"); + + b.Property("idCategory") + .HasColumnType("integer"); + + b.Property("idPublisher") + .HasColumnType("integer"); + + b.Property("isnb") + .HasColumnType("text"); + + b.Property("title") + .HasColumnType("text"); + + b.Property("year") + .HasColumnType("integer"); + + b.HasKey("id"); + + b.ToTable("Books"); + }); + + modelBuilder.Entity("BookManager.Model.Category", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("desciption") + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("Categorys"); + }); + + modelBuilder.Entity("BookManager.Model.Publisher", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("desciption") + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("Publishers"); + }); + + modelBuilder.Entity("BookManager.Model.Stock", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("idBook") + .HasColumnType("integer"); + + b.Property("quantity") + .HasColumnType("integer"); + + b.HasKey("id"); + + b.ToTable("Stocks"); + }); + + modelBuilder.Entity("BookManager.Model.User", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("email") + .IsRequired() + .HasColumnType("text"); + + b.Property("name") + .IsRequired() + .HasColumnType("text"); + + b.Property("password") + .IsRequired() + .HasColumnType("text"); + + b.Property("role") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/BookManager/Migrations/20221119183036_MyFirstMigration2.cs b/BookManager/Migrations/20221119183036_MyFirstMigration2.cs new file mode 100644 index 00000000..21ba31c0 --- /dev/null +++ b/BookManager/Migrations/20221119183036_MyFirstMigration2.cs @@ -0,0 +1,83 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace BookManager.Migrations +{ + /// + public partial class MyFirstMigration2 : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "password", + table: "Users", + type: "text", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "name", + table: "Users", + type: "text", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "email", + table: "Users", + type: "text", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AddColumn( + name: "role", + table: "Users", + type: "text", + nullable: false, + defaultValue: ""); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "role", + table: "Users"); + + migrationBuilder.AlterColumn( + name: "password", + table: "Users", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.AlterColumn( + name: "name", + table: "Users", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.AlterColumn( + name: "email", + table: "Users", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "text"); + } + } +} diff --git a/BookManager/Migrations/20221119184147_MyFirstMigration3.Designer.cs b/BookManager/Migrations/20221119184147_MyFirstMigration3.Designer.cs new file mode 100644 index 00000000..f05892aa --- /dev/null +++ b/BookManager/Migrations/20221119184147_MyFirstMigration3.Designer.cs @@ -0,0 +1,147 @@ +// +using BookManager.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace BookManager.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20221119184147_MyFirstMigration3")] + partial class MyFirstMigration3 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("BookManager.Model.Book", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("Author") + .IsRequired() + .HasColumnType("text"); + + b.Property("decription") + .IsRequired() + .HasColumnType("text"); + + b.Property("idCategory") + .HasColumnType("integer"); + + b.Property("idPublisher") + .HasColumnType("integer"); + + b.Property("isnb") + .IsRequired() + .HasColumnType("text"); + + b.Property("title") + .IsRequired() + .HasColumnType("text"); + + b.Property("year") + .HasColumnType("integer"); + + b.HasKey("id"); + + b.ToTable("Books"); + }); + + modelBuilder.Entity("BookManager.Model.Category", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("desciption") + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("Categorys"); + }); + + modelBuilder.Entity("BookManager.Model.Publisher", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("desciption") + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("Publishers"); + }); + + modelBuilder.Entity("BookManager.Model.Stock", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("idBook") + .HasColumnType("integer"); + + b.Property("quantity") + .HasColumnType("integer"); + + b.HasKey("id"); + + b.ToTable("Stocks"); + }); + + modelBuilder.Entity("BookManager.Model.User", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("email") + .IsRequired() + .HasColumnType("text"); + + b.Property("name") + .IsRequired() + .HasColumnType("text"); + + b.Property("password") + .IsRequired() + .HasColumnType("text"); + + b.Property("role") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/BookManager/Migrations/20221119184147_MyFirstMigration3.cs b/BookManager/Migrations/20221119184147_MyFirstMigration3.cs new file mode 100644 index 00000000..b50b9e5a --- /dev/null +++ b/BookManager/Migrations/20221119184147_MyFirstMigration3.cs @@ -0,0 +1,93 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace BookManager.Migrations +{ + /// + public partial class MyFirstMigration3 : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "idAuthor", + table: "Books"); + + migrationBuilder.AlterColumn( + name: "title", + table: "Books", + type: "text", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "isnb", + table: "Books", + type: "text", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "decription", + table: "Books", + type: "text", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AddColumn( + name: "Author", + table: "Books", + type: "text", + nullable: false, + defaultValue: ""); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Author", + table: "Books"); + + migrationBuilder.AlterColumn( + name: "title", + table: "Books", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.AlterColumn( + name: "isnb", + table: "Books", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.AlterColumn( + name: "decription", + table: "Books", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.AddColumn( + name: "idAuthor", + table: "Books", + type: "text", + nullable: true); + } + } +} diff --git a/BookManager/Migrations/DataContextModelSnapshot.cs b/BookManager/Migrations/DataContextModelSnapshot.cs index 835c0571..5c5f76af 100644 --- a/BookManager/Migrations/DataContextModelSnapshot.cs +++ b/BookManager/Migrations/DataContextModelSnapshot.cs @@ -29,10 +29,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); - b.Property("decription") + b.Property("Author") + .IsRequired() .HasColumnType("text"); - b.Property("idAuthor") + b.Property("decription") + .IsRequired() .HasColumnType("text"); b.Property("idCategory") @@ -42,9 +44,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("integer"); b.Property("isnb") + .IsRequired() .HasColumnType("text"); b.Property("title") + .IsRequired() .HasColumnType("text"); b.Property("year") @@ -115,12 +119,19 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); b.Property("email") + .IsRequired() .HasColumnType("text"); b.Property("name") + .IsRequired() .HasColumnType("text"); b.Property("password") + .IsRequired() + .HasColumnType("text"); + + b.Property("role") + .IsRequired() .HasColumnType("text"); b.HasKey("id"); diff --git a/BookManager/Model/Book.cs b/BookManager/Model/Book.cs index 86634ba9..04528411 100644 --- a/BookManager/Model/Book.cs +++ b/BookManager/Model/Book.cs @@ -5,15 +5,33 @@ namespace BookManager.Model { public class Book { + + public Book() + { + title = string.Empty; + decription = string.Empty; + Author = string.Empty; + title = string.Empty; + isnb = string.Empty; + } + + [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int id { get; set; } - public string? title { get; set; } - public string? decription { get; set; } - public string? idAuthor { get; set; } + [Required] + public string title { get; set; } + [Required] + public string decription { get; set; } + [Required] + public string Author { get; set; } + [Required] public int idCategory { get; set; } - public string? isnb { get; set; } + [Required] + public string isnb { get; set; } + [Required] public int year { get; set; } + [Required] public int idPublisher { get; set; } } diff --git a/BookManager/Model/User.cs b/BookManager/Model/User.cs index 38be1c8a..c96e2b8d 100644 --- a/BookManager/Model/User.cs +++ b/BookManager/Model/User.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace BookManager.Model { @@ -7,20 +8,22 @@ public class User public User() { + name = string.Empty; email = string.Empty; password = string.Empty; role = string.Empty; } [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int id { get; set; } [Required] - public string? name { get; set; } + public string name { get; set; } [Required] public string email { get; set; } [Required] public string password { get; set; } [Required] - public string? role { get; set; } + public string role { get; set; } } } \ No newline at end of file diff --git a/BookManager/Model/stock.cs b/BookManager/Model/stock.cs index 86eb6b1e..6e90012d 100644 --- a/BookManager/Model/stock.cs +++ b/BookManager/Model/stock.cs @@ -1,9 +1,17 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + namespace BookManager.Model { public class Stock { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [Required] public int id { get; set; } + [Required] public int idBook { get; set; } + [Required] public int quantity { get; set; } } } \ No newline at end of file diff --git a/BookManager/Program.cs b/BookManager/Program.cs index 5a1c31ff..65cb7a6e 100644 --- a/BookManager/Program.cs +++ b/BookManager/Program.cs @@ -61,6 +61,7 @@ options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))); builder.Services.AddScoped(); +builder.Services.AddScoped(); var app = builder.Build(); diff --git a/BookManager/README.md b/BookManager/README.md index 395ecf63..756fe26b 100644 --- a/BookManager/README.md +++ b/BookManager/README.md @@ -20,14 +20,12 @@ TODO: FK Migration,seeds,id incremental -> dotnet ef migrations add MyFirstMigration --context BloggingContext +> dotnet ef migrations add MyFirstMigration --context DataContext > dotnet ef database update --context BloggingContext //>Base All - https://www.youtube.com/watch?v=vAUXU0YIWlU https://github.com/renatogroffe/ASPNETCore6-REST_API-JWT-Postman_ContagemAcessos/blob/main/APIContagem/Program.cs https://www.youtube.com/watch?v=ccVmPgxNE6c - diff --git a/BookManager/Repository/BookRepository.cs b/BookManager/Repository/BookRepository.cs index fd0c2df7..191c60f5 100644 --- a/BookManager/Repository/BookRepository.cs +++ b/BookManager/Repository/BookRepository.cs @@ -31,5 +31,14 @@ public async Task GetBooksByIdAsync(int id) } + + + public async Task bookCheckExists(Book book) + { + var ret = await _context.Books.Where(x => x.isnb == book.isnb).ToListAsync(); + return (ret != null && ret.Any()); + + } + } } \ No newline at end of file diff --git a/BookManager/Repository/Interfaces/IBookRepository.cs b/BookManager/Repository/Interfaces/IBookRepository.cs index d92b1e3e..444fd68c 100644 --- a/BookManager/Repository/Interfaces/IBookRepository.cs +++ b/BookManager/Repository/Interfaces/IBookRepository.cs @@ -6,5 +6,6 @@ public interface IBookRepository : IBaseRepository { public Task> GetBooksAsync(); public Task GetBooksByIdAsync(int id); + public Task bookCheckExists(Book book); } } \ No newline at end of file diff --git a/BookManager/Repository/Interfaces/IUserRepository.cs b/BookManager/Repository/Interfaces/IUserRepository.cs index db420c62..0f28fcb5 100644 --- a/BookManager/Repository/Interfaces/IUserRepository.cs +++ b/BookManager/Repository/Interfaces/IUserRepository.cs @@ -5,5 +5,6 @@ namespace BookManager.Repository.Interfaces public interface IUserRepository : IBaseRepository { public Task login(Credential credential); + public Task checkUserExists(User user); } } \ No newline at end of file diff --git a/BookManager/Repository/UserRepository.cs b/BookManager/Repository/UserRepository.cs index b530ae1b..5c754374 100644 --- a/BookManager/Repository/UserRepository.cs +++ b/BookManager/Repository/UserRepository.cs @@ -18,9 +18,6 @@ public UserRepository(DataContext context) : base(context) public async Task login(Credential credential) { - - - var ret = await _context.Users.Where(user => user.email.ToLower().Trim().Equals(credential.email.ToLower().Trim()) && user.password.Equals(credential.password)).FirstOrDefaultAsync(); if (ret != null) @@ -32,5 +29,13 @@ public async Task login(Credential credential) } + public async Task checkUserExists(User user) + { + if (user == null || string.IsNullOrWhiteSpace(user.email)) return false; + string email = user.email.Trim().ToLower(); + var ret = await _context.Users.Where(user => user.email.Equals(email)).ToListAsync(); + return (ret == null || !ret.Any()); + } + } } \ No newline at end of file From 7fa5ce245db1448cff0a732ccfb8b8095ccecb9a Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Sat, 19 Nov 2022 19:47:29 -0300 Subject: [PATCH 09/18] Add app Factoryo --- BookManager/Controllers/AuthContoller.cs | 7 ++ BookManager/Controllers/BooksController.cs | 2 +- BookManager/Model/Category.cs | 4 + BookManager/Model/Credential.cs | 5 + BookManager/Model/Publisher.cs | 5 + BookManager/Model/Token.cs | 5 +- BookManager/Program.cs | 31 +++++- BookManager/README.md | 29 +++--- BookManager/Services/JWTService.cs | 104 --------------------- BookManager/Services/TokenService.cs | 58 +++++++++++- BookManager/appsettings.json | 9 +- 11 files changed, 123 insertions(+), 136 deletions(-) delete mode 100644 BookManager/Services/JWTService.cs diff --git a/BookManager/Controllers/AuthContoller.cs b/BookManager/Controllers/AuthContoller.cs index eba144e0..38e6b2e7 100644 --- a/BookManager/Controllers/AuthContoller.cs +++ b/BookManager/Controllers/AuthContoller.cs @@ -3,6 +3,7 @@ using BookManager.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; namespace BookManager.Controllers { @@ -25,10 +26,16 @@ public async Task login(Credential param) if (param == null || string.IsNullOrWhiteSpace(param.email) || string.IsNullOrWhiteSpace(param.password)) + { + //Logger.LogInformation("Dados Inválidos"); return BadRequest("Dados Inválidos"); + } + var user = await repository.login(param); + + if (user != null && !string.IsNullOrWhiteSpace(user.name)) { Token token = new TokenService().GenerateToken(user); diff --git a/BookManager/Controllers/BooksController.cs b/BookManager/Controllers/BooksController.cs index 09f0ab6a..b4368bdd 100644 --- a/BookManager/Controllers/BooksController.cs +++ b/BookManager/Controllers/BooksController.cs @@ -23,7 +23,7 @@ public async Task Get() var books = await repository.GetBooksAsync(); if (books != null && books.Any()) { - books = books.OrderByDescending(b => b.title); + books = books.OrderBy(b => b.title); return Ok(books); } else diff --git a/BookManager/Model/Category.cs b/BookManager/Model/Category.cs index c31d69e4..1d33b7fa 100644 --- a/BookManager/Model/Category.cs +++ b/BookManager/Model/Category.cs @@ -1,8 +1,12 @@ +using System.ComponentModel.DataAnnotations; + namespace BookManager.Model { public class Category { + [Required] public int id { get; set; } + [Required] public string? desciption { get; set; } } } \ No newline at end of file diff --git a/BookManager/Model/Credential.cs b/BookManager/Model/Credential.cs index 83bb6412..10e71222 100644 --- a/BookManager/Model/Credential.cs +++ b/BookManager/Model/Credential.cs @@ -1,3 +1,5 @@ +using System.ComponentModel.DataAnnotations; + namespace BookManager.Model { public class Credential @@ -7,7 +9,10 @@ public Credential() email = string.Empty; password = string.Empty; } + + [Required] public string email { get; set; } + [Required] public string password { get; set; } } } diff --git a/BookManager/Model/Publisher.cs b/BookManager/Model/Publisher.cs index 7b21f0b8..414a91e5 100644 --- a/BookManager/Model/Publisher.cs +++ b/BookManager/Model/Publisher.cs @@ -1,8 +1,13 @@ +using System.ComponentModel.DataAnnotations; + namespace BookManager.Model { public class Publisher { + + [Required] public int id { get; set; } + [Required] public string? desciption { get; set; } } } \ No newline at end of file diff --git a/BookManager/Model/Token.cs b/BookManager/Model/Token.cs index 0eded270..a63de91c 100644 --- a/BookManager/Model/Token.cs +++ b/BookManager/Model/Token.cs @@ -1,9 +1,12 @@ +using System.ComponentModel.DataAnnotations; + namespace BookManager.Model { public class Token { - public int id { get; set; } + [Required] public string? token { get; set; } + [Required] public DateTime expires { get; set; } } } \ No newline at end of file diff --git a/BookManager/Program.cs b/BookManager/Program.cs index 65cb7a6e..a18dad9e 100644 --- a/BookManager/Program.cs +++ b/BookManager/Program.cs @@ -5,9 +5,14 @@ using System.Text.Json.Serialization; using Microsoft.Extensions.Options; using Microsoft.OpenApi.Models; - +using System.Text; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.IdentityModel.Tokens; +using BookManager.Services; var builder = WebApplication.CreateBuilder(args); +ConfigureAuthentication(builder); + // Add services to the container. @@ -25,7 +30,7 @@ //builder.Services.AddSwaggerGen(); builder.Services.AddSwaggerGen(c => { - c.SwaggerDoc("v1", new OpenApiInfo { Title = "APIContagem", Version = "v1" }); + c.SwaggerDoc("v1", new OpenApiInfo { Title = "APIBookManager", Version = "v1" }); c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { @@ -76,9 +81,29 @@ - +app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run(); + +void ConfigureAuthentication(WebApplicationBuilder builder) +{ + var key = Encoding.ASCII.GetBytes(Settins.secret); + builder.Services.AddAuthentication(x => + { + x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }).AddJwtBearer(x => + { + x.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(key), + ValidateIssuer = false, + ValidateAudience = false + }; + }); +} + diff --git a/BookManager/README.md b/BookManager/README.md index 756fe26b..294b02b5 100644 --- a/BookManager/README.md +++ b/BookManager/README.md @@ -5,27 +5,20 @@ - Modelagem DR -OK - Swagger - OK - Jwt -OK +- gitignore -OK +- injeção de dependencia -ok +- Princípio de responsabilidade única -ok +- Entity -ok +- Crud-OK +- Banco Pstegre -ok +- Migrates -ok +- Seeds - Carga +- Log - SOLID - Factory - Singleton -- gitignore -- injeção de dependencia -- Princípio de responsabilidade única -- Entity -- Crud -- Log -- Banco Postegre -- Migrates -- Seeds - Carga - -TODO: FK Migration,seeds,id incremental +- TDD +- VIDEO > dotnet ef migrations add MyFirstMigration --context DataContext > dotnet ef database update --context BloggingContext - -//>Base All - -https://www.youtube.com/watch?v=vAUXU0YIWlU -https://github.com/renatogroffe/ASPNETCore6-REST_API-JWT-Postman_ContagemAcessos/blob/main/APIContagem/Program.cs - -https://www.youtube.com/watch?v=ccVmPgxNE6c diff --git a/BookManager/Services/JWTService.cs b/BookManager/Services/JWTService.cs deleted file mode 100644 index f6f485b2..00000000 --- a/BookManager/Services/JWTService.cs +++ /dev/null @@ -1,104 +0,0 @@ -// using System; -// using System.Collections.Generic; -// using System.Security.Claims; -// using Microsoft.IdentityModel.Tokens; -// using System.IdentityModel.Tokens.Jwt; -// using VegeFood.Models.JWTModels; -// using Microsoft.Extensions.Options; - -// namespace VegeFood.Services.JWTServices -// { -// public class JWTService: IAuthService -// { -// public string SecretKey { get; set; } -// public JWTService(string secretKey) -// { -// SecretKey = secretKey; -// } - -// public bool IsTokenValid(string token) -// { -// if (string.IsNullOrEmpty(token)) -// throw new ArgumentException("Given token is null or empty."); -// TokenValidationParameters tokenValidationParameters = GetTokenValidationParameters(); -// JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); -// try -// { -// ClaimsPrincipal tokenValid = jwtSecurityTokenHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken); -// return true; -// } -// catch (Exception) -// { -// return false; -// } -// } - -// public string GenerateToken(IAuthContainerModel model) -// { -// if (model == null || model.Claims == null || model.Claims.Length == 0) -// throw new ArgumentException("Arguments to create token are not valid."); - -// SecurityTokenDescriptor securityTokenDescriptor = new SecurityTokenDescriptor -// { -// Subject = new ClaimsIdentity(model.Claims), -// Expires = DateTime.UtcNow.AddMinutes(Convert.ToInt32(model.ExpireMinutes)), -// SigningCredentials = new SigningCredentials(GetSymmetricSecurityKey(), model.SecurityAlgorithm) -// }; - -// JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); -// SecurityToken securityToken = jwtSecurityTokenHandler.CreateToken(securityTokenDescriptor); -// string token = jwtSecurityTokenHandler.WriteToken(securityToken); -// return token; -// } - -// public IEnumerable GetTokenClaims(string token) -// { -// if (string.IsNullOrEmpty(token)) -// throw new ArgumentException("Given token is null or empty."); - -// TokenValidationParameters tokenValidationParameters = GetTokenValidationParameters(); - -// JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); -// try -// { -// ClaimsPrincipal tokenValid = jwtSecurityTokenHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken); -// return tokenValid.Claims; -// } -// catch (Exception ex) -// { -// throw ex; -// } -// } - -// private SecurityKey GetSymmetricSecurityKey() -// { -// byte[] symmetricKey = Convert.FromBase64String(SecretKey); -// return new SymmetricSecurityKey(symmetricKey); -// } - -// private TokenValidationParameters GetTokenValidationParameters() -// { -// return new TokenValidationParameters() -// { -// ValidateIssuer = false, -// ValidateAudience = false, -// IssuerSigningKey = GetSymmetricSecurityKey() -// }; -// } -// } - -// public static class JWTHelper -// { -// public static JWTContainerModel GetJWTContainerModel(string username, string password, IOptions config) -// { -// return new JWTContainerModel(config) -// { -// Claims = new Claim[] -// { -// new Claim("Password", password), -// new Claim(ClaimTypes.Name, username) -// } -// }; -// } -// } -// } \ No newline at end of file diff --git a/BookManager/Services/TokenService.cs b/BookManager/Services/TokenService.cs index c1e71525..951626f2 100644 --- a/BookManager/Services/TokenService.cs +++ b/BookManager/Services/TokenService.cs @@ -40,4 +40,60 @@ private ClaimsIdentity GetClaims(User user) }); return obj; } -} \ No newline at end of file + + + + + public bool IsTokenValid(string token) + { + if (string.IsNullOrEmpty(token)) + throw new ArgumentException("Given token is null or empty."); + TokenValidationParameters tokenValidationParameters = GetTokenValidationParameters(); + JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); + try + { + ClaimsPrincipal tokenValid = jwtSecurityTokenHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken); + return true; + } + catch (Exception) + { + return false; + } + } + + // public IEnumerable GetTokenClaims(string token) + // { + // if (string.IsNullOrEmpty(token)) + // throw new ArgumentException("Given token is null or empty."); + + // TokenValidationParameters tokenValidationParameters = GetTokenValidationParameters(); + + // JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); + // try + // { + // ClaimsPrincipal tokenValid = jwtSecurityTokenHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken); + // return tokenValid.Claims; + // } + // catch (Exception ex) + // { + // throw ex; + // } + // } + + private SecurityKey GetSymmetricSecurityKey() + { + byte[] symmetricKey = Convert.FromBase64String(Settins.secret); + return new SymmetricSecurityKey(symmetricKey); + } + + private TokenValidationParameters GetTokenValidationParameters() + { + return new TokenValidationParameters() + { + ValidateIssuer = false, + ValidateAudience = false, + IssuerSigningKey = GetSymmetricSecurityKey() + }; + } +} + diff --git a/BookManager/appsettings.json b/BookManager/appsettings.json index b4b66303..67843815 100644 --- a/BookManager/appsettings.json +++ b/BookManager/appsettings.json @@ -2,7 +2,7 @@ "ConnectionStrings": { "DefaultConnection": "Host=localhost;Port=5432;Pooling=true;Database=db_book_manager;User Id=playfast;Password=playfast01;" }, - + "JwtKey": "ZmVkYWY3ZDg4NjNiNDhlMTk3YjkyODdkNDkyYjcwOGU=", "Logging": { "LogLevel": { "Default": "Information", @@ -11,10 +11,3 @@ }, "AllowedHosts": "*" } - -// # Database Settings -// DB_HOST=localhost -// DB_PORT=5432 -// DB_USER=playfast -// DB_PASSWORD=playfast01 -// DB_DATABASE=playfast From 2a2f5be387704946cfe79d059af53e674132dbac Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Mon, 21 Nov 2022 09:32:46 -0300 Subject: [PATCH 10/18] Add load and seeds --- BookManager/Controllers/BooksController.cs | 235 ++++++++++++++---- BookManager/Data/DataContext.cs | 110 +++++++- .../20221121002120_Migration4.Designer.cs | 222 +++++++++++++++++ .../Migrations/20221121002120_Migration4.cs | 175 +++++++++++++ .../Migrations/DataContextModelSnapshot.cs | 79 +++++- BookManager/Model/Book.cs | 16 +- BookManager/Model/BookFilter.cs | 19 ++ BookManager/Model/CustomLog.cs | 24 ++ BookManager/Program.cs | 4 +- BookManager/README.md | 21 +- BookManager/Repository/BookRepository.cs | 52 +++- BookManager/Repository/CostomLogRepository.cs | 16 ++ .../Repository/Interfaces/IBookRepository.cs | 4 + .../Interfaces/ICostomLogRepository.cs | 8 + BookManager/Services/CustonLogServices.cs | 25 ++ BookManager/appsettings.json | 4 +- 16 files changed, 939 insertions(+), 75 deletions(-) create mode 100644 BookManager/Migrations/20221121002120_Migration4.Designer.cs create mode 100644 BookManager/Migrations/20221121002120_Migration4.cs create mode 100644 BookManager/Model/BookFilter.cs create mode 100644 BookManager/Model/CustomLog.cs create mode 100644 BookManager/Repository/CostomLogRepository.cs create mode 100644 BookManager/Repository/Interfaces/ICostomLogRepository.cs create mode 100644 BookManager/Services/CustonLogServices.cs diff --git a/BookManager/Controllers/BooksController.cs b/BookManager/Controllers/BooksController.cs index b4368bdd..68d087fe 100644 --- a/BookManager/Controllers/BooksController.cs +++ b/BookManager/Controllers/BooksController.cs @@ -11,95 +11,240 @@ public class BooksController : ControllerBase { private readonly IBookRepository repository; + private readonly ICostomLogRepository costomLogRepository; - public BooksController(IBookRepository pRepository) + public BooksController(IBookRepository pRepository, ICostomLogRepository pCostomLogRepository) { repository = pRepository; + costomLogRepository = pCostomLogRepository; } [AllowAnonymous] [HttpGet] public async Task Get() { - var books = await repository.GetBooksAsync(); - if (books != null && books.Any()) + + try { - books = books.OrderBy(b => b.title); - return Ok(books); + var books = await repository.GetBooksAsync(); + if (books != null && books.Any()) + { + return Ok(books); + } + else + { + return NotFound("Books not exiists"); + } } - else + catch (Exception ex) { - return NotFound("Books not exiists"); - + logger("Get", ex.ToString()); + return BadRequest(ex.Message); } + } + [AllowAnonymous] + [HttpGet("skip/{skip:int}/take/{take:int}/name/{name}")] + public async Task GetFilter( + [FromRoute] int skip, + [FromRoute] int take, + [FromRoute] string name) + { + try + { + var books = await repository.GetFilter(skip, take, name); + if (books != null && books.Any()) + { + return Ok(books); + } + else + { + return NotFound("Books not exiists"); + } + } + catch (Exception ex) + { + logger("Get", ex.ToString()); + return BadRequest(ex.Message); + } } + [AllowAnonymous] - [HttpGet("{id}")] + [HttpGet("id/{id:int}")] public async Task GetById(int id) { - var book = await repository.GetBooksByIdAsync(id); - return book != null - ? Ok(book) - : BadRequest("Book not found"); + try + { + var book = await repository.GetBooksByIdAsync(id); + return book != null + ? Ok(book) + : BadRequest("Book not found"); + } + catch (Exception ex) + { + logger("Get", ex.ToString()); + return BadRequest(ex.Message); + } } + + [Authorize] [HttpPut] public async Task put(Book book) { - if (book == null) return BadRequest("Dados Inválidos"); - repository.Update(book); + try + { + if (book == null) return BadRequest("Dados Inválidos"); + + var bookDB = await repository.GetBooksByIdAsync(book.id); + if (string.IsNullOrWhiteSpace(book.decription)) + { + bookDB.decription = book.decription; + } + if (string.IsNullOrWhiteSpace(book.author)) + { + bookDB.author = book.author; + } + if (string.IsNullOrWhiteSpace(book.name)) + { + bookDB.name = book.name; + } + if (string.IsNullOrWhiteSpace(book.isnb)) + { + bookDB.isnb = book.isnb; + } + repository.Update(bookDB); + + return await repository.SaveChangesAsync() + ? Ok("Book adicionado com sucesso") + : BadRequest("Erro ao salvar o book"); + } + catch (Exception ex) + { + logger("Get", ex.ToString()); + return BadRequest(ex.Message); + } - return await repository.SaveChangesAsync() - ? Ok("Book adicionado com sucesso") - : BadRequest("Erro ao salvar o book"); } [Authorize] - [HttpDelete] - public async Task delete(Book book) + [HttpDelete("id/{id:int}")] + public async Task delete(int id) { - repository.Delete(book); - - return await repository.SaveChangesAsync() - ? Ok("Book adicionado com sucesso") - : BadRequest("Erro ao salvar o book"); - + try + { + var book = await repository.GetBooksByIdAsync(id); + repository.Delete(book); + return await repository.SaveChangesAsync() + ? Ok("Book excluido com sucesso.") + : BadRequest("Erro ao excluir o book."); + } + catch (Exception ex) + { + logger("Get", ex.ToString()); + return BadRequest(ex.Message); + } } - [Authorize] + [HttpPost] public async Task Post(Book book) { - if (book == null || - string.IsNullOrWhiteSpace(book.title) || - string.IsNullOrWhiteSpace(book.Author) || - string.IsNullOrWhiteSpace(book.decription) || - string.IsNullOrWhiteSpace(book.isnb) || - string.IsNullOrWhiteSpace(book.Author) || - book.idCategory <= 0 || - book.idPublisher <= 0 || - book.year <= 0 - ) + try + { + if (book == null || + string.IsNullOrWhiteSpace(book.name) || + string.IsNullOrWhiteSpace(book.decription) || + string.IsNullOrWhiteSpace(book.isnb) || + string.IsNullOrWhiteSpace(book.author) || + book.idCategory <= 0 || + book.idPublisher <= 0 || + book.year <= 0 + ) + { + return BadRequest("Dados Inválidos"); + } + + var checkExists = await repository.bookCheckExists(book); + if (checkExists) + { + return BadRequest("Book exists."); + } + repository.Add(book); + + return await repository.SaveChangesAsync() + ? Ok("Book adicionado com sucesso") + : BadRequest("Erro ao salvar o book"); + } + catch (Exception ex) { - return BadRequest("Dados Inválidos"); + logger("Get", ex.ToString()); + return BadRequest(ex.Message); } - var checkExists = await repository.bookCheckExists(book); - if (checkExists) + + } + + [AllowAnonymous] + [HttpGet("load/qtd/{qtd:int}")] + public async Task load(int qtd) + { + try { - return BadRequest("Book exists."); + bool controle = false; + if (qtd > 1000) + return BadRequest("Maximo 1000"); + + int max = await repository.getMaxIdBook(); + for (int i = max + 1; i < (qtd + max + 1); i++) + { + var book = new Book + { + + name = $"Nome Book {i}", + decription = $"Description book {i}", + author = "author", + idCategory = 1, + isnb = $"9999{i}", + year = 2004, + idPublisher = 1, + exemplary = i + }; + repository.Add(book); + + } + controle = await repository.SaveChangesAsync(); + return controle + ? Ok("Load com sucesso") + : BadRequest("Erro"); + } + catch (Exception ex) + { + logger("Get", ex.ToString()); + return BadRequest(ex.Message); + } + + } + + private void logger(string pOperation, string pTrace) + { + try + { + var log = new CustomLog() { operation = pOperation, trace = pTrace, createAt = DateTime.Now }; + costomLogRepository.Add(log); + costomLogRepository.SaveChangesAsync(); + } + catch + { + //não sobe, grava no event viwer } - repository.Add(book); - return await repository.SaveChangesAsync() - ? Ok("Book adicionado com sucesso") - : BadRequest("Erro ao salvar o book"); } + } } \ No newline at end of file diff --git a/BookManager/Data/DataContext.cs b/BookManager/Data/DataContext.cs index ec87619f..cb21c3f0 100644 --- a/BookManager/Data/DataContext.cs +++ b/BookManager/Data/DataContext.cs @@ -13,12 +13,112 @@ public DataContext(DbContextOptions options) : base(options) public DbSet Books { get; set; } public DbSet Stocks { get; set; } public DbSet Users { get; set; } + public DbSet CustomLogs { get; set; } - // protected override void OnModelCreating(ModelBuilder modelBuilder) - // { - // base.OnModelCreating(modelBuilder); - // modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly); - // } + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + //base.OnModelCreating(modelBuilder); + //modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly); + + modelBuilder.Entity().HasData( + new User + { + id = 5, + name = "Marcos Simões", + email = "Marcos@gmail.com", + password = "dat@s35", + role = "ADM" + }, + new User + { + id = 6, + name = "Dantas Rocha", + email = "optedev@gmail.com", + password = "dat@s35", + role = "ADM" + } + ); + + modelBuilder.Entity().HasData( + new Category + { + id = 1, + desciption = "Livro Tecnico" + }, + new Category + { + id = 2, + desciption = "Livro Informatica" + } + ); + modelBuilder.Entity().HasData( + new Publisher + { + id = 1, + desciption = "Editora Books" + }, + new Publisher + { + id = 2, + desciption = "EditoraBookman" + } + ); + // modelBuilder.Entity().HasData( + // new Book + // { + // name = "Clean Code", + // decription = "Clean Code Agil", + // author = "", + // idCategory = 1, + // isnb = "111111111", + // year = 2004, + // idPublisher = 1, + // exemplary = 1 + + // }, + // new Book + // { + // name = "Refactory", + // decription = "Refactory", + // author = "", + // idCategory = 1, + // isnb = "111111112", + // year = 2004, + // idPublisher = 2, + // exemplary = 1 + // }, + // new Book + // { + // name = "Clean Code", + // decription = "Clean Code Agil", + // author = "", + // idCategory = 1, + // isnb = "111111113", + // year = 2004, + // idPublisher = 1, + // exemplary = 1 + // } + // ); + + // modelBuilder.Entity().HasData( + // new Stock + // { + // idBook = 1, + // quantity = 1000 + // }, + // new Stock + // { + // idBook = 2, + // quantity = 1000 + // }, + // new Stock + // { + // idBook = 3, + // quantity = 1000 + // } + // ); + + } } } \ No newline at end of file diff --git a/BookManager/Migrations/20221121002120_Migration4.Designer.cs b/BookManager/Migrations/20221121002120_Migration4.Designer.cs new file mode 100644 index 00000000..6b9b0662 --- /dev/null +++ b/BookManager/Migrations/20221121002120_Migration4.Designer.cs @@ -0,0 +1,222 @@ +// +using System; +using BookManager.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace BookManager.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20221121002120_Migration4")] + partial class Migration4 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("BookManager.Model.Book", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("author") + .IsRequired() + .HasColumnType("text"); + + b.Property("createAt") + .HasColumnType("timestamp with time zone"); + + b.Property("decription") + .IsRequired() + .HasColumnType("text"); + + b.Property("exemplary") + .HasColumnType("integer"); + + b.Property("idCategory") + .HasColumnType("integer"); + + b.Property("idPublisher") + .HasColumnType("integer"); + + b.Property("isnb") + .IsRequired() + .HasColumnType("text"); + + b.Property("name") + .IsRequired() + .HasColumnType("text"); + + b.Property("year") + .HasColumnType("integer"); + + b.HasKey("id"); + + b.ToTable("Books"); + }); + + modelBuilder.Entity("BookManager.Model.Category", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("desciption") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("Categorys"); + + b.HasData( + new + { + id = 1, + desciption = "Livro Tecnico" + }, + new + { + id = 2, + desciption = "Livro Informatica" + }); + }); + + modelBuilder.Entity("BookManager.Model.CustomLog", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("createAt") + .HasColumnType("timestamp with time zone"); + + b.Property("operation") + .IsRequired() + .HasColumnType("text"); + + b.Property("trace") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("CustomLogs"); + }); + + modelBuilder.Entity("BookManager.Model.Publisher", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("desciption") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("Publishers"); + + b.HasData( + new + { + id = 1, + desciption = "Editora Books" + }, + new + { + id = 2, + desciption = "EditoraBookman" + }); + }); + + modelBuilder.Entity("BookManager.Model.Stock", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("idBook") + .HasColumnType("integer"); + + b.Property("quantity") + .HasColumnType("integer"); + + b.HasKey("id"); + + b.ToTable("Stocks"); + }); + + modelBuilder.Entity("BookManager.Model.User", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("email") + .IsRequired() + .HasColumnType("text"); + + b.Property("name") + .IsRequired() + .HasColumnType("text"); + + b.Property("password") + .IsRequired() + .HasColumnType("text"); + + b.Property("role") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("Users"); + + b.HasData( + new + { + id = 5, + email = "Marcos@gmail.com", + name = "Marcos Simões", + password = "dat@s35", + role = "ADM" + }, + new + { + id = 6, + email = "optedev@gmail.com", + name = "Dantas Rocha", + password = "dat@s35", + role = "ADM" + }); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/BookManager/Migrations/20221121002120_Migration4.cs b/BookManager/Migrations/20221121002120_Migration4.cs new file mode 100644 index 00000000..9867ff1e --- /dev/null +++ b/BookManager/Migrations/20221121002120_Migration4.cs @@ -0,0 +1,175 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace BookManager.Migrations +{ + /// + public partial class Migration4 : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "Author", + table: "Books", + newName: "author"); + + migrationBuilder.RenameColumn( + name: "title", + table: "Books", + newName: "name"); + + migrationBuilder.AlterColumn( + name: "desciption", + table: "Publishers", + type: "text", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "desciption", + table: "Categorys", + type: "text", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AddColumn( + name: "createAt", + table: "Books", + type: "timestamp with time zone", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + + migrationBuilder.AddColumn( + name: "exemplary", + table: "Books", + type: "integer", + nullable: false, + defaultValue: 0); + + migrationBuilder.CreateTable( + name: "CustomLogs", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + operation = table.Column(type: "text", nullable: false), + trace = table.Column(type: "text", nullable: false), + createAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CustomLogs", x => x.id); + }); + + migrationBuilder.InsertData( + table: "Categorys", + columns: new[] { "id", "desciption" }, + values: new object[,] + { + { 1, "Livro Tecnico" }, + { 2, "Livro Informatica" } + }); + + migrationBuilder.InsertData( + table: "Publishers", + columns: new[] { "id", "desciption" }, + values: new object[,] + { + { 1, "Editora Books" }, + { 2, "EditoraBookman" } + }); + + migrationBuilder.InsertData( + table: "Users", + columns: new[] { "id", "email", "name", "password", "role" }, + values: new object[,] + { + { 5, "Marcos@gmail.com", "Marcos Simões", "dat@s35", "ADM" }, + { 6, "optedev@gmail.com", "Dantas Rocha", "dat@s35", "ADM" } + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CustomLogs"); + + migrationBuilder.DeleteData( + table: "Categorys", + keyColumn: "id", + keyValue: 1); + + migrationBuilder.DeleteData( + table: "Categorys", + keyColumn: "id", + keyValue: 2); + + migrationBuilder.DeleteData( + table: "Publishers", + keyColumn: "id", + keyValue: 1); + + migrationBuilder.DeleteData( + table: "Publishers", + keyColumn: "id", + keyValue: 2); + + migrationBuilder.DeleteData( + table: "Users", + keyColumn: "id", + keyValue: 5); + + migrationBuilder.DeleteData( + table: "Users", + keyColumn: "id", + keyValue: 6); + + migrationBuilder.DropColumn( + name: "createAt", + table: "Books"); + + migrationBuilder.DropColumn( + name: "exemplary", + table: "Books"); + + migrationBuilder.RenameColumn( + name: "author", + table: "Books", + newName: "Author"); + + migrationBuilder.RenameColumn( + name: "name", + table: "Books", + newName: "title"); + + migrationBuilder.AlterColumn( + name: "desciption", + table: "Publishers", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.AlterColumn( + name: "desciption", + table: "Categorys", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "text"); + } + } +} diff --git a/BookManager/Migrations/DataContextModelSnapshot.cs b/BookManager/Migrations/DataContextModelSnapshot.cs index 5c5f76af..9e47f75b 100644 --- a/BookManager/Migrations/DataContextModelSnapshot.cs +++ b/BookManager/Migrations/DataContextModelSnapshot.cs @@ -1,4 +1,5 @@ // +using System; using BookManager.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -29,14 +30,20 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); - b.Property("Author") + b.Property("author") .IsRequired() .HasColumnType("text"); + b.Property("createAt") + .HasColumnType("timestamp with time zone"); + b.Property("decription") .IsRequired() .HasColumnType("text"); + b.Property("exemplary") + .HasColumnType("integer"); + b.Property("idCategory") .HasColumnType("integer"); @@ -47,7 +54,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired() .HasColumnType("text"); - b.Property("title") + b.Property("name") .IsRequired() .HasColumnType("text"); @@ -68,11 +75,48 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); b.Property("desciption") + .IsRequired() .HasColumnType("text"); b.HasKey("id"); b.ToTable("Categorys"); + + b.HasData( + new + { + id = 1, + desciption = "Livro Tecnico" + }, + new + { + id = 2, + desciption = "Livro Informatica" + }); + }); + + modelBuilder.Entity("BookManager.Model.CustomLog", b => + { + b.Property("id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); + + b.Property("createAt") + .HasColumnType("timestamp with time zone"); + + b.Property("operation") + .IsRequired() + .HasColumnType("text"); + + b.Property("trace") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("id"); + + b.ToTable("CustomLogs"); }); modelBuilder.Entity("BookManager.Model.Publisher", b => @@ -84,11 +128,24 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("id")); b.Property("desciption") + .IsRequired() .HasColumnType("text"); b.HasKey("id"); b.ToTable("Publishers"); + + b.HasData( + new + { + id = 1, + desciption = "Editora Books" + }, + new + { + id = 2, + desciption = "EditoraBookman" + }); }); modelBuilder.Entity("BookManager.Model.Stock", b => @@ -137,6 +194,24 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("id"); b.ToTable("Users"); + + b.HasData( + new + { + id = 5, + email = "Marcos@gmail.com", + name = "Marcos Simões", + password = "dat@s35", + role = "ADM" + }, + new + { + id = 6, + email = "optedev@gmail.com", + name = "Dantas Rocha", + password = "dat@s35", + role = "ADM" + }); }); #pragma warning restore 612, 618 } diff --git a/BookManager/Model/Book.cs b/BookManager/Model/Book.cs index 04528411..d2c9bdc3 100644 --- a/BookManager/Model/Book.cs +++ b/BookManager/Model/Book.cs @@ -8,10 +8,9 @@ public class Book public Book() { - title = string.Empty; + name = string.Empty; decription = string.Empty; - Author = string.Empty; - title = string.Empty; + author = string.Empty; isnb = string.Empty; } @@ -20,11 +19,11 @@ public Book() [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int id { get; set; } [Required] - public string title { get; set; } + public string name { get; set; } [Required] public string decription { get; set; } [Required] - public string Author { get; set; } + public string author { get; set; } [Required] public int idCategory { get; set; } [Required] @@ -33,6 +32,13 @@ public Book() public int year { get; set; } [Required] public int idPublisher { get; set; } + [Required] + public DateTime createAt { get; set; } + + [Required] + public int exemplary { get; set; } + + } } \ No newline at end of file diff --git a/BookManager/Model/BookFilter.cs b/BookManager/Model/BookFilter.cs new file mode 100644 index 00000000..36ec8eb7 --- /dev/null +++ b/BookManager/Model/BookFilter.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; + +namespace BookManager.Model +{ + public class BookFilter + { + public BookFilter() + { + name = string.Empty; + decription = string.Empty; + author = string.Empty; + } + public string? name { get; set; } + public string? decription { get; set; } + public string? author { get; set; } + + + } +} diff --git a/BookManager/Model/CustomLog.cs b/BookManager/Model/CustomLog.cs new file mode 100644 index 00000000..27a9193c --- /dev/null +++ b/BookManager/Model/CustomLog.cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace BookManager.Model +{ + public class CustomLog + { + public CustomLog() + { + operation = string.Empty; + trace = string.Empty; + } + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int id { get; set; } + [Required] + public string operation { get; set; } + [Required] + public string trace { get; set; } + [Required] + public DateTime createAt { get; set; } + + } +} \ No newline at end of file diff --git a/BookManager/Program.cs b/BookManager/Program.cs index a18dad9e..1357da64 100644 --- a/BookManager/Program.cs +++ b/BookManager/Program.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using BookManager.Services; +using BookManager.Model; var builder = WebApplication.CreateBuilder(args); ConfigureAuthentication(builder); @@ -67,6 +68,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); var app = builder.Build(); @@ -78,7 +80,7 @@ } app.UseHttpsRedirection(); - +app.UseHttpLogging(); app.UseAuthentication(); diff --git a/BookManager/README.md b/BookManager/README.md index 294b02b5..ff58b4e8 100644 --- a/BookManager/README.md +++ b/BookManager/README.md @@ -1,6 +1,8 @@ ## Desafio Back-End -#### Check list +# Atividades Trllo + +- Check list - Modelagem DR -OK - Swagger - OK @@ -12,13 +14,14 @@ - Crud-OK - Banco Pstegre -ok - Migrates -ok -- Seeds - Carga -- Log -- SOLID -- Factory -- Singleton -- TDD +- Seeds - ok +- Log - ok +- Paginação-ok +- SOLID -ok +- Factory-ok +- Singleton-ok +- TDD-ok - VIDEO -> dotnet ef migrations add MyFirstMigration --context DataContext -> dotnet ef database update --context BloggingContext +dotnet ef migrations add Migration5 --context DataContext +dotnet ef database update --context DataContext diff --git a/BookManager/Repository/BookRepository.cs b/BookManager/Repository/BookRepository.cs index 191c60f5..d6f65273 100644 --- a/BookManager/Repository/BookRepository.cs +++ b/BookManager/Repository/BookRepository.cs @@ -15,22 +15,40 @@ public BookRepository(DataContext context) : base(context) public async Task> GetBooksAsync() { - return await _context.Books - .Select(x => new Book { id = x.id, title = x.title }) - .ToListAsync(); + return await _context.Books.OrderBy(b => b.name).Take(1000).ToListAsync(); } public async Task GetBooksByIdAsync(int id) { - var ret = await _context.Books.Where(x => x.id == id).FirstOrDefaultAsync(); - if (ret != null) + + Book? ret = await _context.Books.Where(x => x.id == id).FirstOrDefaultAsync(); + if (ret == null) { - return ret; + ret = new Book(); } - return new Book(); + return ret; } + public async Task> GetFilter(int skip, int take, string name) + { + + name = string.IsNullOrWhiteSpace(name) ? string.Empty : name.Trim().ToLower(); + + if (!string.IsNullOrWhiteSpace(name)) + { + return await _context.Books.Where( + x => x.name.Contains(name) + ).AsNoTracking().Skip(skip).Take(take).OrderBy(b => b.name).ToListAsync(); + } + else + { + return await _context.Books.AsNoTracking().Skip(skip).Take(take).OrderBy(b => b.name).ToListAsync(); + } + } + + + public async Task bookCheckExists(Book book) @@ -40,5 +58,25 @@ public async Task bookCheckExists(Book book) } + + public async Task getMaxIdBook() + { + int maxId = 0; + var lst = await _context.Books.OrderByDescending(b => b.id).Take(1).ToListAsync(); + if (lst != null && lst.Any()) + { + var obj = lst.FirstOrDefault(); + if (obj != null) + { + maxId = obj.id; + } + + } + return maxId; + + } + + + } } \ No newline at end of file diff --git a/BookManager/Repository/CostomLogRepository.cs b/BookManager/Repository/CostomLogRepository.cs new file mode 100644 index 00000000..a774ae0d --- /dev/null +++ b/BookManager/Repository/CostomLogRepository.cs @@ -0,0 +1,16 @@ +using BookManager.Data; +using BookManager.Repository.Interfaces; + +namespace BookManager.Repository +{ + public class CostomLogRepository : BaseRepository, ICostomLogRepository + { + private readonly DataContext _context; + public CostomLogRepository(DataContext context) : base(context) + { + _context = context; + } + + + } +} \ No newline at end of file diff --git a/BookManager/Repository/Interfaces/IBookRepository.cs b/BookManager/Repository/Interfaces/IBookRepository.cs index 444fd68c..6f389235 100644 --- a/BookManager/Repository/Interfaces/IBookRepository.cs +++ b/BookManager/Repository/Interfaces/IBookRepository.cs @@ -7,5 +7,9 @@ public interface IBookRepository : IBaseRepository public Task> GetBooksAsync(); public Task GetBooksByIdAsync(int id); public Task bookCheckExists(Book book); + + public Task> GetFilter(int skip, int take, string name); + + public Task getMaxIdBook(); } } \ No newline at end of file diff --git a/BookManager/Repository/Interfaces/ICostomLogRepository.cs b/BookManager/Repository/Interfaces/ICostomLogRepository.cs new file mode 100644 index 00000000..a2c6ac70 --- /dev/null +++ b/BookManager/Repository/Interfaces/ICostomLogRepository.cs @@ -0,0 +1,8 @@ + +namespace BookManager.Repository.Interfaces +{ + public interface ICostomLogRepository : IBaseRepository + { + + } +} \ No newline at end of file diff --git a/BookManager/Services/CustonLogServices.cs b/BookManager/Services/CustonLogServices.cs new file mode 100644 index 00000000..f5c8802c --- /dev/null +++ b/BookManager/Services/CustonLogServices.cs @@ -0,0 +1,25 @@ +using BookManager.Model; +using BookManager.Repository; + +namespace BookManager.Services +{ + public static class CustonLogServices + { + + //private readonly CostomLogRepository repository = new CostomLogRepository(); + + public static void Logger(string pOperation, string pTrace) + { + var log = new CustomLog() + { + operation = pOperation, + trace = pTrace, + createAt = DateTime.Now + }; + // await repository.Add(log); + //await repository.SaveChangesAsync(); + + } + + } +} \ No newline at end of file diff --git a/BookManager/appsettings.json b/BookManager/appsettings.json index 67843815..f3af97e9 100644 --- a/BookManager/appsettings.json +++ b/BookManager/appsettings.json @@ -6,7 +6,9 @@ "Logging": { "LogLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Microsoft": "Warning", + "Microsoft.AspNetCore.HttpLogging": "Information", + "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" From 2b257176c07801cb721640bf63efd6a1ec9aed2a Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Mon, 21 Nov 2022 11:00:10 -0300 Subject: [PATCH 11/18] Add load and seeds --- BookManager/Controllers/AuthContoller.cs | 2 +- BookManager/Controllers/BooksController.cs | 77 ++++++++++++++----- BookManager/Data/DataContext.cs | 2 + BookManager/Repository/BookRepository.cs | 23 +++++- .../Repository/Interfaces/IBookRepository.cs | 1 + 5 files changed, 83 insertions(+), 22 deletions(-) diff --git a/BookManager/Controllers/AuthContoller.cs b/BookManager/Controllers/AuthContoller.cs index 38e6b2e7..139c67a1 100644 --- a/BookManager/Controllers/AuthContoller.cs +++ b/BookManager/Controllers/AuthContoller.cs @@ -44,7 +44,7 @@ public async Task login(Credential param) else { - return BadRequest("User not found."); + return NotFound("User not found."); } } diff --git a/BookManager/Controllers/BooksController.cs b/BookManager/Controllers/BooksController.cs index 68d087fe..5ebb0846 100644 --- a/BookManager/Controllers/BooksController.cs +++ b/BookManager/Controllers/BooksController.cs @@ -2,6 +2,7 @@ using BookManager.Repository.Interfaces; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using System.Reflection; namespace BookManager.Controllers { @@ -32,6 +33,7 @@ public async Task Get() } else { + return NotFound("Books not exiists"); } } @@ -44,27 +46,35 @@ public async Task Get() [AllowAnonymous] - [HttpGet("skip/{skip:int}/take/{take:int}/name/{name}")] + [HttpGet("GetFilter/skip/{skip:int}/take/{take:int}/name/{name}")] public async Task GetFilter( - [FromRoute] int skip, - [FromRoute] int take, - [FromRoute] string name) + [FromRoute] int skip = 0, + [FromRoute] int take = 50, + [FromRoute] string name = "") { try { var books = await repository.GetFilter(skip, take, name); + if (books != null && books.Any()) { - return Ok(books); + int pCount = repository.getCountBook(name); + return Ok(new + { + skip = skip, + take = take, + count = pCount, + data = books + }); } else { - return NotFound("Books not exiists"); + return NotFound("Books not exists"); } } catch (Exception ex) { - logger("Get", ex.ToString()); + logger("GetFilter", ex.ToString()); return BadRequest(ex.Message); } } @@ -76,14 +86,20 @@ public async Task GetById(int id) { try { + if (id <= 0) + { + return NotFound("Id Not Found"); + } + + var book = await repository.GetBooksByIdAsync(id); return book != null ? Ok(book) - : BadRequest("Book not found"); + : NotFound("Book not found"); } catch (Exception ex) { - logger("Get", ex.ToString()); + logger("GetById", ex.ToString()); return BadRequest(ex.Message); } } @@ -119,11 +135,11 @@ public async Task put(Book book) return await repository.SaveChangesAsync() ? Ok("Book adicionado com sucesso") - : BadRequest("Erro ao salvar o book"); + : BadRequest("Erro ao salvar book"); } catch (Exception ex) { - logger("Get", ex.ToString()); + logger("Put", ex.ToString()); return BadRequest(ex.Message); } @@ -144,7 +160,7 @@ public async Task delete(int id) } catch (Exception ex) { - logger("Get", ex.ToString()); + logger("delete", ex.ToString()); return BadRequest(ex.Message); } } @@ -181,7 +197,7 @@ public async Task Post(Book book) } catch (Exception ex) { - logger("Get", ex.ToString()); + logger("Post", ex.ToString()); return BadRequest(ex.Message); } @@ -190,7 +206,7 @@ public async Task Post(Book book) [AllowAnonymous] [HttpGet("load/qtd/{qtd:int}")] - public async Task load(int qtd) + public async Task load(int qtd = 100) { try { @@ -211,7 +227,9 @@ public async Task load(int qtd) isnb = $"9999{i}", year = 2004, idPublisher = 1, - exemplary = i + exemplary = i, + createAt = DateTime.Now + }; repository.Add(book); @@ -229,13 +247,18 @@ public async Task load(int qtd) } - private void logger(string pOperation, string pTrace) + private async void logger(string pOperation, string pTrace) { try { - var log = new CustomLog() { operation = pOperation, trace = pTrace, createAt = DateTime.Now }; + var log = new CustomLog() + { + operation = String.Concat("bookController", pOperation).ToLower(), + trace = pTrace, + createAt = DateTime.Now + }; costomLogRepository.Add(log); - costomLogRepository.SaveChangesAsync(); + await costomLogRepository.SaveChangesAsync(); } catch { @@ -245,6 +268,24 @@ private void logger(string pOperation, string pTrace) } + [AllowAnonymous] + [HttpGet("testeLog")] + public IActionResult testeLog() + { + try + { + logger("Get", "Trace"); + return Ok("0k"); + } + catch (Exception ex) + { + + return BadRequest(ex.Message); + } + } + + + } } \ No newline at end of file diff --git a/BookManager/Data/DataContext.cs b/BookManager/Data/DataContext.cs index cb21c3f0..0bcf6006 100644 --- a/BookManager/Data/DataContext.cs +++ b/BookManager/Data/DataContext.cs @@ -7,6 +7,8 @@ public class DataContext : DbContext { public DataContext(DbContextOptions options) : base(options) { + AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); + AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true); } public DbSet Categorys { get; set; } public DbSet Publishers { get; set; } diff --git a/BookManager/Repository/BookRepository.cs b/BookManager/Repository/BookRepository.cs index d6f65273..e37839a8 100644 --- a/BookManager/Repository/BookRepository.cs +++ b/BookManager/Repository/BookRepository.cs @@ -38,7 +38,7 @@ public async Task> GetFilter(int skip, int take, string name) if (!string.IsNullOrWhiteSpace(name)) { return await _context.Books.Where( - x => x.name.Contains(name) + x => x.name.Trim().ToLower().Contains(name) ).AsNoTracking().Skip(skip).Take(take).OrderBy(b => b.name).ToListAsync(); } else @@ -47,6 +47,25 @@ public async Task> GetFilter(int skip, int take, string name) } } + public int getCountBook(string name) + { + int count = 0; + + name = string.IsNullOrWhiteSpace(name) ? string.Empty : name.Trim().ToLower(); + + if (!string.IsNullOrWhiteSpace(name)) + { + count = _context.Books.Where( + x => x.name.Trim().ToLower().Contains(name) + ).AsNoTracking().Count(); + } + else + { + count = _context.Books.Count(); + } + return count; + } + @@ -76,7 +95,5 @@ public async Task getMaxIdBook() } - - } } \ No newline at end of file diff --git a/BookManager/Repository/Interfaces/IBookRepository.cs b/BookManager/Repository/Interfaces/IBookRepository.cs index 6f389235..df9a73e9 100644 --- a/BookManager/Repository/Interfaces/IBookRepository.cs +++ b/BookManager/Repository/Interfaces/IBookRepository.cs @@ -11,5 +11,6 @@ public interface IBookRepository : IBaseRepository public Task> GetFilter(int skip, int take, string name); public Task getMaxIdBook(); + public int getCountBook(string name); } } \ No newline at end of file From 94fc3a2553d45905f5d7b3c5c302e89e682261b1 Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Mon, 21 Nov 2022 12:39:37 -0300 Subject: [PATCH 12/18] Refactory --- BookManager/Controllers/BooksController.cs | 22 ---------------------- BookManager/Data/DataContext.cs | 2 +- BookManager/Repository/UserRepository.cs | 2 +- 3 files changed, 2 insertions(+), 24 deletions(-) diff --git a/BookManager/Controllers/BooksController.cs b/BookManager/Controllers/BooksController.cs index 5ebb0846..4a2f904b 100644 --- a/BookManager/Controllers/BooksController.cs +++ b/BookManager/Controllers/BooksController.cs @@ -264,28 +264,6 @@ private async void logger(string pOperation, string pTrace) { //não sobe, grava no event viwer } - - - } - - [AllowAnonymous] - [HttpGet("testeLog")] - public IActionResult testeLog() - { - try - { - logger("Get", "Trace"); - return Ok("0k"); - } - catch (Exception ex) - { - - return BadRequest(ex.Message); - } } - - - - } } \ No newline at end of file diff --git a/BookManager/Data/DataContext.cs b/BookManager/Data/DataContext.cs index 0bcf6006..458e3fa0 100644 --- a/BookManager/Data/DataContext.cs +++ b/BookManager/Data/DataContext.cs @@ -8,7 +8,7 @@ public class DataContext : DbContext public DataContext(DbContextOptions options) : base(options) { AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); - AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true); + //AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true); } public DbSet Categorys { get; set; } public DbSet Publishers { get; set; } diff --git a/BookManager/Repository/UserRepository.cs b/BookManager/Repository/UserRepository.cs index 5c754374..a39ffe6a 100644 --- a/BookManager/Repository/UserRepository.cs +++ b/BookManager/Repository/UserRepository.cs @@ -34,7 +34,7 @@ public async Task checkUserExists(User user) if (user == null || string.IsNullOrWhiteSpace(user.email)) return false; string email = user.email.Trim().ToLower(); var ret = await _context.Users.Where(user => user.email.Equals(email)).ToListAsync(); - return (ret == null || !ret.Any()); + return !(ret == null || !ret.Any()); } } From 97e4d548ad856e1926e04008cbc5b0ab509d9216 Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Mon, 21 Nov 2022 12:41:07 -0300 Subject: [PATCH 13/18] Refactory --- BookManager/Controllers/BooksController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BookManager/Controllers/BooksController.cs b/BookManager/Controllers/BooksController.cs index 4a2f904b..6f24b287 100644 --- a/BookManager/Controllers/BooksController.cs +++ b/BookManager/Controllers/BooksController.cs @@ -165,7 +165,7 @@ public async Task delete(int id) } } - + [Authorize] [HttpPost] public async Task Post(Book book) { @@ -204,7 +204,7 @@ public async Task Post(Book book) } - [AllowAnonymous] + [Authorize] [HttpGet("load/qtd/{qtd:int}")] public async Task load(int qtd = 100) { From 41bf8dbe82d6ea85076ee0578dde283e3e65520f Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Mon, 21 Nov 2022 17:00:28 -0300 Subject: [PATCH 14/18] Add padrao Factoryy --- .../CustomLogFactory/CustomLogFactory.cs | 26 +++++++++++++++++++ .../Services/CustomLogFactory/CustomLogger.cs | 14 ++++++++++ .../CustomLogFactory/CustomLoggerError.cs | 14 ++++++++++ .../CustomLogFactory/CustomLoggerSuccess.cs | 15 +++++++++++ .../Interface/ICustomLogger.cs | 11 ++++++++ BookManager/Services/CustonLogServices.cs | 25 ------------------ 6 files changed, 80 insertions(+), 25 deletions(-) create mode 100644 BookManager/Services/CustomLogFactory/CustomLogFactory.cs create mode 100644 BookManager/Services/CustomLogFactory/CustomLogger.cs create mode 100644 BookManager/Services/CustomLogFactory/CustomLoggerError.cs create mode 100644 BookManager/Services/CustomLogFactory/CustomLoggerSuccess.cs create mode 100644 BookManager/Services/CustomLogFactory/Interface/ICustomLogger.cs delete mode 100644 BookManager/Services/CustonLogServices.cs diff --git a/BookManager/Services/CustomLogFactory/CustomLogFactory.cs b/BookManager/Services/CustomLogFactory/CustomLogFactory.cs new file mode 100644 index 00000000..08582d56 --- /dev/null +++ b/BookManager/Services/CustomLogFactory/CustomLogFactory.cs @@ -0,0 +1,26 @@ + +using BookManager.Services.CustomLogFactory; +using BookManager.Services.CustomLogFactory.Interface; + +namespace BookManager.Services.CustomLog +{ + public class Factory + { + public ICustomLogger FactoryMethod(int tipo) + { + + switch (tipo) + { + case 1: + return new CustomLoggerError(); + //break; + case 2: + return new CustomLoggerSuccess(); + //break; + default: + return new CustomLoggerError(); + //break; + } + } + } +} \ No newline at end of file diff --git a/BookManager/Services/CustomLogFactory/CustomLogger.cs b/BookManager/Services/CustomLogFactory/CustomLogger.cs new file mode 100644 index 00000000..bbe7f6bb --- /dev/null +++ b/BookManager/Services/CustomLogFactory/CustomLogger.cs @@ -0,0 +1,14 @@ + +using BookManager.Services.CustomLog; + +namespace BookManager.Services.CustomLogFactory +{ + public class CustomLogger + { + public void logger(string pOperation, string pTrace, int tipo) + { + var log = new Factory().FactoryMethod(tipo); + log.logger(pOperation, pTrace); + } + } +} \ No newline at end of file diff --git a/BookManager/Services/CustomLogFactory/CustomLoggerError.cs b/BookManager/Services/CustomLogFactory/CustomLoggerError.cs new file mode 100644 index 00000000..e0f37d0e --- /dev/null +++ b/BookManager/Services/CustomLogFactory/CustomLoggerError.cs @@ -0,0 +1,14 @@ +using BookManager.Data; +using BookManager.Repository; +using BookManager.Services.CustomLogFactory.Interface; + +namespace BookManager.Services.CustomLogFactory +{ + public class CustomLoggerError : ICustomLogger + { + public void logger(string pOperation, string pTrace) + { + //Classe e metodo desacoplado + } + } +} \ No newline at end of file diff --git a/BookManager/Services/CustomLogFactory/CustomLoggerSuccess.cs b/BookManager/Services/CustomLogFactory/CustomLoggerSuccess.cs new file mode 100644 index 00000000..9e382596 --- /dev/null +++ b/BookManager/Services/CustomLogFactory/CustomLoggerSuccess.cs @@ -0,0 +1,15 @@ + +using BookManager.Services.CustomLogFactory.Interface; + +namespace BookManager.Services.CustomLog +{ + public class CustomLoggerSuccess : ICustomLogger + { + + + public void logger(string pOperation, string pTrace) + { + + } + } +} \ No newline at end of file diff --git a/BookManager/Services/CustomLogFactory/Interface/ICustomLogger.cs b/BookManager/Services/CustomLogFactory/Interface/ICustomLogger.cs new file mode 100644 index 00000000..d9f10bed --- /dev/null +++ b/BookManager/Services/CustomLogFactory/Interface/ICustomLogger.cs @@ -0,0 +1,11 @@ + +namespace BookManager.Services.CustomLogFactory.Interface +{ + public interface ICustomLogger + { + public void logger(string pOperation, string pTrace); + } +} + + + diff --git a/BookManager/Services/CustonLogServices.cs b/BookManager/Services/CustonLogServices.cs deleted file mode 100644 index f5c8802c..00000000 --- a/BookManager/Services/CustonLogServices.cs +++ /dev/null @@ -1,25 +0,0 @@ -using BookManager.Model; -using BookManager.Repository; - -namespace BookManager.Services -{ - public static class CustonLogServices - { - - //private readonly CostomLogRepository repository = new CostomLogRepository(); - - public static void Logger(string pOperation, string pTrace) - { - var log = new CustomLog() - { - operation = pOperation, - trace = pTrace, - createAt = DateTime.Now - }; - // await repository.Add(log); - //await repository.SaveChangesAsync(); - - } - - } -} \ No newline at end of file From 41139ce409ddcf54d4134361a08305ebcd13d6d1 Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Mon, 21 Nov 2022 17:17:44 -0300 Subject: [PATCH 15/18] refactory 11y --- BookManager/README.md | 90 ++++++++++++++++++- .../CustomLogFactory/CustomLoggerSuccess.cs | 4 +- 2 files changed, 88 insertions(+), 6 deletions(-) diff --git a/BookManager/README.md b/BookManager/README.md index ff58b4e8..64f2ef55 100644 --- a/BookManager/README.md +++ b/BookManager/README.md @@ -1,8 +1,84 @@ -## Desafio Back-End +# BookManeger Test -# Atividades Trllo +This application is generated using C# And Visual Studio Code -- Check list +Projeto para controle de livros + +## Dependencies + +- Microsoft.EntityFrameworkCore + +```sh +dotnet restore +Database Postgre +Set Conect string in appsettings.json +dotnet ef database update --context DataContext +``` + +## Run the application + +```sh +dotnet run +``` + +## Tests + +```sh +Coleção do postman anexa no projeto + +``` + +## Ecosistema da Api + +``` + +Ide de desenvolvimento Visual Code +Linguagem C# +.Net FrameWork 6 +Docker-distribuição +Banco postegrer (mas poderia seu oracle ou sqlserver) +Construção do banco EF-Migrations +Distribuição - Docker +Autenticação e autorização: JWT +Documentação da Api - Swegger +Teste Api - Postman (Collection anexa) +Revisão de codigo foi utilisado a extensão eslint +Padroes de projeto:(explicitar ) + - Factory src/service/factory.report.ts + - Singleton src/services/singleton.ts + - injeção de dependencia -> src/services/ + - Princípio de responsabilidade única -> src/services/ + + +``` + +## Trello atividades + +```sh + +#1 - Analise e entendimento da demanda +#2 - Dividir para conquistar - dividir o projeto em atividades via trello +#3 - Validar escopo +#4 - Criar setup do projeto +#5 - Gerar o Diagrama classes +#6 - criar a base de dados +#7 - Criar os migrates +#8 - Criar os seeds +#9 - configurar o docker +#10- Gerar os modelos +#11- gerar as controller-limpar +#13- Configurar jwt +#15- Gerar Chave +#16- Testar e refatorar +#17- Atualizar o Re +#18- Validações +#19-pipline + +``` + +## Check List Macro + +```sh - Modelagem DR -OK - Swagger - OK @@ -25,3 +101,11 @@ dotnet ef migrations add Migration5 --context DataContext dotnet ef database update --context DataContext +``` + +## Video Projeto execultaldo + +```sh + https://www.youtube.com/ + +``` diff --git a/BookManager/Services/CustomLogFactory/CustomLoggerSuccess.cs b/BookManager/Services/CustomLogFactory/CustomLoggerSuccess.cs index 9e382596..21a50214 100644 --- a/BookManager/Services/CustomLogFactory/CustomLoggerSuccess.cs +++ b/BookManager/Services/CustomLogFactory/CustomLoggerSuccess.cs @@ -5,11 +5,9 @@ namespace BookManager.Services.CustomLog { public class CustomLoggerSuccess : ICustomLogger { - - public void logger(string pOperation, string pTrace) { - + //Classe e metodo desacoplado } } } \ No newline at end of file From fa98e1d16aa3553b6b915750dc91b31e6ada2a5d Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Mon, 21 Nov 2022 17:19:20 -0300 Subject: [PATCH 16/18] refactory 11y --- BookManager/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BookManager/README.md b/BookManager/README.md index 64f2ef55..30827314 100644 --- a/BookManager/README.md +++ b/BookManager/README.md @@ -1,4 +1,4 @@ -# BookManeger Test +# BookManager Test This application is generated using C# And Visual Studio Code From d15a10feae5f9f02d472ad431fa15910570a4d8c Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Mon, 21 Nov 2022 18:05:32 -0300 Subject: [PATCH 17/18] refactory 11y --- BookManager/Controllers/BooksController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BookManager/Controllers/BooksController.cs b/BookManager/Controllers/BooksController.cs index 6f24b287..a10786d3 100644 --- a/BookManager/Controllers/BooksController.cs +++ b/BookManager/Controllers/BooksController.cs @@ -134,7 +134,7 @@ public async Task put(Book book) repository.Update(bookDB); return await repository.SaveChangesAsync() - ? Ok("Book adicionado com sucesso") + ? Ok("Book Alterado com sucesso") : BadRequest("Erro ao salvar book"); } catch (Exception ex) From 82b7c8c7e0c425c54e7804961d3bb4eb43de8ac7 Mon Sep 17 00:00:00 2001 From: DantasRocha Date: Mon, 21 Nov 2022 18:25:28 -0300 Subject: [PATCH 18/18] add colection --- BookManager/README.md | 4 +- Books.postman_collection.json | 295 ++++++++++++++++++++++++++++++++++ 2 files changed, 297 insertions(+), 2 deletions(-) create mode 100644 Books.postman_collection.json diff --git a/BookManager/README.md b/BookManager/README.md index 30827314..47168f5b 100644 --- a/BookManager/README.md +++ b/BookManager/README.md @@ -97,7 +97,7 @@ Padroes de projeto:(explicitar ) - Factory-ok - Singleton-ok - TDD-ok -- VIDEO +- VIDEO-ok dotnet ef migrations add Migration5 --context DataContext dotnet ef database update --context DataContext @@ -106,6 +106,6 @@ dotnet ef database update --context DataContext ## Video Projeto execultaldo ```sh - https://www.youtube.com/ + https://www.youtube.com/watch?v=mjB4KRNpt3g ``` diff --git a/Books.postman_collection.json b/Books.postman_collection.json new file mode 100644 index 00000000..53632c31 --- /dev/null +++ b/Books.postman_collection.json @@ -0,0 +1,295 @@ +{ + "info": { + "_postman_id": "7b215260-6446-4bc4-bb18-32f4b9196726", + "name": "Books", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "19952004" + }, + "item": [ + { + "name": "01 - AuthSignup", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{ \r\n \"name\": \"User Test\",\r\n \"email\": \"1241@Gmail.com\",\r\n \"password\": \"ForteLuz@123\",\r\n \"role\": \"ADM\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:7102/api/Auth/signup", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "7102", + "path": [ + "api", + "Auth", + "signup" + ] + } + }, + "response": [] + }, + { + "name": "02 - AuthLogin", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var jsonData = JSON.parse(responseBody);\r", + "//pm.environment.set(\"token_app\",JSON.stringify( jsonData.token));\r", + "pm.environment.set(\"token_app\", jsonData.token);\r", + "console.log(jsonData.token);\r", + "\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "noauth" + }, + "method": "POST", + "header": [ + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"email\": \"teste@teste.com\",\r\n \"password\": \"123\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:7102/api/Auth/login", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "7102", + "path": [ + "api", + "Auth", + "login" + ] + } + }, + "response": [] + }, + { + "name": "03 - AddBooks", + "request": { + "auth": { + "type": "noauth" + }, + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_app}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n\r\n \"name\": \"Name\",\r\n \"decription\": \"string\",\r\n \"author\": \"string\",\r\n \"idCategory\": 6,\r\n \"isnb\": \"6699\",\r\n \"year\": 2022,\r\n \"idPublisher\": 1,\r\n \"createAt\": \"2022-11-21T14:30:09.501Z\",\r\n \"exemplary\": 1\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:7102/api/Books", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "7102", + "path": [ + "api", + "Books" + ] + } + }, + "response": [] + }, + { + "name": "04 - BookPut", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_app}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"id\": 149,\r\n \"name\": \"novo nome\",\r\n \"decription\": \"Vova Descrição\",\r\n \"isnb\": \"999\",\r\n \"author\": \"Novo Autor\"\r\n \r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:7102/api/Books", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "7102", + "path": [ + "api", + "Books" + ] + } + }, + "response": [] + }, + { + "name": "05 - BookDetById", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://localhost:7102/api/Books/id/149", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "7102", + "path": [ + "api", + "Books", + "id", + "149" + ] + } + }, + "response": [] + }, + { + "name": "06 - BookDelete", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_app}}", + "type": "text" + } + ], + "url": { + "raw": "https://localhost:7102/api/Books/id/148", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "7102", + "path": [ + "api", + "Books", + "id", + "148" + ] + } + }, + "response": [] + }, + { + "name": "07 - Booksload", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_app}}", + "type": "text" + } + ], + "url": { + "raw": "https://localhost:7102/api/Books/load/qtd/100", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "7102", + "path": [ + "api", + "Books", + "load", + "qtd", + "100" + ] + } + }, + "response": [] + }, + { + "name": "08 - BookGet", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://localhost:7102/api/Books", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "7102", + "path": [ + "api", + "Books" + ] + } + }, + "response": [] + }, + { + "name": "09 - BookGetFilter", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://localhost:7102/api/Books/GetFilter/skip/0/take/50/name/name", + "protocol": "https", + "host": [ + "localhost" + ], + "port": "7102", + "path": [ + "api", + "Books", + "GetFilter", + "skip", + "0", + "take", + "50", + "name", + "name" + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file