Compare commits

...

4 Commits

Author SHA1 Message Date
0aefcb97de Added call for lign API 2025-07-26 08:56:10 +05:30
c45d9238c8 Added an API to save multiple contacts in database 2025-07-25 17:31:11 +05:30
0f65ccace5 Add API interface to call API 2025-07-25 14:36:32 +05:30
9acb9974a0 Add a WPF project for utility application
- Import Director contact is implemented
2025-07-25 13:05:59 +05:30
15 changed files with 843 additions and 2 deletions

View File

@ -68,6 +68,37 @@ namespace Marco.Pms.Services.Controllers
} }
} }
[HttpPost("create/list")]
public async Task<IActionResult> CreateMultipleContacts([FromBody] List<CreateContactDto> createContacts)
{
if (!ModelState.IsValid)
{
var errors = ModelState.Values
.SelectMany(v => v.Errors)
.Select(e => e.ErrorMessage)
.ToList();
_logger.LogWarning("User sent Invalid Date while marking attendance");
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
}
List<object> successResponse = new List<object>();
List<object> errorResponse = new List<object>();
foreach (var createContact in createContacts)
{
var response = await _directoryHelper.CreateMultipleContacts(createContact);
if (response.StatusCode == 200)
{
successResponse.Add(response);
}
else
{
errorResponse.Add(response);
}
}
_logger.LogInfo("SucessCount : {SucessCount} , ErrorCount : {ErrorCount}", successResponse.Count, errorResponse.Count);
return Ok(errorResponse);
}
[HttpPost] [HttpPost]
public async Task<IActionResult> CreateContact([FromBody] CreateContactDto createContact) public async Task<IActionResult> CreateContact([FromBody] CreateContactDto createContact)
{ {

View File

@ -3,7 +3,6 @@ using Marco.Pms.Model.Directory;
using Marco.Pms.Model.Dtos.Directory; using Marco.Pms.Model.Dtos.Directory;
using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Entitlements;
using Marco.Pms.Model.Mapper; using Marco.Pms.Model.Mapper;
using Marco.Pms.Model.Projects;
using Marco.Pms.Model.Utilities; using Marco.Pms.Model.Utilities;
using Marco.Pms.Model.ViewModels.Directory; using Marco.Pms.Model.ViewModels.Directory;
using Marco.Pms.Model.ViewModels.Master; using Marco.Pms.Model.ViewModels.Master;
@ -11,19 +10,23 @@ using Marco.Pms.Model.ViewModels.Projects;
using Marco.Pms.Services.Service; using Marco.Pms.Services.Service;
using MarcoBMS.Services.Helpers; using MarcoBMS.Services.Helpers;
using MarcoBMS.Services.Service; using MarcoBMS.Services.Service;
using Microsoft.CodeAnalysis;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Project = Marco.Pms.Model.Projects.Project;
namespace Marco.Pms.Services.Helpers namespace Marco.Pms.Services.Helpers
{ {
public class DirectoryHelper public class DirectoryHelper
{ {
private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
private readonly ApplicationDbContext _context; private readonly ApplicationDbContext _context;
private readonly ILoggingService _logger; private readonly ILoggingService _logger;
private readonly UserHelper _userHelper; private readonly UserHelper _userHelper;
private readonly PermissionServices _permissionServices; private readonly PermissionServices _permissionServices;
public DirectoryHelper(ApplicationDbContext context, ILoggingService logger, UserHelper userHelper, PermissionServices permissionServices) public DirectoryHelper(IDbContextFactory<ApplicationDbContext> dbContextFactory, ApplicationDbContext context, ILoggingService logger, UserHelper userHelper, PermissionServices permissionServices)
{ {
_dbContextFactory = dbContextFactory;
_context = context; _context = context;
_logger = logger; _logger = logger;
_userHelper = userHelper; _userHelper = userHelper;
@ -295,12 +298,153 @@ namespace Marco.Pms.Services.Helpers
_logger.LogInfo("Employee ID {EmployeeId} sent an empty Bucket id", LoggedInEmployee.Id); _logger.LogInfo("Employee ID {EmployeeId} sent an empty Bucket id", LoggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Bucket ID is empty", "Bucket ID is empty", 400); return ApiResponse<object>.ErrorResponse("Bucket ID is empty", "Bucket ID is empty", 400);
} }
public async Task<ApiResponse<object>> CreateMultipleContacts(CreateContactDto createContact)
{
Guid tenantId = _userHelper.GetTenantId();
var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
Contact? contact = createContact.ToContactFromCreateContactDto(tenantId, LoggedInEmployee.Id);
_context.Contacts.Add(contact);
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException dbEx)
{
_logger.LogError(dbEx, "Databsae Exception occured while adding contact");
return ApiResponse<object>.ErrorResponse("Databsae Exception", createContact, 500);
}
_logger.LogInfo("Contact with ID {ContactId} created by Employee with ID {LoggedInEmployeeId}", contact.Id, LoggedInEmployee.Id);
var tagTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.ContactTagMasters.Where(t => t.TenantId == tenantId).ToListAsync();
});
var bucketIdsTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Buckets.Where(b => b.TenantId == tenantId).Select(b => b.Id).ToListAsync();
});
var projectIdsTask = Task.Run(async () =>
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Projects.Where(p => p.TenantId == tenantId).Select(p => p.Id).ToListAsync();
});
try
{
await Task.WhenAll(tagTask, bucketIdsTask, projectIdsTask);
}
catch (Exception dbEx)
{
_logger.LogError(dbEx, "Exception occured while fetching related table to contacts");
return ApiResponse<object>.ErrorResponse("Databsae Exception", createContact, 500);
}
var tags = tagTask.Result;
var tagNames = tags.Select(t => t.Name.ToLower()).ToList();
var bucketIds = bucketIdsTask.Result;
var projectIds = projectIdsTask.Result;
if (createContact.ContactPhones != null)
{
List<ContactPhone> phones = createContact.ContactPhones.Select(cp => cp.ToContactPhoneFromCreateContactPhoneDto(tenantId, contact.Id)).ToList();
_context.ContactsPhones.AddRange(phones);
_logger.LogInfo("{count} phone number are saved in contact with ID {ContactId} by employee with ID {LoggedEmployeeId}", phones.Count, contact.Id, LoggedInEmployee.Id);
}
if (createContact.ContactEmails != null)
{
List<ContactEmail> emails = createContact.ContactEmails.Select(ce => ce.ToContactEmailFromCreateContactEmailDto(tenantId, contact.Id)).ToList();
_context.ContactsEmails.AddRange(emails);
_logger.LogInfo("{count} email addresses are saved in contact with ID {ContactId} by employee with ID {LoggedEmployeeId}", emails.Count, contact.Id, LoggedInEmployee.Id);
}
if (createContact.BucketIds != null)
{
List<ContactBucketMapping> contactBucketMappings = createContact.BucketIds
.Where(b => bucketIds.Contains(b))
.Select(b => new ContactBucketMapping
{
BucketId = b,
ContactId = contact.Id
}).ToList();
_context.ContactBucketMappings.AddRange(contactBucketMappings);
_logger.LogInfo("Contact with ID {ContactId} added to {count} number of buckets by employee with ID {LoggedEmployeeId}", contact.Id, contactBucketMappings.Count, LoggedInEmployee.Id);
}
if (createContact.ProjectIds != null)
{
List<ContactProjectMapping> projectMappings = createContact.ProjectIds
.Where(p => projectIds.Contains(p))
.Select(p => new ContactProjectMapping
{
ProjectId = p,
ContactId = contact.Id,
TenantId = tenantId
})
.ToList();
_context.ContactProjectMappings.AddRange(projectMappings);
_logger.LogInfo("Contact with ID {ContactId} added to {count} number of project by employee with ID {LoggedEmployeeId}", contact.Id, projectMappings.Count, LoggedInEmployee.Id);
}
if (createContact.Tags != null)
{
List<ContactTagMapping> contactTagMappings = new List<ContactTagMapping>();
foreach (var tag in createContact.Tags)
{
if (tagNames.Contains(tag.Name.ToLower()))
{
ContactTagMaster existingTag = tags.Find(t => t.Name == tag.Name) ?? new ContactTagMaster();
_context.ContactTagMappings.Add(new ContactTagMapping
{
ContactId = contact.Id,
ContactTagId = tag.Id ?? existingTag.Id
});
}
else if (tag.Id == null || tags.Where(t => t.Name == tag.Name) == null)
{
var newtag = new ContactTagMaster
{
Name = tag.Name,
TenantId = tenantId
};
_context.ContactTagMasters.Add(newtag);
ContactTagMapping tagMapping = new ContactTagMapping
{
ContactTagId = newtag.Id,
ContactId = contact.Id
};
contactTagMappings.Add(tagMapping);
}
}
_context.ContactTagMappings.AddRange(contactTagMappings);
_logger.LogInfo("{count} number of tags added to Contact with ID {ContactId} by employee with ID {LoggedEmployeeId}", contactTagMappings.Count, contact.Id, LoggedInEmployee.Id);
}
try
{
await _context.SaveChangesAsync();
return ApiResponse<object>.SuccessResponse(true);
}
catch (DbUpdateException dbEx)
{
_logger.LogError(dbEx, "Databsae Exception occured while adding related entries to contacts");
return ApiResponse<object>.ErrorResponse("Databsae Exception", createContact, 500);
}
}
public async Task<ApiResponse<object>> CreateContact(CreateContactDto createContact) public async Task<ApiResponse<object>> CreateContact(CreateContactDto createContact)
{ {
Guid tenantId = _userHelper.GetTenantId(); Guid tenantId = _userHelper.GetTenantId();
var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
if (createContact != null) if (createContact != null)
{ {
List<ContactPhone> phones = new List<ContactPhone>(); List<ContactPhone> phones = new List<ContactPhone>();
List<ContactEmail> emails = new List<ContactEmail>(); List<ContactEmail> emails = new List<ContactEmail>();
List<ContactBucketMapping> contactBucketMappings = new List<ContactBucketMapping>(); List<ContactBucketMapping> contactBucketMappings = new List<ContactBucketMapping>();

View File

@ -0,0 +1,93 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
namespace Marco.Pms.UtilityApplication
{
internal class ApiService
{
private readonly HttpClient _httpClient;
private readonly string _apiUrl;
public ApiService(string apiUrl)
{
_httpClient = new HttpClient();
_apiUrl = apiUrl;
}
public async Task<bool> SendDataAsync<T>(T data, string token)
{
try
{
var jsonContent = JsonConvert.SerializeObject(data);
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage response = await _httpClient.PostAsync(_apiUrl, content);
response.EnsureSuccessStatusCode(); // Throws an exception if the HTTP response status is an error code.
string responseBody = await response.Content.ReadAsStringAsync();
// You can parse the responseBody if your API returns something useful
Console.WriteLine($"API Response: {responseBody}");
return true;
}
catch (HttpRequestException ex)
{
Console.WriteLine($"API request error: {ex.Message}");
// Log or handle the error appropriately in your UI
return false;
}
catch (JsonException ex)
{
Console.WriteLine($"JSON serialization error: {ex.Message}");
return false;
}
catch (Exception ex)
{
Console.WriteLine($"An unexpected error occurred: {ex.Message}");
return false;
}
}
public async Task<string> LoginAsync<T>(T data)
{
try
{
var jsonContent = JsonConvert.SerializeObject(data);
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
HttpResponseMessage response = await _httpClient.PostAsync(_apiUrl, content);
response.EnsureSuccessStatusCode(); // Throws an exception if the HTTP response status is an error code.
string responseBody = await response.Content.ReadAsStringAsync();
// You can parse the responseBody if your API returns something useful
Console.WriteLine($"API Response: {responseBody}");
var jObject = JObject.Parse(responseBody);
string jwt = jObject["data"]?["token"]?.ToString() ?? string.Empty; ;
return jwt;
}
catch (HttpRequestException ex)
{
Console.WriteLine($"API request error: {ex.Message}");
// Log or handle the error appropriately in your UI
return string.Empty;
}
catch (JsonException ex)
{
Console.WriteLine($"JSON serialization error: {ex.Message}");
return string.Empty;
}
catch (Exception ex)
{
Console.WriteLine($"An unexpected error occurred: {ex.Message}");
return string.Empty;
}
}
}
}

View File

@ -0,0 +1,9 @@
<Application x:Class="Marco.Pms.UtilityApplication.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Marco.Pms.UtilityApplication"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>

View File

@ -0,0 +1,14 @@
using System.Configuration;
using System.Data;
using System.Windows;
namespace Marco.Pms.UtilityApplication
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}

View File

@ -0,0 +1,10 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@ -0,0 +1,9 @@
namespace Marco.Pms.UtilityApplication
{
public class CategoryMaster
{
public string CategoryID { get; set; }
public string Categories { get; set; }
public string Description { get; set; }
}
}

View File

@ -0,0 +1,32 @@
using Marco.Pms.Model.Projects;
using System.Net;
using System.Xml.Linq;
namespace Marco.Pms.UtilityApplication
{
public class Contacts
{
public string BucketId { get; set; }
public string Owner { get; set; }
public string Name { get; set; }
public string Designation { get; set; }
public string Organization { get; set; }
public string Mobile1 { get; set; }
public string Mobile2 { get; set; }
public string Mobile3 { get; set; }
public string Email1 { get; set; }
public string Email2 { get; set; }
public string Location { get; set; }
public string Address { get; set; }
public string MoreInformation { get; set; }
public string Category { get; set; }
public Guid? CategoryId { get; set; }
public string Tags { get; set; }
public string Project { get; set; }
}
}

View File

@ -0,0 +1,349 @@
using Marco.Pms.Model.Dtos.Directory;
using OfficeOpenXml;
using System.IO;
using System.Net.Mail;
namespace Marco.Pms.UtilityApplication
{
public class DirectoryHelper
{
public async Task<(List<CreateContactDto>, List<Contacts>)> GenerateCreateContactDto(List<Contacts> contactsData, List<CategoryMaster> categoryMasters, List<TagsMaster> tagsMaster, List<ProjectMaster> projectMaster)
{
List<CreateContactDto> lstCreateContactDto = new List<CreateContactDto>();
List<Contacts> failedContacts = new List<Contacts>();
foreach (Contacts contact in contactsData)
{
if (contact.Name != "")
{
CreateContactDto dto = new CreateContactDto();
dto.Name = contact.Name;
dto.Organization = contact.Organization;
dto.Address = contact.Address;
dto.ContactCategoryId = GetContactCategoryID(contact, categoryMasters);
dto.Description = contact.MoreInformation;
dto.ContactPhones = GetContactPhones(contact);
dto.ContactEmails = GetContactEmails(contact);
dto.ProjectIds = GetContactProjectIDs(contact, projectMaster);
dto.BucketIds = GetContactBucketIDs(contact);
dto.Tags = GetContactTags(contact, tagsMaster);
lstCreateContactDto.Add(dto);
}
else
{
// export contact to log
failedContacts.Add(contact);
}
}
return (lstCreateContactDto, failedContacts);
}
private List<ContactTagDto>? GetContactTags(Contacts contact, List<TagsMaster> tagsMaster)
{
List<ContactTagDto> result = new List<ContactTagDto>();
foreach (string tag in contact.Tags.Split(","))
{
ContactTagDto dto = new ContactTagDto();
dto.Name = tag;
var tagObject = tagsMaster.SingleOrDefault(c => c.Tag == tag.Trim());
dto.Id = (tagObject != null && tagObject.TagID != "" ? Guid.Parse(tagObject.TagID) : null);
result.Add(dto);
}
return result;
}
private Guid? GetContactCategoryID(Contacts contact, List<CategoryMaster> categoryMaster)
{
if (contact.Category != "")
{
var category = categoryMaster.SingleOrDefault(c => c.Categories == contact.Category.Trim());
if (category != null && category.CategoryID != "")
{
return new Guid(category.CategoryID);
}
}
return null;
}
private List<Guid>? GetContactBucketIDs(Contacts contact)
{
List<Guid>? result = null;
if (contact.BucketId != "")
{
result = new List<Guid>();
result.Add(new Guid(contact.BucketId));
}
return result;
}
private List<CreateContactEmailDto>? GetContactEmails(Contacts contact)
{
List<CreateContactEmailDto> result = new List<CreateContactEmailDto>();
if (contact.Email1 != "" && IsValidEmailMailAddress(contact.Email1))
{
CreateContactEmailDto dto = new CreateContactEmailDto();
dto.Label = "Work";
dto.EmailAddress = contact.Email1;
result.Add(dto);
}
if (contact.Email2 != "" && IsValidEmailMailAddress(contact.Email2))
{
CreateContactEmailDto dto = new CreateContactEmailDto();
dto.Label = "Work";
dto.EmailAddress = contact.Email2;
result.Add(dto);
}
return result.Count > 0 ? result : null;
}
private List<Guid>? GetContactProjectIDs(Contacts contact, List<Marco.Pms.UtilityApplication.ProjectMaster> projectMasters)
{
List<Guid>? result = null;
if (contact.Project != "")
{
var category = projectMasters.SingleOrDefault(c => c.ProjectName == contact.Project.Trim());
if (category != null && category.ProjectID != "")
{
if (result == null) result = new List<Guid>();
result.Add(new Guid(category.ProjectID));
}
}
return result;
}
private List<CreateContactPhoneDto>? GetContactPhones(Contacts contact)
{
List<CreateContactPhoneDto> result = new List<CreateContactPhoneDto>();
if (contact.Mobile1 != "" && IsValidPhoneNumberBasic(contact.Mobile1))
{
CreateContactPhoneDto dto = new CreateContactPhoneDto();
dto.Label = "Office";
dto.PhoneNumber = contact.Mobile1;
result.Add(dto);
}
if (contact.Mobile2 != "" && IsValidPhoneNumberBasic(contact.Mobile2))
{
CreateContactPhoneDto dto = new CreateContactPhoneDto();
dto.Label = "Office";
dto.PhoneNumber = contact.Mobile2;
result.Add(dto);
}
if (contact.Mobile3 != "" && IsValidPhoneNumberBasic(contact.Mobile3))
{
CreateContactPhoneDto dto = new CreateContactPhoneDto();
dto.Label = "Office";
dto.PhoneNumber = contact.Mobile3;
result.Add(dto);
}
return result.Count > 0 ? result : null;
}
public static bool IsValidPhoneNumberBasic(string phoneNumber)
{
if (string.IsNullOrWhiteSpace(phoneNumber))
{
return false;
}
// Remove common non-digit characters for a cleaner check
string cleanedNumber = new string(phoneNumber.Where(char.IsDigit).ToArray());
// Basic check: Assume a typical phone number length (e.g., 7 to 15 digits)
// This is highly region-specific. For India, mobile numbers are usually 10 digits.
// For US, 10 digits for local, 11 with country code.
return cleanedNumber.Length >= 7 && cleanedNumber.Length <= 15;
}
public static bool IsValidEmailMailAddress(string email)
{
if (string.IsNullOrWhiteSpace(email))
{
return false;
}
try
{
// Attempt to create a MailAddress object.
// If the format is invalid, it will throw a FormatException.
MailAddress m = new MailAddress(email);
// Optional: You can add more specific checks here if needed,
// e.g., checking for specific domain names, but MailAddress itself is very good.
return true;
}
catch (FormatException)
{
// The email format is invalid.
return false;
}
catch (Exception ex)
{
// Catch any other unexpected exceptions.
Console.WriteLine($"An unexpected error occurred during email validation: {ex.Message}");
return false;
}
}
public async Task<(List<Contacts> contactsData, List<CategoryMaster> categoryMasters, List<TagsMaster> tagsMaster, List<ProjectMaster> projectMaster)> ReadExcelData(string filePath)
{
if (!File.Exists(filePath))
{
throw new FileNotFoundException($"Excel file not found at: {filePath}");
}
// Set the license context for EPPlus
// If you are using EPPlus in a commercial application, you need to acquire a commercial license.
// For non-commercial use or development, use the NonCommercial license context.
ExcelPackage.License.SetNonCommercialPersonal("Vikas");
List<Contacts> contactsData = new List<Contacts>();
List<CategoryMaster> categoryMasters = new List<CategoryMaster>();
List<TagsMaster> tagsMaster = new List<TagsMaster>();
List<ProjectMaster> projectMaster = new List<ProjectMaster>();
using (var package = new ExcelPackage(new FileInfo(filePath)))
{
// --- Read Transactions Sheet ---
ExcelWorksheet transactionsSheet = package.Workbook.Worksheets["CategoryMaster"]; // Assuming sheet name "Transactions"
if (transactionsSheet != null)
{
int rowCount = transactionsSheet.Dimension.Rows;
for (int row = 2; row <= rowCount; row++) // Assuming header in row 1
{
try
{
categoryMasters.Add(new CategoryMaster
{
CategoryID = transactionsSheet.Cells[row, 1].Text.Trim(),
Categories = transactionsSheet.Cells[row, 2].Text.Trim(),
Description = transactionsSheet.Cells[row, 3].Text.Trim(),
});
}
catch (FormatException ex)
{
Console.WriteLine($"Error parsing transaction data on row {row}: {ex.Message}");
// Optionally, skip row or log error more verbosely
}
}
}
else
{
Console.WriteLine("Transactions sheet not found in the Excel file.");
}
ExcelWorksheet tagsMasterSheet = package.Workbook.Worksheets["TagMaster"]; // Assuming sheet name "Transactions"
if (tagsMasterSheet != null)
{
int rowCount = tagsMasterSheet.Dimension.Rows;
for (int row = 2; row <= rowCount; row++) // Assuming header in row 1
{
try
{
tagsMaster.Add(new TagsMaster
{
TagID = tagsMasterSheet.Cells[row, 1].Text.Trim(),
Tag = tagsMasterSheet.Cells[row, 2].Text.Trim(),
});
}
catch (FormatException ex)
{
Console.WriteLine($"Error parsing tags data on row {row}: {ex.Message}");
// Optionally, skip row or log error more verbosely
}
}
}
else
{
Console.WriteLine("tags sheet not found in the Excel file.");
}
ExcelWorksheet projectsMasterSheet = package.Workbook.Worksheets["ProjectMaster"]; // Assuming sheet name "Transactions"
if (projectsMasterSheet != null)
{
int rowCount = projectsMasterSheet.Dimension.Rows;
for (int row = 2; row <= rowCount; row++) // Assuming header in row 1
{
try
{
projectMaster.Add(new ProjectMaster
{
ProjectID = projectsMasterSheet.Cells[row, 1].Text.Trim(),
ProjectName = projectsMasterSheet.Cells[row, 2].Text.Trim(),
});
}
catch (FormatException ex)
{
Console.WriteLine($"Error parsing projects data on row {row}: {ex.Message}");
// Optionally, skip row or log error more verbosely
}
}
}
else
{
Console.WriteLine("projects sheet not found in the Excel file.");
}
// --- Read Master Data Sheet ---
ExcelWorksheet masterSheet = package.Workbook.Worksheets["Contacts"]; // Assuming sheet name "MasterData"
if (masterSheet != null)
{
int rowCount = masterSheet.Dimension.Rows;
for (int row = 3; row <= rowCount; row++) // Assuming header in row 1
{
try
{
contactsData.Add(new Contacts
{
BucketId = masterSheet.Cells[row, 1].Text.Trim(),
Owner = masterSheet.Cells[row, 2].Text.Trim(),
Name = masterSheet.Cells[row, 3].Text.Trim(),
Designation = masterSheet.Cells[row, 4].Text.Trim(),
Organization = masterSheet.Cells[row, 5].Text.Trim(),
Mobile1 = masterSheet.Cells[row, 6].Text.Trim(),
Mobile2 = masterSheet.Cells[row, 7].Text.Trim(),
Mobile3 = masterSheet.Cells[row, 8].Text.Trim(),
Email1 = masterSheet.Cells[row, 9].Text.Trim(),
Email2 = masterSheet.Cells[row, 10].Text.Trim(),
Location = masterSheet.Cells[row, 11].Text.Trim(),
Address = masterSheet.Cells[row, 12].Text.Trim(),
MoreInformation = masterSheet.Cells[row, 13].Text.Trim(),
Category = masterSheet.Cells[row, 14].Text.Trim(),
Tags = masterSheet.Cells[row, 15].Text.Trim(),
Project = masterSheet.Cells[row, 16].Text.Trim()
});
}
catch (FormatException ex)
{
Console.WriteLine($"Error parsing master data on row {row}: {ex.Message}");
// Optionally, skip row or log error more verbosely
}
}
}
else
{
Console.WriteLine("MasterData sheet not found in the Excel file.");
}
}
return (contactsData, categoryMasters, tagsMaster, projectMaster);
}
}
}

View File

@ -0,0 +1,21 @@
<Window x:Class="Marco.Pms.UtilityApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Marco.Pms.UtilityApplication"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" WindowState="Maximized">
<Grid Margin="0,0,0,-113" UseLayoutRounding="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="7*"/>
<ColumnDefinition Width="93*"/>
</Grid.ColumnDefinitions>
<TextBox HorizontalAlignment="Left" Margin="80,36,0,0" TextWrapping="Wrap" Text="E:\Downloads\Directory Contacts - Marketing Team Yatin.xlsx" VerticalAlignment="Top" Width="508" Name="txtFilePath" FontSize="16" Grid.Column="1"/>
<Label Content="Select File" HorizontalAlignment="Left" Margin="36,30,0,0" VerticalAlignment="Top" Name="lblFileName" Height="29" Width="99" FontSize="16" Grid.ColumnSpan="2"/>
<Button Content="Upload File" HorizontalAlignment="Left" Margin="598,37,0,0" VerticalAlignment="Top" Name="btnFileUpload" FontSize="16" Click="btnFileUpload_Click" Width="118" Grid.Column="1"/>
<Button Content="Submit" HorizontalAlignment="Left" Margin="309,70,0,0" VerticalAlignment="Top" x:Name="btnSubmit" FontSize="16" RenderTransformOrigin="0.147,2.815" Click="btnSubmit_Click" Width="117" Grid.Column="1"/>
<DataGrid d:ItemsSource="{d:SampleData ItemCount=5}" Margin="0,118,0,0" Name="ContactsDataGrid" Grid.ColumnSpan="2"/>
</Grid>
</Window>

View File

@ -0,0 +1,88 @@
using Marco.Pms.Model.Dtos.Authentication;
using Marco.Pms.Model.Dtos.Directory;
using Microsoft.Win32;
using System.Windows;
namespace Marco.Pms.UtilityApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
//DirectoryHelper helper = new DirectoryHelper();
private readonly DirectoryHelper _directoryHelper;
private readonly ApiService _apiService;
private readonly ApiService _loginApiService;
// Replace with your actual API endpoint
private const string DirectoryApiEndpoint = "http://localhost:5032/api/directory/create/list";
private const string LoginApiEndpoint = "http://localhost:5032/api/auth/login";
public MainWindow()
{
InitializeComponent();
_apiService = new ApiService(DirectoryApiEndpoint);
_loginApiService = new ApiService(LoginApiEndpoint);
_directoryHelper = new DirectoryHelper();
}
private void btnFileUpload_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Excel files (*.xlsx)|*.xlsx|CSV files (*.csv)|*.csv"; // Optional: filter file types
if (openFileDialog.ShowDialog() == true)
{
string filePath = openFileDialog.FileName;
// Now you can use filePath to read or process the selected file
txtFilePath.Text = filePath;
//MessageBox.Show($"Selected file: {filePath}");
}
}
private async void btnSubmit_Click(object sender, RoutedEventArgs e)
{
List<Contacts> contactsData = null;
List<TagsMaster> tagsMaster = null;
List<ProjectMaster> projectMaster = null;
List<CategoryMaster> categoryMasters = null;
List<CreateContactDto> createContactDto = null;
List<Contacts> failedContacts = null;
(contactsData, categoryMasters, tagsMaster, projectMaster) = await _directoryHelper.ReadExcelData(txtFilePath.Text);
(createContactDto, failedContacts) = await _directoryHelper.GenerateCreateContactDto(contactsData, categoryMasters, tagsMaster, projectMaster);
// Check if there's data to display
if (failedContacts != null && failedContacts.Any())
{
// Assign the list to the DataGrid's ItemsSource
ContactsDataGrid.ItemsSource = failedContacts;
// You can optionally update a status text block
// StatusTextBlock.Text = $"Displayed {importedContacts.Count} contacts.";
}
else
{
// Clear the DataGrid if no data
ContactsDataGrid.ItemsSource = null;
// StatusTextBlock.Text = "No contacts to display.";
}
LoginDto loginDto = new LoginDto
{
Username = "admin@marcoaiot.com",
Password = "User@123"
};
string jwt = await _loginApiService.LoginAsync(loginDto);
bool success = await _apiService.SendDataAsync(createContactDto, jwt);
//foreach (Contacts contact in contactsData)
//{
// //.Text = $"Sending {apiDataList.Count} records to API...";
// bool success = await _apiService.SendDataAsync(contact);
//}
}
}
}

View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="EPPlus" Version="8.0.8" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Marco.Pms.Model\Marco.Pms.Model.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,8 @@
namespace Marco.Pms.UtilityApplication
{
public class ProjectMaster
{
public string ProjectID { get; set; }
public string ProjectName { get; set; }
}
}

View File

@ -0,0 +1,8 @@
namespace Marco.Pms.UtilityApplication
{
public class TagsMaster
{
public string TagID { get; set; }
public string Tag { get; set; }
}
}

View File

@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marco.Pms.Services", "Marco
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marco.Pms.CacheHelper", "Marco.Pms.CacheHelper\Marco.Pms.CacheHelper.csproj", "{1A105C22-4ED7-4F54-8834-6923DDD96852}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marco.Pms.CacheHelper", "Marco.Pms.CacheHelper\Marco.Pms.CacheHelper.csproj", "{1A105C22-4ED7-4F54-8834-6923DDD96852}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marco.Pms.UtilityApplication", "Marco.Pms.UtilityApplication\Marco.Pms.UtilityApplication.csproj", "{1F67DA6E-C4B4-4D48-8484-713F801772A5}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -39,6 +41,10 @@ Global
{1A105C22-4ED7-4F54-8834-6923DDD96852}.Debug|Any CPU.Build.0 = Debug|Any CPU {1A105C22-4ED7-4F54-8834-6923DDD96852}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A105C22-4ED7-4F54-8834-6923DDD96852}.Release|Any CPU.ActiveCfg = Release|Any CPU {1A105C22-4ED7-4F54-8834-6923DDD96852}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A105C22-4ED7-4F54-8834-6923DDD96852}.Release|Any CPU.Build.0 = Release|Any CPU {1A105C22-4ED7-4F54-8834-6923DDD96852}.Release|Any CPU.Build.0 = Release|Any CPU
{1F67DA6E-C4B4-4D48-8484-713F801772A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1F67DA6E-C4B4-4D48-8484-713F801772A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1F67DA6E-C4B4-4D48-8484-713F801772A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1F67DA6E-C4B4-4D48-8484-713F801772A5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE