Skip to content

Commit

Permalink
1
Browse files Browse the repository at this point in the history
  • Loading branch information
akbaramd committed Jan 1, 2025
1 parent 28fd916 commit 02bf7f1
Show file tree
Hide file tree
Showing 16 changed files with 460 additions and 173 deletions.
6 changes: 4 additions & 2 deletions Nezam.EES.Slice.Identity/Application/Dto/Users/UserDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ public class UserDto
public Guid UserId { get; set; } // Using raw GUID for external compatibility
public string UserName { get; set; } // Assuming the string value for simplicity in DTOs
public string? Email { get; set; } // Nullable email as string for external systems
public string Profile { get; set; } // Optional profile info as a string representation
public string FirstName { get; set; } // Optional profile info as a string representation
public string? LastName { get; set; } // Optional profile info as a string representation
public List<RoleDto> Roles { get; set; } = new(); // List of associated roles
public bool IsCanDelete { get; set; } // Indicates if the user can be deleted

Expand All @@ -23,7 +24,8 @@ public static UserDto FromEntity(UserEntity user)
UserId = user.UserId.Value,
UserName = user.UserName.Value,
Email = user.Email?.Value,
Profile = user.Profile?.ToString(),
FirstName = user.Profile?.FirstName??"",
LastName = user.Profile?.LastName,
IsCanDelete = user.IsCanDelete,
Roles = user.Roles.Select(RoleDto.FromEntity).ToList()
};
Expand Down
115 changes: 60 additions & 55 deletions Nezam.EES.Slice.Secretariat/Application/Dto/DocumentDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@ namespace Nezam.EES.Slice.Secretariat.Application.Dto
{
public class DocumentDto
{
public Guid DocumentId { get; set; } // Using raw GUID for external compatibility
public string Title { get; set; }
public string Content { get; set; }
public Guid OwnerParticipantId { get; set; } // Using raw GUID for external compatibility
public string OwnerParticipantName { get; set; }
public Guid ReceiverParticipantId { get; set; } // Using raw GUID for external compatibility
public string ReceiverParticipantName { get; set; }
public string Type { get; set; } // Enum as string for external compatibility
public string Status { get; set; } // Enum as string for external compatibility
public string TrackingCode { get; set; }
public Guid DocumentId { get; set; }
public string Title { get; set; } = string.Empty; // Default empty string to avoid nulls
public string Content { get; set; } = string.Empty;
public ParticipantDto? OwnerParticipant { get; set; }
public ParticipantDto? ReceiverParticipant { get; set; }
public string Type { get; set; } = string.Empty;
public string Status { get; set; } = string.Empty;
public string TrackingCode { get; set; } = string.Empty;
public int LetterNumber { get; set; }
public DateTime LetterDate { get; set; }
public List<DocumentAttachmentDto> Attachments { get; set; } = new();
Expand All @@ -26,102 +24,109 @@ public static DocumentDto FromEntity(DocumentAggregateRoot entity)

return new DocumentDto
{
DocumentId = entity.DocumentId.Value,
Title = entity.Title,
Content = entity.Content,
OwnerParticipantId = entity.OwnerParticipantId.Value,
OwnerParticipantName = entity.OwnerParticipant?.Name,
ReceiverParticipantId = entity.ReceiverParticipantId.Value,
ReceiverParticipantName = entity.ReceiverParticipant?.Name,
Type = entity.Type.ToString(),
Status = entity.Status.ToString(),
TrackingCode = entity.TrackingCode,
DocumentId = entity.DocumentId?.Value ?? Guid.Empty,
Title = entity.Title ?? string.Empty,
Content = entity.Content ?? string.Empty,
OwnerParticipant = entity.OwnerParticipant != null
? ParticipantDto.FromEntity(entity.OwnerParticipant)
: null,
ReceiverParticipant = entity.ReceiverParticipant != null
? ParticipantDto.FromEntity(entity.ReceiverParticipant)
: null,
Type = entity.Type?.ToString() ?? string.Empty,
Status = entity.Status?.ToString() ?? string.Empty,
TrackingCode = entity.TrackingCode ?? string.Empty,
LetterNumber = entity.LetterNumber,
LetterDate = entity.LetterDate,
Attachments = entity.Attachments.Select(DocumentAttachmentDto.FromEntity).ToList(),
Referrals = entity.Referrals.Select(DocumentReferralDto.FromEntity).ToList()
Attachments = entity.Attachments?.Select(DocumentAttachmentDto.FromEntity).ToList() ?? new List<DocumentAttachmentDto>(),
Referrals = entity.Referrals?.Select(DocumentReferralDto.FromEntity).ToList() ?? new List<DocumentReferralDto>()
};
}
}


public class DocumentAttachmentDto
{
public Guid DocumentAttachmentId { get; set; } // Using raw GUID for external compatibility
public string FileName { get; set; }
public string FileType { get; set; }
public Guid DocumentAttachmentId { get; set; }
public string FileName { get; set; } = string.Empty;
public string FileType { get; set; } = string.Empty;
public long FileSize { get; set; }
public string FilePath { get; set; }
public string FilePath { get; set; } = string.Empty;
public DateTime UploadDate { get; set; }

public static DocumentAttachmentDto FromEntity(DocumentAttachmentEntity entity)
public static DocumentAttachmentDto FromEntity(DocumentAttachmentEntity? entity)
{
if (entity == null) throw new ArgumentNullException(nameof(entity));

return new DocumentAttachmentDto
{
DocumentAttachmentId = entity.DocumentAttachmentId.Value,
FileName = entity.FileName,
FileType = entity.FileType,
DocumentAttachmentId = entity.DocumentAttachmentId?.Value ?? Guid.Empty,
FileName = entity.FileName ?? string.Empty,
FileType = entity.FileType ?? string.Empty,
FileSize = entity.FileSize,
FilePath = entity.FilePath,
FilePath = entity.FilePath ?? string.Empty,
UploadDate = entity.UploadDate
};
}
}


public class DocumentReferralDto
{
public Guid DocumentReferralId { get; set; } // Using raw GUID for external compatibility
public Guid DocumentId { get; set; } // Using raw GUID for external compatibility
public Guid ReferrerUserId { get; set; } // Using raw GUID for external compatibility
public string ReferrerUserName { get; set; }
public Guid ReceiverUserId { get; set; } // Using raw GUID for external compatibility
public string ReceiverUserName { get; set; }
public string Status { get; set; } // Enum as string for external compatibility
public Guid DocumentReferralId { get; set; }
public Guid DocumentId { get; set; }
public ParticipantDto? ReferrerParticipant { get; set; }
public ParticipantDto? ReceiverParticipant { get; set; }
public string Status { get; set; } = string.Empty;
public DateTime ReferralDate { get; set; }
public DateTime? ViewedDate { get; set; }
public DateTime? RespondedDate { get; set; }
public string? ResponseContent { get; set; }
public Guid? ParentReferralId { get; set; } // Using raw GUID for external compatibility
public Guid? ParentReferralId { get; set; }

public static DocumentReferralDto FromEntity(DocumentReferralEntity entity)
public static DocumentReferralDto FromEntity(DocumentReferralEntity? entity)
{
if (entity == null) throw new ArgumentNullException(nameof(entity));

return new DocumentReferralDto
{
DocumentReferralId = entity.DocumentReferralId.Value,
DocumentId = entity.DocumentId.Value,
ReferrerUserId = entity.ReferrerUserId.Value,
ReferrerUserName = entity.ReferrerUser?.Name,
ReceiverUserId = entity.ReceiverUserId.Value,
ReceiverUserName = entity.ReceiverUser?.Name,
Status = entity.Status.ToString(),
DocumentReferralId = entity.DocumentReferralId?.Value ?? Guid.Empty,
DocumentId = entity.DocumentId?.Value ?? Guid.Empty,
ReferrerParticipant = entity.ReferrerParticipant != null
? ParticipantDto.FromEntity(entity.ReferrerParticipant)
: null,
ReceiverParticipant = entity.ReceiverParticipant != null
? ParticipantDto.FromEntity(entity.ReceiverParticipant)
: null,
Status = entity.Status?.ToString() ?? string.Empty,
ReferralDate = entity.ReferralDate,
ViewedDate = entity.ViewedDate,
RespondedDate = entity.RespondedDate,
ResponseContent = entity.ResponseContent,
ResponseContent = entity.ResponseContent ?? string.Empty,
ParentReferralId = entity.ParentReferralId?.Value
};
}
}



public class ParticipantDto
{
public Guid ParticipantId { get; set; } // Using raw GUID for external compatibility
public Guid? UserId { get; set; } // Using raw GUID for external compatibility
public string Name { get; set; }
public Guid ParticipantId { get; set; }
public Guid? UserId { get; set; }
public string Name { get; set; } = string.Empty;

public static ParticipantDto FromEntity(Participant entity)
public static ParticipantDto FromEntity(Participant? entity)
{
if (entity == null) throw new ArgumentNullException(nameof(entity));
if (entity == null) return null;

return new ParticipantDto
{
ParticipantId = entity.ParticipantId.Value,
ParticipantId = entity.ParticipantId?.Value ?? Guid.Empty,
UserId = entity.UserId?.Value,
Name = entity.Name
Name = entity.Name ?? string.Empty
};
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
using System.Security.Claims;
using FastEndpoints;
using FluentValidation;
using Microsoft.AspNetCore.Http;
using Nezam.EES.Slice.Secretariat.Domains.Documents.Repositories;
using Nezam.EES.Slice.Secretariat.Domains.Documents.ValueObjects;
using Payeh.SharedKernel.UnitOfWork;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Nezam.EEs.Shared.Domain.Identity.User;
using Nezam.EES.Slice.Secretariat.Domains.Documents;
using Nezam.EES.Slice.Secretariat.Domains.Participant;
using Nezam.EES.Slice.Secretariat.Domains.Participant.Repositories;

namespace Nezam.EES.Slice.Secretariat.Application.UseCases.Documents.AddReferral;

public class AddReferralEndpoint : Endpoint<AddReferralRequest>
{
private readonly IDocumentRepository _documentRepository;
private readonly IParticipantRepository _participantRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager;

public AddReferralEndpoint(IDocumentRepository documentRepository, IUnitOfWorkManager unitOfWorkManager, IParticipantRepository participantRepository)
{
_documentRepository = documentRepository;
_unitOfWorkManager = unitOfWorkManager;
_participantRepository = participantRepository;
}

public override void Configure()
{
Post("/api/documents/{DocumentId}/add-referral");
}

public override async Task HandleAsync(AddReferralRequest req, CancellationToken ct)
{
using var uow = _unitOfWorkManager.Begin();

// Get the current user's ParticipantId from the context
var userID = GetCurrentUserId();
if (userID == null)
{
AddError("Access", "User is not authorized or ParticipantId is missing.");
await SendErrorsAsync(cancellation: ct);
return;
}
var referrerParticipantId = await GetParticipantIdByUserIdAsync(userID, ct);
// Validate Document ID from route
var documentId = DocumentId.NewId(req.DocumentId);

// Fetch the document
var document = await _documentRepository.FindOneAsync(x => x.DocumentId == documentId);
if (document == null)
{
AddError("Document", "Document not found.");
await SendErrorsAsync(cancellation: ct);
return;
}

// Check access control: Ensure ReferrerParticipantId has access to this document
if (!HasAccessToDocument(referrerParticipantId.Value, document))
{
AddError("Access", "You do not have access to this document.");
await SendErrorsAsync(cancellation: ct);
return;
}

// Validate participants
if (referrerParticipantId.Value == req.ReceiverParticipantId)
{
AddError("Participants", "You cannot refer a document to yourself.");
await SendErrorsAsync(cancellation: ct);
return;
}

// Validate content
if (string.IsNullOrWhiteSpace(req.Content))
{
AddError("Content", "Content cannot be empty.");
await SendErrorsAsync(cancellation: ct);
return;
}

// Handle Parent Referral
if (req.ParentReferralId.HasValue)
{
var parentReferralId = DocumentReferralId.NewId(req.ParentReferralId.Value);
var parentReferral = document.Referrals.FirstOrDefault(r => r.DocumentReferralId == parentReferralId);

if (parentReferral == null)
{
AddError("ParentReferral", "Parent referral not found.");
await SendErrorsAsync(cancellation: ct);
return;
}

if (parentReferral.ReceiverParticipantId.Value != referrerParticipantId.Value)
{
AddError("Access", "You do not have permission to respond to this referral.");
await SendErrorsAsync(cancellation: ct);
return;
}

// Respond to the parent referral
parentReferral.Respond();
}

// Add a new referral regardless of whether ParentReferralId exists
document.AddReferral(
ParticipantId.NewId(req.ReceiverParticipantId),
ParticipantId.NewId(referrerParticipantId.Value),
req.Content,
req.ParentReferralId.HasValue ? DocumentReferralId.NewId(req.ParentReferralId.Value) : null
);

// Save changes
await _documentRepository.UpdateAsync(document, true);
await uow.CommitAsync(ct);

await SendOkAsync(new { Message = "Referral added successfully." }, ct);
}


private async Task<ParticipantId?> GetParticipantIdByUserIdAsync(UserId userId, CancellationToken ct)
{
return (await _participantRepository.GetOneAsync(x=>x.UserId == userId)).ParticipantId;
}
private bool HasAccessToDocument(Guid referrerParticipantId, DocumentAggregateRoot document)
{
// Check if the referrer is either a referrer or receiver in the document's existing referrals
return document.Referrals.Any(r =>
r.ReferrerParticipantId.Value == referrerParticipantId ||
r.ReceiverParticipantId.Value == referrerParticipantId);
}

private UserId? GetCurrentUserId()
{
var userIdClaim = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
return userIdClaim != null ? UserId.NewId(Guid.Parse(userIdClaim.Value)) : null;
}
}

public class AddReferralRequest
{
[FromRoute]
public Guid DocumentId { get; set; }

public Guid ReceiverParticipantId { get; set; }

public string Content { get; set; } = default!; // Content for the referral

public Guid? ParentReferralId { get; set; }
}

public class AddReferralRequestValidator : Validator<AddReferralRequest>
{
public AddReferralRequestValidator()
{
RuleFor(x => x.DocumentId).NotEmpty().WithMessage("Document ID is required.");
RuleFor(x => x.ReceiverParticipantId).NotEmpty().WithMessage("Receiver participant ID is required.");
RuleFor(x => x.Content).NotEmpty().WithMessage("Content is required.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Nezam.EES.Slice.Secretariat.Domains.Documents.Enumerations;
using Nezam.EES.Slice.Secretariat.Domains.Participant;
using Nezam.EES.Slice.Secretariat.Infrastructure.EntityFrameworkCore;
using Payeh.SharedKernel.Domain.Enumerations;

namespace Nezam.EES.Slice.Secretariat.Application.UseCases.Documents.CreateDocument;

Expand Down Expand Up @@ -57,7 +58,7 @@ public override async Task HandleAsync(CreateDocumentRequest req, CancellationTo
var documentNumber = await GenerateDocumentNumberAsync(DateTime.UtcNow.Year, ct);

var document = CreateDocument(req, participantId, receiverParticipantId, documentNumber);

document.ChangeType(Enumeration.FromId<DocumentType>(req.Type) ?? DocumentType.Internal);
await _dbContext.Documents.AddAsync(document, ct);
await _dbContext.SaveChangesAsync(ct);

Expand Down Expand Up @@ -89,7 +90,8 @@ private async Task<int> GenerateDocumentNumberAsync(int year, CancellationToken
return count + 1;
}

private DocumentAggregateRoot CreateDocument(CreateDocumentRequest req, ParticipantId participantId, ParticipantId receiverParticipantId, int documentNumber)
private DocumentAggregateRoot CreateDocument(CreateDocumentRequest req, ParticipantId participantId,
ParticipantId receiverParticipantId, int documentNumber)
{
return new DocumentAggregateRoot(
req.Title,
Expand All @@ -106,4 +108,4 @@ private DocumentAggregateRoot CreateDocument(CreateDocumentRequest req, Particip
var userIdClaim = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
return userIdClaim != null ? UserId.NewId(Guid.Parse(userIdClaim.Value)) : null;
}
}
}
Loading

0 comments on commit 02bf7f1

Please sign in to comment.