diff --git a/SumaTuba.Infra/Contracts/Repositories/UserPlan/IPersonUserRepository.cs b/SumaTuba.Infra/Contracts/Repositories/UserPlan/IPersonUserRepository.cs new file mode 100644 index 0000000..fcd30d7 --- /dev/null +++ b/SumaTuba.Infra/Contracts/Repositories/UserPlan/IPersonUserRepository.cs @@ -0,0 +1,19 @@ +using SumaTube.Infra.MongoDB.Documents; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SumaTube.Infra.Contracts.Repositories.UserPlan +{ + public interface IPersonUserRepository + { + Task GetByIdAsync(string id); + Task GetByEmailAsync(string email); + Task> GetAllAsync(); + Task CreateAsync(PersonUserDocument PersonUserDocument); + Task UpdateAsync(PersonUserDocument PersonUserDocument); + Task DeleteAsync(string id); + } +} diff --git a/SumaTuba.Infra/MongoDB/Documents/PersonUserDocument.cs b/SumaTuba.Infra/MongoDB/Documents/PersonUserDocument.cs new file mode 100644 index 0000000..0b2a4ea --- /dev/null +++ b/SumaTuba.Infra/MongoDB/Documents/PersonUserDocument.cs @@ -0,0 +1,43 @@ +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SumaTube.Infra.MongoDB.Documents +{ + public class PersonUserDocument + { + [BsonId] + [BsonRepresentation(BsonType.ObjectId)] + public string Id { get; set; } + + public string Username { get; set; } + + public string FirstName { get; set; } + + public string LastName { get; set; } + + public string Email { get; set; } + + public DateTime LastChanged { get; set; } + + public bool IsActive { get; set; } + + public bool IsProfileCompleted { get; set; } + + public int CountryId { get; set; } + + public int BusinessAreaId { get; set; } + + public string DesiredName { get; set; } + + public DateTime CreatedAt { get; set; } + + public UserPaymentDocument CurrentPlan { get; set; } + + public List PastPlans { get; set; } = new List(); + } +} diff --git a/SumaTuba.Infra/MongoDB/Documents/UserPaymentDocument.cs b/SumaTuba.Infra/MongoDB/Documents/UserPaymentDocument.cs new file mode 100644 index 0000000..9763c15 --- /dev/null +++ b/SumaTuba.Infra/MongoDB/Documents/UserPaymentDocument.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SumaTube.Infra.MongoDB.Documents +{ + public class UserPaymentDocument + { + public string Id { get; set; } + + public string Name { get; set; } + + public decimal Value { get; set; } + + public DateTime StartDate { get; set; } + + public DateTime EndDate { get; set; } + + public bool IsActive { get; set; } + } +} diff --git a/SumaTuba.Infra/MongoDB/Mappers/UserPlan/PersonUserMapper.cs b/SumaTuba.Infra/MongoDB/Mappers/UserPlan/PersonUserMapper.cs new file mode 100644 index 0000000..2eae509 --- /dev/null +++ b/SumaTuba.Infra/MongoDB/Mappers/UserPlan/PersonUserMapper.cs @@ -0,0 +1,19 @@ +using SumaTube.Domain.Entities.UserPlan; +using SumaTube.Infra.MongoDB.Documents; +using SumaTube.Crosscutting.Mappers; + +namespace SumaTube.Infra.MongoDB.Mappers.UserPlan +{ + public static class PersonUserMapper + { + public static PersonUserDocument ToDocument(this PersonUser entity) + { + return entity.MapTo(); + } + + public static PersonUser ToDomain(this PersonUserDocument document) + { + return document.MapTo(); + } + } +} diff --git a/SumaTuba.Infra/MongoDB/MongoConfig.cs b/SumaTuba.Infra/MongoDB/MongoConfig.cs new file mode 100644 index 0000000..c7d82f2 --- /dev/null +++ b/SumaTuba.Infra/MongoDB/MongoConfig.cs @@ -0,0 +1,76 @@ +using SumaTube.Infra.MongoDB; +using MongoDB.Bson.Serialization.Conventions; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Serializers; +using MongoDB.Bson.Serialization.IdGenerators; +using MongoDB.Bson; +using SumaTube.Domain; +using SumaTube.Domain.Entities.UserPlan; + +namespace SumaTube.Infra.MongoDB +{ + public static class MongoConfig + { + public static void Configure() + { + var conventionPack = new ConventionPack { new IgnoreIfNullConvention(true) }; + ConventionRegistry.Register("IgnoreIfNull", conventionPack, t => true); + + if (!BsonClassMap.IsClassMapRegistered(typeof(PersonUser))) + { + BsonClassMap.RegisterClassMap(cm => + { + cm.MapIdProperty(p => p.Id) + .SetSerializer(new StringSerializer(BsonType.ObjectId)) + .SetIdGenerator(StringObjectIdGenerator.Instance); + + cm.MapProperty(p => p.Username); + cm.MapProperty(p => p.Name); + cm.MapProperty(p => p.Email); + cm.MapProperty(p => p.DateChanged); + cm.MapProperty(p => p.IsProfileCompleted); + cm.MapProperty(p => p.CountryId); + cm.MapProperty(p => p.BusinessAreaId); + cm.MapProperty(p => p.DesiredName); + cm.MapProperty(p => p.CreatedAt); + cm.MapProperty(p => p.Plano); + cm.MapProperty(p => p.PastPlans); + + cm.MapCreator(p => new PersonUser( + p.Id.Value, + p.Username, + p.Name, + p.Email, + p.DateChanged, + p.IsProfileCompleted, + p.CountryId, + p.BusinessAreaId, + p.DesiredName, + p.CreatedAt, + p.Plano, + p.PastPlans + )); + + cm.AutoMap(); + }); + } + + // Configure também as classes ValueObject se necessário + ConfigureValueObjects(); + } + + private static void ConfigureValueObjects() + { + if (!BsonClassMap.IsClassMapRegistered(typeof(Name))) + { + BsonClassMap.RegisterClassMap(cm => + { + cm.AutoMap(); + cm.MapCreator(n => new Name(n.FirstName, n.LastName)); + }); + } + + // Adicione mapeamento para outros value objects conforme necessário + } + } +} diff --git a/SumaTuba.Infra/MongoDB/MongoDBContext.cs b/SumaTuba.Infra/MongoDB/MongoDBContext.cs index 295d1b4..7c8393c 100644 --- a/SumaTuba.Infra/MongoDB/MongoDBContext.cs +++ b/SumaTuba.Infra/MongoDB/MongoDBContext.cs @@ -4,8 +4,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using MongoDB.Driver; +using SumaTube.Domain.Entities.UserPlan; -namespace Blinks.Infra.MongoDB +namespace SumaTube.Infra.MongoDB { public class MongoDbContext { diff --git a/SumaTuba.Infra/MongoDB/Repositories/PersonUserRepository.cs b/SumaTuba.Infra/MongoDB/Repositories/PersonUserRepository.cs new file mode 100644 index 0000000..cef42cb --- /dev/null +++ b/SumaTuba.Infra/MongoDB/Repositories/PersonUserRepository.cs @@ -0,0 +1,40 @@ +using MongoDB.Driver; +using SumaTube.Infra.MongoDB.Documents; + +namespace SumaTube.Infra.MongoDB.Repositories +{ + public class PersonUserRepository + { + private readonly IMongoCollection _collection; + + public PersonUserRepository(IMongoDatabase database) + { + _collection = database.GetCollection("PersonUsers"); + } + + public async Task GetByIdAsync(string id) + { + return await _collection.Find(p => p.Id == id).FirstOrDefaultAsync(); + } + + public async Task> GetAllAsync() + { + return await _collection.Find(_ => true).ToListAsync(); + } + + public async Task CreateAsync(PersonUserDocument PersonUserDocument) + { + await _collection.InsertOneAsync(PersonUserDocument); + } + + public async Task UpdateAsync(PersonUserDocument PersonUserDocument) + { + await _collection.ReplaceOneAsync(p => p.Id == PersonUserDocument.Id, PersonUserDocument); + } + + public async Task DeleteAsync(string id) + { + await _collection.DeleteOneAsync(p => p.Id == id); + } + } +} \ No newline at end of file diff --git a/SumaTuba.Infra/MongoDB/UserPerson.cs b/SumaTuba.Infra/MongoDB/UserPerson.cs index 7710f3b..d9da253 100644 --- a/SumaTuba.Infra/MongoDB/UserPerson.cs +++ b/SumaTuba.Infra/MongoDB/UserPerson.cs @@ -1,10 +1,10 @@ using global::MongoDB.Bson.Serialization.Attributes; using global::MongoDB.Bson; -namespace Blinks.Infra.MongoDB +namespace SumaTube.Infra.MongoDB { - public class PersonUser + public class UserPerson { [BsonId] [BsonRepresentation(BsonType.ObjectId)] diff --git a/SumaTuba.Infra/SumaTube.Infra.csproj b/SumaTuba.Infra/SumaTube.Infra.csproj index 41cbdd4..8a9897b 100644 --- a/SumaTuba.Infra/SumaTube.Infra.csproj +++ b/SumaTuba.Infra/SumaTube.Infra.csproj @@ -9,11 +9,21 @@ - - + + + + + + + + + + + + diff --git a/SumaTuba.Infra/VideoSumarizer/Videos/VideoProcessingMessageDocument.cs b/SumaTuba.Infra/VideoSumarizer/Videos/VideoProcessingMessageDocument.cs new file mode 100644 index 0000000..117b1c8 --- /dev/null +++ b/SumaTuba.Infra/VideoSumarizer/Videos/VideoProcessingMessageDocument.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SumaTube.Infra.VideoSumarizer.Videos +{ + public class VideoProcessingMessageDocument + { + public VideoProcessingMessageDocument(string sessionId, string url, string language) + { + SessionId = sessionId; + Url = url; + Language = language; + } + public string SessionId { get; private set; } + public string Url { get; private set; } + public string Language { get; private set; } + } +} diff --git a/SumaTuba.Infra/VideoSumarizer/Videos/VideoSumarizerService.cs b/SumaTuba.Infra/VideoSumarizer/Videos/VideoSumarizerService.cs new file mode 100644 index 0000000..6e1ffd6 --- /dev/null +++ b/SumaTuba.Infra/VideoSumarizer/Videos/VideoSumarizerService.cs @@ -0,0 +1,87 @@ +using RabbitMQ.Client; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace SumaTube.Infra.VideoSumarizer.Videos +{ + public class VideoSumarizerService + { + private static string _hostName = Environment.GetEnvironmentVariable("RABBITMQ_HOST") ?? "localhost"; + private static string _userName = Environment.GetEnvironmentVariable("RABBITMQ_USER") ?? "guest"; + private static string _password = Environment.GetEnvironmentVariable("RABBITMQ_PASSWORD") ?? "guest"; + private static string _queueName = "video-processing-queue"; + + public async Task RequestVideoSummarization(string sessionId, string url, string language) + { + Console.WriteLine("### Video Processor Publisher ###"); + Console.WriteLine($"Conectando ao RabbitMQ em {_hostName}..."); + + try + { + var factory = new ConnectionFactory() + { + HostName = _hostName, + UserName = _userName, + Password = _password + }; + + using (var connection = await factory.CreateConnectionAsync()) + using (var channel = await connection.CreateChannelAsync()) + { + await channel.QueueDeclareAsync( + queue: _queueName, + durable: true, + exclusive: false, + autoDelete: false, + arguments: null); + + var properties = new BasicProperties + { + Persistent = true + }; + + Console.WriteLine("Conexão estabelecida com RabbitMQ"); + Console.WriteLine("Pressione 'Ctrl+C' para sair"); + + // Loop para publicar mensagens + while (true) + { + if (string.IsNullOrWhiteSpace(language)) + language = "pt"; + + // Criar objeto de mensagem + var message = new VideoProcessingMessageDocument( + sessionId, + url, + language); + + // Serializar para JSON + var messageJson = JsonSerializer.Serialize(message); + var body = Encoding.UTF8.GetBytes(messageJson); + + // Publicar mensagem + await channel.BasicPublishAsync(exchange: string.Empty, + routingKey: _queueName, + mandatory: true, + basicProperties: properties, + body: body); + + Console.WriteLine($"[x] Mensagem enviada: {messageJson}"); + } + } + } + catch (Exception ex) + { + Console.WriteLine($"Erro: {ex.Message}"); + Console.WriteLine(ex.StackTrace); + } + + Console.WriteLine("Publicador finalizado."); + Console.ReadLine(); + } + } +} diff --git a/SumaTube.Crosscutting/Logging/Configuration/SerilogConfiguration.cs b/SumaTube.Crosscutting/Logging/Configuration/SerilogConfiguration.cs new file mode 100644 index 0000000..69c174c --- /dev/null +++ b/SumaTube.Crosscutting/Logging/Configuration/SerilogConfiguration.cs @@ -0,0 +1,116 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Serilog.Events; +using Serilog; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Serilog.Extensions.Hosting; +using Microsoft.AspNetCore.Builder; + +namespace SumaTube.Crosscutting.Logging.Configuration +{ + public static class SerilogConfiguration + { + public static LoggerConfiguration SetLoggerConfiguration(this WebApplicationBuilder builder, LoggerConfiguration config, IServiceProvider services, IConfiguration configuration) + { + var workspace = configuration["Serilog:Properties:Workspace"]; + var seqServer = configuration.GetValue("Serilog:WriteTo:2:Args:serverUrl"); ; + + config + .ReadFrom.Configuration(configuration) + .ReadFrom.Services(services) + .Enrich.FromLogContext() + .Enrich.WithEnvironmentName() + .Enrich.WithMachineName() + .Enrich.WithProperty("Application", "SumaTube") + .Enrich.WithProperty("Workspace", workspace) + .WriteTo.Seq(seqServer) + ; + + return config; + } + + + public static IServiceCollection AddSerilogServices(this IServiceCollection services, IConfiguration configuration, IHostEnvironment environment) + { + // Obtenha o workspace do Seq baseado no ambiente + //var workspace = environment.IsDevelopment() ? "Dev" : "Prod"; + + services.AddSingleton(); + + var workspace = configuration["Serilog:Properties:Workspace"]; + + // Crie o logger usando a configuração + Log.Logger = new LoggerConfiguration() + .ReadFrom.Configuration(configuration) + .Enrich.FromLogContext() + .Enrich.WithMachineName() + .Enrich.WithEnvironmentName() + //.Enrich.WithProperty("Workspace", workspace) // Adiciona explicitamente o workspace + .CreateLogger(); + + // Registra o logger no container de DI + services.AddSingleton(Log.Logger); + + return services; + } + + // Método opcional para configuração direta sem usar appsettings.json + public static IServiceCollection AddSerilogServicesWithCode( + this IServiceCollection services, + IHostEnvironment environment) + { + services.AddSingleton(); + + // Defina as configurações do Seq baseado no ambiente + var (workspace, apiKey) = environment.IsDevelopment() + ? ("Dev", "sua-api-key-dev") + : ("Prod", "sua-api-key-prod"); + + // Configuração básica para ambos ambientes + var loggerConfig = new LoggerConfiguration() + .MinimumLevel.Debug() + .Enrich.FromLogContext() + .Enrich.WithMachineName() + .Enrich.WithEnvironmentUserName() + .Enrich.WithThreadId() + .Enrich.WithProperty("Application", "SumaTube") + .Enrich.WithProperty("Environment", environment.EnvironmentName) + .Enrich.WithProperty("Workspace", workspace); + + // Adicione destinos específicos por ambiente + if (environment.IsDevelopment()) + { + loggerConfig + .MinimumLevel.Override("Microsoft", LogEventLevel.Information) + .WriteTo.Console() + .WriteTo.File("logs/dev-app-.log", rollingInterval: RollingInterval.Day); + } + else // Produção ou outros ambientes + { + loggerConfig + .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) + .MinimumLevel.Override("System", LogEventLevel.Error) + .WriteTo.File("logs/prod-app-.log", rollingInterval: RollingInterval.Day); + } + + // Adicione o Seq para ambos ambientes, mas com configurações diferentes + //loggerConfig.WriteTo.Seq( + // "http://logs-ingest.carneiro.ddnsfree.com", + // apiKey: apiKey); + loggerConfig.WriteTo.Seq( + "http://logs.carneiro.ddnsfree.com:5341"); + + Log.Logger = loggerConfig.CreateLogger(); + + // Registra o logger no container de DI + services.AddSingleton(Log.Logger); + + return services; + } + } +} diff --git a/SumaTube.Crosscutting/Logging/Extensions/LoggerExtensions.cs b/SumaTube.Crosscutting/Logging/Extensions/LoggerExtensions.cs new file mode 100644 index 0000000..278a278 --- /dev/null +++ b/SumaTube.Crosscutting/Logging/Extensions/LoggerExtensions.cs @@ -0,0 +1,28 @@ +using Microsoft.Extensions.Logging; + +namespace SumaTube.Crosscutting.Logging.Extensions +{ + public static class LoggerExtensions + { + public static void LogMethodEntry(this ILogger logger, string methodName, params object[] parameters) + { + logger.LogInformation("Entering method {MethodName} with parameters {@Parameters}", methodName, parameters); + } + + public static void LogMethodExit(this ILogger logger, string methodName, object result = null) + { + logger.LogInformation("Exiting method {MethodName} with result {@Result}", methodName, result); + } + + public static void LogException(this ILogger logger, Exception exception, string message = null) + { + logger.LogError(exception, message ?? "An error occurred: {ErrorMessage}", exception.Message); + } + + public static void LogPerformance(this ILogger logger, string operation, long elapsedMilliseconds) + { + logger.LogInformation("Performance: {Operation} took {ElapsedMilliseconds} ms", operation, elapsedMilliseconds); + } + } +} + diff --git a/SumaTube.Crosscutting/Mapper/GenericMapper.cs b/SumaTube.Crosscutting/Mapper/GenericMapper.cs new file mode 100644 index 0000000..8ef0cc7 --- /dev/null +++ b/SumaTube.Crosscutting/Mapper/GenericMapper.cs @@ -0,0 +1,254 @@ +namespace SumaTube.Crosscutting.Mappers +{ + using System; + using System.Linq; + using System.Reflection; + + public static class GenericMapper + { + public static TDestination MapTo(this TSource source) + where TDestination : class + { + if (source == null) + return default; + + var destType = typeof(TDestination); + + // Verifica se o tipo de destino tem um construtor público + var constructors = destType.GetConstructors(BindingFlags.Public | BindingFlags.Instance) + .OrderByDescending(c => c.GetParameters().Length) + .ToList(); + + // Se o tipo de destino tem um construtor com parâmetros, tenta mapear para ele + if (constructors.Any() && constructors[0].GetParameters().Length > 0) + { + return MapToImmutableObject(source, constructors); + } + // Caso contrário, usa a abordagem de mapeamento de propriedades para objetos mutáveis + else + { + return MapToMutableObject(source); + } + } + + private static TDestination MapToImmutableObject(TSource source, List constructors) + where TDestination : class + { + var sourceType = typeof(TSource); + var sourceProps = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance); + + // Tenta cada construtor, começando pelo que tem mais parâmetros + foreach (var constructor in constructors) + { + var parameters = constructor.GetParameters(); + if (parameters.Length == 0) + { + // Construtor sem parâmetros, cria instância diretamente + var instance = constructor.Invoke(null); + return (TDestination)instance; + } + + var parameterValues = new object[parameters.Length]; + bool canUseConstructor = true; + + // Tenta mapear os parâmetros do construtor + for (int i = 0; i < parameters.Length; i++) + { + var param = parameters[i]; + + // Procura propriedade com o mesmo nome (case insensitive) + var matchingProp = sourceProps.FirstOrDefault(p => + string.Equals(p.Name, param.Name, StringComparison.OrdinalIgnoreCase)); + + if (matchingProp != null) + { + var value = matchingProp.GetValue(source); + + // Se os tipos são compatíveis, usa o valor diretamente + if (param.ParameterType.IsAssignableFrom(matchingProp.PropertyType)) + { + parameterValues[i] = value; + } + // Verifica se existe uma conversão implícita + else if (value != null && TryImplicitConversion(value, param.ParameterType, out var convertedValue)) + { + parameterValues[i] = convertedValue; + } + // Se o valor é um tipo complexo, tenta mapear recursivamente + else if (value != null && !matchingProp.PropertyType.IsPrimitive && + !matchingProp.PropertyType.Namespace.StartsWith("System")) + { + try + { + var method = typeof(GenericMapper).GetMethod(nameof(MapTo)); + var genericMethod = method.MakeGenericMethod(matchingProp.PropertyType, param.ParameterType); + parameterValues[i] = genericMethod.Invoke(null, new[] { value }); + } + catch + { + canUseConstructor = false; + break; + } + } + else + { + canUseConstructor = false; + break; + } + } + else + { + // Se não encontrou uma propriedade correspondente, verifica se o parâmetro é opcional + if (param.IsOptional) + { + parameterValues[i] = param.DefaultValue; + } + else + { + canUseConstructor = false; + break; + } + } + } + + if (canUseConstructor) + { + try + { + var instance = constructor.Invoke(parameterValues); + return (TDestination)instance; + } + catch + { + // Se falhou ao criar a instância, tenta o próximo construtor + continue; + } + } + } + + // Se não conseguiu usar nenhum construtor, lança exceção + throw new InvalidOperationException( + $"Não foi possível mapear {sourceType.Name} para {typeof(TDestination).Name} " + + $"usando os construtores disponíveis. Verifique se os nomes das propriedades " + + $"correspondem aos nomes dos parâmetros do construtor (case insensitive)."); + } + + private static TDestination MapToMutableObject(TSource source) + where TDestination : class + { + var destType = typeof(TDestination); + + // Tenta criar uma instância usando o construtor sem parâmetros + TDestination destination; + try + { + destination = Activator.CreateInstance(); + } + catch (Exception ex) + { + throw new InvalidOperationException( + $"Não foi possível criar uma instância de {destType.Name}. " + + $"Certifique-se de que a classe tenha um construtor sem parâmetros acessível.", ex); + } + + var sourceType = typeof(TSource); + var sourceProps = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance); + var destProps = destType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty); + + foreach (var destProp in destProps) + { + if (!destProp.CanWrite) + continue; + + // Procura propriedade com o mesmo nome (case insensitive) + var sourceProp = sourceProps.FirstOrDefault(p => + string.Equals(p.Name, destProp.Name, StringComparison.OrdinalIgnoreCase)); + + if (sourceProp != null) + { + var value = sourceProp.GetValue(source); + if (value != null) + { + // Se os tipos são compatíveis, atribui diretamente + if (destProp.PropertyType.IsAssignableFrom(sourceProp.PropertyType)) + { + destProp.SetValue(destination, value); + } + // Verifica se existe uma conversão implícita + else if (TryImplicitConversion(value, destProp.PropertyType, out var convertedValue)) + { + destProp.SetValue(destination, convertedValue); + } + // Se o valor é um tipo complexo, tenta mapear recursivamente + else if (!sourceProp.PropertyType.IsPrimitive && + !sourceProp.PropertyType.Namespace.StartsWith("System")) + { + try + { + var method = typeof(GenericMapper).GetMethod(nameof(MapTo)); + var genericMethod = method.MakeGenericMethod(sourceProp.PropertyType, destProp.PropertyType); + var mappedValue = genericMethod.Invoke(null, new[] { value }); + destProp.SetValue(destination, mappedValue); + } + catch + { + // Ignora se não conseguir mapear + } + } + } + } + } + + return destination; + } + + private static bool TryImplicitConversion(object source, Type destinationType, out object result) + { + result = null; + if (source == null) return false; + + var sourceType = source.GetType(); + + // Verifica operador de conversão implícita no tipo de origem + var methodSource = sourceType.GetMethods(BindingFlags.Public | BindingFlags.Static) + .FirstOrDefault(m => + m.Name == "op_Implicit" && + m.ReturnType == destinationType && + m.GetParameters().Length == 1 && + m.GetParameters()[0].ParameterType == sourceType); + + if (methodSource != null) + { + result = methodSource.Invoke(null, new[] { source }); + return true; + } + + // Verifica operador de conversão implícita no tipo de destino + var methodDest = destinationType.GetMethods(BindingFlags.Public | BindingFlags.Static) + .FirstOrDefault(m => + m.Name == "op_Implicit" && + m.ReturnType == destinationType && + m.GetParameters().Length == 1 && + m.GetParameters()[0].ParameterType == sourceType); + + if (methodDest != null) + { + result = methodDest.Invoke(null, new[] { source }); + return true; + } + + // Tenta converter usando Convert.ChangeType + try + { + if (destinationType.IsValueType || destinationType == typeof(string)) + { + result = Convert.ChangeType(source, destinationType); + return true; + } + } + catch { } + + return false; + } + } +} diff --git a/SumaTube.Crosscutting/SumaTube.Crosscutting.csproj b/SumaTube.Crosscutting/SumaTube.Crosscutting.csproj new file mode 100644 index 0000000..8682132 --- /dev/null +++ b/SumaTube.Crosscutting/SumaTube.Crosscutting.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + diff --git a/SumaTube.Domain/Entities/BusinessAreas.cs b/SumaTube.Domain/Entities/BusinessAreas.cs deleted file mode 100644 index dd6719c..0000000 --- a/SumaTube.Domain/Entities/BusinessAreas.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Blinks.Domain.Entities -{ - public class BusinessAreas - { - public BusinessAreas() { } - - public string Name { get; set; } - } -} diff --git a/SumaTube.Domain/Entities/BusinessAres.cs b/SumaTube.Domain/Entities/BusinessAres.cs deleted file mode 100644 index f91ad5d..0000000 --- a/SumaTube.Domain/Entities/BusinessAres.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Blinks.Domain.Entities -{ - internal class BusinessAres - { - } -} diff --git a/SumaTube.Domain/Entities/LinkBio.cs b/SumaTube.Domain/Entities/LinkBio.cs deleted file mode 100644 index c858bac..0000000 --- a/SumaTube.Domain/Entities/LinkBio.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Blinks.Domain.Entities -{ - public class LinkBio - { - /// - /// Ordem de exibição - /// - public int OrderNum { get; set; } - - /// - /// Parte customizada do link - /// - public string UrlData { get; set; } - - /// - /// Parte fixa do link (obter do service links quando cadastrar) - /// - public string ServiceUrl { get; set; } - - /// - /// Url/caminho do PNG do link - /// - public string ServiceIcon { get; set; } - - /// - /// Exibir/nao exibir - /// - public bool IsVisible { get; set; } - } -} diff --git a/SumaTube.Domain/Entities/PageBio.cs b/SumaTube.Domain/Entities/PageBio.cs deleted file mode 100644 index 219ff29..0000000 --- a/SumaTube.Domain/Entities/PageBio.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Blinks.Domain.Entities -{ - public class PageBio - { - public int Id { get; set; } - public string UrlParte1 { get; set; } - public string UrlParte2 { get; set; } - public string Name { get; set; } - public string Description { get; set; } - public List? Links { get; set; } - } -} diff --git a/SumaTube.Domain/Entities/PersonUser.cs b/SumaTube.Domain/Entities/PersonUser.cs deleted file mode 100644 index 2b5a2a3..0000000 --- a/SumaTube.Domain/Entities/PersonUser.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Blinks.Domain.ValueObjects; - -namespace Blinks.Domain.Entities -{ - public class PersonUser - { - public Id id { get; private set; } - public Username Username { get; private set; } - public Name Name { get; private set; } - public string FirstName => Name.FirstName; - public string LastName => Name.LastName; - public Email Email { get; private set; } - public DateChanged DateChanged { get; private set; } - public bool IsProfileCompleted { get; private set; } - public int CountryId { get; private set; } - public int BusinessAreaId { get; private set; } - public string DesiredName { get; private set; } - public DateTime CreatedAt { get; private set; } - public UserPlan? Plano { get; private set; } - public List? PastPlans { get; private set; } - } -} diff --git a/SumaTube.Domain/Entities/UserPlan/PersonUser.cs b/SumaTube.Domain/Entities/UserPlan/PersonUser.cs new file mode 100644 index 0000000..ce6f32d --- /dev/null +++ b/SumaTube.Domain/Entities/UserPlan/PersonUser.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SumaTube.Domain.ValueObjects; + +namespace SumaTube.Domain.Entities.UserPlan +{ + public class PersonUser + { + public PersonUser(string id, Username username, Name name, Email email, + DateChanged dateChanged, bool isProfileCompleted, int countryId, + int businessAreaId, string desiredName, DateTime createdAt, + UserPayment plano = null, List pastPlans = null) + { + Id = id ?? Guid.NewGuid().ToString("N"); + Username = username; + Name = name; + Email = email; + DateChanged = dateChanged; + IsProfileCompleted = isProfileCompleted; + CountryId = countryId; + BusinessAreaId = businessAreaId; + DesiredName = desiredName; + CreatedAt = createdAt; + Plano = plano; + PastPlans = pastPlans ?? new List(); + } + + public Id Id { get; private set; } + public Username Username { get; private set; } + public Name Name { get; private set; } + public string FirstName => Name.FirstName; + public string LastName => Name.LastName; + public Email Email { get; private set; } + public DateChanged DateChanged { get; private set; } + public bool IsProfileCompleted { get; private set; } + public int CountryId { get; private set; } + public int BusinessAreaId { get; private set; } + public string DesiredName { get; private set; } + public DateTime CreatedAt { get; private set; } + public UserPayment? Plano { get; private set; } + public List? PastPlans { get; private set; } + + public PersonUser AddPlano(UserPayment plano) + { + if (plano == null) throw new ArgumentNullException(nameof(plano)); + PastPlans.Add(plano); + return this; + } + + + } +} diff --git a/SumaTube.Domain/Entities/ServiceLinkPart.cs b/SumaTube.Domain/Entities/UserPlan/ServiceLinkPart.cs similarity index 88% rename from SumaTube.Domain/Entities/ServiceLinkPart.cs rename to SumaTube.Domain/Entities/UserPlan/ServiceLinkPart.cs index 9da3b32..0e29848 100644 --- a/SumaTube.Domain/Entities/ServiceLinkPart.cs +++ b/SumaTube.Domain/Entities/UserPlan/ServiceLinkPart.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Blinks.Domain.Entities +namespace SumaTube.Domain.Entities.UserPlan.UserPlan { public class ServiceLinkPart { diff --git a/SumaTube.Domain/Entities/ServiceLinks.cs b/SumaTube.Domain/Entities/UserPlan/ServiceLinks.cs similarity index 94% rename from SumaTube.Domain/Entities/ServiceLinks.cs rename to SumaTube.Domain/Entities/UserPlan/ServiceLinks.cs index b596c59..77d12f5 100644 --- a/SumaTube.Domain/Entities/ServiceLinks.cs +++ b/SumaTube.Domain/Entities/UserPlan/ServiceLinks.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Blinks.Domain.Entities +namespace SumaTube.Domain.Entities.UserPlan.UserPlan { /// /// Vai ler uma lista estatica do BD com os links dos serviços diff --git a/SumaTube.Domain/Entities/UserPlan.cs b/SumaTube.Domain/Entities/UserPlan/UserPayment.cs similarity index 87% rename from SumaTube.Domain/Entities/UserPlan.cs rename to SumaTube.Domain/Entities/UserPlan/UserPayment.cs index 11dd18d..7235057 100644 --- a/SumaTube.Domain/Entities/UserPlan.cs +++ b/SumaTube.Domain/Entities/UserPlan/UserPayment.cs @@ -4,9 +4,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Blinks.Domain.Entities +namespace SumaTube.Domain.Entities.UserPlan { - public class UserPlan + public class UserPayment { public int Id { get; set; } public string Name { get; set; } diff --git a/SumaTube.Domain/Entities/Videos/UserVideo.cs b/SumaTube.Domain/Entities/Videos/UserVideo.cs new file mode 100644 index 0000000..3e77699 --- /dev/null +++ b/SumaTube.Domain/Entities/Videos/UserVideo.cs @@ -0,0 +1,48 @@ +using BaseDomain.Results; +using SumaTube.Domain.ValueObjects; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SumaTube.Domain.Entities.Videos +{ + public class UserVideo + { + + public Id Id { get; private set; } + public string Name { get; private set; } + public List VideoGroups { get; private set; } = new List(); + + public UserVideo(int userId, string name) + { + this.Id = Guid.NewGuid(); + this.Name = name; + } + + public Result AddVideoGroup(string name, string description) + { + if (!VideoGroups.Any(v => v.Name == name)) + { + this.VideoGroups.Add(new VideoGroup(name, description)); + return true; + } + return false; + } + + public Result AddVideo(string collectionName, string url) + { + var videoCollectionItem = VideoGroups.Find(v => v.Name == collectionName); + if (videoCollectionItem != null) + { + if (videoCollectionItem.Videos.Any(v => v.Url == url)) return false; + videoCollectionItem.AddVideo(this.Id.Value, url); + return true; + } + return false; + } + + public static UserVideo Create(int userId, string name) => new UserVideo(userId, name); + } +} diff --git a/SumaTube.Domain/Entities/Videos/VideoData.cs b/SumaTube.Domain/Entities/Videos/VideoData.cs new file mode 100644 index 0000000..8347453 --- /dev/null +++ b/SumaTube.Domain/Entities/Videos/VideoData.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SumaTube.Domain.Entities.Videos +{ + public enum VideoSiteEnum + { + Youtube + } + public class VideoData + { + public string SessionId { get; private set; } + public string Title { get; private set; } + public string Image { get; private set; } + public string Url { get; private set; } + public VideoSiteEnum Site { get; private set; } + public VideoResult VideoResult { get; private set; } + + public VideoData(string sessionId, string url) + { + SessionId = sessionId; + Url = url; + } + + public void SetVideoResult(VideoResult videoResult) + { + VideoResult = videoResult; + } + + public void UpdateData(string title, string iamge) + { + Title = title; + Image = iamge; + } + public void ChangeStatus(VideoStatusEnum videoStatus) + { + this.VideoResult.ChangeStatus(videoStatus); + } + } +} diff --git a/SumaTube.Domain/Entities/Videos/VideoGroup.cs b/SumaTube.Domain/Entities/Videos/VideoGroup.cs new file mode 100644 index 0000000..510a988 --- /dev/null +++ b/SumaTube.Domain/Entities/Videos/VideoGroup.cs @@ -0,0 +1,45 @@ +using SumaTube.Domain.ValueObjects; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SumaTube.Domain.Entities.Videos +{ + public class VideoGroup + { + public Id Id { get; set; } + + public string Name { get; set; } + + public string Description { get; set; } + + public DateTime CreatedAt { get; set; } + + public List Videos { get; private set; } + + public VideoGroup(string name, string description) + { + Id = Guid.NewGuid(); + Name = name; + Description = description; + CreatedAt = DateTime.Now; + Videos = new List(); + } + + public VideoGroup(string id, string name, string description, DateTime createdAt, List videos) + { + Id = id; + Name = name; + Description = description; + CreatedAt = createdAt; + Videos = videos; + } + + public void AddVideo(string sessionId, string url) + { + Videos.Add(new VideoData(sessionId, url)); + } + } +} diff --git a/SumaTube.Domain/Entities/Videos/VideoResult.cs b/SumaTube.Domain/Entities/Videos/VideoResult.cs new file mode 100644 index 0000000..096b358 --- /dev/null +++ b/SumaTube.Domain/Entities/Videos/VideoResult.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SumaTube.Domain.Entities.Videos +{ + public enum VideoStatusEnum + { + Requested, + Processed, + Error + } + public class VideoResult + { + public string VideoUrl { get; private set; } + public string Summary { get; private set; } + public string ErrorMessage { get; private set; } + public VideoStatusEnum VideoStatus { get; private set; } + public DateTime LastStatusDate { get; private set; } + + public void ChangeStatus(VideoStatusEnum status) + { + LastStatusDate = DateTime.Now; + VideoStatus = status; + } + } +} diff --git a/SumaTube.Domain/SumaTube.Domain.csproj b/SumaTube.Domain/SumaTube.Domain.csproj index 7a86427..31c4e52 100644 --- a/SumaTube.Domain/SumaTube.Domain.csproj +++ b/SumaTube.Domain/SumaTube.Domain.csproj @@ -18,4 +18,9 @@ + + + + + diff --git a/SumaTube.Domain/ValueObjects/DateBirth.cs b/SumaTube.Domain/ValueObjects/DateBirth.cs index bce01cd..4922010 100644 --- a/SumaTube.Domain/ValueObjects/DateBirth.cs +++ b/SumaTube.Domain/ValueObjects/DateBirth.cs @@ -4,7 +4,7 @@ using System.Diagnostics.Metrics; using System.IO; using System.Reflection.Emit; -namespace Blinks.Domain +namespace SumaTube.Domain { public class DateBirth : AValueObject { diff --git a/SumaTube.Domain/ValueObjects/DateChanged.cs b/SumaTube.Domain/ValueObjects/DateChanged.cs index 0f96921..f2dddde 100644 --- a/SumaTube.Domain/ValueObjects/DateChanged.cs +++ b/SumaTube.Domain/ValueObjects/DateChanged.cs @@ -2,7 +2,7 @@ using BaseDomain; using System.Globalization; -namespace Blinks.Domain +namespace SumaTube.Domain { public class DateChanged : AValueObject { diff --git a/SumaTube.Domain/ValueObjects/Email.cs b/SumaTube.Domain/ValueObjects/Email.cs index a86bf25..b14f523 100644 --- a/SumaTube.Domain/ValueObjects/Email.cs +++ b/SumaTube.Domain/ValueObjects/Email.cs @@ -1,7 +1,7 @@ using BaseDomain; using System.Net.Mail; -namespace Blinks.Domain +namespace SumaTube.Domain { public class Email : AValueObject { diff --git a/SumaTube.Domain/ValueObjects/Id.cs b/SumaTube.Domain/ValueObjects/Id.cs index 92d6347..f156510 100644 --- a/SumaTube.Domain/ValueObjects/Id.cs +++ b/SumaTube.Domain/ValueObjects/Id.cs @@ -1,22 +1,66 @@ using BaseDomain; using System; using System.Collections.Generic; +using System.Drawing; using System.Linq; +using System.Runtime.CompilerServices; +using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; -namespace Blinks.Domain.ValueObjects +namespace SumaTube.Domain.ValueObjects { public class Id : AValueObject { + private string _value; + public string Value => _value; + public override bool GetValidationExpression() { - throw new NotImplementedException(); + return string.IsNullOrWhiteSpace(_value); } protected override IEnumerable GetEqualityComponents() { throw new NotImplementedException(); } + + public Id(string valor, Guid id) + { + if (string.IsNullOrWhiteSpace(valor)) + throw new ArgumentException("O valor não pode ser nulo ou vazio", nameof(valor)); + + _value = valor; + } + + public Id(Guid id) + { + _value = id.ToString("N"); + } + + + private Id(string valor) : this(valor, Guid.NewGuid()) + { + } + + public static implicit operator Id(string valor) + { + return new Id(valor); + } + + public static implicit operator Id(Guid id) + { + return new Id(id); + } + + public static explicit operator string(Id vo) + { + return vo.Value.ToString(); + } + + public static explicit operator Guid(Id vo) + { + return Guid.Parse(vo.Value); + } } } diff --git a/SumaTube.Domain/ValueObjects/Name.cs b/SumaTube.Domain/ValueObjects/Name.cs index 5125e0d..f91ec1e 100644 --- a/SumaTube.Domain/ValueObjects/Name.cs +++ b/SumaTube.Domain/ValueObjects/Name.cs @@ -1,23 +1,29 @@ using BaseDomain; -namespace Blinks.Domain +namespace SumaTube.Domain { public class Name : AValueObject { - public Name(string fullName) - { + public Name(string fullName) + { this.FullName = fullName; var names = fullName.Split(' '); if (names.Length >= 2) { this.FirstName = names[0]; - this.LastName = names[names.Length-1]; + this.LastName = names[names.Length - 1]; } } - public string FullName { get; set; } - public string FirstName { get; set; } - public string LastName { get; set; } + public Name(string firstName, string lastName) + { + this.FirstName = firstName; + this.LastName = lastName; + } + + public string FullName { get; private set; } + public string FirstName { get; private set; } + public string LastName { get; private set; } public override bool GetValidationExpression() { diff --git a/SumaTube.Domain/ValueObjects/Phone.cs b/SumaTube.Domain/ValueObjects/Phone.cs index 15fb16b..faa4b7d 100644 --- a/SumaTube.Domain/ValueObjects/Phone.cs +++ b/SumaTube.Domain/ValueObjects/Phone.cs @@ -1,7 +1,7 @@ using BaseDomain; using System.Text.RegularExpressions; -namespace Blinks.Domain +namespace SumaTube.Domain { public class Phone : AValueObject { diff --git a/SumaTube.Domain/ValueObjects/Username.cs b/SumaTube.Domain/ValueObjects/Username.cs index d9a5395..0e01174 100644 --- a/SumaTube.Domain/ValueObjects/Username.cs +++ b/SumaTube.Domain/ValueObjects/Username.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Blinks.Domain.ValueObjects +namespace SumaTube.Domain.ValueObjects { public class Username { diff --git a/SumaTube.sln b/SumaTube.sln index d7fa2d3..73a2817 100644 --- a/SumaTube.sln +++ b/SumaTube.sln @@ -11,6 +11,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SumaTube", "SumaTube\SumaTu EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseDomain", "BaseDomain\BaseDomain.csproj", "{8DEA200D-FF43-0D75-15A2-7DA8831449C9}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SumaTube.Crosscutting", "SumaTube.Crosscutting\SumaTube.Crosscutting.csproj", "{46EE417D-A974-4011-9799-646F31C9C146}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SumaTube.Application", "..\SumaTube.Application\SumaTube.Application.csproj", "{C598FDC6-26F5-44B2-AB7C-A5471DBE4168}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,6 +37,14 @@ Global {8DEA200D-FF43-0D75-15A2-7DA8831449C9}.Debug|Any CPU.Build.0 = Debug|Any CPU {8DEA200D-FF43-0D75-15A2-7DA8831449C9}.Release|Any CPU.ActiveCfg = Release|Any CPU {8DEA200D-FF43-0D75-15A2-7DA8831449C9}.Release|Any CPU.Build.0 = Release|Any CPU + {46EE417D-A974-4011-9799-646F31C9C146}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {46EE417D-A974-4011-9799-646F31C9C146}.Debug|Any CPU.Build.0 = Debug|Any CPU + {46EE417D-A974-4011-9799-646F31C9C146}.Release|Any CPU.ActiveCfg = Release|Any CPU + {46EE417D-A974-4011-9799-646F31C9C146}.Release|Any CPU.Build.0 = Release|Any CPU + {C598FDC6-26F5-44B2-AB7C-A5471DBE4168}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C598FDC6-26F5-44B2-AB7C-A5471DBE4168}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C598FDC6-26F5-44B2-AB7C-A5471DBE4168}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C598FDC6-26F5-44B2-AB7C-A5471DBE4168}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SumaTube/Controllers/CartHomeController.cs b/SumaTube/Controllers/CartHomeController.cs index 5e1ed80..a304908 100644 --- a/SumaTube/Controllers/CartHomeController.cs +++ b/SumaTube/Controllers/CartHomeController.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Mvc; -namespace Blinks.Controllers +namespace SumaTube.Controllers { public class CartHomeController : Controller { diff --git a/SumaTube/Controllers/HomeController.cs b/SumaTube/Controllers/HomeController.cs index d9491cc..1f5e4e4 100644 --- a/SumaTube/Controllers/HomeController.cs +++ b/SumaTube/Controllers/HomeController.cs @@ -1,21 +1,23 @@ using Microsoft.AspNetCore.Mvc; using System.Diagnostics; -using Blinks.Models; +using SumaTube.Crosscutting.Logging.Extensions; +using SumaTube.Models; -namespace Blinks.Controllers +namespace SumaTube.Controllers { public class HomeController : Controller { - private readonly ILogger logger; + private readonly ILogger _logger; public HomeController(ILogger logger) { - this.logger = logger; + this._logger = logger; } public IActionResult Index() { - this.logger.LogInformation("Home carregada!"); + _logger.LogInformation("Home carregada!"); + _logger.LogMethodEntry(nameof(Index)); return View(); } diff --git a/SumaTube/Controllers/LanguageController.cs b/SumaTube/Controllers/LanguageController.cs index 333e780..69cde13 100644 --- a/SumaTube/Controllers/LanguageController.cs +++ b/SumaTube/Controllers/LanguageController.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Mvc; using System.Globalization; -namespace Blinks.Controllers +namespace SumaTube.Controllers { public class LanguageController : Controller { diff --git a/SumaTube/Controllers/LoginController.cs b/SumaTube/Controllers/LoginController.cs index 10688a0..56b0770 100644 --- a/SumaTube/Controllers/LoginController.cs +++ b/SumaTube/Controllers/LoginController.cs @@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication; using Stripe; -namespace Blinks.Controllers +namespace SumaTube.Controllers { public class LoginController : Controller { diff --git a/SumaTube/Controllers/PayController.cs b/SumaTube/Controllers/PayController.cs index c0227fb..8b27ed3 100644 --- a/SumaTube/Controllers/PayController.cs +++ b/SumaTube/Controllers/PayController.cs @@ -2,7 +2,7 @@ using Stripe; using Stripe.Checkout; -namespace Blinks.Controllers +namespace SumaTube.Controllers { [Route("Pay")] public class PayController : Controller diff --git a/SumaTube/Controllers/PlansController.cs b/SumaTube/Controllers/PlansController.cs index 2ac88cb..eef08e1 100644 --- a/SumaTube/Controllers/PlansController.cs +++ b/SumaTube/Controllers/PlansController.cs @@ -2,9 +2,9 @@ using Newtonsoft.Json; using Stripe; using Stripe.Checkout; -using Blinks.Models; +using SumaTube.Models; -namespace Blinks.Controllers +namespace SumaTube.Controllers { public class PlansController : Controller { diff --git a/SumaTube/Controllers/SignInController.cs b/SumaTube/Controllers/SignInController.cs index c1e2c98..58e6100 100644 --- a/SumaTube/Controllers/SignInController.cs +++ b/SumaTube/Controllers/SignInController.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Mvc; using System.Diagnostics; -namespace Blinks.Controllers +namespace SumaTube.Controllers { [Route("signin-microsoft")] public class SignInController : Controller diff --git a/SumaTube/Controllers/StartupController.cs b/SumaTube/Controllers/StartupController.cs index 85ba2ff..5aef120 100644 --- a/SumaTube/Controllers/StartupController.cs +++ b/SumaTube/Controllers/StartupController.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Mvc; -namespace Blinks.Controllers +namespace SumaTube.Controllers { public class StartupController : Controller { diff --git a/SumaTube/Dockerfile b/SumaTube/Dockerfile index ea45e5f..3c44468 100644 --- a/SumaTube/Dockerfile +++ b/SumaTube/Dockerfile @@ -7,16 +7,16 @@ EXPOSE 443 FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build WORKDIR /src -COPY ["Blinks.csproj", "."] -RUN dotnet restore "./Blinks.csproj" +COPY ["SumaTube.csproj", "."] +RUN dotnet restore "./SumaTube.csproj" COPY . . WORKDIR "/src/." -RUN dotnet build "Blinks.csproj" -c Release -o /app/build +RUN dotnet build "SumaTube.csproj" -c Release -o /app/build FROM build AS publish -RUN dotnet publish "Blinks.csproj" -c Release -o /app/publish /p:UseAppHost=false +RUN dotnet publish "SumaTube.csproj" -c Release -o /app/publish /p:UseAppHost=false FROM base AS final WORKDIR /app COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "Blinks.dll"] \ No newline at end of file +ENTRYPOINT ["dotnet", "SumaTube.dll"] \ No newline at end of file diff --git a/SumaTube/LogConfig/LogCredentials.cs b/SumaTube/LogConfig/LogCredentials.cs index aa357ac..f15ecdd 100644 --- a/SumaTube/LogConfig/LogCredentials.cs +++ b/SumaTube/LogConfig/LogCredentials.cs @@ -1,6 +1,6 @@ //using Serilog.Sinks.Loki; -//namespace Blinks.LogConfig +//namespace SumaTube.LogConfig //{ // public class LogCredentials : LokiCredentials // { diff --git a/SumaTube/LogConfig/LogLabelProvider.cs b/SumaTube/LogConfig/LogLabelProvider.cs index dc8d067..a0a4764 100644 --- a/SumaTube/LogConfig/LogLabelProvider.cs +++ b/SumaTube/LogConfig/LogLabelProvider.cs @@ -1,6 +1,6 @@ //using Serilog.Sinks.Loki.Labels; -namespace Blinks.LogConfig +namespace SumaTube.LogConfig { //public class LogLabelProvider : ILogLabelProvider //{ @@ -8,7 +8,7 @@ namespace Blinks.LogConfig // { // return new List // { - // new LokiLabel("app", "blinks"), + // new LokiLabel("app", "SumaTube"), // new LokiLabel("namespace", "test") // }; // } diff --git a/SumaTube/Middle/RequestLocalizationMiddleware.cs b/SumaTube/Middle/RequestLocalizationMiddleware.cs index 62a7e0b..aa87cfd 100644 --- a/SumaTube/Middle/RequestLocalizationMiddleware.cs +++ b/SumaTube/Middle/RequestLocalizationMiddleware.cs @@ -1,4 +1,4 @@ -namespace Blinks.Middle +namespace SumaTube.Middle { using Microsoft.AspNetCore.Http; using System.Globalization; diff --git a/SumaTube/Models/ChangeViewModel.cs b/SumaTube/Models/ChangeViewModel.cs index 8b91cc3..5d54d90 100644 --- a/SumaTube/Models/ChangeViewModel.cs +++ b/SumaTube/Models/ChangeViewModel.cs @@ -1,4 +1,4 @@ -namespace Blinks.Models +namespace SumaTube.Models { public class ChangeViewModel { diff --git a/SumaTube/Models/ErrorViewModel.cs b/SumaTube/Models/ErrorViewModel.cs index 755301c..de8102b 100644 --- a/SumaTube/Models/ErrorViewModel.cs +++ b/SumaTube/Models/ErrorViewModel.cs @@ -1,4 +1,4 @@ -namespace Blinks.Models +namespace SumaTube.Models { public class ErrorViewModel { diff --git a/SumaTube/Models/Payment.cs b/SumaTube/Models/Payment.cs index ce8aae5..343bd50 100644 --- a/SumaTube/Models/Payment.cs +++ b/SumaTube/Models/Payment.cs @@ -1,4 +1,4 @@ -namespace Blinks.Models +namespace SumaTube.Models { public class Payment { diff --git a/SumaTube/NewReport2.upgrade.json b/SumaTube/NewReport2.upgrade.json index a0aa5b9..27e8022 100644 --- a/SumaTube/NewReport2.upgrade.json +++ b/SumaTube/NewReport2.upgrade.json @@ -32,7 +32,7 @@ }, "projects": [ { - "path": "Blinks.csproj", + "path": "SumaTube.csproj", "startingProject": true, "issues": 1, "storyPoints": 1, @@ -40,7 +40,7 @@ { "incidentId": "1161414d-b2e4-4447-9d34-e811b563e1c5", "ruleId": "NuGet.0001", - "projectPath": "Blinks.csproj", + "projectPath": "SumaTube.csproj", "state": "Active", "location": { "snippetModel": { @@ -48,7 +48,7 @@ "protected": "Microsoft.VisualStudio.Azure.Containers.Tools.Targets, 1.19.4\n\nRecommendation:\n\nNo supported version found" }, "kind": "File", - "path": "Blinks.csproj", + "path": "SumaTube.csproj", "snippet": "Microsoft.VisualStudio.Azure.Containers.Tools.Targets, 1.19.4\n\nRecommendation:\n\nNo supported version found", "protectedSnippet": "Microsoft.VisualStudio.Azure.Containers.Tools.Targets, 1.19.4\n\nRecommendation:\n\nNo supported version found", "label": "Microsoft.VisualStudio.Azure.Containers.Tools.Targets 1.19.4" @@ -57,7 +57,7 @@ ] }, { - "path": "C:\\vscode\\Blinks.me.mvc\\Blinks.Domain\\Blinks.Domain.csproj", + "path": "C:\\vscode\\SumaTube.me.mvc\\SumaTube.Domain\\SumaTube.Domain.csproj", "startingProject": true, "issues": 1, "storyPoints": 1, @@ -65,7 +65,7 @@ { "incidentId": "2fdd89a6-9f8d-4428-8845-41d048dcaf73", "ruleId": "Project.0002", - "projectPath": "C:\\vscode\\Blinks.me.mvc\\Blinks.Domain\\Blinks.Domain.csproj", + "projectPath": "C:\\vscode\\SumaTube.me.mvc\\SumaTube.Domain\\SumaTube.Domain.csproj", "state": "Active", "location": { "snippetModel": { @@ -73,7 +73,7 @@ "protected": "Current: net7.0\nNew: net8.0" }, "kind": "File", - "path": "C:\\vscode\\Blinks.me.mvc\\Blinks.Domain\\Blinks.Domain.csproj", + "path": "C:\\vscode\\SumaTube.me.mvc\\SumaTube.Domain\\SumaTube.Domain.csproj", "snippet": "Current: net7.0\nNew: net8.0", "protectedSnippet": "Current: net7.0\nNew: net8.0" } diff --git a/SumaTube/Program.cs b/SumaTube/Program.cs index acf7a95..3e52531 100644 --- a/SumaTube/Program.cs +++ b/SumaTube/Program.cs @@ -1,4 +1,4 @@ -using Blinks.LogConfig; +using SumaTube.LogConfig; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Google; using Microsoft.AspNetCore.Authentication.MicrosoftAccount; @@ -11,26 +11,14 @@ using Stripe; using Stripe.Forwarding; using System.Globalization; using System.Security.Policy; +using SumaTube.Crosscutting.Logging.Configuration; var builder = WebApplication.CreateBuilder(args); -//var credentials = new BasicAuthCredentials("http://192.168.0.82:3100"); -//var credentials = new LogCredentials("http://192.168.0.82:3100"); - -Log.Logger = new LoggerConfiguration() - .MinimumLevel.Information() - .Enrich.FromLogContext() - .Enrich.WithProperty("app", "blinks") - .WriteTo.Console() - .WriteTo.File("logs/log.txt", rollingInterval: RollingInterval.Day) - .WriteTo.GrafanaLoki( - uri: "http://192.168.0.82:3100", - propertiesAsLabels: new List { "app", "blinks" }, - restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Debug - ) - .CreateLogger(); - -builder.Host.UseSerilog(); +builder.Host.UseSerilog((context, services, configuration) => +{ + builder.SetLoggerConfiguration(configuration, services, context.Configuration); +}); // Add services to the container. builder.Services.AddControllersWithViews(); @@ -86,21 +74,29 @@ builder.Services.Configure(options => StripeConfiguration.ApiKey = builder.Configuration["Stripe:SecretKey"]; builder.Services.AddControllersWithViews(); builder.Services.AddHttpClient(); -builder.Services.AddSerilog(); var app = builder.Build(); +app.UseSerilogRequestLogging(options => +{ + options.EnrichDiagnosticContext = (diagnosticContext, httpContext) => + { + diagnosticContext.Set("UserAgent", httpContext.Request.Headers["User-Agent"]); + diagnosticContext.Set("ClientIP", httpContext.Connection.RemoteIpAddress); + diagnosticContext.Set("UserName", httpContext.User?.Identity?.Name ?? "Anonymous"); + }; +}); + var locOptions = app.Services.GetService>(); app.UseRequestLocalization(locOptions.Value); app.UseMiddleware(); // Configure the HTTP request pipeline. -if (!app.Environment.IsDevelopment()) +if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseExceptionHandler("/Home/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } @@ -116,8 +112,11 @@ app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); -app.UseSerilogRequestLogging(); app.UseRequestLocalization(); +Log.Information("Aplicação iniciando"); +Log.Warning("Este é um aviso de teste"); +Log.Error("Este é um erro de teste para verificar o Seq"); + app.Run(); diff --git a/SumaTube/Resource.Designer.cs b/SumaTube/Resource.Designer.cs index f184f70..0f0d633 100644 --- a/SumaTube/Resource.Designer.cs +++ b/SumaTube/Resource.Designer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -namespace Blinks { +namespace SumaTube { using System; @@ -39,7 +39,7 @@ namespace Blinks { public static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Blinks.Resource", typeof(Resource).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SumaTube.Resource", typeof(Resource).Assembly); resourceMan = temp; } return resourceMan; diff --git a/SumaTube/Resource.pt-BR.Designer.cs b/SumaTube/Resource.pt-BR.Designer.cs index f5d60b4..7a7d1ab 100644 --- a/SumaTube/Resource.pt-BR.Designer.cs +++ b/SumaTube/Resource.pt-BR.Designer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -namespace Blinks { +namespace SumaTube { using System; diff --git a/SumaTube/SumaTube.csproj b/SumaTube/SumaTube.csproj index 85fe4e3..62bd7f8 100644 --- a/SumaTube/SumaTube.csproj +++ b/SumaTube/SumaTube.csproj @@ -12,11 +12,16 @@ - - + + + + + + + @@ -25,6 +30,10 @@ + + + + True diff --git a/SumaTube/Views/Shared/_Layout.cshtml b/SumaTube/Views/Shared/_Layout.cshtml index af6b613..ed0cc58 100644 --- a/SumaTube/Views/Shared/_Layout.cshtml +++ b/SumaTube/Views/Shared/_Layout.cshtml @@ -5,7 +5,7 @@ - @ViewData["Title"] - Blinks + @ViewData["Title"] - SumaTube @@ -80,7 +80,7 @@ diff --git a/SumaTube/Views/SignIn/Index.cshtml b/SumaTube/Views/SignIn/Index.cshtml index e411335..15f5ae5 100644 --- a/SumaTube/Views/SignIn/Index.cshtml +++ b/SumaTube/Views/SignIn/Index.cshtml @@ -11,7 +11,7 @@ - Blinks + SumaTube diff --git a/SumaTube/Views/Startup/Index.cshtml b/SumaTube/Views/Startup/Index.cshtml index 2f45d70..805649c 100644 --- a/SumaTube/Views/Startup/Index.cshtml +++ b/SumaTube/Views/Startup/Index.cshtml @@ -1,4 +1,4 @@ -@using Blinks +@using SumaTube @* For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 diff --git a/SumaTube/Views/_ViewImports.cshtml b/SumaTube/Views/_ViewImports.cshtml index d65f1e1..20588fc 100644 --- a/SumaTube/Views/_ViewImports.cshtml +++ b/SumaTube/Views/_ViewImports.cshtml @@ -1,3 +1,3 @@ -@using Blinks -@using Blinks.Models +@using SumaTube +@using SumaTube.Models @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/SumaTube/appsettings.Development.json b/SumaTube/appsettings.Development.json index 0c208ae..f6a545b 100644 --- a/SumaTube/appsettings.Development.json +++ b/SumaTube/appsettings.Development.json @@ -1,8 +1,28 @@ { - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Serilog": { + "WriteTo": [ + { "Name": "Console" }, + { + "Name": "File", + "Args": { + "path": "logs/dev-app-.log", + "rollingInterval": "Day" + } + }, + { + "Name": "Seq", + "Args": { + "serverUrl": "http://192.168.0.76:5341", + "compact": true, + "batchPostingLimit": 100 + } + } + ], + "Properties": { + "Environment": "Development", + "Workspace": "Dev", + "Application": "SumaTube" } } } + diff --git a/SumaTube/appsettings.Production.json b/SumaTube/appsettings.Production.json new file mode 100644 index 0000000..57c80ee --- /dev/null +++ b/SumaTube/appsettings.Production.json @@ -0,0 +1,33 @@ +{ + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "Microsoft": "Warning", + "System": "Error" // Note que em produção aumentamos o nível de logs do sistema + } + }, + "WriteTo": [ + { + "Name": "File", + "Args": { + "path": "logs/prod-app-.log", + "rollingInterval": "Day" + } + }, + { + "Name": "Seq", + "Args": { + "serverUrl": "http://logs-ingest.carneiro.ddnsfree.com", + "compact": true, + "batchPostingLimit": 100 + } + } + ], + "Properties": { + "Environment": "Production", + "Workspace": "Prod", + "Application": "SumaTube" + } + } +} \ No newline at end of file diff --git a/SumaTube/appsettings.json b/SumaTube/appsettings.json index 61310e6..baefd4e 100644 --- a/SumaTube/appsettings.json +++ b/SumaTube/appsettings.json @@ -1,8 +1,20 @@ { - "Logging": { - "LogLevel": { + "Serilog": { + "MinimumLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Override": { + "Microsoft": "Warning", + "System": "Warning" + } + }, + "Enrich": [ + "FromLogContext", + "WithMachineName", + "WithThreadId", + "WithEnvironmentUserName" + ], + "Properties": { + "Application": "SumaTube" } }, "AllowedHosts": "*",