Implemented core forum features including ticket creation, ticket updates, adding and updating comments, managing attachments, retrieving ticket details by ID, and fetching the ticket list
This commit is contained in:
parent
fce124ac8b
commit
ace2fe7d54
@ -1,12 +1,14 @@
|
|||||||
using System;
|
namespace Marco.Pms.Model.Dtos.Forum
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Marco.Pms.Model.Dtos.Forum
|
|
||||||
{
|
{
|
||||||
public class AddCommentDto
|
public class AddCommentDto
|
||||||
{
|
{
|
||||||
|
public Guid Id { get; set; } = Guid.Empty;
|
||||||
|
public Guid TicketId { get; set; } = Guid.Empty;
|
||||||
|
public Guid AuthorId { get; set; }
|
||||||
|
public string MessageText { get; set; } = string.Empty;
|
||||||
|
public DateTime SentAt { get; set; }
|
||||||
|
public Guid? ParentMessageId { get; set; } // For threaded replies
|
||||||
|
public ICollection<ForumAttachmentDto>? Attachments { get; set; }
|
||||||
|
public int TenantId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,5 +2,17 @@
|
|||||||
{
|
{
|
||||||
public class CreateTicketDto
|
public class CreateTicketDto
|
||||||
{
|
{
|
||||||
|
public Guid Id { get; set; } = Guid.Empty;
|
||||||
|
public string Subject { get; set; } = string.Empty;
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
public Guid StatusId { get; set; }
|
||||||
|
public Guid TypeId { get; set; } // QualityIssue, HelpDesk, Feedback
|
||||||
|
public int CreatedById { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public int LinkedActivityId { get; set; } // task or project ID
|
||||||
|
public ICollection<ForumAttachmentDto>? Attachments { get; set; }
|
||||||
|
public Guid PriorityId { get; set; }
|
||||||
|
public ICollection<Guid>? TagIds { get; set; }
|
||||||
|
public int TenantId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
using System;
|
namespace Marco.Pms.Model.Dtos.Forum
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Marco.Pms.Model.Dtos.Forum
|
|
||||||
{
|
{
|
||||||
public class ForumAttachmentDto
|
public class ForumAttachmentDto
|
||||||
{
|
{
|
||||||
|
public Guid Id { get; set; } = Guid.Empty;
|
||||||
|
public Guid TicketId { get; set; } = Guid.Empty;
|
||||||
|
public Guid? CommentId { get; set; }
|
||||||
|
public string FileName { get; set; } = string.Empty;
|
||||||
|
public string? Base64Data { get; set; }
|
||||||
|
public int FileSize { get; set; }
|
||||||
|
public string ContentType { get; set; } = string.Empty;
|
||||||
|
public DateTime SentAt { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
Marco.Pms.Model/Dtos/Forum/UpdateCommentDto.cs
Normal file
14
Marco.Pms.Model/Dtos/Forum/UpdateCommentDto.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Forum
|
||||||
|
{
|
||||||
|
public class UpdateCommentDto
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid TicketId { get; set; }
|
||||||
|
public Guid AuthorId { get; set; }
|
||||||
|
public string MessageText { get; set; } = string.Empty;
|
||||||
|
public DateTime SentAt { get; set; }
|
||||||
|
public Guid? ParentMessageId { get; set; } // For threaded replies
|
||||||
|
public ICollection<ForumAttachmentDto>? Attachments { get; set; }
|
||||||
|
public int TenantId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
18
Marco.Pms.Model/Dtos/Forum/UpdateTicketDto.cs
Normal file
18
Marco.Pms.Model/Dtos/Forum/UpdateTicketDto.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Forum
|
||||||
|
{
|
||||||
|
public class UpdateTicketDto
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Subject { get; set; } = string.Empty;
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
public Guid StatusId { get; set; }
|
||||||
|
public Guid TypeId { get; set; } // QualityIssue, HelpDesk, Feedback
|
||||||
|
public int CreatedById { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public int LinkedActivityId { get; set; } // task or project ID
|
||||||
|
public ICollection<ForumAttachmentDto>? Attachments { get; set; }
|
||||||
|
public Guid PriorityId { get; set; }
|
||||||
|
public ICollection<Guid>? TagIds { get; set; }
|
||||||
|
public int TenantId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,7 @@ namespace Marco.Pms.Model.Forum
|
|||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
[ForeignKey(nameof(TicketId))]
|
[ForeignKey(nameof(TicketId))]
|
||||||
public TicketForum? Ticket { get; set; }
|
public TicketForum? Ticket { get; set; }
|
||||||
public Guid CommentId { get; set; }
|
public Guid? CommentId { get; set; }
|
||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
[ForeignKey(nameof(CommentId))]
|
[ForeignKey(nameof(CommentId))]
|
||||||
public TicketComment? TicketComment { get; set; }
|
public TicketComment? TicketComment { get; set; }
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public Guid TicketId { get; set; }
|
public Guid TicketId { get; set; }
|
||||||
public TicketForum Ticket { get; set; } = new TicketForum();
|
public TicketForum? Ticket { get; set; }
|
||||||
|
|
||||||
public Guid TagId { get; set; }
|
public Guid TagId { get; set; }
|
||||||
public TicketTagMaster Tag { get; set; } = new TicketTagMaster();
|
public TicketTagMaster? Tag { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
176
Marco.Pms.Model/Mapper/ForumMapper.cs
Normal file
176
Marco.Pms.Model/Mapper/ForumMapper.cs
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
using Marco.Pms.Model.DocumentManager;
|
||||||
|
using Marco.Pms.Model.Dtos.Forum;
|
||||||
|
using Marco.Pms.Model.Employees;
|
||||||
|
using Marco.Pms.Model.Forum;
|
||||||
|
using Marco.Pms.Model.ViewModels.Forum;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.Mapper
|
||||||
|
{
|
||||||
|
public static class ForumMapper
|
||||||
|
{
|
||||||
|
public static TicketForum ToTicketForumFromCreateTicketDto(this CreateTicketDto createTicketDto)
|
||||||
|
{
|
||||||
|
return new TicketForum
|
||||||
|
{
|
||||||
|
Subject = createTicketDto.Subject,
|
||||||
|
Description = createTicketDto.Description,
|
||||||
|
StatusId = createTicketDto.StatusId,
|
||||||
|
TypeId = createTicketDto.TypeId,
|
||||||
|
CreatedById = createTicketDto.CreatedById,
|
||||||
|
CreatedAt = createTicketDto.CreatedAt,
|
||||||
|
LinkedActivityId = createTicketDto.LinkedActivityId,
|
||||||
|
PriorityId = createTicketDto.PriorityId,
|
||||||
|
TenantId = createTicketDto.TenantId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static TicketForum ToTicketForumFromUpdateTicketDto(this UpdateTicketDto updateTicketDto, TicketForum ticket)
|
||||||
|
{
|
||||||
|
return new TicketForum
|
||||||
|
{
|
||||||
|
Id = updateTicketDto.Id,
|
||||||
|
Subject = updateTicketDto.Subject,
|
||||||
|
Description = updateTicketDto.Description,
|
||||||
|
StatusId = updateTicketDto.StatusId,
|
||||||
|
TypeId = updateTicketDto.TypeId,
|
||||||
|
CreatedById = ticket.CreatedById,
|
||||||
|
CreatedAt = ticket.CreatedAt,
|
||||||
|
LinkedActivityId = updateTicketDto.LinkedActivityId,
|
||||||
|
PriorityId = updateTicketDto.PriorityId,
|
||||||
|
TenantId = ticket.TenantId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TicketComment ToTicketCommentFromAddCommentDto(this AddCommentDto commentDto)
|
||||||
|
{
|
||||||
|
return new TicketComment
|
||||||
|
{
|
||||||
|
TicketId = commentDto.TicketId,
|
||||||
|
AuthorId = commentDto.AuthorId,
|
||||||
|
MessageText = commentDto.MessageText,
|
||||||
|
SentAt = commentDto.SentAt,
|
||||||
|
ParentMessageId = commentDto.ParentMessageId,
|
||||||
|
TenantId = commentDto.TenantId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static TicketComment ToTicketCommentFromUpdateCommentDto(this UpdateCommentDto updateComment, int tenantId, TicketComment comment)
|
||||||
|
{
|
||||||
|
return new TicketComment
|
||||||
|
{
|
||||||
|
Id = updateComment.Id,
|
||||||
|
TicketId = updateComment.TicketId,
|
||||||
|
AuthorId = comment.AuthorId,
|
||||||
|
MessageText = updateComment.MessageText,
|
||||||
|
SentAt = comment.SentAt,
|
||||||
|
ParentMessageId = updateComment.ParentMessageId,
|
||||||
|
TenantId = tenantId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static TicketAttachment ToTicketAttachmentFromForumAttachmentDto(this ForumAttachmentDto AttachmentDto, Guid ticketId, Guid fileId, Guid? commentId = null)
|
||||||
|
{
|
||||||
|
return new TicketAttachment
|
||||||
|
{
|
||||||
|
TicketId = ticketId,
|
||||||
|
CommentId = commentId,
|
||||||
|
FileName = AttachmentDto.FileName,
|
||||||
|
FileId = fileId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Document ToDocumentFromForumAttachmentDto(this ForumAttachmentDto AttachmentDto, string objectKey, string thumbS3Key, DateTime uploadedAt, int tenantId)
|
||||||
|
{
|
||||||
|
return new Document
|
||||||
|
{
|
||||||
|
FileName = AttachmentDto.FileName,
|
||||||
|
ContentType = AttachmentDto.ContentType,
|
||||||
|
S3Key = objectKey,
|
||||||
|
ThumbS3Key = thumbS3Key,
|
||||||
|
Base64Data = AttachmentDto.Base64Data,
|
||||||
|
FileSize = AttachmentDto.FileSize,
|
||||||
|
UploadedAt = uploadedAt,
|
||||||
|
TenantId = tenantId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static ForumTicketVM ToForumTicketVMFromTicketForum(this TicketForum ticket, Employee employee)
|
||||||
|
{
|
||||||
|
return new ForumTicketVM
|
||||||
|
{
|
||||||
|
Id = ticket.Id,
|
||||||
|
Subject = ticket.Subject,
|
||||||
|
Description = ticket.Description,
|
||||||
|
CreatedAt = ticket.CreatedAt,
|
||||||
|
LinkedActivityId = ticket.LinkedActivityId,
|
||||||
|
Status = ticket.TicketStatusMaster.ToTicketStatusVMFromTicketStatusMaster(),
|
||||||
|
Priority = ticket.Priority.ToTicketPriorityVMFromTicketPriorityMaster(),
|
||||||
|
Type = ticket.TicketTypeMaster.ToTicketTypeVMFromTicketTypeMaster(),
|
||||||
|
CreatedBy = employee.ToBasicEmployeeVMFromEmployee(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static TicketAttachmentVM ToTicketAttachmentVMFromTicketAttachment(this TicketAttachment attachment, string preSignedUrl, string thumbPreSignedUrl)
|
||||||
|
{
|
||||||
|
return new TicketAttachmentVM
|
||||||
|
{
|
||||||
|
Id = attachment.Id,
|
||||||
|
TicketId = attachment.TicketId,
|
||||||
|
CommentId = attachment.CommentId,
|
||||||
|
FileName = attachment.FileName,
|
||||||
|
PreSignedUrl = preSignedUrl,
|
||||||
|
ThumbPreSignedUrl = thumbPreSignedUrl
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static TicketCommentVM ToTicketCommentVMFromTicketComment(this TicketComment comment, Employee employee)
|
||||||
|
{
|
||||||
|
return new TicketCommentVM
|
||||||
|
{
|
||||||
|
Id = comment.Id,
|
||||||
|
TicketId = comment.TicketId,
|
||||||
|
Author = employee.ToBasicEmployeeVMFromEmployee(),
|
||||||
|
MessageText = comment.MessageText,
|
||||||
|
SentAt = comment.SentAt,
|
||||||
|
ParentMessageId = comment.ParentMessageId,
|
||||||
|
Attachments = new List<TicketAttachmentVM>()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static TicketStatusVM ToTicketStatusVMFromTicketStatusMaster(this TicketStatusMaster statusMaster)
|
||||||
|
{
|
||||||
|
return new TicketStatusVM
|
||||||
|
{
|
||||||
|
Id = statusMaster.Id,
|
||||||
|
Name = statusMaster.Name,
|
||||||
|
Description = statusMaster.Description,
|
||||||
|
ColorCode = statusMaster.ColorCode,
|
||||||
|
IsDefault = statusMaster.IsDefault
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static TicketPriorityVM ToTicketPriorityVMFromTicketPriorityMaster(this TicketPriorityMaster priorityMaster)
|
||||||
|
{
|
||||||
|
return new TicketPriorityVM
|
||||||
|
{
|
||||||
|
Id = priorityMaster.Id,
|
||||||
|
Name = priorityMaster.Name,
|
||||||
|
Level = priorityMaster.Level,
|
||||||
|
ColorCode = priorityMaster.ColorCode,
|
||||||
|
IsDefault = priorityMaster.IsDefault
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static TicketTypeVM ToTicketTypeVMFromTicketTypeMaster(this TicketTypeMaster typeMaster)
|
||||||
|
{
|
||||||
|
return new TicketTypeVM
|
||||||
|
{
|
||||||
|
Id = typeMaster.Id,
|
||||||
|
Name = typeMaster.Name,
|
||||||
|
Description = typeMaster.Description,
|
||||||
|
IsDefault = typeMaster.IsDefault
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static TicketTagVM ToTicketTagVMFromTicketTagMaster(this TicketTagMaster tagMaster)
|
||||||
|
{
|
||||||
|
return new TicketTagVM
|
||||||
|
{
|
||||||
|
Id = tagMaster.Id,
|
||||||
|
Name = tagMaster.Name,
|
||||||
|
ColorCode = tagMaster.ColorCode,
|
||||||
|
IsDefault = tagMaster.IsDefault
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
Marco.Pms.Model/ViewModels/DocumentManager/DocumentVM.cs
Normal file
14
Marco.Pms.Model/ViewModels/DocumentManager/DocumentVM.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
namespace Marco.Pms.Model.ViewModels.DocumentManager
|
||||||
|
{
|
||||||
|
public class DocumentVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid? BatchId { get; set; }
|
||||||
|
public string FileName { get; set; } = string.Empty;
|
||||||
|
public string? PreSignedUrl { get; set; }
|
||||||
|
public string? ThumbPreSignedUrl { get; set; }
|
||||||
|
public long FileSize { get; set; }
|
||||||
|
public string ContentType { get; set; } = string.Empty;
|
||||||
|
public DateTime UploadedAt { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,20 @@
|
|||||||
namespace Marco.Pms.Model.ViewModels.Forum
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ViewModels.Forum
|
||||||
{
|
{
|
||||||
public class ForumTicketVM
|
public class ForumTicketVM
|
||||||
{
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Subject { get; set; } = string.Empty;
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
public TicketStatusVM? Status { get; set; }
|
||||||
|
public TicketTypeVM? Type { get; set; } // QualityIssue, HelpDesk, Feedback
|
||||||
|
public TicketPriorityVM? Priority { get; set; }
|
||||||
|
public BasicEmployeeVM? CreatedBy { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public int LinkedActivityId { get; set; } // task or project ID
|
||||||
|
public ICollection<TicketCommentVM>? Comments { get; set; } // view model
|
||||||
|
public ICollection<TicketAttachmentVM>? Attachments { get; set; } // view model
|
||||||
|
public ICollection<TicketTagVM>? Tags { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
Marco.Pms.Model/ViewModels/Forum/TicketAttachmentVM.cs
Normal file
12
Marco.Pms.Model/ViewModels/Forum/TicketAttachmentVM.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace Marco.Pms.Model.ViewModels.Forum
|
||||||
|
{
|
||||||
|
public class TicketAttachmentVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid TicketId { get; set; }
|
||||||
|
public Guid? CommentId { get; set; }
|
||||||
|
public string FileName { get; set; } = string.Empty;
|
||||||
|
public string? PreSignedUrl { get; set; }
|
||||||
|
public string ThumbPreSignedUrl { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
16
Marco.Pms.Model/ViewModels/Forum/TicketCommentVM.cs
Normal file
16
Marco.Pms.Model/ViewModels/Forum/TicketCommentVM.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ViewModels.Forum
|
||||||
|
{
|
||||||
|
public class TicketCommentVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid TicketId { get; set; }
|
||||||
|
public BasicEmployeeVM? Author { get; set; }
|
||||||
|
public string MessageText { get; set; } = string.Empty;
|
||||||
|
public DateTime SentAt { get; set; }
|
||||||
|
public Guid? ParentMessageId { get; set; } // For threaded replies
|
||||||
|
|
||||||
|
public ICollection<TicketAttachmentVM>? Attachments { get; set; }
|
||||||
|
}
|
||||||
|
}
|
12
Marco.Pms.Model/ViewModels/Forum/TicketPriorityVM.cs
Normal file
12
Marco.Pms.Model/ViewModels/Forum/TicketPriorityVM.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace Marco.Pms.Model.ViewModels.Forum
|
||||||
|
{
|
||||||
|
public class TicketPriorityVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty; // e.g., Low, Medium, High, Critical
|
||||||
|
public int Level { get; set; } // 1 = Low, 2 = Medium...
|
||||||
|
public string? ColorCode { get; set; }
|
||||||
|
public bool IsDefault { get; set; } // true for system defaults
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
11
Marco.Pms.Model/ViewModels/Forum/TicketStatusVM.cs
Normal file
11
Marco.Pms.Model/ViewModels/Forum/TicketStatusVM.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace Marco.Pms.Model.ViewModels.Forum
|
||||||
|
{
|
||||||
|
public class TicketStatusVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty; // e.g., "Open", "In Progress"
|
||||||
|
public string? Description { get; set; }
|
||||||
|
public string? ColorCode { get; set; } // e.g., "#FF0000"
|
||||||
|
public bool IsDefault { get; set; } // true for system defaults
|
||||||
|
}
|
||||||
|
}
|
10
Marco.Pms.Model/ViewModels/Forum/TicketTagVM.cs
Normal file
10
Marco.Pms.Model/ViewModels/Forum/TicketTagVM.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace Marco.Pms.Model.ViewModels.Forum
|
||||||
|
{
|
||||||
|
public class TicketTagVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty; // e.g., "Bug", "UI", "Urgent"
|
||||||
|
public string? ColorCode { get; set; }
|
||||||
|
public bool IsDefault { get; set; }
|
||||||
|
}
|
||||||
|
}
|
11
Marco.Pms.Model/ViewModels/Forum/TicketTypeVM.cs
Normal file
11
Marco.Pms.Model/ViewModels/Forum/TicketTypeVM.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace Marco.Pms.Model.ViewModels.Forum
|
||||||
|
{
|
||||||
|
public class TicketTypeVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty; // e.g., "Quality Issue"
|
||||||
|
public string? Description { get; set; }
|
||||||
|
public bool IsDefault { get; set; } // true for system defaults
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,73 +1,796 @@
|
|||||||
using Marco.Pms.DataAccess.Data;
|
using Marco.Pms.DataAccess.Data;
|
||||||
using Marco.Pms.Model.Authentication;
|
using Marco.Pms.Model.DocumentManager;
|
||||||
using Marco.Pms.Model.Dtos.Forum;
|
using Marco.Pms.Model.Dtos.Forum;
|
||||||
using Marco.Pms.Model.Dtos.Util;
|
using Marco.Pms.Model.Employees;
|
||||||
using Marco.Pms.Model.Industries;
|
using Marco.Pms.Model.Forum;
|
||||||
|
using Marco.Pms.Model.Mapper;
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
|
using Marco.Pms.Model.ViewModels.Forum;
|
||||||
|
using Marco.Pms.Services.Service;
|
||||||
using MarcoBMS.Services.Helpers;
|
using MarcoBMS.Services.Helpers;
|
||||||
using MarcoBMS.Services.Service;
|
using MarcoBMS.Services.Service;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Marco.Pms.Services.Controllers
|
namespace Marco.Pms.Services.Controllers
|
||||||
{
|
{
|
||||||
|
[Authorize]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class ForumController : ControllerBase
|
public class ForumController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly UserManager<IdentityUser> _userManager;
|
|
||||||
private readonly ApplicationDbContext _context;
|
private readonly ApplicationDbContext _context;
|
||||||
private readonly JwtSettings _jwtSettings;
|
private readonly UserHelper _userHelper;
|
||||||
private readonly RefreshTokenService _refreshTokenService;
|
private readonly S3UploadService _s3Service;
|
||||||
private readonly IEmailSender _emailSender;
|
private readonly ILoggingService _logger;
|
||||||
private readonly IConfiguration _configuration;
|
|
||||||
private readonly EmployeeHelper _employeeHelper;
|
|
||||||
//string tenentId = "1";
|
//string tenentId = "1";
|
||||||
public ForumController(UserManager<IdentityUser> userManager, ApplicationDbContext context, JwtSettings jwtSettings, RefreshTokenService refreshTokenService,
|
public ForumController(ApplicationDbContext context, S3UploadService s3Service, UserHelper userHelper, ILoggingService logger)
|
||||||
IEmailSender emailSender, IConfiguration configuration, EmployeeHelper employeeHelper)
|
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
|
||||||
_jwtSettings = jwtSettings;
|
|
||||||
_refreshTokenService = refreshTokenService;
|
|
||||||
_emailSender = emailSender;
|
|
||||||
_configuration = configuration;
|
|
||||||
_employeeHelper = employeeHelper;
|
|
||||||
_context = context;
|
_context = context;
|
||||||
|
_userHelper = userHelper;
|
||||||
|
_s3Service = s3Service;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("tickets")]
|
[HttpPost("ticket")]
|
||||||
public async Task<IActionResult> CreateNewTicket([FromBody] CreateTicketDto createTicketDto)
|
public async Task<IActionResult> CreateNewTicket([FromBody] CreateTicketDto createTicketDto)
|
||||||
{
|
{
|
||||||
return NotFound(ApiResponse<object>.ErrorResponse("Industry not found.", "Industry not found.", 404));
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
var errors = ModelState.Values
|
||||||
|
.SelectMany(v => v.Errors)
|
||||||
|
.Select(e => e.ErrorMessage)
|
||||||
|
.ToList();
|
||||||
|
_logger.LogError("{error}", errors);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
||||||
|
}
|
||||||
|
int tenantId = _userHelper.GetTenantId();
|
||||||
|
if (tenantId == createTicketDto.TenantId)
|
||||||
|
{
|
||||||
|
TicketForum ticketForum = createTicketDto.ToTicketForumFromCreateTicketDto();
|
||||||
|
_context.Tickets.Add(ticketForum);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
List<TicketAttachment> attachments = new List<TicketAttachment>();
|
||||||
|
List<TicketTag> ticketTags = new List<TicketTag>();
|
||||||
|
List<Document> documents = new List<Document>();
|
||||||
|
List<TicketTagVM> tagVMs = new List<TicketTagVM>();
|
||||||
|
|
||||||
|
if (createTicketDto.Attachments != null)
|
||||||
|
{
|
||||||
|
foreach (var attachmentDto in createTicketDto.Attachments)
|
||||||
|
{
|
||||||
|
byte[] fileBytes;
|
||||||
|
var Image = attachmentDto;
|
||||||
|
if (string.IsNullOrEmpty(Image.Base64Data))
|
||||||
|
{
|
||||||
|
_logger.LogError("Base64 data is missing");
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Base64 data is missing", "Base64 data is missing", 400));
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//If base64 has a data URI prefix, strip it
|
||||||
|
var base64 = Image.Base64Data.Contains(",")
|
||||||
|
? Image.Base64Data.Substring(Image.Base64Data.IndexOf(",") + 1)
|
||||||
|
: Image.Base64Data;
|
||||||
|
|
||||||
|
fileBytes = Convert.FromBase64String(base64);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("{error}", ex.Message);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse(ex.Message, ex, 400)); ;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("tickets/{id}/comment")]
|
using var stream = new MemoryStream(fileBytes);
|
||||||
|
|
||||||
|
|
||||||
|
string fileName = _s3Service.GenerateFileName(Image.ContentType, tenantId, string.Empty);
|
||||||
|
|
||||||
|
var objectKey = await _s3Service.UploadFileAsync(stream, fileName, Image.ContentType);
|
||||||
|
|
||||||
|
Document document = attachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, createTicketDto.CreatedAt, tenantId);
|
||||||
|
_context.Documents.Add(document);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
documents.Add(document);
|
||||||
|
|
||||||
|
var attachment = attachmentDto.ToTicketAttachmentFromForumAttachmentDto(ticketForum.Id, document.Id);
|
||||||
|
attachments.Add(attachment);
|
||||||
|
}
|
||||||
|
_context.TicketAttachments.AddRange(attachments);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (createTicketDto.TagIds != null)
|
||||||
|
{
|
||||||
|
List<TicketTagMaster>? tagMasters = await _context.TicketTagMasters.Where(t => createTicketDto.TagIds.Contains(t.Id)).ToListAsync();
|
||||||
|
foreach (var ticketTag in tagMasters)
|
||||||
|
{
|
||||||
|
TicketTagVM tagVM = ticketTag.ToTicketTagVMFromTicketTagMaster();
|
||||||
|
|
||||||
|
TicketTag tag = new TicketTag
|
||||||
|
{
|
||||||
|
TicketId = ticketForum.Id,
|
||||||
|
TagId = ticketTag.Id
|
||||||
|
};
|
||||||
|
tagVMs.Add(tagVM);
|
||||||
|
ticketTags.Add(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.TicketTags.AddRange(ticketTags);
|
||||||
|
}
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
var ticket = await _context.Tickets.Include(t => t.TicketTypeMaster).Include(t => t.TicketStatusMaster).Include(t => t.Priority).FirstOrDefaultAsync(t => t.Id == ticketForum.Id);
|
||||||
|
|
||||||
|
Employee? employee = await _context.Employees.FirstOrDefaultAsync(e => e.Id == ticketForum.CreatedById);
|
||||||
|
|
||||||
|
|
||||||
|
ForumTicketVM ticketVM = ticket.ToForumTicketVMFromTicketForum(employee);
|
||||||
|
|
||||||
|
ticketVM.Tags = tagVMs;
|
||||||
|
|
||||||
|
List<TicketAttachmentVM> attachmentVMs = new List<TicketAttachmentVM>();
|
||||||
|
foreach (var attachment in attachments)
|
||||||
|
{
|
||||||
|
var document = documents.Find(d => d.Id == attachment.FileId);
|
||||||
|
string preSignedUrl = string.Empty;
|
||||||
|
if (document != null)
|
||||||
|
{
|
||||||
|
preSignedUrl = await _s3Service.GeneratePreSignedUrlAsync(document.S3Key);
|
||||||
|
}
|
||||||
|
attachmentVMs.Add(attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl));
|
||||||
|
}
|
||||||
|
ticketVM.Attachments = attachmentVMs;
|
||||||
|
_logger.LogInfo("Ticket created by Employee {EmployeeId}", ticketForum.CreatedById);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(ticketVM, "Ticket Created Successfully", 200));
|
||||||
|
}
|
||||||
|
_logger.LogWarning("Employee {EmployeeId} tries to create ticket in different Tenant", createTicketDto.CreatedById);
|
||||||
|
return Unauthorized(ApiResponse<object>.ErrorResponse("Not Authorized", "Not Authorized", 401));
|
||||||
|
}
|
||||||
|
[HttpPost("ticket/edit")]
|
||||||
|
public async Task<IActionResult> UpdateNewTicket([FromBody] UpdateTicketDto updateTicketDto)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
var errors = ModelState.Values
|
||||||
|
.SelectMany(v => v.Errors)
|
||||||
|
.Select(e => e.ErrorMessage)
|
||||||
|
.ToList();
|
||||||
|
_logger.LogError("{error}", errors);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
||||||
|
}
|
||||||
|
int tenantId = _userHelper.GetTenantId();
|
||||||
|
if (tenantId == updateTicketDto.TenantId)
|
||||||
|
{
|
||||||
|
var existingTicket = await _context.Tickets.Include(t => t.TicketTypeMaster).Include(t => t.TicketStatusMaster).Include(t => t.Priority).AsNoTracking().FirstOrDefaultAsync(t => t.Id == updateTicketDto.Id);
|
||||||
|
if (existingTicket != null)
|
||||||
|
{
|
||||||
|
TicketForum ticketForum = updateTicketDto.ToTicketForumFromUpdateTicketDto(existingTicket);
|
||||||
|
_context.Tickets.Update(ticketForum);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
|
||||||
|
List<TicketAttachment> attachments = new List<TicketAttachment>();
|
||||||
|
List<TicketTag> ticketTags = new List<TicketTag>();
|
||||||
|
List<TicketTagVM> tagVMs = new List<TicketTagVM>();
|
||||||
|
|
||||||
|
List<TicketAttachment> existingAttachments = await _context.TicketAttachments.Where(a => a.TicketId == updateTicketDto.Id).ToListAsync();
|
||||||
|
var existingattachmentids = existingAttachments.Select(a => a.Id).ToList();
|
||||||
|
var attachmentDtoids = updateTicketDto.Attachments.Select(a => a.Id).ToList();
|
||||||
|
foreach (var attachmentDto in updateTicketDto.Attachments)
|
||||||
|
{
|
||||||
|
if (!existingattachmentids.Contains(attachmentDto.Id) && attachmentDto.TicketId != updateTicketDto.Id)
|
||||||
|
{
|
||||||
|
byte[] fileBytes;
|
||||||
|
var Image = attachmentDto;
|
||||||
|
if (string.IsNullOrEmpty(Image.Base64Data))
|
||||||
|
{
|
||||||
|
_logger.LogError("Base64 data is missing");
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Base64 data is missing", "Base64 data is missing", 400));
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//If base64 has a data URI prefix, strip it
|
||||||
|
var base64 = Image.Base64Data.Contains(",")
|
||||||
|
? Image.Base64Data.Substring(Image.Base64Data.IndexOf(",") + 1)
|
||||||
|
: Image.Base64Data;
|
||||||
|
|
||||||
|
fileBytes = Convert.FromBase64String(base64);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("{error}", ex.Message);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse(ex.Message, ex, 400)); ;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var stream = new MemoryStream(fileBytes);
|
||||||
|
|
||||||
|
|
||||||
|
string fileName = _s3Service.GenerateFileName(Image.ContentType, tenantId, string.Empty);
|
||||||
|
|
||||||
|
var objectKey = await _s3Service.UploadFileAsync(stream, fileName, Image.ContentType);
|
||||||
|
|
||||||
|
Document document = attachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, updateTicketDto.CreatedAt, tenantId);
|
||||||
|
_context.Documents.Add(document);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
var attachment = attachmentDto.ToTicketAttachmentFromForumAttachmentDto(ticketForum.Id, document.Id);
|
||||||
|
attachments.Add(attachment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (attachments.Count != 0)
|
||||||
|
{
|
||||||
|
_context.TicketAttachments.AddRange(attachments);
|
||||||
|
}
|
||||||
|
var deletedAttachments = existingAttachments.Where(a => !attachmentDtoids.Contains(a.Id) && a.CommentId == null).ToList();
|
||||||
|
var deletedFileIds = deletedAttachments.Select(a => a.FileId).ToList();
|
||||||
|
if (deletedFileIds.Count != 0)
|
||||||
|
{
|
||||||
|
List<Document> existingDocuments = await _context.Documents.Where(d => deletedFileIds.Contains(d.Id)).ToListAsync();
|
||||||
|
foreach (var existingDocument in existingDocuments)
|
||||||
|
{
|
||||||
|
await _s3Service.DeleteFileAsync(existingDocument.S3Key);
|
||||||
|
//await _s3Service.DeleteFileAsync(existingDocument.ThumbS3Key);
|
||||||
|
}
|
||||||
|
_context.TicketAttachments.RemoveRange(deletedAttachments);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TicketTag> existingTicketTags = await _context.TicketTags.Where(t => t.TicketId == updateTicketDto.Id).ToListAsync();
|
||||||
|
List<TicketTagMaster>? tagMasters = await _context.TicketTagMasters.Where(t => updateTicketDto.TagIds.Contains(t.Id)).ToListAsync();
|
||||||
|
var existingTicketTagIds = existingTicketTags.Select(t => t.TagId).ToList();
|
||||||
|
|
||||||
|
foreach (var ticketTag in tagMasters)
|
||||||
|
{
|
||||||
|
TicketTagVM tagVM = ticketTag.ToTicketTagVMFromTicketTagMaster();
|
||||||
|
|
||||||
|
TicketTag tag = new TicketTag
|
||||||
|
{
|
||||||
|
TicketId = ticketForum.Id,
|
||||||
|
TagId = ticketTag.Id
|
||||||
|
};
|
||||||
|
tagVMs.Add(tagVM);
|
||||||
|
var demo = !existingTicketTagIds.Contains(tag.TagId);
|
||||||
|
if (!existingTicketTagIds.Contains(tag.TagId))
|
||||||
|
{
|
||||||
|
ticketTags.Add(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ticketTags != null)
|
||||||
|
{
|
||||||
|
_context.TicketTags.AddRange(ticketTags);
|
||||||
|
}
|
||||||
|
var deletedTicketTags = existingTicketTags.Where(t => !updateTicketDto.TagIds.Contains(t.TagId)).ToList();
|
||||||
|
if (deletedTicketTags.Count != 0)
|
||||||
|
{
|
||||||
|
_context.TicketTags.RemoveRange(deletedTicketTags);
|
||||||
|
}
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
var ticket = await _context.Tickets.Include(t => t.TicketTypeMaster).Include(t => t.TicketStatusMaster).Include(t => t.Priority).FirstOrDefaultAsync(t => t.Id == ticketForum.Id);
|
||||||
|
|
||||||
|
List<TicketComment> comments = await _context.TicketComments.Where(c => c.TicketId == ticket.Id).ToListAsync();
|
||||||
|
var authorIds = comments.Select(c => c.AuthorId.ToString()).ToList();
|
||||||
|
|
||||||
|
List<Employee>? employees = await _context.Employees.Where(e => e.Id == ticketForum.CreatedById || authorIds.Contains(e.ApplicationUserId ?? "")).ToListAsync();
|
||||||
|
|
||||||
|
Employee employee = employees.Find(e => e.Id == ticketForum.CreatedById);
|
||||||
|
ForumTicketVM ticketVM = ticket.ToForumTicketVMFromTicketForum(employee);
|
||||||
|
|
||||||
|
ticketVM.Tags = tagVMs;
|
||||||
|
|
||||||
|
List<TicketCommentVM> commentVMs = new List<TicketCommentVM>();
|
||||||
|
foreach (var comment in comments)
|
||||||
|
{
|
||||||
|
employee = employees.Find(e => e.ApplicationUserId == comment.AuthorId.ToString()) ?? new Employee();
|
||||||
|
commentVMs.Add(comment.ToTicketCommentVMFromTicketComment(employee));
|
||||||
|
}
|
||||||
|
|
||||||
|
attachments = await _context.TicketAttachments.Where(a => a.TicketId == updateTicketDto.Id).ToListAsync();
|
||||||
|
var fileIds = attachments.Select(a => a.FileId).ToList();
|
||||||
|
List<Document> documents = await _context.Documents.Where(d => fileIds.Contains(d.Id)).ToListAsync();
|
||||||
|
List<TicketAttachmentVM> ticketAttachmentVMs = new List<TicketAttachmentVM>();
|
||||||
|
foreach (var attachment in attachments)
|
||||||
|
{
|
||||||
|
var document = documents.Find(d => d.Id == attachment.FileId);
|
||||||
|
string preSignedUrl = string.Empty;
|
||||||
|
if (document != null)
|
||||||
|
{
|
||||||
|
preSignedUrl = await _s3Service.GeneratePreSignedUrlAsync(document.S3Key);
|
||||||
|
}
|
||||||
|
if (attachment.CommentId == null)
|
||||||
|
{
|
||||||
|
ticketAttachmentVMs.Add(attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var commentVM = commentVMs.Find(c => c.Id == attachment.CommentId);
|
||||||
|
commentVM.Attachments.Add(attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ticketVM.Comments = commentVMs;
|
||||||
|
ticketVM.Attachments = ticketAttachmentVMs;
|
||||||
|
_logger.LogInfo("Ticket {TicketId} updated", updateTicketDto.Id);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(ticketVM, "Ticket Updated Successfully", 200));
|
||||||
|
}
|
||||||
|
_logger.LogError("Ticket {TicketId} not Found in database", updateTicketDto.Id);
|
||||||
|
return NotFound(ApiResponse<object>.ErrorResponse("Ticket not Found", "Ticket not Found", 404));
|
||||||
|
}
|
||||||
|
_logger.LogWarning("Employee {EmployeeId} tries to create ticket in different Tenant", updateTicketDto.CreatedById);
|
||||||
|
return Unauthorized(ApiResponse<object>.ErrorResponse("Not Authorized", "Not Authorized", 401));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("ticket/comment")]
|
||||||
public async Task<IActionResult> AddComment([FromBody] AddCommentDto addCommentDto)
|
public async Task<IActionResult> AddComment([FromBody] AddCommentDto addCommentDto)
|
||||||
{
|
{
|
||||||
return NotFound(ApiResponse<object>.ErrorResponse("Industry not found.", "Industry not found.", 404));
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
var errors = ModelState.Values
|
||||||
|
.SelectMany(v => v.Errors)
|
||||||
|
.Select(e => e.ErrorMessage)
|
||||||
|
.ToList();
|
||||||
|
_logger.LogError("{error}", errors);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("tickets/{id}/attachments")]
|
int tenantId = _userHelper.GetTenantId();
|
||||||
public async Task<IActionResult> UploadAttachments([FromBody] ForumAttachmentDto forumAttachmentDto)
|
List<TicketAttachment> attachments = new List<TicketAttachment>();
|
||||||
|
List<Document> documents = new List<Document>();
|
||||||
|
|
||||||
|
TicketComment comment = addCommentDto.ToTicketCommentFromAddCommentDto();
|
||||||
|
_context.TicketComments.Add(comment);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
if (addCommentDto.Attachments != null)
|
||||||
{
|
{
|
||||||
return NotFound(ApiResponse<object>.ErrorResponse("Industry not found.", "Industry not found.", 404));
|
foreach (var attachmentDto in addCommentDto.Attachments)
|
||||||
|
{
|
||||||
|
byte[] fileBytes;
|
||||||
|
var Image = attachmentDto;
|
||||||
|
if (string.IsNullOrEmpty(Image.Base64Data))
|
||||||
|
{
|
||||||
|
_logger.LogError("Base64 data is missing");
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Base64 data is missing", "Base64 data is missing", 400));
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//If base64 has a data URI prefix, strip it
|
||||||
|
var base64 = Image.Base64Data.Contains(",")
|
||||||
|
? Image.Base64Data.Substring(Image.Base64Data.IndexOf(",") + 1)
|
||||||
|
: Image.Base64Data;
|
||||||
|
|
||||||
|
fileBytes = Convert.FromBase64String(base64);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("{error}", ex.Message);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse(ex.Message, ex, 400)); ;
|
||||||
|
}
|
||||||
|
using var stream = new MemoryStream(fileBytes);
|
||||||
|
|
||||||
|
|
||||||
|
string fileName = _s3Service.GenerateFileName(Image.ContentType, tenantId, string.Empty);
|
||||||
|
|
||||||
|
var objectKey = await _s3Service.UploadFileAsync(stream, fileName, Image.ContentType);
|
||||||
|
|
||||||
|
Document document = attachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, addCommentDto.SentAt, tenantId);
|
||||||
|
_context.Documents.Add(document);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
documents.Add(document);
|
||||||
|
|
||||||
|
var attachment = attachmentDto.ToTicketAttachmentFromForumAttachmentDto(addCommentDto.TicketId, document.Id, comment.Id);
|
||||||
|
attachments.Add(attachment);
|
||||||
|
}
|
||||||
|
_context.TicketAttachments.AddRange(attachments);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
Employee employee = await _context.Employees.FirstOrDefaultAsync(e => e.ApplicationUserId == addCommentDto.AuthorId.ToString()) ?? new Employee();
|
||||||
|
TicketCommentVM commentVM = comment.ToTicketCommentVMFromTicketComment(employee);
|
||||||
|
|
||||||
|
List<TicketAttachmentVM> attachmentVMs = new List<TicketAttachmentVM>();
|
||||||
|
if (attachments != null)
|
||||||
|
{
|
||||||
|
foreach (var attachment in attachments)
|
||||||
|
{
|
||||||
|
var document = documents.Find(d => d.Id == attachment.FileId);
|
||||||
|
string preSignedUrl = string.Empty;
|
||||||
|
if (document != null)
|
||||||
|
{
|
||||||
|
preSignedUrl = await _s3Service.GeneratePreSignedUrlAsync(document.S3Key);
|
||||||
|
}
|
||||||
|
attachmentVMs.Add(attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
commentVM.Attachments = attachmentVMs;
|
||||||
|
|
||||||
|
_logger.LogInfo("User {ApplicationUserId} commented on a ticket", comment.AuthorId);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(commentVM, "Comment Created Successfully", 200));
|
||||||
|
}
|
||||||
|
[HttpPost("ticket/comment/edit")]
|
||||||
|
public async Task<IActionResult> EditComment([FromBody] UpdateCommentDto updateCommentDto)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
var errors = ModelState.Values
|
||||||
|
.SelectMany(v => v.Errors)
|
||||||
|
.Select(e => e.ErrorMessage)
|
||||||
|
.ToList();
|
||||||
|
_logger.LogError("{error}", errors);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPatch("tickets/{id}/status")]
|
int tenantId = _userHelper.GetTenantId();
|
||||||
public async Task<IActionResult> UpdateTicketStatus([FromBody] InquiryDto inquiryDto)
|
List<TicketAttachment> attachments = new List<TicketAttachment>();
|
||||||
|
|
||||||
|
TicketComment existingComment = await _context.TicketComments.AsNoTracking().FirstOrDefaultAsync(c => c.Id == updateCommentDto.Id) ?? new TicketComment();
|
||||||
|
TicketComment updateComment = updateCommentDto.ToTicketCommentFromUpdateCommentDto(tenantId, existingComment);
|
||||||
|
_context.TicketComments.Update(updateComment);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
List<TicketAttachment> existingAttachments = await _context.TicketAttachments.Where(a => a.CommentId == updateComment.Id).ToListAsync();
|
||||||
|
var existingattachmentids = existingAttachments.Select(a => a.Id).ToList();
|
||||||
|
var attachmentDtoids = updateCommentDto.Attachments.Select(a => a.Id).ToList();
|
||||||
|
|
||||||
|
foreach (var attachmentDto in updateCommentDto.Attachments)
|
||||||
{
|
{
|
||||||
return NotFound(ApiResponse<object>.ErrorResponse("Industry not found.", "Industry not found.", 404));
|
if (!existingattachmentids.Contains(attachmentDto.Id) && attachmentDto.CommentId != updateComment.Id)
|
||||||
|
{
|
||||||
|
byte[] fileBytes;
|
||||||
|
var Image = attachmentDto;
|
||||||
|
if (string.IsNullOrEmpty(Image.Base64Data))
|
||||||
|
{
|
||||||
|
_logger.LogError("Base64 data is missing");
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Base64 data is missing", "Base64 data is missing", 400));
|
||||||
}
|
}
|
||||||
[HttpGet("tickets/{id}")]
|
try
|
||||||
|
{
|
||||||
|
//If base64 has a data URI prefix, strip it
|
||||||
|
var base64 = Image.Base64Data.Contains(",")
|
||||||
|
? Image.Base64Data.Substring(Image.Base64Data.IndexOf(",") + 1)
|
||||||
|
: Image.Base64Data;
|
||||||
|
|
||||||
|
fileBytes = Convert.FromBase64String(base64);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("{error}", ex.Message);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse(ex.Message, ex, 400)); ;
|
||||||
|
}
|
||||||
|
using var stream = new MemoryStream(fileBytes);
|
||||||
|
|
||||||
|
|
||||||
|
string fileName = _s3Service.GenerateFileName(Image.ContentType, tenantId, string.Empty);
|
||||||
|
|
||||||
|
var objectKey = await _s3Service.UploadFileAsync(stream, fileName, Image.ContentType);
|
||||||
|
|
||||||
|
Document document = attachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, existingComment.SentAt, tenantId);
|
||||||
|
_context.Documents.Add(document);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
var attachment = attachmentDto.ToTicketAttachmentFromForumAttachmentDto(existingComment.TicketId, document.Id, updateComment.Id);
|
||||||
|
attachments.Add(attachment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (attachments.Count != 0)
|
||||||
|
{
|
||||||
|
_context.TicketAttachments.AddRange(attachments);
|
||||||
|
}
|
||||||
|
var deletedAttachments = existingAttachments.Where(a => !attachmentDtoids.Contains(a.Id) && a.CommentId != null).ToList();
|
||||||
|
var deletedFileIds = deletedAttachments.Select(a => a.FileId).ToList();
|
||||||
|
if (deletedFileIds.Count != 0)
|
||||||
|
{
|
||||||
|
List<Document> existingDocuments = await _context.Documents.Where(d => deletedFileIds.Contains(d.Id)).ToListAsync();
|
||||||
|
foreach (var existingDocument in existingDocuments)
|
||||||
|
{
|
||||||
|
await _s3Service.DeleteFileAsync(existingDocument.S3Key);
|
||||||
|
//await _s3Service.DeleteFileAsync(existingDocument.ThumbS3Key);
|
||||||
|
}
|
||||||
|
_context.TicketAttachments.RemoveRange(deletedAttachments);
|
||||||
|
}
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
Employee employee = await _context.Employees.FirstOrDefaultAsync(e => e.ApplicationUserId == existingComment.AuthorId.ToString()) ?? new Employee();
|
||||||
|
TicketCommentVM commentVM = updateComment.ToTicketCommentVMFromTicketComment(employee);
|
||||||
|
|
||||||
|
List<TicketAttachmentVM> attachmentVMs = new List<TicketAttachmentVM>();
|
||||||
|
attachments = await _context.TicketAttachments.Where(a => a.CommentId == updateCommentDto.Id).ToListAsync();
|
||||||
|
var fileIds = attachments.Select(a => a.FileId).ToList();
|
||||||
|
List<Document> documents = await _context.Documents.Where(d => fileIds.Contains(d.Id)).ToListAsync();
|
||||||
|
|
||||||
|
if (attachments != null)
|
||||||
|
{
|
||||||
|
foreach (var attachment in attachments)
|
||||||
|
{
|
||||||
|
var document = documents.Find(d => d.Id == attachment.FileId);
|
||||||
|
string preSignedUrl = string.Empty;
|
||||||
|
if (document != null)
|
||||||
|
{
|
||||||
|
preSignedUrl = await _s3Service.GeneratePreSignedUrlAsync(document.S3Key);
|
||||||
|
}
|
||||||
|
attachmentVMs.Add(attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
commentVM.Attachments = attachmentVMs;
|
||||||
|
|
||||||
|
_logger.LogInfo("comment {CommentId} was Updated", updateComment.Id);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(commentVM, "Comment Updated Successfully", 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("ticket/attachment")]
|
||||||
|
public async Task<IActionResult> UploadAttachments([FromBody] List<ForumAttachmentDto> forumAttachmentDtos)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
var errors = ModelState.Values
|
||||||
|
.SelectMany(v => v.Errors)
|
||||||
|
.Select(e => e.ErrorMessage)
|
||||||
|
.ToList();
|
||||||
|
_logger.LogError("{error}", errors);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
||||||
|
}
|
||||||
|
|
||||||
|
int tenantId = _userHelper.GetTenantId();
|
||||||
|
List<TicketAttachmentVM> ticketAttachmentVMs = new List<TicketAttachmentVM>();
|
||||||
|
|
||||||
|
foreach (var forumAttachmentDto in forumAttachmentDtos)
|
||||||
|
{
|
||||||
|
byte[] fileBytes;
|
||||||
|
if (string.IsNullOrEmpty(forumAttachmentDto.Base64Data))
|
||||||
|
{
|
||||||
|
_logger.LogError("Base64 data is missing");
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Base64 data is missing", "Base64 data is missing", 400));
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//If base64 has a data URI prefix, strip it
|
||||||
|
var base64 = forumAttachmentDto.Base64Data.Contains(",")
|
||||||
|
? forumAttachmentDto.Base64Data.Substring(forumAttachmentDto.Base64Data.IndexOf(",") + 1)
|
||||||
|
: forumAttachmentDto.Base64Data;
|
||||||
|
|
||||||
|
fileBytes = Convert.FromBase64String(base64);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("{error}", ex.Message);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse(ex.Message, ex, 400)); ;
|
||||||
|
}
|
||||||
|
using var stream = new MemoryStream(fileBytes);
|
||||||
|
|
||||||
|
|
||||||
|
string fileName = _s3Service.GenerateFileName(forumAttachmentDto.ContentType, tenantId, string.Empty);
|
||||||
|
|
||||||
|
var objectKey = await _s3Service.UploadFileAsync(stream, fileName, forumAttachmentDto.ContentType);
|
||||||
|
|
||||||
|
Document document = forumAttachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, forumAttachmentDto.SentAt, tenantId);
|
||||||
|
_context.Documents.Add(document);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
var attachment = forumAttachmentDto.ToTicketAttachmentFromForumAttachmentDto(forumAttachmentDto.TicketId, document.Id, forumAttachmentDto.CommentId);
|
||||||
|
_context.TicketAttachments.Add(attachment);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
string preSignedUrl = await _s3Service.GeneratePreSignedUrlAsync(document.S3Key);
|
||||||
|
|
||||||
|
TicketAttachmentVM attachmentVM = attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl);
|
||||||
|
ticketAttachmentVMs.Add(attachmentVM);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInfo("Attachments were added");
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(ticketAttachmentVMs, "attechments added Successfully", 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPatch("ticket/status/{id}")]
|
||||||
|
public async Task<IActionResult> UpdateTicketStatus(Guid id, [FromQuery] Guid statusId)
|
||||||
|
{
|
||||||
|
int tenantId = _userHelper.GetTenantId();
|
||||||
|
TicketForum ticket = await _context.Tickets.FirstOrDefaultAsync(t => t.Id == id && t.TenantId == tenantId) ?? new TicketForum();
|
||||||
|
ticket.StatusId = statusId;
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
ticket = await _context.Tickets.Include(t => t.TicketTypeMaster).Include(t => t.TicketStatusMaster).Include(t => t.Priority).FirstOrDefaultAsync(t => t.Id == id && t.TenantId == tenantId) ?? new TicketForum();
|
||||||
|
List<TicketComment> comments = await _context.TicketComments.Where(c => c.TicketId == ticket.Id).ToListAsync();
|
||||||
|
var authorIds = comments.Select(c => c.AuthorId.ToString()).ToList();
|
||||||
|
|
||||||
|
List<Employee> employees = await _context.Employees.Where(e => e.Id == ticket.CreatedById || authorIds.Contains(e.ApplicationUserId ?? "")).ToListAsync();
|
||||||
|
Employee employee = employees.Find(e => e.Id == ticket.CreatedById) ?? new Employee();
|
||||||
|
|
||||||
|
ForumTicketVM ticketVM = ticket.ToForumTicketVMFromTicketForum(employee);
|
||||||
|
|
||||||
|
var ticketTags = await _context.TicketTags.Where(t => t.TicketId == ticket.Id).ToListAsync();
|
||||||
|
List<Guid> tagIds = ticketTags.Select(t => t.TagId).ToList();
|
||||||
|
|
||||||
|
List<TicketTagMaster>? tagMasters = await _context.TicketTagMasters.Where(t => tagIds.Contains(t.Id)).ToListAsync();
|
||||||
|
List<TicketTagVM> tagVMs = new List<TicketTagVM>();
|
||||||
|
foreach (var ticketTag in tagMasters)
|
||||||
|
{
|
||||||
|
TicketTagVM tagVM = ticketTag.ToTicketTagVMFromTicketTagMaster();
|
||||||
|
tagVMs.Add(tagVM);
|
||||||
|
}
|
||||||
|
ticketVM.Tags = tagVMs;
|
||||||
|
|
||||||
|
List<TicketCommentVM> commentVMs = new List<TicketCommentVM>();
|
||||||
|
foreach (var comment in comments)
|
||||||
|
{
|
||||||
|
employee = employees.Find(e => e.ApplicationUserId == comment.AuthorId.ToString()) ?? new Employee();
|
||||||
|
commentVMs.Add(comment.ToTicketCommentVMFromTicketComment(employee));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TicketAttachment> attachments = await _context.TicketAttachments.Where(a => a.TicketId == id).ToListAsync();
|
||||||
|
List<Guid> fileIds = attachments.Select(a => a.FileId).ToList();
|
||||||
|
|
||||||
|
List<Document> documents = await _context.Documents.Where(d => fileIds.Contains(d.Id)).ToListAsync();
|
||||||
|
|
||||||
|
List<TicketAttachmentVM> ticketAttachmentVMs = new List<TicketAttachmentVM>();
|
||||||
|
foreach (var attachment in attachments)
|
||||||
|
{
|
||||||
|
var document = documents.Find(d => d.Id == attachment.FileId);
|
||||||
|
string preSignedUrl = string.Empty;
|
||||||
|
if (document != null)
|
||||||
|
{
|
||||||
|
preSignedUrl = await _s3Service.GeneratePreSignedUrlAsync(document.S3Key);
|
||||||
|
}
|
||||||
|
if (attachment.CommentId == null)
|
||||||
|
{
|
||||||
|
ticketAttachmentVMs.Add(attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var commentVM = commentVMs.Find(c => c.Id == attachment.CommentId);
|
||||||
|
commentVM.Attachments.Add(attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ticketVM.Comments = commentVMs;
|
||||||
|
ticketVM.Attachments = ticketAttachmentVMs;
|
||||||
|
|
||||||
|
_logger.LogInfo("Status of Ticket {TicketId} is changes to {status}", id, ticket.TicketStatusMaster.Name);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(ticketVM, "Ticket Fetched Successfully", 200));
|
||||||
|
}
|
||||||
|
[HttpGet("ticket/{id}")]
|
||||||
public async Task<IActionResult> GetTicketDetail(Guid id)
|
public async Task<IActionResult> GetTicketDetail(Guid id)
|
||||||
{
|
{
|
||||||
return NotFound(ApiResponse<object>.ErrorResponse("Industry not found.", "Industry not found.", 404));
|
int tenantId = _userHelper.GetTenantId();
|
||||||
|
TicketForum ticket = await _context.Tickets.Include(t => t.TicketTypeMaster).Include(t => t.TicketStatusMaster).Include(t => t.Priority).FirstOrDefaultAsync(t => t.Id == id && t.TenantId == tenantId) ?? new TicketForum();
|
||||||
|
List<TicketComment> comments = await _context.TicketComments.Where(c => c.TicketId == ticket.Id).ToListAsync();
|
||||||
|
var authorIds = comments.Select(c => c.AuthorId.ToString()).ToList();
|
||||||
|
|
||||||
|
List<Employee> employees = await _context.Employees.Where(e => e.Id == ticket.CreatedById || authorIds.Contains(e.ApplicationUserId ?? "")).ToListAsync();
|
||||||
|
Employee employee = employees.Find(e => e.Id == ticket.CreatedById) ?? new Employee();
|
||||||
|
|
||||||
|
ForumTicketVM ticketVM = ticket.ToForumTicketVMFromTicketForum(employee);
|
||||||
|
|
||||||
|
var ticketTags = await _context.TicketTags.Where(t => t.TicketId == ticket.Id).ToListAsync();
|
||||||
|
List<Guid> tagIds = ticketTags.Select(t => t.TagId).ToList();
|
||||||
|
|
||||||
|
List<TicketTagMaster>? tagMasters = await _context.TicketTagMasters.Where(t => tagIds.Contains(t.Id)).ToListAsync();
|
||||||
|
List<TicketTagVM> tagVMs = new List<TicketTagVM>();
|
||||||
|
foreach (var ticketTag in tagMasters)
|
||||||
|
{
|
||||||
|
TicketTagVM tagVM = ticketTag.ToTicketTagVMFromTicketTagMaster();
|
||||||
|
tagVMs.Add(tagVM);
|
||||||
|
}
|
||||||
|
ticketVM.Tags = tagVMs;
|
||||||
|
|
||||||
|
List<TicketCommentVM> commentVMs = new List<TicketCommentVM>();
|
||||||
|
foreach (var comment in comments)
|
||||||
|
{
|
||||||
|
employee = employees.Find(e => e.ApplicationUserId == comment.AuthorId.ToString()) ?? new Employee();
|
||||||
|
commentVMs.Add(comment.ToTicketCommentVMFromTicketComment(employee));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TicketAttachment> attachments = await _context.TicketAttachments.Where(a => a.TicketId == id).ToListAsync();
|
||||||
|
List<Guid> fileIds = attachments.Select(a => a.FileId).ToList();
|
||||||
|
|
||||||
|
List<Document> documents = await _context.Documents.Where(d => fileIds.Contains(d.Id)).ToListAsync();
|
||||||
|
|
||||||
|
List<TicketAttachmentVM> ticketAttachmentVMs = new List<TicketAttachmentVM>();
|
||||||
|
foreach (var attachment in attachments)
|
||||||
|
{
|
||||||
|
var document = documents.Find(d => d.Id == attachment.FileId);
|
||||||
|
string preSignedUrl = string.Empty;
|
||||||
|
if (document != null)
|
||||||
|
{
|
||||||
|
preSignedUrl = await _s3Service.GeneratePreSignedUrlAsync(document.S3Key);
|
||||||
|
}
|
||||||
|
if (attachment.CommentId == null)
|
||||||
|
{
|
||||||
|
ticketAttachmentVMs.Add(attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var commentVM = commentVMs.Find(c => c.Id == attachment.CommentId);
|
||||||
|
commentVM.Attachments.Add(attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ticketVM.Comments = commentVMs;
|
||||||
|
ticketVM.Attachments = ticketAttachmentVMs;
|
||||||
|
|
||||||
|
_logger.LogInfo("Fetched Ticket {TicketId}", id);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(ticketVM, "Ticket Fetched Successfully", 200));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("tickets")]
|
[HttpGet("tickets")]
|
||||||
public async Task<IActionResult> ListTickets([FromBody] InquiryDto inquiryDto)
|
public async Task<IActionResult> ListTickets()
|
||||||
{
|
{
|
||||||
return NotFound(ApiResponse<object>.ErrorResponse("Industry not found.", "Industry not found.", 404));
|
int tenantId = _userHelper.GetTenantId();
|
||||||
|
List<TicketForum> tickets = await _context.Tickets.Include(t => t.TicketTypeMaster).Include(t => t.TicketStatusMaster).Include(t => t.Priority).Where(t => t.TenantId == tenantId).ToListAsync();
|
||||||
|
var createdByIds = tickets.Select(t => t.CreatedById).ToList();
|
||||||
|
var ticketIds = tickets.Select(t => t.Id).ToList();
|
||||||
|
|
||||||
|
List<TicketComment> ticketComments = await _context.TicketComments.Where(c => ticketIds.Contains(c.TicketId)).ToListAsync();
|
||||||
|
var authorIds = ticketComments.Select(c => c.AuthorId.ToString()).ToList();
|
||||||
|
|
||||||
|
List<Employee> employees = await _context.Employees.Where(e => createdByIds.Contains(e.Id) || authorIds.Contains(e.ApplicationUserId)).ToListAsync();
|
||||||
|
|
||||||
|
var ticketTags = await _context.TicketTags.Where(t => ticketIds.Contains(t.TicketId)).ToListAsync();
|
||||||
|
List<Guid> tagIds = ticketTags.Select(t => t.TagId).ToList();
|
||||||
|
|
||||||
|
List<TicketTagMaster>? tagMasters = await _context.TicketTagMasters.Where(t => tagIds.Contains(t.Id)).ToListAsync();
|
||||||
|
|
||||||
|
List<TicketAttachment> ticketAttachments = await _context.TicketAttachments.Where(a => ticketIds.Contains(a.TicketId)).ToListAsync();
|
||||||
|
List<Guid> documentIds = ticketAttachments.Select(a => a.FileId).ToList();
|
||||||
|
|
||||||
|
List<Document> documents = await _context.Documents.Where(d => documentIds.Contains(d.Id)).ToListAsync();
|
||||||
|
|
||||||
|
List<ForumTicketVM> ticketVMs = new List<ForumTicketVM>();
|
||||||
|
foreach (var ticket in tickets)
|
||||||
|
{
|
||||||
|
Employee employee = employees.Find(e => e.Id == ticket.CreatedById) ?? new Employee();
|
||||||
|
ForumTicketVM ticketVM = ticket.ToForumTicketVMFromTicketForum(employee);
|
||||||
|
|
||||||
|
var ticketTagMappers = ticketTags.Where(t => t.TicketId == ticket.Id).ToList();
|
||||||
|
List<Guid> ticketTagIds = ticketTagMappers.Select(t => t.TagId).ToList();
|
||||||
|
|
||||||
|
List<TicketTagMaster> ticketTagMasters = tagMasters.Where(t => ticketTagIds.Contains(t.Id)).ToList();
|
||||||
|
|
||||||
|
List<TicketTagVM> tagVMs = new List<TicketTagVM>();
|
||||||
|
foreach (var ticketTag in ticketTagMasters)
|
||||||
|
{
|
||||||
|
TicketTagVM tagVM = ticketTag.ToTicketTagVMFromTicketTagMaster();
|
||||||
|
tagVMs.Add(tagVM);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TicketComment> comments = ticketComments.Where(c => c.TicketId == ticket.Id).ToList();
|
||||||
|
List<TicketCommentVM> commentVMs = new List<TicketCommentVM>();
|
||||||
|
foreach (var comment in comments)
|
||||||
|
{
|
||||||
|
employee = employees.Find(e => e.ApplicationUserId == comment.AuthorId.ToString()) ?? new Employee();
|
||||||
|
commentVMs.Add(comment.ToTicketCommentVMFromTicketComment(employee));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TicketAttachment> attachments = ticketAttachments.Where(a => a.TicketId == ticket.Id).ToList();
|
||||||
|
List<Guid> fileIds = attachments.Select(a => a.FileId).ToList();
|
||||||
|
|
||||||
|
List<Document> files = documents.Where(d => fileIds.Contains(d.Id)).ToList();
|
||||||
|
|
||||||
|
List<TicketAttachmentVM> ticketAttachmentVMs = new List<TicketAttachmentVM>();
|
||||||
|
foreach (var attachment in attachments)
|
||||||
|
{
|
||||||
|
var document = documents.Find(d => d.Id == attachment.FileId);
|
||||||
|
string preSignedUrl = string.Empty;
|
||||||
|
if (document != null)
|
||||||
|
{
|
||||||
|
preSignedUrl = await _s3Service.GeneratePreSignedUrlAsync(document.S3Key);
|
||||||
|
}
|
||||||
|
if (attachment.CommentId == null)
|
||||||
|
{
|
||||||
|
ticketAttachmentVMs.Add(attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var commentVM = commentVMs.Find(c => c.Id == attachment.CommentId);
|
||||||
|
commentVM.Attachments.Add(attachment.ToTicketAttachmentVMFromTicketAttachment(preSignedUrl, preSignedUrl));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ticketVM.Comments = commentVMs;
|
||||||
|
ticketVM.Attachments = ticketAttachmentVMs;
|
||||||
|
ticketVM.Tags = tagVMs;
|
||||||
|
ticketVMs.Add(ticketVM);
|
||||||
|
}
|
||||||
|
_logger.LogInfo("{count} tickets records fetched successfully from tenant {tenantId}", ticketVMs.Count, tenantId);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(ticketVMs, System.String.Format("{0} tickets records fetched successfully", ticketVMs.Count), 200));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
using Marco.Pms.DataAccess.Data;
|
using Marco.Pms.DataAccess.Data;
|
||||||
using Marco.Pms.Model.Dtos.Activities;
|
using Marco.Pms.Model.Dtos.Activities;
|
||||||
using Marco.Pms.Model.Entitlements;
|
using Marco.Pms.Model.Entitlements;
|
||||||
|
using Marco.Pms.Model.Forum;
|
||||||
using Marco.Pms.Model.Mapper;
|
using Marco.Pms.Model.Mapper;
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Marco.Pms.Model.ViewModels.Activities;
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
|
using Marco.Pms.Model.ViewModels.Forum;
|
||||||
using MarcoBMS.Services.Helpers;
|
using MarcoBMS.Services.Helpers;
|
||||||
|
using MarcoBMS.Services.Service;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@ -18,10 +21,12 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
{
|
{
|
||||||
private readonly ApplicationDbContext _context;
|
private readonly ApplicationDbContext _context;
|
||||||
private readonly UserHelper _userHelper;
|
private readonly UserHelper _userHelper;
|
||||||
public MasterController(ApplicationDbContext context, UserHelper userHelper)
|
private readonly ILoggingService _logger;
|
||||||
|
public MasterController(ApplicationDbContext context, UserHelper userHelper, ILoggingService logger)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_userHelper = userHelper;
|
_userHelper = userHelper;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("activities")]
|
[Route("activities")]
|
||||||
@ -30,14 +35,15 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
var tenantId = _userHelper.GetTenantId();
|
var tenantId = _userHelper.GetTenantId();
|
||||||
var activities = await _context.ActivityMasters.Where(c => c.TenantId == tenantId && c.IsActive == true).ToListAsync();
|
var activities = await _context.ActivityMasters.Where(c => c.TenantId == tenantId && c.IsActive == true).ToListAsync();
|
||||||
List<ActivityVM> activitiesVM = new List<ActivityVM>();
|
List<ActivityVM> activitiesVM = new List<ActivityVM>();
|
||||||
foreach (var activity in activities) {
|
foreach (var activity in activities)
|
||||||
|
{
|
||||||
var checkList = await _context.ActivityCheckLists.Where(c => c.TenantId == tenantId && c.ActivityId == activity.Id).ToListAsync();
|
var checkList = await _context.ActivityCheckLists.Where(c => c.TenantId == tenantId && c.ActivityId == activity.Id).ToListAsync();
|
||||||
List<CheckListVM> checkListVM = new List<CheckListVM>();
|
List<CheckListVM> checkListVM = new List<CheckListVM>();
|
||||||
if(checkList != null)
|
if (checkList != null)
|
||||||
{
|
{
|
||||||
foreach (ActivityCheckList check in checkList)
|
foreach (ActivityCheckList check in checkList)
|
||||||
{
|
{
|
||||||
var checkVM = check.ToCheckListVMFromActivityCheckList(activity.Id,false);
|
var checkVM = check.ToCheckListVMFromActivityCheckList(activity.Id, false);
|
||||||
checkListVM.Add(checkVM);
|
checkListVM.Add(checkVM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,7 +51,8 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
ActivityVM activityVM = activity.ToActivityVMFromActivityMaster(checkListVM);
|
ActivityVM activityVM = activity.ToActivityVMFromActivityMaster(checkListVM);
|
||||||
activitiesVM.Add(activityVM);
|
activitiesVM.Add(activityVM);
|
||||||
}
|
}
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(activitiesVM, "Success.", 200));
|
_logger.LogInfo("{count} activity records fetched successfully from tenant {tenantId}", activitiesVM.Count, tenantId);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(activitiesVM, System.String.Format("{0} activity records fetched successfully", activitiesVM.Count), 200));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("activity")]
|
[HttpPost("activity")]
|
||||||
@ -55,81 +62,87 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
var employee = await _userHelper.GetCurrentEmployeeAsync();
|
var employee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
if (employee.TenantId != tenantId)
|
if (employee.TenantId != tenantId)
|
||||||
{
|
{
|
||||||
|
_logger.LogWarning("User from tenant {employeeTenantId} tries to access data from tenant {tenantId}", employee.TenantId, tenantId);
|
||||||
return Unauthorized(ApiResponse<object>.ErrorResponse("Current tenant did not match with user's tenant", "Current tenant did not match with user's tenant", 401));
|
return Unauthorized(ApiResponse<object>.ErrorResponse("Current tenant did not match with user's tenant", "Current tenant did not match with user's tenant", 401));
|
||||||
}
|
}
|
||||||
var activityMaster = createActivity.ToActivityMasterFromCreateActivityMasterDto(tenantId);
|
var activityMaster = createActivity.ToActivityMasterFromCreateActivityMasterDto(tenantId);
|
||||||
_context.ActivityMasters.Add(activityMaster);
|
_context.ActivityMasters.Add(activityMaster);
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
if (createActivity.CheckList != null) {
|
|
||||||
List<ActivityCheckList> activityCheckList = new List<ActivityCheckList>();
|
|
||||||
foreach (var check in createActivity.CheckList)
|
|
||||||
{
|
|
||||||
ActivityCheckList checkList = check.ToActivityCheckListFromCreateCheckListDto(tenantId,activityMaster.Id);
|
|
||||||
activityCheckList.Add(checkList);
|
|
||||||
}
|
|
||||||
_context.ActivityCheckLists.AddRange(activityCheckList);
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
List<CheckListVM> checkListVM = new List<CheckListVM>();
|
List<CheckListVM> checkListVM = new List<CheckListVM>();
|
||||||
foreach (ActivityCheckList check in activityCheckList)
|
|
||||||
{
|
|
||||||
var checkVM = check.ToCheckListVMFromActivityCheckList(activityMaster.Id,false);
|
|
||||||
checkListVM.Add(checkVM);
|
|
||||||
}
|
|
||||||
|
|
||||||
ActivityVM activityVM = activityMaster.ToActivityVMFromActivityMaster(checkListVM);
|
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(activityVM, "Activity created successfully", 200));
|
|
||||||
}
|
|
||||||
return BadRequest(ApiResponse<object>.ErrorResponse("Check List is Empty", "Check List is Empty", 400));
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("edit/{id}")]
|
|
||||||
public async Task<IActionResult> UpdateActivity(int id, [FromBody] CreateActivityMasterDto createActivity)
|
|
||||||
{
|
|
||||||
var tenantId = _userHelper.GetTenantId();
|
|
||||||
var employee = await _userHelper.GetCurrentEmployeeAsync();
|
|
||||||
ActivityMaster? activity = await _context.ActivityMasters.FirstOrDefaultAsync(x => x.Id == id && x.IsActive == true && x.TenantId == tenantId);
|
|
||||||
if (activity != null && createActivity.UnitOfMeasurement != null && createActivity.ActivityName != null) {
|
|
||||||
|
|
||||||
activity.ActivityName = createActivity.ActivityName;
|
|
||||||
activity.UnitOfMeasurement = createActivity.UnitOfMeasurement;
|
|
||||||
|
|
||||||
if (createActivity.CheckList != null)
|
if (createActivity.CheckList != null)
|
||||||
{
|
{
|
||||||
List<ActivityCheckList> activityCheckList = new List<ActivityCheckList>();
|
List<ActivityCheckList> activityCheckList = new List<ActivityCheckList>();
|
||||||
foreach (var check in createActivity.CheckList)
|
foreach (var check in createActivity.CheckList)
|
||||||
{
|
{
|
||||||
ActivityCheckList checkList = check.ToActivityCheckListFromCreateCheckListDto(tenantId,activity.Id);
|
ActivityCheckList checkList = check.ToActivityCheckListFromCreateCheckListDto(tenantId, activityMaster.Id);
|
||||||
|
activityCheckList.Add(checkList);
|
||||||
|
}
|
||||||
|
_context.ActivityCheckLists.AddRange(activityCheckList);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
foreach (ActivityCheckList check in activityCheckList)
|
||||||
|
{
|
||||||
|
var checkVM = check.ToCheckListVMFromActivityCheckList(activityMaster.Id, false);
|
||||||
|
checkListVM.Add(checkVM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActivityVM activityVM = activityMaster.ToActivityVMFromActivityMaster(checkListVM);
|
||||||
|
|
||||||
|
_logger.LogInfo("activity created successfully from tenant {tenantId}", tenantId);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(activityVM, "activity created successfully", 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("activity/edit/{id}")]
|
||||||
|
public async Task<IActionResult> UpdateActivity(int id, [FromBody] CreateActivityMasterDto createActivity)
|
||||||
|
{
|
||||||
|
var tenantId = _userHelper.GetTenantId();
|
||||||
|
var employee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
ActivityMaster? activity = await _context.ActivityMasters.FirstOrDefaultAsync(x => x.Id == id && x.IsActive == true && x.TenantId == tenantId);
|
||||||
|
if (activity != null && createActivity.UnitOfMeasurement != null && createActivity.ActivityName != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
activity.ActivityName = createActivity.ActivityName;
|
||||||
|
activity.UnitOfMeasurement = createActivity.UnitOfMeasurement;
|
||||||
|
List<CheckListVM> checkListVM = new List<CheckListVM>();
|
||||||
|
|
||||||
|
if (createActivity.CheckList != null)
|
||||||
|
{
|
||||||
|
List<ActivityCheckList> activityCheckList = new List<ActivityCheckList>();
|
||||||
|
foreach (var check in createActivity.CheckList)
|
||||||
|
{
|
||||||
|
ActivityCheckList checkList = check.ToActivityCheckListFromCreateCheckListDto(tenantId, activity.Id);
|
||||||
activityCheckList.Add(checkList);
|
activityCheckList.Add(checkList);
|
||||||
}
|
}
|
||||||
_context.ActivityCheckLists.UpdateRange(activityCheckList);
|
_context.ActivityCheckLists.UpdateRange(activityCheckList);
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
List<CheckListVM> checkListVM = new List<CheckListVM>();
|
|
||||||
foreach (ActivityCheckList check in activityCheckList)
|
foreach (ActivityCheckList check in activityCheckList)
|
||||||
{
|
{
|
||||||
var checkVM = check.ToCheckListVMFromActivityCheckList(activity.Id, false);
|
var checkVM = check.ToCheckListVMFromActivityCheckList(activity.Id, false);
|
||||||
checkListVM.Add(checkVM);
|
checkListVM.Add(checkVM);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ActivityVM activityVM = activity.ToActivityVMFromActivityMaster(checkListVM);
|
ActivityVM activityVM = activity.ToActivityVMFromActivityMaster(checkListVM);
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(activityVM, "Activity created successfully", 200));
|
_logger.LogInfo("activity updated successfully from tenant {tenantId}", tenantId);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(activityVM, "activity updated successfully", 200));
|
||||||
}
|
}
|
||||||
|
_logger.LogError("Activity {ActivityId} not found", id);
|
||||||
|
return NotFound(ApiResponse<object>.ErrorResponse("Activity not found", "Activity not found", 404));
|
||||||
}
|
}
|
||||||
|
|
||||||
return NotFound(ApiResponse<object>.ErrorResponse("Activity no found", "Activity no found", 404));
|
[HttpDelete("activity/delete/{id}")]
|
||||||
}
|
|
||||||
#nullable disable
|
|
||||||
[HttpDelete("delete/{id}")]
|
|
||||||
public async Task<IActionResult> DeleteActivity(int Id)
|
public async Task<IActionResult> DeleteActivity(int Id)
|
||||||
{
|
{
|
||||||
int tenantId = _userHelper.GetTenantId();
|
int tenantId = _userHelper.GetTenantId();
|
||||||
var activity = await _context.ActivityMasters.FirstOrDefaultAsync(a => a.Id == Id && a.TenantId == tenantId);
|
var activity = await _context.ActivityMasters.FirstOrDefaultAsync(a => a.Id == Id && a.TenantId == tenantId);
|
||||||
if(activity != null)
|
if (activity != null)
|
||||||
{
|
{
|
||||||
activity.IsActive = false;
|
activity.IsActive = false;
|
||||||
}
|
}
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(null, "Activity Deleted Successfully", 200));
|
_logger.LogInfo("Activity Deleted Successfully from tenant {tenantId}", tenantId);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(new { }, "Activity Deleted Successfully", 200));
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("industries")]
|
[Route("industries")]
|
||||||
@ -138,7 +151,68 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
var tenantId = _userHelper.GetTenantId();
|
var tenantId = _userHelper.GetTenantId();
|
||||||
var industries = await _context.Industries.ToListAsync();
|
var industries = await _context.Industries.ToListAsync();
|
||||||
|
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(industries, "Success.", 200));
|
_logger.LogInfo("{count} industry records fetched successfully from tenant {tenantId}", industries.Count, tenantId);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(industries, System.String.Format("{0} industry records fetched successfully", industries.Count), 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("ticket-status")]
|
||||||
|
public async Task<IActionResult> GetTicketStatusMaster()
|
||||||
|
{
|
||||||
|
var tenantId = _userHelper.GetTenantId();
|
||||||
|
List<TicketStatusVM> statusVMs = new List<TicketStatusVM>();
|
||||||
|
List<TicketStatusMaster> statusMasters = await _context.TicketStatusMasters.Where(s => s.TenantId == tenantId).ToListAsync();
|
||||||
|
foreach (var statusMaster in statusMasters)
|
||||||
|
{
|
||||||
|
statusVMs.Add(statusMaster.ToTicketStatusVMFromTicketStatusMaster());
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInfo("{count} Ticket Status records fetched successfully from tenant {tenantId}", statusVMs.Count, tenantId);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(statusVMs, System.String.Format("{0} Ticket Status records fetched successfully", statusVMs.Count), 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("ticket-types")]
|
||||||
|
public async Task<IActionResult> GetTicketTypeMaster()
|
||||||
|
{
|
||||||
|
var tenantId = _userHelper.GetTenantId();
|
||||||
|
List<TicketTypeVM> typeVMs = new List<TicketTypeVM>();
|
||||||
|
List<TicketTypeMaster> typeMasters = await _context.TicketTypeMasters.Where(s => s.TenantId == tenantId).ToListAsync();
|
||||||
|
foreach (var typeMaster in typeMasters)
|
||||||
|
{
|
||||||
|
typeVMs.Add(typeMaster.ToTicketTypeVMFromTicketTypeMaster());
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInfo("{count} Ticket Type records fetched successfully from tenant {tenantId}", typeVMs.Count, tenantId);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(typeVMs, System.String.Format("{0} Ticket Type records fetched successfully", typeVMs.Count), 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("ticket-priorities")]
|
||||||
|
public async Task<IActionResult> GetTicketPriorityMaster()
|
||||||
|
{
|
||||||
|
var tenantId = _userHelper.GetTenantId();
|
||||||
|
List<TicketPriorityVM> priorityVMs = new List<TicketPriorityVM>();
|
||||||
|
List<TicketPriorityMaster> priorityMasters = await _context.TicketPriorityMasters.Where(s => s.TenantId == tenantId).ToListAsync();
|
||||||
|
foreach (var priorityMaster in priorityMasters)
|
||||||
|
{
|
||||||
|
priorityVMs.Add(priorityMaster.ToTicketPriorityVMFromTicketPriorityMaster());
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInfo("{count} Ticket Priority records fetched successfully from tenant {tenantId}", priorityVMs.Count, tenantId);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(priorityVMs, System.String.Format("{0} Ticket Priority records fetched successfully", priorityVMs.Count), 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("ticket-tags")]
|
||||||
|
public async Task<IActionResult> GetTicketTagMaster()
|
||||||
|
{
|
||||||
|
var tenantId = _userHelper.GetTenantId();
|
||||||
|
List<TicketTagVM> tagVMs = new List<TicketTagVM>();
|
||||||
|
List<TicketTagMaster> tagMasters = await _context.TicketTagMasters.Where(s => s.TenantId == tenantId).ToListAsync();
|
||||||
|
foreach (var tagMaster in tagMasters)
|
||||||
|
{
|
||||||
|
tagVMs.Add(tagMaster.ToTicketTagVMFromTicketTagMaster());
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInfo("{count} Ticket Tag records fetched successfully from tenant {tenantId}", tagVMs.Count, tenantId);
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(tagVMs, System.String.Format("{0} Ticket Tag records fetched successfully", tagVMs.Count), 200));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,12 +38,19 @@ namespace Marco.Pms.Services.Service
|
|||||||
ContentType = contentType,
|
ContentType = contentType,
|
||||||
AutoCloseStream = true
|
AutoCloseStream = true
|
||||||
};
|
};
|
||||||
|
try
|
||||||
|
{
|
||||||
var transferUtility = new TransferUtility(_s3Client);
|
var transferUtility = new TransferUtility(_s3Client);
|
||||||
await transferUtility.UploadAsync(uploadRequest);
|
await transferUtility.UploadAsync(uploadRequest);
|
||||||
_logger.LogInfo("File uploaded to Amazon S3");
|
_logger.LogInfo("File uploaded to Amazon S3");
|
||||||
return objectKey;
|
return objectKey;
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("{error} while uploading file to S3", ex.Message);
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
public async Task<string> GeneratePreSignedUrlAsync(string objectKey)
|
public async Task<string> GeneratePreSignedUrlAsync(string objectKey)
|
||||||
{
|
{
|
||||||
int expiresInMinutes = 1;
|
int expiresInMinutes = 1;
|
||||||
@ -54,11 +61,38 @@ namespace Marco.Pms.Services.Service
|
|||||||
Expires = DateTime.UtcNow.AddMinutes(expiresInMinutes),
|
Expires = DateTime.UtcNow.AddMinutes(expiresInMinutes),
|
||||||
Verb = HttpVerb.GET // for download
|
Verb = HttpVerb.GET // for download
|
||||||
};
|
};
|
||||||
|
try
|
||||||
|
{
|
||||||
string url = _s3Client.GetPreSignedURL(request);
|
string url = _s3Client.GetPreSignedURL(request);
|
||||||
_logger.LogInfo("Requested presigned url from Amazon S3");
|
_logger.LogInfo("Requested presigned url from Amazon S3");
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("{error} while requesting presigned url from Amazon S3", ex.Message);
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public async Task<bool> DeleteFileAsync(string objectKey)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var deleteRequest = new DeleteObjectRequest
|
||||||
|
{
|
||||||
|
BucketName = _bucketName,
|
||||||
|
Key = objectKey
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = await _s3Client.DeleteObjectAsync(deleteRequest);
|
||||||
|
_logger.LogInfo("File deleted from Amazon S3");
|
||||||
|
return response.HttpStatusCode == System.Net.HttpStatusCode.NoContent;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("{error} while deleting from Amazon S3", ex.Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
public string GenerateFileName(string contentType, int tenantId, string? name)
|
public string GenerateFileName(string contentType, int tenantId, string? name)
|
||||||
{
|
{
|
||||||
string extenstion = contentType.Split("/")[1];
|
string extenstion = contentType.Split("/")[1];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user