diff --git a/Postall.Domain/Contracts/Repositories/IUserSocialRepository.cs b/Postall.Domain/Contracts/Repositories/IUserSocialRepository.cs new file mode 100644 index 0000000..1387ea1 --- /dev/null +++ b/Postall.Domain/Contracts/Repositories/IUserSocialRepository.cs @@ -0,0 +1,70 @@ +using MongoDB.Driver; +using Postall.Domain.Entities; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Postall.Domain +{ + public interface IUserSocialRepository + { + /// + /// Obtém todos os dados sociais dos usuários + /// + Task> GetAllAsync(); + + /// + /// Obtém os dados sociais pelo ID do MongoDB + /// + Task GetByIdAsync(string id); + + /// + /// Obtém os dados sociais pelo ID do usuário + /// + Task GetByUserIdAsync(string userId); + + /// + /// Obtém os dados sociais pelo token do Google + /// + Task GetByGoogleTokenAsync(string googleToken); + + /// + /// Adiciona novos dados sociais de usuário + /// + Task AddAsync(UserSocialData userSocialData); + + /// + /// Atualiza os dados sociais de um usuário existente + /// + Task UpdateAsync(UserSocialData userSocialData); + + /// + /// Atualiza ou insere os dados sociais de um usuário + /// + Task UpsertAsync(UserSocialData userSocialData); + + /// + /// Atualiza ou insere os dados sociais de um usuário unico pelo id + /// + Task UpdateOneAsync(string userId, UpdateDefinition update); + + /// + /// Remove os dados sociais pelo ID do MongoDB + /// + Task DeleteAsync(string id); + + /// + /// Remove os dados sociais pelo ID do usuário + /// + Task DeleteByUserIdAsync(string userId); + + /// + /// Atualiza apenas o token do Google para um usuário + /// + Task UpdateGoogleTokenAsync(string userId, string googleToken); + + /// + /// Atualiza apenas o token do Facebook para um usuário + /// + Task UpdateFacebookTokenAsync(string userId, FacebookToken facebookToken); + } +} \ No newline at end of file diff --git a/Postall.Infra.MongoDB/Extensions/ServiceRepositoryExtensions.cs b/Postall.Infra.MongoDB/Extensions/ServiceRepositoryExtensions.cs index 33368e1..cf53106 100644 --- a/Postall.Infra.MongoDB/Extensions/ServiceRepositoryExtensions.cs +++ b/Postall.Infra.MongoDB/Extensions/ServiceRepositoryExtensions.cs @@ -18,6 +18,7 @@ namespace Postall.Infra.MongoDB.Extensions { services.AddScoped(); services.AddScoped(); + services.AddScoped(); return services; } diff --git a/Postall.Infra.MongoDB/Repositories/UserSocialRepository.cs b/Postall.Infra.MongoDB/Repositories/UserSocialRepository.cs new file mode 100644 index 0000000..2ad68fc --- /dev/null +++ b/Postall.Infra.MongoDB/Repositories/UserSocialRepository.cs @@ -0,0 +1,210 @@ +using Microsoft.Extensions.Options; +using MongoDB.Bson; +using MongoDB.Driver; +using Postall.Domain; +using Postall.Domain.Entities; +using Postall.Infra.MongoDB.Settings; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Postall.Infra.MongoDB.Repositories +{ + public class UserSocialRepository : IUserSocialRepository + { + private readonly IMongoCollection _userSocialCollection; + + public UserSocialRepository(IOptions mongoDbSettings) + { + var client = new MongoClient(mongoDbSettings.Value.ConnectionString); + var database = client.GetDatabase(mongoDbSettings.Value.DatabaseName); + _userSocialCollection = database.GetCollection(mongoDbSettings.Value.UserSocialCollectionName); + + // Cria índice para userId (deve ser único) + var indexKeysDefinition = Builders.IndexKeys + .Ascending(u => u.UserId); + _userSocialCollection.Indexes.CreateOne(new CreateIndexModel(indexKeysDefinition, new CreateIndexOptions { Unique = true })); + } + + /// + /// Obtém todos os dados sociais dos usuários + /// + public async Task> GetAllAsync() + { + return await _userSocialCollection.Find(u => true).ToListAsync(); + } + + /// + /// Obtém os dados sociais pelo ID do MongoDB + /// + public async Task GetByIdAsync(string id) + { + if (!ObjectId.TryParse(id, out _)) + return null; + + return await _userSocialCollection.Find(u => u.Id == ObjectId.Parse(id)).FirstOrDefaultAsync(); + } + + /// + /// Obtém os dados sociais pelo ID do usuário + /// + public async Task GetByUserIdAsync(string userId) + { + return await _userSocialCollection.Find(u => u.UserId == userId).FirstOrDefaultAsync(); + } + + /// + /// Obtém os dados sociais pelo token do Google + /// + public async Task GetByGoogleTokenAsync(string googleToken) + { + return await _userSocialCollection.Find(u => u.GoogleToken == googleToken).FirstOrDefaultAsync(); + } + + /// + /// Adiciona novos dados sociais de usuário + /// + public async Task AddAsync(UserSocialData userSocialData) + { + var existingUserSocial = await GetByUserIdAsync(userSocialData.UserId); + if (existingUserSocial != null) + return existingUserSocial; + + if (userSocialData.Id == ObjectId.Empty) + { + userSocialData.Id = ObjectId.GenerateNewId(); + } + + try + { + await _userSocialCollection.InsertOneAsync(userSocialData); + } + catch (MongoWriteException ex) + { + if (ex.WriteError.Category == ServerErrorCategory.DuplicateKey) + { + return await GetByUserIdAsync(userSocialData.UserId); + } + else + { + throw; + } + } + return userSocialData; + } + + /// + /// Atualiza os dados sociais de um usuário existente + /// + public async Task UpdateAsync(UserSocialData userSocialData) + { + if (userSocialData.Id == ObjectId.Empty) + return false; + + var result = await _userSocialCollection.ReplaceOneAsync( + u => u.Id == userSocialData.Id, + userSocialData, + new ReplaceOptions { IsUpsert = false }); + + return result.IsAcknowledged && result.ModifiedCount > 0; + } + + /// + /// Atualiza os dados sociais de um usuário existente + /// + public async Task UpdateOneAsync(UserSocialData userSocialData) + { + if (userSocialData.Id == ObjectId.Empty) + return false; + + var result = await _userSocialCollection.ReplaceOneAsync( + u => u.Id == userSocialData.Id, + userSocialData, + new ReplaceOptions { IsUpsert = false }); + + return result.IsAcknowledged && result.ModifiedCount > 0; + } + + /// + /// Atualiza ou insere os dados sociais de um usuário + /// + public async Task UpsertAsync(UserSocialData userSocialData) + { + var existingData = await GetByUserIdAsync(userSocialData.UserId); + + if (existingData != null) + { + userSocialData.Id = existingData.Id; + await _userSocialCollection.ReplaceOneAsync( + u => u.Id == existingData.Id, + userSocialData, + new ReplaceOptions { IsUpsert = true }); + return userSocialData; + } + else + { + return await AddAsync(userSocialData); + } + } + + /// + /// Remove os dados sociais pelo ID do MongoDB + /// + public async Task DeleteAsync(string id) + { + if (!ObjectId.TryParse(id, out _)) + return false; + + var result = await _userSocialCollection.DeleteOneAsync(u => u.Id == ObjectId.Parse(id)); + return result.IsAcknowledged && result.DeletedCount > 0; + } + + /// + /// Remove os dados sociais pelo ID do usuário + /// + public async Task DeleteByUserIdAsync(string userId) + { + var result = await _userSocialCollection.DeleteOneAsync(u => u.UserId == userId); + return result.IsAcknowledged && result.DeletedCount > 0; + } + + /// + /// Atualiza apenas o token do Google para um usuário + /// + public async Task UpdateGoogleTokenAsync(string userId, string googleToken) + { + var update = Builders.Update.Set(u => u.GoogleToken, googleToken); + var result = await _userSocialCollection.UpdateOneAsync( + u => u.UserId == userId, + update, + new UpdateOptions { IsUpsert = true }); + + return result.IsAcknowledged && (result.ModifiedCount > 0 || result.UpsertedId != null); + } + + /// + /// Atualiza apenas o token do Facebook para um usuário + /// + public async Task UpdateFacebookTokenAsync(string userId, FacebookToken facebookToken) + { + var update = Builders.Update.Set(u => u.FacebookToken, facebookToken); + var result = await _userSocialCollection.UpdateOneAsync( + u => u.UserId == userId, + update, + new UpdateOptions { IsUpsert = true }); + + return result.IsAcknowledged && (result.ModifiedCount > 0 || result.UpsertedId != null); + } + + public async Task UpdateOneAsync(string userId, UpdateDefinition update) + { + var result = await _userSocialCollection.UpdateOneAsync( + x => x.UserId == userId, + update, + new UpdateOptions { IsUpsert = true }); + + return result.IsAcknowledged && (result.ModifiedCount > 0 || result.UpsertedId != null); + } + } +} \ No newline at end of file diff --git a/Postall.Infra.MongoDB/Settings/MongoDbSetting.cs b/Postall.Infra.MongoDB/Settings/MongoDbSetting.cs index aaf4efe..a350cc5 100644 --- a/Postall.Infra.MongoDB/Settings/MongoDbSetting.cs +++ b/Postall.Infra.MongoDB/Settings/MongoDbSetting.cs @@ -15,5 +15,6 @@ namespace Postall.Infra.MongoDB.Settings public string DatabaseName { get; set; } public string ChannelsCollectionName { get; set; } public string VideosCollectionName { get; set; } + public string UserSocialCollectionName { get; internal set; } } } diff --git a/Postall.Infra/Services/FacebookTokenService.cs b/Postall.Infra/Services/FacebookTokenService.cs index 19e110c..dd3aca3 100644 --- a/Postall.Infra/Services/FacebookTokenService.cs +++ b/Postall.Infra/Services/FacebookTokenService.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Configuration; using MongoDB.Driver; +using Postall.Domain; using Postall.Domain.Dtos.Responses; using Postall.Domain.Entities; using Postall.Domain.Services.Contracts; @@ -14,14 +15,14 @@ namespace Postall.Infra.Services { public class FacebookTokenService: IFacebookServices { - private readonly IMongoCollection _tokens; private readonly IConfiguration _config; + private readonly IUserSocialRepository _userSocialRepository; private readonly HttpClient _httpClient; - public FacebookTokenService(IConfiguration configuration, IMongoCollection tokens, IHttpClientFactory httpClientFactory) + public FacebookTokenService(IConfiguration configuration, IHttpClientFactory httpClientFactory, IUserSocialRepository userSocialRepository) { _config = configuration; - _tokens = tokens; + this._userSocialRepository = userSocialRepository; _httpClient = httpClientFactory.CreateClient("Facebook"); } @@ -46,11 +47,21 @@ namespace Postall.Infra.Services .Set(x => x.FacebookToken.AccessToken, token) .Set(x => x.FacebookToken.ExpiresAt, DateTime.UtcNow.AddDays(60)); - await _tokens.UpdateOneAsync( - x => x.UserId == userId, - update, - new UpdateOptions { IsUpsert = true } + if (_userSocialRepository.GetByIdAsync(userId) == null) + { + await _userSocialRepository.AddAsync(new UserSocialData() { UserId = Guid.NewGuid().ToString("N")}); + return; + } + + await _userSocialRepository.UpdateOneAsync( + userId, + update ); } + + private async Task UpdateOneAsync(Func value, UpdateDefinition update, UpdateOptions updateOptions) + { + throw new NotImplementedException(); + } } } diff --git a/Postall/Postall.csproj b/Postall/Postall.csproj index 68388a3..c9f7187 100644 --- a/Postall/Postall.csproj +++ b/Postall/Postall.csproj @@ -9,13 +9,6 @@ . - - - - - - - diff --git a/Postall/appsettings.Development.json b/Postall/appsettings.Development.json index 9a2632a..81baff0 100644 --- a/Postall/appsettings.Development.json +++ b/Postall/appsettings.Development.json @@ -8,6 +8,8 @@ "MongoDbSettings": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "YouTubeChannelsDB", - "ChannelsCollectionName": "Channels" + "ChannelsCollectionName": "Channels", + "VideosCollectionName": "Videos", + "UserSocialCollectionName": "UserSocial" } } diff --git a/Postall/appsettings.json b/Postall/appsettings.json index 4f3fe48..8d5c148 100644 --- a/Postall/appsettings.json +++ b/Postall/appsettings.json @@ -29,6 +29,7 @@ "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "YouTubeChannelsDB", "ChannelsCollectionName": "Channels", - "VideosCollectionName": "Videos" + "VideosCollectionName": "Videos", + "UserSocialCollectionName": "UserSocial" } } \ No newline at end of file