From 8191ca0e602b2177783007ed152bcd907914ff2b Mon Sep 17 00:00:00 2001 From: eduardomps Date: Sat, 14 Mar 2020 17:09:39 -0300 Subject: [PATCH 1/8] inicial, com console app para algoritmo duplicados --- .gitignore | 19 ++++++++++ .vscode/launch.json | 27 +++++++++++++ .vscode/tasks.json | 42 +++++++++++++++++++++ duplicados/Program.cs | 73 ++++++++++++++++++++++++++++++++++++ duplicados/duplicados.csproj | 8 ++++ 5 files changed, 169 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 duplicados/Program.cs create mode 100644 duplicados/duplicados.csproj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0a9ca7b --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +duplicados/bin/Debug/netcoreapp3.1/duplicados +duplicados/bin/Debug/netcoreapp3.1/duplicados.deps.json +duplicados/bin/Debug/netcoreapp3.1/duplicados.dll +duplicados/bin/Debug/netcoreapp3.1/duplicados.pdb +duplicados/bin/Debug/netcoreapp3.1/duplicados.runtimeconfig.dev.json +duplicados/bin/Debug/netcoreapp3.1/duplicados.runtimeconfig.json +duplicados/obj/duplicados.csproj.nuget.cache +duplicados/obj/duplicados.csproj.nuget.dgspec.json +duplicados/obj/duplicados.csproj.nuget.g.props +duplicados/obj/duplicados.csproj.nuget.g.targets +duplicados/obj/project.assets.json +duplicados/obj/Debug/netcoreapp3.1/duplicados +duplicados/obj/Debug/netcoreapp3.1/duplicados.AssemblyInfo.cs +duplicados/obj/Debug/netcoreapp3.1/duplicados.AssemblyInfoInputs.cache +duplicados/obj/Debug/netcoreapp3.1/duplicados.assets.cache +duplicados/obj/Debug/netcoreapp3.1/duplicados.csproj.FileListAbsolute.txt +duplicados/obj/Debug/netcoreapp3.1/duplicados.csprojAssemblyReference.cache +duplicados/obj/Debug/netcoreapp3.1/duplicados.dll +duplicados/obj/Debug/netcoreapp3.1/duplicados.pdb diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..6641488 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + // 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 + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/duplicados/bin/Debug/netcoreapp3.1/duplicados.dll", + "args": [], + "cwd": "${workspaceFolder}/duplicados", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "internalConsole", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..519e63f --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/duplicados/duplicados.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/duplicados/duplicados.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "${workspaceFolder}/duplicados/duplicados.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/duplicados/Program.cs b/duplicados/Program.cs new file mode 100644 index 0000000..3ddc8a0 --- /dev/null +++ b/duplicados/Program.cs @@ -0,0 +1,73 @@ +using System; +using System.Linq; +using System.Text.RegularExpressions; + +namespace duplicados +{ + class Program + { + static void Main(string[] args) + { + if(args.Length <= 0) + { + Console.WriteLine("USO DO PROGRAMA: duplicados !"); + return; + } + + string numbers = args[0]; + string separator = ","; + + bool validArgs = false; + string errorMessage = string.Empty; + (validArgs, errorMessage) = ValidateArgs(numbers, separator); + if(!validArgs) + { + Console.WriteLine(errorMessage); + return; + } + Console.WriteLine(FindDuplicates(numbers,separator)); + + } + + /// encontra algum duplicado na lista + private static string FindDuplicates(string numbers, string separator) + { + string result = "Não foram encontrados duplicados!"; + + // faz o split da string, já convertendo para long + long[] numberList = numbers + .Split(separator, StringSplitOptions.RemoveEmptyEntries) + .Select(numberStr => long.Parse(numberStr)) + .ToArray(); + + for(int index=0;index(numberList,index+1,num => currentNumber==num); + if(dupIndex >= 0) + { + result = $"Duplicado encontrado! \nnúmero: {currentNumber}, índices: {index},{dupIndex}"; + break; + } + } + + return result; + } + + ///Validações básicas + private static (bool validArgs, string errorMessage) ValidateArgs(string numbers, string separator) + { + if(numbers.IndexOf(separator) < 0) + { + return (false,"Separador não encontrado na lista!"); + } + if(!Regex.IsMatch(numbers,@$"^(\d+)({separator}\d+)*")) + { + return (false,"Lista inválida!"); + } + + return (true,string.Empty); + } + } +} diff --git a/duplicados/duplicados.csproj b/duplicados/duplicados.csproj new file mode 100644 index 0000000..d453e9a --- /dev/null +++ b/duplicados/duplicados.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp3.1 + + + From b6f6ef039b9657ca8d78f394e7827630fefbd4a4 Mon Sep 17 00:00:00 2001 From: eduardomps Date: Sat, 14 Mar 2020 18:05:29 -0300 Subject: [PATCH 2/8] =?UTF-8?q?algoritmo=20de=20verifica=C3=A7=C3=A3o=20de?= =?UTF-8?q?=20pal=C3=ADndromos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 19 ++++++++ .vscode/launch.json | 18 +++++++- palindromos/Program.cs | 82 ++++++++++++++++++++++++++++++++++ palindromos/palindromos.csproj | 8 ++++ 4 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 palindromos/Program.cs create mode 100644 palindromos/palindromos.csproj diff --git a/.gitignore b/.gitignore index 0a9ca7b..3e3c159 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,22 @@ duplicados/obj/Debug/netcoreapp3.1/duplicados.csproj.FileListAbsolute.txt duplicados/obj/Debug/netcoreapp3.1/duplicados.csprojAssemblyReference.cache duplicados/obj/Debug/netcoreapp3.1/duplicados.dll duplicados/obj/Debug/netcoreapp3.1/duplicados.pdb +palindromos/bin/Debug/netcoreapp3.1/palindromos +palindromos/bin/Debug/netcoreapp3.1/palindromos.deps.json +palindromos/bin/Debug/netcoreapp3.1/palindromos.dll +palindromos/bin/Debug/netcoreapp3.1/palindromos.pdb +palindromos/bin/Debug/netcoreapp3.1/palindromos.runtimeconfig.dev.json +palindromos/bin/Debug/netcoreapp3.1/palindromos.runtimeconfig.json +palindromos/obj/palindromos.csproj.nuget.cache +palindromos/obj/palindromos.csproj.nuget.dgspec.json +palindromos/obj/palindromos.csproj.nuget.g.props +palindromos/obj/palindromos.csproj.nuget.g.targets +palindromos/obj/project.assets.json +palindromos/obj/Debug/netcoreapp3.1/palindromos +palindromos/obj/Debug/netcoreapp3.1/palindromos.AssemblyInfo.cs +palindromos/obj/Debug/netcoreapp3.1/palindromos.AssemblyInfoInputs.cache +palindromos/obj/Debug/netcoreapp3.1/palindromos.assets.cache +palindromos/obj/Debug/netcoreapp3.1/palindromos.csproj.FileListAbsolute.txt +palindromos/obj/Debug/netcoreapp3.1/palindromos.csprojAssemblyReference.cache +palindromos/obj/Debug/netcoreapp3.1/palindromos.dll +palindromos/obj/Debug/netcoreapp3.1/palindromos.pdb diff --git a/.vscode/launch.json b/.vscode/launch.json index 6641488..79bd94c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -3,9 +3,9 @@ // Use hover for the description of the existing attributes // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md "version": "0.2.0", - "configurations": [ + "configurations": [ { - "name": ".NET Core Launch (console)", + "name": "Duplicados", "type": "coreclr", "request": "launch", "preLaunchTask": "build", @@ -17,11 +17,25 @@ "console": "internalConsole", "stopAtEntry": false }, + { + "name": "Palindromos", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/palindromos/bin/Debug/netcoreapp3.1/palindromos.dll", + "args": ["A Rita, sobre vovô, verbos atira"], + "cwd": "${workspaceFolder}/palindromos", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "internalConsole", + "stopAtEntry": false + }, { "name": ".NET Core Attach", "type": "coreclr", "request": "attach", "processId": "${command:pickProcess}" } + ] } \ No newline at end of file diff --git a/palindromos/Program.cs b/palindromos/Program.cs new file mode 100644 index 0000000..f7e4a34 --- /dev/null +++ b/palindromos/Program.cs @@ -0,0 +1,82 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace palindromos +{ + class Program + { + static void Main(string[] args) + { + if(args.Length <= 0) + { + Console.WriteLine("USO DO PROGRAMA: palindromos !"); + return; + } + string input = args[0]; + + Console.WriteLine("CONSIDERANDO espaços, especiais e diacríticos: "); + string result = IsPalindrome(input) + ? $"'{input}' É palíndromo!" + : $"'{input}' NÃO É palíndromo."; + Console.WriteLine(result); + + Console.WriteLine("IGNORANDO espaços, especiais e diacríticos: "); + result = IsPalindrome(input, false) + ? $"'{input}' É palíndromo!" + : $"'{input}' NÃO É palíndromo."; + Console.WriteLine(result); + } + + // Valida se a string de entrada é palíndroma + private static bool IsPalindrome(string input, bool isSimpleWord = true) + { + bool isPalindrome = true; + // parâmetro isSimpleWord indica se validará apenas + // uma palavra ex.: "arara" ou se é frase e portanto + // deve usar regras de espaços e diacríticos + if(!isSimpleWord) + { + // remove os espaços e especiais + // e os diacríticos + input = Regex.Replace(input, @"\W+", string.Empty); + input = RemoveDiacritics(input); + } + // garantindo o ignoreCase + input = input.ToUpper(); + int halfLengthIndex = input.Length / 2 - 1; + int lastIndex = input.Length - 1; + // vai até a metade da string + for(int index=0; index< halfLengthIndex; index++) + { + // compara o caractrer no primeiro indice com o ultimo + // o segundo com o penultimo, etc + // se encontrar alguma coisa diferente, já pode retornar falso + if(input[index] != input[lastIndex-index]) + { + isPalindrome = false; + break; + } + + } + return isPalindrome; + } + + // método para "limpar" a string de diacríticos + // ps.: já havia utilizado anteriormente em produção + // -- fonte: https://stackoverflow.com/a/13155469 + private static string RemoveDiacritics(string str) + { + if (null == str) return null; + var chars = str + .Normalize(NormalizationForm.FormD) + .ToCharArray() + .Where(c=> CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark) + .ToArray(); + + return new string(chars).Normalize(NormalizationForm.FormC); + } + } +} diff --git a/palindromos/palindromos.csproj b/palindromos/palindromos.csproj new file mode 100644 index 0000000..d453e9a --- /dev/null +++ b/palindromos/palindromos.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp3.1 + + + From b12c9537bbdfd2c05082c35c2dafd4ca229028fd Mon Sep 17 00:00:00 2001 From: eduardomps Date: Sat, 14 Mar 2020 21:41:54 -0300 Subject: [PATCH 3/8] =?UTF-8?q?ajustes=20em=20rela=C3=A7=C3=A3o=20aos=20ta?= =?UTF-8?q?rgetFrameworks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 42 ++++------------------------------ .vscode/launch.json | 2 +- duplicados/Program.cs | 2 +- duplicados/duplicados.csproj | 2 +- palindromos/palindromos.csproj | 2 +- 5 files changed, 8 insertions(+), 42 deletions(-) diff --git a/.gitignore b/.gitignore index 3e3c159..877dd3b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,38 +1,4 @@ -duplicados/bin/Debug/netcoreapp3.1/duplicados -duplicados/bin/Debug/netcoreapp3.1/duplicados.deps.json -duplicados/bin/Debug/netcoreapp3.1/duplicados.dll -duplicados/bin/Debug/netcoreapp3.1/duplicados.pdb -duplicados/bin/Debug/netcoreapp3.1/duplicados.runtimeconfig.dev.json -duplicados/bin/Debug/netcoreapp3.1/duplicados.runtimeconfig.json -duplicados/obj/duplicados.csproj.nuget.cache -duplicados/obj/duplicados.csproj.nuget.dgspec.json -duplicados/obj/duplicados.csproj.nuget.g.props -duplicados/obj/duplicados.csproj.nuget.g.targets -duplicados/obj/project.assets.json -duplicados/obj/Debug/netcoreapp3.1/duplicados -duplicados/obj/Debug/netcoreapp3.1/duplicados.AssemblyInfo.cs -duplicados/obj/Debug/netcoreapp3.1/duplicados.AssemblyInfoInputs.cache -duplicados/obj/Debug/netcoreapp3.1/duplicados.assets.cache -duplicados/obj/Debug/netcoreapp3.1/duplicados.csproj.FileListAbsolute.txt -duplicados/obj/Debug/netcoreapp3.1/duplicados.csprojAssemblyReference.cache -duplicados/obj/Debug/netcoreapp3.1/duplicados.dll -duplicados/obj/Debug/netcoreapp3.1/duplicados.pdb -palindromos/bin/Debug/netcoreapp3.1/palindromos -palindromos/bin/Debug/netcoreapp3.1/palindromos.deps.json -palindromos/bin/Debug/netcoreapp3.1/palindromos.dll -palindromos/bin/Debug/netcoreapp3.1/palindromos.pdb -palindromos/bin/Debug/netcoreapp3.1/palindromos.runtimeconfig.dev.json -palindromos/bin/Debug/netcoreapp3.1/palindromos.runtimeconfig.json -palindromos/obj/palindromos.csproj.nuget.cache -palindromos/obj/palindromos.csproj.nuget.dgspec.json -palindromos/obj/palindromos.csproj.nuget.g.props -palindromos/obj/palindromos.csproj.nuget.g.targets -palindromos/obj/project.assets.json -palindromos/obj/Debug/netcoreapp3.1/palindromos -palindromos/obj/Debug/netcoreapp3.1/palindromos.AssemblyInfo.cs -palindromos/obj/Debug/netcoreapp3.1/palindromos.AssemblyInfoInputs.cache -palindromos/obj/Debug/netcoreapp3.1/palindromos.assets.cache -palindromos/obj/Debug/netcoreapp3.1/palindromos.csproj.FileListAbsolute.txt -palindromos/obj/Debug/netcoreapp3.1/palindromos.csprojAssemblyReference.cache -palindromos/obj/Debug/netcoreapp3.1/palindromos.dll -palindromos/obj/Debug/netcoreapp3.1/palindromos.pdb +duplicados/bin/* +duplicados/obj/* +palindromos/bin/* +palindromos/obj/* \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 79bd94c..2013c06 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,7 +11,7 @@ "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. "program": "${workspaceFolder}/duplicados/bin/Debug/netcoreapp3.1/duplicados.dll", - "args": [], + "args": ["002,12,4,97866,1234,9,35,3456,12,3"], "cwd": "${workspaceFolder}/duplicados", // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console "console": "internalConsole", diff --git a/duplicados/Program.cs b/duplicados/Program.cs index 3ddc8a0..eacdcf6 100644 --- a/duplicados/Program.cs +++ b/duplicados/Program.cs @@ -62,7 +62,7 @@ private static (bool validArgs, string errorMessage) ValidateArgs(string numbers { return (false,"Separador não encontrado na lista!"); } - if(!Regex.IsMatch(numbers,@$"^(\d+)({separator}\d+)*")) + if(!Regex.IsMatch(numbers,$@"^(\d+)({separator}\d+)*")) { return (false,"Lista inválida!"); } diff --git a/duplicados/duplicados.csproj b/duplicados/duplicados.csproj index d453e9a..4071de9 100644 --- a/duplicados/duplicados.csproj +++ b/duplicados/duplicados.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + netcoreapp3.1;netcoreapp3.0;netcoreapp2.2;netcoreapp2.1;netcoreapp2.0 diff --git a/palindromos/palindromos.csproj b/palindromos/palindromos.csproj index d453e9a..4071de9 100644 --- a/palindromos/palindromos.csproj +++ b/palindromos/palindromos.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + netcoreapp3.1;netcoreapp3.0;netcoreapp2.2;netcoreapp2.1;netcoreapp2.0 From e14cf05bc0530d13d2bf61991b93356bf81ae17d Mon Sep 17 00:00:00 2001 From: eduardomps Date: Sun, 15 Mar 2020 15:43:01 -0300 Subject: [PATCH 4/8] API funcional + db SQLite todo: login, calculo de rota --- .gitignore | 4 +- cidades/Cidades.db | Bin 0 -> 36864 bytes cidades/Controllers/CityController.cs | 90 ++++++++++++++++++ cidades/Infrastructure/CityDbContext.cs | 20 ++++ .../Configuration/CityConfiguration.cs | 21 ++++ .../Configuration/CityToCityConfiguration.cs | 17 ++++ .../Extensions/AuthServiceExtentions.cs | 29 ++++++ .../Infrastructure/Services/CityService.cs | 64 +++++++++++++ .../20200315180129_createNew.Designer.cs | 77 +++++++++++++++ .../Migrations/20200315180129_createNew.cs | 69 ++++++++++++++ .../Migrations/CityDbContextModelSnapshot.cs | 75 +++++++++++++++ cidades/Model/City.cs | 26 +++++ cidades/Model/CityToCity.cs | 10 ++ cidades/Program.cs | 26 +++++ cidades/Properties/launchSettings.json | 30 ++++++ cidades/Startup.cs | 67 +++++++++++++ cidades/appsettings.Development.json | 9 ++ cidades/appsettings.json | 13 +++ cidades/cidades.csproj | 13 +++ palindromos/palindromos.csproj | 2 +- 20 files changed, 660 insertions(+), 2 deletions(-) create mode 100644 cidades/Cidades.db create mode 100644 cidades/Controllers/CityController.cs create mode 100644 cidades/Infrastructure/CityDbContext.cs create mode 100644 cidades/Infrastructure/Configuration/CityConfiguration.cs create mode 100644 cidades/Infrastructure/Configuration/CityToCityConfiguration.cs create mode 100644 cidades/Infrastructure/Extensions/AuthServiceExtentions.cs create mode 100644 cidades/Infrastructure/Services/CityService.cs create mode 100644 cidades/Migrations/20200315180129_createNew.Designer.cs create mode 100644 cidades/Migrations/20200315180129_createNew.cs create mode 100644 cidades/Migrations/CityDbContextModelSnapshot.cs create mode 100644 cidades/Model/City.cs create mode 100644 cidades/Model/CityToCity.cs create mode 100644 cidades/Program.cs create mode 100644 cidades/Properties/launchSettings.json create mode 100644 cidades/Startup.cs create mode 100644 cidades/appsettings.Development.json create mode 100644 cidades/appsettings.json create mode 100644 cidades/cidades.csproj diff --git a/.gitignore b/.gitignore index 877dd3b..c8a3f11 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ duplicados/bin/* duplicados/obj/* palindromos/bin/* -palindromos/obj/* \ No newline at end of file +palindromos/obj/* +cidades/bin/* +cidades/obj/* \ No newline at end of file diff --git a/cidades/Cidades.db b/cidades/Cidades.db new file mode 100644 index 0000000000000000000000000000000000000000..2e7a74980e48d20094bc0d8d37fa629c9145c5ac GIT binary patch literal 36864 zcmeI*&2QUe90%~nZ+YvIXJ$ZDs;W;7(i*L+`T}f~m`3KhC9F-eI7RCLMJ6$ur_}Cj zhcRwt5^&_Oe}EGlK;nWxoOa^Gal1|&kaj^6haJ$6fX9y8CS7`%#HH2OO49g=pWp9! zKF^a%PU@%Tl~pIS*@vFLWrb{koFt-1-e!ytBJq2c-*-2KKaqEL_)nql`C(5bGV?mi z)4xb2cb^m<(C_m9kU@jSY4g&f4Siu zc7VQKH5>IZug$dDZP6*RWIUN3~)GwxtQR%vUcXb_i-RfCVVUN-gelJQ&_qh1fo$;+QFYp%4AN)=Zo z1rpDf;AV%PgEg&g=*9beYR$R*u}jzFRPoFiVKW}xq*7qt?AmV2KCr6{jPrpPr(8aL zrg_cMPD4r;M@NM_((a7mT0LcXAVM_tdyu=+;Mobl`UkEz_HmW|aW8K))+<#Wdd;Xd zk|`BWX4WvS4otL~x83bnq2syFW=bj!%>MlVxzf&tkS?A(Cwy9oyVYzO%WKXxKaLi> z;{>7S-yT{h4t9FzG5r14GuR8sr&f|Zd9NIlI3!LVOwyy8@3p(F@IBiP;*R%FlBl^- zMNAdnKX=%y8JeXzH?%l9x6eesYV-Uq(1(QIut5L<5P$##AOHafKmY;|fB*y_a3lqo zAYCZV&(6=zF3i0#cYbzmezDo|ZT>-I)xNbbGdDAzz{}fB*y_009U< z00Izz00ba#gayW=3)#ay1c<)>&lm2A^bvhPf2Lp4yL6kb)3@krG*fs~xL>$;ggcI= zLjVF0fB*y_009U<00Izzz_Af{A+L}LQPnNi?l|ssYvwmoS5GKpOi~-pjc&^d$lYyI zpBPcdqNuKTAKAWZwLPEdb|>&y-P-bkH@`RaS8@tDE2*aCv3EWGaEV_m5QG-_@(WXc zIjfMt4$e?@sX|IWD^7TQ1`LTqY6nVoW((6oMOFx`13cL%Fy4>-6$8x=Guj2&i zub8R#{{H_7p-+y@lt4!y009U<00Izz00bZa0SG_<0ubN=IYAl~dJ8(_d*}a834ID0 z2tWV=5P$##AOHafKmY;|fB*!JpMWe#SwZYw|Bv(k<2SzO5dLW$@tSTH_A;8pgFUqG? zVPJItQ_oU)Torbg1~BzZ9D4Y=0H&U1^2I3hA&UZ-dMa*cvLb+~EAei!8i1+GFUh4S zS^r7^rq2JzUtS(3Ns9wpJjL6Y9asW@H=YlnK>sHEh7AG`fB*y_009U<00Izz00bZa Nf#WA2OZ@x){{ZSMcKQGS literal 0 HcmV?d00001 diff --git a/cidades/Controllers/CityController.cs b/cidades/Controllers/CityController.cs new file mode 100644 index 0000000..0fccc2f --- /dev/null +++ b/cidades/Controllers/CityController.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using cidades.Infrastructure.Services; +using cidades.Model; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; + +namespace cidades.Controllers +{ + + [ApiController, Route("api/[controller]"), AllowAnonymous]//, Authorize] + public class CityController : ControllerBase + { + private readonly ILogger _logger; + private readonly CityService _service; + + public CityController(ILogger logger, CityService service) + { + _logger = logger; + _service = service; + } + + [HttpGet]//, AllowAnonymous] + public IActionResult List() + { + var cities = _service.List(); + return Ok(cities); + } + + [HttpPost, Route("create")] + public IActionResult Create([FromBody]City city) + { + City cityDb = _service.Find(city.Name, city.CountryState); + if(cityDb!=null) + return BadRequest(new { Error = "Cidade já existe na base!" }); + _service.Create(city); + return CreatedAtAction(nameof(Get), new { id = city.Id }, city); + } + + [HttpGet,Route("{id:int}")] + public IActionResult Get(int id) + { + City city = _service.Get(id); + if(city==null) + return NotFound(); + return Ok(city); + } + + [HttpPost("{id:int}/update")] + public IActionResult Update(int id, [FromBody]City city) + { + City cityDb = _service.Get(id); + if(cityDb==null) + return NotFound(); + + _service.Update(id, city); + return NoContent(); + } + + [HttpGet("population/{idList:regex(^(\\d+)(,\\d+)*$)}")] + public IActionResult SumPopulation(string idList) + { + List cities = _service.GetCities(idList); + long totalPop = cities.Sum(c => c.Population); + string names = string.Join(',',cities.Select(c => c.Name).ToList()); + return Ok(new { Cities = names, TotalPopulation = totalPop }); + } + + [HttpGet("{id:int}/limits")] + public IActionResult Limits(int id) + { + //todo get city + City city = new City(){Id = id}; + string neighborNames = string.Join(',',city.Neighbors.Select(c => c.Name).ToList()); + return Ok(new { City = city.Name, Neighbors = neighborNames }); + } + + [HttpGet("findpath/{idFrom:int}/{idTo:int}")] + public IActionResult FindPath(int idFrom, int idTo) + { + //todo get path + List path = new List(); + string pathCityNames = string.Join(',',path.Select(c => c.Name).ToList()); + return Ok(new { Path = pathCityNames }); + } + } +} \ No newline at end of file diff --git a/cidades/Infrastructure/CityDbContext.cs b/cidades/Infrastructure/CityDbContext.cs new file mode 100644 index 0000000..f8a4d62 --- /dev/null +++ b/cidades/Infrastructure/CityDbContext.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using cidades.Model; +using Microsoft.EntityFrameworkCore; + +namespace cidades.Infrastructure +{ + public class CityDbContext : DbContext + { + public CityDbContext(DbContextOptions options):base(options) + { + + } + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); + } + + public DbSet Cities {get;set;} + } +} \ No newline at end of file diff --git a/cidades/Infrastructure/Configuration/CityConfiguration.cs b/cidades/Infrastructure/Configuration/CityConfiguration.cs new file mode 100644 index 0000000..c4bcae5 --- /dev/null +++ b/cidades/Infrastructure/Configuration/CityConfiguration.cs @@ -0,0 +1,21 @@ +using cidades.Model; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace cidades.Infrastructure.Configuration +{ + public class CityConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(c => c.Id); + builder.Property(c => c.Name); + builder.Property(c => c.Population); + builder.Property(c => c.CountryState).HasMaxLength(2); + builder.HasIndex(c => new { c.Name, c.CountryState }).IsUnique(true); + builder.HasMany(c => c.CityRoutes).WithOne(cr => cr.City).HasForeignKey(c => c.IdCity); + builder.Ignore(c => c.Neighbors); + } + + } +} \ No newline at end of file diff --git a/cidades/Infrastructure/Configuration/CityToCityConfiguration.cs b/cidades/Infrastructure/Configuration/CityToCityConfiguration.cs new file mode 100644 index 0000000..111ac98 --- /dev/null +++ b/cidades/Infrastructure/Configuration/CityToCityConfiguration.cs @@ -0,0 +1,17 @@ +using cidades.Model; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace cidades.Infrastructure.Configuration +{ + public class CityToCityConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(c =>new {c.IdCity,c.IdCityTo}); + + builder.HasOne(cc => cc.CityTo).WithMany(c => c.CityRoutesFrom).HasForeignKey(c => c.IdCityTo); + } + + } +} \ No newline at end of file diff --git a/cidades/Infrastructure/Extensions/AuthServiceExtentions.cs b/cidades/Infrastructure/Extensions/AuthServiceExtentions.cs new file mode 100644 index 0000000..06dd570 --- /dev/null +++ b/cidades/Infrastructure/Extensions/AuthServiceExtentions.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Net; +using System.Net.Http; + +namespace AytyTechSafetySuite.Extensions +{ + public static class AuthServiceExtension + { + + public static IServiceCollection AddCustomAuth(this IServiceCollection services, IConfiguration configuration) + { + services + .AddAuthorization() + .AddAuthentication( + ).AddJwtBearer("Bearer", options => + { + options.Authority = $"{configuration["Identity:AuthorityUrl"]}"; + options.TokenValidationParameters.ValidateAudience = false; + options.TokenValidationParameters.ValidateLifetime = true; + options.TokenValidationParameters.ValidateIssuer = false; + }); + return services; + } + } +} \ No newline at end of file diff --git a/cidades/Infrastructure/Services/CityService.cs b/cidades/Infrastructure/Services/CityService.cs new file mode 100644 index 0000000..bfbae94 --- /dev/null +++ b/cidades/Infrastructure/Services/CityService.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using cidades.Model; +using Microsoft.EntityFrameworkCore; + +namespace cidades.Infrastructure.Services +{ + public class CityService + { + private readonly CityDbContext _dbContext; + public CityService(CityDbContext dbContext) + { + _dbContext = dbContext; + } + + internal void Create(City city) + { + _dbContext.Cities.Add(city); + _dbContext.SaveChanges(); + } + + internal City Get(int id) + { + return _dbContext.Cities + .Include(c => c.CityRoutes) + .ThenInclude(cr => cr.CityTo) + .FirstOrDefault(c => c.Id == id); + } + + internal void Update(int id, City city) + { + City cityDb = this.Get(id); + + if(!string.IsNullOrEmpty(city.Name)) + cityDb.Name = city.Name; + if(city.Population > 0) + cityDb.Population = city.Population; + if(city.CityRoutes.Count > 0) + cityDb.CityRoutes = city.CityRoutes; + _dbContext.Cities.Update(cityDb); + _dbContext.SaveChanges(); + } + + internal List List() + { + return _dbContext.Cities.ToList(); + } + + internal City Find(string name, string countryState) + { + return _dbContext.Cities.FirstOrDefault(c => c.Name == name && c.CountryState == countryState); + } + + internal List GetCities(string idList) + { + List idIntList = idList + .Split(',',StringSplitOptions.RemoveEmptyEntries) + .Select(id => int.Parse(id)) + .ToList(); + return _dbContext.Cities.Where(c => idIntList.Contains(c.Id.Value)).ToList(); + } + } +} \ No newline at end of file diff --git a/cidades/Migrations/20200315180129_createNew.Designer.cs b/cidades/Migrations/20200315180129_createNew.Designer.cs new file mode 100644 index 0000000..d34225e --- /dev/null +++ b/cidades/Migrations/20200315180129_createNew.Designer.cs @@ -0,0 +1,77 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using cidades.Infrastructure; + +namespace cidades.Migrations +{ + [DbContext(typeof(CityDbContext))] + [Migration("20200315180129_createNew")] + partial class createNew + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.2"); + + modelBuilder.Entity("cidades.Model.City", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CountryState") + .HasColumnType("TEXT") + .HasMaxLength(2); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Population") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Name", "CountryState") + .IsUnique(); + + b.ToTable("Cities"); + }); + + modelBuilder.Entity("cidades.Model.CityToCity", b => + { + b.Property("IdCity") + .HasColumnType("INTEGER"); + + b.Property("IdCityTo") + .HasColumnType("INTEGER"); + + b.HasKey("IdCity", "IdCityTo"); + + b.HasIndex("IdCityTo"); + + b.ToTable("CityToCity"); + }); + + modelBuilder.Entity("cidades.Model.CityToCity", b => + { + b.HasOne("cidades.Model.City", "City") + .WithMany("CityRoutes") + .HasForeignKey("IdCity") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("cidades.Model.City", "CityTo") + .WithMany("CityRoutesFrom") + .HasForeignKey("IdCityTo") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/cidades/Migrations/20200315180129_createNew.cs b/cidades/Migrations/20200315180129_createNew.cs new file mode 100644 index 0000000..ba50b2b --- /dev/null +++ b/cidades/Migrations/20200315180129_createNew.cs @@ -0,0 +1,69 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace cidades.Migrations +{ + public partial class createNew : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Cities", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(nullable: true), + Population = table.Column(nullable: false), + CountryState = table.Column(maxLength: 2, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Cities", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "CityToCity", + columns: table => new + { + IdCity = table.Column(nullable: false), + IdCityTo = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CityToCity", x => new { x.IdCity, x.IdCityTo }); + table.ForeignKey( + name: "FK_CityToCity_Cities_IdCity", + column: x => x.IdCity, + principalTable: "Cities", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_CityToCity_Cities_IdCityTo", + column: x => x.IdCityTo, + principalTable: "Cities", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Cities_Name_CountryState", + table: "Cities", + columns: new[] { "Name", "CountryState" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_CityToCity_IdCityTo", + table: "CityToCity", + column: "IdCityTo"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CityToCity"); + + migrationBuilder.DropTable( + name: "Cities"); + } + } +} diff --git a/cidades/Migrations/CityDbContextModelSnapshot.cs b/cidades/Migrations/CityDbContextModelSnapshot.cs new file mode 100644 index 0000000..7583721 --- /dev/null +++ b/cidades/Migrations/CityDbContextModelSnapshot.cs @@ -0,0 +1,75 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using cidades.Infrastructure; + +namespace cidades.Migrations +{ + [DbContext(typeof(CityDbContext))] + partial class CityDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.2"); + + modelBuilder.Entity("cidades.Model.City", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CountryState") + .HasColumnType("TEXT") + .HasMaxLength(2); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Population") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Name", "CountryState") + .IsUnique(); + + b.ToTable("Cities"); + }); + + modelBuilder.Entity("cidades.Model.CityToCity", b => + { + b.Property("IdCity") + .HasColumnType("INTEGER"); + + b.Property("IdCityTo") + .HasColumnType("INTEGER"); + + b.HasKey("IdCity", "IdCityTo"); + + b.HasIndex("IdCityTo"); + + b.ToTable("CityToCity"); + }); + + modelBuilder.Entity("cidades.Model.CityToCity", b => + { + b.HasOne("cidades.Model.City", "City") + .WithMany("CityRoutes") + .HasForeignKey("IdCity") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("cidades.Model.City", "CityTo") + .WithMany("CityRoutesFrom") + .HasForeignKey("IdCityTo") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/cidades/Model/City.cs b/cidades/Model/City.cs new file mode 100644 index 0000000..19863b6 --- /dev/null +++ b/cidades/Model/City.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; + +namespace cidades.Model +{ + public class City + { + public int? Id {get;set;} + public string Name {get;set;} + public int Population {get;set;} + public string CountryState {get;set;} + public List CityRoutes {get;set;} = new List(); + [JsonIgnore] + public List CityRoutesFrom {get;set;} = new List(); + public List Neighbors + { + get + { + return CityRoutes.Select(r => r.CityTo).ToList(); + } + } + + + } +} \ No newline at end of file diff --git a/cidades/Model/CityToCity.cs b/cidades/Model/CityToCity.cs new file mode 100644 index 0000000..7a4f427 --- /dev/null +++ b/cidades/Model/CityToCity.cs @@ -0,0 +1,10 @@ +namespace cidades.Model +{ + public class CityToCity + { + public int IdCity {get;set;} + public City City {get;set;} + public int IdCityTo {get;set;} + public City CityTo {get;set;} + } +} \ No newline at end of file diff --git a/cidades/Program.cs b/cidades/Program.cs new file mode 100644 index 0000000..e08ad6d --- /dev/null +++ b/cidades/Program.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace cidades +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} diff --git a/cidades/Properties/launchSettings.json b/cidades/Properties/launchSettings.json new file mode 100644 index 0000000..6396d62 --- /dev/null +++ b/cidades/Properties/launchSettings.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:2391", + "sslPort": 44316 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "weatherforecast", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "cidades": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "weatherforecast", + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/cidades/Startup.cs b/cidades/Startup.cs new file mode 100644 index 0000000..2cf7259 --- /dev/null +++ b/cidades/Startup.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using AytyTechSafetySuite.Extensions; +using cidades.Infrastructure; +using cidades.Infrastructure.Services; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; + +namespace cidades +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddDbContext( + options => options.UseSqlite(Configuration.GetConnectionString("SQLite")) + ); + services.AddScoped(); + services.AddCustomAuth(Configuration); + services.AddControllers() + .AddNewtonsoftJson(options => + //evitando referencias circulares com Json.NET... + options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore); + services.AddRouting(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseHttpsRedirection(); + + app.UseRouting(); + + app.UseAuthorization(); + + app.UseAuthentication(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } + } +} diff --git a/cidades/appsettings.Development.json b/cidades/appsettings.Development.json new file mode 100644 index 0000000..4f30a00 --- /dev/null +++ b/cidades/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/cidades/appsettings.json b/cidades/appsettings.json new file mode 100644 index 0000000..d3cb2bd --- /dev/null +++ b/cidades/appsettings.json @@ -0,0 +1,13 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + "ConnectionStrings":{ + "SQLite":"Data Source=Cidades.db" + } +} diff --git a/cidades/cidades.csproj b/cidades/cidades.csproj new file mode 100644 index 0000000..c5b9b6e --- /dev/null +++ b/cidades/cidades.csproj @@ -0,0 +1,13 @@ + + + netcoreapp3.1 + + + + + + + + + + \ No newline at end of file diff --git a/palindromos/palindromos.csproj b/palindromos/palindromos.csproj index 4071de9..d453e9a 100644 --- a/palindromos/palindromos.csproj +++ b/palindromos/palindromos.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1;netcoreapp3.0;netcoreapp2.2;netcoreapp2.1;netcoreapp2.0 + netcoreapp3.1 From 161d97e30f44b35078048d5f433a2e477df36c7f Mon Sep 17 00:00:00 2001 From: eduardomps Date: Sun, 15 Mar 2020 17:03:18 -0300 Subject: [PATCH 5/8] =?UTF-8?q?atualiza=C3=A7=C3=A3o=20dos=20relacionament?= =?UTF-8?q?os=20de=20cidades?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cidades/Cidades.db | Bin 36864 -> 36864 bytes cidades/Controllers/CityController.cs | 5 +++-- .../Infrastructure/Services/CityService.cs | 6 ++++-- cidades/Model/City.cs | 7 ++++++- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/cidades/Cidades.db b/cidades/Cidades.db index 2e7a74980e48d20094bc0d8d37fa629c9145c5ac..abc3384e2ad7dcc8bd42e0a3693375b6560037b9 100644 GIT binary patch delta 864 zcmXZaPe>F|90%|>Gw;vL?9BVlxOoVX>{uWKMG%By0}%xkOkKJSBD%8emgXgd6@v&n zNUcTKA?r|429kBC4oTFZA}}F>pr9nA5{jZr5%hjD?&15{nVlWJyYn5JvBzfYIcv*C zoMxe(l~}4uRNGl2kO0|E793_0h7arjWm*7GXu8;;>2|-A~33EVjVG|DDYQAOJzWMoO3{vr* z_=-<>hb2?`7GB^X?&3VIVcL`)$4Lxf&=lW^hT;|#FXu|tk}FhPD5G2+qR`icL0DJ{ zavfDF^!-B5E97pWt8#563#BL&J9zPiJB5xdxMz8`k8!htB^T|e;y$ioRWHHCE9}!h z%=75PSyO*bH+5sW(aJZ)R!{9jy;iArB-v24KAa{FrkQ62m|>c?#n##o(j>rBrmPSV z-w<0#R-+{hWN8v&vAA+qrGF&r9Z3^z{!M8~lldLi29hR%v5>bjE6wU1d+Wn}&2NqM zW-pTrfAJgN@fu&SY#P7EV_e1svz?cCW>)h6^O(d9(>ud)dYD0(Qnln6Q_6@k1f{Pj mgOJh;%cLsh=Y2}gqvS57t0_{6!S|f+3g3avf&%mS zCad?EnA( diff --git a/cidades/Controllers/CityController.cs b/cidades/Controllers/CityController.cs index 0fccc2f..d165739 100644 --- a/cidades/Controllers/CityController.cs +++ b/cidades/Controllers/CityController.cs @@ -72,8 +72,9 @@ public IActionResult SumPopulation(string idList) [HttpGet("{id:int}/limits")] public IActionResult Limits(int id) { - //todo get city - City city = new City(){Id = id}; + City city = _service.Get(id); + if(city==null) + return NotFound(); string neighborNames = string.Join(',',city.Neighbors.Select(c => c.Name).ToList()); return Ok(new { City = city.Name, Neighbors = neighborNames }); } diff --git a/cidades/Infrastructure/Services/CityService.cs b/cidades/Infrastructure/Services/CityService.cs index bfbae94..3531b4a 100644 --- a/cidades/Infrastructure/Services/CityService.cs +++ b/cidades/Infrastructure/Services/CityService.cs @@ -25,6 +25,8 @@ internal City Get(int id) return _dbContext.Cities .Include(c => c.CityRoutes) .ThenInclude(cr => cr.CityTo) + .Include(c => c.CityRoutesFrom) + .ThenInclude(cr => cr.City) .FirstOrDefault(c => c.Id == id); } @@ -36,8 +38,8 @@ internal void Update(int id, City city) cityDb.Name = city.Name; if(city.Population > 0) cityDb.Population = city.Population; - if(city.CityRoutes.Count > 0) - cityDb.CityRoutes = city.CityRoutes; + if(!string.IsNullOrEmpty(city.CountryState)) + cityDb.CountryState = city.CountryState; _dbContext.Cities.Update(cityDb); _dbContext.SaveChanges(); } diff --git a/cidades/Model/City.cs b/cidades/Model/City.cs index 19863b6..0534560 100644 --- a/cidades/Model/City.cs +++ b/cidades/Model/City.cs @@ -17,7 +17,12 @@ public List Neighbors { get { - return CityRoutes.Select(r => r.CityTo).ToList(); + var listTo = CityRoutes.Select(r => r.CityTo).ToList(); + var listFrom = CityRoutesFrom.Select(r => r.City) + .Where(c => !listTo.Contains(c)) + .ToList(); + listTo.AddRange(listFrom); + return listTo; } } From 6851e0d2cf9bf11faa7443871fa914792d52b94a Mon Sep 17 00:00:00 2001 From: eduardomps Date: Sun, 15 Mar 2020 17:46:47 -0300 Subject: [PATCH 6/8] Implementado FindPath --- cidades/Controllers/CityController.cs | 12 ++-- .../Infrastructure/Services/CityService.cs | 66 +++++++++++++++++++ 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/cidades/Controllers/CityController.cs b/cidades/Controllers/CityController.cs index d165739..3f42269 100644 --- a/cidades/Controllers/CityController.cs +++ b/cidades/Controllers/CityController.cs @@ -82,10 +82,14 @@ public IActionResult Limits(int id) [HttpGet("findpath/{idFrom:int}/{idTo:int}")] public IActionResult FindPath(int idFrom, int idTo) { - //todo get path - List path = new List(); - string pathCityNames = string.Join(',',path.Select(c => c.Name).ToList()); - return Ok(new { Path = pathCityNames }); + City city = _service.Get(idFrom); + City cityTo = _service.Get(idTo); + if(city == null || cityTo == null) + return NotFound(); + + string pathCityNames = _service.FindPath(city, cityTo); + + return Ok(new { Start = city.Name, End = cityTo.Name, Path = pathCityNames }); } } } \ No newline at end of file diff --git a/cidades/Infrastructure/Services/CityService.cs b/cidades/Infrastructure/Services/CityService.cs index 3531b4a..88756fe 100644 --- a/cidades/Infrastructure/Services/CityService.cs +++ b/cidades/Infrastructure/Services/CityService.cs @@ -62,5 +62,71 @@ internal List GetCities(string idList) .ToList(); return _dbContext.Cities.Where(c => idIntList.Contains(c.Id.Value)).ToList(); } + + internal string FindPath(City city, City cityTo) + { + return this.DepthFirstIterative(city, cityTo); + } + + // Das aulas de Estrutura de Dados 1/2: DFS + // procura em um grafo selecionando sempre, no caso, a primeira cidade vizinha + // caso não encontre, faz o backtrack e tenta a segunda, e assim por diante + // ligeiramente modificado da fonte: https://stackoverflow.com/a/26429707 + private string DepthFirstIterative(City start, City endNode) + { + string pathCityNames = string.Empty; + var visited = new LinkedList(); + var stack = new Stack(); + + stack.Push(start); + + while (stack.Count != 0) + { + var current = stack.Pop(); + + if (visited.Contains(current)) + continue; + + visited.AddLast(current); + // faz o Get toda vez, para garantir o Load das entidades + // das listas que compõem a propriedade Neighbors + var neighbors = new LinkedList(this.Get(current.Id.Value).Neighbors); + + foreach (var neighbor in neighbors) + { + if (visited.Contains(neighbor)) + continue; + + if (neighbor.Equals(endNode)) + { + visited.AddLast(neighbor); + pathCityNames = string.Join(',',visited.Select(c => c.Name).ToList()); + visited.RemoveLast(); + break; + } + } + + // aqui não estamos necessariamente preocupados com menor caminho + // então se encontrou um, já retorna + if(!string.IsNullOrEmpty(pathCityNames)) + break; + + bool isPushed = false; + foreach (var neighbor in neighbors.Reverse()) + { + if (neighbor.Equals(endNode) || visited.Contains(neighbor) || stack.Contains(neighbor)) + { + continue; + } + + isPushed = true; + stack.Push(neighbor); + } + + if (!isPushed) + visited.RemoveLast(); + } + return pathCityNames; + } } } \ No newline at end of file From 6e0c0baa3814f035666273dedb1ff3c5b892e2ea Mon Sep 17 00:00:00 2001 From: eduardomps Date: Sun, 15 Mar 2020 18:54:23 -0300 Subject: [PATCH 7/8] =?UTF-8?q?Auth=20funcional=20+=20m=C3=A9todo=20de=20l?= =?UTF-8?q?ogin=20que=20retorna=20JWT=20para=20os=20demais?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cidades/Controllers/CityController.cs | 6 +- cidades/Controllers/UserController.cs | 63 +++++++++++++++++++ .../Extensions/AuthServiceExtentions.cs | 46 +++++++++++--- .../Infrastructure/Services/CityService.cs | 4 +- .../Infrastructure/Services/UserService.cs | 48 ++++++++++++++ cidades/Model/City.cs | 2 + cidades/Model/User.cs | 9 +++ cidades/Startup.cs | 8 +-- cidades/appsettings.Development.json | 2 +- cidades/appsettings.json | 3 + 10 files changed, 170 insertions(+), 21 deletions(-) create mode 100644 cidades/Controllers/UserController.cs create mode 100644 cidades/Infrastructure/Services/UserService.cs create mode 100644 cidades/Model/User.cs diff --git a/cidades/Controllers/CityController.cs b/cidades/Controllers/CityController.cs index 3f42269..3d6d5a7 100644 --- a/cidades/Controllers/CityController.cs +++ b/cidades/Controllers/CityController.cs @@ -1,7 +1,5 @@ -using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; using cidades.Infrastructure.Services; using cidades.Model; using Microsoft.AspNetCore.Authorization; @@ -11,7 +9,7 @@ namespace cidades.Controllers { - [ApiController, Route("api/[controller]"), AllowAnonymous]//, Authorize] + [ApiController, Route("api/[controller]"), Authorize] public class CityController : ControllerBase { private readonly ILogger _logger; @@ -23,7 +21,7 @@ public CityController(ILogger logger, CityService service) _service = service; } - [HttpGet]//, AllowAnonymous] + [HttpGet, AllowAnonymous] public IActionResult List() { var cities = _service.List(); diff --git a/cidades/Controllers/UserController.cs b/cidades/Controllers/UserController.cs new file mode 100644 index 0000000..cd35e2e --- /dev/null +++ b/cidades/Controllers/UserController.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Security.Claims; +using System.Text; +using cidades.Infrastructure.Services; +using cidades.Model; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.Tokens; + +namespace cidades.Controllers +{ + // baseado no sample do OpenIddict: + // https://github.com/cornflourblue/aspnet-core-3-registration-login-api + [ApiController, Route("api/[controller]"), AllowAnonymous] + public class UserController : ControllerBase + { + private readonly UserService _userService; + private readonly IConfiguration _configuration; + public UserController(UserService userService, IConfiguration configuration) + { + _userService = userService; + _configuration = configuration; + } + + [HttpPost("authenticate")] + public IActionResult Authenticate([FromBody]User model) + { + var user = _userService.Authenticate(model.Username, model.Password); + + if (user == null) + return BadRequest(new { message = "Username or password is incorrect" }); + + var tokenHandler = new JwtSecurityTokenHandler(); + var key = Encoding.ASCII.GetBytes(_configuration.GetValue("JWT:SigningKey")); + var tokenDescriptor = new SecurityTokenDescriptor + { + Subject = new ClaimsIdentity(new Claim[] + { + new Claim(ClaimTypes.Name, user.Id.ToString()) + }), + Expires = DateTime.UtcNow.AddHours(2), + SigningCredentials = new SigningCredentials + (new SymmetricSecurityKey(key), + SecurityAlgorithms.HmacSha256Signature) + }; + var token = tokenHandler.CreateToken(tokenDescriptor); + var tokenString = tokenHandler.WriteToken(token); + + + return Ok(new + { + Id = user.Id, + Username = user.Username, + Token = tokenString + }); + } + } +} \ No newline at end of file diff --git a/cidades/Infrastructure/Extensions/AuthServiceExtentions.cs b/cidades/Infrastructure/Extensions/AuthServiceExtentions.cs index 06dd570..c10c73e 100644 --- a/cidades/Infrastructure/Extensions/AuthServiceExtentions.cs +++ b/cidades/Infrastructure/Extensions/AuthServiceExtentions.cs @@ -1,10 +1,14 @@ +using cidades.Infrastructure.Services; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; using System; using System.Net; using System.Net.Http; +using System.Text; +using System.Threading.Tasks; namespace AytyTechSafetySuite.Extensions { @@ -13,16 +17,40 @@ public static class AuthServiceExtension public static IServiceCollection AddCustomAuth(this IServiceCollection services, IConfiguration configuration) { - services - .AddAuthorization() - .AddAuthentication( - ).AddJwtBearer("Bearer", options => + services.AddAuthentication(x => + { + x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(x => + { + x.Events = new JwtBearerEvents { - options.Authority = $"{configuration["Identity:AuthorityUrl"]}"; - options.TokenValidationParameters.ValidateAudience = false; - options.TokenValidationParameters.ValidateLifetime = true; - options.TokenValidationParameters.ValidateIssuer = false; - }); + OnTokenValidated = context => + { + var userService = context.HttpContext.RequestServices.GetRequiredService(); + var userId = int.Parse(context.Principal.Identity.Name); + var user = userService.GetById(userId); + if (user == null) + { + context.Fail("Unauthorized"); + }else{ + context.Success(); + } + return Task.CompletedTask; + } + }; + x.RequireHttpsMetadata = false; + x.SaveToken = true; + var key = Encoding.ASCII.GetBytes(configuration.GetValue("JWT:SigningKey")); + x.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(key), + ValidateIssuer = false, + ValidateAudience = false + }; + }); return services; } } diff --git a/cidades/Infrastructure/Services/CityService.cs b/cidades/Infrastructure/Services/CityService.cs index 88756fe..7d63664 100644 --- a/cidades/Infrastructure/Services/CityService.cs +++ b/cidades/Infrastructure/Services/CityService.cs @@ -46,7 +46,9 @@ internal void Update(int id, City city) internal List List() { - return _dbContext.Cities.ToList(); + return _dbContext.Cities + // sem os Include pois o retorno do List ficaria com vários MB! + .ToList(); } internal City Find(string name, string countryState) diff --git a/cidades/Infrastructure/Services/UserService.cs b/cidades/Infrastructure/Services/UserService.cs new file mode 100644 index 0000000..08dfafa --- /dev/null +++ b/cidades/Infrastructure/Services/UserService.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using cidades.Model; +using Microsoft.EntityFrameworkCore; + +namespace cidades.Infrastructure.Services +{ + // baseado no sample do OpenIddict: + // https://github.com/cornflourblue/aspnet-core-3-registration-login-api + public class UserService + { + // lista hardcoded de usuários, por simplicidade + private readonly List users = new List + { + new User(){ Id = 1, Username = "eduardo", Password = "teste"}, + new User(){ Id = 2, Username = "knewin", Password = "vagaemprego"} + }; + public UserService() + { + } + + public User Authenticate(string username, string password) + { + if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) + return null; + + // aqui buscaria de uma fonte correta + // para fins deste teste, estamos usando uma lista hardcoded + var user = users.SingleOrDefault(x => x.Username == username); + + if (user == null) + return null; + + // aqui também deveria verificar o hash, não a igualdade + if (password!=user.Password) + return null; + + + return user; + } + + internal object GetById(int userId) + { + return users.SingleOrDefault(u => u.Id == userId); + } + } +} diff --git a/cidades/Model/City.cs b/cidades/Model/City.cs index 0534560..fd98a01 100644 --- a/cidades/Model/City.cs +++ b/cidades/Model/City.cs @@ -10,9 +10,11 @@ public class City public string Name {get;set;} public int Population {get;set;} public string CountryState {get;set;} + [JsonIgnore] public List CityRoutes {get;set;} = new List(); [JsonIgnore] public List CityRoutesFrom {get;set;} = new List(); + public List Neighbors { get diff --git a/cidades/Model/User.cs b/cidades/Model/User.cs new file mode 100644 index 0000000..707ecac --- /dev/null +++ b/cidades/Model/User.cs @@ -0,0 +1,9 @@ +namespace cidades.Model +{ + public class User + { + public int Id {get;set;} + public string Username {get;set;} + public string Password {get;set;} + } +} \ No newline at end of file diff --git a/cidades/Startup.cs b/cidades/Startup.cs index 2cf7259..4a1afcc 100644 --- a/cidades/Startup.cs +++ b/cidades/Startup.cs @@ -35,6 +35,7 @@ public void ConfigureServices(IServiceCollection services) ); services.AddScoped(); services.AddCustomAuth(Configuration); + services.AddScoped(); services.AddControllers() .AddNewtonsoftJson(options => //evitando referencias circulares com Json.NET... @@ -49,15 +50,10 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseDeveloperExceptionPage(); } - app.UseHttpsRedirection(); - app.UseRouting(); - - app.UseAuthorization(); - app.UseAuthentication(); - + app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); diff --git a/cidades/appsettings.Development.json b/cidades/appsettings.Development.json index 4f30a00..34b9d20 100644 --- a/cidades/appsettings.Development.json +++ b/cidades/appsettings.Development.json @@ -2,7 +2,7 @@ "Logging": { "LogLevel": { "Default": "Debug", - "Microsoft": "Warning", + "Microsoft": "Debug", "Microsoft.Hosting.Lifetime": "Information" } } diff --git a/cidades/appsettings.json b/cidades/appsettings.json index d3cb2bd..e181bc3 100644 --- a/cidades/appsettings.json +++ b/cidades/appsettings.json @@ -9,5 +9,8 @@ "AllowedHosts": "*", "ConnectionStrings":{ "SQLite":"Data Source=Cidades.db" + }, + "JWT":{ + "SigningKey":"CHAVE_SUPOSTAMENTE_SECRETA" } } From 4a0bc942e7ee570944420fd118ac43ba429721f6 Mon Sep 17 00:00:00 2001 From: eduardomps Date: Sun, 15 Mar 2020 20:05:42 -0300 Subject: [PATCH 8/8] Documentando --- README.md | 345 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 275 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index cbf3d87..19b50bd 100644 --- a/README.md +++ b/README.md @@ -1,80 +1,285 @@ -**Bem Vindo!** -# -Este documento README tem como objetivo fornecer as informações necessárias para realização do exame. +#**Teste - Eduardo MPS** +##Algoritmos: + +**'Duplicados na lista'** + +- Gerada console application "duplicados" em .Net core 3.1 +- como executar compilado: +``` +dotnet duplicados.dll +``` +Exemplo: +``` +$ dotnet duplicados.dll 002,12,4,97866,1234,9,35,3456,12,3 + Duplicado encontrado! + número: 12, índices: 1,8 +``` +--- + +**'Palíndromo'** -` Objetivo: ` - -- Solução de alguns algoritmos propostos e a construção de uma API. -- Você deve realizar um fork deste repositório e ao finalizar submeter um pull request com a solução ou nos enviar um link do seu repositório. -- Nós avaliaremos o que foi feito e entraremos em contato para dar um parecer. - - -`O que será avaliado?` - - - A principal ideia do teste é medir sua capacidade lógica e conhecimento na linguagem e seus frameworks - - Qualidade do seu código - - Sua capacidade de deixar o projeto organizado - - Capacidade de tomar decisões - -`Informações Importantes: ` - -- Independente de onde chegou no teste, nos envie para analisarmos, ninguém precisa ser perfeito! -- Não se esqueça de enviar um script para carga inicial dos dados no banco ou planejar a carga inicial programaticamente. -- Vamos executar sua API e verificar as requests com o postman =) - -`Seu arquivo Readme.md deve conter: ` - -- Informação de como executar o seu código, descrevendo as rotas que criou e seus contratos. -- Instruções para executar os testes ( preferencialmente queremos fazer isto via linha de comando ) -- Os algoritmos estarão na pasta Algoritmos, você é livre para entregá-los na estrutura que desejar. ( incluso no projeto, somente um arquivo de texto, uma classe, um console application, fique a vontade ) - -# -**Algoritmos:** -# -`Duplicados na lista` +- Gerada console application "palindromos" em .Net core 3.1 +- como executar compilado: +``` +dotnet palindromos.dll "" +``` +Exemplo: +``` +$ dotnet palindromos.dll "A Rita, sobre vovô, verbos atira" +CONSIDERANDO espaços e diacríticos: +'A Rita, sobre vovô, verbos atira' não é palíndromo. +IGNORANDO espaços e diacríticos: +'A Rita, sobre vovô, verbos atira' é palíndromo! +``` +## API Cidades: + +- Gerada WebAPI em .Net core 3.1 +- Criado, para facilitar, com base SQLite, já incluída no repositório +- Com autenticação + - método que recebe JSON com username/password e retorna JWT + - JWT usado como Bearer Token nos demais métodos, exceto método de listar todas + +Considerando ***{URLBase}*** = https://localhost:5001/api + +### Métodos + +#### Login +**POST** *{URLBase}*/user/authenticate + +``` +curl --request POST \ + --url https://localhost:5001/api/user/authenticate \ + --header 'content-type: application/json' \ + --data '{ + "Username":"eduardo", + "Password":"teste" +}' +``` +**Retorno**: +``` +{ + "id": 1, + "username": "eduardo", + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IjEiLCJuYmYiOjE1ODQzMDg1NzgsImV4cCI6MTU4NDMxNTc3OCwiaWF0IjoxNTg0MzA4NTc4fQ.aa_PP57NRXXV5fPE-DL8UOOw1z-WY7GHElWeFnAZo9E" +} ``` -Este algoritmo deve receber como parâmetro um vetor contendo uma sequência de números inteiros -e retornar o índice do primeiro item duplicado. + +***Obs.:*** dois usuários hardcoded, o do exemplo e "eduardo"/"teste" + +#### Listar cidades +**GET** *{URLBase}*/city/ ``` -# -`Palindromo` - +curl --request GET \ + --url https://localhost:5001/api/city/ +``` +**Retorno**: ``` -Definição: Um palindromo é um string que pode ser lida da mesma forma de trás para frente. Por exemplo, "abcba" ou "arara" é um palindromo. +[ + { + "id": 1, + "name": "Florianopolis", + "population": 500000, + "countryState": "SC", + "cityRoutes": [], + "cityRoutesFrom": [], + "neighbors": [] + }, -o que é Palindromo? -> https://pt.wikipedia.org/wiki/Pal%C3%ADndromo - -Faça um método que deve receber uma string como parâmetro e retornar um bool informando se é palíndromo ou não. + ... + + { + "id": 13, + "name": "Canelinha", + "population": 12000, + "countryState": "SC", + "cityRoutes": [], + "cityRoutesFrom": [], + "neighbors": [] + } +] ``` - -# -**Agora você deve contruir uma API que contenha: (pode usar net core ou clássico ) ** -``` -- Uma funcionalidade para fazer login. -- Uma funcionalidade para cadastrar novas cidades: - - As cidades devem contar no mínimo com: - - Um nome e uma estrutura que diga com quem ela faz fronteira - - Ex: - - {"Nome": "A", "Fronteira": ["B", "E"]} - - {"Nome": "São José", "Fronteira": ["Florianópolis", "Palhoça"]} -- Um meio para retornar todas as cidades já cadastradas ( essa não precisa estar autenticado ) -- Um meio para procurar uma cidade especifica -- Um meio que retorne as cidades que fazem fronteira com uma cidade específica - - Ex: Quem faz fronteira com a Cidade B? -- Retornar a soma dos habitantes de um conjunto de cidades - - Ex: cidade A,B,C possuem 50 mil habitantes -- Um método pra eu poder atualizar os dados de uma cidade, por exemplo mudar a quantidade de habitantes. -- O caminho que devo fazer de uma cidade a outra - - Ex: sair de cidade Buenos aires e ir até a cidade Florianópolis +***Obs.:*** +1) único método permitido sem autenticação +2) este método não retorna as cidades vizinhas, intencionalmente + +#### Buscar Cidade +**GET** *{URLBase}*/city/{id} + ``` - - - -`Lembre-se Avaliaremos o que for entregue, mesmo que incompleto` - -**Boa sorte !!** - -![alt](https://ajsoifer.files.wordpress.com/2014/04/keep-calm-and-don-t-feed-the-troll-48.png) +curl --request GET \ + --url https://localhost:5001/api/city/1 \ + --header 'authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IjEiLCJuYmYiOjE1ODQzMDc5MDcsImV4cCI6MTU4NDMxNTEwNywiaWF0IjoxNTg0MzA3OTA3fQ.Hml_DakcrvnpS3XVz-pdnIcvo0BUaQSekEg6iHrtCjY' +``` +**Retorno**: +Caso não encontre pelo id, retorna 404; +Caso contrário: +``` +{ + "id": 1, + "name": "Florianopolis", + "population": 500000, + "countryState": "SC", + "cityRoutes": [ + { + "idCity": 1, + "idCityTo": 2, + "cityTo": { + "id": 2, + "name": "Sao Jose", + "population": 243000, + "countryState": null, + "cityRoutes": [], + "cityRoutesFrom": [], + "neighbors": [] + } + } + ], + "cityRoutesFrom": [], + "neighbors": [ + { + "id": 2, + "name": "Sao Jose", + "population": 243000, + "countryState": null, + "cityRoutes": [], + "cityRoutesFrom": [ + { + "idCity": 1, + "idCityTo": 2 + } + ], + "neighbors": [] + } + ] +} +``` + +#### Criar Cidade +**POST** *{URLBase}*/city/create + +``` +curl --request POST \ + --url https://localhost:5001/api/city/create \ + --header 'authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IjEiLCJuYmYiOjE1ODQzMDc5MDcsImV4cCI6MTU4NDMxNTEwNywiaWF0IjoxNTg0MzA3OTA3fQ.Hml_DakcrvnpS3XVz-pdnIcvo0BUaQSekEg6iHrtCjY' \ + --header 'content-type: application/json' \ + --data '{ + "name": "Canelinha", + "population": 12000, + "countryState": "SC" + }' +``` +**Retorno:** +Em caso de sucesso,status 201, Created At redirecionando para o método anterior: +``` +{ + "id": 1, + "name": "Florianopolis", + "population": 500000, + "countryState": "SC", + "cityRoutes": [ + { + "idCity": 1, + "idCityTo": 2, + "cityTo": { + "id": 2, + "name": "Sao Jose", + "population": 243000, + "countryState": null, + "cityRoutes": [], + "cityRoutesFrom": [], + "neighbors": [] + } + } + ], + "cityRoutesFrom": [], + "neighbors": [ + { + "id": 2, + "name": "Sao Jose", + "population": 243000, + "countryState": null, + "cityRoutes": [], + "cityRoutesFrom": [ + { + "idCity": 1, + "idCityTo": 2 + } + ], + "neighbors": [] + } + ] +} +``` + +#### Cidades limítrofes +**GET** *{URLBase}*/city/{id}/limits +``` +curl --request GET \ + --url https://localhost:5001/api/city/5/limits \ + --header 'authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IjEiLCJuYmYiOjE1ODQzMDc5MDcsImV4cCI6MTU4NDMxNTEwNywiaWF0IjoxNTg0MzA3OTA3fQ.Hml_DakcrvnpS3XVz-pdnIcvo0BUaQSekEg6iHrtCjY' +``` +**Retorno:** +Caso não encontre pelo id, retorna 404; +Caso contrário: +``` +{ + "city": "Palhoca", + "neighbors": "Santo Amaro da Imperatriz,Sao Pedro de Alcantara,Sao Jose" +} +``` + +#### Soma de Habitantes +**GET** *{URLBase}*/city/population/{idsCSV} +``` +curl --request GET \ + --url 'https://localhost:5001/api/city/population/1,2,4' \ + --header 'authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IjEiLCJuYmYiOjE1ODQzMDc5MDcsImV4cCI6MTU4NDMxNTEwNywiaWF0IjoxNTg0MzA3OTA3fQ.Hml_DakcrvnpS3XVz-pdnIcvo0BUaQSekEg6iHrtCjY' +``` + +**Retorno:** + +``` +{ + "cities": "Florianopolis,Sao Jose,Biguacu", + "totalPopulation": 812000 +} +``` + +#### Atualizar Cidade +**POST** *{URLBase}*/city/{id}/update + +``` +curl --request POST \ + --url https://localhost:5001/api/city/13/update \ + --header 'authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IjEiLCJuYmYiOjE1ODQzMDc5MDcsImV4cCI6MTU4NDMxNTEwNywiaWF0IjoxNTg0MzA3OTA3fQ.Hml_DakcrvnpS3XVz-pdnIcvo0BUaQSekEg6iHrtCjY' \ + --header 'content-type: application/json' \ + --data '{ + "name": "Canelinha", + "population": 12000, + "countryState": "SC" +}' +``` +**Retorno:** +Caso não encontre pelo id, status 404 +Caso contrário, status 204 (NoContent) + +#### Caminho Entre Cidades +**GET** *{URLBase}*/city/findpath/{idCityFrom}/{idCityTo} +``` +curl --request GET \ + --url https://localhost:5001/api/city/findpath/10/6 \ + --header 'authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IjEiLCJuYmYiOjE1ODQzMDc5MDcsImV4cCI6MTU4NDMxNTEwNywiaWF0IjoxNTg0MzA3OTA3fQ.Hml_DakcrvnpS3XVz-pdnIcvo0BUaQSekEg6iHrtCjY' +``` +**Retorno:** +Caso não encontre início ou destino pelo id, status 404 +Caso contrário +``` +{ + "start": "Sao Joao Batista", + "end": "Santo Amaro da Imperatriz", + "path": "Sao Joao Batista,Antonio Carlos,Sao Pedro de Alcantara,Santo Amaro da Imperatriz" +} +``` \ No newline at end of file