Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AIChatBot.API/AIChatBot.API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Google.Cloud.Firestore" Version="3.8.0" />
<PackageReference Include="HtmlAgilityPack.NetCore" Version="1.5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
Expand Down
152 changes: 152 additions & 0 deletions AIChatBot.API/DataContext/Firestore/AgentFileFirestoreDataContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
using AIChatBot.API.DataContext.Firestore;
using AIChatBot.API.Interfaces.DataContext;
using AIChatBot.API.Models.Base;
using AIChatBot.API.Models.Entities;
using AIChatBot.API.Models.Firestore;
using Google.Cloud.Firestore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace AIChatBot.API.DataContext.Firestore
{
public class AgentFileFirestoreDataContext : BaseFirestoreRepository, IAgentFileDataContext
{
private const string COLLECTION_NAME = "agentFiles";

public AgentFileFirestoreDataContext(FirestoreDb firestoreDb, ILogger<AgentFileFirestoreDataContext> logger, IOptions<FirestoreSettings> settings)
: base(firestoreDb, logger, settings)
{
}

public async Task<AgentFile> CreateFileAsync(string fileName, string filePath, string downloadUrl, long fileSize, Guid userId, int chatSessionId)
{
try
{
var agentFile = new AgentFile
{
FileName = fileName,
FilePath = filePath,
DownloadUrl = downloadUrl,
FileSize = fileSize,
UserId = userId,
ChatSessionId = chatSessionId,
CreatedAt = DateTime.UtcNow
};

var fileDoc = AgentFileDocument.FromEntity(agentFile);

// Add document and get the auto-generated ID
var docRef = await _firestoreDb.Collection(COLLECTION_NAME).AddAsync(fileDoc);

// Update the document with the auto-generated ID as the file ID
agentFile.Id = int.Parse(docRef.Id);
fileDoc.Id = agentFile.Id;
await docRef.SetAsync(fileDoc);

_logger.LogInformation("Created agent file {FileId} for session {SessionId}", agentFile.Id, chatSessionId);
return agentFile;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error creating agent file for session {SessionId}", chatSessionId);
throw;
}
}

public async Task<List<AgentFile>> GetFilesBySessionAsync(int chatSessionId, Guid userId)
{
try
{
var query = _firestoreDb.Collection(COLLECTION_NAME)
.WhereEqualTo("chatSessionId", chatSessionId)
.WhereEqualTo("userId", userId.ToString())
.OrderByDescending("createdAt");

var snapshot = await query.GetSnapshotAsync();
var files = snapshot.Documents
.Select(doc => doc.ConvertTo<AgentFileDocument>().ToEntity())
.ToList();

_logger.LogInformation("Retrieved {Count} files for session {SessionId}", files.Count, chatSessionId);
return files;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting files for session {SessionId}", chatSessionId);
throw;
}
}

public async Task<AgentFile?> GetFileByIdAsync(int fileId)
{
try
{
var query = _firestoreDb.Collection(COLLECTION_NAME).WhereEqualTo("id", fileId);
var snapshot = await query.GetSnapshotAsync();

if (!snapshot.Documents.Any())
{
_logger.LogWarning("Agent file with ID {FileId} not found", fileId);
return null;
}

var fileDoc = snapshot.Documents.First().ConvertTo<AgentFileDocument>();
return fileDoc.ToEntity();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting file by ID {FileId}", fileId);
throw;
}
}

public async Task<List<AgentFile>> GetFilesByUserAsync(Guid userId)
{
try
{
var query = _firestoreDb.Collection(COLLECTION_NAME)
.WhereEqualTo("userId", userId.ToString())
.OrderByDescending("createdAt");

var snapshot = await query.GetSnapshotAsync();
var files = snapshot.Documents
.Select(doc => doc.ConvertTo<AgentFileDocument>().ToEntity())
.ToList();

_logger.LogInformation("Retrieved {Count} files for user {UserId}", files.Count, userId);
return files;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting files for user {UserId}", userId);
throw;
}
}

public async Task UpdateFileAsync(AgentFile agentFile)
{
try
{
var fileDoc = AgentFileDocument.FromEntity(agentFile);
var query = _firestoreDb.Collection(COLLECTION_NAME).WhereEqualTo("id", agentFile.Id);
var snapshot = await query.GetSnapshotAsync();

if (!snapshot.Documents.Any())
{
_logger.LogWarning("Agent file with ID {FileId} not found for update", agentFile.Id);
return;
}

var doc = snapshot.Documents.First();
await doc.Reference.SetAsync(fileDoc);

_logger.LogInformation("Updated agent file {FileId}", agentFile.Id);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error updating agent file {FileId}", agentFile.Id);
throw;
}
}
}
}
138 changes: 138 additions & 0 deletions AIChatBot.API/DataContext/Firestore/BaseFirestoreRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
using Google.Cloud.Firestore;
using Microsoft.Extensions.Options;
using AIChatBot.API.Models.Base;
using Microsoft.Extensions.Logging;

namespace AIChatBot.API.DataContext.Firestore
{
public abstract class BaseFirestoreRepository
{
protected readonly FirestoreDb _firestoreDb;
protected readonly ILogger _logger;
protected readonly FirestoreSettings _settings;

protected BaseFirestoreRepository(FirestoreDb firestoreDb, ILogger logger, IOptions<FirestoreSettings> settings)
{
_firestoreDb = firestoreDb;
_logger = logger;
_settings = settings.Value;
}

protected async Task<T?> GetDocumentAsync<T>(string collectionName, string documentId) where T : class
{
try
{
var docRef = _firestoreDb.Collection(collectionName).Document(documentId);
var snapshot = await docRef.GetSnapshotAsync();

if (!snapshot.Exists)
{
_logger.LogWarning("Document {DocumentId} not found in collection {CollectionName}", documentId, collectionName);
return null;
}

return snapshot.ConvertTo<T>();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting document {DocumentId} from collection {CollectionName}", documentId, collectionName);
throw;
}
}

protected async Task<List<T>> GetCollectionAsync<T>(string collectionName) where T : class
{
try
{
var collection = _firestoreDb.Collection(collectionName);
var snapshot = await collection.GetSnapshotAsync();

return snapshot.Documents.Select(doc => doc.ConvertTo<T>()).ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting collection {CollectionName}", collectionName);
throw;
}
}

protected async Task<List<T>> QueryCollectionAsync<T>(string collectionName, Query query) where T : class
{
try
{
var snapshot = await query.GetSnapshotAsync();
return snapshot.Documents.Select(doc => doc.ConvertTo<T>()).ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error querying collection {CollectionName}", collectionName);
throw;
}
}

protected async Task<string> AddDocumentAsync<T>(string collectionName, T document) where T : class
{
try
{
var collection = _firestoreDb.Collection(collectionName);
var docRef = await collection.AddAsync(document);

_logger.LogInformation("Document added to collection {CollectionName} with ID {DocumentId}", collectionName, docRef.Id);
return docRef.Id;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error adding document to collection {CollectionName}", collectionName);
throw;
}
}

protected async Task SetDocumentAsync<T>(string collectionName, string documentId, T document) where T : class
{
try
{
var docRef = _firestoreDb.Collection(collectionName).Document(documentId);
await docRef.SetAsync(document);

_logger.LogInformation("Document {DocumentId} set in collection {CollectionName}", documentId, collectionName);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error setting document {DocumentId} in collection {CollectionName}", documentId, collectionName);
throw;
}
}

protected async Task UpdateDocumentAsync(string collectionName, string documentId, Dictionary<string, object> updates)
{
try
{
var docRef = _firestoreDb.Collection(collectionName).Document(documentId);
await docRef.UpdateAsync(updates);

_logger.LogInformation("Document {DocumentId} updated in collection {CollectionName}", documentId, collectionName);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error updating document {DocumentId} in collection {CollectionName}", documentId, collectionName);
throw;
}
}

protected async Task DeleteDocumentAsync(string collectionName, string documentId)
{
try
{
var docRef = _firestoreDb.Collection(collectionName).Document(documentId);
await docRef.DeleteAsync();

_logger.LogInformation("Document {DocumentId} deleted from collection {CollectionName}", documentId, collectionName);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting document {DocumentId} from collection {CollectionName}", documentId, collectionName);
throw;
}
}
}
}
Loading