changes mongo camera report

This commit is contained in:
2025-12-12 19:42:08 +03:30
parent ea896c4c11
commit eb49bf771d
11 changed files with 459 additions and 114 deletions

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using _0_Framework.Domain;
using MongoDB.Bson.Serialization.Attributes;
namespace Company.Domain.CameraBugReportAgg;
@@ -9,8 +10,13 @@ namespace Company.Domain.CameraBugReportAgg;
/// </summary>
public class CameraBugReport : EntityBase
{
[BsonId]
[BsonRepresentation(MongoDB.Bson.BsonType.String)]
public new string Id { get; set; }
public CameraBugReport()
{
Id = Guid.NewGuid().ToString();
CreationDate = DateTime.Now;
Status = CameraBugReportStatus.Open;
Screenshots = new List<CameraBugReportScreenshot>();
@@ -70,35 +76,91 @@ public class CameraBugReport : EntityBase
StackTrace = stackTrace;
}
[BsonElement("screenshots")]
public List<CameraBugReportScreenshot> Screenshots { get; private set; }
[BsonElement("logs")]
public List<CameraBugReportLog> Logs { get; private set; }
[BsonElement("updateDate")]
public DateTime? UpdateDate { get; private set; }
[BsonElement("creationDate")]
public DateTime CreationDate { get; private set; }
[BsonElement("stackTrace")]
public string StackTrace { get; private set; }
[BsonElement("status")]
public CameraBugReportStatus Status { get; private set; }
[BsonElement("priority")]
public CameraBugPriority Priority { get; private set; }
[BsonElement("type")]
public CameraBugReportType Type { get; private set; }
[BsonElement("flavor")]
public string Flavor { get; private set; }
[BsonElement("lastUpdateTime")]
public DateTime LastUpdateTime { get; private set; }
[BsonElement("installTime")]
public DateTime InstallTime { get; private set; }
[BsonElement("packageName")]
public string PackageName { get; private set; }
[BsonElement("buildNumber")]
public string BuildNumber { get; private set; }
[BsonElement("appVersion")]
public string AppVersion { get; private set; }
[BsonElement("networkType")]
public string NetworkType { get; private set; }
[BsonElement("isCharging")]
public bool IsCharging { get; private set; }
[BsonElement("batteryLevel")]
public int BatteryLevel { get; private set; }
[BsonElement("storageInMB")]
public int StorageInMB { get; private set; }
[BsonElement("memoryInMB")]
public int MemoryInMB { get; private set; }
[BsonElement("screenResolution")]
public string ScreenResolution { get; private set; }
[BsonElement("deviceId")]
public string DeviceId { get; private set; }
[BsonElement("manufacturer")]
public string Manufacturer { get; private set; }
[BsonElement("platform")]
public string Platform { get; private set; }
[BsonElement("osVersion")]
public string OsVersion { get; private set; }
[BsonElement("deviceModel")]
public string DeviceModel { get; private set; }
[BsonElement("accountId")]
public long? AccountId { get; private set; }
[BsonElement("userEmail")]
public string UserEmail { get; private set; }
[BsonElement("description")]
public string Description { get; private set; }
[BsonElement("title")]
public string Title { get; private set; }
public void ChangeStatus(CameraBugReportStatus newStatus)

View File

@@ -1,5 +1,6 @@
using System;
using _0_Framework.Domain;
using MongoDB.Bson.Serialization.Attributes;
namespace Company.Domain.CameraBugReportAgg
{
@@ -8,9 +9,11 @@ namespace Company.Domain.CameraBugReportAgg
/// </summary>
public class CameraBugReportLog : EntityBase
{
public long CameraBugReportId { get; set; }
public CameraBugReport CameraBugReport { get; set; }
// FK و navigation property حذف شد برای MongoDB
[BsonElement("message")]
public string Message { get; set; }
[BsonElement("timestamp")]
public DateTime Timestamp { get; set; }
}
}

View File

@@ -1,5 +1,6 @@
using System;
using _0_Framework.Domain;
using MongoDB.Bson.Serialization.Attributes;
namespace Company.Domain.CameraBugReportAgg
{
@@ -8,10 +9,14 @@ namespace Company.Domain.CameraBugReportAgg
/// </summary>
public class CameraBugReportScreenshot : EntityBase
{
public long CameraBugReportId { get; set; }
public CameraBugReport CameraBugReport { get; set; }
// FK و navigation property حذف شد برای MongoDB
[BsonElement("base64Data")]
public string Base64Data { get; set; }
[BsonElement("fileName")]
public string FileName { get; set; }
[BsonElement("uploadDate")]
public DateTime UploadDate { get; set; }
}
}

View File

@@ -1,13 +1,33 @@
using System.Collections.Generic;
using System.Linq;
using _0_Framework_b.Domain;
using System.Threading.Tasks;
using _0_Framework.InfraStructure;
namespace Company.Domain.CameraBugReportAgg;
// Custom methods can be added here if needed
/// <summary>
/// رابط انبار گزارش خرابی دوربین برای MongoDB
/// </summary>
public interface ICameraBugReportRepository : IRepository<long, CameraBugReport>
{
void Remove(CameraBugReport bugReport);
IQueryable<CameraBugReport> GetAllAsNoTracking();
bool IsExist(long id);
// Async methods for MongoDB operations
Task CreateAsync(CameraBugReport bugReport);
Task UpdateAsync(CameraBugReport bugReport);
Task<CameraBugReport> GetByIdAsync(string id);
Task<List<CameraBugReport>> GetAllAsync();
Task<List<CameraBugReport>> GetAllAsync(int skip, int take);
Task DeleteAsync(string id);
Task<bool> IsExistAsync(string id);
Task<List<CameraBugReport>> FilterAsync(
CameraBugReportType? type = null,
CameraBugPriority? priority = null,
CameraBugReportStatus? status = null,
string searchTerm = null,
int skip = 0,
int take = 10);
Task<int> CountAsync(
CameraBugReportType? type = null,
CameraBugPriority? priority = null,
CameraBugReportStatus? status = null,
string searchTerm = null);
}

View File

@@ -0,0 +1,176 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Company.Domain.CameraBugReportAgg;
using MongoDB.Bson;
using MongoDB.Driver;
namespace CompanyManagement.Infrastructure.Mongo.CameraBugReportRepo;
/// <summary>
/// پیاده‌سازی انبار گزارش خرابی دوربین برای MongoDB
/// </summary>
public class CameraBugReportRepository : ICameraBugReportRepository
{
private readonly IMongoCollection<CameraBugReport> _cameraBugReports;
public CameraBugReportRepository(IMongoDatabase database)
{
_cameraBugReports = database.GetCollection<CameraBugReport>("CameraBugReports");
}
public async Task CreateAsync(CameraBugReport bugReport)
{
await _cameraBugReports.InsertOneAsync(bugReport);
}
public async Task UpdateAsync(CameraBugReport bugReport)
{
await _cameraBugReports.ReplaceOneAsync(
x => x.Id == bugReport.Id,
bugReport);
}
public async Task<CameraBugReport> GetByIdAsync(string id)
{
return await _cameraBugReports
.Find(x => x.Id == id)
.FirstOrDefaultAsync();
}
public async Task<List<CameraBugReport>> GetAllAsync()
{
return await _cameraBugReports
.Find(_ => true)
.ToListAsync();
}
public async Task<List<CameraBugReport>> GetAllAsync(int skip, int take)
{
return await _cameraBugReports
.Find(_ => true)
.Skip(skip)
.Limit(take)
.SortByDescending(x => x.CreationDate)
.ToListAsync();
}
public async Task DeleteAsync(string id)
{
await _cameraBugReports.DeleteOneAsync(x => x.Id == id);
}
public async Task<bool> IsExistAsync(string id)
{
var result = await _cameraBugReports
.Find(x => x.Id == id)
.FirstOrDefaultAsync();
return result != null;
}
public async Task<List<CameraBugReport>> FilterAsync(
CameraBugReportType? type = null,
CameraBugPriority? priority = null,
CameraBugReportStatus? status = null,
string searchTerm = null,
int skip = 0,
int take = 10)
{
var filterDefinition = BuildFilterDefinition(type, priority, status, searchTerm);
return await _cameraBugReports
.Find(filterDefinition)
.Skip(skip)
.Limit(take)
.SortByDescending(x => x.CreationDate)
.ToListAsync();
}
public async Task<int> CountAsync(
CameraBugReportType? type = null,
CameraBugPriority? priority = null,
CameraBugReportStatus? status = null,
string searchTerm = null)
{
var filterDefinition = BuildFilterDefinition(type, priority, status, searchTerm);
var count = await _cameraBugReports.CountDocumentsAsync(filterDefinition);
return (int)count;
}
private FilterDefinition<CameraBugReport> BuildFilterDefinition(
CameraBugReportType? type = null,
CameraBugPriority? priority = null,
CameraBugReportStatus? status = null,
string searchTerm = null)
{
var filters = new List<FilterDefinition<CameraBugReport>>();
if (type.HasValue)
filters.Add(Builders<CameraBugReport>.Filter.Eq(x => x.Type, type.Value));
if (priority.HasValue)
filters.Add(Builders<CameraBugReport>.Filter.Eq(x => x.Priority, priority.Value));
if (status.HasValue)
filters.Add(Builders<CameraBugReport>.Filter.Eq(x => x.Status, status.Value));
if (!string.IsNullOrEmpty(searchTerm))
{
var searchFilter = Builders<CameraBugReport>.Filter.Or(
Builders<CameraBugReport>.Filter.Regex(x => x.Title, new BsonRegularExpression(searchTerm, "i")),
Builders<CameraBugReport>.Filter.Regex(x => x.Description, new BsonRegularExpression(searchTerm, "i")),
Builders<CameraBugReport>.Filter.Regex(x => x.UserEmail, new BsonRegularExpression(searchTerm, "i"))
);
filters.Add(searchFilter);
}
if (filters.Count == 0)
return Builders<CameraBugReport>.Filter.Empty;
return Builders<CameraBugReport>.Filter.And(filters);
}
// Sync methods from IRepository interface (not used in MongoDB flow but required for interface implementation)
public CameraBugReport Get(long id)
{
throw new NotImplementedException("استفاده از GetByIdAsync برای MongoDB");
}
public List<CameraBugReport> Get()
{
throw new NotImplementedException("استفاده از GetAllAsync برای MongoDB");
}
public void Create(CameraBugReport entity)
{
throw new NotImplementedException("استفاده از CreateAsync برای MongoDB");
}
public bool ExistsIgnoreQueryFilter(System.Linq.Expressions.Expression<Func<CameraBugReport, bool>> expression)
{
throw new NotImplementedException("استفاده از IsExistAsync برای MongoDB");
}
public bool Exists(System.Linq.Expressions.Expression<Func<CameraBugReport, bool>> expression)
{
throw new NotImplementedException("استفاده از FilterAsync برای MongoDB");
}
public void SaveChanges()
{
throw new NotImplementedException("MongoDB نیازی به SaveChanges ندارد");
}
public async Task SaveChangesAsync()
{
// MongoDB خودکار ذخیره می‌کند، بنابراین این متد خالی است
await Task.CompletedTask;
}
public Task<Microsoft.EntityFrameworkCore.Storage.IDbContextTransaction> BeginTransactionAsync()
{
throw new NotImplementedException("MongoDB اعاملات را بصورت متفاوت مدیریت می‌کند");
}
}

View File

@@ -5,7 +5,7 @@ namespace CompanyManagment.App.Contracts.CameraBugReport
{
public class CameraBugReportDetailViewModel
{
public long Id { get; set; }
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string UserEmail { get; set; }
@@ -39,7 +39,6 @@ namespace CompanyManagment.App.Contracts.CameraBugReport
public class CameraBugReportScreenshotViewModel
{
public long Id { get; set; }
public string FileName { get; set; }
public DateTime UploadDate { get; set; }
public string Base64Data { get; set; }

View File

@@ -4,7 +4,7 @@ namespace CompanyManagment.App.Contracts.CameraBugReport
{
public class CameraBugReportViewModel
{
public long Id { get; set; }
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string UserEmail { get; set; }

View File

@@ -3,7 +3,7 @@ namespace CompanyManagment.App.Contracts.CameraBugReport
{
public class EditCameraBugReportCommand
{
public long Id { get; set; }
public string Id { get; set; }
public CameraBugPriority Priority { get; set; }
public CameraBugReportStatus Status { get; set; }
}

View File

@@ -1,10 +1,20 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using _0_Framework.Application;
namespace CompanyManagment.App.Contracts.CameraBugReport
{
public interface ICameraBugReportApplication
{
Task<OperationResult> CreateAsync(CreateCameraBugReportCommand command);
Task<OperationResult> EditAsync(EditCameraBugReportCommand command);
Task<OperationResult> DeleteAsync(string id);
Task<List<CameraBugReportViewModel>> GetAllAsync(CameraBugReportSearchModel searchModel);
Task<CameraBugReportDetailViewModel> GetDetailsAsync(string id);
Task<bool> IsExistAsync(string id);
// Keep sync methods for backward compatibility but they delegate to async
OperationResult Create(CreateCameraBugReportCommand command);
OperationResult Edit(EditCameraBugReportCommand command);
OperationResult Delete(long id);

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using _0_Framework.Application;
using CompanyManagment.App.Contracts.CameraBugReport;
using Company.Domain.CameraBugReportAgg;
@@ -16,7 +17,8 @@ namespace CompanyManagment.Application
_repository = repository;
}
public OperationResult Create(CreateCameraBugReportCommand command)
// ============ Async Methods (MongoDB) ============
public async Task<OperationResult> CreateAsync(CreateCameraBugReportCommand command)
{
var op = new OperationResult();
try
@@ -66,8 +68,8 @@ namespace CompanyManagment.Application
}
}
_repository.Create(bugReport);
_repository.SaveChanges();
await _repository.CreateAsync(bugReport);
await _repository.SaveChangesAsync();
return op.Succcedded();
}
@@ -77,19 +79,20 @@ namespace CompanyManagment.Application
}
}
public OperationResult Edit(EditCameraBugReportCommand command)
public async Task<OperationResult> EditAsync(EditCameraBugReportCommand command)
{
var op = new OperationResult();
try
{
var bugReport = _repository.Get(command.Id);
var bugReport = await _repository.GetByIdAsync(command.Id.ToString());
if (bugReport == null)
return op.Failed("گزارش خرابی یافت نشد.");
bugReport.ChangePriority(command.Priority);
bugReport.ChangeStatus(command.Status);
_repository.SaveChanges();
await _repository.UpdateAsync(bugReport);
await _repository.SaveChangesAsync();
return op.Succcedded();
}
@@ -99,17 +102,17 @@ namespace CompanyManagment.Application
}
}
public OperationResult Delete(long id)
public async Task<OperationResult> DeleteAsync(string id)
{
var op = new OperationResult();
try
{
var bugReport = _repository.Get(id);
if (bugReport == null)
var exists = await _repository.IsExistAsync(id);
if (!exists)
return op.Failed("گزارش خرابی یافت نشد.");
_repository.Remove(bugReport);
_repository.SaveChanges();
await _repository.DeleteAsync(id);
await _repository.SaveChangesAsync();
return op.Succcedded();
}
@@ -119,108 +122,173 @@ namespace CompanyManagment.Application
}
}
public async Task<List<CameraBugReportViewModel>> GetAllAsync(CameraBugReportSearchModel searchModel)
{
try
{
var skip = (searchModel.PageNumber - 1) * searchModel.PageSize;
var bugReports = await _repository.FilterAsync(
searchModel.Type,
searchModel.Priority,
searchModel.Status,
searchModel.SearchTerm,
skip,
searchModel.PageSize
);
return bugReports.Select(x => new CameraBugReportViewModel
{
Id = x.Id,
Title = x.Title,
Description = x.Description,
UserEmail = x.UserEmail,
AccountId = x.AccountId,
DeviceModel = x.DeviceModel,
AppVersion = x.AppVersion,
Type = x.Type,
Priority = x.Priority,
Status = x.Status,
CreationDate = x.CreationDate,
UpdateDate = x.UpdateDate,
LogsCount = x.Logs?.Count ?? 0,
ScreenshotsCount = x.Screenshots?.Count ?? 0
}).ToList();
}
catch (Exception ex)
{
throw new Exception($"خطا در دریافت لیست گزارش‌ها: {ex.Message}", ex);
}
}
public async Task<CameraBugReportDetailViewModel> GetDetailsAsync(string id)
{
try
{
var bugReport = await _repository.GetByIdAsync(id);
if (bugReport == null)
return null;
return new CameraBugReportDetailViewModel
{
Id = bugReport.Id,
Title = bugReport.Title,
Description = bugReport.Description,
UserEmail = bugReport.UserEmail,
AccountId = bugReport.AccountId,
DeviceModel = bugReport.DeviceModel,
OsVersion = bugReport.OsVersion,
Platform = bugReport.Platform,
Manufacturer = bugReport.Manufacturer,
DeviceId = bugReport.DeviceId,
ScreenResolution = bugReport.ScreenResolution,
MemoryInMB = bugReport.MemoryInMB,
StorageInMB = bugReport.StorageInMB,
BatteryLevel = bugReport.BatteryLevel,
IsCharging = bugReport.IsCharging,
NetworkType = bugReport.NetworkType,
AppVersion = bugReport.AppVersion,
BuildNumber = bugReport.BuildNumber,
PackageName = bugReport.PackageName,
InstallTime = bugReport.InstallTime,
LastUpdateTime = bugReport.LastUpdateTime,
Flavor = bugReport.Flavor,
Type = bugReport.Type,
Priority = bugReport.Priority,
Status = bugReport.Status,
StackTrace = bugReport.StackTrace,
CreationDate = bugReport.CreationDate,
UpdateDate = bugReport.UpdateDate,
Logs = bugReport.Logs?.Select(x => x.Message).ToList() ?? new List<string>(),
Screenshots = bugReport.Screenshots?.Select(x => new CameraBugReportScreenshotViewModel
{
FileName = x.FileName,
UploadDate = x.UploadDate,
Base64Data = x.Base64Data
}).ToList() ?? new List<CameraBugReportScreenshotViewModel>()
};
}
catch (Exception ex)
{
throw new Exception($"خطا در دریافت جزئیات گزارش: {ex.Message}", ex);
}
}
public async Task<bool> IsExistAsync(string id)
{
return await _repository.IsExistAsync(id);
}
// ============ Sync Methods (Backward Compatibility) ============
public OperationResult Create(CreateCameraBugReportCommand command)
{
try
{
return CreateAsync(command).ConfigureAwait(false).GetAwaiter().GetResult();
}
catch (Exception ex)
{
return new OperationResult().Failed($"خطا: {ex.Message}");
}
}
public OperationResult Edit(EditCameraBugReportCommand command)
{
try
{
return EditAsync(command).ConfigureAwait(false).GetAwaiter().GetResult();
}
catch (Exception ex)
{
return new OperationResult().Failed($"خطا: {ex.Message}");
}
}
public OperationResult Delete(long id)
{
try
{
return DeleteAsync(id.ToString()).ConfigureAwait(false).GetAwaiter().GetResult();
}
catch (Exception ex)
{
return new OperationResult().Failed($"خطا: {ex.Message}");
}
}
public List<CameraBugReportViewModel> GetAll(CameraBugReportSearchModel searchModel)
{
var query = _repository.GetAllAsNoTracking();
// فیلتر کردن بر اساس Type
if (searchModel.Type.HasValue)
query = query.Where(x => x.Type == searchModel.Type.Value);
// فیلتر کردن بر اساس Priority
if (searchModel.Priority.HasValue)
query = query.Where(x => x.Priority == searchModel.Priority.Value);
// فیلتر کردن بر اساس Status
if (searchModel.Status.HasValue)
query = query.Where(x => x.Status == searchModel.Status.Value);
// فیلتر کردن بر اساس SearchTerm
if (!string.IsNullOrEmpty(searchModel.SearchTerm))
try
{
var searchLower = searchModel.SearchTerm.ToLower();
query = query.Where(x =>
x.Title.ToLower().Contains(searchLower) ||
x.Description.ToLower().Contains(searchLower) ||
x.UserEmail.ToLower().Contains(searchLower)
);
return GetAllAsync(searchModel).ConfigureAwait(false).GetAwaiter().GetResult();
}
var bugReports = query
.OrderByDescending(x => x.CreationDate)
.Skip((searchModel.PageNumber) * searchModel.PageSize)
.Take(searchModel.PageSize)
.ToList();
return bugReports.Select(x => new CameraBugReportViewModel
catch (Exception ex)
{
Id = x.id,
Title = x.Title,
Description = x.Description,
UserEmail = x.UserEmail,
AccountId = x.AccountId,
DeviceModel = x.DeviceModel,
AppVersion = x.AppVersion,
Type = x.Type,
Priority = x.Priority,
Status = x.Status,
CreationDate = x.CreationDate,
UpdateDate = x.UpdateDate,
LogsCount = x.Logs?.Count ?? 0,
ScreenshotsCount = x.Screenshots?.Count ?? 0
}).ToList();
throw new Exception($"خطا: {ex.Message}", ex);
}
}
public CameraBugReportDetailViewModel GetDetails(long id)
{
var bugReport = _repository.Get(id);
if (bugReport == null)
return null;
return new CameraBugReportDetailViewModel
try
{
Id = bugReport.id,
Title = bugReport.Title,
Description = bugReport.Description,
UserEmail = bugReport.UserEmail,
AccountId = bugReport.AccountId,
DeviceModel = bugReport.DeviceModel,
OsVersion = bugReport.OsVersion,
Platform = bugReport.Platform,
Manufacturer = bugReport.Manufacturer,
DeviceId = bugReport.DeviceId,
ScreenResolution = bugReport.ScreenResolution,
MemoryInMB = bugReport.MemoryInMB,
StorageInMB = bugReport.StorageInMB,
BatteryLevel = bugReport.BatteryLevel,
IsCharging = bugReport.IsCharging,
NetworkType = bugReport.NetworkType,
AppVersion = bugReport.AppVersion,
BuildNumber = bugReport.BuildNumber,
PackageName = bugReport.PackageName,
InstallTime = bugReport.InstallTime,
LastUpdateTime = bugReport.LastUpdateTime,
Flavor = bugReport.Flavor,
Type = bugReport.Type,
Priority = bugReport.Priority,
Status = bugReport.Status,
StackTrace = bugReport.StackTrace,
CreationDate = bugReport.CreationDate,
UpdateDate = bugReport.UpdateDate,
Logs = bugReport.Logs?.Select(x => x.Message).ToList() ?? new List<string>(),
Screenshots = bugReport.Screenshots?.Select(x => new CameraBugReportScreenshotViewModel
{
Id = x.id,
FileName = x.FileName,
UploadDate = x.UploadDate,
Base64Data = x.Base64Data
}).ToList() ?? new List<CameraBugReportScreenshotViewModel>()
};
return GetDetailsAsync(id.ToString()).ConfigureAwait(false).GetAwaiter().GetResult();
}
catch (Exception ex)
{
throw new Exception($"خطا: {ex.Message}", ex);
}
}
public bool IsExist(long id)
{
return _repository.IsExist(id);
try
{
return IsExistAsync(id.ToString()).ConfigureAwait(false).GetAwaiter().GetResult();
}
catch (Exception ex)
{
throw new Exception($"خطا: {ex.Message}", ex);
}
}
}
}

View File

@@ -235,6 +235,8 @@ using _0_Framework.Infrastructure;
using _0_Framework.InfraStructure;
using Company.Domain.CameraBugReportAgg;
using CompanyManagment.App.Contracts.CameraBugReport;
using CompanyManagement.Infrastructure.Mongo.CameraBugReportRepo;
using CameraBugReportRepository = CompanyManagement.Infrastructure.Mongo.CameraBugReportRepo.CameraBugReportRepository;
namespace PersonalContractingParty.Config;
@@ -635,7 +637,7 @@ public class PersonalBootstrapper
services.AddTransient<ICameraBugReportApplication, CameraBugReportApplication>();
services.AddTransient<ICameraBugReportRepository, CameraBugReportRepository>();
services.AddTransient<ICameraBugReportRepository, CameraBugReportRepository>(); // MongoDB Implementation
services.AddDbContext<CompanyContext>(x => x.UseSqlServer(connectionString));
}