diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3e16852
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+bin/
+obj/
+.vs/
\ No newline at end of file
diff --git a/README.md b/README.md
index b7dbd46..5fb998d 100644
--- a/README.md
+++ b/README.md
@@ -1,30 +1,37 @@
-Oportunidade de trabalho na Minuto Seguros
+Técnicas/Linguagem utilizada:
===========================================
+> AspNetCore 2.1, C#
+> SOLID
+> Repository Pattern
+> IoC
-Venha trabalhar na área de tecnologia da Minuto Corretora de Seguros. Utilizamos métodos ágeis para criação de software e nosso clima é de extrema colaboração.
-
-Se você tem interesse em fazer parte de uma equipe multidisciplinar e que adora criar software com qualidade, siga os seguintes passos:
-
-Faça um fork desse projeto e faça um pull request com a resolução do seguinte problema:
+Documentação:
+===========================================
+> Swagger
-Exercício de programação: As principais palavras
--------------------------------------------------------
+Executando a aplicação
+===========================================
+A aplicação trata-se de um web api RESTFULL
-Você deverá criar um programa para obter automaticamente o conteúdo dos dez últimos tópicos publicados no blog da Minuto Seguros. Abaixo segue um link para auxiliá-lo nesse trabalho:
+URL APIs: http://localhost:5000/swagger
-http://www.minutoseguros.com.br/blog/feed/
-Caso tenha problemas em obter o feed, deixamos um arquivo feed.xml aqui no repositório.
+Chamada via CURL
+===========================================
+curl http://localhost:5000/api/v1/feeds/topics
-O seu programa deverá avaliar quais as dez principais palavras abordadas nesses tópicos e qual o número de vezes que elas aparecem. Também deverá exibir a quantidade de palavras por tópico. Além disso, deverão ser removidos os artigos e preposições nessa análise.
-A linguagem que mais utilizamos é C#. Porém, você poderá realizar o exercício na linguagem de programação de sua preferência.
+EXTRA: Banco de dados Mongo
+===========================================
+Ao consumir o serviço Baixar Feeds, um "espelho" do registros é criado em uma base de dados mongo. O objetivo é mostrar de forma simples como a aplicação escalaria de foma simples, caso fosse necessário manter uma base de dados local para outras análises.
-Como trabalhamos aqui
-----------
+Credenciais do banco de dados:
+mongodb://msdbuser:ms#2018@ds135592.mlab.com:35592/minutosegurodb
-Trabalhamos com uma boa infraestrutura, nosso hardware é muito bom e possuímos um ambiente de trabalho muito agradável. A empresa não possui hierarquias desnecessárias e você é convidado e desafiado a colaborar com todas as frentes de trabalho. Ou seja, aqui o “pitaco” é bem vindo!
-Nós acreditamos muito nos números para tomada de decisões. Nós possuímos diversas métricas e isso inclui também medir o nosso código. Acompanhamos esses indicadores para construir códigos sólidos e de fácil manutenção. Afinal, queremos a cada dia mais flexibilidade e continuar animados a evoluir nossas aplicações.
+Fontes para algumas informações:
+===========================================
+https://www.normaculta.com.br/artigo-indefinido/
+https://www.normaculta.com.br/artigo-definido/
+https://www.normaculta.com.br/preposicao/
-Nosso trabalho é baseado em autogestão. Só existe uma regra de convivência na frente de TI: É proibido murmurar! Aqui as opiniões são discutidas, resolvidas e sempre chegamos a um consenso para melhorar a nossa convivência. Isso não foi descrito por um gerente de RH e sim por um desenvolvedor de software!
diff --git a/src/.vs/Minuto.Seguros/v15/.suo b/src/.vs/Minuto.Seguros/v15/.suo
new file mode 100644
index 0000000..183eb4a
Binary files /dev/null and b/src/.vs/Minuto.Seguros/v15/.suo differ
diff --git a/src/.vs/Minuto.Seguros/v15/Server/sqlite3/storage.ide b/src/.vs/Minuto.Seguros/v15/Server/sqlite3/storage.ide
new file mode 100644
index 0000000..ba4fd15
Binary files /dev/null and b/src/.vs/Minuto.Seguros/v15/Server/sqlite3/storage.ide differ
diff --git a/src/.vs/Minuto.Seguros/v15/Server/sqlite3/storage.ide-shm b/src/.vs/Minuto.Seguros/v15/Server/sqlite3/storage.ide-shm
new file mode 100644
index 0000000..52b7087
Binary files /dev/null and b/src/.vs/Minuto.Seguros/v15/Server/sqlite3/storage.ide-shm differ
diff --git a/src/.vs/Minuto.Seguros/v15/Server/sqlite3/storage.ide-wal b/src/.vs/Minuto.Seguros/v15/Server/sqlite3/storage.ide-wal
new file mode 100644
index 0000000..11a7025
Binary files /dev/null and b/src/.vs/Minuto.Seguros/v15/Server/sqlite3/storage.ide-wal differ
diff --git a/src/.vs/MinutoSeguroBlogFeed/DesignTimeBuild/.dtbcache b/src/.vs/MinutoSeguroBlogFeed/DesignTimeBuild/.dtbcache
new file mode 100644
index 0000000..ebd38cd
Binary files /dev/null and b/src/.vs/MinutoSeguroBlogFeed/DesignTimeBuild/.dtbcache differ
diff --git a/src/.vs/config/applicationhost.config b/src/.vs/config/applicationhost.config
new file mode 100644
index 0000000..0e578e6
--- /dev/null
+++ b/src/.vs/config/applicationhost.config
@@ -0,0 +1,1003 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Minuto.Seguros.Application/Controllers/FeedsController.cs b/src/Minuto.Seguros.Application/Controllers/FeedsController.cs
new file mode 100644
index 0000000..0cd604a
--- /dev/null
+++ b/src/Minuto.Seguros.Application/Controllers/FeedsController.cs
@@ -0,0 +1,81 @@
+using System;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Minuto.Seguros.Service.Contracts;
+
+namespace Minuto.Seguros.Application.Controllers.V1
+{
+ ///
+ /// Gestão de feeds
+ ///
+ [Authorize]
+ [ApiVersion("1")]
+ [Route("api/v1/feeds")]
+ [Produces("application/json")]
+ public class FeedsController : ControllerBase
+ {
+ private readonly IFeedService _feedService;
+
+ ///
+ /// Construtor
+ ///
+ ///
+ public FeedsController(
+ IFeedService feedService
+ )
+ {
+ _feedService = feedService;
+ }
+
+ ///
+ /// Baixar Feeds
+ ///
+ [AllowAnonymous]
+ [HttpGet]
+ [ProducesResponseType(201)]
+ [ProducesResponseType(400)]
+ public IActionResult BaixarFeeds()
+ {
+ try
+ {
+ return new ObjectResult(_feedService.GetAllFeeds());
+ }
+ catch (ArgumentNullException ex)
+ {
+ return NotFound(ex);
+ }
+ catch (Exception ex)
+ {
+ return BadRequest(ex);
+ }
+ }
+
+ ///
+ /// Contabilizar TOP 10 palavras por Tópico
+ ///
+ /// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
+ /// Mensagem de confirmação de sucesso ou erro.
+ /// String com o token gerado
+ [AllowAnonymous]
+ [HttpGet]
+ [Route("topics")]
+ [ProducesResponseType(201)]
+ [ProducesResponseType(400)]
+ public IActionResult SincronizarFeeds()
+ {
+ try
+ {
+ var result = _feedService.GetFeeds();
+ return new ObjectResult(result);
+ }
+ catch (ArgumentNullException ex)
+ {
+ return NotFound(ex);
+ }
+ catch (Exception ex)
+ {
+ return BadRequest(ex);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Minuto.Seguros.Application/Extensions/swagger/ActionDescriptorExtensions.cs b/src/Minuto.Seguros.Application/Extensions/swagger/ActionDescriptorExtensions.cs
new file mode 100644
index 0000000..7f45267
--- /dev/null
+++ b/src/Minuto.Seguros.Application/Extensions/swagger/ActionDescriptorExtensions.cs
@@ -0,0 +1,27 @@
+using Microsoft.AspNetCore.Mvc.Abstractions;
+using Microsoft.AspNetCore.Mvc.Versioning;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Minuto.Seguros.Application.Extensions.swagger
+{
+ ///
+ /// Extensão para recuperar nome da api Swagger
+ ///
+ public static class ActionDescriptorExtensions
+ {
+ ///
+ /// Retora versão da api
+ ///
+ ///
+ ///
+ public static ApiVersionModel GetApiVersion(this ActionDescriptor actionDescriptor)
+ {
+ return actionDescriptor?.Properties
+ .Where((kvp) => ((Type)kvp.Key).Equals(typeof(ApiVersionModel)))
+ .Select(kvp => kvp.Value as ApiVersionModel).FirstOrDefault();
+ }
+ }
+}
diff --git a/src/Minuto.Seguros.Application/Filters/swagger/ApiVersionOperationFilter.cs b/src/Minuto.Seguros.Application/Filters/swagger/ApiVersionOperationFilter.cs
new file mode 100644
index 0000000..bb9b13d
--- /dev/null
+++ b/src/Minuto.Seguros.Application/Filters/swagger/ApiVersionOperationFilter.cs
@@ -0,0 +1,43 @@
+using Minuto.Seguros.Application.Extensions.swagger;
+using Swashbuckle.AspNetCore.Swagger;
+using Swashbuckle.AspNetCore.SwaggerGen;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Minuto.Seguros.Application.Filters.swagger
+{
+ ///
+ /// Filtro de api swagger
+ ///
+ public class ApiVersionOperationFilter : IOperationFilter
+ {
+ ///
+ /// Executa filtro de acordo com a versão
+ ///
+ ///
+ ///
+ public void Apply(Operation operation, OperationFilterContext context)
+ {
+ var actionApiVersionModel = context.ApiDescription.ActionDescriptor?.GetApiVersion();
+ if (actionApiVersionModel == null)
+ {
+ return;
+ }
+
+ if (actionApiVersionModel.DeclaredApiVersions.Any())
+ {
+ operation.Produces = operation.Produces
+ .SelectMany(p => actionApiVersionModel.DeclaredApiVersions
+ .Select(version => $"{p};v={version.ToString()}")).ToList();
+ }
+ else
+ {
+ operation.Produces = operation.Produces
+ .SelectMany(p => actionApiVersionModel.ImplementedApiVersions.OrderByDescending(v => v)
+ .Select(version => $"{p};v={version.ToString()}")).ToList();
+ }
+ }
+ }
+}
diff --git a/src/Minuto.Seguros.Application/Filters/swagger/VersionFilter.cs b/src/Minuto.Seguros.Application/Filters/swagger/VersionFilter.cs
new file mode 100644
index 0000000..27bd9e9
--- /dev/null
+++ b/src/Minuto.Seguros.Application/Filters/swagger/VersionFilter.cs
@@ -0,0 +1,30 @@
+using Swashbuckle.AspNetCore.Swagger;
+using Swashbuckle.AspNetCore.SwaggerGen;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Minuto.Seguros.Application.Filters.swagger
+{
+ ///
+ /// Filtro de versão swagger
+ ///
+ ///
+ public class VersionFilter: IDocumentFilter
+ {
+ ///
+ /// Aplica o filtro de acordo com a versão
+ ///
+ ///
+ ///
+ public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
+ {
+ swaggerDoc.Paths = swaggerDoc.Paths
+ .ToDictionary(
+ path => path.Key.Replace("v{version}", swaggerDoc.Info.Version),
+ path => path.Value
+ );
+ }
+ }
+}
diff --git a/src/Minuto.Seguros.Application/Minuto.Seguros.Application.csproj b/src/Minuto.Seguros.Application/Minuto.Seguros.Application.csproj
new file mode 100644
index 0000000..5247488
--- /dev/null
+++ b/src/Minuto.Seguros.Application/Minuto.Seguros.Application.csproj
@@ -0,0 +1,51 @@
+
+
+
+ netcoreapp2.1
+
+
+
+ bin\Debug\netcoreapp2.1\Minuto.Seguro.Application.xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Never
+
+
+
+
diff --git a/src/Minuto.Seguros.Application/Minuto.Seguros.Application.csproj.user b/src/Minuto.Seguros.Application/Minuto.Seguros.Application.csproj.user
new file mode 100644
index 0000000..6c9d9b4
--- /dev/null
+++ b/src/Minuto.Seguros.Application/Minuto.Seguros.Application.csproj.user
@@ -0,0 +1,17 @@
+
+
+
+ ApiControllerWithActionsScaffolder
+ root/Controller
+ 600
+ True
+ False
+ True
+
+ False
+ Minuto.Seguro.Application
+
+
+ ProjectDebugger
+
+
\ No newline at end of file
diff --git a/src/Minuto.Seguros.Application/Minuto.Seguros.Application.xml b/src/Minuto.Seguros.Application/Minuto.Seguros.Application.xml
new file mode 100644
index 0000000..2ba94f1
--- /dev/null
+++ b/src/Minuto.Seguros.Application/Minuto.Seguros.Application.xml
@@ -0,0 +1,20 @@
+
+
+
+ Saraiva.Connecta.Application
+
+
+
+
+ Gestão de feeds
+
+
+
+
+ Baixa todos os feeds disponibilizados pela Minuto Seguros
+
+ Feeds disponibilizados pela Minuto Seguros.
+ Feeds disponibilizados pela Minuto Seguros
+
+
+
diff --git a/src/Minuto.Seguros.Application/Program.cs b/src/Minuto.Seguros.Application/Program.cs
new file mode 100644
index 0000000..8973b9e
--- /dev/null
+++ b/src/Minuto.Seguros.Application/Program.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+
+namespace Minuto.Seguros.Application
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ CreateWebHostBuilder(args).Build().Run();
+ }
+
+ public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
+ WebHost.CreateDefaultBuilder(args)
+ .UseStartup();
+ }
+}
diff --git a/src/Minuto.Seguros.Application/Properties/launchSettings.json b/src/Minuto.Seguros.Application/Properties/launchSettings.json
new file mode 100644
index 0000000..416202e
--- /dev/null
+++ b/src/Minuto.Seguros.Application/Properties/launchSettings.json
@@ -0,0 +1,31 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "launchUrl": "swagger",
+ "iisExpress": {
+ "applicationUrl": "http://localhost:5000",
+ "sslPort": 0
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "Minuto.Seguro.Application": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "applicationUrl": "http://localhost:5000",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Minuto.Seguros.Application/Resources/Swagger_Minuto_Seguros_index.html b/src/Minuto.Seguros.Application/Resources/Swagger_Minuto_Seguros_index.html
new file mode 100644
index 0000000..955b7e0
--- /dev/null
+++ b/src/Minuto.Seguros.Application/Resources/Swagger_Minuto_Seguros_index.html
@@ -0,0 +1,122 @@
+
+
+
+
+
+ Minuto Seguro API
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Minuto.Seguros.Application/Startup.cs b/src/Minuto.Seguros.Application/Startup.cs
new file mode 100644
index 0000000..9b4ddc8
--- /dev/null
+++ b/src/Minuto.Seguros.Application/Startup.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using AutoMapper;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http.Internal;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Minuto.Seguros.Application.Extensions;
+using Minuto.Seguros.Domain.Entities;
+
+namespace Minuto.Seguros.Application
+{
+ ///
+ ///
+ ///
+ public class Startup
+ {
+ ///
+ ///
+ ///
+ public IConfigurationRoot Configuration { get; }
+
+ ///
+ ///
+ ///
+ public IServiceProvider serviceProvider;
+
+ ///
+ ///
+ ///
+ ///
+ public Startup(IHostingEnvironment env)
+ {
+ IConfigurationBuilder builder = new ConfigurationBuilder()
+ .SetBasePath(env.ContentRootPath)
+ .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
+ .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
+
+ builder.AddEnvironmentVariables();
+ Configuration = builder.Build();
+
+ }
+
+ ///
+ /// Configuração dos serviços utilizados pela Application
+ ///
+ /// Coleção de serviços
+ ///
+ public IServiceProvider ConfigureServices(IServiceCollection services)
+ {
+ services.AddCorsService();
+
+ var mappingConfig = new MapperConfiguration(mc =>
+ {
+ mc.CreateMap();
+ mc.CreateMap();
+ mc.CreateMap();
+ mc.CreateMap();
+ });
+
+ IMapper mapper = mappingConfig.CreateMapper();
+ services.AddSingleton(mapper);
+
+ services.AddMvcService();
+ services.AddApiVersioningService();
+ services.AddJwtService(Configuration);
+ services.AddSwaggerService();
+ services.AddHttpContextAccessor();
+ services.AddSettingsService(Configuration);
+
+ serviceProvider = services.RegisterServices(Configuration);
+
+ return serviceProvider;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
+ {
+ app.Use(next => context => { context.Request.EnableRewind(); return next(context); });
+
+ app.UseSwagger();
+
+ app.UseSwaggerUI(c =>
+ {
+ c.IndexStream = () => GetType().GetTypeInfo().Assembly.GetManifestResourceStream("Minuto.Seguros.Application.Resources.Swagger_Minuto_Seguros_index.html");
+ c.SwaggerEndpoint("/swagger/v1/swagger.json", "Minuto Seguro API v1.0");
+ });
+
+ app.UseCors(x => x
+ .AllowAnyOrigin()
+ .AllowAnyMethod()
+ .AllowAnyHeader()
+ .AllowCredentials());
+
+ app.UseAuthentication();
+
+ app.UseStaticFiles();
+ app.UseMvc();
+ }
+ }
+}
diff --git a/src/Minuto.Seguros.Application/Startup/StartupService.cs b/src/Minuto.Seguros.Application/Startup/StartupService.cs
new file mode 100644
index 0000000..070e7dc
--- /dev/null
+++ b/src/Minuto.Seguros.Application/Startup/StartupService.cs
@@ -0,0 +1,185 @@
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc.Authorization;
+using Microsoft.AspNetCore.Mvc.Versioning;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.IdentityModel.Tokens;
+using Minuto.Seguros.Infra.CrossCutting.Configuration;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Swashbuckle.AspNetCore.Swagger;
+using System.Threading.Tasks;
+using Minuto.Seguros.Application.Filters.swagger;
+using Autofac.Extensions.DependencyInjection;
+using Minuto.Seguros.Infra.Data.Connection;
+using Minuto.Seguros.Service;
+using Autofac;
+using Minuto.Seguros.Infra.Data;
+using Minuto.Seguros.Application.Extensions.swagger;
+using AutoMapper;
+using System.IO;
+
+namespace Minuto.Seguros.Application
+{
+ ///
+ /// Classe para unificar configura~ções da startup.cs
+ ///
+ public static class StartupService
+ {
+ ///
+ /// Adicona configuração CORS no projeto
+ ///
+ ///
+ public static void AddCorsService(this IServiceCollection services)
+ {
+ services.AddCors(options => {
+ options.AddPolicy("AllowAllOrigins",
+ builder => builder.AllowAnyOrigin());
+ });
+ }
+
+ ///
+ /// Adiciona configuração do MVC no projeto
+ ///
+ ///
+ public static void AddMvcService(this IServiceCollection services)
+ {
+ services.AddMvc(config => {
+ AuthorizationPolicy policy = new AuthorizationPolicyBuilder()
+ .RequireAuthenticatedUser()
+ .Build();
+ config.Filters.Add(new AuthorizeFilter(policy));
+ })
+ .AddJsonOptions(options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
+ }
+
+ ///
+ /// Adiciona configuração de versionamento de api ao projeto
+ ///
+ ///
+ public static void AddApiVersioningService(this IServiceCollection services)
+ {
+ services.AddApiVersioning(o => {
+ o.DefaultApiVersion = new Microsoft.AspNetCore.Mvc.ApiVersion(1, 0); // Versão padrão
+ o.AssumeDefaultVersionWhenUnspecified = true; // Assume a versão padrão quando não informado
+ o.ApiVersionReader = new MediaTypeApiVersionReader(); // Ler a versão via accept header
+ });
+ }
+
+ ///
+ /// Adiciona configuração JWT no projeto
+ ///
+ ///
+ ///
+ public static void AddJwtService(this IServiceCollection services, IConfigurationRoot configuration)
+ {
+ JwtConfig jwtConfig = configuration.GetSection("JwtConfig").Get();
+ byte[] key = Encoding.ASCII.GetBytes(jwtConfig.Secret);
+ services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+ .AddJwtBearer(options => {
+ options.TokenValidationParameters = new TokenValidationParameters
+ {
+ ValidateIssuer = true,
+ ValidateAudience = true,
+ ValidateLifetime = true,
+ ValidateIssuerSigningKey = true,
+ ValidIssuer = jwtConfig.Issuer,
+ ValidAudience = jwtConfig.Issuer,
+ IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.Secret))
+ };
+ });
+ }
+
+ ///
+ /// Adiciona Swagger na aplicação
+ ///
+ ///
+ public static void AddSwaggerService(this IServiceCollection services)
+ {
+ services.AddSwaggerGen(c => {
+ c.SwaggerDoc("v1",
+ new Info {
+ Version = "v1"
+ , Title = "Minuto Seguro API"
+ });
+
+ c.AddSecurityDefinition("Bearer", new ApiKeyScheme
+ {
+ Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
+ Name = "Authorization",
+ In = "header",
+ Type = "apiKey"
+ });
+
+ c.AddSecurityRequirement(new Dictionary> {
+ { "Bearer", Enumerable.Empty() },
+ });
+
+ c.DocInclusionPredicate((docName, apiDesc) => {
+ ApiVersionModel actionApiVersionModel = apiDesc.ActionDescriptor?.GetApiVersion();
+
+ if (actionApiVersionModel == null)
+ {
+ return true;
+ }
+ if (actionApiVersionModel.DeclaredApiVersions.Any())
+ {
+ return actionApiVersionModel.DeclaredApiVersions.Any(v => $"v{v.ToString()}" == docName);
+ }
+ return actionApiVersionModel.ImplementedApiVersions.Any(v => $"v{v.ToString()}" == docName);
+ });
+ c.DocumentFilter();
+ c.OperationFilter();
+ c.IncludeXmlComments(GetXmlCommentsPath());
+
+ });
+ }
+
+ public static string GetXmlCommentsPath()
+ {
+ return System.String.Format(@"{0}\Minuto.Seguro.Application.xml", System.AppDomain.CurrentDomain.BaseDirectory);
+ }
+
+ ///
+ /// Adiciona suporte a configuração na aplicação
+ ///
+ ///
+ ///
+ public static void AddSettingsService(this IServiceCollection services, IConfigurationRoot Configuration)
+ {
+ services.Configure(Configuration.GetSection("AppSettings"));
+ services.Configure(Configuration.GetSection("ConfigEmail"));
+ services.Configure(Configuration.GetSection("JwtConfig"));
+ ConnectionStrings connectionStrings = Configuration.GetSection("ConnectionStrings").Get();
+ }
+
+ private static ConnectionStrings AddConnectionStringsService(this IServiceCollection services, IConfigurationRoot Configuration)
+ {
+ return Configuration.GetSection("ConnectionStrings").Get();
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public static AutofacServiceProvider RegisterServices(this IServiceCollection services, IConfigurationRoot Configuration)
+ {
+ services.AddScoped();
+ services.AddSingleton(Configuration);
+ services.AddScoped();
+
+ ContainerBuilder containerBuilder = new ContainerBuilder();
+ containerBuilder.RegisterModule(new DataModule(AddConnectionStringsService(services, Configuration).MinutoSeguroConn, "minutosegurodb"));
+ containerBuilder.RegisterModule();
+
+ containerBuilder.RegisterType().As();
+
+ containerBuilder.Populate(services);
+
+ return new AutofacServiceProvider(containerBuilder.Build());
+ }
+ }
+}
diff --git a/src/Minuto.Seguros.Application/appsettings.Development.json b/src/Minuto.Seguros.Application/appsettings.Development.json
new file mode 100644
index 0000000..e203e94
--- /dev/null
+++ b/src/Minuto.Seguros.Application/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Debug",
+ "System": "Information",
+ "Microsoft": "Information"
+ }
+ }
+}
diff --git a/src/Minuto.Seguros.Application/appsettings.json b/src/Minuto.Seguros.Application/appsettings.json
new file mode 100644
index 0000000..6d95ff9
--- /dev/null
+++ b/src/Minuto.Seguros.Application/appsettings.json
@@ -0,0 +1,13 @@
+{
+ "AppSettings": {
+ "UriXmlMinutoSeguros": "https://www.minutoseguros.com.br/blog/feed/"
+ },
+ "ConnectionStrings": {
+ "MinutoSeguroConn": "mongodb://msdbuser:ms#2018@ds135592.mlab.com:35592/minutosegurodb"
+ },
+ "JwtConfig": {
+ "Secret": "1bb320b3904ad153ca8988ea7c283c07",
+ "Issuer": "http://127.0.0.1:5000/",
+ "LifeTimeMinutes": 60
+ }
+}
\ No newline at end of file
diff --git a/src/Minuto.Seguros.Domain/Entities/BaseEntity.cs b/src/Minuto.Seguros.Domain/Entities/BaseEntity.cs
new file mode 100644
index 0000000..503d6e9
--- /dev/null
+++ b/src/Minuto.Seguros.Domain/Entities/BaseEntity.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Minuto.Seguros.Domain.Entities
+{
+ public class BaseEntity
+ {
+ }
+}
diff --git a/src/Minuto.Seguros.Domain/Entities/Feed.cs b/src/Minuto.Seguros.Domain/Entities/Feed.cs
new file mode 100644
index 0000000..5ae1071
--- /dev/null
+++ b/src/Minuto.Seguros.Domain/Entities/Feed.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Minuto.Seguros.Domain.Entities
+{
+ public class Feed: BaseEntity
+ {
+ public string Title { get; set; }
+ public string Description { get; set; }
+ public string[] Categories { get; set; }
+ }
+}
diff --git a/src/Minuto.Seguros.Domain/Minuto.Seguros.Domain.csproj b/src/Minuto.Seguros.Domain/Minuto.Seguros.Domain.csproj
new file mode 100644
index 0000000..86ea3bb
--- /dev/null
+++ b/src/Minuto.Seguros.Domain/Minuto.Seguros.Domain.csproj
@@ -0,0 +1,7 @@
+
+
+
+ netcoreapp2.1
+
+
+
diff --git a/src/Minuto.Seguros.Infra.Client.Corporate.Rss/Clients/RssClient.cs b/src/Minuto.Seguros.Infra.Client.Corporate.Rss/Clients/RssClient.cs
new file mode 100644
index 0000000..36799fb
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.Client.Corporate.Rss/Clients/RssClient.cs
@@ -0,0 +1,50 @@
+using Microsoft.Extensions.Options;
+using Minuto.Seguros.Infra.Client.Corporate.Rss.Contracts;
+using Minuto.Seguros.Infra.Client.Corporate.Rss.Dto;
+using Minuto.Seguros.Infra.CrossCutting.Configuration;
+using Minuto.Seguros.Infra.CrossCutting.Utils;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+
+namespace Minuto.Seguros.Infra.Client.Corporate.Rss
+{
+ public class RssClient : IRssClient
+ {
+ private readonly AppSettings _appSettings;
+
+ public RssClient(
+ IOptions appSettings
+ )
+ {
+ _appSettings = appSettings.Value;
+ }
+
+ public List GetFeeds()
+ {
+ try {
+ XDocument document = XDocument.Load(_appSettings.UriXmlMinutoSeguros);
+ rss Rss = SerializationUtil.Deserialize(document);
+
+ var feeds = new List();
+
+ foreach (var item in Rss.channel.item)
+ {
+ feeds.Add(new FeedDto()
+ {
+ Title = item.title,
+ Description = item.description,
+ Categories = item.category
+ });
+ }
+
+ return feeds;
+ }
+ catch (Exception ex)
+ {
+ throw ex;
+ }
+ }
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.Client.Corporate.Rss/Contracts/IRssClient.cs b/src/Minuto.Seguros.Infra.Client.Corporate.Rss/Contracts/IRssClient.cs
new file mode 100644
index 0000000..0090003
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.Client.Corporate.Rss/Contracts/IRssClient.cs
@@ -0,0 +1,13 @@
+using Minuto.Seguros.Infra.Client.Corporate.Rss.Dto;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Minuto.Seguros.Infra.Client.Corporate.Rss.Contracts
+{
+ public interface IRssClient
+ {
+ List GetFeeds();
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.Client.Corporate.Rss/Dto/FeedDto.cs b/src/Minuto.Seguros.Infra.Client.Corporate.Rss/Dto/FeedDto.cs
new file mode 100644
index 0000000..bf64f80
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.Client.Corporate.Rss/Dto/FeedDto.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Minuto.Seguros.Infra.Client.Corporate.Rss.Dto
+{
+ public class FeedDto
+ {
+ public string Title { get; set; }
+ public string Description { get; set; }
+ public string[] Categories { get; set; }
+ public string FullMessageClean { get; set; }
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.Client.Corporate.Rss/Minuto.Seguros.Infra.Client.Corporate.Rss.csproj b/src/Minuto.Seguros.Infra.Client.Corporate.Rss/Minuto.Seguros.Infra.Client.Corporate.Rss.csproj
new file mode 100644
index 0000000..28cbb0b
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.Client.Corporate.Rss/Minuto.Seguros.Infra.Client.Corporate.Rss.csproj
@@ -0,0 +1,11 @@
+
+
+
+ netcoreapp2.1
+
+
+
+
+
+
+
diff --git a/src/Minuto.Seguros.Infra.CrossCutting/Configuration/AppSettings.cs b/src/Minuto.Seguros.Infra.CrossCutting/Configuration/AppSettings.cs
new file mode 100644
index 0000000..2db272a
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.CrossCutting/Configuration/AppSettings.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Minuto.Seguros.Infra.CrossCutting.Configuration
+{
+ public class AppSettings
+ {
+ public string UriXmlMinutoSeguros { get; set; }
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.CrossCutting/Configuration/ConfigEmail.cs b/src/Minuto.Seguros.Infra.CrossCutting/Configuration/ConfigEmail.cs
new file mode 100644
index 0000000..7fce722
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.CrossCutting/Configuration/ConfigEmail.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Minuto.Seguros.Infra.CrossCutting.Configuration
+{
+ public class ConfigEmail
+ {
+ public string MyProperty { get; set; }
+ public string Credencial { get; set; }
+ public string Email { get; set; }
+ public string Senha { get; set; }
+ public string Smtp { get; set; }
+ public int SmtpPort { get; set; }
+ public bool Ssl { get; set; }
+ public string EmailsTech { get; set; }
+
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.CrossCutting/Configuration/ConnectionStrings.cs b/src/Minuto.Seguros.Infra.CrossCutting/Configuration/ConnectionStrings.cs
new file mode 100644
index 0000000..6d9fd40
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.CrossCutting/Configuration/ConnectionStrings.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Minuto.Seguros.Infra.CrossCutting.Configuration
+{
+ public class ConnectionStrings
+ {
+ public string MinutoSeguroConn { get; set; }
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.CrossCutting/Configuration/JwtConfig.cs b/src/Minuto.Seguros.Infra.CrossCutting/Configuration/JwtConfig.cs
new file mode 100644
index 0000000..a3dc95e
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.CrossCutting/Configuration/JwtConfig.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Minuto.Seguros.Infra.CrossCutting.Configuration
+{
+ public class JwtConfig
+ {
+ public string Secret { get; set; }
+ public string Issuer { get; set; }
+ public int LifeTimeMinutes { get; set; }
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.CrossCutting/Minuto.Seguros.Infra.CrossCutting.csproj b/src/Minuto.Seguros.Infra.CrossCutting/Minuto.Seguros.Infra.CrossCutting.csproj
new file mode 100644
index 0000000..923e8f0
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.CrossCutting/Minuto.Seguros.Infra.CrossCutting.csproj
@@ -0,0 +1,17 @@
+
+
+
+ netcoreapp2.1
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Minuto.Seguros.Infra.CrossCutting/Utils/ClearSentenceUtil.cs b/src/Minuto.Seguros.Infra.CrossCutting/Utils/ClearSentenceUtil.cs
new file mode 100644
index 0000000..7bbe7bd
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.CrossCutting/Utils/ClearSentenceUtil.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Minuto.Seguros.Infra.CrossCutting.Utils
+{
+ public static class ClearSentenceUtil
+ {
+ ///
+ /// Fontes: https://www.normaculta.com.br/artigo-indefinido/
+ /// https://www.normaculta.com.br/artigo-definido/
+ /// https://www.normaculta.com.br/preposicao/
+ ///
+ ///
+ ///
+ public static string ClearSentence(string sentence)
+ {
+ var sentenceClear = string.Concat(" ", sentence, " ");
+
+ sentenceClear = StripHTML(sentenceClear);
+
+ #region | Pontuação
+
+ sentenceClear = sentenceClear
+ .Replace(",", "")
+ .Replace(".", "")
+ .Replace("?", "")
+ .Replace("!", "")
+ .Replace(":", "")
+ .Replace("(", "")
+ .Replace(")", "")
+ .Replace(";", "")
+ .Replace(" - ", " ")
+ .Replace("\n", "")
+ .Replace("\"", "");
+
+ #endregion
+
+ #region | Artigos Definidos
+
+ sentenceClear = sentenceClear
+ .Replace(" a ", " ")
+ .Replace(" as ", " ")
+ .Replace(" A ", " ")
+ .Replace(" As ", " ")
+ .Replace(" AS ", " ")
+ .Replace(" o ", " ")
+ .Replace(" os ", " ")
+ .Replace(" O ", " ")
+ .Replace(" Os ", " ")
+ .Replace(" OS ", " ")
+ .Replace(" da ", " ")
+ .Replace(" Da ", " ")
+ .Replace(" DA ", " ")
+ .Replace(" das ", " ")
+ .Replace(" Das ", " ")
+ .Replace(" DAS ", " ")
+ .Replace(" de ", " ")
+ .Replace(" De ", " ")
+ .Replace(" DE ", " ")
+ .Replace(" no ", " ")
+ .Replace(" No ", " ")
+ .Replace(" NOS ", " ")
+ .Replace(" nos ", " ")
+ .Replace(" Nos ", " ")
+ .Replace(" NOS ", " ");
+ #endregion
+
+ #region | Artigos Indefinidos
+
+ sentenceClear = sentenceClear.Replace(" um ", " ")
+ .Replace(" Um ", " ")
+ .Replace(" UM ", " ")
+ .Replace(" uns ", " ")
+ .Replace(" Uns ", " ")
+ .Replace(" UNS ", " ")
+ .Replace(" dum ", " ")
+ .Replace(" Dum ", " ")
+ .Replace(" DUM ", " ")
+ .Replace(" duns ", " ")
+ .Replace(" Duns ", " ")
+ .Replace(" DUNS ", " ")
+ .Replace(" uma ", " ")
+ .Replace(" Uma ", " ")
+ .Replace(" UMA ", " ")
+ .Replace(" umas ", " ")
+ .Replace(" Umas ", " ")
+ .Replace(" UMAS ", " ")
+ .Replace(" em ", " ")
+ .Replace(" Em ", " ")
+ .Replace(" EM ", " ");
+
+ #endregion
+
+ #region | Preposições
+
+ sentenceClear = sentenceClear
+ .Replace(" do ", " ")
+ .Replace(" Do ", " ")
+ .Replace(" DO ", " ")
+ .Replace(" dos ", " ")
+ .Replace(" Dos ", " ")
+ .Replace(" DOS ", " ")
+ .Replace(" DOS ", " ")
+
+ .Replace(" à ", " ")
+ .Replace(" às ", " ")
+ .Replace(" À ", " ")
+ .Replace(" Às ", " ")
+ .Replace(" ÀS ", " ")
+
+ .Replace(" duma ", " ")
+ .Replace(" Duma ", " ")
+ .Replace(" DUMA ", " ")
+ .Replace(" dumas ", " ")
+ .Replace(" Dumas ", " ")
+ .Replace(" DUMAS ", " ")
+
+ .Replace(" disto ", " ")
+ .Replace(" Disto ", " ")
+ .Replace(" DISTO ", " ")
+
+ .Replace(" na ", " ")
+ .Replace(" Na ", " ")
+ .Replace(" NA ", " ")
+ .Replace(" nas ", " ")
+ .Replace(" Nas ", " ")
+ .Replace(" NAS ", " ")
+
+ .Replace(" ao ", " ")
+ .Replace(" aos ", " ")
+ .Replace(" AO ", " ")
+ .Replace(" Aos ", " ")
+ .Replace(" AOS ", " ")
+
+ .Replace(" num ", " ")
+ .Replace(" Num ", " ")
+ .Replace(" NUM ", " ")
+ .Replace(" nuns ", " ")
+ .Replace(" Nuns ", " ")
+ .Replace(" NUNS ", " ")
+
+ .Replace(" numa ", " ")
+ .Replace(" Numa ", " ")
+ .Replace(" NUMA ", " ")
+ .Replace(" numas ", " ")
+ .Replace(" Numas ", " ")
+ .Replace(" NUMAS ", " ")
+
+ .Replace(" pelo ", " ")
+ .Replace(" Pelo ", " ")
+ .Replace(" PELO ", " ")
+ .Replace(" pelos ", " ")
+ .Replace(" Pelos ", " ")
+ .Replace(" PELOS ", " ")
+
+ .Replace(" pela ", " ")
+ .Replace(" Pela ", " ")
+ .Replace(" PELA ", " ")
+ .Replace(" pelas ", " ")
+ .Replace(" Pelas ", " ")
+ .Replace(" PELAS ", " ")
+
+ .Replace(" nessa ", " ")
+ .Replace(" Nessa ", " ")
+ .Replace(" NESSA", " ")
+ .Replace(" nessas ", " ")
+ .Replace(" Nessas ", " ")
+ .Replace(" NESSAS ", " ")
+
+ .Replace(" aonde ", " ")
+ .Replace(" Aonde ", " ")
+ .Replace(" AONDE", " ");
+
+ #endregion
+
+ return sentenceClear.TrimEnd().TrimStart().ToLower();
+ }
+
+ private static string StripHTML(string input)
+ {
+ return Regex.Replace(input, "<.*?>", String.Empty);
+ }
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.CrossCutting/Utils/RssUtil.cs b/src/Minuto.Seguros.Infra.CrossCutting/Utils/RssUtil.cs
new file mode 100644
index 0000000..c0afa8d
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.CrossCutting/Utils/RssUtil.cs
@@ -0,0 +1,485 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Minuto.Seguros.Infra.CrossCutting.Utils
+{
+ // NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0.
+ ///
+ [System.SerializableAttribute()]
+ [System.ComponentModel.DesignerCategoryAttribute("code")]
+ [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
+ [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
+ public partial class rss
+ {
+
+ private rssChannel channelField;
+
+ private decimal versionField;
+
+ ///
+ public rssChannel channel
+ {
+ get
+ {
+ return this.channelField;
+ }
+ set
+ {
+ this.channelField = value;
+ }
+ }
+
+ ///
+ [System.Xml.Serialization.XmlAttributeAttribute()]
+ public decimal version
+ {
+ get
+ {
+ return this.versionField;
+ }
+ set
+ {
+ this.versionField = value;
+ }
+ }
+ }
+
+ ///
+ [System.SerializableAttribute()]
+ [System.ComponentModel.DesignerCategoryAttribute("code")]
+ [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
+ public partial class rssChannel
+ {
+
+ private string titleField;
+
+ private link linkField;
+
+ private string link1Field;
+
+ private string descriptionField;
+
+ private string lastBuildDateField;
+
+ private string languageField;
+
+ private string updatePeriodField;
+
+ private byte updateFrequencyField;
+
+ private string generatorField;
+
+ private rssChannelItem[] itemField;
+
+ ///
+ public string title
+ {
+ get
+ {
+ return this.titleField;
+ }
+ set
+ {
+ this.titleField = value;
+ }
+ }
+
+ ///
+ [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.w3.org/2005/Atom")]
+ public link link
+ {
+ get
+ {
+ return this.linkField;
+ }
+ set
+ {
+ this.linkField = value;
+ }
+ }
+
+ ///
+ [System.Xml.Serialization.XmlElementAttribute("link")]
+ public string link1
+ {
+ get
+ {
+ return this.link1Field;
+ }
+ set
+ {
+ this.link1Field = value;
+ }
+ }
+
+ ///
+ public string description
+ {
+ get
+ {
+ return this.descriptionField;
+ }
+ set
+ {
+ this.descriptionField = value;
+ }
+ }
+
+ ///
+ public string lastBuildDate
+ {
+ get
+ {
+ return this.lastBuildDateField;
+ }
+ set
+ {
+ this.lastBuildDateField = value;
+ }
+ }
+
+ ///
+ public string language
+ {
+ get
+ {
+ return this.languageField;
+ }
+ set
+ {
+ this.languageField = value;
+ }
+ }
+
+ ///
+ [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://purl.org/rss/1.0/modules/syndication/")]
+ public string updatePeriod
+ {
+ get
+ {
+ return this.updatePeriodField;
+ }
+ set
+ {
+ this.updatePeriodField = value;
+ }
+ }
+
+ ///
+ [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://purl.org/rss/1.0/modules/syndication/")]
+ public byte updateFrequency
+ {
+ get
+ {
+ return this.updateFrequencyField;
+ }
+ set
+ {
+ this.updateFrequencyField = value;
+ }
+ }
+
+ ///
+ public string generator
+ {
+ get
+ {
+ return this.generatorField;
+ }
+ set
+ {
+ this.generatorField = value;
+ }
+ }
+
+ ///
+ [System.Xml.Serialization.XmlElementAttribute("item")]
+ public rssChannelItem[] item
+ {
+ get
+ {
+ return this.itemField;
+ }
+ set
+ {
+ this.itemField = value;
+ }
+ }
+ }
+
+ ///
+ [System.SerializableAttribute()]
+ [System.ComponentModel.DesignerCategoryAttribute("code")]
+ [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2005/Atom")]
+ [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.w3.org/2005/Atom", IsNullable = false)]
+ public partial class link
+ {
+
+ private string hrefField;
+
+ private string relField;
+
+ private string typeField;
+
+ ///
+ [System.Xml.Serialization.XmlAttributeAttribute()]
+ public string href
+ {
+ get
+ {
+ return this.hrefField;
+ }
+ set
+ {
+ this.hrefField = value;
+ }
+ }
+
+ ///
+ [System.Xml.Serialization.XmlAttributeAttribute()]
+ public string rel
+ {
+ get
+ {
+ return this.relField;
+ }
+ set
+ {
+ this.relField = value;
+ }
+ }
+
+ ///
+ [System.Xml.Serialization.XmlAttributeAttribute()]
+ public string type
+ {
+ get
+ {
+ return this.typeField;
+ }
+ set
+ {
+ this.typeField = value;
+ }
+ }
+ }
+
+ ///
+ [System.SerializableAttribute()]
+ [System.ComponentModel.DesignerCategoryAttribute("code")]
+ [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
+ public partial class rssChannelItem
+ {
+
+ private string titleField;
+
+ private string linkField;
+
+ private string commentsField;
+
+ private string pubDateField;
+
+ private string creatorField;
+
+ private string[] categoryField;
+
+ private rssChannelItemGuid guidField;
+
+ private string descriptionField;
+
+ private string encodedField;
+
+ private string commentRssField;
+
+ private byte comments1Field;
+
+ ///
+ public string title
+ {
+ get
+ {
+ return this.titleField;
+ }
+ set
+ {
+ this.titleField = value;
+ }
+ }
+
+ ///
+ public string link
+ {
+ get
+ {
+ return this.linkField;
+ }
+ set
+ {
+ this.linkField = value;
+ }
+ }
+
+ ///
+ public string comments
+ {
+ get
+ {
+ return this.commentsField;
+ }
+ set
+ {
+ this.commentsField = value;
+ }
+ }
+
+ ///
+ public string pubDate
+ {
+ get
+ {
+ return this.pubDateField;
+ }
+ set
+ {
+ this.pubDateField = value;
+ }
+ }
+
+ ///
+ [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://purl.org/dc/elements/1.1/")]
+ public string creator
+ {
+ get
+ {
+ return this.creatorField;
+ }
+ set
+ {
+ this.creatorField = value;
+ }
+ }
+
+ ///
+ [System.Xml.Serialization.XmlElementAttribute("category")]
+ public string[] category
+ {
+ get
+ {
+ return this.categoryField;
+ }
+ set
+ {
+ this.categoryField = value;
+ }
+ }
+
+ ///
+ public rssChannelItemGuid guid
+ {
+ get
+ {
+ return this.guidField;
+ }
+ set
+ {
+ this.guidField = value;
+ }
+ }
+
+ ///
+ public string description
+ {
+ get
+ {
+ return this.descriptionField;
+ }
+ set
+ {
+ this.descriptionField = value;
+ }
+ }
+
+ ///
+ [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://purl.org/rss/1.0/modules/content/")]
+ public string encoded
+ {
+ get
+ {
+ return this.encodedField;
+ }
+ set
+ {
+ this.encodedField = value;
+ }
+ }
+
+ ///
+ [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://wellformedweb.org/CommentAPI/")]
+ public string commentRss
+ {
+ get
+ {
+ return this.commentRssField;
+ }
+ set
+ {
+ this.commentRssField = value;
+ }
+ }
+
+ ///
+ [System.Xml.Serialization.XmlElementAttribute("comments", Namespace = "http://purl.org/rss/1.0/modules/slash/")]
+ public byte comments1
+ {
+ get
+ {
+ return this.comments1Field;
+ }
+ set
+ {
+ this.comments1Field = value;
+ }
+ }
+ }
+
+ ///
+ [System.SerializableAttribute()]
+ [System.ComponentModel.DesignerCategoryAttribute("code")]
+ [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
+ public partial class rssChannelItemGuid
+ {
+
+ private bool isPermaLinkField;
+
+ private string valueField;
+
+ ///
+ [System.Xml.Serialization.XmlAttributeAttribute()]
+ public bool isPermaLink
+ {
+ get
+ {
+ return this.isPermaLinkField;
+ }
+ set
+ {
+ this.isPermaLinkField = value;
+ }
+ }
+
+ ///
+ [System.Xml.Serialization.XmlTextAttribute()]
+ public string Value
+ {
+ get
+ {
+ return this.valueField;
+ }
+ set
+ {
+ this.valueField = value;
+ }
+ }
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.CrossCutting/Utils/SerializationUtil.cs b/src/Minuto.Seguros.Infra.CrossCutting/Utils/SerializationUtil.cs
new file mode 100644
index 0000000..49a4f0b
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.CrossCutting/Utils/SerializationUtil.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Xml.Linq;
+using System.Xml.Serialization;
+
+namespace Minuto.Seguros.Infra.CrossCutting.Utils
+{
+ public static class SerializationUtil
+ {
+
+ public static T Deserialize(XDocument doc)
+ {
+ XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
+
+ using (var reader = doc.Root.CreateReader())
+ {
+ return (T)xmlSerializer.Deserialize(reader);
+ }
+ }
+
+ public static XDocument Serialize(T value)
+ {
+ XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
+
+ XDocument doc = new XDocument();
+ using (var writer = doc.CreateWriter())
+ {
+ xmlSerializer.Serialize(writer, value);
+ }
+
+ return doc;
+ }
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.CrossCutting/Utils/WordUtil.cs b/src/Minuto.Seguros.Infra.CrossCutting/Utils/WordUtil.cs
new file mode 100644
index 0000000..74cff20
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.CrossCutting/Utils/WordUtil.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Minuto.Seguros.Infra.CrossCutting.Utils
+{
+ public static class WordUtil
+ {
+ public static int CountRecurrence(string word, List words)
+ {
+ return words.Count(w => w == word);
+ }
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.Data/Connection/Config.cs b/src/Minuto.Seguros.Infra.Data/Connection/Config.cs
new file mode 100644
index 0000000..21ff2cd
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.Data/Connection/Config.cs
@@ -0,0 +1,24 @@
+using Microsoft.Extensions.Configuration;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Minuto.Seguros.Infra.Data.Connection
+{
+ public class Config : IConfig
+ {
+ public Config(IConfiguration configuration)
+ {
+ IConfigurationSection section = configuration.GetSection("MongoDB");
+ MongoConnectionString = section["ConnectionStrings"];
+ MongoDatabase = section["Database"];
+ }
+ public Config(string connectionString, string database)
+ {
+ MongoConnectionString = connectionString;
+ MongoDatabase = database;
+ }
+ public string MongoConnectionString { get; private set; }
+ public string MongoDatabase { get; private set; }
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.Data/Connection/IConfig.cs b/src/Minuto.Seguros.Infra.Data/Connection/IConfig.cs
new file mode 100644
index 0000000..7bf2293
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.Data/Connection/IConfig.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Minuto.Seguros.Infra.Data.Connection
+{
+ public interface IConfig
+ {
+ string MongoConnectionString { get; }
+ string MongoDatabase { get; }
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.Data/Connection/IConnect.cs b/src/Minuto.Seguros.Infra.Data/Connection/IConnect.cs
new file mode 100644
index 0000000..47bdfd5
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.Data/Connection/IConnect.cs
@@ -0,0 +1,10 @@
+using MongoDB.Driver;
+using System;
+
+namespace Minuto.Seguros.Infra.Data.Connection
+{
+ public interface IConnect : IDisposable
+ {
+ IMongoCollection Collection(string CollectionName);
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.Data/Context/MongoContext.cs b/src/Minuto.Seguros.Infra.Data/Context/MongoContext.cs
new file mode 100644
index 0000000..6c8a610
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.Data/Context/MongoContext.cs
@@ -0,0 +1,72 @@
+using Minuto.Seguros.Domain.Entities;
+using Minuto.Seguros.Infra.Data.Connection;
+using MongoDB.Bson.Serialization;
+using MongoDB.Driver;
+using System;
+
+namespace Minuto.Seguros.Infra.Data.Context
+{
+ public class MongoContext : IDisposable, IConnect
+ {
+ protected MongoClient Client { get; private set; }
+ protected IMongoDatabase DataBase { get; private set; }
+
+ public IMongoCollection Collection(string CollectionName)
+ {
+ return DataBase.GetCollection(CollectionName);
+ }
+ public MongoContext(IConfig config)
+ {
+ Client = new MongoClient(config.MongoConnectionString);
+ DataBase = Client.GetDatabase(config.MongoDatabase);
+ }
+
+ public MongoContext(string connectionString, string database)
+ {
+ Client = new MongoClient(connectionString);
+ DataBase = Client.GetDatabase(database);
+ Map();
+ }
+
+ public IMongoCollection Feeds
+ {
+ get
+ {
+ return DataBase.GetCollection("Feeds");
+ }
+ }
+
+ private void Map()
+ {
+ BsonClassMap.RegisterClassMap(cm =>
+ {
+ cm.AutoMap();
+ });
+ }
+
+ #region Dispose
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposed)
+ {
+ if (disposing)
+ {
+ DataBase = null;
+ Client = null;
+ }
+ disposed = true;
+ }
+ }
+ ~MongoContext()
+ {
+ Dispose(false);
+ }
+ private bool disposed = false;
+ #endregion Dispose
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.Data/Contracts/IBaseRepository.cs b/src/Minuto.Seguros.Infra.Data/Contracts/IBaseRepository.cs
new file mode 100644
index 0000000..b518e8e
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.Data/Contracts/IBaseRepository.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Minuto.Seguros.Infra.Data.Contracts
+{
+ public interface IBaseRepository where T : class
+ {
+ T Add(T model);
+ T Find(Expression> filter);
+ IEnumerable All(Expression> filter);
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.Data/Contracts/IFeedRepository.cs b/src/Minuto.Seguros.Infra.Data/Contracts/IFeedRepository.cs
new file mode 100644
index 0000000..13c103e
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.Data/Contracts/IFeedRepository.cs
@@ -0,0 +1,8 @@
+using Minuto.Seguros.Domain.Entities;
+
+namespace Minuto.Seguros.Infra.Data.Contracts
+{
+ public interface IFeedRepository: IBaseRepository
+ {
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.Data/DataModule.cs b/src/Minuto.Seguros.Infra.Data/DataModule.cs
new file mode 100644
index 0000000..a651b11
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.Data/DataModule.cs
@@ -0,0 +1,31 @@
+using Autofac;
+using Minuto.Seguros.Infra.Data.Context;
+
+namespace Minuto.Seguros.Infra.Data
+{
+ public class DataModule: Module
+ {
+ public readonly string _connectionString;
+ public readonly string _database;
+
+ public DataModule(string connectionString, string database)
+ {
+ _connectionString = connectionString;
+ _database = database;
+ }
+
+ protected override void Load(ContainerBuilder builder)
+ {
+ builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly())
+ .Where(t => t.Name.EndsWith("Repository") && !t.Name.EndsWith("BaseRepository"))
+ .AsImplementedInterfaces()
+ .InstancePerLifetimeScope();
+
+
+ builder.Register(c => new MongoContext(_connectionString, _database))
+ .As().SingleInstance();
+
+ base.Load(builder);
+ }
+ }
+}
diff --git a/src/Minuto.Seguros.Infra.Data/Minuto.Seguros.Infra.Data.csproj b/src/Minuto.Seguros.Infra.Data/Minuto.Seguros.Infra.Data.csproj
new file mode 100644
index 0000000..d6a7bb6
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.Data/Minuto.Seguros.Infra.Data.csproj
@@ -0,0 +1,19 @@
+
+
+
+ netcoreapp2.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Minuto.Seguros.Infra.Data/Repository/FeedRepository.cs b/src/Minuto.Seguros.Infra.Data/Repository/FeedRepository.cs
new file mode 100644
index 0000000..eeb965f
--- /dev/null
+++ b/src/Minuto.Seguros.Infra.Data/Repository/FeedRepository.cs
@@ -0,0 +1,38 @@
+using Minuto.Seguros.Domain.Entities;
+using Minuto.Seguros.Infra.Data.Context;
+using Minuto.Seguros.Infra.Data.Contracts;
+using MongoDB.Driver;
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Minuto.Seguros.Infra.Data.Repository
+{
+ public class FeedRepository : IFeedRepository
+ {
+ private readonly MongoContext _mongoContext;
+
+ public FeedRepository(MongoContext mongoContext)
+ {
+ _mongoContext = mongoContext;
+ }
+
+ public Feed Add(Feed model)
+ {
+ _mongoContext.Feeds.InsertOneAsync(model);
+ return model;
+ }
+
+ public IEnumerable All(Expression> filter)
+ {
+ return _mongoContext.Feeds.Find(filter).ToList();
+ }
+
+ public Feed Find(Expression> filter)
+ {
+ return _mongoContext.Feeds.Find(filter).FirstOrDefault();
+ }
+ }
+}
diff --git a/src/Minuto.Seguros.Service/Contracts/IBaseService.cs b/src/Minuto.Seguros.Service/Contracts/IBaseService.cs
new file mode 100644
index 0000000..ec79685
--- /dev/null
+++ b/src/Minuto.Seguros.Service/Contracts/IBaseService.cs
@@ -0,0 +1,16 @@
+using Minuto.Seguros.Domain.Entities;
+using Minuto.Seguros.Infra.Data.Contracts;
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+
+namespace Minuto.Seguros.Service.Contracts
+{
+ public interface IBaseService : IDisposable where T : IBaseRepository where TE : BaseEntity
+ {
+ TE Add(TE model);
+ TE Find(Expression> filter);
+ IEnumerable All(Expression> filter);
+ }
+}
diff --git a/src/Minuto.Seguros.Service/Contracts/IFeedService.cs b/src/Minuto.Seguros.Service/Contracts/IFeedService.cs
new file mode 100644
index 0000000..991915f
--- /dev/null
+++ b/src/Minuto.Seguros.Service/Contracts/IFeedService.cs
@@ -0,0 +1,15 @@
+using Minuto.Seguros.Domain.Entities;
+using Minuto.Seguros.Infra.Data.Contracts;
+using Minuto.Seguros.Service.Dto;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Minuto.Seguros.Service.Contracts
+{
+ public interface IFeedService : IBaseService
+ {
+ List GetFeeds();
+ List GetAllFeeds();
+ }
+}
diff --git a/src/Minuto.Seguros.Service/Dto/FeedDto.cs b/src/Minuto.Seguros.Service/Dto/FeedDto.cs
new file mode 100644
index 0000000..39ea0c2
--- /dev/null
+++ b/src/Minuto.Seguros.Service/Dto/FeedDto.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Minuto.Seguros.Service.Dto
+{
+ public class FeedDto
+ {
+ public string Title { get; set; }
+ public string Description { get; set; }
+ public string[] Categories { get; set; }
+ public string FullMessageClean { get; set; }
+ }
+}
diff --git a/src/Minuto.Seguros.Service/Dto/TopicDto.cs b/src/Minuto.Seguros.Service/Dto/TopicDto.cs
new file mode 100644
index 0000000..5f36f5a
--- /dev/null
+++ b/src/Minuto.Seguros.Service/Dto/TopicDto.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Minuto.Seguros.Service.Dto
+{
+ public class TopicDto
+ {
+ public string Title { get; set; }
+ public List TopWords{ get; set; }
+ public int TotalWords { get; set; }
+ public string CleanerText { get; set; }
+ }
+}
diff --git a/src/Minuto.Seguros.Service/Dto/WordDto.cs b/src/Minuto.Seguros.Service/Dto/WordDto.cs
new file mode 100644
index 0000000..5af148e
--- /dev/null
+++ b/src/Minuto.Seguros.Service/Dto/WordDto.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Minuto.Seguros.Service.Dto
+{
+ public class WordDto
+ {
+ public string Word { get; set; }
+ public int Amount { get; set; }
+ }
+}
diff --git a/src/Minuto.Seguros.Service/Minuto.Seguros.Service.csproj b/src/Minuto.Seguros.Service/Minuto.Seguros.Service.csproj
new file mode 100644
index 0000000..c69b29d
--- /dev/null
+++ b/src/Minuto.Seguros.Service/Minuto.Seguros.Service.csproj
@@ -0,0 +1,17 @@
+
+
+
+ netcoreapp2.1
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Minuto.Seguros.Service/ServiceModule.cs b/src/Minuto.Seguros.Service/ServiceModule.cs
new file mode 100644
index 0000000..4b025d7
--- /dev/null
+++ b/src/Minuto.Seguros.Service/ServiceModule.cs
@@ -0,0 +1,15 @@
+using Autofac;
+
+namespace Minuto.Seguros.Service
+{
+ public class ServiceModule : Module
+ {
+ protected override void Load(ContainerBuilder builder)
+ {
+ builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly())
+ .Where(t => t.Name.EndsWith("Service") && !t.Name.EndsWith("BaseService"))
+ .AsImplementedInterfaces();
+ base.Load(builder);
+ }
+ }
+}
diff --git a/src/Minuto.Seguros.Service/Services/BaseService.cs b/src/Minuto.Seguros.Service/Services/BaseService.cs
new file mode 100644
index 0000000..33881b1
--- /dev/null
+++ b/src/Minuto.Seguros.Service/Services/BaseService.cs
@@ -0,0 +1,42 @@
+using Minuto.Seguros.Domain.Entities;
+using Minuto.Seguros.Infra.Data.Contracts;
+using Minuto.Seguros.Service.Contracts;
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Minuto.Seguros.Service.Services
+{
+ internal abstract class BaseService : IBaseService where T : IBaseRepository where TE : BaseEntity
+ {
+ public readonly IBaseRepository _repository;
+
+ public BaseService(IBaseRepository repository)
+ {
+ _repository = repository;
+ }
+
+ public virtual TE Add(TE entity)
+ {
+ return _repository.Add(entity);
+ }
+
+ public IEnumerable All(Expression> filter)
+ {
+ return _repository.All(filter);
+ }
+
+ public void Dispose()
+ {
+ GC.SuppressFinalize(this);
+ }
+
+ public TE Find(Expression> filter)
+ {
+ return _repository.Find(filter);
+ }
+
+ }
+}
diff --git a/src/Minuto.Seguros.Service/Services/FeedService.cs b/src/Minuto.Seguros.Service/Services/FeedService.cs
new file mode 100644
index 0000000..8fe026f
--- /dev/null
+++ b/src/Minuto.Seguros.Service/Services/FeedService.cs
@@ -0,0 +1,108 @@
+using AutoMapper;
+using Minuto.Seguros.Domain.Entities;
+using Minuto.Seguros.Infra.Client.Corporate.Rss.Contracts;
+using Minuto.Seguros.Infra.CrossCutting.Utils;
+using Minuto.Seguros.Infra.Data.Contracts;
+using Minuto.Seguros.Service.Contracts;
+using Minuto.Seguros.Service.Dto;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Minuto.Seguros.Service.Services
+{
+ internal class FeedService : BaseService, IFeedService
+ {
+ private readonly IFeedRepository _feedRepository;
+ private readonly IRssClient _rssClient;
+ private readonly IMapper _mapper;
+
+ public FeedService(
+ IFeedRepository feedRepository,
+ IRssClient rssClient,
+ IMapper mapper
+ ) : base(feedRepository)
+ {
+ _feedRepository = feedRepository;
+ _rssClient = rssClient;
+ _mapper = mapper;
+ }
+
+ public List GetFeeds()
+ {
+ try
+ {
+ var feeds = _rssClient.GetFeeds();
+ List feedsMap = new List();
+
+ foreach (var item in feeds)
+ {
+ item.FullMessageClean = ClearSentenceUtil.ClearSentence(string.Concat(item.Title, " ", item.Description, " ", string.Join(", ", item.Categories)));
+ feedsMap.Add(_mapper.Map(item));
+ }
+
+ List words;
+ List wordsRecurrence;
+ List topics = new List();
+
+ foreach (var item in feedsMap)
+ {
+ wordsRecurrence = new List();
+ words = item.FullMessageClean.Split(' ').ToList();
+
+ foreach (var word in words)
+ {
+ if (!wordsRecurrence.Any(w => w.Word == word))
+ {
+ wordsRecurrence.Add(new WordDto()
+ {
+ Word = word,
+ Amount = WordUtil.CountRecurrence(word, words)
+ });
+ }
+ }
+
+ topics.Add(new TopicDto()
+ {
+ Title = item.Title,
+ TotalWords = wordsRecurrence.Count(),
+ TopWords = wordsRecurrence.OrderByDescending(w => w.Amount).Take(10).ToList(),
+ CleanerText = item.FullMessageClean
+ });
+ }
+
+ return topics;
+
+ } catch(Exception ex)
+ {
+ throw ex;
+ }
+
+ }
+
+ public List GetAllFeeds()
+ {
+ try {
+ var feeds = _rssClient.GetFeeds();
+ List feedsMap = new List();
+
+ foreach (var item in feeds)
+ {
+ feedsMap.Add(_mapper.Map(item));
+
+ /* Sem necessidade, apenas uma amostragem que quis colocar
+ * pra mostrar que se fosse uma integração continua, teríamos fácil uma base de dados para manipulação.
+ */
+ _feedRepository.Add(_mapper.Map(item));
+ }
+
+ return feedsMap;
+ }
+ catch (Exception ex)
+ {
+ throw ex;
+ }
+ }
+ }
+}
diff --git a/src/Minuto.Seguros.sln b/src/Minuto.Seguros.sln
new file mode 100644
index 0000000..6669990
--- /dev/null
+++ b/src/Minuto.Seguros.sln
@@ -0,0 +1,83 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27703.2042
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1 - Application", "1 - Application", "{FFA04C89-7397-4C58-BD03-B2135494A001}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2 - Domain", "2 - Domain", "{836DD694-FC22-410C-8178-CFC9F962B18F}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3 - Service", "3 - Service", "{D2C920A4-1557-4097-ABF7-D924252157B9}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4 - Infra", "4 - Infra", "{58DB3E18-46C1-4263-BC9B-59F45B8AFD1F}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4.1 - CrossCutting", "4.1 - CrossCutting", "{58E569A2-4C8C-4821-8142-692DDEF5D314}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Minuto.Seguros.Infra.CrossCutting", "Minuto.Seguros.Infra.CrossCutting\Minuto.Seguros.Infra.CrossCutting.csproj", "{67EE7CB7-4804-469F-B05B-1E50F709C790}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4.2 - Data", "4.2 - Data", "{1B0F4628-3482-46F4-B9D8-80E9021905F0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Minuto.Seguros.Infra.Data", "Minuto.Seguros.Infra.Data\Minuto.Seguros.Infra.Data.csproj", "{D09C4DBC-D564-495B-929A-F8A7BCD51D20}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Minuto.Seguros.Domain", "Minuto.Seguros.Domain\Minuto.Seguros.Domain.csproj", "{89C33D3B-269B-4B8C-9748-25F19660CE02}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Minuto.Seguros.Application", "Minuto.Seguros.Application\Minuto.Seguros.Application.csproj", "{C5B0E5BC-BAB0-40FD-97D5-F8A395E8E00D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Minuto.Seguros.Service", "Minuto.Seguros.Service\Minuto.Seguros.Service.csproj", "{1DC0F90D-0A43-44FF-B97C-EC9090FD23CE}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4.3 - Client", "4.3 - Client", "{CB64D581-B76A-448B-8324-C83CF71DFDC6}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4.3.1 - Corporate", "4.3.1 - Corporate", "{D23B1506-6257-46D4-B31F-A4DDDB2B704C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Minuto.Seguros.Infra.Client.Corporate.Rss", "Minuto.Seguros.Infra.Client.Corporate.Rss\Minuto.Seguros.Infra.Client.Corporate.Rss.csproj", "{950035F1-0F08-4C7D-8DBE-508126547D0C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {67EE7CB7-4804-469F-B05B-1E50F709C790}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {67EE7CB7-4804-469F-B05B-1E50F709C790}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {67EE7CB7-4804-469F-B05B-1E50F709C790}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {67EE7CB7-4804-469F-B05B-1E50F709C790}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D09C4DBC-D564-495B-929A-F8A7BCD51D20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D09C4DBC-D564-495B-929A-F8A7BCD51D20}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D09C4DBC-D564-495B-929A-F8A7BCD51D20}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D09C4DBC-D564-495B-929A-F8A7BCD51D20}.Release|Any CPU.Build.0 = Release|Any CPU
+ {89C33D3B-269B-4B8C-9748-25F19660CE02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {89C33D3B-269B-4B8C-9748-25F19660CE02}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {89C33D3B-269B-4B8C-9748-25F19660CE02}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {89C33D3B-269B-4B8C-9748-25F19660CE02}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C5B0E5BC-BAB0-40FD-97D5-F8A395E8E00D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C5B0E5BC-BAB0-40FD-97D5-F8A395E8E00D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C5B0E5BC-BAB0-40FD-97D5-F8A395E8E00D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C5B0E5BC-BAB0-40FD-97D5-F8A395E8E00D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1DC0F90D-0A43-44FF-B97C-EC9090FD23CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1DC0F90D-0A43-44FF-B97C-EC9090FD23CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1DC0F90D-0A43-44FF-B97C-EC9090FD23CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1DC0F90D-0A43-44FF-B97C-EC9090FD23CE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {950035F1-0F08-4C7D-8DBE-508126547D0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {950035F1-0F08-4C7D-8DBE-508126547D0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {950035F1-0F08-4C7D-8DBE-508126547D0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {950035F1-0F08-4C7D-8DBE-508126547D0C}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {58E569A2-4C8C-4821-8142-692DDEF5D314} = {58DB3E18-46C1-4263-BC9B-59F45B8AFD1F}
+ {67EE7CB7-4804-469F-B05B-1E50F709C790} = {58E569A2-4C8C-4821-8142-692DDEF5D314}
+ {1B0F4628-3482-46F4-B9D8-80E9021905F0} = {58DB3E18-46C1-4263-BC9B-59F45B8AFD1F}
+ {D09C4DBC-D564-495B-929A-F8A7BCD51D20} = {1B0F4628-3482-46F4-B9D8-80E9021905F0}
+ {89C33D3B-269B-4B8C-9748-25F19660CE02} = {836DD694-FC22-410C-8178-CFC9F962B18F}
+ {C5B0E5BC-BAB0-40FD-97D5-F8A395E8E00D} = {FFA04C89-7397-4C58-BD03-B2135494A001}
+ {1DC0F90D-0A43-44FF-B97C-EC9090FD23CE} = {D2C920A4-1557-4097-ABF7-D924252157B9}
+ {CB64D581-B76A-448B-8324-C83CF71DFDC6} = {58DB3E18-46C1-4263-BC9B-59F45B8AFD1F}
+ {D23B1506-6257-46D4-B31F-A4DDDB2B704C} = {CB64D581-B76A-448B-8324-C83CF71DFDC6}
+ {950035F1-0F08-4C7D-8DBE-508126547D0C} = {D23B1506-6257-46D4-B31F-A4DDDB2B704C}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {2DE70224-24E4-489E-89D8-B8CA86B701DB}
+ EndGlobalSection
+EndGlobal