deploy commited on
Commit ·
fc06b79
0
Parent(s):
Deploy restore contacts feature
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .dockerignore +17 -0
- ContactManagementAPI/ContactManagementAPI.csproj +22 -0
- ContactManagementAPI/Controllers/AccountController.cs +66 -0
- ContactManagementAPI/Controllers/AdminController.cs +1171 -0
- ContactManagementAPI/Controllers/DocumentController.cs +100 -0
- ContactManagementAPI/Controllers/HomeController.cs +1045 -0
- ContactManagementAPI/Controllers/PhotoController.cs +176 -0
- ContactManagementAPI/Data/ApplicationDbContext.cs +104 -0
- ContactManagementAPI/Migrations/20260206165849_InitialCreate.Designer.cs +305 -0
- ContactManagementAPI/Migrations/20260206165849_InitialCreate.cs +162 -0
- ContactManagementAPI/Migrations/20260208162549_MakeContactFieldsNullable.Designer.cs +291 -0
- ContactManagementAPI/Migrations/20260208162549_MakeContactFieldsNullable.cs +355 -0
- ContactManagementAPI/Migrations/20260209052719_AddSampleData.Designer.cs +291 -0
- ContactManagementAPI/Migrations/20260209052719_AddSampleData.cs +197 -0
- ContactManagementAPI/Migrations/20260209090000_AddUserSecurity.Designer.cs +463 -0
- ContactManagementAPI/Migrations/20260209090000_AddUserSecurity.cs +143 -0
- ContactManagementAPI/Migrations/20260216070933_AddNewContactGroups.Designer.cs +478 -0
- ContactManagementAPI/Migrations/20260216070933_AddNewContactGroups.cs +142 -0
- ContactManagementAPI/Migrations/20260220171502_AddContactIdentityBankGenderDobFields.Designer.cs +508 -0
- ContactManagementAPI/Migrations/20260220171502_AddContactIdentityBankGenderDobFields.cs +231 -0
- ContactManagementAPI/Migrations/20260220171919_AddContactBankAccountsTable.Designer.cs +557 -0
- ContactManagementAPI/Migrations/20260220171919_AddContactBankAccountsTable.cs +164 -0
- ContactManagementAPI/Migrations/20260221045734_AddPanNumberToContact.Designer.cs +560 -0
- ContactManagementAPI/Migrations/20260221045734_AddPanNumberToContact.cs +141 -0
- ContactManagementAPI/Migrations/ApplicationDbContextModelSnapshot.cs +557 -0
- ContactManagementAPI/Models/AdminHistoryEntry.cs +12 -0
- ContactManagementAPI/Models/AppUser.cs +33 -0
- ContactManagementAPI/Models/Contact.cs +46 -0
- ContactManagementAPI/Models/ContactBankAccount.cs +15 -0
- ContactManagementAPI/Models/ContactDocument.cs +17 -0
- ContactManagementAPI/Models/ContactGroup.cs +15 -0
- ContactManagementAPI/Models/ContactPhoto.cs +17 -0
- ContactManagementAPI/Models/GroupRight.cs +18 -0
- ContactManagementAPI/Models/RightsCatalog.cs +44 -0
- ContactManagementAPI/Models/UserGroup.cs +23 -0
- ContactManagementAPI/Models/UserRight.cs +18 -0
- ContactManagementAPI/Program.cs +179 -0
- ContactManagementAPI/Properties/launchSettings.json +37 -0
- ContactManagementAPI/Security/RequireRightAttribute.cs +49 -0
- ContactManagementAPI/Services/AdminHistoryService.cs +73 -0
- ContactManagementAPI/Services/AuthorizationService.cs +52 -0
- ContactManagementAPI/Services/ContactStatisticsService.cs +173 -0
- ContactManagementAPI/Services/FileUploadService.cs +142 -0
- ContactManagementAPI/Services/ImportExportService.cs +573 -0
- ContactManagementAPI/Services/SeedData.cs +333 -0
- ContactManagementAPI/Services/SessionKeys.cs +7 -0
- ContactManagementAPI/Services/UserContextService.cs +49 -0
- ContactManagementAPI/ViewModels/AdminViewModels.cs +111 -0
- ContactManagementAPI/Views/Account/AccessDenied.cshtml +11 -0
- ContactManagementAPI/Views/Account/Login.cshtml +42 -0
.dockerignore
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
**/bin/
|
| 2 |
+
**/obj/
|
| 3 |
+
**/.vs/
|
| 4 |
+
**/.vscode/
|
| 5 |
+
**/.git/
|
| 6 |
+
**/.venv/
|
| 7 |
+
|
| 8 |
+
Deployment/
|
| 9 |
+
Installers/
|
| 10 |
+
Published/
|
| 11 |
+
|
| 12 |
+
screenshots/
|
| 13 |
+
*.rar
|
| 14 |
+
*.zip
|
| 15 |
+
*.7z
|
| 16 |
+
*.pdf
|
| 17 |
+
*.docx
|
ContactManagementAPI/ContactManagementAPI.csproj
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<Project Sdk="Microsoft.NET.Sdk.Web">
|
| 2 |
+
|
| 3 |
+
<PropertyGroup>
|
| 4 |
+
<TargetFramework>net8.0</TargetFramework>
|
| 5 |
+
<Nullable>enable</Nullable>
|
| 6 |
+
<ImplicitUsings>enable</ImplicitUsings>
|
| 7 |
+
</PropertyGroup>
|
| 8 |
+
|
| 9 |
+
<ItemGroup>
|
| 10 |
+
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
| 11 |
+
<PackageReference Include="EPPlus" Version="7.0.0" />
|
| 12 |
+
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
|
| 13 |
+
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" />
|
| 14 |
+
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
|
| 15 |
+
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0">
|
| 16 |
+
<PrivateAssets>all</PrivateAssets>
|
| 17 |
+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
| 18 |
+
</PackageReference>
|
| 19 |
+
<PackageReference Include="QuestPDF" Version="2024.12.3" />
|
| 20 |
+
</ItemGroup>
|
| 21 |
+
|
| 22 |
+
</Project>
|
ContactManagementAPI/Controllers/AccountController.cs
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using ContactManagementAPI.Data;
|
| 2 |
+
using ContactManagementAPI.Models;
|
| 3 |
+
using ContactManagementAPI.Services;
|
| 4 |
+
using ContactManagementAPI.ViewModels;
|
| 5 |
+
using Microsoft.AspNetCore.Identity;
|
| 6 |
+
using Microsoft.AspNetCore.Mvc;
|
| 7 |
+
using Microsoft.EntityFrameworkCore;
|
| 8 |
+
|
| 9 |
+
namespace ContactManagementAPI.Controllers
|
| 10 |
+
{
|
| 11 |
+
public class AccountController : Controller
|
| 12 |
+
{
|
| 13 |
+
private readonly ApplicationDbContext _context;
|
| 14 |
+
private readonly PasswordHasher<AppUser> _passwordHasher = new();
|
| 15 |
+
|
| 16 |
+
public AccountController(ApplicationDbContext context)
|
| 17 |
+
{
|
| 18 |
+
_context = context;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
[HttpGet]
|
| 22 |
+
public IActionResult Login(string? returnUrl = null)
|
| 23 |
+
{
|
| 24 |
+
return View(new LoginViewModel { ReturnUrl = returnUrl });
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
[HttpPost]
|
| 28 |
+
[ValidateAntiForgeryToken]
|
| 29 |
+
public IActionResult Login(LoginViewModel model)
|
| 30 |
+
{
|
| 31 |
+
if (!ModelState.IsValid)
|
| 32 |
+
return View(model);
|
| 33 |
+
|
| 34 |
+
var user = _context.AppUsers
|
| 35 |
+
.Include(u => u.Group)
|
| 36 |
+
.FirstOrDefault(u => u.UserName == model.UserName);
|
| 37 |
+
|
| 38 |
+
if (user == null || !user.IsActive)
|
| 39 |
+
{
|
| 40 |
+
ModelState.AddModelError(string.Empty, "Invalid username or password.");
|
| 41 |
+
return View(model);
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
var result = _passwordHasher.VerifyHashedPassword(user, user.PasswordHash, model.Password);
|
| 45 |
+
if (result == PasswordVerificationResult.Failed)
|
| 46 |
+
{
|
| 47 |
+
ModelState.AddModelError(string.Empty, "Invalid username or password.");
|
| 48 |
+
return View(model);
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
HttpContext.Session.SetInt32(SessionKeys.UserId, user.Id);
|
| 52 |
+
return Redirect(string.IsNullOrWhiteSpace(model.ReturnUrl) ? "/" : model.ReturnUrl);
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
public IActionResult Logout()
|
| 56 |
+
{
|
| 57 |
+
HttpContext.Session.Clear();
|
| 58 |
+
return RedirectToAction("Login");
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
public IActionResult AccessDenied()
|
| 62 |
+
{
|
| 63 |
+
return View();
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
}
|
ContactManagementAPI/Controllers/AdminController.cs
ADDED
|
@@ -0,0 +1,1171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
using System.Linq;
|
| 3 |
+
using System.IO.Compression;
|
| 4 |
+
using Microsoft.Data.Sqlite;
|
| 5 |
+
using ContactManagementAPI.Data;
|
| 6 |
+
using ContactManagementAPI.Models;
|
| 7 |
+
using ContactManagementAPI.Security;
|
| 8 |
+
using ContactManagementAPI.Services;
|
| 9 |
+
using ContactManagementAPI.ViewModels;
|
| 10 |
+
using Microsoft.AspNetCore.Identity;
|
| 11 |
+
using Microsoft.AspNetCore.Mvc;
|
| 12 |
+
using Microsoft.EntityFrameworkCore;
|
| 13 |
+
|
| 14 |
+
namespace ContactManagementAPI.Controllers
|
| 15 |
+
{
|
| 16 |
+
public class AdminController : Controller
|
| 17 |
+
{
|
| 18 |
+
private readonly ApplicationDbContext _context;
|
| 19 |
+
private readonly UserContextService _userContextService;
|
| 20 |
+
private readonly AdminHistoryService _adminHistoryService;
|
| 21 |
+
private readonly IWebHostEnvironment _environment;
|
| 22 |
+
private readonly PasswordHasher<AppUser> _passwordHasher = new();
|
| 23 |
+
|
| 24 |
+
public AdminController(ApplicationDbContext context, UserContextService userContextService, AdminHistoryService adminHistoryService, IWebHostEnvironment environment)
|
| 25 |
+
{
|
| 26 |
+
_context = context;
|
| 27 |
+
_userContextService = userContextService;
|
| 28 |
+
_adminHistoryService = adminHistoryService;
|
| 29 |
+
_environment = environment;
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
private static bool IsSuperAdminUser(AppUser? user)
|
| 33 |
+
{
|
| 34 |
+
return user != null && string.Equals(user.UserName, SeedData.SuperAdminUserName, StringComparison.OrdinalIgnoreCase);
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
private static bool IsProtectedSystemUser(AppUser? user)
|
| 38 |
+
{
|
| 39 |
+
return user != null &&
|
| 40 |
+
(IsSuperAdminUser(user) || string.Equals(user.UserName, "admin", StringComparison.OrdinalIgnoreCase));
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
private ContactGroup? ResolveContactGroupForUserGroup(UserGroup? userGroup)
|
| 44 |
+
{
|
| 45 |
+
if (userGroup == null)
|
| 46 |
+
{
|
| 47 |
+
return null;
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
if (!string.IsNullOrWhiteSpace(userGroup.Name) && userGroup.Name.StartsWith("ContactGroup - ", StringComparison.OrdinalIgnoreCase))
|
| 51 |
+
{
|
| 52 |
+
var contactGroupName = userGroup.Name.Substring("ContactGroup - ".Length).Trim();
|
| 53 |
+
if (!string.IsNullOrWhiteSpace(contactGroupName))
|
| 54 |
+
{
|
| 55 |
+
return _context.ContactGroups.FirstOrDefault(cg => cg.Name == contactGroupName);
|
| 56 |
+
}
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
return _context.ContactGroups.FirstOrDefault(cg => cg.Id == userGroup.Id);
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
private string GetUploadsRoot()
|
| 63 |
+
{
|
| 64 |
+
var uploadsRoot = Environment.GetEnvironmentVariable("UPLOADS_ROOT");
|
| 65 |
+
if (!string.IsNullOrWhiteSpace(uploadsRoot))
|
| 66 |
+
{
|
| 67 |
+
Directory.CreateDirectory(uploadsRoot);
|
| 68 |
+
Directory.CreateDirectory(Path.Combine(uploadsRoot, "photos"));
|
| 69 |
+
Directory.CreateDirectory(Path.Combine(uploadsRoot, "documents"));
|
| 70 |
+
return uploadsRoot;
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
var fallback = Path.Combine(_environment.WebRootPath, "uploads");
|
| 74 |
+
Directory.CreateDirectory(fallback);
|
| 75 |
+
Directory.CreateDirectory(Path.Combine(fallback, "photos"));
|
| 76 |
+
Directory.CreateDirectory(Path.Combine(fallback, "documents"));
|
| 77 |
+
return fallback;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
private static string NormalizeText(string? value)
|
| 81 |
+
{
|
| 82 |
+
return (value ?? string.Empty).Trim().ToUpperInvariant();
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
[RequireRight(RightsCatalog.AdminManageUsers)]
|
| 86 |
+
public IActionResult Users()
|
| 87 |
+
{
|
| 88 |
+
var currentUser = _userContextService.CurrentUser;
|
| 89 |
+
var isSuperAdmin = IsSuperAdminUser(currentUser);
|
| 90 |
+
|
| 91 |
+
var usersQuery = _context.AppUsers
|
| 92 |
+
.Include(u => u.Group)
|
| 93 |
+
.AsQueryable();
|
| 94 |
+
|
| 95 |
+
if (!isSuperAdmin)
|
| 96 |
+
{
|
| 97 |
+
usersQuery = usersQuery.Where(u => !string.Equals(u.UserName, SeedData.SuperAdminUserName, StringComparison.OrdinalIgnoreCase));
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
var users = usersQuery
|
| 101 |
+
.OrderBy(u => u.UserName)
|
| 102 |
+
.ToList();
|
| 103 |
+
|
| 104 |
+
ViewBag.IsSuperAdmin = isSuperAdmin;
|
| 105 |
+
|
| 106 |
+
return View(users);
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
[RequireRight(RightsCatalog.AdminManageUsers)]
|
| 110 |
+
public IActionResult CreateUser()
|
| 111 |
+
{
|
| 112 |
+
ViewData["Groups"] = _context.UserGroups.OrderBy(g => g.Name).ToList();
|
| 113 |
+
return View(new UserCreateViewModel());
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
[HttpPost]
|
| 117 |
+
[ValidateAntiForgeryToken]
|
| 118 |
+
[RequireRight(RightsCatalog.AdminManageUsers)]
|
| 119 |
+
public IActionResult CreateUser(UserCreateViewModel model)
|
| 120 |
+
{
|
| 121 |
+
var currentUser = _userContextService.CurrentUser;
|
| 122 |
+
var isSuperAdmin = IsSuperAdminUser(currentUser);
|
| 123 |
+
|
| 124 |
+
if (string.Equals(model.UserName, SeedData.SuperAdminUserName, StringComparison.OrdinalIgnoreCase) && !isSuperAdmin)
|
| 125 |
+
{
|
| 126 |
+
ModelState.AddModelError(nameof(UserCreateViewModel.UserName), "Super Admin user name is reserved.");
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
if (_context.AppUsers.Any(u => u.UserName == model.UserName))
|
| 130 |
+
{
|
| 131 |
+
ModelState.AddModelError(nameof(UserCreateViewModel.UserName), "User name already exists.");
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
if (!ModelState.IsValid)
|
| 135 |
+
{
|
| 136 |
+
ViewData["Groups"] = _context.UserGroups.OrderBy(g => g.Name).ToList();
|
| 137 |
+
return View(model);
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
var user = new AppUser
|
| 141 |
+
{
|
| 142 |
+
UserName = model.UserName,
|
| 143 |
+
FullName = model.FullName,
|
| 144 |
+
GroupId = model.GroupId,
|
| 145 |
+
IsAdmin = model.IsAdmin,
|
| 146 |
+
IsActive = model.IsActive,
|
| 147 |
+
CreatedAt = DateTime.Now,
|
| 148 |
+
UpdatedAt = DateTime.Now
|
| 149 |
+
};
|
| 150 |
+
|
| 151 |
+
user.PasswordHash = _passwordHasher.HashPassword(user, model.Password);
|
| 152 |
+
_context.AppUsers.Add(user);
|
| 153 |
+
_context.SaveChanges();
|
| 154 |
+
|
| 155 |
+
_adminHistoryService.Log(
|
| 156 |
+
actionType: "Create",
|
| 157 |
+
entityType: "User",
|
| 158 |
+
entityId: user.Id,
|
| 159 |
+
performedBy: _userContextService.CurrentUser?.UserName ?? "Unknown",
|
| 160 |
+
details: $"Created user '{user.UserName}' in group id '{user.GroupId}'.");
|
| 161 |
+
|
| 162 |
+
TempData["SuccessMessage"] = "User created successfully.";
|
| 163 |
+
return RedirectToAction("Users");
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
[RequireRight(RightsCatalog.AdminManageUsers)]
|
| 167 |
+
public IActionResult EditUser(int id)
|
| 168 |
+
{
|
| 169 |
+
var currentUser = _userContextService.CurrentUser;
|
| 170 |
+
var isSuperAdmin = IsSuperAdminUser(currentUser);
|
| 171 |
+
|
| 172 |
+
var user = _context.AppUsers.FirstOrDefault(u => u.Id == id);
|
| 173 |
+
if (user == null)
|
| 174 |
+
return NotFound();
|
| 175 |
+
|
| 176 |
+
if (IsSuperAdminUser(user) && !isSuperAdmin)
|
| 177 |
+
{
|
| 178 |
+
return NotFound();
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
var model = new UserEditViewModel
|
| 182 |
+
{
|
| 183 |
+
Id = user.Id,
|
| 184 |
+
UserName = user.UserName,
|
| 185 |
+
FullName = user.FullName,
|
| 186 |
+
GroupId = user.GroupId,
|
| 187 |
+
IsAdmin = user.IsAdmin,
|
| 188 |
+
IsActive = user.IsActive
|
| 189 |
+
};
|
| 190 |
+
|
| 191 |
+
ViewData["Groups"] = _context.UserGroups.OrderBy(g => g.Name).ToList();
|
| 192 |
+
return View(model);
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
[HttpPost]
|
| 196 |
+
[ValidateAntiForgeryToken]
|
| 197 |
+
[RequireRight(RightsCatalog.AdminManageUsers)]
|
| 198 |
+
public IActionResult EditUser(UserEditViewModel model)
|
| 199 |
+
{
|
| 200 |
+
var currentUser = _userContextService.CurrentUser;
|
| 201 |
+
var isSuperAdmin = IsSuperAdminUser(currentUser);
|
| 202 |
+
|
| 203 |
+
var user = _context.AppUsers.FirstOrDefault(u => u.Id == model.Id);
|
| 204 |
+
if (user == null)
|
| 205 |
+
return NotFound();
|
| 206 |
+
|
| 207 |
+
if (IsSuperAdminUser(user) && !isSuperAdmin)
|
| 208 |
+
{
|
| 209 |
+
return NotFound();
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
if (_context.AppUsers.Any(u => u.UserName == model.UserName && u.Id != model.Id))
|
| 213 |
+
{
|
| 214 |
+
ModelState.AddModelError(nameof(UserEditViewModel.UserName), "User name already exists.");
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
if (string.Equals(model.UserName, SeedData.SuperAdminUserName, StringComparison.OrdinalIgnoreCase) && !IsSuperAdminUser(user))
|
| 218 |
+
{
|
| 219 |
+
ModelState.AddModelError(nameof(UserEditViewModel.UserName), "Super Admin user name is reserved.");
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
if (!ModelState.IsValid)
|
| 223 |
+
{
|
| 224 |
+
ViewData["Groups"] = _context.UserGroups.OrderBy(g => g.Name).ToList();
|
| 225 |
+
return View(model);
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
var wasAdminUser = string.Equals(user.UserName, "admin", StringComparison.OrdinalIgnoreCase);
|
| 229 |
+
var wasSuperAdminUser = IsSuperAdminUser(user);
|
| 230 |
+
|
| 231 |
+
if (wasSuperAdminUser)
|
| 232 |
+
{
|
| 233 |
+
// Super Admin is immutable (prevents lockout and prevents admin-level changes even by mistake)
|
| 234 |
+
ModelState.AddModelError(string.Empty, "Super Admin account cannot be edited.");
|
| 235 |
+
ViewData["Groups"] = _context.UserGroups.OrderBy(g => g.Name).ToList();
|
| 236 |
+
return View(model);
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
user.UserName = model.UserName;
|
| 240 |
+
user.FullName = model.FullName;
|
| 241 |
+
user.GroupId = model.GroupId;
|
| 242 |
+
user.IsAdmin = model.IsAdmin;
|
| 243 |
+
user.IsActive = model.IsActive;
|
| 244 |
+
user.UpdatedAt = DateTime.Now;
|
| 245 |
+
|
| 246 |
+
if (wasAdminUser)
|
| 247 |
+
{
|
| 248 |
+
var administratorsGroupId = _context.UserGroups
|
| 249 |
+
.Where(g => g.Name == "Administrators")
|
| 250 |
+
.Select(g => g.Id)
|
| 251 |
+
.FirstOrDefault();
|
| 252 |
+
|
| 253 |
+
user.IsAdmin = true;
|
| 254 |
+
user.IsActive = true;
|
| 255 |
+
if (administratorsGroupId > 0)
|
| 256 |
+
{
|
| 257 |
+
user.GroupId = administratorsGroupId;
|
| 258 |
+
}
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
if (!string.IsNullOrWhiteSpace(model.NewPassword))
|
| 262 |
+
{
|
| 263 |
+
user.PasswordHash = _passwordHasher.HashPassword(user, model.NewPassword);
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
_context.SaveChanges();
|
| 267 |
+
|
| 268 |
+
_adminHistoryService.Log(
|
| 269 |
+
actionType: "Edit",
|
| 270 |
+
entityType: "User",
|
| 271 |
+
entityId: user.Id,
|
| 272 |
+
performedBy: _userContextService.CurrentUser?.UserName ?? "Unknown",
|
| 273 |
+
details: $"Edited user '{user.UserName}' (Active: {user.IsActive}, Admin: {user.IsAdmin}).");
|
| 274 |
+
|
| 275 |
+
TempData["SuccessMessage"] = "User updated successfully.";
|
| 276 |
+
return RedirectToAction("Users");
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
[RequireRight(RightsCatalog.AdminManageRights)]
|
| 280 |
+
public IActionResult UserRights(int id)
|
| 281 |
+
{
|
| 282 |
+
var currentUser = _userContextService.CurrentUser;
|
| 283 |
+
var isSuperAdmin = IsSuperAdminUser(currentUser);
|
| 284 |
+
|
| 285 |
+
var user = _context.AppUsers
|
| 286 |
+
.Include(u => u.Group)
|
| 287 |
+
.FirstOrDefault(u => u.Id == id);
|
| 288 |
+
|
| 289 |
+
if (user == null)
|
| 290 |
+
return NotFound();
|
| 291 |
+
|
| 292 |
+
if (IsSuperAdminUser(user) && !isSuperAdmin)
|
| 293 |
+
{
|
| 294 |
+
return NotFound();
|
| 295 |
+
}
|
| 296 |
+
|
| 297 |
+
var userRights = _context.UserRights
|
| 298 |
+
.Where(r => r.AppUserId == id)
|
| 299 |
+
.ToList();
|
| 300 |
+
|
| 301 |
+
var groupRights = _context.GroupRights
|
| 302 |
+
.Where(r => r.UserGroupId == user.GroupId)
|
| 303 |
+
.ToList();
|
| 304 |
+
|
| 305 |
+
var rights = RightsCatalog.All.Select(r =>
|
| 306 |
+
{
|
| 307 |
+
var userRight = userRights.FirstOrDefault(ur => ur.RightKey == r.Key);
|
| 308 |
+
var groupRight = groupRights.FirstOrDefault(gr => gr.RightKey == r.Key);
|
| 309 |
+
var selection = userRight == null ? "Inherit" : (userRight.IsGranted ? "Grant" : "Deny");
|
| 310 |
+
var effectiveGranted = user.IsAdmin || (userRight?.IsGranted ?? (groupRight?.IsGranted ?? false));
|
| 311 |
+
var effectiveSource = user.IsAdmin ? "Admin" : userRight != null ? "User" : groupRight != null ? "Group" : "None";
|
| 312 |
+
|
| 313 |
+
return new RightAssignmentViewModel
|
| 314 |
+
{
|
| 315 |
+
Key = r.Key,
|
| 316 |
+
Label = r.Label,
|
| 317 |
+
Category = r.Category,
|
| 318 |
+
Selection = selection,
|
| 319 |
+
EffectiveGranted = effectiveGranted,
|
| 320 |
+
EffectiveSource = effectiveSource
|
| 321 |
+
};
|
| 322 |
+
}).ToList();
|
| 323 |
+
|
| 324 |
+
var model = new UserRightsViewModel
|
| 325 |
+
{
|
| 326 |
+
UserId = user.Id,
|
| 327 |
+
UserName = user.UserName,
|
| 328 |
+
GroupName = user.Group?.Name,
|
| 329 |
+
Rights = rights
|
| 330 |
+
};
|
| 331 |
+
|
| 332 |
+
return View(model);
|
| 333 |
+
}
|
| 334 |
+
|
| 335 |
+
[HttpPost]
|
| 336 |
+
[ValidateAntiForgeryToken]
|
| 337 |
+
[RequireRight(RightsCatalog.AdminManageRights)]
|
| 338 |
+
public IActionResult UserRights(UserRightsViewModel model)
|
| 339 |
+
{
|
| 340 |
+
var currentUser = _userContextService.CurrentUser;
|
| 341 |
+
var isSuperAdmin = IsSuperAdminUser(currentUser);
|
| 342 |
+
|
| 343 |
+
var user = _context.AppUsers.FirstOrDefault(u => u.Id == model.UserId);
|
| 344 |
+
if (user == null)
|
| 345 |
+
return NotFound();
|
| 346 |
+
|
| 347 |
+
if (IsSuperAdminUser(user) && !isSuperAdmin)
|
| 348 |
+
{
|
| 349 |
+
return NotFound();
|
| 350 |
+
}
|
| 351 |
+
|
| 352 |
+
foreach (var right in model.Rights)
|
| 353 |
+
{
|
| 354 |
+
var existing = _context.UserRights.FirstOrDefault(r => r.AppUserId == model.UserId && r.RightKey == right.Key);
|
| 355 |
+
if (right.Selection == "Inherit")
|
| 356 |
+
{
|
| 357 |
+
if (existing != null)
|
| 358 |
+
_context.UserRights.Remove(existing);
|
| 359 |
+
continue;
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
var isGranted = right.Selection == "Grant";
|
| 363 |
+
if (existing == null)
|
| 364 |
+
{
|
| 365 |
+
_context.UserRights.Add(new UserRight
|
| 366 |
+
{
|
| 367 |
+
AppUserId = model.UserId,
|
| 368 |
+
RightKey = right.Key,
|
| 369 |
+
IsGranted = isGranted
|
| 370 |
+
});
|
| 371 |
+
}
|
| 372 |
+
else
|
| 373 |
+
{
|
| 374 |
+
existing.IsGranted = isGranted;
|
| 375 |
+
}
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
_context.SaveChanges();
|
| 379 |
+
|
| 380 |
+
_adminHistoryService.Log(
|
| 381 |
+
actionType: "Edit",
|
| 382 |
+
entityType: "UserRights",
|
| 383 |
+
entityId: model.UserId,
|
| 384 |
+
performedBy: _userContextService.CurrentUser?.UserName ?? "Unknown",
|
| 385 |
+
details: $"Updated rights for user '{user.UserName}'.");
|
| 386 |
+
|
| 387 |
+
TempData["SuccessMessage"] = "User rights updated successfully.";
|
| 388 |
+
return RedirectToAction("UserRights", new { id = model.UserId });
|
| 389 |
+
}
|
| 390 |
+
|
| 391 |
+
[RequireRight(RightsCatalog.AdminManageGroups)]
|
| 392 |
+
public IActionResult Groups()
|
| 393 |
+
{
|
| 394 |
+
var groups = _context.UserGroups
|
| 395 |
+
.OrderBy(g => g.Name)
|
| 396 |
+
.ToList();
|
| 397 |
+
|
| 398 |
+
ViewBag.IsSuperAdmin = IsSuperAdminUser(_userContextService.CurrentUser);
|
| 399 |
+
|
| 400 |
+
return View(groups);
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
[RequireRight(RightsCatalog.AdminManageGroups)]
|
| 404 |
+
public IActionResult CreateGroup()
|
| 405 |
+
{
|
| 406 |
+
return View(new GroupEditViewModel());
|
| 407 |
+
}
|
| 408 |
+
|
| 409 |
+
[HttpPost]
|
| 410 |
+
[ValidateAntiForgeryToken]
|
| 411 |
+
[RequireRight(RightsCatalog.AdminManageGroups)]
|
| 412 |
+
public IActionResult CreateGroup(GroupEditViewModel model)
|
| 413 |
+
{
|
| 414 |
+
if (_context.UserGroups.Any(g => g.Name == model.Name))
|
| 415 |
+
{
|
| 416 |
+
ModelState.AddModelError(nameof(GroupEditViewModel.Name), "Group name already exists.");
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
if (!ModelState.IsValid)
|
| 420 |
+
return View(model);
|
| 421 |
+
|
| 422 |
+
var group = new UserGroup
|
| 423 |
+
{
|
| 424 |
+
Name = model.Name,
|
| 425 |
+
Description = model.Description,
|
| 426 |
+
CreatedAt = DateTime.Now
|
| 427 |
+
};
|
| 428 |
+
|
| 429 |
+
_context.UserGroups.Add(group);
|
| 430 |
+
_context.SaveChanges();
|
| 431 |
+
|
| 432 |
+
var rights = RightsCatalog.All.Select(r => new GroupRight
|
| 433 |
+
{
|
| 434 |
+
UserGroupId = group.Id,
|
| 435 |
+
RightKey = r.Key,
|
| 436 |
+
IsGranted = false
|
| 437 |
+
}).ToList();
|
| 438 |
+
|
| 439 |
+
_context.GroupRights.AddRange(rights);
|
| 440 |
+
_context.SaveChanges();
|
| 441 |
+
|
| 442 |
+
_adminHistoryService.Log(
|
| 443 |
+
actionType: "Create",
|
| 444 |
+
entityType: "Group",
|
| 445 |
+
entityId: group.Id,
|
| 446 |
+
performedBy: _userContextService.CurrentUser?.UserName ?? "Unknown",
|
| 447 |
+
details: $"Created group '{group.Name}'.");
|
| 448 |
+
|
| 449 |
+
TempData["SuccessMessage"] = "Group created successfully.";
|
| 450 |
+
return RedirectToAction("Groups");
|
| 451 |
+
}
|
| 452 |
+
|
| 453 |
+
[RequireRight(RightsCatalog.AdminManageGroups)]
|
| 454 |
+
public IActionResult EditGroup(int id)
|
| 455 |
+
{
|
| 456 |
+
var group = _context.UserGroups.FirstOrDefault(g => g.Id == id);
|
| 457 |
+
if (group == null)
|
| 458 |
+
return NotFound();
|
| 459 |
+
|
| 460 |
+
var model = new GroupEditViewModel
|
| 461 |
+
{
|
| 462 |
+
Id = group.Id,
|
| 463 |
+
Name = group.Name,
|
| 464 |
+
Description = group.Description
|
| 465 |
+
};
|
| 466 |
+
|
| 467 |
+
return View(model);
|
| 468 |
+
}
|
| 469 |
+
|
| 470 |
+
[HttpPost]
|
| 471 |
+
[ValidateAntiForgeryToken]
|
| 472 |
+
[RequireRight(RightsCatalog.AdminManageUsers)]
|
| 473 |
+
public IActionResult DeleteSelectedUsers(List<int> userIds)
|
| 474 |
+
{
|
| 475 |
+
var currentUser = _userContextService.CurrentUser;
|
| 476 |
+
if (!IsSuperAdminUser(currentUser))
|
| 477 |
+
{
|
| 478 |
+
return Forbid();
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
+
if (userIds == null || userIds.Count == 0)
|
| 482 |
+
{
|
| 483 |
+
TempData["ErrorMessage"] = "No users selected.";
|
| 484 |
+
return RedirectToAction(nameof(Users));
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
var messages = new System.Collections.Generic.List<string>();
|
| 488 |
+
var deleted = 0;
|
| 489 |
+
|
| 490 |
+
foreach (var userId in userIds.Distinct())
|
| 491 |
+
{
|
| 492 |
+
var user = _context.AppUsers
|
| 493 |
+
.Include(u => u.Group)
|
| 494 |
+
.FirstOrDefault(u => u.Id == userId);
|
| 495 |
+
|
| 496 |
+
if (user == null)
|
| 497 |
+
{
|
| 498 |
+
continue;
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
+
if (IsProtectedSystemUser(user))
|
| 502 |
+
{
|
| 503 |
+
messages.Add($"User '{user.UserName}' cannot be deleted.");
|
| 504 |
+
continue;
|
| 505 |
+
}
|
| 506 |
+
|
| 507 |
+
var mappedContactGroup = ResolveContactGroupForUserGroup(user.Group);
|
| 508 |
+
if (mappedContactGroup != null)
|
| 509 |
+
{
|
| 510 |
+
var hasContacts = _context.Contacts.Any(c => c.GroupId == mappedContactGroup.Id);
|
| 511 |
+
if (hasContacts)
|
| 512 |
+
{
|
| 513 |
+
messages.Add($"Delete contacts in '{mappedContactGroup.Name}' first, then delete user '{user.UserName}'.");
|
| 514 |
+
continue;
|
| 515 |
+
}
|
| 516 |
+
}
|
| 517 |
+
|
| 518 |
+
_context.AppUsers.Remove(user);
|
| 519 |
+
deleted++;
|
| 520 |
+
|
| 521 |
+
_adminHistoryService.Log(
|
| 522 |
+
actionType: "Delete",
|
| 523 |
+
entityType: "User",
|
| 524 |
+
entityId: user.Id,
|
| 525 |
+
performedBy: currentUser?.UserName ?? "Unknown",
|
| 526 |
+
details: $"Deleted user '{user.UserName}'.");
|
| 527 |
+
}
|
| 528 |
+
|
| 529 |
+
if (deleted > 0)
|
| 530 |
+
{
|
| 531 |
+
_context.SaveChanges();
|
| 532 |
+
}
|
| 533 |
+
|
| 534 |
+
if (messages.Count > 0)
|
| 535 |
+
{
|
| 536 |
+
TempData["ErrorMessage"] = string.Join(" ", messages);
|
| 537 |
+
}
|
| 538 |
+
|
| 539 |
+
if (deleted > 0)
|
| 540 |
+
{
|
| 541 |
+
TempData["SuccessMessage"] = $"Deleted {deleted} user(s).";
|
| 542 |
+
}
|
| 543 |
+
|
| 544 |
+
return RedirectToAction(nameof(Users));
|
| 545 |
+
}
|
| 546 |
+
|
| 547 |
+
[HttpPost]
|
| 548 |
+
[ValidateAntiForgeryToken]
|
| 549 |
+
[RequireRight(RightsCatalog.AdminManageGroups)]
|
| 550 |
+
public IActionResult DeleteSelectedGroups(List<int> groupIds)
|
| 551 |
+
{
|
| 552 |
+
var currentUser = _userContextService.CurrentUser;
|
| 553 |
+
if (!IsSuperAdminUser(currentUser))
|
| 554 |
+
{
|
| 555 |
+
return Forbid();
|
| 556 |
+
}
|
| 557 |
+
|
| 558 |
+
if (groupIds == null || groupIds.Count == 0)
|
| 559 |
+
{
|
| 560 |
+
TempData["ErrorMessage"] = "No groups selected.";
|
| 561 |
+
return RedirectToAction(nameof(Groups));
|
| 562 |
+
}
|
| 563 |
+
|
| 564 |
+
var messages = new System.Collections.Generic.List<string>();
|
| 565 |
+
var deleted = 0;
|
| 566 |
+
|
| 567 |
+
foreach (var groupId in groupIds.Distinct())
|
| 568 |
+
{
|
| 569 |
+
var group = _context.UserGroups
|
| 570 |
+
.Include(g => g.Users)
|
| 571 |
+
.FirstOrDefault(g => g.Id == groupId);
|
| 572 |
+
|
| 573 |
+
if (group == null)
|
| 574 |
+
{
|
| 575 |
+
continue;
|
| 576 |
+
}
|
| 577 |
+
|
| 578 |
+
if (string.Equals(group.Name, "Administrators", StringComparison.OrdinalIgnoreCase))
|
| 579 |
+
{
|
| 580 |
+
messages.Add("Administrators group cannot be deleted.");
|
| 581 |
+
continue;
|
| 582 |
+
}
|
| 583 |
+
|
| 584 |
+
var mappedContactGroup = ResolveContactGroupForUserGroup(group);
|
| 585 |
+
if (mappedContactGroup != null)
|
| 586 |
+
{
|
| 587 |
+
var hasContacts = _context.Contacts.Any(c => c.GroupId == mappedContactGroup.Id);
|
| 588 |
+
if (hasContacts)
|
| 589 |
+
{
|
| 590 |
+
messages.Add($"Delete contacts in '{mappedContactGroup.Name}' first, then delete users, then delete group '{group.Name}'.");
|
| 591 |
+
continue;
|
| 592 |
+
}
|
| 593 |
+
}
|
| 594 |
+
|
| 595 |
+
if (group.Users.Any())
|
| 596 |
+
{
|
| 597 |
+
messages.Add($"Delete users in group '{group.Name}' first, then delete the group.");
|
| 598 |
+
continue;
|
| 599 |
+
}
|
| 600 |
+
|
| 601 |
+
_context.UserGroups.Remove(group);
|
| 602 |
+
deleted++;
|
| 603 |
+
|
| 604 |
+
_adminHistoryService.Log(
|
| 605 |
+
actionType: "Delete",
|
| 606 |
+
entityType: "Group",
|
| 607 |
+
entityId: group.Id,
|
| 608 |
+
performedBy: currentUser?.UserName ?? "Unknown",
|
| 609 |
+
details: $"Deleted group '{group.Name}'.");
|
| 610 |
+
}
|
| 611 |
+
|
| 612 |
+
if (deleted > 0)
|
| 613 |
+
{
|
| 614 |
+
_context.SaveChanges();
|
| 615 |
+
}
|
| 616 |
+
|
| 617 |
+
if (messages.Count > 0)
|
| 618 |
+
{
|
| 619 |
+
TempData["ErrorMessage"] = string.Join(" ", messages);
|
| 620 |
+
}
|
| 621 |
+
|
| 622 |
+
if (deleted > 0)
|
| 623 |
+
{
|
| 624 |
+
TempData["SuccessMessage"] = $"Deleted {deleted} group(s).";
|
| 625 |
+
}
|
| 626 |
+
|
| 627 |
+
return RedirectToAction(nameof(Groups));
|
| 628 |
+
}
|
| 629 |
+
|
| 630 |
+
[HttpPost]
|
| 631 |
+
[ValidateAntiForgeryToken]
|
| 632 |
+
[RequireRight(RightsCatalog.AdminManageGroups)]
|
| 633 |
+
public IActionResult EditGroup(GroupEditViewModel model)
|
| 634 |
+
{
|
| 635 |
+
var group = _context.UserGroups.FirstOrDefault(g => g.Id == model.Id);
|
| 636 |
+
if (group == null)
|
| 637 |
+
return NotFound();
|
| 638 |
+
|
| 639 |
+
if (_context.UserGroups.Any(g => g.Name == model.Name && g.Id != model.Id))
|
| 640 |
+
{
|
| 641 |
+
ModelState.AddModelError(nameof(GroupEditViewModel.Name), "Group name already exists.");
|
| 642 |
+
}
|
| 643 |
+
|
| 644 |
+
if (!ModelState.IsValid)
|
| 645 |
+
return View(model);
|
| 646 |
+
|
| 647 |
+
if (string.Equals(group.Name, "Administrators", StringComparison.OrdinalIgnoreCase) &&
|
| 648 |
+
!string.Equals(model.Name, "Administrators", StringComparison.OrdinalIgnoreCase))
|
| 649 |
+
{
|
| 650 |
+
ModelState.AddModelError(nameof(GroupEditViewModel.Name), "Administrators group name cannot be changed.");
|
| 651 |
+
return View(model);
|
| 652 |
+
}
|
| 653 |
+
|
| 654 |
+
group.Name = model.Name;
|
| 655 |
+
group.Description = model.Description;
|
| 656 |
+
_context.SaveChanges();
|
| 657 |
+
|
| 658 |
+
_adminHistoryService.Log(
|
| 659 |
+
actionType: "Edit",
|
| 660 |
+
entityType: "Group",
|
| 661 |
+
entityId: group.Id,
|
| 662 |
+
performedBy: _userContextService.CurrentUser?.UserName ?? "Unknown",
|
| 663 |
+
details: $"Edited group '{group.Name}'.");
|
| 664 |
+
|
| 665 |
+
TempData["SuccessMessage"] = "Group updated successfully.";
|
| 666 |
+
return RedirectToAction("Groups");
|
| 667 |
+
}
|
| 668 |
+
|
| 669 |
+
[RequireRight(RightsCatalog.AdminManageRights)]
|
| 670 |
+
public IActionResult GroupRights(int id)
|
| 671 |
+
{
|
| 672 |
+
var group = _context.UserGroups.FirstOrDefault(g => g.Id == id);
|
| 673 |
+
if (group == null)
|
| 674 |
+
return NotFound();
|
| 675 |
+
|
| 676 |
+
var groupRights = _context.GroupRights
|
| 677 |
+
.Where(r => r.UserGroupId == id)
|
| 678 |
+
.ToList();
|
| 679 |
+
|
| 680 |
+
var rights = RightsCatalog.All.Select(r =>
|
| 681 |
+
{
|
| 682 |
+
var existing = groupRights.FirstOrDefault(gr => gr.RightKey == r.Key);
|
| 683 |
+
return new RightAssignmentViewModel
|
| 684 |
+
{
|
| 685 |
+
Key = r.Key,
|
| 686 |
+
Label = r.Label,
|
| 687 |
+
Category = r.Category,
|
| 688 |
+
IsGranted = existing?.IsGranted ?? false
|
| 689 |
+
};
|
| 690 |
+
}).ToList();
|
| 691 |
+
|
| 692 |
+
var model = new GroupRightsViewModel
|
| 693 |
+
{
|
| 694 |
+
GroupId = group.Id,
|
| 695 |
+
GroupName = group.Name,
|
| 696 |
+
Rights = rights
|
| 697 |
+
};
|
| 698 |
+
|
| 699 |
+
return View(model);
|
| 700 |
+
}
|
| 701 |
+
|
| 702 |
+
[HttpPost]
|
| 703 |
+
[ValidateAntiForgeryToken]
|
| 704 |
+
[RequireRight(RightsCatalog.AdminManageRights)]
|
| 705 |
+
public IActionResult GroupRights(GroupRightsViewModel model)
|
| 706 |
+
{
|
| 707 |
+
foreach (var right in model.Rights)
|
| 708 |
+
{
|
| 709 |
+
var existing = _context.GroupRights.FirstOrDefault(r => r.UserGroupId == model.GroupId && r.RightKey == right.Key);
|
| 710 |
+
if (existing == null)
|
| 711 |
+
{
|
| 712 |
+
_context.GroupRights.Add(new GroupRight
|
| 713 |
+
{
|
| 714 |
+
UserGroupId = model.GroupId,
|
| 715 |
+
RightKey = right.Key,
|
| 716 |
+
IsGranted = right.IsGranted
|
| 717 |
+
});
|
| 718 |
+
}
|
| 719 |
+
else
|
| 720 |
+
{
|
| 721 |
+
existing.IsGranted = right.IsGranted;
|
| 722 |
+
}
|
| 723 |
+
}
|
| 724 |
+
|
| 725 |
+
_context.SaveChanges();
|
| 726 |
+
|
| 727 |
+
_adminHistoryService.Log(
|
| 728 |
+
actionType: "Edit",
|
| 729 |
+
entityType: "GroupRights",
|
| 730 |
+
entityId: model.GroupId,
|
| 731 |
+
performedBy: _userContextService.CurrentUser?.UserName ?? "Unknown",
|
| 732 |
+
details: $"Updated rights for group '{model.GroupName}'.");
|
| 733 |
+
|
| 734 |
+
TempData["SuccessMessage"] = "Group rights updated successfully.";
|
| 735 |
+
return RedirectToAction("GroupRights", new { id = model.GroupId });
|
| 736 |
+
}
|
| 737 |
+
|
| 738 |
+
[RequireRight(RightsCatalog.AdminManageUsers)]
|
| 739 |
+
public IActionResult History(int take = 200)
|
| 740 |
+
{
|
| 741 |
+
var entries = _adminHistoryService
|
| 742 |
+
.GetLatest(take)
|
| 743 |
+
.Select(e => new AdminHistoryEntryViewModel
|
| 744 |
+
{
|
| 745 |
+
ActionType = e.ActionType,
|
| 746 |
+
EntityType = e.EntityType,
|
| 747 |
+
EntityId = e.EntityId,
|
| 748 |
+
Details = e.Details,
|
| 749 |
+
PerformedBy = e.PerformedBy,
|
| 750 |
+
PerformedAt = e.PerformedAt
|
| 751 |
+
})
|
| 752 |
+
.ToList();
|
| 753 |
+
|
| 754 |
+
var model = new AdminHistoryListViewModel
|
| 755 |
+
{
|
| 756 |
+
Entries = entries
|
| 757 |
+
};
|
| 758 |
+
|
| 759 |
+
return View(model);
|
| 760 |
+
}
|
| 761 |
+
|
| 762 |
+
[RequireRight(RightsCatalog.AdminManageUsers)]
|
| 763 |
+
public IActionResult RestoreContacts()
|
| 764 |
+
{
|
| 765 |
+
var currentUser = _userContextService.CurrentUser;
|
| 766 |
+
if (!IsSuperAdminUser(currentUser))
|
| 767 |
+
{
|
| 768 |
+
return Forbid();
|
| 769 |
+
}
|
| 770 |
+
|
| 771 |
+
return View();
|
| 772 |
+
}
|
| 773 |
+
|
| 774 |
+
[HttpPost]
|
| 775 |
+
[ValidateAntiForgeryToken]
|
| 776 |
+
[RequireRight(RightsCatalog.AdminManageUsers)]
|
| 777 |
+
public async Task<IActionResult> RestoreContacts(IFormFile backupZip)
|
| 778 |
+
{
|
| 779 |
+
var currentUser = _userContextService.CurrentUser;
|
| 780 |
+
if (!IsSuperAdminUser(currentUser))
|
| 781 |
+
{
|
| 782 |
+
return Forbid();
|
| 783 |
+
}
|
| 784 |
+
|
| 785 |
+
if (backupZip == null || backupZip.Length == 0)
|
| 786 |
+
{
|
| 787 |
+
TempData["ErrorMessage"] = "Please select a backup ZIP file.";
|
| 788 |
+
return RedirectToAction(nameof(RestoreContacts));
|
| 789 |
+
}
|
| 790 |
+
|
| 791 |
+
var tempRoot = Path.Combine(Path.GetTempPath(), "cms-restore-" + Guid.NewGuid().ToString("N"));
|
| 792 |
+
Directory.CreateDirectory(tempRoot);
|
| 793 |
+
|
| 794 |
+
try
|
| 795 |
+
{
|
| 796 |
+
var zipPath = Path.Combine(tempRoot, "backup.zip");
|
| 797 |
+
await using (var fs = System.IO.File.Create(zipPath))
|
| 798 |
+
{
|
| 799 |
+
await backupZip.CopyToAsync(fs);
|
| 800 |
+
}
|
| 801 |
+
|
| 802 |
+
ZipFile.ExtractToDirectory(zipPath, tempRoot);
|
| 803 |
+
|
| 804 |
+
// Expect: ContactManagement.db + uploads/photos + uploads/documents
|
| 805 |
+
var backupDbPath = Directory.GetFiles(tempRoot, "ContactManagement.db", SearchOption.AllDirectories)
|
| 806 |
+
.FirstOrDefault();
|
| 807 |
+
|
| 808 |
+
if (string.IsNullOrWhiteSpace(backupDbPath) || !System.IO.File.Exists(backupDbPath))
|
| 809 |
+
{
|
| 810 |
+
TempData["ErrorMessage"] = "Backup ZIP must contain ContactManagement.db";
|
| 811 |
+
return RedirectToAction(nameof(RestoreContacts));
|
| 812 |
+
}
|
| 813 |
+
|
| 814 |
+
var backupUploadsRoot = Directory.GetDirectories(tempRoot, "uploads", SearchOption.AllDirectories)
|
| 815 |
+
.FirstOrDefault();
|
| 816 |
+
|
| 817 |
+
if (string.IsNullOrWhiteSpace(backupUploadsRoot) || !Directory.Exists(backupUploadsRoot))
|
| 818 |
+
{
|
| 819 |
+
TempData["ErrorMessage"] = "Backup ZIP must contain uploads/photos and uploads/documents.";
|
| 820 |
+
return RedirectToAction(nameof(RestoreContacts));
|
| 821 |
+
}
|
| 822 |
+
|
| 823 |
+
var targetUploadsRoot = GetUploadsRoot();
|
| 824 |
+
|
| 825 |
+
var backupConnString = new SqliteConnectionStringBuilder { DataSource = backupDbPath }.ToString();
|
| 826 |
+
await using var backupConn = new SqliteConnection(backupConnString);
|
| 827 |
+
await backupConn.OpenAsync();
|
| 828 |
+
|
| 829 |
+
var wantedNames = new[] { "ABRAHAM", "PREMA", "PONNURAJ" };
|
| 830 |
+
var contactsToRestore = new System.Collections.Generic.List<System.Collections.Generic.Dictionary<string, object?>>();
|
| 831 |
+
|
| 832 |
+
var contactCmd = backupConn.CreateCommand();
|
| 833 |
+
contactCmd.CommandText = @"
|
| 834 |
+
SELECT Id, FirstName, LastName, NickName, Gender, DateOfBirth, Email,
|
| 835 |
+
Mobile1, Mobile2, Mobile3, WhatsAppNumber,
|
| 836 |
+
PassportNumber, PanNumber, AadharNumber, DrivingLicenseNumber, VotersId,
|
| 837 |
+
BankAccountNumber, BankName, BranchName, IfscCode,
|
| 838 |
+
Address, City, State, PostalCode, Country,
|
| 839 |
+
PhotoPath, GroupId, OtherDetails, CreatedAt, UpdatedAt
|
| 840 |
+
FROM Contacts
|
| 841 |
+
WHERE lower(FirstName) IN ('abraham','prema','ponnuraj');";
|
| 842 |
+
|
| 843 |
+
await using (var reader = await contactCmd.ExecuteReaderAsync())
|
| 844 |
+
{
|
| 845 |
+
while (await reader.ReadAsync())
|
| 846 |
+
{
|
| 847 |
+
var dict = new System.Collections.Generic.Dictionary<string, object?>();
|
| 848 |
+
for (var i = 0; i < reader.FieldCount; i++)
|
| 849 |
+
{
|
| 850 |
+
dict[reader.GetName(i)] = await reader.IsDBNullAsync(i) ? null : reader.GetValue(i);
|
| 851 |
+
}
|
| 852 |
+
contactsToRestore.Add(dict);
|
| 853 |
+
}
|
| 854 |
+
}
|
| 855 |
+
|
| 856 |
+
if (contactsToRestore.Count == 0)
|
| 857 |
+
{
|
| 858 |
+
TempData["ErrorMessage"] = "No Abraham/Prema/Ponnuraj contacts were found in the backup DB.";
|
| 859 |
+
return RedirectToAction(nameof(RestoreContacts));
|
| 860 |
+
}
|
| 861 |
+
|
| 862 |
+
// Pull related rows from backup
|
| 863 |
+
var backupContactIds = contactsToRestore.Select(c => Convert.ToInt32(c["Id"])).ToArray();
|
| 864 |
+
var idList = string.Join(",", backupContactIds);
|
| 865 |
+
|
| 866 |
+
var backupPhotos = new System.Collections.Generic.Dictionary<int, System.Collections.Generic.List<System.Collections.Generic.Dictionary<string, object?>>>();
|
| 867 |
+
var photoCmd = backupConn.CreateCommand();
|
| 868 |
+
photoCmd.CommandText = $@"
|
| 869 |
+
SELECT ContactId, PhotoPath, FileName, FileSize, ContentType, IsProfilePhoto, UploadedAt
|
| 870 |
+
FROM ContactPhotos
|
| 871 |
+
WHERE ContactId IN ({idList});";
|
| 872 |
+
await using (var reader = await photoCmd.ExecuteReaderAsync())
|
| 873 |
+
{
|
| 874 |
+
while (await reader.ReadAsync())
|
| 875 |
+
{
|
| 876 |
+
var contactId = reader.GetInt32(0);
|
| 877 |
+
if (!backupPhotos.TryGetValue(contactId, out var list))
|
| 878 |
+
{
|
| 879 |
+
list = new System.Collections.Generic.List<System.Collections.Generic.Dictionary<string, object?>>();
|
| 880 |
+
backupPhotos[contactId] = list;
|
| 881 |
+
}
|
| 882 |
+
|
| 883 |
+
list.Add(new System.Collections.Generic.Dictionary<string, object?>
|
| 884 |
+
{
|
| 885 |
+
["PhotoPath"] = reader.IsDBNull(1) ? null : reader.GetString(1),
|
| 886 |
+
["FileName"] = reader.IsDBNull(2) ? null : reader.GetString(2),
|
| 887 |
+
["FileSize"] = reader.IsDBNull(3) ? 0L : reader.GetInt64(3),
|
| 888 |
+
["ContentType"] = reader.IsDBNull(4) ? null : reader.GetString(4),
|
| 889 |
+
["IsProfilePhoto"] = !reader.IsDBNull(5) && reader.GetBoolean(5),
|
| 890 |
+
["UploadedAt"] = reader.IsDBNull(6) ? (DateTime?)null : reader.GetDateTime(6)
|
| 891 |
+
});
|
| 892 |
+
}
|
| 893 |
+
}
|
| 894 |
+
|
| 895 |
+
var backupDocs = new System.Collections.Generic.Dictionary<int, System.Collections.Generic.List<System.Collections.Generic.Dictionary<string, object?>>>();
|
| 896 |
+
var docCmd = backupConn.CreateCommand();
|
| 897 |
+
docCmd.CommandText = $@"
|
| 898 |
+
SELECT ContactId, DocumentPath, FileName, FileSize, ContentType, DocumentType, UploadedAt
|
| 899 |
+
FROM ContactDocuments
|
| 900 |
+
WHERE ContactId IN ({idList});";
|
| 901 |
+
await using (var reader = await docCmd.ExecuteReaderAsync())
|
| 902 |
+
{
|
| 903 |
+
while (await reader.ReadAsync())
|
| 904 |
+
{
|
| 905 |
+
var contactId = reader.GetInt32(0);
|
| 906 |
+
if (!backupDocs.TryGetValue(contactId, out var list))
|
| 907 |
+
{
|
| 908 |
+
list = new System.Collections.Generic.List<System.Collections.Generic.Dictionary<string, object?>>();
|
| 909 |
+
backupDocs[contactId] = list;
|
| 910 |
+
}
|
| 911 |
+
|
| 912 |
+
list.Add(new System.Collections.Generic.Dictionary<string, object?>
|
| 913 |
+
{
|
| 914 |
+
["DocumentPath"] = reader.IsDBNull(1) ? null : reader.GetString(1),
|
| 915 |
+
["FileName"] = reader.IsDBNull(2) ? null : reader.GetString(2),
|
| 916 |
+
["FileSize"] = reader.IsDBNull(3) ? 0L : reader.GetInt64(3),
|
| 917 |
+
["ContentType"] = reader.IsDBNull(4) ? null : reader.GetString(4),
|
| 918 |
+
["DocumentType"] = reader.IsDBNull(5) ? null : reader.GetString(5),
|
| 919 |
+
["UploadedAt"] = reader.IsDBNull(6) ? (DateTime?)null : reader.GetDateTime(6)
|
| 920 |
+
});
|
| 921 |
+
}
|
| 922 |
+
}
|
| 923 |
+
|
| 924 |
+
var backupBanks = new System.Collections.Generic.Dictionary<int, System.Collections.Generic.List<System.Collections.Generic.Dictionary<string, object?>>>();
|
| 925 |
+
var bankCmd = backupConn.CreateCommand();
|
| 926 |
+
bankCmd.CommandText = $@"
|
| 927 |
+
SELECT ContactId, AccountNumber, BankName, BranchName, IfscCode, CreatedAt, UpdatedAt
|
| 928 |
+
FROM ContactBankAccounts
|
| 929 |
+
WHERE ContactId IN ({idList});";
|
| 930 |
+
await using (var reader = await bankCmd.ExecuteReaderAsync())
|
| 931 |
+
{
|
| 932 |
+
while (await reader.ReadAsync())
|
| 933 |
+
{
|
| 934 |
+
var contactId = reader.GetInt32(0);
|
| 935 |
+
if (!backupBanks.TryGetValue(contactId, out var list))
|
| 936 |
+
{
|
| 937 |
+
list = new System.Collections.Generic.List<System.Collections.Generic.Dictionary<string, object?>>();
|
| 938 |
+
backupBanks[contactId] = list;
|
| 939 |
+
}
|
| 940 |
+
|
| 941 |
+
list.Add(new System.Collections.Generic.Dictionary<string, object?>
|
| 942 |
+
{
|
| 943 |
+
["AccountNumber"] = reader.IsDBNull(1) ? null : reader.GetString(1),
|
| 944 |
+
["BankName"] = reader.IsDBNull(2) ? null : reader.GetString(2),
|
| 945 |
+
["BranchName"] = reader.IsDBNull(3) ? null : reader.GetString(3),
|
| 946 |
+
["IfscCode"] = reader.IsDBNull(4) ? null : reader.GetString(4),
|
| 947 |
+
["CreatedAt"] = reader.IsDBNull(5) ? (DateTime?)null : reader.GetDateTime(5),
|
| 948 |
+
["UpdatedAt"] = reader.IsDBNull(6) ? (DateTime?)null : reader.GetDateTime(6)
|
| 949 |
+
});
|
| 950 |
+
}
|
| 951 |
+
}
|
| 952 |
+
|
| 953 |
+
// Merge into current DB
|
| 954 |
+
_context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.TrackAll;
|
| 955 |
+
|
| 956 |
+
var restoredCount = 0;
|
| 957 |
+
var copiedFiles = 0;
|
| 958 |
+
|
| 959 |
+
foreach (var backupContact in contactsToRestore)
|
| 960 |
+
{
|
| 961 |
+
var firstName = backupContact["FirstName"]?.ToString() ?? string.Empty;
|
| 962 |
+
var lastName = backupContact["LastName"]?.ToString();
|
| 963 |
+
var nickName = backupContact["NickName"]?.ToString();
|
| 964 |
+
|
| 965 |
+
var normalizedFirstName = NormalizeText(firstName);
|
| 966 |
+
if (!wantedNames.Contains(normalizedFirstName))
|
| 967 |
+
{
|
| 968 |
+
continue;
|
| 969 |
+
}
|
| 970 |
+
|
| 971 |
+
var normalizedLastName = NormalizeText(lastName);
|
| 972 |
+
var normalizedNickName = NormalizeText(nickName);
|
| 973 |
+
|
| 974 |
+
var existing = _context.Contacts
|
| 975 |
+
.Include(c => c.Photos)
|
| 976 |
+
.Include(c => c.Documents)
|
| 977 |
+
.Include(c => c.BankAccounts)
|
| 978 |
+
.FirstOrDefault(c =>
|
| 979 |
+
NormalizeText(c.FirstName) == normalizedFirstName &&
|
| 980 |
+
NormalizeText(c.LastName) == normalizedLastName &&
|
| 981 |
+
NormalizeText(c.NickName) == normalizedNickName);
|
| 982 |
+
|
| 983 |
+
if (existing == null)
|
| 984 |
+
{
|
| 985 |
+
existing = new Contact();
|
| 986 |
+
_context.Contacts.Add(existing);
|
| 987 |
+
}
|
| 988 |
+
|
| 989 |
+
// Copy scalar fields
|
| 990 |
+
existing.FirstName = firstName;
|
| 991 |
+
existing.LastName = lastName;
|
| 992 |
+
existing.NickName = nickName;
|
| 993 |
+
existing.Gender = backupContact["Gender"]?.ToString();
|
| 994 |
+
existing.DateOfBirth = backupContact["DateOfBirth"] as DateTime?;
|
| 995 |
+
existing.Email = backupContact["Email"]?.ToString();
|
| 996 |
+
existing.Mobile1 = backupContact["Mobile1"]?.ToString();
|
| 997 |
+
existing.Mobile2 = backupContact["Mobile2"]?.ToString();
|
| 998 |
+
existing.Mobile3 = backupContact["Mobile3"]?.ToString();
|
| 999 |
+
existing.WhatsAppNumber = backupContact["WhatsAppNumber"]?.ToString();
|
| 1000 |
+
existing.PassportNumber = backupContact["PassportNumber"]?.ToString();
|
| 1001 |
+
existing.PanNumber = backupContact["PanNumber"]?.ToString();
|
| 1002 |
+
existing.AadharNumber = backupContact["AadharNumber"]?.ToString();
|
| 1003 |
+
existing.DrivingLicenseNumber = backupContact["DrivingLicenseNumber"]?.ToString();
|
| 1004 |
+
existing.VotersId = backupContact["VotersId"]?.ToString();
|
| 1005 |
+
existing.BankAccountNumber = backupContact["BankAccountNumber"]?.ToString();
|
| 1006 |
+
existing.BankName = backupContact["BankName"]?.ToString();
|
| 1007 |
+
existing.BranchName = backupContact["BranchName"]?.ToString();
|
| 1008 |
+
existing.IfscCode = backupContact["IfscCode"]?.ToString();
|
| 1009 |
+
existing.Address = backupContact["Address"]?.ToString();
|
| 1010 |
+
existing.City = backupContact["City"]?.ToString();
|
| 1011 |
+
existing.State = backupContact["State"]?.ToString();
|
| 1012 |
+
existing.PostalCode = backupContact["PostalCode"]?.ToString();
|
| 1013 |
+
existing.Country = backupContact["Country"]?.ToString();
|
| 1014 |
+
existing.PhotoPath = backupContact["PhotoPath"]?.ToString();
|
| 1015 |
+
existing.GroupId = backupContact["GroupId"] as int?;
|
| 1016 |
+
existing.OtherDetails = backupContact["OtherDetails"]?.ToString();
|
| 1017 |
+
|
| 1018 |
+
existing.CreatedAt = backupContact["CreatedAt"] as DateTime? ?? existing.CreatedAt;
|
| 1019 |
+
existing.UpdatedAt = DateTime.Now;
|
| 1020 |
+
|
| 1021 |
+
await _context.SaveChangesAsync();
|
| 1022 |
+
|
| 1023 |
+
// Replace related data
|
| 1024 |
+
if (existing.Photos.Any())
|
| 1025 |
+
{
|
| 1026 |
+
_context.ContactPhotos.RemoveRange(existing.Photos);
|
| 1027 |
+
}
|
| 1028 |
+
if (existing.Documents.Any())
|
| 1029 |
+
{
|
| 1030 |
+
_context.ContactDocuments.RemoveRange(existing.Documents);
|
| 1031 |
+
}
|
| 1032 |
+
if (existing.BankAccounts.Any())
|
| 1033 |
+
{
|
| 1034 |
+
_context.ContactBankAccounts.RemoveRange(existing.BankAccounts);
|
| 1035 |
+
}
|
| 1036 |
+
await _context.SaveChangesAsync();
|
| 1037 |
+
|
| 1038 |
+
var sourceId = Convert.ToInt32(backupContact["Id"]);
|
| 1039 |
+
|
| 1040 |
+
if (backupPhotos.TryGetValue(sourceId, out var photos))
|
| 1041 |
+
{
|
| 1042 |
+
foreach (var row in photos)
|
| 1043 |
+
{
|
| 1044 |
+
var photoPath = row["PhotoPath"]?.ToString();
|
| 1045 |
+
if (!string.IsNullOrWhiteSpace(photoPath))
|
| 1046 |
+
{
|
| 1047 |
+
CopyBackupFile(backupUploadsRoot, targetUploadsRoot, photoPath, ref copiedFiles);
|
| 1048 |
+
}
|
| 1049 |
+
|
| 1050 |
+
_context.ContactPhotos.Add(new ContactPhoto
|
| 1051 |
+
{
|
| 1052 |
+
ContactId = existing.Id,
|
| 1053 |
+
PhotoPath = photoPath ?? string.Empty,
|
| 1054 |
+
FileName = row["FileName"]?.ToString() ?? string.Empty,
|
| 1055 |
+
FileSize = row["FileSize"] is long l ? l : 0L,
|
| 1056 |
+
ContentType = row["ContentType"]?.ToString() ?? "application/octet-stream",
|
| 1057 |
+
IsProfilePhoto = row["IsProfilePhoto"] is bool b && b,
|
| 1058 |
+
UploadedAt = row["UploadedAt"] as DateTime? ?? DateTime.Now
|
| 1059 |
+
});
|
| 1060 |
+
}
|
| 1061 |
+
}
|
| 1062 |
+
|
| 1063 |
+
if (backupDocs.TryGetValue(sourceId, out var docs))
|
| 1064 |
+
{
|
| 1065 |
+
foreach (var row in docs)
|
| 1066 |
+
{
|
| 1067 |
+
var docPath = row["DocumentPath"]?.ToString();
|
| 1068 |
+
if (!string.IsNullOrWhiteSpace(docPath))
|
| 1069 |
+
{
|
| 1070 |
+
CopyBackupFile(backupUploadsRoot, targetUploadsRoot, docPath, ref copiedFiles);
|
| 1071 |
+
}
|
| 1072 |
+
|
| 1073 |
+
_context.ContactDocuments.Add(new ContactDocument
|
| 1074 |
+
{
|
| 1075 |
+
ContactId = existing.Id,
|
| 1076 |
+
DocumentPath = docPath ?? string.Empty,
|
| 1077 |
+
FileName = row["FileName"]?.ToString() ?? string.Empty,
|
| 1078 |
+
FileSize = row["FileSize"] is long l ? l : 0L,
|
| 1079 |
+
ContentType = row["ContentType"]?.ToString() ?? "application/octet-stream",
|
| 1080 |
+
DocumentType = row["DocumentType"]?.ToString() ?? "Other",
|
| 1081 |
+
UploadedAt = row["UploadedAt"] as DateTime? ?? DateTime.Now
|
| 1082 |
+
});
|
| 1083 |
+
}
|
| 1084 |
+
}
|
| 1085 |
+
|
| 1086 |
+
if (backupBanks.TryGetValue(sourceId, out var banks))
|
| 1087 |
+
{
|
| 1088 |
+
foreach (var row in banks)
|
| 1089 |
+
{
|
| 1090 |
+
_context.ContactBankAccounts.Add(new ContactBankAccount
|
| 1091 |
+
{
|
| 1092 |
+
ContactId = existing.Id,
|
| 1093 |
+
AccountNumber = row["AccountNumber"]?.ToString(),
|
| 1094 |
+
BankName = row["BankName"]?.ToString(),
|
| 1095 |
+
BranchName = row["BranchName"]?.ToString(),
|
| 1096 |
+
IfscCode = row["IfscCode"]?.ToString(),
|
| 1097 |
+
CreatedAt = row["CreatedAt"] as DateTime? ?? DateTime.Now,
|
| 1098 |
+
UpdatedAt = row["UpdatedAt"] as DateTime? ?? DateTime.Now
|
| 1099 |
+
});
|
| 1100 |
+
}
|
| 1101 |
+
}
|
| 1102 |
+
|
| 1103 |
+
await _context.SaveChangesAsync();
|
| 1104 |
+
restoredCount++;
|
| 1105 |
+
}
|
| 1106 |
+
|
| 1107 |
+
_context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
| 1108 |
+
|
| 1109 |
+
_adminHistoryService.Log(
|
| 1110 |
+
actionType: "Restore",
|
| 1111 |
+
entityType: "Contacts",
|
| 1112 |
+
entityId: 0,
|
| 1113 |
+
performedBy: currentUser?.UserName ?? "Unknown",
|
| 1114 |
+
details: $"Restored {restoredCount} key contacts from backup (copied {copiedFiles} files)."
|
| 1115 |
+
);
|
| 1116 |
+
|
| 1117 |
+
TempData["SuccessMessage"] = $"Restored {restoredCount} contact(s) and copied {copiedFiles} file(s).";
|
| 1118 |
+
return RedirectToAction("Index", "Home");
|
| 1119 |
+
}
|
| 1120 |
+
catch (Exception ex)
|
| 1121 |
+
{
|
| 1122 |
+
TempData["ErrorMessage"] = $"Restore failed: {ex.Message}";
|
| 1123 |
+
return RedirectToAction(nameof(RestoreContacts));
|
| 1124 |
+
}
|
| 1125 |
+
finally
|
| 1126 |
+
{
|
| 1127 |
+
try
|
| 1128 |
+
{
|
| 1129 |
+
if (Directory.Exists(tempRoot))
|
| 1130 |
+
{
|
| 1131 |
+
Directory.Delete(tempRoot, recursive: true);
|
| 1132 |
+
}
|
| 1133 |
+
}
|
| 1134 |
+
catch
|
| 1135 |
+
{
|
| 1136 |
+
// ignore cleanup issues
|
| 1137 |
+
}
|
| 1138 |
+
}
|
| 1139 |
+
|
| 1140 |
+
static void CopyBackupFile(string backupUploadsRoot, string targetUploadsRoot, string webPath, ref int copiedFiles)
|
| 1141 |
+
{
|
| 1142 |
+
var normalized = webPath.Trim();
|
| 1143 |
+
if (normalized.StartsWith("/") == false)
|
| 1144 |
+
{
|
| 1145 |
+
normalized = "/" + normalized;
|
| 1146 |
+
}
|
| 1147 |
+
|
| 1148 |
+
if (!normalized.StartsWith("/uploads/", StringComparison.OrdinalIgnoreCase))
|
| 1149 |
+
{
|
| 1150 |
+
return;
|
| 1151 |
+
}
|
| 1152 |
+
|
| 1153 |
+
var relative = normalized.Substring("/uploads/".Length).Replace('/', Path.DirectorySeparatorChar);
|
| 1154 |
+
var source = Path.Combine(backupUploadsRoot, relative);
|
| 1155 |
+
var dest = Path.Combine(targetUploadsRoot, relative);
|
| 1156 |
+
|
| 1157 |
+
var destDir = Path.GetDirectoryName(dest);
|
| 1158 |
+
if (!string.IsNullOrWhiteSpace(destDir))
|
| 1159 |
+
{
|
| 1160 |
+
Directory.CreateDirectory(destDir);
|
| 1161 |
+
}
|
| 1162 |
+
|
| 1163 |
+
if (System.IO.File.Exists(source))
|
| 1164 |
+
{
|
| 1165 |
+
System.IO.File.Copy(source, dest, overwrite: true);
|
| 1166 |
+
copiedFiles++;
|
| 1167 |
+
}
|
| 1168 |
+
}
|
| 1169 |
+
}
|
| 1170 |
+
}
|
| 1171 |
+
}
|
ContactManagementAPI/Controllers/DocumentController.cs
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using Microsoft.AspNetCore.Mvc;
|
| 2 |
+
using Microsoft.EntityFrameworkCore;
|
| 3 |
+
using ContactManagementAPI.Data;
|
| 4 |
+
using ContactManagementAPI.Models;
|
| 5 |
+
using ContactManagementAPI.Services;
|
| 6 |
+
using ContactManagementAPI.Security;
|
| 7 |
+
|
| 8 |
+
namespace ContactManagementAPI.Controllers
|
| 9 |
+
{
|
| 10 |
+
public class DocumentController : Controller
|
| 11 |
+
{
|
| 12 |
+
private readonly ApplicationDbContext _context;
|
| 13 |
+
private readonly FileUploadService _fileUploadService;
|
| 14 |
+
|
| 15 |
+
public DocumentController(ApplicationDbContext context, FileUploadService fileUploadService)
|
| 16 |
+
{
|
| 17 |
+
_context = context;
|
| 18 |
+
_fileUploadService = fileUploadService;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
// GET: Document/List/5
|
| 22 |
+
[RequireRight(RightsCatalog.ContactsView)]
|
| 23 |
+
public async Task<IActionResult> List(int? id)
|
| 24 |
+
{
|
| 25 |
+
if (id == null)
|
| 26 |
+
return NotFound();
|
| 27 |
+
|
| 28 |
+
var contact = await _context.Contacts
|
| 29 |
+
.Include(c => c.Documents)
|
| 30 |
+
.FirstOrDefaultAsync(c => c.Id == id);
|
| 31 |
+
|
| 32 |
+
if (contact == null)
|
| 33 |
+
return NotFound();
|
| 34 |
+
|
| 35 |
+
return View(contact);
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
// POST: Document/Upload
|
| 39 |
+
[HttpPost]
|
| 40 |
+
[RequireRight(RightsCatalog.DocumentsManage)]
|
| 41 |
+
public async Task<IActionResult> Upload(int contactId, IFormFile documentFile, string documentType = "Other")
|
| 42 |
+
{
|
| 43 |
+
var contact = await _context.Contacts.FindAsync(contactId);
|
| 44 |
+
if (contact == null)
|
| 45 |
+
return Json(new { success = false, message = "Contact not found" });
|
| 46 |
+
|
| 47 |
+
var (success, filePath, errorMessage) = await _fileUploadService.UploadDocumentAsync(documentFile, contactId);
|
| 48 |
+
if (!success)
|
| 49 |
+
return Json(new { success = false, message = errorMessage });
|
| 50 |
+
|
| 51 |
+
var document = new ContactDocument
|
| 52 |
+
{
|
| 53 |
+
ContactId = contactId,
|
| 54 |
+
DocumentPath = filePath,
|
| 55 |
+
FileName = documentFile.FileName,
|
| 56 |
+
FileSize = documentFile.Length,
|
| 57 |
+
ContentType = documentFile.ContentType,
|
| 58 |
+
DocumentType = documentType,
|
| 59 |
+
UploadedAt = DateTime.Now
|
| 60 |
+
};
|
| 61 |
+
|
| 62 |
+
_context.ContactDocuments.Add(document);
|
| 63 |
+
await _context.SaveChangesAsync();
|
| 64 |
+
|
| 65 |
+
return Json(new { success = true, documentId = document.Id, documentPath = filePath });
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
// POST: Document/Delete
|
| 69 |
+
[HttpPost]
|
| 70 |
+
[RequireRight(RightsCatalog.DocumentsManage)]
|
| 71 |
+
public async Task<IActionResult> Delete(int id, int contactId)
|
| 72 |
+
{
|
| 73 |
+
var document = await _context.ContactDocuments.FirstOrDefaultAsync(d => d.Id == id && d.ContactId == contactId);
|
| 74 |
+
if (document == null)
|
| 75 |
+
return Json(new { success = false, message = "Document not found" });
|
| 76 |
+
|
| 77 |
+
_fileUploadService.DeleteFile(document.DocumentPath);
|
| 78 |
+
_context.ContactDocuments.Remove(document);
|
| 79 |
+
await _context.SaveChangesAsync();
|
| 80 |
+
|
| 81 |
+
return Json(new { success = true, message = "Document deleted" });
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
// GET: Document/Download
|
| 85 |
+
[RequireRight(RightsCatalog.ContactsView)]
|
| 86 |
+
public async Task<IActionResult> Download(int id, int contactId)
|
| 87 |
+
{
|
| 88 |
+
var document = await _context.ContactDocuments.FirstOrDefaultAsync(d => d.Id == id && d.ContactId == contactId);
|
| 89 |
+
if (document == null)
|
| 90 |
+
return NotFound();
|
| 91 |
+
|
| 92 |
+
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", document.DocumentPath.TrimStart('/'));
|
| 93 |
+
if (!System.IO.File.Exists(filePath))
|
| 94 |
+
return NotFound();
|
| 95 |
+
|
| 96 |
+
var fileBytes = System.IO.File.ReadAllBytes(filePath);
|
| 97 |
+
return File(fileBytes, document.ContentType, document.FileName);
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
}
|
ContactManagementAPI/Controllers/HomeController.cs
ADDED
|
@@ -0,0 +1,1045 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using Microsoft.AspNetCore.Mvc;
|
| 2 |
+
using Microsoft.EntityFrameworkCore;
|
| 3 |
+
using ContactManagementAPI.Data;
|
| 4 |
+
using ContactManagementAPI.Models;
|
| 5 |
+
using ContactManagementAPI.Services;
|
| 6 |
+
using ContactManagementAPI.Security;
|
| 7 |
+
using System.Globalization;
|
| 8 |
+
|
| 9 |
+
namespace ContactManagementAPI.Controllers
|
| 10 |
+
{
|
| 11 |
+
public class HomeController : Controller
|
| 12 |
+
{
|
| 13 |
+
private readonly ApplicationDbContext _context;
|
| 14 |
+
private readonly FileUploadService _fileUploadService;
|
| 15 |
+
private readonly ImportExportService _importExportService;
|
| 16 |
+
private readonly ContactStatisticsService _statisticsService;
|
| 17 |
+
private readonly UserContextService _userContextService;
|
| 18 |
+
private readonly AdminHistoryService _adminHistoryService;
|
| 19 |
+
|
| 20 |
+
public HomeController(
|
| 21 |
+
ApplicationDbContext context,
|
| 22 |
+
FileUploadService fileUploadService,
|
| 23 |
+
ImportExportService importExportService,
|
| 24 |
+
ContactStatisticsService statisticsService,
|
| 25 |
+
UserContextService userContextService,
|
| 26 |
+
AdminHistoryService adminHistoryService)
|
| 27 |
+
{
|
| 28 |
+
_context = context;
|
| 29 |
+
_fileUploadService = fileUploadService;
|
| 30 |
+
_importExportService = importExportService;
|
| 31 |
+
_statisticsService = statisticsService;
|
| 32 |
+
_userContextService = userContextService;
|
| 33 |
+
_adminHistoryService = adminHistoryService;
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
// GET: Home/Index - Display all contacts with search functionality
|
| 37 |
+
[RequireRight(RightsCatalog.ContactsView)]
|
| 38 |
+
public async Task<IActionResult> Index(string searchTerm = "")
|
| 39 |
+
{
|
| 40 |
+
var currentUser = _userContextService.CurrentUser;
|
| 41 |
+
if (currentUser == null)
|
| 42 |
+
{
|
| 43 |
+
return RedirectToAction("Login", "Account");
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
var contacts = ApplyContactScope(
|
| 47 |
+
_context.Contacts
|
| 48 |
+
.Include(c => c.Group)
|
| 49 |
+
.AsQueryable(),
|
| 50 |
+
currentUser)
|
| 51 |
+
.AsQueryable();
|
| 52 |
+
|
| 53 |
+
if (!string.IsNullOrEmpty(searchTerm))
|
| 54 |
+
{
|
| 55 |
+
contacts = contacts.Where(c =>
|
| 56 |
+
c.FirstName.Contains(searchTerm) ||
|
| 57 |
+
(c.LastName != null && c.LastName.Contains(searchTerm)) ||
|
| 58 |
+
(c.Email != null && c.Email.Contains(searchTerm)) ||
|
| 59 |
+
(c.Mobile1 != null && c.Mobile1.Contains(searchTerm)) ||
|
| 60 |
+
(c.Mobile2 != null && c.Mobile2.Contains(searchTerm)) ||
|
| 61 |
+
(c.Mobile3 != null && c.Mobile3.Contains(searchTerm)));
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
ViewBag.SearchTerm = searchTerm;
|
| 65 |
+
return View(await contacts.OrderByDescending(c => c.UpdatedAt).ToListAsync());
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
// GET: Home/Details/5
|
| 69 |
+
[RequireRight(RightsCatalog.ContactsView)]
|
| 70 |
+
public async Task<IActionResult> Details(int? id)
|
| 71 |
+
{
|
| 72 |
+
if (id == null)
|
| 73 |
+
return NotFound();
|
| 74 |
+
|
| 75 |
+
var currentUser = _userContextService.CurrentUser;
|
| 76 |
+
if (currentUser == null)
|
| 77 |
+
{
|
| 78 |
+
return RedirectToAction("Login", "Account");
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
var contact = await _context.Contacts
|
| 82 |
+
.Include(c => c.Group)
|
| 83 |
+
.Include(c => c.Photos)
|
| 84 |
+
.Include(c => c.Documents)
|
| 85 |
+
.Include(c => c.BankAccounts)
|
| 86 |
+
.FirstOrDefaultAsync(c => c.Id == id);
|
| 87 |
+
|
| 88 |
+
if (contact == null)
|
| 89 |
+
return NotFound();
|
| 90 |
+
|
| 91 |
+
if (!CanAccessContact(currentUser, contact))
|
| 92 |
+
{
|
| 93 |
+
TempData["ErrorMessage"] = "You can view only contacts from your group.";
|
| 94 |
+
return RedirectToAction(nameof(Index));
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
return View(contact);
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
// GET: Home/Create
|
| 101 |
+
[RequireRight(RightsCatalog.ContactsCreate)]
|
| 102 |
+
public IActionResult Create()
|
| 103 |
+
{
|
| 104 |
+
var currentUser = _userContextService.CurrentUser;
|
| 105 |
+
if (currentUser == null)
|
| 106 |
+
{
|
| 107 |
+
return RedirectToAction("Login", "Account");
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
PopulateFormData();
|
| 111 |
+
|
| 112 |
+
if (!currentUser.IsAdmin)
|
| 113 |
+
{
|
| 114 |
+
var scopedContactGroupId = ResolveContactGroupIdForUser(currentUser);
|
| 115 |
+
if (scopedContactGroupId.HasValue)
|
| 116 |
+
{
|
| 117 |
+
ViewData["ForcedGroupId"] = scopedContactGroupId.Value;
|
| 118 |
+
}
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
return View();
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
// POST: Home/Create
|
| 125 |
+
[HttpPost]
|
| 126 |
+
[ValidateAntiForgeryToken]
|
| 127 |
+
[RequireRight(RightsCatalog.ContactsCreate)]
|
| 128 |
+
public async Task<IActionResult> Create([Bind("FirstName,LastName,NickName,Gender,DateOfBirth,Email,Mobile1,Mobile2,Mobile3,WhatsAppNumber,PassportNumber,PanNumber,AadharNumber,DrivingLicenseNumber,VotersId,Address,City,State,PostalCode,Country,GroupId,OtherDetails")] Contact contact, List<ContactBankAccount>? bankAccounts, IFormFile? profilePhoto)
|
| 129 |
+
{
|
| 130 |
+
var currentUser = _userContextService.CurrentUser;
|
| 131 |
+
if (currentUser == null)
|
| 132 |
+
{
|
| 133 |
+
return RedirectToAction("Login", "Account");
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
if (!currentUser.IsAdmin)
|
| 137 |
+
{
|
| 138 |
+
var scopedContactGroupId = ResolveContactGroupIdForUser(currentUser);
|
| 139 |
+
if (!scopedContactGroupId.HasValue)
|
| 140 |
+
{
|
| 141 |
+
ModelState.AddModelError(nameof(Contact.GroupId), "Your account is not assigned to a contact group.");
|
| 142 |
+
}
|
| 143 |
+
else
|
| 144 |
+
{
|
| 145 |
+
contact.GroupId = scopedContactGroupId.Value;
|
| 146 |
+
}
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
NormalizeOptionalBankAccountModelState();
|
| 150 |
+
ValidateDuplicateContact(contact);
|
| 151 |
+
|
| 152 |
+
if (ModelState.IsValid)
|
| 153 |
+
{
|
| 154 |
+
contact.CreatedAt = DateTime.Now;
|
| 155 |
+
contact.UpdatedAt = DateTime.Now;
|
| 156 |
+
|
| 157 |
+
var preparedBankAccounts = PrepareBankAccounts(bankAccounts);
|
| 158 |
+
SyncLegacyBankFields(contact, preparedBankAccounts.FirstOrDefault());
|
| 159 |
+
|
| 160 |
+
// Save contact first to get the ID
|
| 161 |
+
_context.Add(contact);
|
| 162 |
+
await _context.SaveChangesAsync();
|
| 163 |
+
|
| 164 |
+
if (preparedBankAccounts.Any())
|
| 165 |
+
{
|
| 166 |
+
foreach (var bankAccount in preparedBankAccounts)
|
| 167 |
+
{
|
| 168 |
+
bankAccount.ContactId = contact.Id;
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
_context.ContactBankAccounts.AddRange(preparedBankAccounts);
|
| 172 |
+
await _context.SaveChangesAsync();
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
// Handle profile photo upload after we have the contact ID
|
| 176 |
+
if (profilePhoto != null)
|
| 177 |
+
{
|
| 178 |
+
var result = await _fileUploadService.UploadPhotoAsync(profilePhoto, contact.Id);
|
| 179 |
+
if (result.Success)
|
| 180 |
+
{
|
| 181 |
+
contact.PhotoPath = result.FilePath;
|
| 182 |
+
_context.Update(contact);
|
| 183 |
+
await _context.SaveChangesAsync();
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
_adminHistoryService.Log(
|
| 188 |
+
actionType: "Create",
|
| 189 |
+
entityType: "Contact",
|
| 190 |
+
entityId: contact.Id,
|
| 191 |
+
performedBy: _userContextService.CurrentUser?.UserName ?? "Unknown",
|
| 192 |
+
details: $"Created contact '{contact.FirstName} {contact.LastName}'.");
|
| 193 |
+
|
| 194 |
+
TempData["SuccessMessage"] = "Contact created successfully!";
|
| 195 |
+
return RedirectToAction(nameof(Details), new { id = contact.Id });
|
| 196 |
+
}
|
| 197 |
+
PopulateFormData(contact, PrepareBankAccounts(bankAccounts));
|
| 198 |
+
return View(contact);
|
| 199 |
+
}
|
| 200 |
+
|
| 201 |
+
// GET: Home/Edit/5
|
| 202 |
+
[RequireRight(RightsCatalog.ContactsEdit)]
|
| 203 |
+
public async Task<IActionResult> Edit(int? id)
|
| 204 |
+
{
|
| 205 |
+
if (id == null)
|
| 206 |
+
return NotFound();
|
| 207 |
+
|
| 208 |
+
var currentUser = _userContextService.CurrentUser;
|
| 209 |
+
if (currentUser == null)
|
| 210 |
+
{
|
| 211 |
+
return RedirectToAction("Login", "Account");
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
if (!currentUser.IsAdmin)
|
| 215 |
+
{
|
| 216 |
+
TempData["ErrorMessage"] = "Only admin can edit existing contacts.";
|
| 217 |
+
return RedirectToAction(nameof(Index));
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
var contact = await _context.Contacts
|
| 221 |
+
.Include(c => c.BankAccounts)
|
| 222 |
+
.FirstOrDefaultAsync(c => c.Id == id);
|
| 223 |
+
if (contact == null)
|
| 224 |
+
return NotFound();
|
| 225 |
+
|
| 226 |
+
PopulateFormData(contact);
|
| 227 |
+
return View(contact);
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
// POST: Home/Edit/5
|
| 231 |
+
[HttpPost]
|
| 232 |
+
[ValidateAntiForgeryToken]
|
| 233 |
+
[RequireRight(RightsCatalog.ContactsEdit)]
|
| 234 |
+
public async Task<IActionResult> Edit(int id, List<ContactBankAccount>? bankAccounts, IFormFile? profilePhoto)
|
| 235 |
+
{
|
| 236 |
+
var currentUser = _userContextService.CurrentUser;
|
| 237 |
+
if (currentUser == null)
|
| 238 |
+
{
|
| 239 |
+
return RedirectToAction("Login", "Account");
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
if (!currentUser.IsAdmin)
|
| 243 |
+
{
|
| 244 |
+
TempData["ErrorMessage"] = "Only admin can edit existing contacts.";
|
| 245 |
+
return RedirectToAction(nameof(Index));
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
NormalizeOptionalBankAccountModelState();
|
| 249 |
+
|
| 250 |
+
var existingContact = await _context.Contacts
|
| 251 |
+
.AsTracking()
|
| 252 |
+
.Include(c => c.BankAccounts)
|
| 253 |
+
.FirstOrDefaultAsync(c => c.Id == id);
|
| 254 |
+
|
| 255 |
+
if (existingContact == null)
|
| 256 |
+
return NotFound();
|
| 257 |
+
|
| 258 |
+
var updateSucceeded = await TryUpdateModelAsync(
|
| 259 |
+
existingContact,
|
| 260 |
+
"",
|
| 261 |
+
c => c.FirstName,
|
| 262 |
+
c => c.LastName,
|
| 263 |
+
c => c.NickName,
|
| 264 |
+
c => c.Gender,
|
| 265 |
+
c => c.DateOfBirth,
|
| 266 |
+
c => c.Email,
|
| 267 |
+
c => c.Mobile1,
|
| 268 |
+
c => c.Mobile2,
|
| 269 |
+
c => c.Mobile3,
|
| 270 |
+
c => c.WhatsAppNumber,
|
| 271 |
+
c => c.PassportNumber,
|
| 272 |
+
c => c.PanNumber,
|
| 273 |
+
c => c.AadharNumber,
|
| 274 |
+
c => c.DrivingLicenseNumber,
|
| 275 |
+
c => c.VotersId,
|
| 276 |
+
c => c.Address,
|
| 277 |
+
c => c.City,
|
| 278 |
+
c => c.State,
|
| 279 |
+
c => c.PostalCode,
|
| 280 |
+
c => c.Country,
|
| 281 |
+
c => c.GroupId,
|
| 282 |
+
c => c.OtherDetails);
|
| 283 |
+
|
| 284 |
+
if (!updateSucceeded)
|
| 285 |
+
{
|
| 286 |
+
PopulateFormData(existingContact, PrepareBankAccounts(bankAccounts));
|
| 287 |
+
return View(existingContact);
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
ValidateDuplicateContact(existingContact, id);
|
| 291 |
+
|
| 292 |
+
if (ModelState.IsValid)
|
| 293 |
+
{
|
| 294 |
+
try
|
| 295 |
+
{
|
| 296 |
+
var postedGender = Request.Form["Gender"].ToString();
|
| 297 |
+
existingContact.Gender = string.IsNullOrWhiteSpace(postedGender) ? null : postedGender;
|
| 298 |
+
|
| 299 |
+
var postedDateOfBirth = Request.Form["DateOfBirth"].ToString();
|
| 300 |
+
if (string.IsNullOrWhiteSpace(postedDateOfBirth))
|
| 301 |
+
{
|
| 302 |
+
existingContact.DateOfBirth = null;
|
| 303 |
+
}
|
| 304 |
+
else if (DateTime.TryParseExact(postedDateOfBirth, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedDateOfBirth) ||
|
| 305 |
+
DateTime.TryParse(postedDateOfBirth, out parsedDateOfBirth))
|
| 306 |
+
{
|
| 307 |
+
existingContact.DateOfBirth = parsedDateOfBirth;
|
| 308 |
+
}
|
| 309 |
+
|
| 310 |
+
existingContact.UpdatedAt = DateTime.Now;
|
| 311 |
+
|
| 312 |
+
var preparedBankAccounts = PrepareBankAccounts(bankAccounts);
|
| 313 |
+
if (existingContact.BankAccounts.Any())
|
| 314 |
+
{
|
| 315 |
+
_context.ContactBankAccounts.RemoveRange(existingContact.BankAccounts);
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
if (preparedBankAccounts.Any())
|
| 319 |
+
{
|
| 320 |
+
foreach (var bankAccount in preparedBankAccounts)
|
| 321 |
+
{
|
| 322 |
+
bankAccount.ContactId = existingContact.Id;
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
_context.ContactBankAccounts.AddRange(preparedBankAccounts);
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
SyncLegacyBankFields(existingContact, preparedBankAccounts.FirstOrDefault());
|
| 329 |
+
|
| 330 |
+
// Handle profile photo upload
|
| 331 |
+
if (profilePhoto != null)
|
| 332 |
+
{
|
| 333 |
+
var result = await _fileUploadService.UploadPhotoAsync(profilePhoto, existingContact.Id);
|
| 334 |
+
if (result.Success)
|
| 335 |
+
{
|
| 336 |
+
// Delete old photo if exists
|
| 337 |
+
if (!string.IsNullOrEmpty(existingContact.PhotoPath))
|
| 338 |
+
{
|
| 339 |
+
_fileUploadService.DeleteFile(existingContact.PhotoPath);
|
| 340 |
+
}
|
| 341 |
+
existingContact.PhotoPath = result.FilePath;
|
| 342 |
+
}
|
| 343 |
+
}
|
| 344 |
+
|
| 345 |
+
await _context.SaveChangesAsync();
|
| 346 |
+
|
| 347 |
+
_adminHistoryService.Log(
|
| 348 |
+
actionType: "Edit",
|
| 349 |
+
entityType: "Contact",
|
| 350 |
+
entityId: existingContact.Id,
|
| 351 |
+
performedBy: _userContextService.CurrentUser?.UserName ?? "Unknown",
|
| 352 |
+
details: $"Edited contact '{existingContact.FirstName} {existingContact.LastName}'.");
|
| 353 |
+
|
| 354 |
+
TempData["SuccessMessage"] = "Contact updated successfully!";
|
| 355 |
+
return RedirectToAction(nameof(Details), new { id = existingContact.Id });
|
| 356 |
+
}
|
| 357 |
+
catch (DbUpdateConcurrencyException)
|
| 358 |
+
{
|
| 359 |
+
if (!ContactExists(id))
|
| 360 |
+
return NotFound();
|
| 361 |
+
throw;
|
| 362 |
+
}
|
| 363 |
+
}
|
| 364 |
+
PopulateFormData(existingContact, PrepareBankAccounts(bankAccounts));
|
| 365 |
+
return View(existingContact);
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
// GET: Home/Delete/5
|
| 369 |
+
[RequireRight(RightsCatalog.ContactsDelete)]
|
| 370 |
+
public async Task<IActionResult> Delete(int? id)
|
| 371 |
+
{
|
| 372 |
+
if (id == null)
|
| 373 |
+
return NotFound();
|
| 374 |
+
|
| 375 |
+
var currentUser = _userContextService.CurrentUser;
|
| 376 |
+
if (currentUser == null)
|
| 377 |
+
{
|
| 378 |
+
return RedirectToAction("Login", "Account");
|
| 379 |
+
}
|
| 380 |
+
|
| 381 |
+
if (!currentUser.IsAdmin)
|
| 382 |
+
{
|
| 383 |
+
TempData["ErrorMessage"] = "Only admin can delete contacts.";
|
| 384 |
+
return RedirectToAction(nameof(Index));
|
| 385 |
+
}
|
| 386 |
+
|
| 387 |
+
var contact = await _context.Contacts
|
| 388 |
+
.Include(c => c.Group)
|
| 389 |
+
.FirstOrDefaultAsync(c => c.Id == id);
|
| 390 |
+
|
| 391 |
+
if (contact == null)
|
| 392 |
+
return NotFound();
|
| 393 |
+
|
| 394 |
+
return View(contact);
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
+
// POST: Home/Delete/5
|
| 398 |
+
[HttpPost, ActionName("Delete")]
|
| 399 |
+
[ValidateAntiForgeryToken]
|
| 400 |
+
[RequireRight(RightsCatalog.ContactsDelete)]
|
| 401 |
+
public async Task<IActionResult> DeleteConfirmed(int id)
|
| 402 |
+
{
|
| 403 |
+
var currentUser = _userContextService.CurrentUser;
|
| 404 |
+
if (currentUser == null)
|
| 405 |
+
{
|
| 406 |
+
return RedirectToAction("Login", "Account");
|
| 407 |
+
}
|
| 408 |
+
|
| 409 |
+
if (!currentUser.IsAdmin)
|
| 410 |
+
{
|
| 411 |
+
TempData["ErrorMessage"] = "Only admin can delete contacts.";
|
| 412 |
+
return RedirectToAction(nameof(Index));
|
| 413 |
+
}
|
| 414 |
+
|
| 415 |
+
var contact = await _context.Contacts.FindAsync(id);
|
| 416 |
+
if (contact != null)
|
| 417 |
+
{
|
| 418 |
+
_context.Contacts.Remove(contact);
|
| 419 |
+
await _context.SaveChangesAsync();
|
| 420 |
+
TempData["SuccessMessage"] = "Contact deleted successfully!";
|
| 421 |
+
}
|
| 422 |
+
return RedirectToAction(nameof(Index));
|
| 423 |
+
}
|
| 424 |
+
|
| 425 |
+
// POST: Home/DeleteMultiple - Bulk delete contacts
|
| 426 |
+
[HttpPost]
|
| 427 |
+
[ValidateAntiForgeryToken]
|
| 428 |
+
[RequireRight(RightsCatalog.ContactsDelete)]
|
| 429 |
+
public async Task<IActionResult> DeleteMultiple(List<int> contactIds)
|
| 430 |
+
{
|
| 431 |
+
var currentUser = _userContextService.CurrentUser;
|
| 432 |
+
if (currentUser == null)
|
| 433 |
+
{
|
| 434 |
+
return RedirectToAction("Login", "Account");
|
| 435 |
+
}
|
| 436 |
+
|
| 437 |
+
if (!currentUser.IsAdmin)
|
| 438 |
+
{
|
| 439 |
+
TempData["ErrorMessage"] = "Only admin can delete contacts.";
|
| 440 |
+
return RedirectToAction(nameof(Index));
|
| 441 |
+
}
|
| 442 |
+
|
| 443 |
+
if (contactIds == null || !contactIds.Any())
|
| 444 |
+
{
|
| 445 |
+
TempData["ErrorMessage"] = "No contacts selected for deletion.";
|
| 446 |
+
return RedirectToAction(nameof(Index));
|
| 447 |
+
}
|
| 448 |
+
|
| 449 |
+
try
|
| 450 |
+
{
|
| 451 |
+
var contactsToDelete = await _context.Contacts
|
| 452 |
+
.Where(c => contactIds.Contains(c.Id))
|
| 453 |
+
.ToListAsync();
|
| 454 |
+
|
| 455 |
+
if (contactsToDelete.Any())
|
| 456 |
+
{
|
| 457 |
+
_context.Contacts.RemoveRange(contactsToDelete);
|
| 458 |
+
await _context.SaveChangesAsync();
|
| 459 |
+
|
| 460 |
+
TempData["SuccessMessage"] = $"Successfully deleted {contactsToDelete.Count} contact(s)!";
|
| 461 |
+
}
|
| 462 |
+
else
|
| 463 |
+
{
|
| 464 |
+
TempData["ErrorMessage"] = "No matching contacts found to delete.";
|
| 465 |
+
}
|
| 466 |
+
}
|
| 467 |
+
catch (Exception ex)
|
| 468 |
+
{
|
| 469 |
+
TempData["ErrorMessage"] = $"Error deleting contacts: {ex.Message}";
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
return RedirectToAction(nameof(Index));
|
| 473 |
+
}
|
| 474 |
+
|
| 475 |
+
private bool ContactExists(int id)
|
| 476 |
+
{
|
| 477 |
+
return _context.Contacts.Any(e => e.Id == id);
|
| 478 |
+
}
|
| 479 |
+
|
| 480 |
+
private void PopulateFormData(Contact? contact = null, List<ContactBankAccount>? bankAccounts = null)
|
| 481 |
+
{
|
| 482 |
+
ViewData["Groups"] = _context.ContactGroups.OrderBy(g => g.Name).ToList();
|
| 483 |
+
|
| 484 |
+
var bankNames = _context.ContactBankAccounts
|
| 485 |
+
.Where(b => !string.IsNullOrWhiteSpace(b.BankName))
|
| 486 |
+
.Select(b => b.BankName!)
|
| 487 |
+
.Distinct()
|
| 488 |
+
.OrderBy(name => name)
|
| 489 |
+
.ToList();
|
| 490 |
+
|
| 491 |
+
if (!string.IsNullOrWhiteSpace(contact?.BankName) && !bankNames.Contains(contact.BankName))
|
| 492 |
+
{
|
| 493 |
+
bankNames.Add(contact.BankName);
|
| 494 |
+
bankNames = bankNames.OrderBy(name => name).ToList();
|
| 495 |
+
}
|
| 496 |
+
|
| 497 |
+
ViewData["BankNames"] = bankNames;
|
| 498 |
+
|
| 499 |
+
if (bankAccounts != null && bankAccounts.Any())
|
| 500 |
+
{
|
| 501 |
+
ViewData["BankAccounts"] = bankAccounts;
|
| 502 |
+
return;
|
| 503 |
+
}
|
| 504 |
+
|
| 505 |
+
if (contact?.BankAccounts != null && contact.BankAccounts.Any())
|
| 506 |
+
{
|
| 507 |
+
ViewData["BankAccounts"] = contact.BankAccounts.OrderBy(b => b.Id).ToList();
|
| 508 |
+
return;
|
| 509 |
+
}
|
| 510 |
+
|
| 511 |
+
if (contact != null && (!string.IsNullOrWhiteSpace(contact.BankAccountNumber) || !string.IsNullOrWhiteSpace(contact.BankName) || !string.IsNullOrWhiteSpace(contact.BranchName) || !string.IsNullOrWhiteSpace(contact.IfscCode)))
|
| 512 |
+
{
|
| 513 |
+
ViewData["BankAccounts"] = new List<ContactBankAccount>
|
| 514 |
+
{
|
| 515 |
+
new ContactBankAccount
|
| 516 |
+
{
|
| 517 |
+
AccountNumber = contact.BankAccountNumber,
|
| 518 |
+
BankName = contact.BankName,
|
| 519 |
+
BranchName = contact.BranchName,
|
| 520 |
+
IfscCode = contact.IfscCode
|
| 521 |
+
}
|
| 522 |
+
};
|
| 523 |
+
return;
|
| 524 |
+
}
|
| 525 |
+
|
| 526 |
+
ViewData["BankAccounts"] = new List<ContactBankAccount> { new ContactBankAccount() };
|
| 527 |
+
}
|
| 528 |
+
|
| 529 |
+
private static List<ContactBankAccount> PrepareBankAccounts(List<ContactBankAccount>? bankAccounts)
|
| 530 |
+
{
|
| 531 |
+
return (bankAccounts ?? new List<ContactBankAccount>())
|
| 532 |
+
.Where(b => !string.IsNullOrWhiteSpace(b.AccountNumber) || !string.IsNullOrWhiteSpace(b.BankName) || !string.IsNullOrWhiteSpace(b.BranchName) || !string.IsNullOrWhiteSpace(b.IfscCode))
|
| 533 |
+
.Select(b => new ContactBankAccount
|
| 534 |
+
{
|
| 535 |
+
AccountNumber = b.AccountNumber,
|
| 536 |
+
BankName = b.BankName,
|
| 537 |
+
BranchName = b.BranchName,
|
| 538 |
+
IfscCode = b.IfscCode,
|
| 539 |
+
CreatedAt = DateTime.Now,
|
| 540 |
+
UpdatedAt = DateTime.Now
|
| 541 |
+
})
|
| 542 |
+
.ToList();
|
| 543 |
+
}
|
| 544 |
+
|
| 545 |
+
private static void SyncLegacyBankFields(Contact contact, ContactBankAccount? primaryBankAccount)
|
| 546 |
+
{
|
| 547 |
+
if (primaryBankAccount == null)
|
| 548 |
+
{
|
| 549 |
+
contact.BankAccountNumber = null;
|
| 550 |
+
contact.BankName = null;
|
| 551 |
+
contact.BranchName = null;
|
| 552 |
+
contact.IfscCode = null;
|
| 553 |
+
return;
|
| 554 |
+
}
|
| 555 |
+
|
| 556 |
+
contact.BankAccountNumber = primaryBankAccount.AccountNumber;
|
| 557 |
+
contact.BankName = primaryBankAccount.BankName;
|
| 558 |
+
contact.BranchName = primaryBankAccount.BranchName;
|
| 559 |
+
contact.IfscCode = primaryBankAccount.IfscCode;
|
| 560 |
+
}
|
| 561 |
+
|
| 562 |
+
private void NormalizeOptionalBankAccountModelState()
|
| 563 |
+
{
|
| 564 |
+
var bankAccountKeys = ModelState.Keys
|
| 565 |
+
.Where(key => key.StartsWith("bankAccounts[", StringComparison.OrdinalIgnoreCase))
|
| 566 |
+
.ToList();
|
| 567 |
+
|
| 568 |
+
foreach (var key in bankAccountKeys)
|
| 569 |
+
{
|
| 570 |
+
ModelState.Remove(key);
|
| 571 |
+
}
|
| 572 |
+
}
|
| 573 |
+
|
| 574 |
+
private void ValidateDuplicateContact(Contact contact, int? excludeContactId = null)
|
| 575 |
+
{
|
| 576 |
+
var normalizedMobile = NormalizeDigits(contact.Mobile1);
|
| 577 |
+
var normalizedAadhar = NormalizeDigits(contact.AadharNumber);
|
| 578 |
+
|
| 579 |
+
if (!string.IsNullOrWhiteSpace(normalizedMobile))
|
| 580 |
+
{
|
| 581 |
+
var mobileConflict = _context.Contacts
|
| 582 |
+
.AsNoTracking()
|
| 583 |
+
.Where(c => c.Id != (excludeContactId ?? 0) && !string.IsNullOrWhiteSpace(c.Mobile1))
|
| 584 |
+
.Select(c => new { c.FirstName, c.LastName, c.Mobile1 })
|
| 585 |
+
.ToList()
|
| 586 |
+
.FirstOrDefault(c => NormalizeDigits(c.Mobile1) == normalizedMobile);
|
| 587 |
+
|
| 588 |
+
if (mobileConflict != null)
|
| 589 |
+
{
|
| 590 |
+
ModelState.AddModelError(nameof(Contact.Mobile1),
|
| 591 |
+
$"Mobile number already exists for contact '{mobileConflict.FirstName} {mobileConflict.LastName}'.");
|
| 592 |
+
}
|
| 593 |
+
}
|
| 594 |
+
|
| 595 |
+
if (!string.IsNullOrWhiteSpace(normalizedAadhar))
|
| 596 |
+
{
|
| 597 |
+
var aadharConflict = _context.Contacts
|
| 598 |
+
.AsNoTracking()
|
| 599 |
+
.Where(c => c.Id != (excludeContactId ?? 0) && !string.IsNullOrWhiteSpace(c.AadharNumber))
|
| 600 |
+
.Select(c => new { c.FirstName, c.LastName, c.AadharNumber })
|
| 601 |
+
.ToList()
|
| 602 |
+
.FirstOrDefault(c => NormalizeDigits(c.AadharNumber) == normalizedAadhar);
|
| 603 |
+
|
| 604 |
+
if (aadharConflict != null)
|
| 605 |
+
{
|
| 606 |
+
ModelState.AddModelError(nameof(Contact.AadharNumber),
|
| 607 |
+
$"Aadhar number already exists for contact '{aadharConflict.FirstName} {aadharConflict.LastName}'.");
|
| 608 |
+
}
|
| 609 |
+
}
|
| 610 |
+
|
| 611 |
+
if (string.IsNullOrWhiteSpace(normalizedMobile) && string.IsNullOrWhiteSpace(normalizedAadhar))
|
| 612 |
+
{
|
| 613 |
+
var firstName = NormalizeText(contact.FirstName);
|
| 614 |
+
var lastName = NormalizeText(contact.LastName);
|
| 615 |
+
var nickName = NormalizeText(contact.NickName);
|
| 616 |
+
|
| 617 |
+
if (!string.IsNullOrWhiteSpace(firstName))
|
| 618 |
+
{
|
| 619 |
+
var nameConflict = _context.Contacts
|
| 620 |
+
.AsNoTracking()
|
| 621 |
+
.Where(c => c.Id != (excludeContactId ?? 0) && !string.IsNullOrWhiteSpace(c.FirstName))
|
| 622 |
+
.Select(c => new { c.FirstName, c.LastName, c.NickName })
|
| 623 |
+
.ToList()
|
| 624 |
+
.FirstOrDefault(c =>
|
| 625 |
+
NormalizeText(c.FirstName) == firstName &&
|
| 626 |
+
NormalizeText(c.LastName) == lastName &&
|
| 627 |
+
NormalizeText(c.NickName) == nickName);
|
| 628 |
+
|
| 629 |
+
if (nameConflict != null)
|
| 630 |
+
{
|
| 631 |
+
ModelState.AddModelError(nameof(Contact.FirstName),
|
| 632 |
+
"A contact with the same First Name, Last Name, and Nick Name already exists. Provide Mobile1 or Aadhar if this is a different person.");
|
| 633 |
+
}
|
| 634 |
+
}
|
| 635 |
+
}
|
| 636 |
+
}
|
| 637 |
+
|
| 638 |
+
private List<Contact> FilterDuplicateImportedContacts(List<Contact> contacts, List<string> errors)
|
| 639 |
+
{
|
| 640 |
+
var validContacts = new List<Contact>();
|
| 641 |
+
|
| 642 |
+
var existingContacts = _context.Contacts
|
| 643 |
+
.AsNoTracking()
|
| 644 |
+
.Select(c => new { c.FirstName, c.LastName, c.NickName, c.Mobile1, c.AadharNumber })
|
| 645 |
+
.ToList();
|
| 646 |
+
|
| 647 |
+
var seenMobiles = new HashSet<string>();
|
| 648 |
+
var seenAadhars = new HashSet<string>();
|
| 649 |
+
var seenNames = new HashSet<string>();
|
| 650 |
+
|
| 651 |
+
for (var i = 0; i < contacts.Count; i++)
|
| 652 |
+
{
|
| 653 |
+
var contact = contacts[i];
|
| 654 |
+
var rowLabel = $"Row {i + 1} ({contact.FirstName} {contact.LastName})";
|
| 655 |
+
|
| 656 |
+
var normalizedMobile = NormalizeDigits(contact.Mobile1);
|
| 657 |
+
var normalizedAadhar = NormalizeDigits(contact.AadharNumber);
|
| 658 |
+
var firstName = NormalizeText(contact.FirstName);
|
| 659 |
+
var lastName = NormalizeText(contact.LastName);
|
| 660 |
+
var nickName = NormalizeText(contact.NickName);
|
| 661 |
+
var nameKey = $"{firstName}|{lastName}|{nickName}";
|
| 662 |
+
|
| 663 |
+
var hasError = false;
|
| 664 |
+
|
| 665 |
+
if (!string.IsNullOrWhiteSpace(normalizedMobile))
|
| 666 |
+
{
|
| 667 |
+
var existsInDb = existingContacts.Any(c => NormalizeDigits(c.Mobile1) == normalizedMobile);
|
| 668 |
+
var existsInImport = seenMobiles.Contains(normalizedMobile);
|
| 669 |
+
if (existsInDb || existsInImport)
|
| 670 |
+
{
|
| 671 |
+
errors.Add($"{rowLabel}: Mobile1 already exists.");
|
| 672 |
+
hasError = true;
|
| 673 |
+
}
|
| 674 |
+
}
|
| 675 |
+
|
| 676 |
+
if (!string.IsNullOrWhiteSpace(normalizedAadhar))
|
| 677 |
+
{
|
| 678 |
+
var existsInDb = existingContacts.Any(c => NormalizeDigits(c.AadharNumber) == normalizedAadhar);
|
| 679 |
+
var existsInImport = seenAadhars.Contains(normalizedAadhar);
|
| 680 |
+
if (existsInDb || existsInImport)
|
| 681 |
+
{
|
| 682 |
+
errors.Add($"{rowLabel}: AadharNumber already exists.");
|
| 683 |
+
hasError = true;
|
| 684 |
+
}
|
| 685 |
+
}
|
| 686 |
+
|
| 687 |
+
if (string.IsNullOrWhiteSpace(normalizedMobile) && string.IsNullOrWhiteSpace(normalizedAadhar))
|
| 688 |
+
{
|
| 689 |
+
var existsInDb = existingContacts.Any(c =>
|
| 690 |
+
NormalizeText(c.FirstName) == firstName &&
|
| 691 |
+
NormalizeText(c.LastName) == lastName &&
|
| 692 |
+
NormalizeText(c.NickName) == nickName);
|
| 693 |
+
var existsInImport = seenNames.Contains(nameKey);
|
| 694 |
+
|
| 695 |
+
if (existsInDb || existsInImport)
|
| 696 |
+
{
|
| 697 |
+
errors.Add($"{rowLabel}: Same First Name + Last Name + Nick Name already exists.");
|
| 698 |
+
hasError = true;
|
| 699 |
+
}
|
| 700 |
+
}
|
| 701 |
+
|
| 702 |
+
if (hasError)
|
| 703 |
+
{
|
| 704 |
+
continue;
|
| 705 |
+
}
|
| 706 |
+
|
| 707 |
+
if (!string.IsNullOrWhiteSpace(normalizedMobile))
|
| 708 |
+
{
|
| 709 |
+
seenMobiles.Add(normalizedMobile);
|
| 710 |
+
}
|
| 711 |
+
|
| 712 |
+
if (!string.IsNullOrWhiteSpace(normalizedAadhar))
|
| 713 |
+
{
|
| 714 |
+
seenAadhars.Add(normalizedAadhar);
|
| 715 |
+
}
|
| 716 |
+
|
| 717 |
+
if (string.IsNullOrWhiteSpace(normalizedMobile) && string.IsNullOrWhiteSpace(normalizedAadhar))
|
| 718 |
+
{
|
| 719 |
+
seenNames.Add(nameKey);
|
| 720 |
+
}
|
| 721 |
+
|
| 722 |
+
validContacts.Add(contact);
|
| 723 |
+
}
|
| 724 |
+
|
| 725 |
+
return validContacts;
|
| 726 |
+
}
|
| 727 |
+
|
| 728 |
+
private static string NormalizeDigits(string? value)
|
| 729 |
+
{
|
| 730 |
+
if (string.IsNullOrWhiteSpace(value))
|
| 731 |
+
{
|
| 732 |
+
return string.Empty;
|
| 733 |
+
}
|
| 734 |
+
|
| 735 |
+
return new string(value.Where(char.IsDigit).ToArray());
|
| 736 |
+
}
|
| 737 |
+
|
| 738 |
+
private static string NormalizeText(string? value)
|
| 739 |
+
{
|
| 740 |
+
return (value ?? string.Empty).Trim().ToUpperInvariant();
|
| 741 |
+
}
|
| 742 |
+
|
| 743 |
+
#region Import/Export Actions
|
| 744 |
+
|
| 745 |
+
// GET: Home/Dashboard - Display contact statistics
|
| 746 |
+
[RequireRight(RightsCatalog.ContactsView)]
|
| 747 |
+
public async Task<IActionResult> Dashboard()
|
| 748 |
+
{
|
| 749 |
+
var currentUser = _userContextService.CurrentUser;
|
| 750 |
+
if (currentUser == null)
|
| 751 |
+
{
|
| 752 |
+
return RedirectToAction("Login", "Account");
|
| 753 |
+
}
|
| 754 |
+
|
| 755 |
+
if (!currentUser.IsAdmin)
|
| 756 |
+
{
|
| 757 |
+
TempData["ErrorMessage"] = "Dashboard is available only for admin.";
|
| 758 |
+
return RedirectToAction(nameof(Index));
|
| 759 |
+
}
|
| 760 |
+
|
| 761 |
+
var statistics = await _statisticsService.GetStatisticsAsync();
|
| 762 |
+
return View(statistics);
|
| 763 |
+
}
|
| 764 |
+
|
| 765 |
+
// GET: Home/FindDuplicates - Display potential duplicate contacts
|
| 766 |
+
[RequireRight(RightsCatalog.ContactsView)]
|
| 767 |
+
public async Task<IActionResult> FindDuplicates()
|
| 768 |
+
{
|
| 769 |
+
var currentUser = _userContextService.CurrentUser;
|
| 770 |
+
if (currentUser == null)
|
| 771 |
+
{
|
| 772 |
+
return RedirectToAction("Login", "Account");
|
| 773 |
+
}
|
| 774 |
+
|
| 775 |
+
if (!currentUser.IsAdmin)
|
| 776 |
+
{
|
| 777 |
+
TempData["ErrorMessage"] = "Find Duplicates is available only for admin.";
|
| 778 |
+
return RedirectToAction(nameof(Index));
|
| 779 |
+
}
|
| 780 |
+
|
| 781 |
+
var duplicates = await _statisticsService.FindDuplicatesAsync();
|
| 782 |
+
return View(duplicates);
|
| 783 |
+
}
|
| 784 |
+
|
| 785 |
+
// GET: Home/Import - Display import page
|
| 786 |
+
[RequireRight(RightsCatalog.ContactsCreate)]
|
| 787 |
+
public IActionResult Import()
|
| 788 |
+
{
|
| 789 |
+
return View();
|
| 790 |
+
}
|
| 791 |
+
|
| 792 |
+
// POST: Home/ImportFile - Handle file import
|
| 793 |
+
[HttpPost]
|
| 794 |
+
[ValidateAntiForgeryToken]
|
| 795 |
+
[RequireRight(RightsCatalog.ContactsCreate)]
|
| 796 |
+
public async Task<IActionResult> ImportFile(IFormFile file, string fileType)
|
| 797 |
+
{
|
| 798 |
+
var currentUser = _userContextService.CurrentUser;
|
| 799 |
+
if (currentUser == null)
|
| 800 |
+
{
|
| 801 |
+
return RedirectToAction("Login", "Account");
|
| 802 |
+
}
|
| 803 |
+
|
| 804 |
+
if (file == null || file.Length == 0)
|
| 805 |
+
{
|
| 806 |
+
TempData["ErrorMessage"] = "Please select a file to import.";
|
| 807 |
+
return RedirectToAction(nameof(Import));
|
| 808 |
+
}
|
| 809 |
+
|
| 810 |
+
List<Contact> contacts;
|
| 811 |
+
List<string> errors;
|
| 812 |
+
|
| 813 |
+
try
|
| 814 |
+
{
|
| 815 |
+
using var stream = file.OpenReadStream();
|
| 816 |
+
|
| 817 |
+
if (fileType == "excel")
|
| 818 |
+
{
|
| 819 |
+
(contacts, errors) = await _importExportService.ImportFromExcel(stream);
|
| 820 |
+
}
|
| 821 |
+
else if (fileType == "csv")
|
| 822 |
+
{
|
| 823 |
+
(contacts, errors) = await _importExportService.ImportFromCsv(stream);
|
| 824 |
+
}
|
| 825 |
+
else
|
| 826 |
+
{
|
| 827 |
+
TempData["ErrorMessage"] = "Invalid file type selected.";
|
| 828 |
+
return RedirectToAction(nameof(Import));
|
| 829 |
+
}
|
| 830 |
+
|
| 831 |
+
if (errors.Any())
|
| 832 |
+
{
|
| 833 |
+
TempData["ErrorMessage"] = $"Import completed with errors:<br/>{string.Join("<br/>", errors)}";
|
| 834 |
+
}
|
| 835 |
+
|
| 836 |
+
if (contacts.Any())
|
| 837 |
+
{
|
| 838 |
+
if (!currentUser.IsAdmin)
|
| 839 |
+
{
|
| 840 |
+
var scopedContactGroupId = ResolveContactGroupIdForUser(currentUser);
|
| 841 |
+
if (!scopedContactGroupId.HasValue)
|
| 842 |
+
{
|
| 843 |
+
TempData["ErrorMessage"] = "Your account is not assigned to a contact group.";
|
| 844 |
+
return RedirectToAction(nameof(Import));
|
| 845 |
+
}
|
| 846 |
+
|
| 847 |
+
foreach (var importedContact in contacts)
|
| 848 |
+
{
|
| 849 |
+
importedContact.GroupId = scopedContactGroupId.Value;
|
| 850 |
+
}
|
| 851 |
+
}
|
| 852 |
+
|
| 853 |
+
contacts = FilterDuplicateImportedContacts(contacts, errors);
|
| 854 |
+
|
| 855 |
+
if (errors.Any())
|
| 856 |
+
{
|
| 857 |
+
TempData["ErrorMessage"] = $"Import completed with errors:<br/>{string.Join("<br/>", errors)}";
|
| 858 |
+
}
|
| 859 |
+
|
| 860 |
+
if (!contacts.Any())
|
| 861 |
+
{
|
| 862 |
+
TempData["ErrorMessage"] = TempData["ErrorMessage"] ?? "No valid contacts found in the file.";
|
| 863 |
+
return RedirectToAction(nameof(Import));
|
| 864 |
+
}
|
| 865 |
+
|
| 866 |
+
// Set change tracking to true for saving
|
| 867 |
+
_context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.TrackAll;
|
| 868 |
+
|
| 869 |
+
await _context.Contacts.AddRangeAsync(contacts);
|
| 870 |
+
await _context.SaveChangesAsync();
|
| 871 |
+
|
| 872 |
+
// Reset tracking behavior
|
| 873 |
+
_context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
| 874 |
+
|
| 875 |
+
TempData["SuccessMessage"] = $"Successfully imported {contacts.Count} contact(s)!";
|
| 876 |
+
}
|
| 877 |
+
else
|
| 878 |
+
{
|
| 879 |
+
TempData["ErrorMessage"] = "No valid contacts found in the file.";
|
| 880 |
+
}
|
| 881 |
+
}
|
| 882 |
+
catch (Exception ex)
|
| 883 |
+
{
|
| 884 |
+
TempData["ErrorMessage"] = $"Error importing file: {ex.Message}";
|
| 885 |
+
}
|
| 886 |
+
|
| 887 |
+
return RedirectToAction(nameof(Index));
|
| 888 |
+
}
|
| 889 |
+
|
| 890 |
+
// GET: Home/ExportExcel - Export to Excel
|
| 891 |
+
[RequireRight(RightsCatalog.ContactsView)]
|
| 892 |
+
public async Task<IActionResult> ExportExcel()
|
| 893 |
+
{
|
| 894 |
+
var currentUser = _userContextService.CurrentUser;
|
| 895 |
+
if (currentUser == null)
|
| 896 |
+
{
|
| 897 |
+
return RedirectToAction("Login", "Account");
|
| 898 |
+
}
|
| 899 |
+
|
| 900 |
+
var contacts = await ApplyContactScope(
|
| 901 |
+
_context.Contacts
|
| 902 |
+
.Include(c => c.Group)
|
| 903 |
+
.OrderBy(c => c.FirstName),
|
| 904 |
+
currentUser)
|
| 905 |
+
.ToListAsync();
|
| 906 |
+
|
| 907 |
+
var fileBytes = await _importExportService.ExportToExcel(contacts);
|
| 908 |
+
var fileName = $"Contacts_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx";
|
| 909 |
+
|
| 910 |
+
return File(fileBytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
|
| 911 |
+
}
|
| 912 |
+
|
| 913 |
+
// GET: Home/ExportCsv - Export to CSV
|
| 914 |
+
[RequireRight(RightsCatalog.ContactsView)]
|
| 915 |
+
public async Task<IActionResult> ExportCsv()
|
| 916 |
+
{
|
| 917 |
+
var currentUser = _userContextService.CurrentUser;
|
| 918 |
+
if (currentUser == null)
|
| 919 |
+
{
|
| 920 |
+
return RedirectToAction("Login", "Account");
|
| 921 |
+
}
|
| 922 |
+
|
| 923 |
+
var contacts = await ApplyContactScope(
|
| 924 |
+
_context.Contacts
|
| 925 |
+
.Include(c => c.Group)
|
| 926 |
+
.OrderBy(c => c.FirstName),
|
| 927 |
+
currentUser)
|
| 928 |
+
.ToListAsync();
|
| 929 |
+
|
| 930 |
+
var fileBytes = await _importExportService.ExportToCsv(contacts);
|
| 931 |
+
var fileName = $"Contacts_{DateTime.Now:yyyyMMdd_HHmmss}.csv";
|
| 932 |
+
|
| 933 |
+
return File(fileBytes, "text/csv", fileName);
|
| 934 |
+
}
|
| 935 |
+
|
| 936 |
+
// GET: Home/ExportPdf - Export to PDF
|
| 937 |
+
[RequireRight(RightsCatalog.ContactsView)]
|
| 938 |
+
public async Task<IActionResult> ExportPdf()
|
| 939 |
+
{
|
| 940 |
+
var currentUser = _userContextService.CurrentUser;
|
| 941 |
+
if (currentUser == null)
|
| 942 |
+
{
|
| 943 |
+
return RedirectToAction("Login", "Account");
|
| 944 |
+
}
|
| 945 |
+
|
| 946 |
+
var contacts = await ApplyContactScope(
|
| 947 |
+
_context.Contacts
|
| 948 |
+
.Include(c => c.Group)
|
| 949 |
+
.OrderBy(c => c.FirstName),
|
| 950 |
+
currentUser)
|
| 951 |
+
.ToListAsync();
|
| 952 |
+
|
| 953 |
+
var fileBytes = await _importExportService.ExportToPdf(contacts);
|
| 954 |
+
var fileName = $"Contacts_{DateTime.Now:yyyyMMdd_HHmmss}.pdf";
|
| 955 |
+
|
| 956 |
+
return File(fileBytes, "application/pdf", fileName);
|
| 957 |
+
}
|
| 958 |
+
|
| 959 |
+
// GET: Home/DownloadTemplate - Download import template
|
| 960 |
+
public async Task<IActionResult> DownloadTemplate(string type)
|
| 961 |
+
{
|
| 962 |
+
if (type == "excel")
|
| 963 |
+
{
|
| 964 |
+
var fileBytes = await _importExportService.GenerateExcelTemplate();
|
| 965 |
+
return File(fileBytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Contact_Import_Template.xlsx");
|
| 966 |
+
}
|
| 967 |
+
else if (type == "csv")
|
| 968 |
+
{
|
| 969 |
+
var fileBytes = await _importExportService.GenerateCsvTemplate();
|
| 970 |
+
return File(fileBytes, "text/csv", "Contact_Import_Template.csv");
|
| 971 |
+
}
|
| 972 |
+
|
| 973 |
+
return NotFound();
|
| 974 |
+
}
|
| 975 |
+
|
| 976 |
+
private IQueryable<Contact> ApplyContactScope(IQueryable<Contact> query, AppUser currentUser)
|
| 977 |
+
{
|
| 978 |
+
if (currentUser.IsAdmin)
|
| 979 |
+
{
|
| 980 |
+
return query;
|
| 981 |
+
}
|
| 982 |
+
|
| 983 |
+
var scopedContactGroupId = ResolveContactGroupIdForUser(currentUser);
|
| 984 |
+
if (!scopedContactGroupId.HasValue)
|
| 985 |
+
{
|
| 986 |
+
return query.Where(c => false);
|
| 987 |
+
}
|
| 988 |
+
|
| 989 |
+
var groupId = scopedContactGroupId.Value;
|
| 990 |
+
return query.Where(c => c.GroupId == groupId);
|
| 991 |
+
}
|
| 992 |
+
|
| 993 |
+
private bool CanAccessContact(AppUser currentUser, Contact contact)
|
| 994 |
+
{
|
| 995 |
+
if (currentUser.IsAdmin)
|
| 996 |
+
{
|
| 997 |
+
return true;
|
| 998 |
+
}
|
| 999 |
+
|
| 1000 |
+
var scopedContactGroupId = ResolveContactGroupIdForUser(currentUser);
|
| 1001 |
+
return scopedContactGroupId.HasValue && contact.GroupId == scopedContactGroupId.Value;
|
| 1002 |
+
}
|
| 1003 |
+
|
| 1004 |
+
private int? ResolveContactGroupIdForUser(AppUser user)
|
| 1005 |
+
{
|
| 1006 |
+
if (user.IsAdmin)
|
| 1007 |
+
{
|
| 1008 |
+
return null;
|
| 1009 |
+
}
|
| 1010 |
+
|
| 1011 |
+
if (user.GroupId <= 0)
|
| 1012 |
+
{
|
| 1013 |
+
return null;
|
| 1014 |
+
}
|
| 1015 |
+
|
| 1016 |
+
var userGroupName = _context.UserGroups
|
| 1017 |
+
.Where(g => g.Id == user.GroupId)
|
| 1018 |
+
.Select(g => g.Name)
|
| 1019 |
+
.FirstOrDefault();
|
| 1020 |
+
|
| 1021 |
+
if (!string.IsNullOrWhiteSpace(userGroupName) && userGroupName.StartsWith("ContactGroup - ", StringComparison.OrdinalIgnoreCase))
|
| 1022 |
+
{
|
| 1023 |
+
var contactGroupName = userGroupName.Substring("ContactGroup - ".Length).Trim();
|
| 1024 |
+
var mappedContactGroupId = _context.ContactGroups
|
| 1025 |
+
.Where(cg => cg.Name == contactGroupName)
|
| 1026 |
+
.Select(cg => (int?)cg.Id)
|
| 1027 |
+
.FirstOrDefault();
|
| 1028 |
+
|
| 1029 |
+
if (mappedContactGroupId.HasValue)
|
| 1030 |
+
{
|
| 1031 |
+
return mappedContactGroupId.Value;
|
| 1032 |
+
}
|
| 1033 |
+
}
|
| 1034 |
+
|
| 1035 |
+
var directMatch = _context.ContactGroups
|
| 1036 |
+
.Where(cg => cg.Id == user.GroupId)
|
| 1037 |
+
.Select(cg => (int?)cg.Id)
|
| 1038 |
+
.FirstOrDefault();
|
| 1039 |
+
|
| 1040 |
+
return directMatch;
|
| 1041 |
+
}
|
| 1042 |
+
|
| 1043 |
+
#endregion
|
| 1044 |
+
}
|
| 1045 |
+
}
|
ContactManagementAPI/Controllers/PhotoController.cs
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using Microsoft.AspNetCore.Mvc;
|
| 2 |
+
using Microsoft.EntityFrameworkCore;
|
| 3 |
+
using ContactManagementAPI.Data;
|
| 4 |
+
using ContactManagementAPI.Models;
|
| 5 |
+
using ContactManagementAPI.Services;
|
| 6 |
+
using ContactManagementAPI.Security;
|
| 7 |
+
using System.Text.Json;
|
| 8 |
+
|
| 9 |
+
namespace ContactManagementAPI.Controllers
|
| 10 |
+
{
|
| 11 |
+
public class PhotoController : Controller
|
| 12 |
+
{
|
| 13 |
+
private readonly ApplicationDbContext _context;
|
| 14 |
+
private readonly FileUploadService _fileUploadService;
|
| 15 |
+
|
| 16 |
+
public PhotoController(ApplicationDbContext context, FileUploadService fileUploadService)
|
| 17 |
+
{
|
| 18 |
+
_context = context;
|
| 19 |
+
_fileUploadService = fileUploadService;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
// GET: Photo/Gallery/5
|
| 23 |
+
[RequireRight(RightsCatalog.PhotosManage)]
|
| 24 |
+
public async Task<IActionResult> Gallery(int? id)
|
| 25 |
+
{
|
| 26 |
+
if (id == null)
|
| 27 |
+
return NotFound();
|
| 28 |
+
|
| 29 |
+
var contact = await _context.Contacts
|
| 30 |
+
.Include(c => c.Photos)
|
| 31 |
+
.FirstOrDefaultAsync(c => c.Id == id);
|
| 32 |
+
|
| 33 |
+
if (contact == null)
|
| 34 |
+
return NotFound();
|
| 35 |
+
|
| 36 |
+
return View(contact);
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
// POST: Photo/Upload
|
| 40 |
+
[HttpPost]
|
| 41 |
+
[RequireRight(RightsCatalog.PhotosManage)]
|
| 42 |
+
public async Task<IActionResult> Upload(int contactId, IFormFile photoFile)
|
| 43 |
+
{
|
| 44 |
+
var contact = await _context.Contacts.FindAsync(contactId);
|
| 45 |
+
if (contact == null)
|
| 46 |
+
return Json(new { success = false, message = "Contact not found" });
|
| 47 |
+
|
| 48 |
+
var (success, filePath, errorMessage) = await _fileUploadService.UploadPhotoAsync(photoFile, contactId);
|
| 49 |
+
if (!success)
|
| 50 |
+
return Json(new { success = false, message = errorMessage });
|
| 51 |
+
|
| 52 |
+
var photo = new ContactPhoto
|
| 53 |
+
{
|
| 54 |
+
ContactId = contactId,
|
| 55 |
+
PhotoPath = filePath,
|
| 56 |
+
FileName = photoFile.FileName,
|
| 57 |
+
FileSize = photoFile.Length,
|
| 58 |
+
ContentType = photoFile.ContentType,
|
| 59 |
+
IsProfilePhoto = false,
|
| 60 |
+
UploadedAt = DateTime.Now
|
| 61 |
+
};
|
| 62 |
+
|
| 63 |
+
_context.ContactPhotos.Add(photo);
|
| 64 |
+
await _context.SaveChangesAsync();
|
| 65 |
+
|
| 66 |
+
return Json(new { success = true, photoId = photo.Id, photoPath = filePath });
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
// POST: Photo/SetProfilePhoto
|
| 70 |
+
[HttpPost]
|
| 71 |
+
[RequireRight(RightsCatalog.PhotosManage)]
|
| 72 |
+
public async Task<IActionResult> SetProfilePhoto(int contactId, int photoId)
|
| 73 |
+
{
|
| 74 |
+
(contactId, photoId) = await ResolveContactAndPhotoIdsAsync(contactId, photoId);
|
| 75 |
+
|
| 76 |
+
var contact = await _context.Contacts
|
| 77 |
+
.Include(c => c.Photos)
|
| 78 |
+
.FirstOrDefaultAsync(c => c.Id == contactId);
|
| 79 |
+
|
| 80 |
+
if (contact == null)
|
| 81 |
+
return Json(new { success = false, message = "Contact not found" });
|
| 82 |
+
|
| 83 |
+
var photo = await _context.ContactPhotos.FirstOrDefaultAsync(p => p.Id == photoId && p.ContactId == contactId);
|
| 84 |
+
if (photo == null)
|
| 85 |
+
return Json(new { success = false, message = "Photo not found" });
|
| 86 |
+
|
| 87 |
+
// Unset all other profile photos
|
| 88 |
+
foreach (var p in contact.Photos.Where(p => p.IsProfilePhoto))
|
| 89 |
+
{
|
| 90 |
+
p.IsProfilePhoto = false;
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
photo.IsProfilePhoto = true;
|
| 94 |
+
contact.PhotoPath = photo.PhotoPath;
|
| 95 |
+
_context.Update(contact);
|
| 96 |
+
await _context.SaveChangesAsync();
|
| 97 |
+
|
| 98 |
+
return Json(new { success = true, message = "Profile photo updated" });
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
// POST: Photo/Delete
|
| 102 |
+
[HttpPost]
|
| 103 |
+
[RequireRight(RightsCatalog.PhotosManage)]
|
| 104 |
+
public async Task<IActionResult> Delete(int id, int contactId)
|
| 105 |
+
{
|
| 106 |
+
(contactId, id) = await ResolveContactAndPhotoIdsAsync(contactId, id);
|
| 107 |
+
|
| 108 |
+
var photo = await _context.ContactPhotos.FirstOrDefaultAsync(p => p.Id == id && p.ContactId == contactId);
|
| 109 |
+
if (photo == null)
|
| 110 |
+
{
|
| 111 |
+
photo = await _context.ContactPhotos.FirstOrDefaultAsync(p => p.Id == id);
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
if (photo == null)
|
| 115 |
+
return Json(new { success = false, message = "Photo not found" });
|
| 116 |
+
|
| 117 |
+
_fileUploadService.DeleteFile(photo.PhotoPath);
|
| 118 |
+
_context.ContactPhotos.Remove(photo);
|
| 119 |
+
await _context.SaveChangesAsync();
|
| 120 |
+
|
| 121 |
+
return Json(new { success = true, message = "Photo deleted" });
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
private async Task<(int contactId, int photoId)> ResolveContactAndPhotoIdsAsync(int contactId, int photoId)
|
| 125 |
+
{
|
| 126 |
+
if (Request.HasFormContentType)
|
| 127 |
+
{
|
| 128 |
+
if (contactId <= 0 && int.TryParse(Request.Form["contactId"], out var formContactId))
|
| 129 |
+
contactId = formContactId;
|
| 130 |
+
|
| 131 |
+
if (photoId <= 0)
|
| 132 |
+
{
|
| 133 |
+
if (int.TryParse(Request.Form["photoId"], out var formPhotoId))
|
| 134 |
+
photoId = formPhotoId;
|
| 135 |
+
else if (int.TryParse(Request.Form["id"], out var formId))
|
| 136 |
+
photoId = formId;
|
| 137 |
+
}
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
if (contactId <= 0 && int.TryParse(Request.Query["contactId"], out var queryContactId))
|
| 141 |
+
contactId = queryContactId;
|
| 142 |
+
|
| 143 |
+
if (photoId <= 0)
|
| 144 |
+
{
|
| 145 |
+
if (int.TryParse(Request.Query["photoId"], out var queryPhotoId))
|
| 146 |
+
photoId = queryPhotoId;
|
| 147 |
+
else if (int.TryParse(Request.Query["id"], out var queryId))
|
| 148 |
+
photoId = queryId;
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
if ((contactId <= 0 || photoId <= 0) && Request.ContentType?.Contains("application/json", StringComparison.OrdinalIgnoreCase) == true)
|
| 152 |
+
{
|
| 153 |
+
Request.EnableBuffering();
|
| 154 |
+
Request.Body.Position = 0;
|
| 155 |
+
|
| 156 |
+
using var document = await JsonDocument.ParseAsync(Request.Body);
|
| 157 |
+
var root = document.RootElement;
|
| 158 |
+
|
| 159 |
+
if (contactId <= 0 && root.TryGetProperty("contactId", out var jsonContactId) && jsonContactId.TryGetInt32(out var parsedContactId))
|
| 160 |
+
contactId = parsedContactId;
|
| 161 |
+
|
| 162 |
+
if (photoId <= 0)
|
| 163 |
+
{
|
| 164 |
+
if (root.TryGetProperty("photoId", out var jsonPhotoId) && jsonPhotoId.TryGetInt32(out var parsedPhotoId))
|
| 165 |
+
photoId = parsedPhotoId;
|
| 166 |
+
else if (root.TryGetProperty("id", out var jsonId) && jsonId.TryGetInt32(out var parsedId))
|
| 167 |
+
photoId = parsedId;
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
Request.Body.Position = 0;
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
return (contactId, photoId);
|
| 174 |
+
}
|
| 175 |
+
}
|
| 176 |
+
}
|
ContactManagementAPI/Data/ApplicationDbContext.cs
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using Microsoft.EntityFrameworkCore;
|
| 2 |
+
using ContactManagementAPI.Models;
|
| 3 |
+
|
| 4 |
+
namespace ContactManagementAPI.Data
|
| 5 |
+
{
|
| 6 |
+
public class ApplicationDbContext : DbContext
|
| 7 |
+
{
|
| 8 |
+
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
|
| 9 |
+
: base(options)
|
| 10 |
+
{
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
public DbSet<Contact> Contacts { get; set; }
|
| 14 |
+
public DbSet<ContactGroup> ContactGroups { get; set; }
|
| 15 |
+
public DbSet<ContactPhoto> ContactPhotos { get; set; }
|
| 16 |
+
public DbSet<ContactDocument> ContactDocuments { get; set; }
|
| 17 |
+
public DbSet<ContactBankAccount> ContactBankAccounts { get; set; }
|
| 18 |
+
public DbSet<AppUser> AppUsers { get; set; }
|
| 19 |
+
public DbSet<UserGroup> UserGroups { get; set; }
|
| 20 |
+
public DbSet<GroupRight> GroupRights { get; set; }
|
| 21 |
+
public DbSet<UserRight> UserRights { get; set; }
|
| 22 |
+
|
| 23 |
+
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
| 24 |
+
{
|
| 25 |
+
base.OnModelCreating(modelBuilder);
|
| 26 |
+
|
| 27 |
+
// Contact - ContactGroup relationship
|
| 28 |
+
modelBuilder.Entity<Contact>()
|
| 29 |
+
.HasOne(c => c.Group)
|
| 30 |
+
.WithMany(g => g.Contacts)
|
| 31 |
+
.HasForeignKey(c => c.GroupId)
|
| 32 |
+
.OnDelete(DeleteBehavior.SetNull);
|
| 33 |
+
|
| 34 |
+
// Contact - ContactPhoto relationship
|
| 35 |
+
modelBuilder.Entity<ContactPhoto>()
|
| 36 |
+
.HasOne(cp => cp.Contact)
|
| 37 |
+
.WithMany(c => c.Photos)
|
| 38 |
+
.HasForeignKey(cp => cp.ContactId)
|
| 39 |
+
.OnDelete(DeleteBehavior.Cascade);
|
| 40 |
+
|
| 41 |
+
// Contact - ContactDocument relationship
|
| 42 |
+
modelBuilder.Entity<ContactDocument>()
|
| 43 |
+
.HasOne(cd => cd.Contact)
|
| 44 |
+
.WithMany(c => c.Documents)
|
| 45 |
+
.HasForeignKey(cd => cd.ContactId)
|
| 46 |
+
.OnDelete(DeleteBehavior.Cascade);
|
| 47 |
+
|
| 48 |
+
modelBuilder.Entity<ContactBankAccount>()
|
| 49 |
+
.HasOne(cb => cb.Contact)
|
| 50 |
+
.WithMany(c => c.BankAccounts)
|
| 51 |
+
.HasForeignKey(cb => cb.ContactId)
|
| 52 |
+
.OnDelete(DeleteBehavior.Cascade);
|
| 53 |
+
|
| 54 |
+
// AppUser - UserGroup relationship
|
| 55 |
+
modelBuilder.Entity<AppUser>()
|
| 56 |
+
.HasOne(u => u.Group)
|
| 57 |
+
.WithMany(g => g.Users)
|
| 58 |
+
.HasForeignKey(u => u.GroupId)
|
| 59 |
+
.OnDelete(DeleteBehavior.SetNull);
|
| 60 |
+
|
| 61 |
+
// GroupRight - UserGroup relationship
|
| 62 |
+
modelBuilder.Entity<GroupRight>()
|
| 63 |
+
.HasOne(gr => gr.UserGroup)
|
| 64 |
+
.WithMany(g => g.GroupRights)
|
| 65 |
+
.HasForeignKey(gr => gr.UserGroupId)
|
| 66 |
+
.OnDelete(DeleteBehavior.Cascade);
|
| 67 |
+
|
| 68 |
+
// UserRight - AppUser relationship
|
| 69 |
+
modelBuilder.Entity<UserRight>()
|
| 70 |
+
.HasOne(ur => ur.AppUser)
|
| 71 |
+
.WithMany(u => u.UserRights)
|
| 72 |
+
.HasForeignKey(ur => ur.AppUserId)
|
| 73 |
+
.OnDelete(DeleteBehavior.Cascade);
|
| 74 |
+
|
| 75 |
+
modelBuilder.Entity<AppUser>()
|
| 76 |
+
.HasIndex(u => u.UserName)
|
| 77 |
+
.IsUnique();
|
| 78 |
+
|
| 79 |
+
modelBuilder.Entity<UserGroup>()
|
| 80 |
+
.HasIndex(g => g.Name)
|
| 81 |
+
.IsUnique();
|
| 82 |
+
|
| 83 |
+
modelBuilder.Entity<GroupRight>()
|
| 84 |
+
.HasIndex(gr => new { gr.UserGroupId, gr.RightKey })
|
| 85 |
+
.IsUnique();
|
| 86 |
+
|
| 87 |
+
modelBuilder.Entity<UserRight>()
|
| 88 |
+
.HasIndex(ur => new { ur.AppUserId, ur.RightKey })
|
| 89 |
+
.IsUnique();
|
| 90 |
+
|
| 91 |
+
// Seed default contact groups
|
| 92 |
+
modelBuilder.Entity<ContactGroup>().HasData(
|
| 93 |
+
new ContactGroup { Id = 1, Name = "Family", Description = "Family members", CreatedAt = DateTime.Now },
|
| 94 |
+
new ContactGroup { Id = 2, Name = "Friends", Description = "Friends", CreatedAt = DateTime.Now },
|
| 95 |
+
new ContactGroup { Id = 3, Name = "Business", Description = "Business contacts", CreatedAt = DateTime.Now },
|
| 96 |
+
new ContactGroup { Id = 4, Name = "School", Description = "School contacts", CreatedAt = DateTime.Now },
|
| 97 |
+
new ContactGroup { Id = 5, Name = "Church", Description = "Church members", CreatedAt = DateTime.Now },
|
| 98 |
+
new ContactGroup { Id = 6, Name = "Others", Description = "Other contacts", CreatedAt = DateTime.Now },
|
| 99 |
+
new ContactGroup { Id = 7, Name = "College", Description = "College contacts", CreatedAt = DateTime.Now },
|
| 100 |
+
new ContactGroup { Id = 8, Name = "AA", Description = "Alcoholics Anonymous", CreatedAt = DateTime.Now }
|
| 101 |
+
);
|
| 102 |
+
}
|
| 103 |
+
}
|
| 104 |
+
}
|
ContactManagementAPI/Migrations/20260206165849_InitialCreate.Designer.cs
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// <auto-generated />
|
| 2 |
+
using System;
|
| 3 |
+
using ContactManagementAPI.Data;
|
| 4 |
+
using Microsoft.EntityFrameworkCore;
|
| 5 |
+
using Microsoft.EntityFrameworkCore.Infrastructure;
|
| 6 |
+
using Microsoft.EntityFrameworkCore.Metadata;
|
| 7 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 8 |
+
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
| 9 |
+
|
| 10 |
+
#nullable disable
|
| 11 |
+
|
| 12 |
+
namespace ContactManagementAPI.Migrations
|
| 13 |
+
{
|
| 14 |
+
[DbContext(typeof(ApplicationDbContext))]
|
| 15 |
+
[Migration("20260206165849_InitialCreate")]
|
| 16 |
+
partial class InitialCreate
|
| 17 |
+
{
|
| 18 |
+
/// <inheritdoc />
|
| 19 |
+
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
| 20 |
+
{
|
| 21 |
+
#pragma warning disable 612, 618
|
| 22 |
+
modelBuilder
|
| 23 |
+
.HasAnnotation("ProductVersion", "8.0.0")
|
| 24 |
+
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
| 25 |
+
|
| 26 |
+
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
| 27 |
+
|
| 28 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 29 |
+
{
|
| 30 |
+
b.Property<int>("Id")
|
| 31 |
+
.ValueGeneratedOnAdd()
|
| 32 |
+
.HasColumnType("int");
|
| 33 |
+
|
| 34 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 35 |
+
|
| 36 |
+
b.Property<string>("Address")
|
| 37 |
+
.IsRequired()
|
| 38 |
+
.HasColumnType("nvarchar(max)");
|
| 39 |
+
|
| 40 |
+
b.Property<string>("City")
|
| 41 |
+
.IsRequired()
|
| 42 |
+
.HasColumnType("nvarchar(max)");
|
| 43 |
+
|
| 44 |
+
b.Property<string>("Country")
|
| 45 |
+
.IsRequired()
|
| 46 |
+
.HasColumnType("nvarchar(max)");
|
| 47 |
+
|
| 48 |
+
b.Property<DateTime>("CreatedAt")
|
| 49 |
+
.HasColumnType("datetime2");
|
| 50 |
+
|
| 51 |
+
b.Property<string>("Email")
|
| 52 |
+
.IsRequired()
|
| 53 |
+
.HasColumnType("nvarchar(max)");
|
| 54 |
+
|
| 55 |
+
b.Property<string>("FirstName")
|
| 56 |
+
.IsRequired()
|
| 57 |
+
.HasColumnType("nvarchar(max)");
|
| 58 |
+
|
| 59 |
+
b.Property<int?>("GroupId")
|
| 60 |
+
.HasColumnType("int");
|
| 61 |
+
|
| 62 |
+
b.Property<string>("LastName")
|
| 63 |
+
.IsRequired()
|
| 64 |
+
.HasColumnType("nvarchar(max)");
|
| 65 |
+
|
| 66 |
+
b.Property<string>("Mobile1")
|
| 67 |
+
.IsRequired()
|
| 68 |
+
.HasColumnType("nvarchar(max)");
|
| 69 |
+
|
| 70 |
+
b.Property<string>("Mobile2")
|
| 71 |
+
.IsRequired()
|
| 72 |
+
.HasColumnType("nvarchar(max)");
|
| 73 |
+
|
| 74 |
+
b.Property<string>("Mobile3")
|
| 75 |
+
.IsRequired()
|
| 76 |
+
.HasColumnType("nvarchar(max)");
|
| 77 |
+
|
| 78 |
+
b.Property<string>("NickName")
|
| 79 |
+
.IsRequired()
|
| 80 |
+
.HasColumnType("nvarchar(max)");
|
| 81 |
+
|
| 82 |
+
b.Property<string>("OtherDetails")
|
| 83 |
+
.IsRequired()
|
| 84 |
+
.HasColumnType("nvarchar(max)");
|
| 85 |
+
|
| 86 |
+
b.Property<string>("PhotoPath")
|
| 87 |
+
.IsRequired()
|
| 88 |
+
.HasColumnType("nvarchar(max)");
|
| 89 |
+
|
| 90 |
+
b.Property<string>("PostalCode")
|
| 91 |
+
.IsRequired()
|
| 92 |
+
.HasColumnType("nvarchar(max)");
|
| 93 |
+
|
| 94 |
+
b.Property<string>("State")
|
| 95 |
+
.IsRequired()
|
| 96 |
+
.HasColumnType("nvarchar(max)");
|
| 97 |
+
|
| 98 |
+
b.Property<DateTime>("UpdatedAt")
|
| 99 |
+
.HasColumnType("datetime2");
|
| 100 |
+
|
| 101 |
+
b.Property<string>("WhatsAppNumber")
|
| 102 |
+
.IsRequired()
|
| 103 |
+
.HasColumnType("nvarchar(max)");
|
| 104 |
+
|
| 105 |
+
b.HasKey("Id");
|
| 106 |
+
|
| 107 |
+
b.HasIndex("GroupId");
|
| 108 |
+
|
| 109 |
+
b.ToTable("Contacts");
|
| 110 |
+
});
|
| 111 |
+
|
| 112 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 113 |
+
{
|
| 114 |
+
b.Property<int>("Id")
|
| 115 |
+
.ValueGeneratedOnAdd()
|
| 116 |
+
.HasColumnType("int");
|
| 117 |
+
|
| 118 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 119 |
+
|
| 120 |
+
b.Property<int>("ContactId")
|
| 121 |
+
.HasColumnType("int");
|
| 122 |
+
|
| 123 |
+
b.Property<string>("ContentType")
|
| 124 |
+
.IsRequired()
|
| 125 |
+
.HasColumnType("nvarchar(max)");
|
| 126 |
+
|
| 127 |
+
b.Property<string>("DocumentPath")
|
| 128 |
+
.IsRequired()
|
| 129 |
+
.HasColumnType("nvarchar(max)");
|
| 130 |
+
|
| 131 |
+
b.Property<string>("DocumentType")
|
| 132 |
+
.IsRequired()
|
| 133 |
+
.HasColumnType("nvarchar(max)");
|
| 134 |
+
|
| 135 |
+
b.Property<string>("FileName")
|
| 136 |
+
.IsRequired()
|
| 137 |
+
.HasColumnType("nvarchar(max)");
|
| 138 |
+
|
| 139 |
+
b.Property<long>("FileSize")
|
| 140 |
+
.HasColumnType("bigint");
|
| 141 |
+
|
| 142 |
+
b.Property<DateTime>("UploadedAt")
|
| 143 |
+
.HasColumnType("datetime2");
|
| 144 |
+
|
| 145 |
+
b.HasKey("Id");
|
| 146 |
+
|
| 147 |
+
b.HasIndex("ContactId");
|
| 148 |
+
|
| 149 |
+
b.ToTable("ContactDocuments");
|
| 150 |
+
});
|
| 151 |
+
|
| 152 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 153 |
+
{
|
| 154 |
+
b.Property<int>("Id")
|
| 155 |
+
.ValueGeneratedOnAdd()
|
| 156 |
+
.HasColumnType("int");
|
| 157 |
+
|
| 158 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 159 |
+
|
| 160 |
+
b.Property<DateTime>("CreatedAt")
|
| 161 |
+
.HasColumnType("datetime2");
|
| 162 |
+
|
| 163 |
+
b.Property<string>("Description")
|
| 164 |
+
.IsRequired()
|
| 165 |
+
.HasColumnType("nvarchar(max)");
|
| 166 |
+
|
| 167 |
+
b.Property<string>("Name")
|
| 168 |
+
.IsRequired()
|
| 169 |
+
.HasColumnType("nvarchar(max)");
|
| 170 |
+
|
| 171 |
+
b.HasKey("Id");
|
| 172 |
+
|
| 173 |
+
b.ToTable("ContactGroups");
|
| 174 |
+
|
| 175 |
+
b.HasData(
|
| 176 |
+
new
|
| 177 |
+
{
|
| 178 |
+
Id = 1,
|
| 179 |
+
CreatedAt = new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2243),
|
| 180 |
+
Description = "Family members",
|
| 181 |
+
Name = "Family"
|
| 182 |
+
},
|
| 183 |
+
new
|
| 184 |
+
{
|
| 185 |
+
Id = 2,
|
| 186 |
+
CreatedAt = new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2260),
|
| 187 |
+
Description = "Friends",
|
| 188 |
+
Name = "Friends"
|
| 189 |
+
},
|
| 190 |
+
new
|
| 191 |
+
{
|
| 192 |
+
Id = 3,
|
| 193 |
+
CreatedAt = new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2263),
|
| 194 |
+
Description = "Business contacts",
|
| 195 |
+
Name = "Business"
|
| 196 |
+
},
|
| 197 |
+
new
|
| 198 |
+
{
|
| 199 |
+
Id = 4,
|
| 200 |
+
CreatedAt = new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2266),
|
| 201 |
+
Description = "School contacts",
|
| 202 |
+
Name = "School"
|
| 203 |
+
},
|
| 204 |
+
new
|
| 205 |
+
{
|
| 206 |
+
Id = 5,
|
| 207 |
+
CreatedAt = new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2270),
|
| 208 |
+
Description = "Church members",
|
| 209 |
+
Name = "Church"
|
| 210 |
+
},
|
| 211 |
+
new
|
| 212 |
+
{
|
| 213 |
+
Id = 6,
|
| 214 |
+
CreatedAt = new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2273),
|
| 215 |
+
Description = "Other contacts",
|
| 216 |
+
Name = "Others"
|
| 217 |
+
});
|
| 218 |
+
});
|
| 219 |
+
|
| 220 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 221 |
+
{
|
| 222 |
+
b.Property<int>("Id")
|
| 223 |
+
.ValueGeneratedOnAdd()
|
| 224 |
+
.HasColumnType("int");
|
| 225 |
+
|
| 226 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 227 |
+
|
| 228 |
+
b.Property<int>("ContactId")
|
| 229 |
+
.HasColumnType("int");
|
| 230 |
+
|
| 231 |
+
b.Property<string>("ContentType")
|
| 232 |
+
.IsRequired()
|
| 233 |
+
.HasColumnType("nvarchar(max)");
|
| 234 |
+
|
| 235 |
+
b.Property<string>("FileName")
|
| 236 |
+
.IsRequired()
|
| 237 |
+
.HasColumnType("nvarchar(max)");
|
| 238 |
+
|
| 239 |
+
b.Property<long>("FileSize")
|
| 240 |
+
.HasColumnType("bigint");
|
| 241 |
+
|
| 242 |
+
b.Property<bool>("IsProfilePhoto")
|
| 243 |
+
.HasColumnType("bit");
|
| 244 |
+
|
| 245 |
+
b.Property<string>("PhotoPath")
|
| 246 |
+
.IsRequired()
|
| 247 |
+
.HasColumnType("nvarchar(max)");
|
| 248 |
+
|
| 249 |
+
b.Property<DateTime>("UploadedAt")
|
| 250 |
+
.HasColumnType("datetime2");
|
| 251 |
+
|
| 252 |
+
b.HasKey("Id");
|
| 253 |
+
|
| 254 |
+
b.HasIndex("ContactId");
|
| 255 |
+
|
| 256 |
+
b.ToTable("ContactPhotos");
|
| 257 |
+
});
|
| 258 |
+
|
| 259 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 260 |
+
{
|
| 261 |
+
b.HasOne("ContactManagementAPI.Models.ContactGroup", "Group")
|
| 262 |
+
.WithMany("Contacts")
|
| 263 |
+
.HasForeignKey("GroupId")
|
| 264 |
+
.OnDelete(DeleteBehavior.SetNull);
|
| 265 |
+
|
| 266 |
+
b.Navigation("Group");
|
| 267 |
+
});
|
| 268 |
+
|
| 269 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 270 |
+
{
|
| 271 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 272 |
+
.WithMany("Documents")
|
| 273 |
+
.HasForeignKey("ContactId")
|
| 274 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 275 |
+
.IsRequired();
|
| 276 |
+
|
| 277 |
+
b.Navigation("Contact");
|
| 278 |
+
});
|
| 279 |
+
|
| 280 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 281 |
+
{
|
| 282 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 283 |
+
.WithMany("Photos")
|
| 284 |
+
.HasForeignKey("ContactId")
|
| 285 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 286 |
+
.IsRequired();
|
| 287 |
+
|
| 288 |
+
b.Navigation("Contact");
|
| 289 |
+
});
|
| 290 |
+
|
| 291 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 292 |
+
{
|
| 293 |
+
b.Navigation("Documents");
|
| 294 |
+
|
| 295 |
+
b.Navigation("Photos");
|
| 296 |
+
});
|
| 297 |
+
|
| 298 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 299 |
+
{
|
| 300 |
+
b.Navigation("Contacts");
|
| 301 |
+
});
|
| 302 |
+
#pragma warning restore 612, 618
|
| 303 |
+
}
|
| 304 |
+
}
|
| 305 |
+
}
|
ContactManagementAPI/Migrations/20260206165849_InitialCreate.cs
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 3 |
+
|
| 4 |
+
#nullable disable
|
| 5 |
+
|
| 6 |
+
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
| 7 |
+
|
| 8 |
+
namespace ContactManagementAPI.Migrations
|
| 9 |
+
{
|
| 10 |
+
/// <inheritdoc />
|
| 11 |
+
public partial class InitialCreate : Migration
|
| 12 |
+
{
|
| 13 |
+
/// <inheritdoc />
|
| 14 |
+
protected override void Up(MigrationBuilder migrationBuilder)
|
| 15 |
+
{
|
| 16 |
+
migrationBuilder.CreateTable(
|
| 17 |
+
name: "ContactGroups",
|
| 18 |
+
columns: table => new
|
| 19 |
+
{
|
| 20 |
+
Id = table.Column<int>(type: "int", nullable: false)
|
| 21 |
+
.Annotation("SqlServer:Identity", "1, 1"),
|
| 22 |
+
Name = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 23 |
+
Description = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 24 |
+
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false)
|
| 25 |
+
},
|
| 26 |
+
constraints: table =>
|
| 27 |
+
{
|
| 28 |
+
table.PrimaryKey("PK_ContactGroups", x => x.Id);
|
| 29 |
+
});
|
| 30 |
+
|
| 31 |
+
migrationBuilder.CreateTable(
|
| 32 |
+
name: "Contacts",
|
| 33 |
+
columns: table => new
|
| 34 |
+
{
|
| 35 |
+
Id = table.Column<int>(type: "int", nullable: false)
|
| 36 |
+
.Annotation("SqlServer:Identity", "1, 1"),
|
| 37 |
+
FirstName = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 38 |
+
LastName = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 39 |
+
NickName = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 40 |
+
Email = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 41 |
+
Mobile1 = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 42 |
+
Mobile2 = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 43 |
+
Mobile3 = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 44 |
+
WhatsAppNumber = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 45 |
+
Address = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 46 |
+
City = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 47 |
+
State = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 48 |
+
PostalCode = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 49 |
+
Country = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 50 |
+
PhotoPath = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 51 |
+
GroupId = table.Column<int>(type: "int", nullable: true),
|
| 52 |
+
OtherDetails = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 53 |
+
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
| 54 |
+
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: false)
|
| 55 |
+
},
|
| 56 |
+
constraints: table =>
|
| 57 |
+
{
|
| 58 |
+
table.PrimaryKey("PK_Contacts", x => x.Id);
|
| 59 |
+
table.ForeignKey(
|
| 60 |
+
name: "FK_Contacts_ContactGroups_GroupId",
|
| 61 |
+
column: x => x.GroupId,
|
| 62 |
+
principalTable: "ContactGroups",
|
| 63 |
+
principalColumn: "Id",
|
| 64 |
+
onDelete: ReferentialAction.SetNull);
|
| 65 |
+
});
|
| 66 |
+
|
| 67 |
+
migrationBuilder.CreateTable(
|
| 68 |
+
name: "ContactDocuments",
|
| 69 |
+
columns: table => new
|
| 70 |
+
{
|
| 71 |
+
Id = table.Column<int>(type: "int", nullable: false)
|
| 72 |
+
.Annotation("SqlServer:Identity", "1, 1"),
|
| 73 |
+
ContactId = table.Column<int>(type: "int", nullable: false),
|
| 74 |
+
DocumentPath = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 75 |
+
FileName = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 76 |
+
FileSize = table.Column<long>(type: "bigint", nullable: false),
|
| 77 |
+
ContentType = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 78 |
+
DocumentType = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 79 |
+
UploadedAt = table.Column<DateTime>(type: "datetime2", nullable: false)
|
| 80 |
+
},
|
| 81 |
+
constraints: table =>
|
| 82 |
+
{
|
| 83 |
+
table.PrimaryKey("PK_ContactDocuments", x => x.Id);
|
| 84 |
+
table.ForeignKey(
|
| 85 |
+
name: "FK_ContactDocuments_Contacts_ContactId",
|
| 86 |
+
column: x => x.ContactId,
|
| 87 |
+
principalTable: "Contacts",
|
| 88 |
+
principalColumn: "Id",
|
| 89 |
+
onDelete: ReferentialAction.Cascade);
|
| 90 |
+
});
|
| 91 |
+
|
| 92 |
+
migrationBuilder.CreateTable(
|
| 93 |
+
name: "ContactPhotos",
|
| 94 |
+
columns: table => new
|
| 95 |
+
{
|
| 96 |
+
Id = table.Column<int>(type: "int", nullable: false)
|
| 97 |
+
.Annotation("SqlServer:Identity", "1, 1"),
|
| 98 |
+
ContactId = table.Column<int>(type: "int", nullable: false),
|
| 99 |
+
PhotoPath = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 100 |
+
FileName = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 101 |
+
FileSize = table.Column<long>(type: "bigint", nullable: false),
|
| 102 |
+
ContentType = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 103 |
+
IsProfilePhoto = table.Column<bool>(type: "bit", nullable: false),
|
| 104 |
+
UploadedAt = table.Column<DateTime>(type: "datetime2", nullable: false)
|
| 105 |
+
},
|
| 106 |
+
constraints: table =>
|
| 107 |
+
{
|
| 108 |
+
table.PrimaryKey("PK_ContactPhotos", x => x.Id);
|
| 109 |
+
table.ForeignKey(
|
| 110 |
+
name: "FK_ContactPhotos_Contacts_ContactId",
|
| 111 |
+
column: x => x.ContactId,
|
| 112 |
+
principalTable: "Contacts",
|
| 113 |
+
principalColumn: "Id",
|
| 114 |
+
onDelete: ReferentialAction.Cascade);
|
| 115 |
+
});
|
| 116 |
+
|
| 117 |
+
migrationBuilder.InsertData(
|
| 118 |
+
table: "ContactGroups",
|
| 119 |
+
columns: new[] { "Id", "CreatedAt", "Description", "Name" },
|
| 120 |
+
values: new object[,]
|
| 121 |
+
{
|
| 122 |
+
{ 1, new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2243), "Family members", "Family" },
|
| 123 |
+
{ 2, new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2260), "Friends", "Friends" },
|
| 124 |
+
{ 3, new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2263), "Business contacts", "Business" },
|
| 125 |
+
{ 4, new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2266), "School contacts", "School" },
|
| 126 |
+
{ 5, new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2270), "Church members", "Church" },
|
| 127 |
+
{ 6, new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2273), "Other contacts", "Others" }
|
| 128 |
+
});
|
| 129 |
+
|
| 130 |
+
migrationBuilder.CreateIndex(
|
| 131 |
+
name: "IX_ContactDocuments_ContactId",
|
| 132 |
+
table: "ContactDocuments",
|
| 133 |
+
column: "ContactId");
|
| 134 |
+
|
| 135 |
+
migrationBuilder.CreateIndex(
|
| 136 |
+
name: "IX_ContactPhotos_ContactId",
|
| 137 |
+
table: "ContactPhotos",
|
| 138 |
+
column: "ContactId");
|
| 139 |
+
|
| 140 |
+
migrationBuilder.CreateIndex(
|
| 141 |
+
name: "IX_Contacts_GroupId",
|
| 142 |
+
table: "Contacts",
|
| 143 |
+
column: "GroupId");
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
/// <inheritdoc />
|
| 147 |
+
protected override void Down(MigrationBuilder migrationBuilder)
|
| 148 |
+
{
|
| 149 |
+
migrationBuilder.DropTable(
|
| 150 |
+
name: "ContactDocuments");
|
| 151 |
+
|
| 152 |
+
migrationBuilder.DropTable(
|
| 153 |
+
name: "ContactPhotos");
|
| 154 |
+
|
| 155 |
+
migrationBuilder.DropTable(
|
| 156 |
+
name: "Contacts");
|
| 157 |
+
|
| 158 |
+
migrationBuilder.DropTable(
|
| 159 |
+
name: "ContactGroups");
|
| 160 |
+
}
|
| 161 |
+
}
|
| 162 |
+
}
|
ContactManagementAPI/Migrations/20260208162549_MakeContactFieldsNullable.Designer.cs
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// <auto-generated />
|
| 2 |
+
using System;
|
| 3 |
+
using ContactManagementAPI.Data;
|
| 4 |
+
using Microsoft.EntityFrameworkCore;
|
| 5 |
+
using Microsoft.EntityFrameworkCore.Infrastructure;
|
| 6 |
+
using Microsoft.EntityFrameworkCore.Metadata;
|
| 7 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 8 |
+
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
| 9 |
+
|
| 10 |
+
#nullable disable
|
| 11 |
+
|
| 12 |
+
namespace ContactManagementAPI.Migrations
|
| 13 |
+
{
|
| 14 |
+
[DbContext(typeof(ApplicationDbContext))]
|
| 15 |
+
[Migration("20260208162549_MakeContactFieldsNullable")]
|
| 16 |
+
partial class MakeContactFieldsNullable
|
| 17 |
+
{
|
| 18 |
+
/// <inheritdoc />
|
| 19 |
+
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
| 20 |
+
{
|
| 21 |
+
#pragma warning disable 612, 618
|
| 22 |
+
modelBuilder
|
| 23 |
+
.HasAnnotation("ProductVersion", "8.0.0")
|
| 24 |
+
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
| 25 |
+
|
| 26 |
+
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
| 27 |
+
|
| 28 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 29 |
+
{
|
| 30 |
+
b.Property<int>("Id")
|
| 31 |
+
.ValueGeneratedOnAdd()
|
| 32 |
+
.HasColumnType("int");
|
| 33 |
+
|
| 34 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 35 |
+
|
| 36 |
+
b.Property<string>("Address")
|
| 37 |
+
.HasColumnType("nvarchar(max)");
|
| 38 |
+
|
| 39 |
+
b.Property<string>("City")
|
| 40 |
+
.HasColumnType("nvarchar(max)");
|
| 41 |
+
|
| 42 |
+
b.Property<string>("Country")
|
| 43 |
+
.HasColumnType("nvarchar(max)");
|
| 44 |
+
|
| 45 |
+
b.Property<DateTime>("CreatedAt")
|
| 46 |
+
.HasColumnType("datetime2");
|
| 47 |
+
|
| 48 |
+
b.Property<string>("Email")
|
| 49 |
+
.HasColumnType("nvarchar(max)");
|
| 50 |
+
|
| 51 |
+
b.Property<string>("FirstName")
|
| 52 |
+
.IsRequired()
|
| 53 |
+
.HasColumnType("nvarchar(max)");
|
| 54 |
+
|
| 55 |
+
b.Property<int?>("GroupId")
|
| 56 |
+
.HasColumnType("int");
|
| 57 |
+
|
| 58 |
+
b.Property<string>("LastName")
|
| 59 |
+
.HasColumnType("nvarchar(max)");
|
| 60 |
+
|
| 61 |
+
b.Property<string>("Mobile1")
|
| 62 |
+
.HasColumnType("nvarchar(max)");
|
| 63 |
+
|
| 64 |
+
b.Property<string>("Mobile2")
|
| 65 |
+
.HasColumnType("nvarchar(max)");
|
| 66 |
+
|
| 67 |
+
b.Property<string>("Mobile3")
|
| 68 |
+
.HasColumnType("nvarchar(max)");
|
| 69 |
+
|
| 70 |
+
b.Property<string>("NickName")
|
| 71 |
+
.HasColumnType("nvarchar(max)");
|
| 72 |
+
|
| 73 |
+
b.Property<string>("OtherDetails")
|
| 74 |
+
.HasColumnType("nvarchar(max)");
|
| 75 |
+
|
| 76 |
+
b.Property<string>("PhotoPath")
|
| 77 |
+
.HasColumnType("nvarchar(max)");
|
| 78 |
+
|
| 79 |
+
b.Property<string>("PostalCode")
|
| 80 |
+
.HasColumnType("nvarchar(max)");
|
| 81 |
+
|
| 82 |
+
b.Property<string>("State")
|
| 83 |
+
.HasColumnType("nvarchar(max)");
|
| 84 |
+
|
| 85 |
+
b.Property<DateTime>("UpdatedAt")
|
| 86 |
+
.HasColumnType("datetime2");
|
| 87 |
+
|
| 88 |
+
b.Property<string>("WhatsAppNumber")
|
| 89 |
+
.HasColumnType("nvarchar(max)");
|
| 90 |
+
|
| 91 |
+
b.HasKey("Id");
|
| 92 |
+
|
| 93 |
+
b.HasIndex("GroupId");
|
| 94 |
+
|
| 95 |
+
b.ToTable("Contacts");
|
| 96 |
+
});
|
| 97 |
+
|
| 98 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 99 |
+
{
|
| 100 |
+
b.Property<int>("Id")
|
| 101 |
+
.ValueGeneratedOnAdd()
|
| 102 |
+
.HasColumnType("int");
|
| 103 |
+
|
| 104 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 105 |
+
|
| 106 |
+
b.Property<int>("ContactId")
|
| 107 |
+
.HasColumnType("int");
|
| 108 |
+
|
| 109 |
+
b.Property<string>("ContentType")
|
| 110 |
+
.IsRequired()
|
| 111 |
+
.HasColumnType("nvarchar(max)");
|
| 112 |
+
|
| 113 |
+
b.Property<string>("DocumentPath")
|
| 114 |
+
.IsRequired()
|
| 115 |
+
.HasColumnType("nvarchar(max)");
|
| 116 |
+
|
| 117 |
+
b.Property<string>("DocumentType")
|
| 118 |
+
.IsRequired()
|
| 119 |
+
.HasColumnType("nvarchar(max)");
|
| 120 |
+
|
| 121 |
+
b.Property<string>("FileName")
|
| 122 |
+
.IsRequired()
|
| 123 |
+
.HasColumnType("nvarchar(max)");
|
| 124 |
+
|
| 125 |
+
b.Property<long>("FileSize")
|
| 126 |
+
.HasColumnType("bigint");
|
| 127 |
+
|
| 128 |
+
b.Property<DateTime>("UploadedAt")
|
| 129 |
+
.HasColumnType("datetime2");
|
| 130 |
+
|
| 131 |
+
b.HasKey("Id");
|
| 132 |
+
|
| 133 |
+
b.HasIndex("ContactId");
|
| 134 |
+
|
| 135 |
+
b.ToTable("ContactDocuments");
|
| 136 |
+
});
|
| 137 |
+
|
| 138 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 139 |
+
{
|
| 140 |
+
b.Property<int>("Id")
|
| 141 |
+
.ValueGeneratedOnAdd()
|
| 142 |
+
.HasColumnType("int");
|
| 143 |
+
|
| 144 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 145 |
+
|
| 146 |
+
b.Property<DateTime>("CreatedAt")
|
| 147 |
+
.HasColumnType("datetime2");
|
| 148 |
+
|
| 149 |
+
b.Property<string>("Description")
|
| 150 |
+
.IsRequired()
|
| 151 |
+
.HasColumnType("nvarchar(max)");
|
| 152 |
+
|
| 153 |
+
b.Property<string>("Name")
|
| 154 |
+
.IsRequired()
|
| 155 |
+
.HasColumnType("nvarchar(max)");
|
| 156 |
+
|
| 157 |
+
b.HasKey("Id");
|
| 158 |
+
|
| 159 |
+
b.ToTable("ContactGroups");
|
| 160 |
+
|
| 161 |
+
b.HasData(
|
| 162 |
+
new
|
| 163 |
+
{
|
| 164 |
+
Id = 1,
|
| 165 |
+
CreatedAt = new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5320),
|
| 166 |
+
Description = "Family members",
|
| 167 |
+
Name = "Family"
|
| 168 |
+
},
|
| 169 |
+
new
|
| 170 |
+
{
|
| 171 |
+
Id = 2,
|
| 172 |
+
CreatedAt = new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5332),
|
| 173 |
+
Description = "Friends",
|
| 174 |
+
Name = "Friends"
|
| 175 |
+
},
|
| 176 |
+
new
|
| 177 |
+
{
|
| 178 |
+
Id = 3,
|
| 179 |
+
CreatedAt = new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5333),
|
| 180 |
+
Description = "Business contacts",
|
| 181 |
+
Name = "Business"
|
| 182 |
+
},
|
| 183 |
+
new
|
| 184 |
+
{
|
| 185 |
+
Id = 4,
|
| 186 |
+
CreatedAt = new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5335),
|
| 187 |
+
Description = "School contacts",
|
| 188 |
+
Name = "School"
|
| 189 |
+
},
|
| 190 |
+
new
|
| 191 |
+
{
|
| 192 |
+
Id = 5,
|
| 193 |
+
CreatedAt = new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5339),
|
| 194 |
+
Description = "Church members",
|
| 195 |
+
Name = "Church"
|
| 196 |
+
},
|
| 197 |
+
new
|
| 198 |
+
{
|
| 199 |
+
Id = 6,
|
| 200 |
+
CreatedAt = new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5340),
|
| 201 |
+
Description = "Other contacts",
|
| 202 |
+
Name = "Others"
|
| 203 |
+
});
|
| 204 |
+
});
|
| 205 |
+
|
| 206 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 207 |
+
{
|
| 208 |
+
b.Property<int>("Id")
|
| 209 |
+
.ValueGeneratedOnAdd()
|
| 210 |
+
.HasColumnType("int");
|
| 211 |
+
|
| 212 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 213 |
+
|
| 214 |
+
b.Property<int>("ContactId")
|
| 215 |
+
.HasColumnType("int");
|
| 216 |
+
|
| 217 |
+
b.Property<string>("ContentType")
|
| 218 |
+
.IsRequired()
|
| 219 |
+
.HasColumnType("nvarchar(max)");
|
| 220 |
+
|
| 221 |
+
b.Property<string>("FileName")
|
| 222 |
+
.IsRequired()
|
| 223 |
+
.HasColumnType("nvarchar(max)");
|
| 224 |
+
|
| 225 |
+
b.Property<long>("FileSize")
|
| 226 |
+
.HasColumnType("bigint");
|
| 227 |
+
|
| 228 |
+
b.Property<bool>("IsProfilePhoto")
|
| 229 |
+
.HasColumnType("bit");
|
| 230 |
+
|
| 231 |
+
b.Property<string>("PhotoPath")
|
| 232 |
+
.IsRequired()
|
| 233 |
+
.HasColumnType("nvarchar(max)");
|
| 234 |
+
|
| 235 |
+
b.Property<DateTime>("UploadedAt")
|
| 236 |
+
.HasColumnType("datetime2");
|
| 237 |
+
|
| 238 |
+
b.HasKey("Id");
|
| 239 |
+
|
| 240 |
+
b.HasIndex("ContactId");
|
| 241 |
+
|
| 242 |
+
b.ToTable("ContactPhotos");
|
| 243 |
+
});
|
| 244 |
+
|
| 245 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 246 |
+
{
|
| 247 |
+
b.HasOne("ContactManagementAPI.Models.ContactGroup", "Group")
|
| 248 |
+
.WithMany("Contacts")
|
| 249 |
+
.HasForeignKey("GroupId")
|
| 250 |
+
.OnDelete(DeleteBehavior.SetNull);
|
| 251 |
+
|
| 252 |
+
b.Navigation("Group");
|
| 253 |
+
});
|
| 254 |
+
|
| 255 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 256 |
+
{
|
| 257 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 258 |
+
.WithMany("Documents")
|
| 259 |
+
.HasForeignKey("ContactId")
|
| 260 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 261 |
+
.IsRequired();
|
| 262 |
+
|
| 263 |
+
b.Navigation("Contact");
|
| 264 |
+
});
|
| 265 |
+
|
| 266 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 267 |
+
{
|
| 268 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 269 |
+
.WithMany("Photos")
|
| 270 |
+
.HasForeignKey("ContactId")
|
| 271 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 272 |
+
.IsRequired();
|
| 273 |
+
|
| 274 |
+
b.Navigation("Contact");
|
| 275 |
+
});
|
| 276 |
+
|
| 277 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 278 |
+
{
|
| 279 |
+
b.Navigation("Documents");
|
| 280 |
+
|
| 281 |
+
b.Navigation("Photos");
|
| 282 |
+
});
|
| 283 |
+
|
| 284 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 285 |
+
{
|
| 286 |
+
b.Navigation("Contacts");
|
| 287 |
+
});
|
| 288 |
+
#pragma warning restore 612, 618
|
| 289 |
+
}
|
| 290 |
+
}
|
| 291 |
+
}
|
ContactManagementAPI/Migrations/20260208162549_MakeContactFieldsNullable.cs
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 3 |
+
|
| 4 |
+
#nullable disable
|
| 5 |
+
|
| 6 |
+
namespace ContactManagementAPI.Migrations
|
| 7 |
+
{
|
| 8 |
+
/// <inheritdoc />
|
| 9 |
+
public partial class MakeContactFieldsNullable : Migration
|
| 10 |
+
{
|
| 11 |
+
/// <inheritdoc />
|
| 12 |
+
protected override void Up(MigrationBuilder migrationBuilder)
|
| 13 |
+
{
|
| 14 |
+
migrationBuilder.AlterColumn<string>(
|
| 15 |
+
name: "WhatsAppNumber",
|
| 16 |
+
table: "Contacts",
|
| 17 |
+
type: "nvarchar(max)",
|
| 18 |
+
nullable: true,
|
| 19 |
+
oldClrType: typeof(string),
|
| 20 |
+
oldType: "nvarchar(max)");
|
| 21 |
+
|
| 22 |
+
migrationBuilder.AlterColumn<string>(
|
| 23 |
+
name: "State",
|
| 24 |
+
table: "Contacts",
|
| 25 |
+
type: "nvarchar(max)",
|
| 26 |
+
nullable: true,
|
| 27 |
+
oldClrType: typeof(string),
|
| 28 |
+
oldType: "nvarchar(max)");
|
| 29 |
+
|
| 30 |
+
migrationBuilder.AlterColumn<string>(
|
| 31 |
+
name: "PostalCode",
|
| 32 |
+
table: "Contacts",
|
| 33 |
+
type: "nvarchar(max)",
|
| 34 |
+
nullable: true,
|
| 35 |
+
oldClrType: typeof(string),
|
| 36 |
+
oldType: "nvarchar(max)");
|
| 37 |
+
|
| 38 |
+
migrationBuilder.AlterColumn<string>(
|
| 39 |
+
name: "PhotoPath",
|
| 40 |
+
table: "Contacts",
|
| 41 |
+
type: "nvarchar(max)",
|
| 42 |
+
nullable: true,
|
| 43 |
+
oldClrType: typeof(string),
|
| 44 |
+
oldType: "nvarchar(max)");
|
| 45 |
+
|
| 46 |
+
migrationBuilder.AlterColumn<string>(
|
| 47 |
+
name: "OtherDetails",
|
| 48 |
+
table: "Contacts",
|
| 49 |
+
type: "nvarchar(max)",
|
| 50 |
+
nullable: true,
|
| 51 |
+
oldClrType: typeof(string),
|
| 52 |
+
oldType: "nvarchar(max)");
|
| 53 |
+
|
| 54 |
+
migrationBuilder.AlterColumn<string>(
|
| 55 |
+
name: "NickName",
|
| 56 |
+
table: "Contacts",
|
| 57 |
+
type: "nvarchar(max)",
|
| 58 |
+
nullable: true,
|
| 59 |
+
oldClrType: typeof(string),
|
| 60 |
+
oldType: "nvarchar(max)");
|
| 61 |
+
|
| 62 |
+
migrationBuilder.AlterColumn<string>(
|
| 63 |
+
name: "Mobile3",
|
| 64 |
+
table: "Contacts",
|
| 65 |
+
type: "nvarchar(max)",
|
| 66 |
+
nullable: true,
|
| 67 |
+
oldClrType: typeof(string),
|
| 68 |
+
oldType: "nvarchar(max)");
|
| 69 |
+
|
| 70 |
+
migrationBuilder.AlterColumn<string>(
|
| 71 |
+
name: "Mobile2",
|
| 72 |
+
table: "Contacts",
|
| 73 |
+
type: "nvarchar(max)",
|
| 74 |
+
nullable: true,
|
| 75 |
+
oldClrType: typeof(string),
|
| 76 |
+
oldType: "nvarchar(max)");
|
| 77 |
+
|
| 78 |
+
migrationBuilder.AlterColumn<string>(
|
| 79 |
+
name: "Mobile1",
|
| 80 |
+
table: "Contacts",
|
| 81 |
+
type: "nvarchar(max)",
|
| 82 |
+
nullable: true,
|
| 83 |
+
oldClrType: typeof(string),
|
| 84 |
+
oldType: "nvarchar(max)");
|
| 85 |
+
|
| 86 |
+
migrationBuilder.AlterColumn<string>(
|
| 87 |
+
name: "LastName",
|
| 88 |
+
table: "Contacts",
|
| 89 |
+
type: "nvarchar(max)",
|
| 90 |
+
nullable: true,
|
| 91 |
+
oldClrType: typeof(string),
|
| 92 |
+
oldType: "nvarchar(max)");
|
| 93 |
+
|
| 94 |
+
migrationBuilder.AlterColumn<string>(
|
| 95 |
+
name: "Email",
|
| 96 |
+
table: "Contacts",
|
| 97 |
+
type: "nvarchar(max)",
|
| 98 |
+
nullable: true,
|
| 99 |
+
oldClrType: typeof(string),
|
| 100 |
+
oldType: "nvarchar(max)");
|
| 101 |
+
|
| 102 |
+
migrationBuilder.AlterColumn<string>(
|
| 103 |
+
name: "Country",
|
| 104 |
+
table: "Contacts",
|
| 105 |
+
type: "nvarchar(max)",
|
| 106 |
+
nullable: true,
|
| 107 |
+
oldClrType: typeof(string),
|
| 108 |
+
oldType: "nvarchar(max)");
|
| 109 |
+
|
| 110 |
+
migrationBuilder.AlterColumn<string>(
|
| 111 |
+
name: "City",
|
| 112 |
+
table: "Contacts",
|
| 113 |
+
type: "nvarchar(max)",
|
| 114 |
+
nullable: true,
|
| 115 |
+
oldClrType: typeof(string),
|
| 116 |
+
oldType: "nvarchar(max)");
|
| 117 |
+
|
| 118 |
+
migrationBuilder.AlterColumn<string>(
|
| 119 |
+
name: "Address",
|
| 120 |
+
table: "Contacts",
|
| 121 |
+
type: "nvarchar(max)",
|
| 122 |
+
nullable: true,
|
| 123 |
+
oldClrType: typeof(string),
|
| 124 |
+
oldType: "nvarchar(max)");
|
| 125 |
+
|
| 126 |
+
migrationBuilder.UpdateData(
|
| 127 |
+
table: "ContactGroups",
|
| 128 |
+
keyColumn: "Id",
|
| 129 |
+
keyValue: 1,
|
| 130 |
+
column: "CreatedAt",
|
| 131 |
+
value: new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5320));
|
| 132 |
+
|
| 133 |
+
migrationBuilder.UpdateData(
|
| 134 |
+
table: "ContactGroups",
|
| 135 |
+
keyColumn: "Id",
|
| 136 |
+
keyValue: 2,
|
| 137 |
+
column: "CreatedAt",
|
| 138 |
+
value: new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5332));
|
| 139 |
+
|
| 140 |
+
migrationBuilder.UpdateData(
|
| 141 |
+
table: "ContactGroups",
|
| 142 |
+
keyColumn: "Id",
|
| 143 |
+
keyValue: 3,
|
| 144 |
+
column: "CreatedAt",
|
| 145 |
+
value: new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5333));
|
| 146 |
+
|
| 147 |
+
migrationBuilder.UpdateData(
|
| 148 |
+
table: "ContactGroups",
|
| 149 |
+
keyColumn: "Id",
|
| 150 |
+
keyValue: 4,
|
| 151 |
+
column: "CreatedAt",
|
| 152 |
+
value: new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5335));
|
| 153 |
+
|
| 154 |
+
migrationBuilder.UpdateData(
|
| 155 |
+
table: "ContactGroups",
|
| 156 |
+
keyColumn: "Id",
|
| 157 |
+
keyValue: 5,
|
| 158 |
+
column: "CreatedAt",
|
| 159 |
+
value: new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5339));
|
| 160 |
+
|
| 161 |
+
migrationBuilder.UpdateData(
|
| 162 |
+
table: "ContactGroups",
|
| 163 |
+
keyColumn: "Id",
|
| 164 |
+
keyValue: 6,
|
| 165 |
+
column: "CreatedAt",
|
| 166 |
+
value: new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5340));
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
/// <inheritdoc />
|
| 170 |
+
protected override void Down(MigrationBuilder migrationBuilder)
|
| 171 |
+
{
|
| 172 |
+
migrationBuilder.AlterColumn<string>(
|
| 173 |
+
name: "WhatsAppNumber",
|
| 174 |
+
table: "Contacts",
|
| 175 |
+
type: "nvarchar(max)",
|
| 176 |
+
nullable: false,
|
| 177 |
+
defaultValue: "",
|
| 178 |
+
oldClrType: typeof(string),
|
| 179 |
+
oldType: "nvarchar(max)",
|
| 180 |
+
oldNullable: true);
|
| 181 |
+
|
| 182 |
+
migrationBuilder.AlterColumn<string>(
|
| 183 |
+
name: "State",
|
| 184 |
+
table: "Contacts",
|
| 185 |
+
type: "nvarchar(max)",
|
| 186 |
+
nullable: false,
|
| 187 |
+
defaultValue: "",
|
| 188 |
+
oldClrType: typeof(string),
|
| 189 |
+
oldType: "nvarchar(max)",
|
| 190 |
+
oldNullable: true);
|
| 191 |
+
|
| 192 |
+
migrationBuilder.AlterColumn<string>(
|
| 193 |
+
name: "PostalCode",
|
| 194 |
+
table: "Contacts",
|
| 195 |
+
type: "nvarchar(max)",
|
| 196 |
+
nullable: false,
|
| 197 |
+
defaultValue: "",
|
| 198 |
+
oldClrType: typeof(string),
|
| 199 |
+
oldType: "nvarchar(max)",
|
| 200 |
+
oldNullable: true);
|
| 201 |
+
|
| 202 |
+
migrationBuilder.AlterColumn<string>(
|
| 203 |
+
name: "PhotoPath",
|
| 204 |
+
table: "Contacts",
|
| 205 |
+
type: "nvarchar(max)",
|
| 206 |
+
nullable: false,
|
| 207 |
+
defaultValue: "",
|
| 208 |
+
oldClrType: typeof(string),
|
| 209 |
+
oldType: "nvarchar(max)",
|
| 210 |
+
oldNullable: true);
|
| 211 |
+
|
| 212 |
+
migrationBuilder.AlterColumn<string>(
|
| 213 |
+
name: "OtherDetails",
|
| 214 |
+
table: "Contacts",
|
| 215 |
+
type: "nvarchar(max)",
|
| 216 |
+
nullable: false,
|
| 217 |
+
defaultValue: "",
|
| 218 |
+
oldClrType: typeof(string),
|
| 219 |
+
oldType: "nvarchar(max)",
|
| 220 |
+
oldNullable: true);
|
| 221 |
+
|
| 222 |
+
migrationBuilder.AlterColumn<string>(
|
| 223 |
+
name: "NickName",
|
| 224 |
+
table: "Contacts",
|
| 225 |
+
type: "nvarchar(max)",
|
| 226 |
+
nullable: false,
|
| 227 |
+
defaultValue: "",
|
| 228 |
+
oldClrType: typeof(string),
|
| 229 |
+
oldType: "nvarchar(max)",
|
| 230 |
+
oldNullable: true);
|
| 231 |
+
|
| 232 |
+
migrationBuilder.AlterColumn<string>(
|
| 233 |
+
name: "Mobile3",
|
| 234 |
+
table: "Contacts",
|
| 235 |
+
type: "nvarchar(max)",
|
| 236 |
+
nullable: false,
|
| 237 |
+
defaultValue: "",
|
| 238 |
+
oldClrType: typeof(string),
|
| 239 |
+
oldType: "nvarchar(max)",
|
| 240 |
+
oldNullable: true);
|
| 241 |
+
|
| 242 |
+
migrationBuilder.AlterColumn<string>(
|
| 243 |
+
name: "Mobile2",
|
| 244 |
+
table: "Contacts",
|
| 245 |
+
type: "nvarchar(max)",
|
| 246 |
+
nullable: false,
|
| 247 |
+
defaultValue: "",
|
| 248 |
+
oldClrType: typeof(string),
|
| 249 |
+
oldType: "nvarchar(max)",
|
| 250 |
+
oldNullable: true);
|
| 251 |
+
|
| 252 |
+
migrationBuilder.AlterColumn<string>(
|
| 253 |
+
name: "Mobile1",
|
| 254 |
+
table: "Contacts",
|
| 255 |
+
type: "nvarchar(max)",
|
| 256 |
+
nullable: false,
|
| 257 |
+
defaultValue: "",
|
| 258 |
+
oldClrType: typeof(string),
|
| 259 |
+
oldType: "nvarchar(max)",
|
| 260 |
+
oldNullable: true);
|
| 261 |
+
|
| 262 |
+
migrationBuilder.AlterColumn<string>(
|
| 263 |
+
name: "LastName",
|
| 264 |
+
table: "Contacts",
|
| 265 |
+
type: "nvarchar(max)",
|
| 266 |
+
nullable: false,
|
| 267 |
+
defaultValue: "",
|
| 268 |
+
oldClrType: typeof(string),
|
| 269 |
+
oldType: "nvarchar(max)",
|
| 270 |
+
oldNullable: true);
|
| 271 |
+
|
| 272 |
+
migrationBuilder.AlterColumn<string>(
|
| 273 |
+
name: "Email",
|
| 274 |
+
table: "Contacts",
|
| 275 |
+
type: "nvarchar(max)",
|
| 276 |
+
nullable: false,
|
| 277 |
+
defaultValue: "",
|
| 278 |
+
oldClrType: typeof(string),
|
| 279 |
+
oldType: "nvarchar(max)",
|
| 280 |
+
oldNullable: true);
|
| 281 |
+
|
| 282 |
+
migrationBuilder.AlterColumn<string>(
|
| 283 |
+
name: "Country",
|
| 284 |
+
table: "Contacts",
|
| 285 |
+
type: "nvarchar(max)",
|
| 286 |
+
nullable: false,
|
| 287 |
+
defaultValue: "",
|
| 288 |
+
oldClrType: typeof(string),
|
| 289 |
+
oldType: "nvarchar(max)",
|
| 290 |
+
oldNullable: true);
|
| 291 |
+
|
| 292 |
+
migrationBuilder.AlterColumn<string>(
|
| 293 |
+
name: "City",
|
| 294 |
+
table: "Contacts",
|
| 295 |
+
type: "nvarchar(max)",
|
| 296 |
+
nullable: false,
|
| 297 |
+
defaultValue: "",
|
| 298 |
+
oldClrType: typeof(string),
|
| 299 |
+
oldType: "nvarchar(max)",
|
| 300 |
+
oldNullable: true);
|
| 301 |
+
|
| 302 |
+
migrationBuilder.AlterColumn<string>(
|
| 303 |
+
name: "Address",
|
| 304 |
+
table: "Contacts",
|
| 305 |
+
type: "nvarchar(max)",
|
| 306 |
+
nullable: false,
|
| 307 |
+
defaultValue: "",
|
| 308 |
+
oldClrType: typeof(string),
|
| 309 |
+
oldType: "nvarchar(max)",
|
| 310 |
+
oldNullable: true);
|
| 311 |
+
|
| 312 |
+
migrationBuilder.UpdateData(
|
| 313 |
+
table: "ContactGroups",
|
| 314 |
+
keyColumn: "Id",
|
| 315 |
+
keyValue: 1,
|
| 316 |
+
column: "CreatedAt",
|
| 317 |
+
value: new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2243));
|
| 318 |
+
|
| 319 |
+
migrationBuilder.UpdateData(
|
| 320 |
+
table: "ContactGroups",
|
| 321 |
+
keyColumn: "Id",
|
| 322 |
+
keyValue: 2,
|
| 323 |
+
column: "CreatedAt",
|
| 324 |
+
value: new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2260));
|
| 325 |
+
|
| 326 |
+
migrationBuilder.UpdateData(
|
| 327 |
+
table: "ContactGroups",
|
| 328 |
+
keyColumn: "Id",
|
| 329 |
+
keyValue: 3,
|
| 330 |
+
column: "CreatedAt",
|
| 331 |
+
value: new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2263));
|
| 332 |
+
|
| 333 |
+
migrationBuilder.UpdateData(
|
| 334 |
+
table: "ContactGroups",
|
| 335 |
+
keyColumn: "Id",
|
| 336 |
+
keyValue: 4,
|
| 337 |
+
column: "CreatedAt",
|
| 338 |
+
value: new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2266));
|
| 339 |
+
|
| 340 |
+
migrationBuilder.UpdateData(
|
| 341 |
+
table: "ContactGroups",
|
| 342 |
+
keyColumn: "Id",
|
| 343 |
+
keyValue: 5,
|
| 344 |
+
column: "CreatedAt",
|
| 345 |
+
value: new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2270));
|
| 346 |
+
|
| 347 |
+
migrationBuilder.UpdateData(
|
| 348 |
+
table: "ContactGroups",
|
| 349 |
+
keyColumn: "Id",
|
| 350 |
+
keyValue: 6,
|
| 351 |
+
column: "CreatedAt",
|
| 352 |
+
value: new DateTime(2026, 2, 6, 22, 28, 46, 432, DateTimeKind.Local).AddTicks(2273));
|
| 353 |
+
}
|
| 354 |
+
}
|
| 355 |
+
}
|
ContactManagementAPI/Migrations/20260209052719_AddSampleData.Designer.cs
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// <auto-generated />
|
| 2 |
+
using System;
|
| 3 |
+
using ContactManagementAPI.Data;
|
| 4 |
+
using Microsoft.EntityFrameworkCore;
|
| 5 |
+
using Microsoft.EntityFrameworkCore.Infrastructure;
|
| 6 |
+
using Microsoft.EntityFrameworkCore.Metadata;
|
| 7 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 8 |
+
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
| 9 |
+
|
| 10 |
+
#nullable disable
|
| 11 |
+
|
| 12 |
+
namespace ContactManagementAPI.Migrations
|
| 13 |
+
{
|
| 14 |
+
[DbContext(typeof(ApplicationDbContext))]
|
| 15 |
+
[Migration("20260209052719_AddSampleData")]
|
| 16 |
+
partial class AddSampleData
|
| 17 |
+
{
|
| 18 |
+
/// <inheritdoc />
|
| 19 |
+
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
| 20 |
+
{
|
| 21 |
+
#pragma warning disable 612, 618
|
| 22 |
+
modelBuilder
|
| 23 |
+
.HasAnnotation("ProductVersion", "8.0.0")
|
| 24 |
+
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
| 25 |
+
|
| 26 |
+
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
| 27 |
+
|
| 28 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 29 |
+
{
|
| 30 |
+
b.Property<int>("Id")
|
| 31 |
+
.ValueGeneratedOnAdd()
|
| 32 |
+
.HasColumnType("int");
|
| 33 |
+
|
| 34 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 35 |
+
|
| 36 |
+
b.Property<string>("Address")
|
| 37 |
+
.HasColumnType("nvarchar(max)");
|
| 38 |
+
|
| 39 |
+
b.Property<string>("City")
|
| 40 |
+
.HasColumnType("nvarchar(max)");
|
| 41 |
+
|
| 42 |
+
b.Property<string>("Country")
|
| 43 |
+
.HasColumnType("nvarchar(max)");
|
| 44 |
+
|
| 45 |
+
b.Property<DateTime>("CreatedAt")
|
| 46 |
+
.HasColumnType("datetime2");
|
| 47 |
+
|
| 48 |
+
b.Property<string>("Email")
|
| 49 |
+
.HasColumnType("nvarchar(max)");
|
| 50 |
+
|
| 51 |
+
b.Property<string>("FirstName")
|
| 52 |
+
.IsRequired()
|
| 53 |
+
.HasColumnType("nvarchar(max)");
|
| 54 |
+
|
| 55 |
+
b.Property<int?>("GroupId")
|
| 56 |
+
.HasColumnType("int");
|
| 57 |
+
|
| 58 |
+
b.Property<string>("LastName")
|
| 59 |
+
.HasColumnType("nvarchar(max)");
|
| 60 |
+
|
| 61 |
+
b.Property<string>("Mobile1")
|
| 62 |
+
.HasColumnType("nvarchar(max)");
|
| 63 |
+
|
| 64 |
+
b.Property<string>("Mobile2")
|
| 65 |
+
.HasColumnType("nvarchar(max)");
|
| 66 |
+
|
| 67 |
+
b.Property<string>("Mobile3")
|
| 68 |
+
.HasColumnType("nvarchar(max)");
|
| 69 |
+
|
| 70 |
+
b.Property<string>("NickName")
|
| 71 |
+
.HasColumnType("nvarchar(max)");
|
| 72 |
+
|
| 73 |
+
b.Property<string>("OtherDetails")
|
| 74 |
+
.HasColumnType("nvarchar(max)");
|
| 75 |
+
|
| 76 |
+
b.Property<string>("PhotoPath")
|
| 77 |
+
.HasColumnType("nvarchar(max)");
|
| 78 |
+
|
| 79 |
+
b.Property<string>("PostalCode")
|
| 80 |
+
.HasColumnType("nvarchar(max)");
|
| 81 |
+
|
| 82 |
+
b.Property<string>("State")
|
| 83 |
+
.HasColumnType("nvarchar(max)");
|
| 84 |
+
|
| 85 |
+
b.Property<DateTime>("UpdatedAt")
|
| 86 |
+
.HasColumnType("datetime2");
|
| 87 |
+
|
| 88 |
+
b.Property<string>("WhatsAppNumber")
|
| 89 |
+
.HasColumnType("nvarchar(max)");
|
| 90 |
+
|
| 91 |
+
b.HasKey("Id");
|
| 92 |
+
|
| 93 |
+
b.HasIndex("GroupId");
|
| 94 |
+
|
| 95 |
+
b.ToTable("Contacts");
|
| 96 |
+
});
|
| 97 |
+
|
| 98 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 99 |
+
{
|
| 100 |
+
b.Property<int>("Id")
|
| 101 |
+
.ValueGeneratedOnAdd()
|
| 102 |
+
.HasColumnType("int");
|
| 103 |
+
|
| 104 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 105 |
+
|
| 106 |
+
b.Property<int>("ContactId")
|
| 107 |
+
.HasColumnType("int");
|
| 108 |
+
|
| 109 |
+
b.Property<string>("ContentType")
|
| 110 |
+
.IsRequired()
|
| 111 |
+
.HasColumnType("nvarchar(max)");
|
| 112 |
+
|
| 113 |
+
b.Property<string>("DocumentPath")
|
| 114 |
+
.IsRequired()
|
| 115 |
+
.HasColumnType("nvarchar(max)");
|
| 116 |
+
|
| 117 |
+
b.Property<string>("DocumentType")
|
| 118 |
+
.IsRequired()
|
| 119 |
+
.HasColumnType("nvarchar(max)");
|
| 120 |
+
|
| 121 |
+
b.Property<string>("FileName")
|
| 122 |
+
.IsRequired()
|
| 123 |
+
.HasColumnType("nvarchar(max)");
|
| 124 |
+
|
| 125 |
+
b.Property<long>("FileSize")
|
| 126 |
+
.HasColumnType("bigint");
|
| 127 |
+
|
| 128 |
+
b.Property<DateTime>("UploadedAt")
|
| 129 |
+
.HasColumnType("datetime2");
|
| 130 |
+
|
| 131 |
+
b.HasKey("Id");
|
| 132 |
+
|
| 133 |
+
b.HasIndex("ContactId");
|
| 134 |
+
|
| 135 |
+
b.ToTable("ContactDocuments");
|
| 136 |
+
});
|
| 137 |
+
|
| 138 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 139 |
+
{
|
| 140 |
+
b.Property<int>("Id")
|
| 141 |
+
.ValueGeneratedOnAdd()
|
| 142 |
+
.HasColumnType("int");
|
| 143 |
+
|
| 144 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 145 |
+
|
| 146 |
+
b.Property<DateTime>("CreatedAt")
|
| 147 |
+
.HasColumnType("datetime2");
|
| 148 |
+
|
| 149 |
+
b.Property<string>("Description")
|
| 150 |
+
.IsRequired()
|
| 151 |
+
.HasColumnType("nvarchar(max)");
|
| 152 |
+
|
| 153 |
+
b.Property<string>("Name")
|
| 154 |
+
.IsRequired()
|
| 155 |
+
.HasColumnType("nvarchar(max)");
|
| 156 |
+
|
| 157 |
+
b.HasKey("Id");
|
| 158 |
+
|
| 159 |
+
b.ToTable("ContactGroups");
|
| 160 |
+
|
| 161 |
+
b.HasData(
|
| 162 |
+
new
|
| 163 |
+
{
|
| 164 |
+
Id = 1,
|
| 165 |
+
CreatedAt = new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8518),
|
| 166 |
+
Description = "Family members",
|
| 167 |
+
Name = "Family"
|
| 168 |
+
},
|
| 169 |
+
new
|
| 170 |
+
{
|
| 171 |
+
Id = 2,
|
| 172 |
+
CreatedAt = new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8531),
|
| 173 |
+
Description = "Friends",
|
| 174 |
+
Name = "Friends"
|
| 175 |
+
},
|
| 176 |
+
new
|
| 177 |
+
{
|
| 178 |
+
Id = 3,
|
| 179 |
+
CreatedAt = new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8533),
|
| 180 |
+
Description = "Business contacts",
|
| 181 |
+
Name = "Business"
|
| 182 |
+
},
|
| 183 |
+
new
|
| 184 |
+
{
|
| 185 |
+
Id = 4,
|
| 186 |
+
CreatedAt = new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8535),
|
| 187 |
+
Description = "School contacts",
|
| 188 |
+
Name = "School"
|
| 189 |
+
},
|
| 190 |
+
new
|
| 191 |
+
{
|
| 192 |
+
Id = 5,
|
| 193 |
+
CreatedAt = new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8537),
|
| 194 |
+
Description = "Church members",
|
| 195 |
+
Name = "Church"
|
| 196 |
+
},
|
| 197 |
+
new
|
| 198 |
+
{
|
| 199 |
+
Id = 6,
|
| 200 |
+
CreatedAt = new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8538),
|
| 201 |
+
Description = "Other contacts",
|
| 202 |
+
Name = "Others"
|
| 203 |
+
});
|
| 204 |
+
});
|
| 205 |
+
|
| 206 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 207 |
+
{
|
| 208 |
+
b.Property<int>("Id")
|
| 209 |
+
.ValueGeneratedOnAdd()
|
| 210 |
+
.HasColumnType("int");
|
| 211 |
+
|
| 212 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 213 |
+
|
| 214 |
+
b.Property<int>("ContactId")
|
| 215 |
+
.HasColumnType("int");
|
| 216 |
+
|
| 217 |
+
b.Property<string>("ContentType")
|
| 218 |
+
.IsRequired()
|
| 219 |
+
.HasColumnType("nvarchar(max)");
|
| 220 |
+
|
| 221 |
+
b.Property<string>("FileName")
|
| 222 |
+
.IsRequired()
|
| 223 |
+
.HasColumnType("nvarchar(max)");
|
| 224 |
+
|
| 225 |
+
b.Property<long>("FileSize")
|
| 226 |
+
.HasColumnType("bigint");
|
| 227 |
+
|
| 228 |
+
b.Property<bool>("IsProfilePhoto")
|
| 229 |
+
.HasColumnType("bit");
|
| 230 |
+
|
| 231 |
+
b.Property<string>("PhotoPath")
|
| 232 |
+
.IsRequired()
|
| 233 |
+
.HasColumnType("nvarchar(max)");
|
| 234 |
+
|
| 235 |
+
b.Property<DateTime>("UploadedAt")
|
| 236 |
+
.HasColumnType("datetime2");
|
| 237 |
+
|
| 238 |
+
b.HasKey("Id");
|
| 239 |
+
|
| 240 |
+
b.HasIndex("ContactId");
|
| 241 |
+
|
| 242 |
+
b.ToTable("ContactPhotos");
|
| 243 |
+
});
|
| 244 |
+
|
| 245 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 246 |
+
{
|
| 247 |
+
b.HasOne("ContactManagementAPI.Models.ContactGroup", "Group")
|
| 248 |
+
.WithMany("Contacts")
|
| 249 |
+
.HasForeignKey("GroupId")
|
| 250 |
+
.OnDelete(DeleteBehavior.SetNull);
|
| 251 |
+
|
| 252 |
+
b.Navigation("Group");
|
| 253 |
+
});
|
| 254 |
+
|
| 255 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 256 |
+
{
|
| 257 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 258 |
+
.WithMany("Documents")
|
| 259 |
+
.HasForeignKey("ContactId")
|
| 260 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 261 |
+
.IsRequired();
|
| 262 |
+
|
| 263 |
+
b.Navigation("Contact");
|
| 264 |
+
});
|
| 265 |
+
|
| 266 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 267 |
+
{
|
| 268 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 269 |
+
.WithMany("Photos")
|
| 270 |
+
.HasForeignKey("ContactId")
|
| 271 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 272 |
+
.IsRequired();
|
| 273 |
+
|
| 274 |
+
b.Navigation("Contact");
|
| 275 |
+
});
|
| 276 |
+
|
| 277 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 278 |
+
{
|
| 279 |
+
b.Navigation("Documents");
|
| 280 |
+
|
| 281 |
+
b.Navigation("Photos");
|
| 282 |
+
});
|
| 283 |
+
|
| 284 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 285 |
+
{
|
| 286 |
+
b.Navigation("Contacts");
|
| 287 |
+
});
|
| 288 |
+
#pragma warning restore 612, 618
|
| 289 |
+
}
|
| 290 |
+
}
|
| 291 |
+
}
|
ContactManagementAPI/Migrations/20260209052719_AddSampleData.cs
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 3 |
+
|
| 4 |
+
#nullable disable
|
| 5 |
+
|
| 6 |
+
namespace ContactManagementAPI.Migrations
|
| 7 |
+
{
|
| 8 |
+
/// <inheritdoc />
|
| 9 |
+
public partial class AddSampleData : Migration
|
| 10 |
+
{
|
| 11 |
+
/// <inheritdoc />
|
| 12 |
+
protected override void Up(MigrationBuilder migrationBuilder)
|
| 13 |
+
{
|
| 14 |
+
migrationBuilder.UpdateData(
|
| 15 |
+
table: "ContactGroups",
|
| 16 |
+
keyColumn: "Id",
|
| 17 |
+
keyValue: 1,
|
| 18 |
+
column: "CreatedAt",
|
| 19 |
+
value: new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8518));
|
| 20 |
+
|
| 21 |
+
migrationBuilder.UpdateData(
|
| 22 |
+
table: "ContactGroups",
|
| 23 |
+
keyColumn: "Id",
|
| 24 |
+
keyValue: 2,
|
| 25 |
+
column: "CreatedAt",
|
| 26 |
+
value: new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8531));
|
| 27 |
+
|
| 28 |
+
migrationBuilder.UpdateData(
|
| 29 |
+
table: "ContactGroups",
|
| 30 |
+
keyColumn: "Id",
|
| 31 |
+
keyValue: 3,
|
| 32 |
+
column: "CreatedAt",
|
| 33 |
+
value: new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8533));
|
| 34 |
+
|
| 35 |
+
migrationBuilder.UpdateData(
|
| 36 |
+
table: "ContactGroups",
|
| 37 |
+
keyColumn: "Id",
|
| 38 |
+
keyValue: 4,
|
| 39 |
+
column: "CreatedAt",
|
| 40 |
+
value: new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8535));
|
| 41 |
+
|
| 42 |
+
migrationBuilder.UpdateData(
|
| 43 |
+
table: "ContactGroups",
|
| 44 |
+
keyColumn: "Id",
|
| 45 |
+
keyValue: 5,
|
| 46 |
+
column: "CreatedAt",
|
| 47 |
+
value: new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8537));
|
| 48 |
+
|
| 49 |
+
migrationBuilder.UpdateData(
|
| 50 |
+
table: "ContactGroups",
|
| 51 |
+
keyColumn: "Id",
|
| 52 |
+
keyValue: 6,
|
| 53 |
+
column: "CreatedAt",
|
| 54 |
+
value: new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8538));
|
| 55 |
+
|
| 56 |
+
// Insert sample contacts
|
| 57 |
+
migrationBuilder.InsertData(
|
| 58 |
+
table: "Contacts",
|
| 59 |
+
columns: new[] { "Id", "FirstName", "LastName", "NickName", "Email", "Mobile1", "Mobile2", "Mobile3", "WhatsAppNumber", "Address", "City", "State", "PostalCode", "Country", "PhotoPath", "GroupId", "OtherDetails", "CreatedAt", "UpdatedAt" },
|
| 60 |
+
values: new object[,]
|
| 61 |
+
{
|
| 62 |
+
{ 1, "John", "Doe", "Johnny", "john.doe@email.com", "+1-555-0101", "+1-555-0102", null, "+1-555-0101", "123 Main Street", "New York", "NY", "10001", "USA", "/uploads/photos/1_sample.jpg", 1, "Close friend from college", new DateTime(2026, 2, 9, 10, 30, 0), new DateTime(2026, 2, 9, 10, 30, 0) },
|
| 63 |
+
{ 2, "Sarah", "Smith", "Sara", "sarah.smith@email.com", "+1-555-0201", "+1-555-0202", "+1-555-0203", "+1-555-0201", "456 Oak Avenue", "Los Angeles", "CA", "90001", "USA", "/uploads/photos/2_sample.jpg", 2, "Works at Tech Corp", new DateTime(2026, 2, 9, 10, 32, 0), new DateTime(2026, 2, 9, 10, 32, 0) },
|
| 64 |
+
{ 3, "Michael", "Johnson", "Mike", "michael.j@email.com", "+1-555-0301", null, null, "+1-555-0301", "789 Pine Road", "Chicago", "IL", "60601", "USA", "/uploads/photos/3_sample.jpg", 3, "Project manager", new DateTime(2026, 2, 9, 10, 34, 0), new DateTime(2026, 2, 9, 10, 34, 0) },
|
| 65 |
+
{ 4, "Emily", "Brown", "Em", "emily.brown@email.com", "+1-555-0401", "+1-555-0402", null, "+1-555-0401", "321 Elm Street", "Houston", "TX", "77001", "USA", "/uploads/photos/4_sample.jpg", 1, "Sister, lives in Houston", new DateTime(2026, 2, 9, 10, 36, 0), new DateTime(2026, 2, 9, 10, 36, 0) },
|
| 66 |
+
{ 5, "David", "Wilson", "Dave", "david.w@email.com", "+1-555-0501", "+1-555-0502", "+1-555-0503", "+1-555-0501", "654 Cedar Lane", "Phoenix", "AZ", "85001", "USA", "/uploads/photos/5_sample.jpg", 4, "School principal", new DateTime(2026, 2, 9, 10, 38, 0), new DateTime(2026, 2, 9, 10, 38, 0) }
|
| 67 |
+
});
|
| 68 |
+
|
| 69 |
+
// Insert sample documents
|
| 70 |
+
migrationBuilder.InsertData(
|
| 71 |
+
table: "ContactDocuments",
|
| 72 |
+
columns: new[] { "ContactId", "DocumentPath", "FileName", "FileSize", "ContentType", "DocumentType", "UploadedAt" },
|
| 73 |
+
values: new object[,]
|
| 74 |
+
{
|
| 75 |
+
{ 1, "/uploads/documents/1_ID_Proof.pdf", "john_doe_id.pdf", 145000L, "application/pdf", "ID", new DateTime(2026, 2, 9, 10, 30, 0) },
|
| 76 |
+
{ 1, "/uploads/documents/1_Resume.pdf", "john_doe_resume.pdf", 235000L, "application/pdf", "Resume", new DateTime(2026, 2, 9, 10, 31, 0) },
|
| 77 |
+
{ 2, "/uploads/documents/2_Business_Card.pdf", "sarah_smith_business.pdf", 89000L, "application/pdf", "Business", new DateTime(2026, 2, 9, 10, 32, 0) },
|
| 78 |
+
{ 2, "/uploads/documents/2_Address_Proof.pdf", "sarah_address.pdf", 156000L, "application/pdf", "Address", new DateTime(2026, 2, 9, 10, 33, 0) },
|
| 79 |
+
{ 3, "/uploads/documents/3_Contract.pdf", "michael_contract.pdf", 289000L, "application/pdf", "Contract", new DateTime(2026, 2, 9, 10, 34, 0) },
|
| 80 |
+
{ 4, "/uploads/documents/4_ID_Proof.pdf", "emily_id.pdf", 167000L, "application/pdf", "ID", new DateTime(2026, 2, 9, 10, 36, 0) },
|
| 81 |
+
{ 5, "/uploads/documents/5_Certification.pdf", "david_certification.pdf", 198000L, "application/pdf", "Certification", new DateTime(2026, 2, 9, 10, 38, 0) },
|
| 82 |
+
{ 5, "/uploads/documents/5_License.pdf", "david_license.pdf", 142000L, "application/pdf", "License", new DateTime(2026, 2, 9, 10, 39, 0) }
|
| 83 |
+
});
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
/// <inheritdoc />
|
| 87 |
+
protected override void Down(MigrationBuilder migrationBuilder)
|
| 88 |
+
{
|
| 89 |
+
migrationBuilder.DeleteData(
|
| 90 |
+
table: "ContactDocuments",
|
| 91 |
+
keyColumn: "Id",
|
| 92 |
+
keyValue: 1);
|
| 93 |
+
|
| 94 |
+
migrationBuilder.DeleteData(
|
| 95 |
+
table: "ContactDocuments",
|
| 96 |
+
keyColumn: "Id",
|
| 97 |
+
keyValue: 2);
|
| 98 |
+
|
| 99 |
+
migrationBuilder.DeleteData(
|
| 100 |
+
table: "ContactDocuments",
|
| 101 |
+
keyColumn: "Id",
|
| 102 |
+
keyValue: 3);
|
| 103 |
+
|
| 104 |
+
migrationBuilder.DeleteData(
|
| 105 |
+
table: "ContactDocuments",
|
| 106 |
+
keyColumn: "Id",
|
| 107 |
+
keyValue: 4);
|
| 108 |
+
|
| 109 |
+
migrationBuilder.DeleteData(
|
| 110 |
+
table: "ContactDocuments",
|
| 111 |
+
keyColumn: "Id",
|
| 112 |
+
keyValue: 5);
|
| 113 |
+
|
| 114 |
+
migrationBuilder.DeleteData(
|
| 115 |
+
table: "ContactDocuments",
|
| 116 |
+
keyColumn: "Id",
|
| 117 |
+
keyValue: 6);
|
| 118 |
+
|
| 119 |
+
migrationBuilder.DeleteData(
|
| 120 |
+
table: "ContactDocuments",
|
| 121 |
+
keyColumn: "Id",
|
| 122 |
+
keyValue: 7);
|
| 123 |
+
|
| 124 |
+
migrationBuilder.DeleteData(
|
| 125 |
+
table: "ContactDocuments",
|
| 126 |
+
keyColumn: "Id",
|
| 127 |
+
keyValue: 8);
|
| 128 |
+
|
| 129 |
+
migrationBuilder.DeleteData(
|
| 130 |
+
table: "Contacts",
|
| 131 |
+
keyColumn: "Id",
|
| 132 |
+
keyValue: 1);
|
| 133 |
+
|
| 134 |
+
migrationBuilder.DeleteData(
|
| 135 |
+
table: "Contacts",
|
| 136 |
+
keyColumn: "Id",
|
| 137 |
+
keyValue: 2);
|
| 138 |
+
|
| 139 |
+
migrationBuilder.DeleteData(
|
| 140 |
+
table: "Contacts",
|
| 141 |
+
keyColumn: "Id",
|
| 142 |
+
keyValue: 3);
|
| 143 |
+
|
| 144 |
+
migrationBuilder.DeleteData(
|
| 145 |
+
table: "Contacts",
|
| 146 |
+
keyColumn: "Id",
|
| 147 |
+
keyValue: 4);
|
| 148 |
+
|
| 149 |
+
migrationBuilder.DeleteData(
|
| 150 |
+
table: "Contacts",
|
| 151 |
+
keyColumn: "Id",
|
| 152 |
+
keyValue: 5);
|
| 153 |
+
|
| 154 |
+
migrationBuilder.UpdateData(
|
| 155 |
+
table: "ContactGroups",
|
| 156 |
+
keyColumn: "Id",
|
| 157 |
+
keyValue: 1,
|
| 158 |
+
column: "CreatedAt",
|
| 159 |
+
value: new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5320));
|
| 160 |
+
|
| 161 |
+
migrationBuilder.UpdateData(
|
| 162 |
+
table: "ContactGroups",
|
| 163 |
+
keyColumn: "Id",
|
| 164 |
+
keyValue: 2,
|
| 165 |
+
column: "CreatedAt",
|
| 166 |
+
value: new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5332));
|
| 167 |
+
|
| 168 |
+
migrationBuilder.UpdateData(
|
| 169 |
+
table: "ContactGroups",
|
| 170 |
+
keyColumn: "Id",
|
| 171 |
+
keyValue: 3,
|
| 172 |
+
column: "CreatedAt",
|
| 173 |
+
value: new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5333));
|
| 174 |
+
|
| 175 |
+
migrationBuilder.UpdateData(
|
| 176 |
+
table: "ContactGroups",
|
| 177 |
+
keyColumn: "Id",
|
| 178 |
+
keyValue: 4,
|
| 179 |
+
column: "CreatedAt",
|
| 180 |
+
value: new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5335));
|
| 181 |
+
|
| 182 |
+
migrationBuilder.UpdateData(
|
| 183 |
+
table: "ContactGroups",
|
| 184 |
+
keyColumn: "Id",
|
| 185 |
+
keyValue: 5,
|
| 186 |
+
column: "CreatedAt",
|
| 187 |
+
value: new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5339));
|
| 188 |
+
|
| 189 |
+
migrationBuilder.UpdateData(
|
| 190 |
+
table: "ContactGroups",
|
| 191 |
+
keyColumn: "Id",
|
| 192 |
+
keyValue: 6,
|
| 193 |
+
column: "CreatedAt",
|
| 194 |
+
value: new DateTime(2026, 2, 8, 21, 55, 46, 992, DateTimeKind.Local).AddTicks(5340));
|
| 195 |
+
}
|
| 196 |
+
}
|
| 197 |
+
}
|
ContactManagementAPI/Migrations/20260209090000_AddUserSecurity.Designer.cs
ADDED
|
@@ -0,0 +1,463 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// <auto-generated />
|
| 2 |
+
using System;
|
| 3 |
+
using ContactManagementAPI.Data;
|
| 4 |
+
using Microsoft.EntityFrameworkCore;
|
| 5 |
+
using Microsoft.EntityFrameworkCore.Infrastructure;
|
| 6 |
+
using Microsoft.EntityFrameworkCore.Metadata;
|
| 7 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 8 |
+
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
| 9 |
+
|
| 10 |
+
#nullable disable
|
| 11 |
+
|
| 12 |
+
namespace ContactManagementAPI.Migrations
|
| 13 |
+
{
|
| 14 |
+
[DbContext(typeof(ApplicationDbContext))]
|
| 15 |
+
[Migration("20260209090000_AddUserSecurity")]
|
| 16 |
+
partial class AddUserSecurity
|
| 17 |
+
{
|
| 18 |
+
/// <inheritdoc />
|
| 19 |
+
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
| 20 |
+
{
|
| 21 |
+
#pragma warning disable 612, 618
|
| 22 |
+
modelBuilder
|
| 23 |
+
.HasAnnotation("ProductVersion", "8.0.0")
|
| 24 |
+
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
| 25 |
+
|
| 26 |
+
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
| 27 |
+
|
| 28 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 29 |
+
{
|
| 30 |
+
b.Property<int>("Id")
|
| 31 |
+
.ValueGeneratedOnAdd()
|
| 32 |
+
.HasColumnType("int");
|
| 33 |
+
|
| 34 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 35 |
+
|
| 36 |
+
b.Property<string>("Address")
|
| 37 |
+
.HasColumnType("nvarchar(max)");
|
| 38 |
+
|
| 39 |
+
b.Property<string>("City")
|
| 40 |
+
.HasColumnType("nvarchar(max)");
|
| 41 |
+
|
| 42 |
+
b.Property<string>("Country")
|
| 43 |
+
.HasColumnType("nvarchar(max)");
|
| 44 |
+
|
| 45 |
+
b.Property<DateTime>("CreatedAt")
|
| 46 |
+
.HasColumnType("datetime2");
|
| 47 |
+
|
| 48 |
+
b.Property<string>("Email")
|
| 49 |
+
.HasColumnType("nvarchar(max)");
|
| 50 |
+
|
| 51 |
+
b.Property<string>("FirstName")
|
| 52 |
+
.IsRequired()
|
| 53 |
+
.HasColumnType("nvarchar(max)");
|
| 54 |
+
|
| 55 |
+
b.Property<int?>("GroupId")
|
| 56 |
+
.HasColumnType("int");
|
| 57 |
+
|
| 58 |
+
b.Property<string>("LastName")
|
| 59 |
+
.HasColumnType("nvarchar(max)");
|
| 60 |
+
|
| 61 |
+
b.Property<string>("Mobile1")
|
| 62 |
+
.HasColumnType("nvarchar(max)");
|
| 63 |
+
|
| 64 |
+
b.Property<string>("Mobile2")
|
| 65 |
+
.HasColumnType("nvarchar(max)");
|
| 66 |
+
|
| 67 |
+
b.Property<string>("Mobile3")
|
| 68 |
+
.HasColumnType("nvarchar(max)");
|
| 69 |
+
|
| 70 |
+
b.Property<string>("NickName")
|
| 71 |
+
.HasColumnType("nvarchar(max)");
|
| 72 |
+
|
| 73 |
+
b.Property<string>("OtherDetails")
|
| 74 |
+
.HasColumnType("nvarchar(max)");
|
| 75 |
+
|
| 76 |
+
b.Property<string>("PhotoPath")
|
| 77 |
+
.HasColumnType("nvarchar(max)");
|
| 78 |
+
|
| 79 |
+
b.Property<string>("PostalCode")
|
| 80 |
+
.HasColumnType("nvarchar(max)");
|
| 81 |
+
|
| 82 |
+
b.Property<string>("State")
|
| 83 |
+
.HasColumnType("nvarchar(max)");
|
| 84 |
+
|
| 85 |
+
b.Property<DateTime>("UpdatedAt")
|
| 86 |
+
.HasColumnType("datetime2");
|
| 87 |
+
|
| 88 |
+
b.Property<string>("WhatsAppNumber")
|
| 89 |
+
.HasColumnType("nvarchar(max)");
|
| 90 |
+
|
| 91 |
+
b.HasKey("Id");
|
| 92 |
+
|
| 93 |
+
b.HasIndex("GroupId");
|
| 94 |
+
|
| 95 |
+
b.ToTable("Contacts");
|
| 96 |
+
});
|
| 97 |
+
|
| 98 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 99 |
+
{
|
| 100 |
+
b.Property<int>("Id")
|
| 101 |
+
.ValueGeneratedOnAdd()
|
| 102 |
+
.HasColumnType("int");
|
| 103 |
+
|
| 104 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 105 |
+
|
| 106 |
+
b.Property<int>("ContactId")
|
| 107 |
+
.HasColumnType("int");
|
| 108 |
+
|
| 109 |
+
b.Property<string>("ContentType")
|
| 110 |
+
.IsRequired()
|
| 111 |
+
.HasColumnType("nvarchar(max)");
|
| 112 |
+
|
| 113 |
+
b.Property<string>("DocumentPath")
|
| 114 |
+
.IsRequired()
|
| 115 |
+
.HasColumnType("nvarchar(max)");
|
| 116 |
+
|
| 117 |
+
b.Property<string>("DocumentType")
|
| 118 |
+
.IsRequired()
|
| 119 |
+
.HasColumnType("nvarchar(max)");
|
| 120 |
+
|
| 121 |
+
b.Property<string>("FileName")
|
| 122 |
+
.IsRequired()
|
| 123 |
+
.HasColumnType("nvarchar(max)");
|
| 124 |
+
|
| 125 |
+
b.Property<long>("FileSize")
|
| 126 |
+
.HasColumnType("bigint");
|
| 127 |
+
|
| 128 |
+
b.Property<DateTime>("UploadedAt")
|
| 129 |
+
.HasColumnType("datetime2");
|
| 130 |
+
|
| 131 |
+
b.HasKey("Id");
|
| 132 |
+
|
| 133 |
+
b.HasIndex("ContactId");
|
| 134 |
+
|
| 135 |
+
b.ToTable("ContactDocuments");
|
| 136 |
+
});
|
| 137 |
+
|
| 138 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 139 |
+
{
|
| 140 |
+
b.Property<int>("Id")
|
| 141 |
+
.ValueGeneratedOnAdd()
|
| 142 |
+
.HasColumnType("int");
|
| 143 |
+
|
| 144 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 145 |
+
|
| 146 |
+
b.Property<DateTime>("CreatedAt")
|
| 147 |
+
.HasColumnType("datetime2");
|
| 148 |
+
|
| 149 |
+
b.Property<string>("Description")
|
| 150 |
+
.IsRequired()
|
| 151 |
+
.HasColumnType("nvarchar(max)");
|
| 152 |
+
|
| 153 |
+
b.Property<string>("Name")
|
| 154 |
+
.IsRequired()
|
| 155 |
+
.HasColumnType("nvarchar(max)");
|
| 156 |
+
|
| 157 |
+
b.HasKey("Id");
|
| 158 |
+
|
| 159 |
+
b.ToTable("ContactGroups");
|
| 160 |
+
|
| 161 |
+
b.HasData(
|
| 162 |
+
new
|
| 163 |
+
{
|
| 164 |
+
Id = 1,
|
| 165 |
+
CreatedAt = new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8518),
|
| 166 |
+
Description = "Family members",
|
| 167 |
+
Name = "Family"
|
| 168 |
+
},
|
| 169 |
+
new
|
| 170 |
+
{
|
| 171 |
+
Id = 2,
|
| 172 |
+
CreatedAt = new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8531),
|
| 173 |
+
Description = "Friends",
|
| 174 |
+
Name = "Friends"
|
| 175 |
+
},
|
| 176 |
+
new
|
| 177 |
+
{
|
| 178 |
+
Id = 3,
|
| 179 |
+
CreatedAt = new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8533),
|
| 180 |
+
Description = "Business contacts",
|
| 181 |
+
Name = "Business"
|
| 182 |
+
},
|
| 183 |
+
new
|
| 184 |
+
{
|
| 185 |
+
Id = 4,
|
| 186 |
+
CreatedAt = new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8535),
|
| 187 |
+
Description = "School contacts",
|
| 188 |
+
Name = "School"
|
| 189 |
+
},
|
| 190 |
+
new
|
| 191 |
+
{
|
| 192 |
+
Id = 5,
|
| 193 |
+
CreatedAt = new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8537),
|
| 194 |
+
Description = "Church members",
|
| 195 |
+
Name = "Church"
|
| 196 |
+
},
|
| 197 |
+
new
|
| 198 |
+
{
|
| 199 |
+
Id = 6,
|
| 200 |
+
CreatedAt = new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8538),
|
| 201 |
+
Description = "Other contacts",
|
| 202 |
+
Name = "Others"
|
| 203 |
+
});
|
| 204 |
+
});
|
| 205 |
+
|
| 206 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 207 |
+
{
|
| 208 |
+
b.Property<int>("Id")
|
| 209 |
+
.ValueGeneratedOnAdd()
|
| 210 |
+
.HasColumnType("int");
|
| 211 |
+
|
| 212 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 213 |
+
|
| 214 |
+
b.Property<int>("ContactId")
|
| 215 |
+
.HasColumnType("int");
|
| 216 |
+
|
| 217 |
+
b.Property<string>("ContentType")
|
| 218 |
+
.IsRequired()
|
| 219 |
+
.HasColumnType("nvarchar(max)");
|
| 220 |
+
|
| 221 |
+
b.Property<string>("FileName")
|
| 222 |
+
.IsRequired()
|
| 223 |
+
.HasColumnType("nvarchar(max)");
|
| 224 |
+
|
| 225 |
+
b.Property<long>("FileSize")
|
| 226 |
+
.HasColumnType("bigint");
|
| 227 |
+
|
| 228 |
+
b.Property<bool>("IsProfilePhoto")
|
| 229 |
+
.HasColumnType("bit");
|
| 230 |
+
|
| 231 |
+
b.Property<string>("PhotoPath")
|
| 232 |
+
.IsRequired()
|
| 233 |
+
.HasColumnType("nvarchar(max)");
|
| 234 |
+
|
| 235 |
+
b.Property<DateTime>("UploadedAt")
|
| 236 |
+
.HasColumnType("datetime2");
|
| 237 |
+
|
| 238 |
+
b.HasKey("Id");
|
| 239 |
+
|
| 240 |
+
b.HasIndex("ContactId");
|
| 241 |
+
|
| 242 |
+
b.ToTable("ContactPhotos");
|
| 243 |
+
});
|
| 244 |
+
|
| 245 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 246 |
+
{
|
| 247 |
+
b.Property<int>("Id")
|
| 248 |
+
.ValueGeneratedOnAdd()
|
| 249 |
+
.HasColumnType("int");
|
| 250 |
+
|
| 251 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 252 |
+
|
| 253 |
+
b.Property<DateTime>("CreatedAt")
|
| 254 |
+
.HasColumnType("datetime2");
|
| 255 |
+
|
| 256 |
+
b.Property<string>("FullName")
|
| 257 |
+
.HasMaxLength(200)
|
| 258 |
+
.HasColumnType("nvarchar(200)");
|
| 259 |
+
|
| 260 |
+
b.Property<int?>("GroupId")
|
| 261 |
+
.HasColumnType("int");
|
| 262 |
+
|
| 263 |
+
b.Property<bool>("IsActive")
|
| 264 |
+
.HasColumnType("bit");
|
| 265 |
+
|
| 266 |
+
b.Property<bool>("IsAdmin")
|
| 267 |
+
.HasColumnType("bit");
|
| 268 |
+
|
| 269 |
+
b.Property<string>("PasswordHash")
|
| 270 |
+
.IsRequired()
|
| 271 |
+
.HasColumnType("nvarchar(max)");
|
| 272 |
+
|
| 273 |
+
b.Property<DateTime>("UpdatedAt")
|
| 274 |
+
.HasColumnType("datetime2");
|
| 275 |
+
|
| 276 |
+
b.Property<string>("UserName")
|
| 277 |
+
.IsRequired()
|
| 278 |
+
.HasMaxLength(100)
|
| 279 |
+
.HasColumnType("nvarchar(100)");
|
| 280 |
+
|
| 281 |
+
b.HasKey("Id");
|
| 282 |
+
|
| 283 |
+
b.HasIndex("GroupId");
|
| 284 |
+
|
| 285 |
+
b.HasIndex("UserName")
|
| 286 |
+
.IsUnique();
|
| 287 |
+
|
| 288 |
+
b.ToTable("AppUsers");
|
| 289 |
+
});
|
| 290 |
+
|
| 291 |
+
modelBuilder.Entity("ContactManagementAPI.Models.GroupRight", b =>
|
| 292 |
+
{
|
| 293 |
+
b.Property<int>("Id")
|
| 294 |
+
.ValueGeneratedOnAdd()
|
| 295 |
+
.HasColumnType("int");
|
| 296 |
+
|
| 297 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 298 |
+
|
| 299 |
+
b.Property<bool>("IsGranted")
|
| 300 |
+
.HasColumnType("bit");
|
| 301 |
+
|
| 302 |
+
b.Property<string>("RightKey")
|
| 303 |
+
.IsRequired()
|
| 304 |
+
.HasMaxLength(100)
|
| 305 |
+
.HasColumnType("nvarchar(100)");
|
| 306 |
+
|
| 307 |
+
b.Property<int>("UserGroupId")
|
| 308 |
+
.HasColumnType("int");
|
| 309 |
+
|
| 310 |
+
b.HasKey("Id");
|
| 311 |
+
|
| 312 |
+
b.HasIndex("UserGroupId", "RightKey")
|
| 313 |
+
.IsUnique();
|
| 314 |
+
|
| 315 |
+
b.ToTable("GroupRights");
|
| 316 |
+
});
|
| 317 |
+
|
| 318 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserGroup", b =>
|
| 319 |
+
{
|
| 320 |
+
b.Property<int>("Id")
|
| 321 |
+
.ValueGeneratedOnAdd()
|
| 322 |
+
.HasColumnType("int");
|
| 323 |
+
|
| 324 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 325 |
+
|
| 326 |
+
b.Property<DateTime>("CreatedAt")
|
| 327 |
+
.HasColumnType("datetime2");
|
| 328 |
+
|
| 329 |
+
b.Property<string>("Description")
|
| 330 |
+
.HasMaxLength(500)
|
| 331 |
+
.HasColumnType("nvarchar(500)");
|
| 332 |
+
|
| 333 |
+
b.Property<string>("Name")
|
| 334 |
+
.IsRequired()
|
| 335 |
+
.HasMaxLength(150)
|
| 336 |
+
.HasColumnType("nvarchar(150)");
|
| 337 |
+
|
| 338 |
+
b.HasKey("Id");
|
| 339 |
+
|
| 340 |
+
b.HasIndex("Name")
|
| 341 |
+
.IsUnique();
|
| 342 |
+
|
| 343 |
+
b.ToTable("UserGroups");
|
| 344 |
+
});
|
| 345 |
+
|
| 346 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserRight", b =>
|
| 347 |
+
{
|
| 348 |
+
b.Property<int>("Id")
|
| 349 |
+
.ValueGeneratedOnAdd()
|
| 350 |
+
.HasColumnType("int");
|
| 351 |
+
|
| 352 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 353 |
+
|
| 354 |
+
b.Property<int>("AppUserId")
|
| 355 |
+
.HasColumnType("int");
|
| 356 |
+
|
| 357 |
+
b.Property<bool>("IsGranted")
|
| 358 |
+
.HasColumnType("bit");
|
| 359 |
+
|
| 360 |
+
b.Property<string>("RightKey")
|
| 361 |
+
.IsRequired()
|
| 362 |
+
.HasMaxLength(100)
|
| 363 |
+
.HasColumnType("nvarchar(100)");
|
| 364 |
+
|
| 365 |
+
b.HasKey("Id");
|
| 366 |
+
|
| 367 |
+
b.HasIndex("AppUserId", "RightKey")
|
| 368 |
+
.IsUnique();
|
| 369 |
+
|
| 370 |
+
b.ToTable("UserRights");
|
| 371 |
+
});
|
| 372 |
+
|
| 373 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 374 |
+
{
|
| 375 |
+
b.HasOne("ContactManagementAPI.Models.ContactGroup", "Group")
|
| 376 |
+
.WithMany("Contacts")
|
| 377 |
+
.HasForeignKey("GroupId")
|
| 378 |
+
.OnDelete(DeleteBehavior.SetNull);
|
| 379 |
+
|
| 380 |
+
b.Navigation("Group");
|
| 381 |
+
});
|
| 382 |
+
|
| 383 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 384 |
+
{
|
| 385 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 386 |
+
.WithMany("Documents")
|
| 387 |
+
.HasForeignKey("ContactId")
|
| 388 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 389 |
+
.IsRequired();
|
| 390 |
+
|
| 391 |
+
b.Navigation("Contact");
|
| 392 |
+
});
|
| 393 |
+
|
| 394 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 395 |
+
{
|
| 396 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 397 |
+
.WithMany("Photos")
|
| 398 |
+
.HasForeignKey("ContactId")
|
| 399 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 400 |
+
.IsRequired();
|
| 401 |
+
|
| 402 |
+
b.Navigation("Contact");
|
| 403 |
+
});
|
| 404 |
+
|
| 405 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 406 |
+
{
|
| 407 |
+
b.HasOne("ContactManagementAPI.Models.UserGroup", "Group")
|
| 408 |
+
.WithMany("Users")
|
| 409 |
+
.HasForeignKey("GroupId")
|
| 410 |
+
.OnDelete(DeleteBehavior.SetNull);
|
| 411 |
+
|
| 412 |
+
b.Navigation("Group");
|
| 413 |
+
});
|
| 414 |
+
|
| 415 |
+
modelBuilder.Entity("ContactManagementAPI.Models.GroupRight", b =>
|
| 416 |
+
{
|
| 417 |
+
b.HasOne("ContactManagementAPI.Models.UserGroup", "UserGroup")
|
| 418 |
+
.WithMany("GroupRights")
|
| 419 |
+
.HasForeignKey("UserGroupId")
|
| 420 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 421 |
+
.IsRequired();
|
| 422 |
+
|
| 423 |
+
b.Navigation("UserGroup");
|
| 424 |
+
});
|
| 425 |
+
|
| 426 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserRight", b =>
|
| 427 |
+
{
|
| 428 |
+
b.HasOne("ContactManagementAPI.Models.AppUser", "AppUser")
|
| 429 |
+
.WithMany("UserRights")
|
| 430 |
+
.HasForeignKey("AppUserId")
|
| 431 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 432 |
+
.IsRequired();
|
| 433 |
+
|
| 434 |
+
b.Navigation("AppUser");
|
| 435 |
+
});
|
| 436 |
+
|
| 437 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 438 |
+
{
|
| 439 |
+
b.Navigation("Documents");
|
| 440 |
+
|
| 441 |
+
b.Navigation("Photos");
|
| 442 |
+
});
|
| 443 |
+
|
| 444 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 445 |
+
{
|
| 446 |
+
b.Navigation("Contacts");
|
| 447 |
+
});
|
| 448 |
+
|
| 449 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 450 |
+
{
|
| 451 |
+
b.Navigation("UserRights");
|
| 452 |
+
});
|
| 453 |
+
|
| 454 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserGroup", b =>
|
| 455 |
+
{
|
| 456 |
+
b.Navigation("GroupRights");
|
| 457 |
+
|
| 458 |
+
b.Navigation("Users");
|
| 459 |
+
});
|
| 460 |
+
#pragma warning restore 612, 618
|
| 461 |
+
}
|
| 462 |
+
}
|
| 463 |
+
}
|
ContactManagementAPI/Migrations/20260209090000_AddUserSecurity.cs
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 3 |
+
|
| 4 |
+
#nullable disable
|
| 5 |
+
|
| 6 |
+
namespace ContactManagementAPI.Migrations
|
| 7 |
+
{
|
| 8 |
+
/// <inheritdoc />
|
| 9 |
+
public partial class AddUserSecurity : Migration
|
| 10 |
+
{
|
| 11 |
+
/// <inheritdoc />
|
| 12 |
+
protected override void Up(MigrationBuilder migrationBuilder)
|
| 13 |
+
{
|
| 14 |
+
migrationBuilder.CreateTable(
|
| 15 |
+
name: "UserGroups",
|
| 16 |
+
columns: table => new
|
| 17 |
+
{
|
| 18 |
+
Id = table.Column<int>(type: "int", nullable: false)
|
| 19 |
+
.Annotation("SqlServer:Identity", "1, 1"),
|
| 20 |
+
Name = table.Column<string>(type: "nvarchar(150)", maxLength: 150, nullable: false),
|
| 21 |
+
Description = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
| 22 |
+
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false)
|
| 23 |
+
},
|
| 24 |
+
constraints: table =>
|
| 25 |
+
{
|
| 26 |
+
table.PrimaryKey("PK_UserGroups", x => x.Id);
|
| 27 |
+
});
|
| 28 |
+
|
| 29 |
+
migrationBuilder.CreateTable(
|
| 30 |
+
name: "AppUsers",
|
| 31 |
+
columns: table => new
|
| 32 |
+
{
|
| 33 |
+
Id = table.Column<int>(type: "int", nullable: false)
|
| 34 |
+
.Annotation("SqlServer:Identity", "1, 1"),
|
| 35 |
+
UserName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
| 36 |
+
PasswordHash = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
| 37 |
+
FullName = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
|
| 38 |
+
IsAdmin = table.Column<bool>(type: "bit", nullable: false),
|
| 39 |
+
IsActive = table.Column<bool>(type: "bit", nullable: false),
|
| 40 |
+
GroupId = table.Column<int>(type: "int", nullable: true),
|
| 41 |
+
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
| 42 |
+
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: false)
|
| 43 |
+
},
|
| 44 |
+
constraints: table =>
|
| 45 |
+
{
|
| 46 |
+
table.PrimaryKey("PK_AppUsers", x => x.Id);
|
| 47 |
+
table.ForeignKey(
|
| 48 |
+
name: "FK_AppUsers_UserGroups_GroupId",
|
| 49 |
+
column: x => x.GroupId,
|
| 50 |
+
principalTable: "UserGroups",
|
| 51 |
+
principalColumn: "Id",
|
| 52 |
+
onDelete: ReferentialAction.SetNull);
|
| 53 |
+
});
|
| 54 |
+
|
| 55 |
+
migrationBuilder.CreateTable(
|
| 56 |
+
name: "GroupRights",
|
| 57 |
+
columns: table => new
|
| 58 |
+
{
|
| 59 |
+
Id = table.Column<int>(type: "int", nullable: false)
|
| 60 |
+
.Annotation("SqlServer:Identity", "1, 1"),
|
| 61 |
+
UserGroupId = table.Column<int>(type: "int", nullable: false),
|
| 62 |
+
RightKey = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
| 63 |
+
IsGranted = table.Column<bool>(type: "bit", nullable: false)
|
| 64 |
+
},
|
| 65 |
+
constraints: table =>
|
| 66 |
+
{
|
| 67 |
+
table.PrimaryKey("PK_GroupRights", x => x.Id);
|
| 68 |
+
table.ForeignKey(
|
| 69 |
+
name: "FK_GroupRights_UserGroups_UserGroupId",
|
| 70 |
+
column: x => x.UserGroupId,
|
| 71 |
+
principalTable: "UserGroups",
|
| 72 |
+
principalColumn: "Id",
|
| 73 |
+
onDelete: ReferentialAction.Cascade);
|
| 74 |
+
});
|
| 75 |
+
|
| 76 |
+
migrationBuilder.CreateTable(
|
| 77 |
+
name: "UserRights",
|
| 78 |
+
columns: table => new
|
| 79 |
+
{
|
| 80 |
+
Id = table.Column<int>(type: "int", nullable: false)
|
| 81 |
+
.Annotation("SqlServer:Identity", "1, 1"),
|
| 82 |
+
AppUserId = table.Column<int>(type: "int", nullable: false),
|
| 83 |
+
RightKey = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
| 84 |
+
IsGranted = table.Column<bool>(type: "bit", nullable: false)
|
| 85 |
+
},
|
| 86 |
+
constraints: table =>
|
| 87 |
+
{
|
| 88 |
+
table.PrimaryKey("PK_UserRights", x => x.Id);
|
| 89 |
+
table.ForeignKey(
|
| 90 |
+
name: "FK_UserRights_AppUsers_AppUserId",
|
| 91 |
+
column: x => x.AppUserId,
|
| 92 |
+
principalTable: "AppUsers",
|
| 93 |
+
principalColumn: "Id",
|
| 94 |
+
onDelete: ReferentialAction.Cascade);
|
| 95 |
+
});
|
| 96 |
+
|
| 97 |
+
migrationBuilder.CreateIndex(
|
| 98 |
+
name: "IX_AppUsers_GroupId",
|
| 99 |
+
table: "AppUsers",
|
| 100 |
+
column: "GroupId");
|
| 101 |
+
|
| 102 |
+
migrationBuilder.CreateIndex(
|
| 103 |
+
name: "IX_AppUsers_UserName",
|
| 104 |
+
table: "AppUsers",
|
| 105 |
+
column: "UserName",
|
| 106 |
+
unique: true);
|
| 107 |
+
|
| 108 |
+
migrationBuilder.CreateIndex(
|
| 109 |
+
name: "IX_GroupRights_UserGroupId_RightKey",
|
| 110 |
+
table: "GroupRights",
|
| 111 |
+
columns: new[] { "UserGroupId", "RightKey" },
|
| 112 |
+
unique: true);
|
| 113 |
+
|
| 114 |
+
migrationBuilder.CreateIndex(
|
| 115 |
+
name: "IX_UserGroups_Name",
|
| 116 |
+
table: "UserGroups",
|
| 117 |
+
column: "Name",
|
| 118 |
+
unique: true);
|
| 119 |
+
|
| 120 |
+
migrationBuilder.CreateIndex(
|
| 121 |
+
name: "IX_UserRights_AppUserId_RightKey",
|
| 122 |
+
table: "UserRights",
|
| 123 |
+
columns: new[] { "AppUserId", "RightKey" },
|
| 124 |
+
unique: true);
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
/// <inheritdoc />
|
| 128 |
+
protected override void Down(MigrationBuilder migrationBuilder)
|
| 129 |
+
{
|
| 130 |
+
migrationBuilder.DropTable(
|
| 131 |
+
name: "UserRights");
|
| 132 |
+
|
| 133 |
+
migrationBuilder.DropTable(
|
| 134 |
+
name: "GroupRights");
|
| 135 |
+
|
| 136 |
+
migrationBuilder.DropTable(
|
| 137 |
+
name: "AppUsers");
|
| 138 |
+
|
| 139 |
+
migrationBuilder.DropTable(
|
| 140 |
+
name: "UserGroups");
|
| 141 |
+
}
|
| 142 |
+
}
|
| 143 |
+
}
|
ContactManagementAPI/Migrations/20260216070933_AddNewContactGroups.Designer.cs
ADDED
|
@@ -0,0 +1,478 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// <auto-generated />
|
| 2 |
+
using System;
|
| 3 |
+
using ContactManagementAPI.Data;
|
| 4 |
+
using Microsoft.EntityFrameworkCore;
|
| 5 |
+
using Microsoft.EntityFrameworkCore.Infrastructure;
|
| 6 |
+
using Microsoft.EntityFrameworkCore.Metadata;
|
| 7 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 8 |
+
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
| 9 |
+
|
| 10 |
+
#nullable disable
|
| 11 |
+
|
| 12 |
+
namespace ContactManagementAPI.Migrations
|
| 13 |
+
{
|
| 14 |
+
[DbContext(typeof(ApplicationDbContext))]
|
| 15 |
+
[Migration("20260216070933_AddNewContactGroups")]
|
| 16 |
+
partial class AddNewContactGroups
|
| 17 |
+
{
|
| 18 |
+
/// <inheritdoc />
|
| 19 |
+
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
| 20 |
+
{
|
| 21 |
+
#pragma warning disable 612, 618
|
| 22 |
+
modelBuilder
|
| 23 |
+
.HasAnnotation("ProductVersion", "8.0.0")
|
| 24 |
+
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
| 25 |
+
|
| 26 |
+
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
| 27 |
+
|
| 28 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 29 |
+
{
|
| 30 |
+
b.Property<int>("Id")
|
| 31 |
+
.ValueGeneratedOnAdd()
|
| 32 |
+
.HasColumnType("int");
|
| 33 |
+
|
| 34 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 35 |
+
|
| 36 |
+
b.Property<DateTime>("CreatedAt")
|
| 37 |
+
.HasColumnType("datetime2");
|
| 38 |
+
|
| 39 |
+
b.Property<string>("FullName")
|
| 40 |
+
.HasMaxLength(200)
|
| 41 |
+
.HasColumnType("nvarchar(200)");
|
| 42 |
+
|
| 43 |
+
b.Property<int>("GroupId")
|
| 44 |
+
.HasColumnType("int");
|
| 45 |
+
|
| 46 |
+
b.Property<bool>("IsActive")
|
| 47 |
+
.HasColumnType("bit");
|
| 48 |
+
|
| 49 |
+
b.Property<bool>("IsAdmin")
|
| 50 |
+
.HasColumnType("bit");
|
| 51 |
+
|
| 52 |
+
b.Property<string>("PasswordHash")
|
| 53 |
+
.IsRequired()
|
| 54 |
+
.HasColumnType("nvarchar(max)");
|
| 55 |
+
|
| 56 |
+
b.Property<DateTime>("UpdatedAt")
|
| 57 |
+
.HasColumnType("datetime2");
|
| 58 |
+
|
| 59 |
+
b.Property<string>("UserName")
|
| 60 |
+
.IsRequired()
|
| 61 |
+
.HasMaxLength(100)
|
| 62 |
+
.HasColumnType("nvarchar(100)");
|
| 63 |
+
|
| 64 |
+
b.HasKey("Id");
|
| 65 |
+
|
| 66 |
+
b.HasIndex("GroupId");
|
| 67 |
+
|
| 68 |
+
b.HasIndex("UserName")
|
| 69 |
+
.IsUnique();
|
| 70 |
+
|
| 71 |
+
b.ToTable("AppUsers");
|
| 72 |
+
});
|
| 73 |
+
|
| 74 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 75 |
+
{
|
| 76 |
+
b.Property<int>("Id")
|
| 77 |
+
.ValueGeneratedOnAdd()
|
| 78 |
+
.HasColumnType("int");
|
| 79 |
+
|
| 80 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 81 |
+
|
| 82 |
+
b.Property<string>("Address")
|
| 83 |
+
.HasColumnType("nvarchar(max)");
|
| 84 |
+
|
| 85 |
+
b.Property<string>("City")
|
| 86 |
+
.HasColumnType("nvarchar(max)");
|
| 87 |
+
|
| 88 |
+
b.Property<string>("Country")
|
| 89 |
+
.HasColumnType("nvarchar(max)");
|
| 90 |
+
|
| 91 |
+
b.Property<DateTime>("CreatedAt")
|
| 92 |
+
.HasColumnType("datetime2");
|
| 93 |
+
|
| 94 |
+
b.Property<string>("Email")
|
| 95 |
+
.HasColumnType("nvarchar(max)");
|
| 96 |
+
|
| 97 |
+
b.Property<string>("FirstName")
|
| 98 |
+
.IsRequired()
|
| 99 |
+
.HasColumnType("nvarchar(max)");
|
| 100 |
+
|
| 101 |
+
b.Property<int?>("GroupId")
|
| 102 |
+
.HasColumnType("int");
|
| 103 |
+
|
| 104 |
+
b.Property<string>("LastName")
|
| 105 |
+
.HasColumnType("nvarchar(max)");
|
| 106 |
+
|
| 107 |
+
b.Property<string>("Mobile1")
|
| 108 |
+
.HasColumnType("nvarchar(max)");
|
| 109 |
+
|
| 110 |
+
b.Property<string>("Mobile2")
|
| 111 |
+
.HasColumnType("nvarchar(max)");
|
| 112 |
+
|
| 113 |
+
b.Property<string>("Mobile3")
|
| 114 |
+
.HasColumnType("nvarchar(max)");
|
| 115 |
+
|
| 116 |
+
b.Property<string>("NickName")
|
| 117 |
+
.HasColumnType("nvarchar(max)");
|
| 118 |
+
|
| 119 |
+
b.Property<string>("OtherDetails")
|
| 120 |
+
.HasColumnType("nvarchar(max)");
|
| 121 |
+
|
| 122 |
+
b.Property<string>("PhotoPath")
|
| 123 |
+
.HasColumnType("nvarchar(max)");
|
| 124 |
+
|
| 125 |
+
b.Property<string>("PostalCode")
|
| 126 |
+
.HasColumnType("nvarchar(max)");
|
| 127 |
+
|
| 128 |
+
b.Property<string>("State")
|
| 129 |
+
.HasColumnType("nvarchar(max)");
|
| 130 |
+
|
| 131 |
+
b.Property<DateTime>("UpdatedAt")
|
| 132 |
+
.HasColumnType("datetime2");
|
| 133 |
+
|
| 134 |
+
b.Property<string>("WhatsAppNumber")
|
| 135 |
+
.HasColumnType("nvarchar(max)");
|
| 136 |
+
|
| 137 |
+
b.HasKey("Id");
|
| 138 |
+
|
| 139 |
+
b.HasIndex("GroupId");
|
| 140 |
+
|
| 141 |
+
b.ToTable("Contacts");
|
| 142 |
+
});
|
| 143 |
+
|
| 144 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 145 |
+
{
|
| 146 |
+
b.Property<int>("Id")
|
| 147 |
+
.ValueGeneratedOnAdd()
|
| 148 |
+
.HasColumnType("int");
|
| 149 |
+
|
| 150 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 151 |
+
|
| 152 |
+
b.Property<int>("ContactId")
|
| 153 |
+
.HasColumnType("int");
|
| 154 |
+
|
| 155 |
+
b.Property<string>("ContentType")
|
| 156 |
+
.IsRequired()
|
| 157 |
+
.HasColumnType("nvarchar(max)");
|
| 158 |
+
|
| 159 |
+
b.Property<string>("DocumentPath")
|
| 160 |
+
.IsRequired()
|
| 161 |
+
.HasColumnType("nvarchar(max)");
|
| 162 |
+
|
| 163 |
+
b.Property<string>("DocumentType")
|
| 164 |
+
.IsRequired()
|
| 165 |
+
.HasColumnType("nvarchar(max)");
|
| 166 |
+
|
| 167 |
+
b.Property<string>("FileName")
|
| 168 |
+
.IsRequired()
|
| 169 |
+
.HasColumnType("nvarchar(max)");
|
| 170 |
+
|
| 171 |
+
b.Property<long>("FileSize")
|
| 172 |
+
.HasColumnType("bigint");
|
| 173 |
+
|
| 174 |
+
b.Property<DateTime>("UploadedAt")
|
| 175 |
+
.HasColumnType("datetime2");
|
| 176 |
+
|
| 177 |
+
b.HasKey("Id");
|
| 178 |
+
|
| 179 |
+
b.HasIndex("ContactId");
|
| 180 |
+
|
| 181 |
+
b.ToTable("ContactDocuments");
|
| 182 |
+
});
|
| 183 |
+
|
| 184 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 185 |
+
{
|
| 186 |
+
b.Property<int>("Id")
|
| 187 |
+
.ValueGeneratedOnAdd()
|
| 188 |
+
.HasColumnType("int");
|
| 189 |
+
|
| 190 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 191 |
+
|
| 192 |
+
b.Property<DateTime>("CreatedAt")
|
| 193 |
+
.HasColumnType("datetime2");
|
| 194 |
+
|
| 195 |
+
b.Property<string>("Description")
|
| 196 |
+
.IsRequired()
|
| 197 |
+
.HasColumnType("nvarchar(max)");
|
| 198 |
+
|
| 199 |
+
b.Property<string>("Name")
|
| 200 |
+
.IsRequired()
|
| 201 |
+
.HasColumnType("nvarchar(max)");
|
| 202 |
+
|
| 203 |
+
b.HasKey("Id");
|
| 204 |
+
|
| 205 |
+
b.ToTable("ContactGroups");
|
| 206 |
+
|
| 207 |
+
b.HasData(
|
| 208 |
+
new
|
| 209 |
+
{
|
| 210 |
+
Id = 1,
|
| 211 |
+
CreatedAt = new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7842),
|
| 212 |
+
Description = "Family members",
|
| 213 |
+
Name = "Family"
|
| 214 |
+
},
|
| 215 |
+
new
|
| 216 |
+
{
|
| 217 |
+
Id = 2,
|
| 218 |
+
CreatedAt = new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7855),
|
| 219 |
+
Description = "Friends",
|
| 220 |
+
Name = "Friends"
|
| 221 |
+
},
|
| 222 |
+
new
|
| 223 |
+
{
|
| 224 |
+
Id = 3,
|
| 225 |
+
CreatedAt = new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7857),
|
| 226 |
+
Description = "Business contacts",
|
| 227 |
+
Name = "Business"
|
| 228 |
+
},
|
| 229 |
+
new
|
| 230 |
+
{
|
| 231 |
+
Id = 4,
|
| 232 |
+
CreatedAt = new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7858),
|
| 233 |
+
Description = "School contacts",
|
| 234 |
+
Name = "School"
|
| 235 |
+
},
|
| 236 |
+
new
|
| 237 |
+
{
|
| 238 |
+
Id = 5,
|
| 239 |
+
CreatedAt = new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7860),
|
| 240 |
+
Description = "Church members",
|
| 241 |
+
Name = "Church"
|
| 242 |
+
},
|
| 243 |
+
new
|
| 244 |
+
{
|
| 245 |
+
Id = 6,
|
| 246 |
+
CreatedAt = new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7862),
|
| 247 |
+
Description = "Other contacts",
|
| 248 |
+
Name = "Others"
|
| 249 |
+
},
|
| 250 |
+
new
|
| 251 |
+
{
|
| 252 |
+
Id = 7,
|
| 253 |
+
CreatedAt = new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7863),
|
| 254 |
+
Description = "College contacts",
|
| 255 |
+
Name = "College"
|
| 256 |
+
},
|
| 257 |
+
new
|
| 258 |
+
{
|
| 259 |
+
Id = 8,
|
| 260 |
+
CreatedAt = new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7864),
|
| 261 |
+
Description = "Alcoholics Anonymous",
|
| 262 |
+
Name = "AA"
|
| 263 |
+
});
|
| 264 |
+
});
|
| 265 |
+
|
| 266 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 267 |
+
{
|
| 268 |
+
b.Property<int>("Id")
|
| 269 |
+
.ValueGeneratedOnAdd()
|
| 270 |
+
.HasColumnType("int");
|
| 271 |
+
|
| 272 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 273 |
+
|
| 274 |
+
b.Property<int>("ContactId")
|
| 275 |
+
.HasColumnType("int");
|
| 276 |
+
|
| 277 |
+
b.Property<string>("ContentType")
|
| 278 |
+
.IsRequired()
|
| 279 |
+
.HasColumnType("nvarchar(max)");
|
| 280 |
+
|
| 281 |
+
b.Property<string>("FileName")
|
| 282 |
+
.IsRequired()
|
| 283 |
+
.HasColumnType("nvarchar(max)");
|
| 284 |
+
|
| 285 |
+
b.Property<long>("FileSize")
|
| 286 |
+
.HasColumnType("bigint");
|
| 287 |
+
|
| 288 |
+
b.Property<bool>("IsProfilePhoto")
|
| 289 |
+
.HasColumnType("bit");
|
| 290 |
+
|
| 291 |
+
b.Property<string>("PhotoPath")
|
| 292 |
+
.IsRequired()
|
| 293 |
+
.HasColumnType("nvarchar(max)");
|
| 294 |
+
|
| 295 |
+
b.Property<DateTime>("UploadedAt")
|
| 296 |
+
.HasColumnType("datetime2");
|
| 297 |
+
|
| 298 |
+
b.HasKey("Id");
|
| 299 |
+
|
| 300 |
+
b.HasIndex("ContactId");
|
| 301 |
+
|
| 302 |
+
b.ToTable("ContactPhotos");
|
| 303 |
+
});
|
| 304 |
+
|
| 305 |
+
modelBuilder.Entity("ContactManagementAPI.Models.GroupRight", b =>
|
| 306 |
+
{
|
| 307 |
+
b.Property<int>("Id")
|
| 308 |
+
.ValueGeneratedOnAdd()
|
| 309 |
+
.HasColumnType("int");
|
| 310 |
+
|
| 311 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 312 |
+
|
| 313 |
+
b.Property<bool>("IsGranted")
|
| 314 |
+
.HasColumnType("bit");
|
| 315 |
+
|
| 316 |
+
b.Property<string>("RightKey")
|
| 317 |
+
.IsRequired()
|
| 318 |
+
.HasMaxLength(100)
|
| 319 |
+
.HasColumnType("nvarchar(100)");
|
| 320 |
+
|
| 321 |
+
b.Property<int>("UserGroupId")
|
| 322 |
+
.HasColumnType("int");
|
| 323 |
+
|
| 324 |
+
b.HasKey("Id");
|
| 325 |
+
|
| 326 |
+
b.HasIndex("UserGroupId", "RightKey")
|
| 327 |
+
.IsUnique();
|
| 328 |
+
|
| 329 |
+
b.ToTable("GroupRights");
|
| 330 |
+
});
|
| 331 |
+
|
| 332 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserGroup", b =>
|
| 333 |
+
{
|
| 334 |
+
b.Property<int>("Id")
|
| 335 |
+
.ValueGeneratedOnAdd()
|
| 336 |
+
.HasColumnType("int");
|
| 337 |
+
|
| 338 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 339 |
+
|
| 340 |
+
b.Property<DateTime>("CreatedAt")
|
| 341 |
+
.HasColumnType("datetime2");
|
| 342 |
+
|
| 343 |
+
b.Property<string>("Description")
|
| 344 |
+
.HasMaxLength(500)
|
| 345 |
+
.HasColumnType("nvarchar(500)");
|
| 346 |
+
|
| 347 |
+
b.Property<string>("Name")
|
| 348 |
+
.IsRequired()
|
| 349 |
+
.HasMaxLength(150)
|
| 350 |
+
.HasColumnType("nvarchar(150)");
|
| 351 |
+
|
| 352 |
+
b.HasKey("Id");
|
| 353 |
+
|
| 354 |
+
b.HasIndex("Name")
|
| 355 |
+
.IsUnique();
|
| 356 |
+
|
| 357 |
+
b.ToTable("UserGroups");
|
| 358 |
+
});
|
| 359 |
+
|
| 360 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserRight", b =>
|
| 361 |
+
{
|
| 362 |
+
b.Property<int>("Id")
|
| 363 |
+
.ValueGeneratedOnAdd()
|
| 364 |
+
.HasColumnType("int");
|
| 365 |
+
|
| 366 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 367 |
+
|
| 368 |
+
b.Property<int>("AppUserId")
|
| 369 |
+
.HasColumnType("int");
|
| 370 |
+
|
| 371 |
+
b.Property<bool>("IsGranted")
|
| 372 |
+
.HasColumnType("bit");
|
| 373 |
+
|
| 374 |
+
b.Property<string>("RightKey")
|
| 375 |
+
.IsRequired()
|
| 376 |
+
.HasMaxLength(100)
|
| 377 |
+
.HasColumnType("nvarchar(100)");
|
| 378 |
+
|
| 379 |
+
b.HasKey("Id");
|
| 380 |
+
|
| 381 |
+
b.HasIndex("AppUserId", "RightKey")
|
| 382 |
+
.IsUnique();
|
| 383 |
+
|
| 384 |
+
b.ToTable("UserRights");
|
| 385 |
+
});
|
| 386 |
+
|
| 387 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 388 |
+
{
|
| 389 |
+
b.HasOne("ContactManagementAPI.Models.UserGroup", "Group")
|
| 390 |
+
.WithMany("Users")
|
| 391 |
+
.HasForeignKey("GroupId")
|
| 392 |
+
.OnDelete(DeleteBehavior.SetNull)
|
| 393 |
+
.IsRequired();
|
| 394 |
+
|
| 395 |
+
b.Navigation("Group");
|
| 396 |
+
});
|
| 397 |
+
|
| 398 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 399 |
+
{
|
| 400 |
+
b.HasOne("ContactManagementAPI.Models.ContactGroup", "Group")
|
| 401 |
+
.WithMany("Contacts")
|
| 402 |
+
.HasForeignKey("GroupId")
|
| 403 |
+
.OnDelete(DeleteBehavior.SetNull);
|
| 404 |
+
|
| 405 |
+
b.Navigation("Group");
|
| 406 |
+
});
|
| 407 |
+
|
| 408 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 409 |
+
{
|
| 410 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 411 |
+
.WithMany("Documents")
|
| 412 |
+
.HasForeignKey("ContactId")
|
| 413 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 414 |
+
.IsRequired();
|
| 415 |
+
|
| 416 |
+
b.Navigation("Contact");
|
| 417 |
+
});
|
| 418 |
+
|
| 419 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 420 |
+
{
|
| 421 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 422 |
+
.WithMany("Photos")
|
| 423 |
+
.HasForeignKey("ContactId")
|
| 424 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 425 |
+
.IsRequired();
|
| 426 |
+
|
| 427 |
+
b.Navigation("Contact");
|
| 428 |
+
});
|
| 429 |
+
|
| 430 |
+
modelBuilder.Entity("ContactManagementAPI.Models.GroupRight", b =>
|
| 431 |
+
{
|
| 432 |
+
b.HasOne("ContactManagementAPI.Models.UserGroup", "UserGroup")
|
| 433 |
+
.WithMany("GroupRights")
|
| 434 |
+
.HasForeignKey("UserGroupId")
|
| 435 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 436 |
+
.IsRequired();
|
| 437 |
+
|
| 438 |
+
b.Navigation("UserGroup");
|
| 439 |
+
});
|
| 440 |
+
|
| 441 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserRight", b =>
|
| 442 |
+
{
|
| 443 |
+
b.HasOne("ContactManagementAPI.Models.AppUser", "AppUser")
|
| 444 |
+
.WithMany("UserRights")
|
| 445 |
+
.HasForeignKey("AppUserId")
|
| 446 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 447 |
+
.IsRequired();
|
| 448 |
+
|
| 449 |
+
b.Navigation("AppUser");
|
| 450 |
+
});
|
| 451 |
+
|
| 452 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 453 |
+
{
|
| 454 |
+
b.Navigation("UserRights");
|
| 455 |
+
});
|
| 456 |
+
|
| 457 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 458 |
+
{
|
| 459 |
+
b.Navigation("Documents");
|
| 460 |
+
|
| 461 |
+
b.Navigation("Photos");
|
| 462 |
+
});
|
| 463 |
+
|
| 464 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 465 |
+
{
|
| 466 |
+
b.Navigation("Contacts");
|
| 467 |
+
});
|
| 468 |
+
|
| 469 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserGroup", b =>
|
| 470 |
+
{
|
| 471 |
+
b.Navigation("GroupRights");
|
| 472 |
+
|
| 473 |
+
b.Navigation("Users");
|
| 474 |
+
});
|
| 475 |
+
#pragma warning restore 612, 618
|
| 476 |
+
}
|
| 477 |
+
}
|
| 478 |
+
}
|
ContactManagementAPI/Migrations/20260216070933_AddNewContactGroups.cs
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 3 |
+
|
| 4 |
+
#nullable disable
|
| 5 |
+
|
| 6 |
+
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
| 7 |
+
|
| 8 |
+
namespace ContactManagementAPI.Migrations
|
| 9 |
+
{
|
| 10 |
+
/// <inheritdoc />
|
| 11 |
+
public partial class AddNewContactGroups : Migration
|
| 12 |
+
{
|
| 13 |
+
/// <inheritdoc />
|
| 14 |
+
protected override void Up(MigrationBuilder migrationBuilder)
|
| 15 |
+
{
|
| 16 |
+
migrationBuilder.AlterColumn<int>(
|
| 17 |
+
name: "GroupId",
|
| 18 |
+
table: "AppUsers",
|
| 19 |
+
type: "int",
|
| 20 |
+
nullable: false,
|
| 21 |
+
defaultValue: 0,
|
| 22 |
+
oldClrType: typeof(int),
|
| 23 |
+
oldType: "int",
|
| 24 |
+
oldNullable: true);
|
| 25 |
+
|
| 26 |
+
migrationBuilder.UpdateData(
|
| 27 |
+
table: "ContactGroups",
|
| 28 |
+
keyColumn: "Id",
|
| 29 |
+
keyValue: 1,
|
| 30 |
+
column: "CreatedAt",
|
| 31 |
+
value: new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7842));
|
| 32 |
+
|
| 33 |
+
migrationBuilder.UpdateData(
|
| 34 |
+
table: "ContactGroups",
|
| 35 |
+
keyColumn: "Id",
|
| 36 |
+
keyValue: 2,
|
| 37 |
+
column: "CreatedAt",
|
| 38 |
+
value: new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7855));
|
| 39 |
+
|
| 40 |
+
migrationBuilder.UpdateData(
|
| 41 |
+
table: "ContactGroups",
|
| 42 |
+
keyColumn: "Id",
|
| 43 |
+
keyValue: 3,
|
| 44 |
+
column: "CreatedAt",
|
| 45 |
+
value: new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7857));
|
| 46 |
+
|
| 47 |
+
migrationBuilder.UpdateData(
|
| 48 |
+
table: "ContactGroups",
|
| 49 |
+
keyColumn: "Id",
|
| 50 |
+
keyValue: 4,
|
| 51 |
+
column: "CreatedAt",
|
| 52 |
+
value: new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7858));
|
| 53 |
+
|
| 54 |
+
migrationBuilder.UpdateData(
|
| 55 |
+
table: "ContactGroups",
|
| 56 |
+
keyColumn: "Id",
|
| 57 |
+
keyValue: 5,
|
| 58 |
+
column: "CreatedAt",
|
| 59 |
+
value: new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7860));
|
| 60 |
+
|
| 61 |
+
migrationBuilder.UpdateData(
|
| 62 |
+
table: "ContactGroups",
|
| 63 |
+
keyColumn: "Id",
|
| 64 |
+
keyValue: 6,
|
| 65 |
+
column: "CreatedAt",
|
| 66 |
+
value: new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7862));
|
| 67 |
+
|
| 68 |
+
migrationBuilder.InsertData(
|
| 69 |
+
table: "ContactGroups",
|
| 70 |
+
columns: new[] { "Id", "CreatedAt", "Description", "Name" },
|
| 71 |
+
values: new object[,]
|
| 72 |
+
{
|
| 73 |
+
{ 7, new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7863), "College contacts", "College" },
|
| 74 |
+
{ 8, new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7864), "Alcoholics Anonymous", "AA" }
|
| 75 |
+
});
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
/// <inheritdoc />
|
| 79 |
+
protected override void Down(MigrationBuilder migrationBuilder)
|
| 80 |
+
{
|
| 81 |
+
migrationBuilder.DeleteData(
|
| 82 |
+
table: "ContactGroups",
|
| 83 |
+
keyColumn: "Id",
|
| 84 |
+
keyValue: 7);
|
| 85 |
+
|
| 86 |
+
migrationBuilder.DeleteData(
|
| 87 |
+
table: "ContactGroups",
|
| 88 |
+
keyColumn: "Id",
|
| 89 |
+
keyValue: 8);
|
| 90 |
+
|
| 91 |
+
migrationBuilder.AlterColumn<int>(
|
| 92 |
+
name: "GroupId",
|
| 93 |
+
table: "AppUsers",
|
| 94 |
+
type: "int",
|
| 95 |
+
nullable: true,
|
| 96 |
+
oldClrType: typeof(int),
|
| 97 |
+
oldType: "int");
|
| 98 |
+
|
| 99 |
+
migrationBuilder.UpdateData(
|
| 100 |
+
table: "ContactGroups",
|
| 101 |
+
keyColumn: "Id",
|
| 102 |
+
keyValue: 1,
|
| 103 |
+
column: "CreatedAt",
|
| 104 |
+
value: new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8518));
|
| 105 |
+
|
| 106 |
+
migrationBuilder.UpdateData(
|
| 107 |
+
table: "ContactGroups",
|
| 108 |
+
keyColumn: "Id",
|
| 109 |
+
keyValue: 2,
|
| 110 |
+
column: "CreatedAt",
|
| 111 |
+
value: new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8531));
|
| 112 |
+
|
| 113 |
+
migrationBuilder.UpdateData(
|
| 114 |
+
table: "ContactGroups",
|
| 115 |
+
keyColumn: "Id",
|
| 116 |
+
keyValue: 3,
|
| 117 |
+
column: "CreatedAt",
|
| 118 |
+
value: new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8533));
|
| 119 |
+
|
| 120 |
+
migrationBuilder.UpdateData(
|
| 121 |
+
table: "ContactGroups",
|
| 122 |
+
keyColumn: "Id",
|
| 123 |
+
keyValue: 4,
|
| 124 |
+
column: "CreatedAt",
|
| 125 |
+
value: new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8535));
|
| 126 |
+
|
| 127 |
+
migrationBuilder.UpdateData(
|
| 128 |
+
table: "ContactGroups",
|
| 129 |
+
keyColumn: "Id",
|
| 130 |
+
keyValue: 5,
|
| 131 |
+
column: "CreatedAt",
|
| 132 |
+
value: new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8537));
|
| 133 |
+
|
| 134 |
+
migrationBuilder.UpdateData(
|
| 135 |
+
table: "ContactGroups",
|
| 136 |
+
keyColumn: "Id",
|
| 137 |
+
keyValue: 6,
|
| 138 |
+
column: "CreatedAt",
|
| 139 |
+
value: new DateTime(2026, 2, 9, 10, 57, 18, 734, DateTimeKind.Local).AddTicks(8538));
|
| 140 |
+
}
|
| 141 |
+
}
|
| 142 |
+
}
|
ContactManagementAPI/Migrations/20260220171502_AddContactIdentityBankGenderDobFields.Designer.cs
ADDED
|
@@ -0,0 +1,508 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// <auto-generated />
|
| 2 |
+
using System;
|
| 3 |
+
using ContactManagementAPI.Data;
|
| 4 |
+
using Microsoft.EntityFrameworkCore;
|
| 5 |
+
using Microsoft.EntityFrameworkCore.Infrastructure;
|
| 6 |
+
using Microsoft.EntityFrameworkCore.Metadata;
|
| 7 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 8 |
+
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
| 9 |
+
|
| 10 |
+
#nullable disable
|
| 11 |
+
|
| 12 |
+
namespace ContactManagementAPI.Migrations
|
| 13 |
+
{
|
| 14 |
+
[DbContext(typeof(ApplicationDbContext))]
|
| 15 |
+
[Migration("20260220171502_AddContactIdentityBankGenderDobFields")]
|
| 16 |
+
partial class AddContactIdentityBankGenderDobFields
|
| 17 |
+
{
|
| 18 |
+
/// <inheritdoc />
|
| 19 |
+
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
| 20 |
+
{
|
| 21 |
+
#pragma warning disable 612, 618
|
| 22 |
+
modelBuilder
|
| 23 |
+
.HasAnnotation("ProductVersion", "8.0.0")
|
| 24 |
+
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
| 25 |
+
|
| 26 |
+
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
| 27 |
+
|
| 28 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 29 |
+
{
|
| 30 |
+
b.Property<int>("Id")
|
| 31 |
+
.ValueGeneratedOnAdd()
|
| 32 |
+
.HasColumnType("int");
|
| 33 |
+
|
| 34 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 35 |
+
|
| 36 |
+
b.Property<DateTime>("CreatedAt")
|
| 37 |
+
.HasColumnType("datetime2");
|
| 38 |
+
|
| 39 |
+
b.Property<string>("FullName")
|
| 40 |
+
.HasMaxLength(200)
|
| 41 |
+
.HasColumnType("nvarchar(200)");
|
| 42 |
+
|
| 43 |
+
b.Property<int>("GroupId")
|
| 44 |
+
.HasColumnType("int");
|
| 45 |
+
|
| 46 |
+
b.Property<bool>("IsActive")
|
| 47 |
+
.HasColumnType("bit");
|
| 48 |
+
|
| 49 |
+
b.Property<bool>("IsAdmin")
|
| 50 |
+
.HasColumnType("bit");
|
| 51 |
+
|
| 52 |
+
b.Property<string>("PasswordHash")
|
| 53 |
+
.IsRequired()
|
| 54 |
+
.HasColumnType("nvarchar(max)");
|
| 55 |
+
|
| 56 |
+
b.Property<DateTime>("UpdatedAt")
|
| 57 |
+
.HasColumnType("datetime2");
|
| 58 |
+
|
| 59 |
+
b.Property<string>("UserName")
|
| 60 |
+
.IsRequired()
|
| 61 |
+
.HasMaxLength(100)
|
| 62 |
+
.HasColumnType("nvarchar(100)");
|
| 63 |
+
|
| 64 |
+
b.HasKey("Id");
|
| 65 |
+
|
| 66 |
+
b.HasIndex("GroupId");
|
| 67 |
+
|
| 68 |
+
b.HasIndex("UserName")
|
| 69 |
+
.IsUnique();
|
| 70 |
+
|
| 71 |
+
b.ToTable("AppUsers");
|
| 72 |
+
});
|
| 73 |
+
|
| 74 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 75 |
+
{
|
| 76 |
+
b.Property<int>("Id")
|
| 77 |
+
.ValueGeneratedOnAdd()
|
| 78 |
+
.HasColumnType("int");
|
| 79 |
+
|
| 80 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 81 |
+
|
| 82 |
+
b.Property<string>("AadharNumber")
|
| 83 |
+
.HasColumnType("nvarchar(max)");
|
| 84 |
+
|
| 85 |
+
b.Property<string>("Address")
|
| 86 |
+
.HasColumnType("nvarchar(max)");
|
| 87 |
+
|
| 88 |
+
b.Property<string>("BankAccountNumber")
|
| 89 |
+
.HasColumnType("nvarchar(max)");
|
| 90 |
+
|
| 91 |
+
b.Property<string>("BankName")
|
| 92 |
+
.HasColumnType("nvarchar(max)");
|
| 93 |
+
|
| 94 |
+
b.Property<string>("BranchName")
|
| 95 |
+
.HasColumnType("nvarchar(max)");
|
| 96 |
+
|
| 97 |
+
b.Property<string>("City")
|
| 98 |
+
.HasColumnType("nvarchar(max)");
|
| 99 |
+
|
| 100 |
+
b.Property<string>("Country")
|
| 101 |
+
.HasColumnType("nvarchar(max)");
|
| 102 |
+
|
| 103 |
+
b.Property<DateTime>("CreatedAt")
|
| 104 |
+
.HasColumnType("datetime2");
|
| 105 |
+
|
| 106 |
+
b.Property<DateTime?>("DateOfBirth")
|
| 107 |
+
.HasColumnType("datetime2");
|
| 108 |
+
|
| 109 |
+
b.Property<string>("DrivingLicenseNumber")
|
| 110 |
+
.HasColumnType("nvarchar(max)");
|
| 111 |
+
|
| 112 |
+
b.Property<string>("Email")
|
| 113 |
+
.HasColumnType("nvarchar(max)");
|
| 114 |
+
|
| 115 |
+
b.Property<string>("FirstName")
|
| 116 |
+
.IsRequired()
|
| 117 |
+
.HasColumnType("nvarchar(max)");
|
| 118 |
+
|
| 119 |
+
b.Property<string>("Gender")
|
| 120 |
+
.HasColumnType("nvarchar(max)");
|
| 121 |
+
|
| 122 |
+
b.Property<int?>("GroupId")
|
| 123 |
+
.HasColumnType("int");
|
| 124 |
+
|
| 125 |
+
b.Property<string>("IfscCode")
|
| 126 |
+
.HasColumnType("nvarchar(max)");
|
| 127 |
+
|
| 128 |
+
b.Property<string>("LastName")
|
| 129 |
+
.HasColumnType("nvarchar(max)");
|
| 130 |
+
|
| 131 |
+
b.Property<string>("Mobile1")
|
| 132 |
+
.HasColumnType("nvarchar(max)");
|
| 133 |
+
|
| 134 |
+
b.Property<string>("Mobile2")
|
| 135 |
+
.HasColumnType("nvarchar(max)");
|
| 136 |
+
|
| 137 |
+
b.Property<string>("Mobile3")
|
| 138 |
+
.HasColumnType("nvarchar(max)");
|
| 139 |
+
|
| 140 |
+
b.Property<string>("NickName")
|
| 141 |
+
.HasColumnType("nvarchar(max)");
|
| 142 |
+
|
| 143 |
+
b.Property<string>("OtherDetails")
|
| 144 |
+
.HasColumnType("nvarchar(max)");
|
| 145 |
+
|
| 146 |
+
b.Property<string>("PassportNumber")
|
| 147 |
+
.HasColumnType("nvarchar(max)");
|
| 148 |
+
|
| 149 |
+
b.Property<string>("PhotoPath")
|
| 150 |
+
.HasColumnType("nvarchar(max)");
|
| 151 |
+
|
| 152 |
+
b.Property<string>("PostalCode")
|
| 153 |
+
.HasColumnType("nvarchar(max)");
|
| 154 |
+
|
| 155 |
+
b.Property<string>("State")
|
| 156 |
+
.HasColumnType("nvarchar(max)");
|
| 157 |
+
|
| 158 |
+
b.Property<DateTime>("UpdatedAt")
|
| 159 |
+
.HasColumnType("datetime2");
|
| 160 |
+
|
| 161 |
+
b.Property<string>("VotersId")
|
| 162 |
+
.HasColumnType("nvarchar(max)");
|
| 163 |
+
|
| 164 |
+
b.Property<string>("WhatsAppNumber")
|
| 165 |
+
.HasColumnType("nvarchar(max)");
|
| 166 |
+
|
| 167 |
+
b.HasKey("Id");
|
| 168 |
+
|
| 169 |
+
b.HasIndex("GroupId");
|
| 170 |
+
|
| 171 |
+
b.ToTable("Contacts");
|
| 172 |
+
});
|
| 173 |
+
|
| 174 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 175 |
+
{
|
| 176 |
+
b.Property<int>("Id")
|
| 177 |
+
.ValueGeneratedOnAdd()
|
| 178 |
+
.HasColumnType("int");
|
| 179 |
+
|
| 180 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 181 |
+
|
| 182 |
+
b.Property<int>("ContactId")
|
| 183 |
+
.HasColumnType("int");
|
| 184 |
+
|
| 185 |
+
b.Property<string>("ContentType")
|
| 186 |
+
.IsRequired()
|
| 187 |
+
.HasColumnType("nvarchar(max)");
|
| 188 |
+
|
| 189 |
+
b.Property<string>("DocumentPath")
|
| 190 |
+
.IsRequired()
|
| 191 |
+
.HasColumnType("nvarchar(max)");
|
| 192 |
+
|
| 193 |
+
b.Property<string>("DocumentType")
|
| 194 |
+
.IsRequired()
|
| 195 |
+
.HasColumnType("nvarchar(max)");
|
| 196 |
+
|
| 197 |
+
b.Property<string>("FileName")
|
| 198 |
+
.IsRequired()
|
| 199 |
+
.HasColumnType("nvarchar(max)");
|
| 200 |
+
|
| 201 |
+
b.Property<long>("FileSize")
|
| 202 |
+
.HasColumnType("bigint");
|
| 203 |
+
|
| 204 |
+
b.Property<DateTime>("UploadedAt")
|
| 205 |
+
.HasColumnType("datetime2");
|
| 206 |
+
|
| 207 |
+
b.HasKey("Id");
|
| 208 |
+
|
| 209 |
+
b.HasIndex("ContactId");
|
| 210 |
+
|
| 211 |
+
b.ToTable("ContactDocuments");
|
| 212 |
+
});
|
| 213 |
+
|
| 214 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 215 |
+
{
|
| 216 |
+
b.Property<int>("Id")
|
| 217 |
+
.ValueGeneratedOnAdd()
|
| 218 |
+
.HasColumnType("int");
|
| 219 |
+
|
| 220 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 221 |
+
|
| 222 |
+
b.Property<DateTime>("CreatedAt")
|
| 223 |
+
.HasColumnType("datetime2");
|
| 224 |
+
|
| 225 |
+
b.Property<string>("Description")
|
| 226 |
+
.IsRequired()
|
| 227 |
+
.HasColumnType("nvarchar(max)");
|
| 228 |
+
|
| 229 |
+
b.Property<string>("Name")
|
| 230 |
+
.IsRequired()
|
| 231 |
+
.HasColumnType("nvarchar(max)");
|
| 232 |
+
|
| 233 |
+
b.HasKey("Id");
|
| 234 |
+
|
| 235 |
+
b.ToTable("ContactGroups");
|
| 236 |
+
|
| 237 |
+
b.HasData(
|
| 238 |
+
new
|
| 239 |
+
{
|
| 240 |
+
Id = 1,
|
| 241 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5689),
|
| 242 |
+
Description = "Family members",
|
| 243 |
+
Name = "Family"
|
| 244 |
+
},
|
| 245 |
+
new
|
| 246 |
+
{
|
| 247 |
+
Id = 2,
|
| 248 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5716),
|
| 249 |
+
Description = "Friends",
|
| 250 |
+
Name = "Friends"
|
| 251 |
+
},
|
| 252 |
+
new
|
| 253 |
+
{
|
| 254 |
+
Id = 3,
|
| 255 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5720),
|
| 256 |
+
Description = "Business contacts",
|
| 257 |
+
Name = "Business"
|
| 258 |
+
},
|
| 259 |
+
new
|
| 260 |
+
{
|
| 261 |
+
Id = 4,
|
| 262 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5722),
|
| 263 |
+
Description = "School contacts",
|
| 264 |
+
Name = "School"
|
| 265 |
+
},
|
| 266 |
+
new
|
| 267 |
+
{
|
| 268 |
+
Id = 5,
|
| 269 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5723),
|
| 270 |
+
Description = "Church members",
|
| 271 |
+
Name = "Church"
|
| 272 |
+
},
|
| 273 |
+
new
|
| 274 |
+
{
|
| 275 |
+
Id = 6,
|
| 276 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5725),
|
| 277 |
+
Description = "Other contacts",
|
| 278 |
+
Name = "Others"
|
| 279 |
+
},
|
| 280 |
+
new
|
| 281 |
+
{
|
| 282 |
+
Id = 7,
|
| 283 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5727),
|
| 284 |
+
Description = "College contacts",
|
| 285 |
+
Name = "College"
|
| 286 |
+
},
|
| 287 |
+
new
|
| 288 |
+
{
|
| 289 |
+
Id = 8,
|
| 290 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5729),
|
| 291 |
+
Description = "Alcoholics Anonymous",
|
| 292 |
+
Name = "AA"
|
| 293 |
+
});
|
| 294 |
+
});
|
| 295 |
+
|
| 296 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 297 |
+
{
|
| 298 |
+
b.Property<int>("Id")
|
| 299 |
+
.ValueGeneratedOnAdd()
|
| 300 |
+
.HasColumnType("int");
|
| 301 |
+
|
| 302 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 303 |
+
|
| 304 |
+
b.Property<int>("ContactId")
|
| 305 |
+
.HasColumnType("int");
|
| 306 |
+
|
| 307 |
+
b.Property<string>("ContentType")
|
| 308 |
+
.IsRequired()
|
| 309 |
+
.HasColumnType("nvarchar(max)");
|
| 310 |
+
|
| 311 |
+
b.Property<string>("FileName")
|
| 312 |
+
.IsRequired()
|
| 313 |
+
.HasColumnType("nvarchar(max)");
|
| 314 |
+
|
| 315 |
+
b.Property<long>("FileSize")
|
| 316 |
+
.HasColumnType("bigint");
|
| 317 |
+
|
| 318 |
+
b.Property<bool>("IsProfilePhoto")
|
| 319 |
+
.HasColumnType("bit");
|
| 320 |
+
|
| 321 |
+
b.Property<string>("PhotoPath")
|
| 322 |
+
.IsRequired()
|
| 323 |
+
.HasColumnType("nvarchar(max)");
|
| 324 |
+
|
| 325 |
+
b.Property<DateTime>("UploadedAt")
|
| 326 |
+
.HasColumnType("datetime2");
|
| 327 |
+
|
| 328 |
+
b.HasKey("Id");
|
| 329 |
+
|
| 330 |
+
b.HasIndex("ContactId");
|
| 331 |
+
|
| 332 |
+
b.ToTable("ContactPhotos");
|
| 333 |
+
});
|
| 334 |
+
|
| 335 |
+
modelBuilder.Entity("ContactManagementAPI.Models.GroupRight", b =>
|
| 336 |
+
{
|
| 337 |
+
b.Property<int>("Id")
|
| 338 |
+
.ValueGeneratedOnAdd()
|
| 339 |
+
.HasColumnType("int");
|
| 340 |
+
|
| 341 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 342 |
+
|
| 343 |
+
b.Property<bool>("IsGranted")
|
| 344 |
+
.HasColumnType("bit");
|
| 345 |
+
|
| 346 |
+
b.Property<string>("RightKey")
|
| 347 |
+
.IsRequired()
|
| 348 |
+
.HasMaxLength(100)
|
| 349 |
+
.HasColumnType("nvarchar(100)");
|
| 350 |
+
|
| 351 |
+
b.Property<int>("UserGroupId")
|
| 352 |
+
.HasColumnType("int");
|
| 353 |
+
|
| 354 |
+
b.HasKey("Id");
|
| 355 |
+
|
| 356 |
+
b.HasIndex("UserGroupId", "RightKey")
|
| 357 |
+
.IsUnique();
|
| 358 |
+
|
| 359 |
+
b.ToTable("GroupRights");
|
| 360 |
+
});
|
| 361 |
+
|
| 362 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserGroup", b =>
|
| 363 |
+
{
|
| 364 |
+
b.Property<int>("Id")
|
| 365 |
+
.ValueGeneratedOnAdd()
|
| 366 |
+
.HasColumnType("int");
|
| 367 |
+
|
| 368 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 369 |
+
|
| 370 |
+
b.Property<DateTime>("CreatedAt")
|
| 371 |
+
.HasColumnType("datetime2");
|
| 372 |
+
|
| 373 |
+
b.Property<string>("Description")
|
| 374 |
+
.HasMaxLength(500)
|
| 375 |
+
.HasColumnType("nvarchar(500)");
|
| 376 |
+
|
| 377 |
+
b.Property<string>("Name")
|
| 378 |
+
.IsRequired()
|
| 379 |
+
.HasMaxLength(150)
|
| 380 |
+
.HasColumnType("nvarchar(150)");
|
| 381 |
+
|
| 382 |
+
b.HasKey("Id");
|
| 383 |
+
|
| 384 |
+
b.HasIndex("Name")
|
| 385 |
+
.IsUnique();
|
| 386 |
+
|
| 387 |
+
b.ToTable("UserGroups");
|
| 388 |
+
});
|
| 389 |
+
|
| 390 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserRight", b =>
|
| 391 |
+
{
|
| 392 |
+
b.Property<int>("Id")
|
| 393 |
+
.ValueGeneratedOnAdd()
|
| 394 |
+
.HasColumnType("int");
|
| 395 |
+
|
| 396 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 397 |
+
|
| 398 |
+
b.Property<int>("AppUserId")
|
| 399 |
+
.HasColumnType("int");
|
| 400 |
+
|
| 401 |
+
b.Property<bool>("IsGranted")
|
| 402 |
+
.HasColumnType("bit");
|
| 403 |
+
|
| 404 |
+
b.Property<string>("RightKey")
|
| 405 |
+
.IsRequired()
|
| 406 |
+
.HasMaxLength(100)
|
| 407 |
+
.HasColumnType("nvarchar(100)");
|
| 408 |
+
|
| 409 |
+
b.HasKey("Id");
|
| 410 |
+
|
| 411 |
+
b.HasIndex("AppUserId", "RightKey")
|
| 412 |
+
.IsUnique();
|
| 413 |
+
|
| 414 |
+
b.ToTable("UserRights");
|
| 415 |
+
});
|
| 416 |
+
|
| 417 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 418 |
+
{
|
| 419 |
+
b.HasOne("ContactManagementAPI.Models.UserGroup", "Group")
|
| 420 |
+
.WithMany("Users")
|
| 421 |
+
.HasForeignKey("GroupId")
|
| 422 |
+
.OnDelete(DeleteBehavior.SetNull)
|
| 423 |
+
.IsRequired();
|
| 424 |
+
|
| 425 |
+
b.Navigation("Group");
|
| 426 |
+
});
|
| 427 |
+
|
| 428 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 429 |
+
{
|
| 430 |
+
b.HasOne("ContactManagementAPI.Models.ContactGroup", "Group")
|
| 431 |
+
.WithMany("Contacts")
|
| 432 |
+
.HasForeignKey("GroupId")
|
| 433 |
+
.OnDelete(DeleteBehavior.SetNull);
|
| 434 |
+
|
| 435 |
+
b.Navigation("Group");
|
| 436 |
+
});
|
| 437 |
+
|
| 438 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 439 |
+
{
|
| 440 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 441 |
+
.WithMany("Documents")
|
| 442 |
+
.HasForeignKey("ContactId")
|
| 443 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 444 |
+
.IsRequired();
|
| 445 |
+
|
| 446 |
+
b.Navigation("Contact");
|
| 447 |
+
});
|
| 448 |
+
|
| 449 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 450 |
+
{
|
| 451 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 452 |
+
.WithMany("Photos")
|
| 453 |
+
.HasForeignKey("ContactId")
|
| 454 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 455 |
+
.IsRequired();
|
| 456 |
+
|
| 457 |
+
b.Navigation("Contact");
|
| 458 |
+
});
|
| 459 |
+
|
| 460 |
+
modelBuilder.Entity("ContactManagementAPI.Models.GroupRight", b =>
|
| 461 |
+
{
|
| 462 |
+
b.HasOne("ContactManagementAPI.Models.UserGroup", "UserGroup")
|
| 463 |
+
.WithMany("GroupRights")
|
| 464 |
+
.HasForeignKey("UserGroupId")
|
| 465 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 466 |
+
.IsRequired();
|
| 467 |
+
|
| 468 |
+
b.Navigation("UserGroup");
|
| 469 |
+
});
|
| 470 |
+
|
| 471 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserRight", b =>
|
| 472 |
+
{
|
| 473 |
+
b.HasOne("ContactManagementAPI.Models.AppUser", "AppUser")
|
| 474 |
+
.WithMany("UserRights")
|
| 475 |
+
.HasForeignKey("AppUserId")
|
| 476 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 477 |
+
.IsRequired();
|
| 478 |
+
|
| 479 |
+
b.Navigation("AppUser");
|
| 480 |
+
});
|
| 481 |
+
|
| 482 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 483 |
+
{
|
| 484 |
+
b.Navigation("UserRights");
|
| 485 |
+
});
|
| 486 |
+
|
| 487 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 488 |
+
{
|
| 489 |
+
b.Navigation("Documents");
|
| 490 |
+
|
| 491 |
+
b.Navigation("Photos");
|
| 492 |
+
});
|
| 493 |
+
|
| 494 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 495 |
+
{
|
| 496 |
+
b.Navigation("Contacts");
|
| 497 |
+
});
|
| 498 |
+
|
| 499 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserGroup", b =>
|
| 500 |
+
{
|
| 501 |
+
b.Navigation("GroupRights");
|
| 502 |
+
|
| 503 |
+
b.Navigation("Users");
|
| 504 |
+
});
|
| 505 |
+
#pragma warning restore 612, 618
|
| 506 |
+
}
|
| 507 |
+
}
|
| 508 |
+
}
|
ContactManagementAPI/Migrations/20260220171502_AddContactIdentityBankGenderDobFields.cs
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 3 |
+
|
| 4 |
+
#nullable disable
|
| 5 |
+
|
| 6 |
+
namespace ContactManagementAPI.Migrations
|
| 7 |
+
{
|
| 8 |
+
/// <inheritdoc />
|
| 9 |
+
public partial class AddContactIdentityBankGenderDobFields : Migration
|
| 10 |
+
{
|
| 11 |
+
/// <inheritdoc />
|
| 12 |
+
protected override void Up(MigrationBuilder migrationBuilder)
|
| 13 |
+
{
|
| 14 |
+
migrationBuilder.AddColumn<string>(
|
| 15 |
+
name: "AadharNumber",
|
| 16 |
+
table: "Contacts",
|
| 17 |
+
type: "nvarchar(max)",
|
| 18 |
+
nullable: true);
|
| 19 |
+
|
| 20 |
+
migrationBuilder.AddColumn<string>(
|
| 21 |
+
name: "BankAccountNumber",
|
| 22 |
+
table: "Contacts",
|
| 23 |
+
type: "nvarchar(max)",
|
| 24 |
+
nullable: true);
|
| 25 |
+
|
| 26 |
+
migrationBuilder.AddColumn<string>(
|
| 27 |
+
name: "BankName",
|
| 28 |
+
table: "Contacts",
|
| 29 |
+
type: "nvarchar(max)",
|
| 30 |
+
nullable: true);
|
| 31 |
+
|
| 32 |
+
migrationBuilder.AddColumn<string>(
|
| 33 |
+
name: "BranchName",
|
| 34 |
+
table: "Contacts",
|
| 35 |
+
type: "nvarchar(max)",
|
| 36 |
+
nullable: true);
|
| 37 |
+
|
| 38 |
+
migrationBuilder.AddColumn<DateTime>(
|
| 39 |
+
name: "DateOfBirth",
|
| 40 |
+
table: "Contacts",
|
| 41 |
+
type: "datetime2",
|
| 42 |
+
nullable: true);
|
| 43 |
+
|
| 44 |
+
migrationBuilder.AddColumn<string>(
|
| 45 |
+
name: "DrivingLicenseNumber",
|
| 46 |
+
table: "Contacts",
|
| 47 |
+
type: "nvarchar(max)",
|
| 48 |
+
nullable: true);
|
| 49 |
+
|
| 50 |
+
migrationBuilder.AddColumn<string>(
|
| 51 |
+
name: "Gender",
|
| 52 |
+
table: "Contacts",
|
| 53 |
+
type: "nvarchar(max)",
|
| 54 |
+
nullable: true);
|
| 55 |
+
|
| 56 |
+
migrationBuilder.AddColumn<string>(
|
| 57 |
+
name: "IfscCode",
|
| 58 |
+
table: "Contacts",
|
| 59 |
+
type: "nvarchar(max)",
|
| 60 |
+
nullable: true);
|
| 61 |
+
|
| 62 |
+
migrationBuilder.AddColumn<string>(
|
| 63 |
+
name: "PassportNumber",
|
| 64 |
+
table: "Contacts",
|
| 65 |
+
type: "nvarchar(max)",
|
| 66 |
+
nullable: true);
|
| 67 |
+
|
| 68 |
+
migrationBuilder.AddColumn<string>(
|
| 69 |
+
name: "VotersId",
|
| 70 |
+
table: "Contacts",
|
| 71 |
+
type: "nvarchar(max)",
|
| 72 |
+
nullable: true);
|
| 73 |
+
|
| 74 |
+
migrationBuilder.UpdateData(
|
| 75 |
+
table: "ContactGroups",
|
| 76 |
+
keyColumn: "Id",
|
| 77 |
+
keyValue: 1,
|
| 78 |
+
column: "CreatedAt",
|
| 79 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5689));
|
| 80 |
+
|
| 81 |
+
migrationBuilder.UpdateData(
|
| 82 |
+
table: "ContactGroups",
|
| 83 |
+
keyColumn: "Id",
|
| 84 |
+
keyValue: 2,
|
| 85 |
+
column: "CreatedAt",
|
| 86 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5716));
|
| 87 |
+
|
| 88 |
+
migrationBuilder.UpdateData(
|
| 89 |
+
table: "ContactGroups",
|
| 90 |
+
keyColumn: "Id",
|
| 91 |
+
keyValue: 3,
|
| 92 |
+
column: "CreatedAt",
|
| 93 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5720));
|
| 94 |
+
|
| 95 |
+
migrationBuilder.UpdateData(
|
| 96 |
+
table: "ContactGroups",
|
| 97 |
+
keyColumn: "Id",
|
| 98 |
+
keyValue: 4,
|
| 99 |
+
column: "CreatedAt",
|
| 100 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5722));
|
| 101 |
+
|
| 102 |
+
migrationBuilder.UpdateData(
|
| 103 |
+
table: "ContactGroups",
|
| 104 |
+
keyColumn: "Id",
|
| 105 |
+
keyValue: 5,
|
| 106 |
+
column: "CreatedAt",
|
| 107 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5723));
|
| 108 |
+
|
| 109 |
+
migrationBuilder.UpdateData(
|
| 110 |
+
table: "ContactGroups",
|
| 111 |
+
keyColumn: "Id",
|
| 112 |
+
keyValue: 6,
|
| 113 |
+
column: "CreatedAt",
|
| 114 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5725));
|
| 115 |
+
|
| 116 |
+
migrationBuilder.UpdateData(
|
| 117 |
+
table: "ContactGroups",
|
| 118 |
+
keyColumn: "Id",
|
| 119 |
+
keyValue: 7,
|
| 120 |
+
column: "CreatedAt",
|
| 121 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5727));
|
| 122 |
+
|
| 123 |
+
migrationBuilder.UpdateData(
|
| 124 |
+
table: "ContactGroups",
|
| 125 |
+
keyColumn: "Id",
|
| 126 |
+
keyValue: 8,
|
| 127 |
+
column: "CreatedAt",
|
| 128 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5729));
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
/// <inheritdoc />
|
| 132 |
+
protected override void Down(MigrationBuilder migrationBuilder)
|
| 133 |
+
{
|
| 134 |
+
migrationBuilder.DropColumn(
|
| 135 |
+
name: "AadharNumber",
|
| 136 |
+
table: "Contacts");
|
| 137 |
+
|
| 138 |
+
migrationBuilder.DropColumn(
|
| 139 |
+
name: "BankAccountNumber",
|
| 140 |
+
table: "Contacts");
|
| 141 |
+
|
| 142 |
+
migrationBuilder.DropColumn(
|
| 143 |
+
name: "BankName",
|
| 144 |
+
table: "Contacts");
|
| 145 |
+
|
| 146 |
+
migrationBuilder.DropColumn(
|
| 147 |
+
name: "BranchName",
|
| 148 |
+
table: "Contacts");
|
| 149 |
+
|
| 150 |
+
migrationBuilder.DropColumn(
|
| 151 |
+
name: "DateOfBirth",
|
| 152 |
+
table: "Contacts");
|
| 153 |
+
|
| 154 |
+
migrationBuilder.DropColumn(
|
| 155 |
+
name: "DrivingLicenseNumber",
|
| 156 |
+
table: "Contacts");
|
| 157 |
+
|
| 158 |
+
migrationBuilder.DropColumn(
|
| 159 |
+
name: "Gender",
|
| 160 |
+
table: "Contacts");
|
| 161 |
+
|
| 162 |
+
migrationBuilder.DropColumn(
|
| 163 |
+
name: "IfscCode",
|
| 164 |
+
table: "Contacts");
|
| 165 |
+
|
| 166 |
+
migrationBuilder.DropColumn(
|
| 167 |
+
name: "PassportNumber",
|
| 168 |
+
table: "Contacts");
|
| 169 |
+
|
| 170 |
+
migrationBuilder.DropColumn(
|
| 171 |
+
name: "VotersId",
|
| 172 |
+
table: "Contacts");
|
| 173 |
+
|
| 174 |
+
migrationBuilder.UpdateData(
|
| 175 |
+
table: "ContactGroups",
|
| 176 |
+
keyColumn: "Id",
|
| 177 |
+
keyValue: 1,
|
| 178 |
+
column: "CreatedAt",
|
| 179 |
+
value: new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7842));
|
| 180 |
+
|
| 181 |
+
migrationBuilder.UpdateData(
|
| 182 |
+
table: "ContactGroups",
|
| 183 |
+
keyColumn: "Id",
|
| 184 |
+
keyValue: 2,
|
| 185 |
+
column: "CreatedAt",
|
| 186 |
+
value: new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7855));
|
| 187 |
+
|
| 188 |
+
migrationBuilder.UpdateData(
|
| 189 |
+
table: "ContactGroups",
|
| 190 |
+
keyColumn: "Id",
|
| 191 |
+
keyValue: 3,
|
| 192 |
+
column: "CreatedAt",
|
| 193 |
+
value: new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7857));
|
| 194 |
+
|
| 195 |
+
migrationBuilder.UpdateData(
|
| 196 |
+
table: "ContactGroups",
|
| 197 |
+
keyColumn: "Id",
|
| 198 |
+
keyValue: 4,
|
| 199 |
+
column: "CreatedAt",
|
| 200 |
+
value: new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7858));
|
| 201 |
+
|
| 202 |
+
migrationBuilder.UpdateData(
|
| 203 |
+
table: "ContactGroups",
|
| 204 |
+
keyColumn: "Id",
|
| 205 |
+
keyValue: 5,
|
| 206 |
+
column: "CreatedAt",
|
| 207 |
+
value: new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7860));
|
| 208 |
+
|
| 209 |
+
migrationBuilder.UpdateData(
|
| 210 |
+
table: "ContactGroups",
|
| 211 |
+
keyColumn: "Id",
|
| 212 |
+
keyValue: 6,
|
| 213 |
+
column: "CreatedAt",
|
| 214 |
+
value: new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7862));
|
| 215 |
+
|
| 216 |
+
migrationBuilder.UpdateData(
|
| 217 |
+
table: "ContactGroups",
|
| 218 |
+
keyColumn: "Id",
|
| 219 |
+
keyValue: 7,
|
| 220 |
+
column: "CreatedAt",
|
| 221 |
+
value: new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7863));
|
| 222 |
+
|
| 223 |
+
migrationBuilder.UpdateData(
|
| 224 |
+
table: "ContactGroups",
|
| 225 |
+
keyColumn: "Id",
|
| 226 |
+
keyValue: 8,
|
| 227 |
+
column: "CreatedAt",
|
| 228 |
+
value: new DateTime(2026, 2, 16, 12, 39, 30, 575, DateTimeKind.Local).AddTicks(7864));
|
| 229 |
+
}
|
| 230 |
+
}
|
| 231 |
+
}
|
ContactManagementAPI/Migrations/20260220171919_AddContactBankAccountsTable.Designer.cs
ADDED
|
@@ -0,0 +1,557 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// <auto-generated />
|
| 2 |
+
using System;
|
| 3 |
+
using ContactManagementAPI.Data;
|
| 4 |
+
using Microsoft.EntityFrameworkCore;
|
| 5 |
+
using Microsoft.EntityFrameworkCore.Infrastructure;
|
| 6 |
+
using Microsoft.EntityFrameworkCore.Metadata;
|
| 7 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 8 |
+
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
| 9 |
+
|
| 10 |
+
#nullable disable
|
| 11 |
+
|
| 12 |
+
namespace ContactManagementAPI.Migrations
|
| 13 |
+
{
|
| 14 |
+
[DbContext(typeof(ApplicationDbContext))]
|
| 15 |
+
[Migration("20260220171919_AddContactBankAccountsTable")]
|
| 16 |
+
partial class AddContactBankAccountsTable
|
| 17 |
+
{
|
| 18 |
+
/// <inheritdoc />
|
| 19 |
+
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
| 20 |
+
{
|
| 21 |
+
#pragma warning disable 612, 618
|
| 22 |
+
modelBuilder
|
| 23 |
+
.HasAnnotation("ProductVersion", "8.0.0")
|
| 24 |
+
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
| 25 |
+
|
| 26 |
+
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
| 27 |
+
|
| 28 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 29 |
+
{
|
| 30 |
+
b.Property<int>("Id")
|
| 31 |
+
.ValueGeneratedOnAdd()
|
| 32 |
+
.HasColumnType("int");
|
| 33 |
+
|
| 34 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 35 |
+
|
| 36 |
+
b.Property<DateTime>("CreatedAt")
|
| 37 |
+
.HasColumnType("datetime2");
|
| 38 |
+
|
| 39 |
+
b.Property<string>("FullName")
|
| 40 |
+
.HasMaxLength(200)
|
| 41 |
+
.HasColumnType("nvarchar(200)");
|
| 42 |
+
|
| 43 |
+
b.Property<int>("GroupId")
|
| 44 |
+
.HasColumnType("int");
|
| 45 |
+
|
| 46 |
+
b.Property<bool>("IsActive")
|
| 47 |
+
.HasColumnType("bit");
|
| 48 |
+
|
| 49 |
+
b.Property<bool>("IsAdmin")
|
| 50 |
+
.HasColumnType("bit");
|
| 51 |
+
|
| 52 |
+
b.Property<string>("PasswordHash")
|
| 53 |
+
.IsRequired()
|
| 54 |
+
.HasColumnType("nvarchar(max)");
|
| 55 |
+
|
| 56 |
+
b.Property<DateTime>("UpdatedAt")
|
| 57 |
+
.HasColumnType("datetime2");
|
| 58 |
+
|
| 59 |
+
b.Property<string>("UserName")
|
| 60 |
+
.IsRequired()
|
| 61 |
+
.HasMaxLength(100)
|
| 62 |
+
.HasColumnType("nvarchar(100)");
|
| 63 |
+
|
| 64 |
+
b.HasKey("Id");
|
| 65 |
+
|
| 66 |
+
b.HasIndex("GroupId");
|
| 67 |
+
|
| 68 |
+
b.HasIndex("UserName")
|
| 69 |
+
.IsUnique();
|
| 70 |
+
|
| 71 |
+
b.ToTable("AppUsers");
|
| 72 |
+
});
|
| 73 |
+
|
| 74 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 75 |
+
{
|
| 76 |
+
b.Property<int>("Id")
|
| 77 |
+
.ValueGeneratedOnAdd()
|
| 78 |
+
.HasColumnType("int");
|
| 79 |
+
|
| 80 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 81 |
+
|
| 82 |
+
b.Property<string>("AadharNumber")
|
| 83 |
+
.HasColumnType("nvarchar(max)");
|
| 84 |
+
|
| 85 |
+
b.Property<string>("Address")
|
| 86 |
+
.HasColumnType("nvarchar(max)");
|
| 87 |
+
|
| 88 |
+
b.Property<string>("BankAccountNumber")
|
| 89 |
+
.HasColumnType("nvarchar(max)");
|
| 90 |
+
|
| 91 |
+
b.Property<string>("BankName")
|
| 92 |
+
.HasColumnType("nvarchar(max)");
|
| 93 |
+
|
| 94 |
+
b.Property<string>("BranchName")
|
| 95 |
+
.HasColumnType("nvarchar(max)");
|
| 96 |
+
|
| 97 |
+
b.Property<string>("City")
|
| 98 |
+
.HasColumnType("nvarchar(max)");
|
| 99 |
+
|
| 100 |
+
b.Property<string>("Country")
|
| 101 |
+
.HasColumnType("nvarchar(max)");
|
| 102 |
+
|
| 103 |
+
b.Property<DateTime>("CreatedAt")
|
| 104 |
+
.HasColumnType("datetime2");
|
| 105 |
+
|
| 106 |
+
b.Property<DateTime?>("DateOfBirth")
|
| 107 |
+
.HasColumnType("datetime2");
|
| 108 |
+
|
| 109 |
+
b.Property<string>("DrivingLicenseNumber")
|
| 110 |
+
.HasColumnType("nvarchar(max)");
|
| 111 |
+
|
| 112 |
+
b.Property<string>("Email")
|
| 113 |
+
.HasColumnType("nvarchar(max)");
|
| 114 |
+
|
| 115 |
+
b.Property<string>("FirstName")
|
| 116 |
+
.IsRequired()
|
| 117 |
+
.HasColumnType("nvarchar(max)");
|
| 118 |
+
|
| 119 |
+
b.Property<string>("Gender")
|
| 120 |
+
.HasColumnType("nvarchar(max)");
|
| 121 |
+
|
| 122 |
+
b.Property<int?>("GroupId")
|
| 123 |
+
.HasColumnType("int");
|
| 124 |
+
|
| 125 |
+
b.Property<string>("IfscCode")
|
| 126 |
+
.HasColumnType("nvarchar(max)");
|
| 127 |
+
|
| 128 |
+
b.Property<string>("LastName")
|
| 129 |
+
.HasColumnType("nvarchar(max)");
|
| 130 |
+
|
| 131 |
+
b.Property<string>("Mobile1")
|
| 132 |
+
.HasColumnType("nvarchar(max)");
|
| 133 |
+
|
| 134 |
+
b.Property<string>("Mobile2")
|
| 135 |
+
.HasColumnType("nvarchar(max)");
|
| 136 |
+
|
| 137 |
+
b.Property<string>("Mobile3")
|
| 138 |
+
.HasColumnType("nvarchar(max)");
|
| 139 |
+
|
| 140 |
+
b.Property<string>("NickName")
|
| 141 |
+
.HasColumnType("nvarchar(max)");
|
| 142 |
+
|
| 143 |
+
b.Property<string>("OtherDetails")
|
| 144 |
+
.HasColumnType("nvarchar(max)");
|
| 145 |
+
|
| 146 |
+
b.Property<string>("PassportNumber")
|
| 147 |
+
.HasColumnType("nvarchar(max)");
|
| 148 |
+
|
| 149 |
+
b.Property<string>("PhotoPath")
|
| 150 |
+
.HasColumnType("nvarchar(max)");
|
| 151 |
+
|
| 152 |
+
b.Property<string>("PostalCode")
|
| 153 |
+
.HasColumnType("nvarchar(max)");
|
| 154 |
+
|
| 155 |
+
b.Property<string>("State")
|
| 156 |
+
.HasColumnType("nvarchar(max)");
|
| 157 |
+
|
| 158 |
+
b.Property<DateTime>("UpdatedAt")
|
| 159 |
+
.HasColumnType("datetime2");
|
| 160 |
+
|
| 161 |
+
b.Property<string>("VotersId")
|
| 162 |
+
.HasColumnType("nvarchar(max)");
|
| 163 |
+
|
| 164 |
+
b.Property<string>("WhatsAppNumber")
|
| 165 |
+
.HasColumnType("nvarchar(max)");
|
| 166 |
+
|
| 167 |
+
b.HasKey("Id");
|
| 168 |
+
|
| 169 |
+
b.HasIndex("GroupId");
|
| 170 |
+
|
| 171 |
+
b.ToTable("Contacts");
|
| 172 |
+
});
|
| 173 |
+
|
| 174 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactBankAccount", b =>
|
| 175 |
+
{
|
| 176 |
+
b.Property<int>("Id")
|
| 177 |
+
.ValueGeneratedOnAdd()
|
| 178 |
+
.HasColumnType("int");
|
| 179 |
+
|
| 180 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 181 |
+
|
| 182 |
+
b.Property<string>("AccountNumber")
|
| 183 |
+
.HasColumnType("nvarchar(max)");
|
| 184 |
+
|
| 185 |
+
b.Property<string>("BankName")
|
| 186 |
+
.HasColumnType("nvarchar(max)");
|
| 187 |
+
|
| 188 |
+
b.Property<string>("BranchName")
|
| 189 |
+
.HasColumnType("nvarchar(max)");
|
| 190 |
+
|
| 191 |
+
b.Property<int>("ContactId")
|
| 192 |
+
.HasColumnType("int");
|
| 193 |
+
|
| 194 |
+
b.Property<DateTime>("CreatedAt")
|
| 195 |
+
.HasColumnType("datetime2");
|
| 196 |
+
|
| 197 |
+
b.Property<string>("IfscCode")
|
| 198 |
+
.HasColumnType("nvarchar(max)");
|
| 199 |
+
|
| 200 |
+
b.Property<DateTime>("UpdatedAt")
|
| 201 |
+
.HasColumnType("datetime2");
|
| 202 |
+
|
| 203 |
+
b.HasKey("Id");
|
| 204 |
+
|
| 205 |
+
b.HasIndex("ContactId");
|
| 206 |
+
|
| 207 |
+
b.ToTable("ContactBankAccounts");
|
| 208 |
+
});
|
| 209 |
+
|
| 210 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 211 |
+
{
|
| 212 |
+
b.Property<int>("Id")
|
| 213 |
+
.ValueGeneratedOnAdd()
|
| 214 |
+
.HasColumnType("int");
|
| 215 |
+
|
| 216 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 217 |
+
|
| 218 |
+
b.Property<int>("ContactId")
|
| 219 |
+
.HasColumnType("int");
|
| 220 |
+
|
| 221 |
+
b.Property<string>("ContentType")
|
| 222 |
+
.IsRequired()
|
| 223 |
+
.HasColumnType("nvarchar(max)");
|
| 224 |
+
|
| 225 |
+
b.Property<string>("DocumentPath")
|
| 226 |
+
.IsRequired()
|
| 227 |
+
.HasColumnType("nvarchar(max)");
|
| 228 |
+
|
| 229 |
+
b.Property<string>("DocumentType")
|
| 230 |
+
.IsRequired()
|
| 231 |
+
.HasColumnType("nvarchar(max)");
|
| 232 |
+
|
| 233 |
+
b.Property<string>("FileName")
|
| 234 |
+
.IsRequired()
|
| 235 |
+
.HasColumnType("nvarchar(max)");
|
| 236 |
+
|
| 237 |
+
b.Property<long>("FileSize")
|
| 238 |
+
.HasColumnType("bigint");
|
| 239 |
+
|
| 240 |
+
b.Property<DateTime>("UploadedAt")
|
| 241 |
+
.HasColumnType("datetime2");
|
| 242 |
+
|
| 243 |
+
b.HasKey("Id");
|
| 244 |
+
|
| 245 |
+
b.HasIndex("ContactId");
|
| 246 |
+
|
| 247 |
+
b.ToTable("ContactDocuments");
|
| 248 |
+
});
|
| 249 |
+
|
| 250 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 251 |
+
{
|
| 252 |
+
b.Property<int>("Id")
|
| 253 |
+
.ValueGeneratedOnAdd()
|
| 254 |
+
.HasColumnType("int");
|
| 255 |
+
|
| 256 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 257 |
+
|
| 258 |
+
b.Property<DateTime>("CreatedAt")
|
| 259 |
+
.HasColumnType("datetime2");
|
| 260 |
+
|
| 261 |
+
b.Property<string>("Description")
|
| 262 |
+
.IsRequired()
|
| 263 |
+
.HasColumnType("nvarchar(max)");
|
| 264 |
+
|
| 265 |
+
b.Property<string>("Name")
|
| 266 |
+
.IsRequired()
|
| 267 |
+
.HasColumnType("nvarchar(max)");
|
| 268 |
+
|
| 269 |
+
b.HasKey("Id");
|
| 270 |
+
|
| 271 |
+
b.ToTable("ContactGroups");
|
| 272 |
+
|
| 273 |
+
b.HasData(
|
| 274 |
+
new
|
| 275 |
+
{
|
| 276 |
+
Id = 1,
|
| 277 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4198),
|
| 278 |
+
Description = "Family members",
|
| 279 |
+
Name = "Family"
|
| 280 |
+
},
|
| 281 |
+
new
|
| 282 |
+
{
|
| 283 |
+
Id = 2,
|
| 284 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4211),
|
| 285 |
+
Description = "Friends",
|
| 286 |
+
Name = "Friends"
|
| 287 |
+
},
|
| 288 |
+
new
|
| 289 |
+
{
|
| 290 |
+
Id = 3,
|
| 291 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4213),
|
| 292 |
+
Description = "Business contacts",
|
| 293 |
+
Name = "Business"
|
| 294 |
+
},
|
| 295 |
+
new
|
| 296 |
+
{
|
| 297 |
+
Id = 4,
|
| 298 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4214),
|
| 299 |
+
Description = "School contacts",
|
| 300 |
+
Name = "School"
|
| 301 |
+
},
|
| 302 |
+
new
|
| 303 |
+
{
|
| 304 |
+
Id = 5,
|
| 305 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4216),
|
| 306 |
+
Description = "Church members",
|
| 307 |
+
Name = "Church"
|
| 308 |
+
},
|
| 309 |
+
new
|
| 310 |
+
{
|
| 311 |
+
Id = 6,
|
| 312 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4217),
|
| 313 |
+
Description = "Other contacts",
|
| 314 |
+
Name = "Others"
|
| 315 |
+
},
|
| 316 |
+
new
|
| 317 |
+
{
|
| 318 |
+
Id = 7,
|
| 319 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4218),
|
| 320 |
+
Description = "College contacts",
|
| 321 |
+
Name = "College"
|
| 322 |
+
},
|
| 323 |
+
new
|
| 324 |
+
{
|
| 325 |
+
Id = 8,
|
| 326 |
+
CreatedAt = new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4220),
|
| 327 |
+
Description = "Alcoholics Anonymous",
|
| 328 |
+
Name = "AA"
|
| 329 |
+
});
|
| 330 |
+
});
|
| 331 |
+
|
| 332 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 333 |
+
{
|
| 334 |
+
b.Property<int>("Id")
|
| 335 |
+
.ValueGeneratedOnAdd()
|
| 336 |
+
.HasColumnType("int");
|
| 337 |
+
|
| 338 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 339 |
+
|
| 340 |
+
b.Property<int>("ContactId")
|
| 341 |
+
.HasColumnType("int");
|
| 342 |
+
|
| 343 |
+
b.Property<string>("ContentType")
|
| 344 |
+
.IsRequired()
|
| 345 |
+
.HasColumnType("nvarchar(max)");
|
| 346 |
+
|
| 347 |
+
b.Property<string>("FileName")
|
| 348 |
+
.IsRequired()
|
| 349 |
+
.HasColumnType("nvarchar(max)");
|
| 350 |
+
|
| 351 |
+
b.Property<long>("FileSize")
|
| 352 |
+
.HasColumnType("bigint");
|
| 353 |
+
|
| 354 |
+
b.Property<bool>("IsProfilePhoto")
|
| 355 |
+
.HasColumnType("bit");
|
| 356 |
+
|
| 357 |
+
b.Property<string>("PhotoPath")
|
| 358 |
+
.IsRequired()
|
| 359 |
+
.HasColumnType("nvarchar(max)");
|
| 360 |
+
|
| 361 |
+
b.Property<DateTime>("UploadedAt")
|
| 362 |
+
.HasColumnType("datetime2");
|
| 363 |
+
|
| 364 |
+
b.HasKey("Id");
|
| 365 |
+
|
| 366 |
+
b.HasIndex("ContactId");
|
| 367 |
+
|
| 368 |
+
b.ToTable("ContactPhotos");
|
| 369 |
+
});
|
| 370 |
+
|
| 371 |
+
modelBuilder.Entity("ContactManagementAPI.Models.GroupRight", b =>
|
| 372 |
+
{
|
| 373 |
+
b.Property<int>("Id")
|
| 374 |
+
.ValueGeneratedOnAdd()
|
| 375 |
+
.HasColumnType("int");
|
| 376 |
+
|
| 377 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 378 |
+
|
| 379 |
+
b.Property<bool>("IsGranted")
|
| 380 |
+
.HasColumnType("bit");
|
| 381 |
+
|
| 382 |
+
b.Property<string>("RightKey")
|
| 383 |
+
.IsRequired()
|
| 384 |
+
.HasMaxLength(100)
|
| 385 |
+
.HasColumnType("nvarchar(100)");
|
| 386 |
+
|
| 387 |
+
b.Property<int>("UserGroupId")
|
| 388 |
+
.HasColumnType("int");
|
| 389 |
+
|
| 390 |
+
b.HasKey("Id");
|
| 391 |
+
|
| 392 |
+
b.HasIndex("UserGroupId", "RightKey")
|
| 393 |
+
.IsUnique();
|
| 394 |
+
|
| 395 |
+
b.ToTable("GroupRights");
|
| 396 |
+
});
|
| 397 |
+
|
| 398 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserGroup", b =>
|
| 399 |
+
{
|
| 400 |
+
b.Property<int>("Id")
|
| 401 |
+
.ValueGeneratedOnAdd()
|
| 402 |
+
.HasColumnType("int");
|
| 403 |
+
|
| 404 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 405 |
+
|
| 406 |
+
b.Property<DateTime>("CreatedAt")
|
| 407 |
+
.HasColumnType("datetime2");
|
| 408 |
+
|
| 409 |
+
b.Property<string>("Description")
|
| 410 |
+
.HasMaxLength(500)
|
| 411 |
+
.HasColumnType("nvarchar(500)");
|
| 412 |
+
|
| 413 |
+
b.Property<string>("Name")
|
| 414 |
+
.IsRequired()
|
| 415 |
+
.HasMaxLength(150)
|
| 416 |
+
.HasColumnType("nvarchar(150)");
|
| 417 |
+
|
| 418 |
+
b.HasKey("Id");
|
| 419 |
+
|
| 420 |
+
b.HasIndex("Name")
|
| 421 |
+
.IsUnique();
|
| 422 |
+
|
| 423 |
+
b.ToTable("UserGroups");
|
| 424 |
+
});
|
| 425 |
+
|
| 426 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserRight", b =>
|
| 427 |
+
{
|
| 428 |
+
b.Property<int>("Id")
|
| 429 |
+
.ValueGeneratedOnAdd()
|
| 430 |
+
.HasColumnType("int");
|
| 431 |
+
|
| 432 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 433 |
+
|
| 434 |
+
b.Property<int>("AppUserId")
|
| 435 |
+
.HasColumnType("int");
|
| 436 |
+
|
| 437 |
+
b.Property<bool>("IsGranted")
|
| 438 |
+
.HasColumnType("bit");
|
| 439 |
+
|
| 440 |
+
b.Property<string>("RightKey")
|
| 441 |
+
.IsRequired()
|
| 442 |
+
.HasMaxLength(100)
|
| 443 |
+
.HasColumnType("nvarchar(100)");
|
| 444 |
+
|
| 445 |
+
b.HasKey("Id");
|
| 446 |
+
|
| 447 |
+
b.HasIndex("AppUserId", "RightKey")
|
| 448 |
+
.IsUnique();
|
| 449 |
+
|
| 450 |
+
b.ToTable("UserRights");
|
| 451 |
+
});
|
| 452 |
+
|
| 453 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 454 |
+
{
|
| 455 |
+
b.HasOne("ContactManagementAPI.Models.UserGroup", "Group")
|
| 456 |
+
.WithMany("Users")
|
| 457 |
+
.HasForeignKey("GroupId")
|
| 458 |
+
.OnDelete(DeleteBehavior.SetNull)
|
| 459 |
+
.IsRequired();
|
| 460 |
+
|
| 461 |
+
b.Navigation("Group");
|
| 462 |
+
});
|
| 463 |
+
|
| 464 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 465 |
+
{
|
| 466 |
+
b.HasOne("ContactManagementAPI.Models.ContactGroup", "Group")
|
| 467 |
+
.WithMany("Contacts")
|
| 468 |
+
.HasForeignKey("GroupId")
|
| 469 |
+
.OnDelete(DeleteBehavior.SetNull);
|
| 470 |
+
|
| 471 |
+
b.Navigation("Group");
|
| 472 |
+
});
|
| 473 |
+
|
| 474 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactBankAccount", b =>
|
| 475 |
+
{
|
| 476 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 477 |
+
.WithMany("BankAccounts")
|
| 478 |
+
.HasForeignKey("ContactId")
|
| 479 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 480 |
+
.IsRequired();
|
| 481 |
+
|
| 482 |
+
b.Navigation("Contact");
|
| 483 |
+
});
|
| 484 |
+
|
| 485 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 486 |
+
{
|
| 487 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 488 |
+
.WithMany("Documents")
|
| 489 |
+
.HasForeignKey("ContactId")
|
| 490 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 491 |
+
.IsRequired();
|
| 492 |
+
|
| 493 |
+
b.Navigation("Contact");
|
| 494 |
+
});
|
| 495 |
+
|
| 496 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 497 |
+
{
|
| 498 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 499 |
+
.WithMany("Photos")
|
| 500 |
+
.HasForeignKey("ContactId")
|
| 501 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 502 |
+
.IsRequired();
|
| 503 |
+
|
| 504 |
+
b.Navigation("Contact");
|
| 505 |
+
});
|
| 506 |
+
|
| 507 |
+
modelBuilder.Entity("ContactManagementAPI.Models.GroupRight", b =>
|
| 508 |
+
{
|
| 509 |
+
b.HasOne("ContactManagementAPI.Models.UserGroup", "UserGroup")
|
| 510 |
+
.WithMany("GroupRights")
|
| 511 |
+
.HasForeignKey("UserGroupId")
|
| 512 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 513 |
+
.IsRequired();
|
| 514 |
+
|
| 515 |
+
b.Navigation("UserGroup");
|
| 516 |
+
});
|
| 517 |
+
|
| 518 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserRight", b =>
|
| 519 |
+
{
|
| 520 |
+
b.HasOne("ContactManagementAPI.Models.AppUser", "AppUser")
|
| 521 |
+
.WithMany("UserRights")
|
| 522 |
+
.HasForeignKey("AppUserId")
|
| 523 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 524 |
+
.IsRequired();
|
| 525 |
+
|
| 526 |
+
b.Navigation("AppUser");
|
| 527 |
+
});
|
| 528 |
+
|
| 529 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 530 |
+
{
|
| 531 |
+
b.Navigation("UserRights");
|
| 532 |
+
});
|
| 533 |
+
|
| 534 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 535 |
+
{
|
| 536 |
+
b.Navigation("BankAccounts");
|
| 537 |
+
|
| 538 |
+
b.Navigation("Documents");
|
| 539 |
+
|
| 540 |
+
b.Navigation("Photos");
|
| 541 |
+
});
|
| 542 |
+
|
| 543 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 544 |
+
{
|
| 545 |
+
b.Navigation("Contacts");
|
| 546 |
+
});
|
| 547 |
+
|
| 548 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserGroup", b =>
|
| 549 |
+
{
|
| 550 |
+
b.Navigation("GroupRights");
|
| 551 |
+
|
| 552 |
+
b.Navigation("Users");
|
| 553 |
+
});
|
| 554 |
+
#pragma warning restore 612, 618
|
| 555 |
+
}
|
| 556 |
+
}
|
| 557 |
+
}
|
ContactManagementAPI/Migrations/20260220171919_AddContactBankAccountsTable.cs
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 3 |
+
|
| 4 |
+
#nullable disable
|
| 5 |
+
|
| 6 |
+
namespace ContactManagementAPI.Migrations
|
| 7 |
+
{
|
| 8 |
+
/// <inheritdoc />
|
| 9 |
+
public partial class AddContactBankAccountsTable : Migration
|
| 10 |
+
{
|
| 11 |
+
/// <inheritdoc />
|
| 12 |
+
protected override void Up(MigrationBuilder migrationBuilder)
|
| 13 |
+
{
|
| 14 |
+
migrationBuilder.CreateTable(
|
| 15 |
+
name: "ContactBankAccounts",
|
| 16 |
+
columns: table => new
|
| 17 |
+
{
|
| 18 |
+
Id = table.Column<int>(type: "int", nullable: false)
|
| 19 |
+
.Annotation("SqlServer:Identity", "1, 1"),
|
| 20 |
+
ContactId = table.Column<int>(type: "int", nullable: false),
|
| 21 |
+
AccountNumber = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
| 22 |
+
BankName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
| 23 |
+
BranchName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
| 24 |
+
IfscCode = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
| 25 |
+
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
| 26 |
+
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: false)
|
| 27 |
+
},
|
| 28 |
+
constraints: table =>
|
| 29 |
+
{
|
| 30 |
+
table.PrimaryKey("PK_ContactBankAccounts", x => x.Id);
|
| 31 |
+
table.ForeignKey(
|
| 32 |
+
name: "FK_ContactBankAccounts_Contacts_ContactId",
|
| 33 |
+
column: x => x.ContactId,
|
| 34 |
+
principalTable: "Contacts",
|
| 35 |
+
principalColumn: "Id",
|
| 36 |
+
onDelete: ReferentialAction.Cascade);
|
| 37 |
+
});
|
| 38 |
+
|
| 39 |
+
migrationBuilder.UpdateData(
|
| 40 |
+
table: "ContactGroups",
|
| 41 |
+
keyColumn: "Id",
|
| 42 |
+
keyValue: 1,
|
| 43 |
+
column: "CreatedAt",
|
| 44 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4198));
|
| 45 |
+
|
| 46 |
+
migrationBuilder.UpdateData(
|
| 47 |
+
table: "ContactGroups",
|
| 48 |
+
keyColumn: "Id",
|
| 49 |
+
keyValue: 2,
|
| 50 |
+
column: "CreatedAt",
|
| 51 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4211));
|
| 52 |
+
|
| 53 |
+
migrationBuilder.UpdateData(
|
| 54 |
+
table: "ContactGroups",
|
| 55 |
+
keyColumn: "Id",
|
| 56 |
+
keyValue: 3,
|
| 57 |
+
column: "CreatedAt",
|
| 58 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4213));
|
| 59 |
+
|
| 60 |
+
migrationBuilder.UpdateData(
|
| 61 |
+
table: "ContactGroups",
|
| 62 |
+
keyColumn: "Id",
|
| 63 |
+
keyValue: 4,
|
| 64 |
+
column: "CreatedAt",
|
| 65 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4214));
|
| 66 |
+
|
| 67 |
+
migrationBuilder.UpdateData(
|
| 68 |
+
table: "ContactGroups",
|
| 69 |
+
keyColumn: "Id",
|
| 70 |
+
keyValue: 5,
|
| 71 |
+
column: "CreatedAt",
|
| 72 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4216));
|
| 73 |
+
|
| 74 |
+
migrationBuilder.UpdateData(
|
| 75 |
+
table: "ContactGroups",
|
| 76 |
+
keyColumn: "Id",
|
| 77 |
+
keyValue: 6,
|
| 78 |
+
column: "CreatedAt",
|
| 79 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4217));
|
| 80 |
+
|
| 81 |
+
migrationBuilder.UpdateData(
|
| 82 |
+
table: "ContactGroups",
|
| 83 |
+
keyColumn: "Id",
|
| 84 |
+
keyValue: 7,
|
| 85 |
+
column: "CreatedAt",
|
| 86 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4218));
|
| 87 |
+
|
| 88 |
+
migrationBuilder.UpdateData(
|
| 89 |
+
table: "ContactGroups",
|
| 90 |
+
keyColumn: "Id",
|
| 91 |
+
keyValue: 8,
|
| 92 |
+
column: "CreatedAt",
|
| 93 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4220));
|
| 94 |
+
|
| 95 |
+
migrationBuilder.CreateIndex(
|
| 96 |
+
name: "IX_ContactBankAccounts_ContactId",
|
| 97 |
+
table: "ContactBankAccounts",
|
| 98 |
+
column: "ContactId");
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
/// <inheritdoc />
|
| 102 |
+
protected override void Down(MigrationBuilder migrationBuilder)
|
| 103 |
+
{
|
| 104 |
+
migrationBuilder.DropTable(
|
| 105 |
+
name: "ContactBankAccounts");
|
| 106 |
+
|
| 107 |
+
migrationBuilder.UpdateData(
|
| 108 |
+
table: "ContactGroups",
|
| 109 |
+
keyColumn: "Id",
|
| 110 |
+
keyValue: 1,
|
| 111 |
+
column: "CreatedAt",
|
| 112 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5689));
|
| 113 |
+
|
| 114 |
+
migrationBuilder.UpdateData(
|
| 115 |
+
table: "ContactGroups",
|
| 116 |
+
keyColumn: "Id",
|
| 117 |
+
keyValue: 2,
|
| 118 |
+
column: "CreatedAt",
|
| 119 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5716));
|
| 120 |
+
|
| 121 |
+
migrationBuilder.UpdateData(
|
| 122 |
+
table: "ContactGroups",
|
| 123 |
+
keyColumn: "Id",
|
| 124 |
+
keyValue: 3,
|
| 125 |
+
column: "CreatedAt",
|
| 126 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5720));
|
| 127 |
+
|
| 128 |
+
migrationBuilder.UpdateData(
|
| 129 |
+
table: "ContactGroups",
|
| 130 |
+
keyColumn: "Id",
|
| 131 |
+
keyValue: 4,
|
| 132 |
+
column: "CreatedAt",
|
| 133 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5722));
|
| 134 |
+
|
| 135 |
+
migrationBuilder.UpdateData(
|
| 136 |
+
table: "ContactGroups",
|
| 137 |
+
keyColumn: "Id",
|
| 138 |
+
keyValue: 5,
|
| 139 |
+
column: "CreatedAt",
|
| 140 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5723));
|
| 141 |
+
|
| 142 |
+
migrationBuilder.UpdateData(
|
| 143 |
+
table: "ContactGroups",
|
| 144 |
+
keyColumn: "Id",
|
| 145 |
+
keyValue: 6,
|
| 146 |
+
column: "CreatedAt",
|
| 147 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5725));
|
| 148 |
+
|
| 149 |
+
migrationBuilder.UpdateData(
|
| 150 |
+
table: "ContactGroups",
|
| 151 |
+
keyColumn: "Id",
|
| 152 |
+
keyValue: 7,
|
| 153 |
+
column: "CreatedAt",
|
| 154 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5727));
|
| 155 |
+
|
| 156 |
+
migrationBuilder.UpdateData(
|
| 157 |
+
table: "ContactGroups",
|
| 158 |
+
keyColumn: "Id",
|
| 159 |
+
keyValue: 8,
|
| 160 |
+
column: "CreatedAt",
|
| 161 |
+
value: new DateTime(2026, 2, 20, 22, 44, 58, 435, DateTimeKind.Local).AddTicks(5729));
|
| 162 |
+
}
|
| 163 |
+
}
|
| 164 |
+
}
|
ContactManagementAPI/Migrations/20260221045734_AddPanNumberToContact.Designer.cs
ADDED
|
@@ -0,0 +1,560 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// <auto-generated />
|
| 2 |
+
using System;
|
| 3 |
+
using ContactManagementAPI.Data;
|
| 4 |
+
using Microsoft.EntityFrameworkCore;
|
| 5 |
+
using Microsoft.EntityFrameworkCore.Infrastructure;
|
| 6 |
+
using Microsoft.EntityFrameworkCore.Metadata;
|
| 7 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 8 |
+
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
| 9 |
+
|
| 10 |
+
#nullable disable
|
| 11 |
+
|
| 12 |
+
namespace ContactManagementAPI.Migrations
|
| 13 |
+
{
|
| 14 |
+
[DbContext(typeof(ApplicationDbContext))]
|
| 15 |
+
[Migration("20260221045734_AddPanNumberToContact")]
|
| 16 |
+
partial class AddPanNumberToContact
|
| 17 |
+
{
|
| 18 |
+
/// <inheritdoc />
|
| 19 |
+
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
| 20 |
+
{
|
| 21 |
+
#pragma warning disable 612, 618
|
| 22 |
+
modelBuilder
|
| 23 |
+
.HasAnnotation("ProductVersion", "8.0.0")
|
| 24 |
+
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
| 25 |
+
|
| 26 |
+
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
| 27 |
+
|
| 28 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 29 |
+
{
|
| 30 |
+
b.Property<int>("Id")
|
| 31 |
+
.ValueGeneratedOnAdd()
|
| 32 |
+
.HasColumnType("int");
|
| 33 |
+
|
| 34 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 35 |
+
|
| 36 |
+
b.Property<DateTime>("CreatedAt")
|
| 37 |
+
.HasColumnType("datetime2");
|
| 38 |
+
|
| 39 |
+
b.Property<string>("FullName")
|
| 40 |
+
.HasMaxLength(200)
|
| 41 |
+
.HasColumnType("nvarchar(200)");
|
| 42 |
+
|
| 43 |
+
b.Property<int>("GroupId")
|
| 44 |
+
.HasColumnType("int");
|
| 45 |
+
|
| 46 |
+
b.Property<bool>("IsActive")
|
| 47 |
+
.HasColumnType("bit");
|
| 48 |
+
|
| 49 |
+
b.Property<bool>("IsAdmin")
|
| 50 |
+
.HasColumnType("bit");
|
| 51 |
+
|
| 52 |
+
b.Property<string>("PasswordHash")
|
| 53 |
+
.IsRequired()
|
| 54 |
+
.HasColumnType("nvarchar(max)");
|
| 55 |
+
|
| 56 |
+
b.Property<DateTime>("UpdatedAt")
|
| 57 |
+
.HasColumnType("datetime2");
|
| 58 |
+
|
| 59 |
+
b.Property<string>("UserName")
|
| 60 |
+
.IsRequired()
|
| 61 |
+
.HasMaxLength(100)
|
| 62 |
+
.HasColumnType("nvarchar(100)");
|
| 63 |
+
|
| 64 |
+
b.HasKey("Id");
|
| 65 |
+
|
| 66 |
+
b.HasIndex("GroupId");
|
| 67 |
+
|
| 68 |
+
b.HasIndex("UserName")
|
| 69 |
+
.IsUnique();
|
| 70 |
+
|
| 71 |
+
b.ToTable("AppUsers");
|
| 72 |
+
});
|
| 73 |
+
|
| 74 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 75 |
+
{
|
| 76 |
+
b.Property<int>("Id")
|
| 77 |
+
.ValueGeneratedOnAdd()
|
| 78 |
+
.HasColumnType("int");
|
| 79 |
+
|
| 80 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 81 |
+
|
| 82 |
+
b.Property<string>("AadharNumber")
|
| 83 |
+
.HasColumnType("nvarchar(max)");
|
| 84 |
+
|
| 85 |
+
b.Property<string>("Address")
|
| 86 |
+
.HasColumnType("nvarchar(max)");
|
| 87 |
+
|
| 88 |
+
b.Property<string>("BankAccountNumber")
|
| 89 |
+
.HasColumnType("nvarchar(max)");
|
| 90 |
+
|
| 91 |
+
b.Property<string>("BankName")
|
| 92 |
+
.HasColumnType("nvarchar(max)");
|
| 93 |
+
|
| 94 |
+
b.Property<string>("BranchName")
|
| 95 |
+
.HasColumnType("nvarchar(max)");
|
| 96 |
+
|
| 97 |
+
b.Property<string>("City")
|
| 98 |
+
.HasColumnType("nvarchar(max)");
|
| 99 |
+
|
| 100 |
+
b.Property<string>("Country")
|
| 101 |
+
.HasColumnType("nvarchar(max)");
|
| 102 |
+
|
| 103 |
+
b.Property<DateTime>("CreatedAt")
|
| 104 |
+
.HasColumnType("datetime2");
|
| 105 |
+
|
| 106 |
+
b.Property<DateTime?>("DateOfBirth")
|
| 107 |
+
.HasColumnType("datetime2");
|
| 108 |
+
|
| 109 |
+
b.Property<string>("DrivingLicenseNumber")
|
| 110 |
+
.HasColumnType("nvarchar(max)");
|
| 111 |
+
|
| 112 |
+
b.Property<string>("Email")
|
| 113 |
+
.HasColumnType("nvarchar(max)");
|
| 114 |
+
|
| 115 |
+
b.Property<string>("FirstName")
|
| 116 |
+
.IsRequired()
|
| 117 |
+
.HasColumnType("nvarchar(max)");
|
| 118 |
+
|
| 119 |
+
b.Property<string>("Gender")
|
| 120 |
+
.HasColumnType("nvarchar(max)");
|
| 121 |
+
|
| 122 |
+
b.Property<int?>("GroupId")
|
| 123 |
+
.HasColumnType("int");
|
| 124 |
+
|
| 125 |
+
b.Property<string>("IfscCode")
|
| 126 |
+
.HasColumnType("nvarchar(max)");
|
| 127 |
+
|
| 128 |
+
b.Property<string>("LastName")
|
| 129 |
+
.HasColumnType("nvarchar(max)");
|
| 130 |
+
|
| 131 |
+
b.Property<string>("Mobile1")
|
| 132 |
+
.HasColumnType("nvarchar(max)");
|
| 133 |
+
|
| 134 |
+
b.Property<string>("Mobile2")
|
| 135 |
+
.HasColumnType("nvarchar(max)");
|
| 136 |
+
|
| 137 |
+
b.Property<string>("Mobile3")
|
| 138 |
+
.HasColumnType("nvarchar(max)");
|
| 139 |
+
|
| 140 |
+
b.Property<string>("NickName")
|
| 141 |
+
.HasColumnType("nvarchar(max)");
|
| 142 |
+
|
| 143 |
+
b.Property<string>("OtherDetails")
|
| 144 |
+
.HasColumnType("nvarchar(max)");
|
| 145 |
+
|
| 146 |
+
b.Property<string>("PanNumber")
|
| 147 |
+
.HasColumnType("nvarchar(max)");
|
| 148 |
+
|
| 149 |
+
b.Property<string>("PassportNumber")
|
| 150 |
+
.HasColumnType("nvarchar(max)");
|
| 151 |
+
|
| 152 |
+
b.Property<string>("PhotoPath")
|
| 153 |
+
.HasColumnType("nvarchar(max)");
|
| 154 |
+
|
| 155 |
+
b.Property<string>("PostalCode")
|
| 156 |
+
.HasColumnType("nvarchar(max)");
|
| 157 |
+
|
| 158 |
+
b.Property<string>("State")
|
| 159 |
+
.HasColumnType("nvarchar(max)");
|
| 160 |
+
|
| 161 |
+
b.Property<DateTime>("UpdatedAt")
|
| 162 |
+
.HasColumnType("datetime2");
|
| 163 |
+
|
| 164 |
+
b.Property<string>("VotersId")
|
| 165 |
+
.HasColumnType("nvarchar(max)");
|
| 166 |
+
|
| 167 |
+
b.Property<string>("WhatsAppNumber")
|
| 168 |
+
.HasColumnType("nvarchar(max)");
|
| 169 |
+
|
| 170 |
+
b.HasKey("Id");
|
| 171 |
+
|
| 172 |
+
b.HasIndex("GroupId");
|
| 173 |
+
|
| 174 |
+
b.ToTable("Contacts");
|
| 175 |
+
});
|
| 176 |
+
|
| 177 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactBankAccount", b =>
|
| 178 |
+
{
|
| 179 |
+
b.Property<int>("Id")
|
| 180 |
+
.ValueGeneratedOnAdd()
|
| 181 |
+
.HasColumnType("int");
|
| 182 |
+
|
| 183 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 184 |
+
|
| 185 |
+
b.Property<string>("AccountNumber")
|
| 186 |
+
.HasColumnType("nvarchar(max)");
|
| 187 |
+
|
| 188 |
+
b.Property<string>("BankName")
|
| 189 |
+
.HasColumnType("nvarchar(max)");
|
| 190 |
+
|
| 191 |
+
b.Property<string>("BranchName")
|
| 192 |
+
.HasColumnType("nvarchar(max)");
|
| 193 |
+
|
| 194 |
+
b.Property<int>("ContactId")
|
| 195 |
+
.HasColumnType("int");
|
| 196 |
+
|
| 197 |
+
b.Property<DateTime>("CreatedAt")
|
| 198 |
+
.HasColumnType("datetime2");
|
| 199 |
+
|
| 200 |
+
b.Property<string>("IfscCode")
|
| 201 |
+
.HasColumnType("nvarchar(max)");
|
| 202 |
+
|
| 203 |
+
b.Property<DateTime>("UpdatedAt")
|
| 204 |
+
.HasColumnType("datetime2");
|
| 205 |
+
|
| 206 |
+
b.HasKey("Id");
|
| 207 |
+
|
| 208 |
+
b.HasIndex("ContactId");
|
| 209 |
+
|
| 210 |
+
b.ToTable("ContactBankAccounts");
|
| 211 |
+
});
|
| 212 |
+
|
| 213 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 214 |
+
{
|
| 215 |
+
b.Property<int>("Id")
|
| 216 |
+
.ValueGeneratedOnAdd()
|
| 217 |
+
.HasColumnType("int");
|
| 218 |
+
|
| 219 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 220 |
+
|
| 221 |
+
b.Property<int>("ContactId")
|
| 222 |
+
.HasColumnType("int");
|
| 223 |
+
|
| 224 |
+
b.Property<string>("ContentType")
|
| 225 |
+
.IsRequired()
|
| 226 |
+
.HasColumnType("nvarchar(max)");
|
| 227 |
+
|
| 228 |
+
b.Property<string>("DocumentPath")
|
| 229 |
+
.IsRequired()
|
| 230 |
+
.HasColumnType("nvarchar(max)");
|
| 231 |
+
|
| 232 |
+
b.Property<string>("DocumentType")
|
| 233 |
+
.IsRequired()
|
| 234 |
+
.HasColumnType("nvarchar(max)");
|
| 235 |
+
|
| 236 |
+
b.Property<string>("FileName")
|
| 237 |
+
.IsRequired()
|
| 238 |
+
.HasColumnType("nvarchar(max)");
|
| 239 |
+
|
| 240 |
+
b.Property<long>("FileSize")
|
| 241 |
+
.HasColumnType("bigint");
|
| 242 |
+
|
| 243 |
+
b.Property<DateTime>("UploadedAt")
|
| 244 |
+
.HasColumnType("datetime2");
|
| 245 |
+
|
| 246 |
+
b.HasKey("Id");
|
| 247 |
+
|
| 248 |
+
b.HasIndex("ContactId");
|
| 249 |
+
|
| 250 |
+
b.ToTable("ContactDocuments");
|
| 251 |
+
});
|
| 252 |
+
|
| 253 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 254 |
+
{
|
| 255 |
+
b.Property<int>("Id")
|
| 256 |
+
.ValueGeneratedOnAdd()
|
| 257 |
+
.HasColumnType("int");
|
| 258 |
+
|
| 259 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 260 |
+
|
| 261 |
+
b.Property<DateTime>("CreatedAt")
|
| 262 |
+
.HasColumnType("datetime2");
|
| 263 |
+
|
| 264 |
+
b.Property<string>("Description")
|
| 265 |
+
.IsRequired()
|
| 266 |
+
.HasColumnType("nvarchar(max)");
|
| 267 |
+
|
| 268 |
+
b.Property<string>("Name")
|
| 269 |
+
.IsRequired()
|
| 270 |
+
.HasColumnType("nvarchar(max)");
|
| 271 |
+
|
| 272 |
+
b.HasKey("Id");
|
| 273 |
+
|
| 274 |
+
b.ToTable("ContactGroups");
|
| 275 |
+
|
| 276 |
+
b.HasData(
|
| 277 |
+
new
|
| 278 |
+
{
|
| 279 |
+
Id = 1,
|
| 280 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7176),
|
| 281 |
+
Description = "Family members",
|
| 282 |
+
Name = "Family"
|
| 283 |
+
},
|
| 284 |
+
new
|
| 285 |
+
{
|
| 286 |
+
Id = 2,
|
| 287 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7190),
|
| 288 |
+
Description = "Friends",
|
| 289 |
+
Name = "Friends"
|
| 290 |
+
},
|
| 291 |
+
new
|
| 292 |
+
{
|
| 293 |
+
Id = 3,
|
| 294 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7192),
|
| 295 |
+
Description = "Business contacts",
|
| 296 |
+
Name = "Business"
|
| 297 |
+
},
|
| 298 |
+
new
|
| 299 |
+
{
|
| 300 |
+
Id = 4,
|
| 301 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7196),
|
| 302 |
+
Description = "School contacts",
|
| 303 |
+
Name = "School"
|
| 304 |
+
},
|
| 305 |
+
new
|
| 306 |
+
{
|
| 307 |
+
Id = 5,
|
| 308 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7198),
|
| 309 |
+
Description = "Church members",
|
| 310 |
+
Name = "Church"
|
| 311 |
+
},
|
| 312 |
+
new
|
| 313 |
+
{
|
| 314 |
+
Id = 6,
|
| 315 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7199),
|
| 316 |
+
Description = "Other contacts",
|
| 317 |
+
Name = "Others"
|
| 318 |
+
},
|
| 319 |
+
new
|
| 320 |
+
{
|
| 321 |
+
Id = 7,
|
| 322 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7200),
|
| 323 |
+
Description = "College contacts",
|
| 324 |
+
Name = "College"
|
| 325 |
+
},
|
| 326 |
+
new
|
| 327 |
+
{
|
| 328 |
+
Id = 8,
|
| 329 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7202),
|
| 330 |
+
Description = "Alcoholics Anonymous",
|
| 331 |
+
Name = "AA"
|
| 332 |
+
});
|
| 333 |
+
});
|
| 334 |
+
|
| 335 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 336 |
+
{
|
| 337 |
+
b.Property<int>("Id")
|
| 338 |
+
.ValueGeneratedOnAdd()
|
| 339 |
+
.HasColumnType("int");
|
| 340 |
+
|
| 341 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 342 |
+
|
| 343 |
+
b.Property<int>("ContactId")
|
| 344 |
+
.HasColumnType("int");
|
| 345 |
+
|
| 346 |
+
b.Property<string>("ContentType")
|
| 347 |
+
.IsRequired()
|
| 348 |
+
.HasColumnType("nvarchar(max)");
|
| 349 |
+
|
| 350 |
+
b.Property<string>("FileName")
|
| 351 |
+
.IsRequired()
|
| 352 |
+
.HasColumnType("nvarchar(max)");
|
| 353 |
+
|
| 354 |
+
b.Property<long>("FileSize")
|
| 355 |
+
.HasColumnType("bigint");
|
| 356 |
+
|
| 357 |
+
b.Property<bool>("IsProfilePhoto")
|
| 358 |
+
.HasColumnType("bit");
|
| 359 |
+
|
| 360 |
+
b.Property<string>("PhotoPath")
|
| 361 |
+
.IsRequired()
|
| 362 |
+
.HasColumnType("nvarchar(max)");
|
| 363 |
+
|
| 364 |
+
b.Property<DateTime>("UploadedAt")
|
| 365 |
+
.HasColumnType("datetime2");
|
| 366 |
+
|
| 367 |
+
b.HasKey("Id");
|
| 368 |
+
|
| 369 |
+
b.HasIndex("ContactId");
|
| 370 |
+
|
| 371 |
+
b.ToTable("ContactPhotos");
|
| 372 |
+
});
|
| 373 |
+
|
| 374 |
+
modelBuilder.Entity("ContactManagementAPI.Models.GroupRight", b =>
|
| 375 |
+
{
|
| 376 |
+
b.Property<int>("Id")
|
| 377 |
+
.ValueGeneratedOnAdd()
|
| 378 |
+
.HasColumnType("int");
|
| 379 |
+
|
| 380 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 381 |
+
|
| 382 |
+
b.Property<bool>("IsGranted")
|
| 383 |
+
.HasColumnType("bit");
|
| 384 |
+
|
| 385 |
+
b.Property<string>("RightKey")
|
| 386 |
+
.IsRequired()
|
| 387 |
+
.HasMaxLength(100)
|
| 388 |
+
.HasColumnType("nvarchar(100)");
|
| 389 |
+
|
| 390 |
+
b.Property<int>("UserGroupId")
|
| 391 |
+
.HasColumnType("int");
|
| 392 |
+
|
| 393 |
+
b.HasKey("Id");
|
| 394 |
+
|
| 395 |
+
b.HasIndex("UserGroupId", "RightKey")
|
| 396 |
+
.IsUnique();
|
| 397 |
+
|
| 398 |
+
b.ToTable("GroupRights");
|
| 399 |
+
});
|
| 400 |
+
|
| 401 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserGroup", b =>
|
| 402 |
+
{
|
| 403 |
+
b.Property<int>("Id")
|
| 404 |
+
.ValueGeneratedOnAdd()
|
| 405 |
+
.HasColumnType("int");
|
| 406 |
+
|
| 407 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 408 |
+
|
| 409 |
+
b.Property<DateTime>("CreatedAt")
|
| 410 |
+
.HasColumnType("datetime2");
|
| 411 |
+
|
| 412 |
+
b.Property<string>("Description")
|
| 413 |
+
.HasMaxLength(500)
|
| 414 |
+
.HasColumnType("nvarchar(500)");
|
| 415 |
+
|
| 416 |
+
b.Property<string>("Name")
|
| 417 |
+
.IsRequired()
|
| 418 |
+
.HasMaxLength(150)
|
| 419 |
+
.HasColumnType("nvarchar(150)");
|
| 420 |
+
|
| 421 |
+
b.HasKey("Id");
|
| 422 |
+
|
| 423 |
+
b.HasIndex("Name")
|
| 424 |
+
.IsUnique();
|
| 425 |
+
|
| 426 |
+
b.ToTable("UserGroups");
|
| 427 |
+
});
|
| 428 |
+
|
| 429 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserRight", b =>
|
| 430 |
+
{
|
| 431 |
+
b.Property<int>("Id")
|
| 432 |
+
.ValueGeneratedOnAdd()
|
| 433 |
+
.HasColumnType("int");
|
| 434 |
+
|
| 435 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 436 |
+
|
| 437 |
+
b.Property<int>("AppUserId")
|
| 438 |
+
.HasColumnType("int");
|
| 439 |
+
|
| 440 |
+
b.Property<bool>("IsGranted")
|
| 441 |
+
.HasColumnType("bit");
|
| 442 |
+
|
| 443 |
+
b.Property<string>("RightKey")
|
| 444 |
+
.IsRequired()
|
| 445 |
+
.HasMaxLength(100)
|
| 446 |
+
.HasColumnType("nvarchar(100)");
|
| 447 |
+
|
| 448 |
+
b.HasKey("Id");
|
| 449 |
+
|
| 450 |
+
b.HasIndex("AppUserId", "RightKey")
|
| 451 |
+
.IsUnique();
|
| 452 |
+
|
| 453 |
+
b.ToTable("UserRights");
|
| 454 |
+
});
|
| 455 |
+
|
| 456 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 457 |
+
{
|
| 458 |
+
b.HasOne("ContactManagementAPI.Models.UserGroup", "Group")
|
| 459 |
+
.WithMany("Users")
|
| 460 |
+
.HasForeignKey("GroupId")
|
| 461 |
+
.OnDelete(DeleteBehavior.SetNull)
|
| 462 |
+
.IsRequired();
|
| 463 |
+
|
| 464 |
+
b.Navigation("Group");
|
| 465 |
+
});
|
| 466 |
+
|
| 467 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 468 |
+
{
|
| 469 |
+
b.HasOne("ContactManagementAPI.Models.ContactGroup", "Group")
|
| 470 |
+
.WithMany("Contacts")
|
| 471 |
+
.HasForeignKey("GroupId")
|
| 472 |
+
.OnDelete(DeleteBehavior.SetNull);
|
| 473 |
+
|
| 474 |
+
b.Navigation("Group");
|
| 475 |
+
});
|
| 476 |
+
|
| 477 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactBankAccount", b =>
|
| 478 |
+
{
|
| 479 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 480 |
+
.WithMany("BankAccounts")
|
| 481 |
+
.HasForeignKey("ContactId")
|
| 482 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 483 |
+
.IsRequired();
|
| 484 |
+
|
| 485 |
+
b.Navigation("Contact");
|
| 486 |
+
});
|
| 487 |
+
|
| 488 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 489 |
+
{
|
| 490 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 491 |
+
.WithMany("Documents")
|
| 492 |
+
.HasForeignKey("ContactId")
|
| 493 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 494 |
+
.IsRequired();
|
| 495 |
+
|
| 496 |
+
b.Navigation("Contact");
|
| 497 |
+
});
|
| 498 |
+
|
| 499 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 500 |
+
{
|
| 501 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 502 |
+
.WithMany("Photos")
|
| 503 |
+
.HasForeignKey("ContactId")
|
| 504 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 505 |
+
.IsRequired();
|
| 506 |
+
|
| 507 |
+
b.Navigation("Contact");
|
| 508 |
+
});
|
| 509 |
+
|
| 510 |
+
modelBuilder.Entity("ContactManagementAPI.Models.GroupRight", b =>
|
| 511 |
+
{
|
| 512 |
+
b.HasOne("ContactManagementAPI.Models.UserGroup", "UserGroup")
|
| 513 |
+
.WithMany("GroupRights")
|
| 514 |
+
.HasForeignKey("UserGroupId")
|
| 515 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 516 |
+
.IsRequired();
|
| 517 |
+
|
| 518 |
+
b.Navigation("UserGroup");
|
| 519 |
+
});
|
| 520 |
+
|
| 521 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserRight", b =>
|
| 522 |
+
{
|
| 523 |
+
b.HasOne("ContactManagementAPI.Models.AppUser", "AppUser")
|
| 524 |
+
.WithMany("UserRights")
|
| 525 |
+
.HasForeignKey("AppUserId")
|
| 526 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 527 |
+
.IsRequired();
|
| 528 |
+
|
| 529 |
+
b.Navigation("AppUser");
|
| 530 |
+
});
|
| 531 |
+
|
| 532 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 533 |
+
{
|
| 534 |
+
b.Navigation("UserRights");
|
| 535 |
+
});
|
| 536 |
+
|
| 537 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 538 |
+
{
|
| 539 |
+
b.Navigation("BankAccounts");
|
| 540 |
+
|
| 541 |
+
b.Navigation("Documents");
|
| 542 |
+
|
| 543 |
+
b.Navigation("Photos");
|
| 544 |
+
});
|
| 545 |
+
|
| 546 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 547 |
+
{
|
| 548 |
+
b.Navigation("Contacts");
|
| 549 |
+
});
|
| 550 |
+
|
| 551 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserGroup", b =>
|
| 552 |
+
{
|
| 553 |
+
b.Navigation("GroupRights");
|
| 554 |
+
|
| 555 |
+
b.Navigation("Users");
|
| 556 |
+
});
|
| 557 |
+
#pragma warning restore 612, 618
|
| 558 |
+
}
|
| 559 |
+
}
|
| 560 |
+
}
|
ContactManagementAPI/Migrations/20260221045734_AddPanNumberToContact.cs
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
using Microsoft.EntityFrameworkCore.Migrations;
|
| 3 |
+
|
| 4 |
+
#nullable disable
|
| 5 |
+
|
| 6 |
+
namespace ContactManagementAPI.Migrations
|
| 7 |
+
{
|
| 8 |
+
/// <inheritdoc />
|
| 9 |
+
public partial class AddPanNumberToContact : Migration
|
| 10 |
+
{
|
| 11 |
+
/// <inheritdoc />
|
| 12 |
+
protected override void Up(MigrationBuilder migrationBuilder)
|
| 13 |
+
{
|
| 14 |
+
migrationBuilder.AddColumn<string>(
|
| 15 |
+
name: "PanNumber",
|
| 16 |
+
table: "Contacts",
|
| 17 |
+
type: "nvarchar(max)",
|
| 18 |
+
nullable: true);
|
| 19 |
+
|
| 20 |
+
migrationBuilder.UpdateData(
|
| 21 |
+
table: "ContactGroups",
|
| 22 |
+
keyColumn: "Id",
|
| 23 |
+
keyValue: 1,
|
| 24 |
+
column: "CreatedAt",
|
| 25 |
+
value: new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7176));
|
| 26 |
+
|
| 27 |
+
migrationBuilder.UpdateData(
|
| 28 |
+
table: "ContactGroups",
|
| 29 |
+
keyColumn: "Id",
|
| 30 |
+
keyValue: 2,
|
| 31 |
+
column: "CreatedAt",
|
| 32 |
+
value: new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7190));
|
| 33 |
+
|
| 34 |
+
migrationBuilder.UpdateData(
|
| 35 |
+
table: "ContactGroups",
|
| 36 |
+
keyColumn: "Id",
|
| 37 |
+
keyValue: 3,
|
| 38 |
+
column: "CreatedAt",
|
| 39 |
+
value: new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7192));
|
| 40 |
+
|
| 41 |
+
migrationBuilder.UpdateData(
|
| 42 |
+
table: "ContactGroups",
|
| 43 |
+
keyColumn: "Id",
|
| 44 |
+
keyValue: 4,
|
| 45 |
+
column: "CreatedAt",
|
| 46 |
+
value: new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7196));
|
| 47 |
+
|
| 48 |
+
migrationBuilder.UpdateData(
|
| 49 |
+
table: "ContactGroups",
|
| 50 |
+
keyColumn: "Id",
|
| 51 |
+
keyValue: 5,
|
| 52 |
+
column: "CreatedAt",
|
| 53 |
+
value: new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7198));
|
| 54 |
+
|
| 55 |
+
migrationBuilder.UpdateData(
|
| 56 |
+
table: "ContactGroups",
|
| 57 |
+
keyColumn: "Id",
|
| 58 |
+
keyValue: 6,
|
| 59 |
+
column: "CreatedAt",
|
| 60 |
+
value: new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7199));
|
| 61 |
+
|
| 62 |
+
migrationBuilder.UpdateData(
|
| 63 |
+
table: "ContactGroups",
|
| 64 |
+
keyColumn: "Id",
|
| 65 |
+
keyValue: 7,
|
| 66 |
+
column: "CreatedAt",
|
| 67 |
+
value: new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7200));
|
| 68 |
+
|
| 69 |
+
migrationBuilder.UpdateData(
|
| 70 |
+
table: "ContactGroups",
|
| 71 |
+
keyColumn: "Id",
|
| 72 |
+
keyValue: 8,
|
| 73 |
+
column: "CreatedAt",
|
| 74 |
+
value: new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7202));
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
/// <inheritdoc />
|
| 78 |
+
protected override void Down(MigrationBuilder migrationBuilder)
|
| 79 |
+
{
|
| 80 |
+
migrationBuilder.DropColumn(
|
| 81 |
+
name: "PanNumber",
|
| 82 |
+
table: "Contacts");
|
| 83 |
+
|
| 84 |
+
migrationBuilder.UpdateData(
|
| 85 |
+
table: "ContactGroups",
|
| 86 |
+
keyColumn: "Id",
|
| 87 |
+
keyValue: 1,
|
| 88 |
+
column: "CreatedAt",
|
| 89 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4198));
|
| 90 |
+
|
| 91 |
+
migrationBuilder.UpdateData(
|
| 92 |
+
table: "ContactGroups",
|
| 93 |
+
keyColumn: "Id",
|
| 94 |
+
keyValue: 2,
|
| 95 |
+
column: "CreatedAt",
|
| 96 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4211));
|
| 97 |
+
|
| 98 |
+
migrationBuilder.UpdateData(
|
| 99 |
+
table: "ContactGroups",
|
| 100 |
+
keyColumn: "Id",
|
| 101 |
+
keyValue: 3,
|
| 102 |
+
column: "CreatedAt",
|
| 103 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4213));
|
| 104 |
+
|
| 105 |
+
migrationBuilder.UpdateData(
|
| 106 |
+
table: "ContactGroups",
|
| 107 |
+
keyColumn: "Id",
|
| 108 |
+
keyValue: 4,
|
| 109 |
+
column: "CreatedAt",
|
| 110 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4214));
|
| 111 |
+
|
| 112 |
+
migrationBuilder.UpdateData(
|
| 113 |
+
table: "ContactGroups",
|
| 114 |
+
keyColumn: "Id",
|
| 115 |
+
keyValue: 5,
|
| 116 |
+
column: "CreatedAt",
|
| 117 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4216));
|
| 118 |
+
|
| 119 |
+
migrationBuilder.UpdateData(
|
| 120 |
+
table: "ContactGroups",
|
| 121 |
+
keyColumn: "Id",
|
| 122 |
+
keyValue: 6,
|
| 123 |
+
column: "CreatedAt",
|
| 124 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4217));
|
| 125 |
+
|
| 126 |
+
migrationBuilder.UpdateData(
|
| 127 |
+
table: "ContactGroups",
|
| 128 |
+
keyColumn: "Id",
|
| 129 |
+
keyValue: 7,
|
| 130 |
+
column: "CreatedAt",
|
| 131 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4218));
|
| 132 |
+
|
| 133 |
+
migrationBuilder.UpdateData(
|
| 134 |
+
table: "ContactGroups",
|
| 135 |
+
keyColumn: "Id",
|
| 136 |
+
keyValue: 8,
|
| 137 |
+
column: "CreatedAt",
|
| 138 |
+
value: new DateTime(2026, 2, 20, 22, 49, 18, 470, DateTimeKind.Local).AddTicks(4220));
|
| 139 |
+
}
|
| 140 |
+
}
|
| 141 |
+
}
|
ContactManagementAPI/Migrations/ApplicationDbContextModelSnapshot.cs
ADDED
|
@@ -0,0 +1,557 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// <auto-generated />
|
| 2 |
+
using System;
|
| 3 |
+
using ContactManagementAPI.Data;
|
| 4 |
+
using Microsoft.EntityFrameworkCore;
|
| 5 |
+
using Microsoft.EntityFrameworkCore.Infrastructure;
|
| 6 |
+
using Microsoft.EntityFrameworkCore.Metadata;
|
| 7 |
+
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
| 8 |
+
|
| 9 |
+
#nullable disable
|
| 10 |
+
|
| 11 |
+
namespace ContactManagementAPI.Migrations
|
| 12 |
+
{
|
| 13 |
+
[DbContext(typeof(ApplicationDbContext))]
|
| 14 |
+
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
|
| 15 |
+
{
|
| 16 |
+
protected override void BuildModel(ModelBuilder modelBuilder)
|
| 17 |
+
{
|
| 18 |
+
#pragma warning disable 612, 618
|
| 19 |
+
modelBuilder
|
| 20 |
+
.HasAnnotation("ProductVersion", "8.0.0")
|
| 21 |
+
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
| 22 |
+
|
| 23 |
+
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
| 24 |
+
|
| 25 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 26 |
+
{
|
| 27 |
+
b.Property<int>("Id")
|
| 28 |
+
.ValueGeneratedOnAdd()
|
| 29 |
+
.HasColumnType("int");
|
| 30 |
+
|
| 31 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 32 |
+
|
| 33 |
+
b.Property<DateTime>("CreatedAt")
|
| 34 |
+
.HasColumnType("datetime2");
|
| 35 |
+
|
| 36 |
+
b.Property<string>("FullName")
|
| 37 |
+
.HasMaxLength(200)
|
| 38 |
+
.HasColumnType("nvarchar(200)");
|
| 39 |
+
|
| 40 |
+
b.Property<int>("GroupId")
|
| 41 |
+
.HasColumnType("int");
|
| 42 |
+
|
| 43 |
+
b.Property<bool>("IsActive")
|
| 44 |
+
.HasColumnType("bit");
|
| 45 |
+
|
| 46 |
+
b.Property<bool>("IsAdmin")
|
| 47 |
+
.HasColumnType("bit");
|
| 48 |
+
|
| 49 |
+
b.Property<string>("PasswordHash")
|
| 50 |
+
.IsRequired()
|
| 51 |
+
.HasColumnType("nvarchar(max)");
|
| 52 |
+
|
| 53 |
+
b.Property<DateTime>("UpdatedAt")
|
| 54 |
+
.HasColumnType("datetime2");
|
| 55 |
+
|
| 56 |
+
b.Property<string>("UserName")
|
| 57 |
+
.IsRequired()
|
| 58 |
+
.HasMaxLength(100)
|
| 59 |
+
.HasColumnType("nvarchar(100)");
|
| 60 |
+
|
| 61 |
+
b.HasKey("Id");
|
| 62 |
+
|
| 63 |
+
b.HasIndex("GroupId");
|
| 64 |
+
|
| 65 |
+
b.HasIndex("UserName")
|
| 66 |
+
.IsUnique();
|
| 67 |
+
|
| 68 |
+
b.ToTable("AppUsers");
|
| 69 |
+
});
|
| 70 |
+
|
| 71 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 72 |
+
{
|
| 73 |
+
b.Property<int>("Id")
|
| 74 |
+
.ValueGeneratedOnAdd()
|
| 75 |
+
.HasColumnType("int");
|
| 76 |
+
|
| 77 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 78 |
+
|
| 79 |
+
b.Property<string>("AadharNumber")
|
| 80 |
+
.HasColumnType("nvarchar(max)");
|
| 81 |
+
|
| 82 |
+
b.Property<string>("Address")
|
| 83 |
+
.HasColumnType("nvarchar(max)");
|
| 84 |
+
|
| 85 |
+
b.Property<string>("BankAccountNumber")
|
| 86 |
+
.HasColumnType("nvarchar(max)");
|
| 87 |
+
|
| 88 |
+
b.Property<string>("BankName")
|
| 89 |
+
.HasColumnType("nvarchar(max)");
|
| 90 |
+
|
| 91 |
+
b.Property<string>("BranchName")
|
| 92 |
+
.HasColumnType("nvarchar(max)");
|
| 93 |
+
|
| 94 |
+
b.Property<string>("City")
|
| 95 |
+
.HasColumnType("nvarchar(max)");
|
| 96 |
+
|
| 97 |
+
b.Property<string>("Country")
|
| 98 |
+
.HasColumnType("nvarchar(max)");
|
| 99 |
+
|
| 100 |
+
b.Property<DateTime>("CreatedAt")
|
| 101 |
+
.HasColumnType("datetime2");
|
| 102 |
+
|
| 103 |
+
b.Property<DateTime?>("DateOfBirth")
|
| 104 |
+
.HasColumnType("datetime2");
|
| 105 |
+
|
| 106 |
+
b.Property<string>("DrivingLicenseNumber")
|
| 107 |
+
.HasColumnType("nvarchar(max)");
|
| 108 |
+
|
| 109 |
+
b.Property<string>("Email")
|
| 110 |
+
.HasColumnType("nvarchar(max)");
|
| 111 |
+
|
| 112 |
+
b.Property<string>("FirstName")
|
| 113 |
+
.IsRequired()
|
| 114 |
+
.HasColumnType("nvarchar(max)");
|
| 115 |
+
|
| 116 |
+
b.Property<string>("Gender")
|
| 117 |
+
.HasColumnType("nvarchar(max)");
|
| 118 |
+
|
| 119 |
+
b.Property<int?>("GroupId")
|
| 120 |
+
.HasColumnType("int");
|
| 121 |
+
|
| 122 |
+
b.Property<string>("IfscCode")
|
| 123 |
+
.HasColumnType("nvarchar(max)");
|
| 124 |
+
|
| 125 |
+
b.Property<string>("LastName")
|
| 126 |
+
.HasColumnType("nvarchar(max)");
|
| 127 |
+
|
| 128 |
+
b.Property<string>("Mobile1")
|
| 129 |
+
.HasColumnType("nvarchar(max)");
|
| 130 |
+
|
| 131 |
+
b.Property<string>("Mobile2")
|
| 132 |
+
.HasColumnType("nvarchar(max)");
|
| 133 |
+
|
| 134 |
+
b.Property<string>("Mobile3")
|
| 135 |
+
.HasColumnType("nvarchar(max)");
|
| 136 |
+
|
| 137 |
+
b.Property<string>("NickName")
|
| 138 |
+
.HasColumnType("nvarchar(max)");
|
| 139 |
+
|
| 140 |
+
b.Property<string>("OtherDetails")
|
| 141 |
+
.HasColumnType("nvarchar(max)");
|
| 142 |
+
|
| 143 |
+
b.Property<string>("PanNumber")
|
| 144 |
+
.HasColumnType("nvarchar(max)");
|
| 145 |
+
|
| 146 |
+
b.Property<string>("PassportNumber")
|
| 147 |
+
.HasColumnType("nvarchar(max)");
|
| 148 |
+
|
| 149 |
+
b.Property<string>("PhotoPath")
|
| 150 |
+
.HasColumnType("nvarchar(max)");
|
| 151 |
+
|
| 152 |
+
b.Property<string>("PostalCode")
|
| 153 |
+
.HasColumnType("nvarchar(max)");
|
| 154 |
+
|
| 155 |
+
b.Property<string>("State")
|
| 156 |
+
.HasColumnType("nvarchar(max)");
|
| 157 |
+
|
| 158 |
+
b.Property<DateTime>("UpdatedAt")
|
| 159 |
+
.HasColumnType("datetime2");
|
| 160 |
+
|
| 161 |
+
b.Property<string>("VotersId")
|
| 162 |
+
.HasColumnType("nvarchar(max)");
|
| 163 |
+
|
| 164 |
+
b.Property<string>("WhatsAppNumber")
|
| 165 |
+
.HasColumnType("nvarchar(max)");
|
| 166 |
+
|
| 167 |
+
b.HasKey("Id");
|
| 168 |
+
|
| 169 |
+
b.HasIndex("GroupId");
|
| 170 |
+
|
| 171 |
+
b.ToTable("Contacts");
|
| 172 |
+
});
|
| 173 |
+
|
| 174 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactBankAccount", b =>
|
| 175 |
+
{
|
| 176 |
+
b.Property<int>("Id")
|
| 177 |
+
.ValueGeneratedOnAdd()
|
| 178 |
+
.HasColumnType("int");
|
| 179 |
+
|
| 180 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 181 |
+
|
| 182 |
+
b.Property<string>("AccountNumber")
|
| 183 |
+
.HasColumnType("nvarchar(max)");
|
| 184 |
+
|
| 185 |
+
b.Property<string>("BankName")
|
| 186 |
+
.HasColumnType("nvarchar(max)");
|
| 187 |
+
|
| 188 |
+
b.Property<string>("BranchName")
|
| 189 |
+
.HasColumnType("nvarchar(max)");
|
| 190 |
+
|
| 191 |
+
b.Property<int>("ContactId")
|
| 192 |
+
.HasColumnType("int");
|
| 193 |
+
|
| 194 |
+
b.Property<DateTime>("CreatedAt")
|
| 195 |
+
.HasColumnType("datetime2");
|
| 196 |
+
|
| 197 |
+
b.Property<string>("IfscCode")
|
| 198 |
+
.HasColumnType("nvarchar(max)");
|
| 199 |
+
|
| 200 |
+
b.Property<DateTime>("UpdatedAt")
|
| 201 |
+
.HasColumnType("datetime2");
|
| 202 |
+
|
| 203 |
+
b.HasKey("Id");
|
| 204 |
+
|
| 205 |
+
b.HasIndex("ContactId");
|
| 206 |
+
|
| 207 |
+
b.ToTable("ContactBankAccounts");
|
| 208 |
+
});
|
| 209 |
+
|
| 210 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 211 |
+
{
|
| 212 |
+
b.Property<int>("Id")
|
| 213 |
+
.ValueGeneratedOnAdd()
|
| 214 |
+
.HasColumnType("int");
|
| 215 |
+
|
| 216 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 217 |
+
|
| 218 |
+
b.Property<int>("ContactId")
|
| 219 |
+
.HasColumnType("int");
|
| 220 |
+
|
| 221 |
+
b.Property<string>("ContentType")
|
| 222 |
+
.IsRequired()
|
| 223 |
+
.HasColumnType("nvarchar(max)");
|
| 224 |
+
|
| 225 |
+
b.Property<string>("DocumentPath")
|
| 226 |
+
.IsRequired()
|
| 227 |
+
.HasColumnType("nvarchar(max)");
|
| 228 |
+
|
| 229 |
+
b.Property<string>("DocumentType")
|
| 230 |
+
.IsRequired()
|
| 231 |
+
.HasColumnType("nvarchar(max)");
|
| 232 |
+
|
| 233 |
+
b.Property<string>("FileName")
|
| 234 |
+
.IsRequired()
|
| 235 |
+
.HasColumnType("nvarchar(max)");
|
| 236 |
+
|
| 237 |
+
b.Property<long>("FileSize")
|
| 238 |
+
.HasColumnType("bigint");
|
| 239 |
+
|
| 240 |
+
b.Property<DateTime>("UploadedAt")
|
| 241 |
+
.HasColumnType("datetime2");
|
| 242 |
+
|
| 243 |
+
b.HasKey("Id");
|
| 244 |
+
|
| 245 |
+
b.HasIndex("ContactId");
|
| 246 |
+
|
| 247 |
+
b.ToTable("ContactDocuments");
|
| 248 |
+
});
|
| 249 |
+
|
| 250 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 251 |
+
{
|
| 252 |
+
b.Property<int>("Id")
|
| 253 |
+
.ValueGeneratedOnAdd()
|
| 254 |
+
.HasColumnType("int");
|
| 255 |
+
|
| 256 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 257 |
+
|
| 258 |
+
b.Property<DateTime>("CreatedAt")
|
| 259 |
+
.HasColumnType("datetime2");
|
| 260 |
+
|
| 261 |
+
b.Property<string>("Description")
|
| 262 |
+
.IsRequired()
|
| 263 |
+
.HasColumnType("nvarchar(max)");
|
| 264 |
+
|
| 265 |
+
b.Property<string>("Name")
|
| 266 |
+
.IsRequired()
|
| 267 |
+
.HasColumnType("nvarchar(max)");
|
| 268 |
+
|
| 269 |
+
b.HasKey("Id");
|
| 270 |
+
|
| 271 |
+
b.ToTable("ContactGroups");
|
| 272 |
+
|
| 273 |
+
b.HasData(
|
| 274 |
+
new
|
| 275 |
+
{
|
| 276 |
+
Id = 1,
|
| 277 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7176),
|
| 278 |
+
Description = "Family members",
|
| 279 |
+
Name = "Family"
|
| 280 |
+
},
|
| 281 |
+
new
|
| 282 |
+
{
|
| 283 |
+
Id = 2,
|
| 284 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7190),
|
| 285 |
+
Description = "Friends",
|
| 286 |
+
Name = "Friends"
|
| 287 |
+
},
|
| 288 |
+
new
|
| 289 |
+
{
|
| 290 |
+
Id = 3,
|
| 291 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7192),
|
| 292 |
+
Description = "Business contacts",
|
| 293 |
+
Name = "Business"
|
| 294 |
+
},
|
| 295 |
+
new
|
| 296 |
+
{
|
| 297 |
+
Id = 4,
|
| 298 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7196),
|
| 299 |
+
Description = "School contacts",
|
| 300 |
+
Name = "School"
|
| 301 |
+
},
|
| 302 |
+
new
|
| 303 |
+
{
|
| 304 |
+
Id = 5,
|
| 305 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7198),
|
| 306 |
+
Description = "Church members",
|
| 307 |
+
Name = "Church"
|
| 308 |
+
},
|
| 309 |
+
new
|
| 310 |
+
{
|
| 311 |
+
Id = 6,
|
| 312 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7199),
|
| 313 |
+
Description = "Other contacts",
|
| 314 |
+
Name = "Others"
|
| 315 |
+
},
|
| 316 |
+
new
|
| 317 |
+
{
|
| 318 |
+
Id = 7,
|
| 319 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7200),
|
| 320 |
+
Description = "College contacts",
|
| 321 |
+
Name = "College"
|
| 322 |
+
},
|
| 323 |
+
new
|
| 324 |
+
{
|
| 325 |
+
Id = 8,
|
| 326 |
+
CreatedAt = new DateTime(2026, 2, 21, 10, 27, 31, 12, DateTimeKind.Local).AddTicks(7202),
|
| 327 |
+
Description = "Alcoholics Anonymous",
|
| 328 |
+
Name = "AA"
|
| 329 |
+
});
|
| 330 |
+
});
|
| 331 |
+
|
| 332 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 333 |
+
{
|
| 334 |
+
b.Property<int>("Id")
|
| 335 |
+
.ValueGeneratedOnAdd()
|
| 336 |
+
.HasColumnType("int");
|
| 337 |
+
|
| 338 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 339 |
+
|
| 340 |
+
b.Property<int>("ContactId")
|
| 341 |
+
.HasColumnType("int");
|
| 342 |
+
|
| 343 |
+
b.Property<string>("ContentType")
|
| 344 |
+
.IsRequired()
|
| 345 |
+
.HasColumnType("nvarchar(max)");
|
| 346 |
+
|
| 347 |
+
b.Property<string>("FileName")
|
| 348 |
+
.IsRequired()
|
| 349 |
+
.HasColumnType("nvarchar(max)");
|
| 350 |
+
|
| 351 |
+
b.Property<long>("FileSize")
|
| 352 |
+
.HasColumnType("bigint");
|
| 353 |
+
|
| 354 |
+
b.Property<bool>("IsProfilePhoto")
|
| 355 |
+
.HasColumnType("bit");
|
| 356 |
+
|
| 357 |
+
b.Property<string>("PhotoPath")
|
| 358 |
+
.IsRequired()
|
| 359 |
+
.HasColumnType("nvarchar(max)");
|
| 360 |
+
|
| 361 |
+
b.Property<DateTime>("UploadedAt")
|
| 362 |
+
.HasColumnType("datetime2");
|
| 363 |
+
|
| 364 |
+
b.HasKey("Id");
|
| 365 |
+
|
| 366 |
+
b.HasIndex("ContactId");
|
| 367 |
+
|
| 368 |
+
b.ToTable("ContactPhotos");
|
| 369 |
+
});
|
| 370 |
+
|
| 371 |
+
modelBuilder.Entity("ContactManagementAPI.Models.GroupRight", b =>
|
| 372 |
+
{
|
| 373 |
+
b.Property<int>("Id")
|
| 374 |
+
.ValueGeneratedOnAdd()
|
| 375 |
+
.HasColumnType("int");
|
| 376 |
+
|
| 377 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 378 |
+
|
| 379 |
+
b.Property<bool>("IsGranted")
|
| 380 |
+
.HasColumnType("bit");
|
| 381 |
+
|
| 382 |
+
b.Property<string>("RightKey")
|
| 383 |
+
.IsRequired()
|
| 384 |
+
.HasMaxLength(100)
|
| 385 |
+
.HasColumnType("nvarchar(100)");
|
| 386 |
+
|
| 387 |
+
b.Property<int>("UserGroupId")
|
| 388 |
+
.HasColumnType("int");
|
| 389 |
+
|
| 390 |
+
b.HasKey("Id");
|
| 391 |
+
|
| 392 |
+
b.HasIndex("UserGroupId", "RightKey")
|
| 393 |
+
.IsUnique();
|
| 394 |
+
|
| 395 |
+
b.ToTable("GroupRights");
|
| 396 |
+
});
|
| 397 |
+
|
| 398 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserGroup", b =>
|
| 399 |
+
{
|
| 400 |
+
b.Property<int>("Id")
|
| 401 |
+
.ValueGeneratedOnAdd()
|
| 402 |
+
.HasColumnType("int");
|
| 403 |
+
|
| 404 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 405 |
+
|
| 406 |
+
b.Property<DateTime>("CreatedAt")
|
| 407 |
+
.HasColumnType("datetime2");
|
| 408 |
+
|
| 409 |
+
b.Property<string>("Description")
|
| 410 |
+
.HasMaxLength(500)
|
| 411 |
+
.HasColumnType("nvarchar(500)");
|
| 412 |
+
|
| 413 |
+
b.Property<string>("Name")
|
| 414 |
+
.IsRequired()
|
| 415 |
+
.HasMaxLength(150)
|
| 416 |
+
.HasColumnType("nvarchar(150)");
|
| 417 |
+
|
| 418 |
+
b.HasKey("Id");
|
| 419 |
+
|
| 420 |
+
b.HasIndex("Name")
|
| 421 |
+
.IsUnique();
|
| 422 |
+
|
| 423 |
+
b.ToTable("UserGroups");
|
| 424 |
+
});
|
| 425 |
+
|
| 426 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserRight", b =>
|
| 427 |
+
{
|
| 428 |
+
b.Property<int>("Id")
|
| 429 |
+
.ValueGeneratedOnAdd()
|
| 430 |
+
.HasColumnType("int");
|
| 431 |
+
|
| 432 |
+
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
| 433 |
+
|
| 434 |
+
b.Property<int>("AppUserId")
|
| 435 |
+
.HasColumnType("int");
|
| 436 |
+
|
| 437 |
+
b.Property<bool>("IsGranted")
|
| 438 |
+
.HasColumnType("bit");
|
| 439 |
+
|
| 440 |
+
b.Property<string>("RightKey")
|
| 441 |
+
.IsRequired()
|
| 442 |
+
.HasMaxLength(100)
|
| 443 |
+
.HasColumnType("nvarchar(100)");
|
| 444 |
+
|
| 445 |
+
b.HasKey("Id");
|
| 446 |
+
|
| 447 |
+
b.HasIndex("AppUserId", "RightKey")
|
| 448 |
+
.IsUnique();
|
| 449 |
+
|
| 450 |
+
b.ToTable("UserRights");
|
| 451 |
+
});
|
| 452 |
+
|
| 453 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 454 |
+
{
|
| 455 |
+
b.HasOne("ContactManagementAPI.Models.UserGroup", "Group")
|
| 456 |
+
.WithMany("Users")
|
| 457 |
+
.HasForeignKey("GroupId")
|
| 458 |
+
.OnDelete(DeleteBehavior.SetNull)
|
| 459 |
+
.IsRequired();
|
| 460 |
+
|
| 461 |
+
b.Navigation("Group");
|
| 462 |
+
});
|
| 463 |
+
|
| 464 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 465 |
+
{
|
| 466 |
+
b.HasOne("ContactManagementAPI.Models.ContactGroup", "Group")
|
| 467 |
+
.WithMany("Contacts")
|
| 468 |
+
.HasForeignKey("GroupId")
|
| 469 |
+
.OnDelete(DeleteBehavior.SetNull);
|
| 470 |
+
|
| 471 |
+
b.Navigation("Group");
|
| 472 |
+
});
|
| 473 |
+
|
| 474 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactBankAccount", b =>
|
| 475 |
+
{
|
| 476 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 477 |
+
.WithMany("BankAccounts")
|
| 478 |
+
.HasForeignKey("ContactId")
|
| 479 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 480 |
+
.IsRequired();
|
| 481 |
+
|
| 482 |
+
b.Navigation("Contact");
|
| 483 |
+
});
|
| 484 |
+
|
| 485 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactDocument", b =>
|
| 486 |
+
{
|
| 487 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 488 |
+
.WithMany("Documents")
|
| 489 |
+
.HasForeignKey("ContactId")
|
| 490 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 491 |
+
.IsRequired();
|
| 492 |
+
|
| 493 |
+
b.Navigation("Contact");
|
| 494 |
+
});
|
| 495 |
+
|
| 496 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactPhoto", b =>
|
| 497 |
+
{
|
| 498 |
+
b.HasOne("ContactManagementAPI.Models.Contact", "Contact")
|
| 499 |
+
.WithMany("Photos")
|
| 500 |
+
.HasForeignKey("ContactId")
|
| 501 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 502 |
+
.IsRequired();
|
| 503 |
+
|
| 504 |
+
b.Navigation("Contact");
|
| 505 |
+
});
|
| 506 |
+
|
| 507 |
+
modelBuilder.Entity("ContactManagementAPI.Models.GroupRight", b =>
|
| 508 |
+
{
|
| 509 |
+
b.HasOne("ContactManagementAPI.Models.UserGroup", "UserGroup")
|
| 510 |
+
.WithMany("GroupRights")
|
| 511 |
+
.HasForeignKey("UserGroupId")
|
| 512 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 513 |
+
.IsRequired();
|
| 514 |
+
|
| 515 |
+
b.Navigation("UserGroup");
|
| 516 |
+
});
|
| 517 |
+
|
| 518 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserRight", b =>
|
| 519 |
+
{
|
| 520 |
+
b.HasOne("ContactManagementAPI.Models.AppUser", "AppUser")
|
| 521 |
+
.WithMany("UserRights")
|
| 522 |
+
.HasForeignKey("AppUserId")
|
| 523 |
+
.OnDelete(DeleteBehavior.Cascade)
|
| 524 |
+
.IsRequired();
|
| 525 |
+
|
| 526 |
+
b.Navigation("AppUser");
|
| 527 |
+
});
|
| 528 |
+
|
| 529 |
+
modelBuilder.Entity("ContactManagementAPI.Models.AppUser", b =>
|
| 530 |
+
{
|
| 531 |
+
b.Navigation("UserRights");
|
| 532 |
+
});
|
| 533 |
+
|
| 534 |
+
modelBuilder.Entity("ContactManagementAPI.Models.Contact", b =>
|
| 535 |
+
{
|
| 536 |
+
b.Navigation("BankAccounts");
|
| 537 |
+
|
| 538 |
+
b.Navigation("Documents");
|
| 539 |
+
|
| 540 |
+
b.Navigation("Photos");
|
| 541 |
+
});
|
| 542 |
+
|
| 543 |
+
modelBuilder.Entity("ContactManagementAPI.Models.ContactGroup", b =>
|
| 544 |
+
{
|
| 545 |
+
b.Navigation("Contacts");
|
| 546 |
+
});
|
| 547 |
+
|
| 548 |
+
modelBuilder.Entity("ContactManagementAPI.Models.UserGroup", b =>
|
| 549 |
+
{
|
| 550 |
+
b.Navigation("GroupRights");
|
| 551 |
+
|
| 552 |
+
b.Navigation("Users");
|
| 553 |
+
});
|
| 554 |
+
#pragma warning restore 612, 618
|
| 555 |
+
}
|
| 556 |
+
}
|
| 557 |
+
}
|
ContactManagementAPI/Models/AdminHistoryEntry.cs
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
namespace ContactManagementAPI.Models
|
| 2 |
+
{
|
| 3 |
+
public class AdminHistoryEntry
|
| 4 |
+
{
|
| 5 |
+
public string ActionType { get; set; } = string.Empty;
|
| 6 |
+
public string EntityType { get; set; } = string.Empty;
|
| 7 |
+
public int? EntityId { get; set; }
|
| 8 |
+
public string Details { get; set; } = string.Empty;
|
| 9 |
+
public string PerformedBy { get; set; } = string.Empty;
|
| 10 |
+
public DateTime PerformedAt { get; set; }
|
| 11 |
+
}
|
| 12 |
+
}
|
ContactManagementAPI/Models/AppUser.cs
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
using System.Collections.Generic;
|
| 3 |
+
using System.ComponentModel.DataAnnotations;
|
| 4 |
+
|
| 5 |
+
namespace ContactManagementAPI.Models
|
| 6 |
+
{
|
| 7 |
+
public class AppUser
|
| 8 |
+
{
|
| 9 |
+
public int Id { get; set; }
|
| 10 |
+
|
| 11 |
+
[Required]
|
| 12 |
+
[MaxLength(100)]
|
| 13 |
+
public string UserName { get; set; } = string.Empty;
|
| 14 |
+
|
| 15 |
+
[Required]
|
| 16 |
+
public string PasswordHash { get; set; } = string.Empty;
|
| 17 |
+
|
| 18 |
+
[MaxLength(200)]
|
| 19 |
+
public string? FullName { get; set; }
|
| 20 |
+
|
| 21 |
+
public bool IsAdmin { get; set; }
|
| 22 |
+
public bool IsActive { get; set; } = true;
|
| 23 |
+
|
| 24 |
+
[Required]
|
| 25 |
+
public int GroupId { get; set; }
|
| 26 |
+
public UserGroup? Group { get; set; }
|
| 27 |
+
|
| 28 |
+
public DateTime CreatedAt { get; set; }
|
| 29 |
+
public DateTime UpdatedAt { get; set; }
|
| 30 |
+
|
| 31 |
+
public ICollection<UserRight> UserRights { get; set; } = new List<UserRight>();
|
| 32 |
+
}
|
| 33 |
+
}
|
ContactManagementAPI/Models/Contact.cs
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
using System.Collections.Generic;
|
| 3 |
+
using System.ComponentModel.DataAnnotations;
|
| 4 |
+
|
| 5 |
+
namespace ContactManagementAPI.Models
|
| 6 |
+
{
|
| 7 |
+
public class Contact
|
| 8 |
+
{
|
| 9 |
+
public int Id { get; set; }
|
| 10 |
+
[Required]
|
| 11 |
+
public string FirstName { get; set; } = string.Empty;
|
| 12 |
+
public string? LastName { get; set; }
|
| 13 |
+
public string? NickName { get; set; }
|
| 14 |
+
public string? Gender { get; set; }
|
| 15 |
+
public DateTime? DateOfBirth { get; set; }
|
| 16 |
+
public string? Email { get; set; }
|
| 17 |
+
public string? Mobile1 { get; set; }
|
| 18 |
+
public string? Mobile2 { get; set; }
|
| 19 |
+
public string? Mobile3 { get; set; }
|
| 20 |
+
public string? WhatsAppNumber { get; set; }
|
| 21 |
+
public string? PassportNumber { get; set; }
|
| 22 |
+
public string? PanNumber { get; set; }
|
| 23 |
+
public string? AadharNumber { get; set; }
|
| 24 |
+
public string? DrivingLicenseNumber { get; set; }
|
| 25 |
+
public string? VotersId { get; set; }
|
| 26 |
+
public string? BankAccountNumber { get; set; }
|
| 27 |
+
public string? BankName { get; set; }
|
| 28 |
+
public string? BranchName { get; set; }
|
| 29 |
+
public string? IfscCode { get; set; }
|
| 30 |
+
public string? Address { get; set; }
|
| 31 |
+
public string? City { get; set; }
|
| 32 |
+
public string? State { get; set; }
|
| 33 |
+
public string? PostalCode { get; set; }
|
| 34 |
+
public string? Country { get; set; }
|
| 35 |
+
public string? PhotoPath { get; set; }
|
| 36 |
+
public int? GroupId { get; set; }
|
| 37 |
+
public ContactGroup? Group { get; set; }
|
| 38 |
+
public string? OtherDetails { get; set; }
|
| 39 |
+
public DateTime CreatedAt { get; set; }
|
| 40 |
+
public DateTime UpdatedAt { get; set; }
|
| 41 |
+
|
| 42 |
+
public ICollection<ContactPhoto> Photos { get; set; } = new List<ContactPhoto>();
|
| 43 |
+
public ICollection<ContactDocument> Documents { get; set; } = new List<ContactDocument>();
|
| 44 |
+
public ICollection<ContactBankAccount> BankAccounts { get; set; } = new List<ContactBankAccount>();
|
| 45 |
+
}
|
| 46 |
+
}
|
ContactManagementAPI/Models/ContactBankAccount.cs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
namespace ContactManagementAPI.Models
|
| 2 |
+
{
|
| 3 |
+
public class ContactBankAccount
|
| 4 |
+
{
|
| 5 |
+
public int Id { get; set; }
|
| 6 |
+
public int ContactId { get; set; }
|
| 7 |
+
public Contact? Contact { get; set; }
|
| 8 |
+
public string? AccountNumber { get; set; }
|
| 9 |
+
public string? BankName { get; set; }
|
| 10 |
+
public string? BranchName { get; set; }
|
| 11 |
+
public string? IfscCode { get; set; }
|
| 12 |
+
public DateTime CreatedAt { get; set; }
|
| 13 |
+
public DateTime UpdatedAt { get; set; }
|
| 14 |
+
}
|
| 15 |
+
}
|
ContactManagementAPI/Models/ContactDocument.cs
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
|
| 3 |
+
namespace ContactManagementAPI.Models
|
| 4 |
+
{
|
| 5 |
+
public class ContactDocument
|
| 6 |
+
{
|
| 7 |
+
public int Id { get; set; }
|
| 8 |
+
public int ContactId { get; set; }
|
| 9 |
+
public Contact Contact { get; set; }
|
| 10 |
+
public string DocumentPath { get; set; }
|
| 11 |
+
public string FileName { get; set; }
|
| 12 |
+
public long FileSize { get; set; }
|
| 13 |
+
public string ContentType { get; set; }
|
| 14 |
+
public string DocumentType { get; set; } // e.g., "ID", "Address", "Contract", etc.
|
| 15 |
+
public DateTime UploadedAt { get; set; }
|
| 16 |
+
}
|
| 17 |
+
}
|
ContactManagementAPI/Models/ContactGroup.cs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
using System.Collections.Generic;
|
| 3 |
+
|
| 4 |
+
namespace ContactManagementAPI.Models
|
| 5 |
+
{
|
| 6 |
+
public class ContactGroup
|
| 7 |
+
{
|
| 8 |
+
public int Id { get; set; }
|
| 9 |
+
public string Name { get; set; }
|
| 10 |
+
public string Description { get; set; }
|
| 11 |
+
public DateTime CreatedAt { get; set; }
|
| 12 |
+
|
| 13 |
+
public ICollection<Contact> Contacts { get; set; } = new List<Contact>();
|
| 14 |
+
}
|
| 15 |
+
}
|
ContactManagementAPI/Models/ContactPhoto.cs
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
|
| 3 |
+
namespace ContactManagementAPI.Models
|
| 4 |
+
{
|
| 5 |
+
public class ContactPhoto
|
| 6 |
+
{
|
| 7 |
+
public int Id { get; set; }
|
| 8 |
+
public int ContactId { get; set; }
|
| 9 |
+
public Contact Contact { get; set; }
|
| 10 |
+
public string PhotoPath { get; set; }
|
| 11 |
+
public string FileName { get; set; }
|
| 12 |
+
public long FileSize { get; set; }
|
| 13 |
+
public string ContentType { get; set; }
|
| 14 |
+
public bool IsProfilePhoto { get; set; }
|
| 15 |
+
public DateTime UploadedAt { get; set; }
|
| 16 |
+
}
|
| 17 |
+
}
|
ContactManagementAPI/Models/GroupRight.cs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System.ComponentModel.DataAnnotations;
|
| 2 |
+
|
| 3 |
+
namespace ContactManagementAPI.Models
|
| 4 |
+
{
|
| 5 |
+
public class GroupRight
|
| 6 |
+
{
|
| 7 |
+
public int Id { get; set; }
|
| 8 |
+
|
| 9 |
+
public int UserGroupId { get; set; }
|
| 10 |
+
public UserGroup? UserGroup { get; set; }
|
| 11 |
+
|
| 12 |
+
[Required]
|
| 13 |
+
[MaxLength(100)]
|
| 14 |
+
public string RightKey { get; set; } = string.Empty;
|
| 15 |
+
|
| 16 |
+
public bool IsGranted { get; set; }
|
| 17 |
+
}
|
| 18 |
+
}
|
ContactManagementAPI/Models/RightsCatalog.cs
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System.Collections.Generic;
|
| 2 |
+
|
| 3 |
+
namespace ContactManagementAPI.Models
|
| 4 |
+
{
|
| 5 |
+
public static class RightsCatalog
|
| 6 |
+
{
|
| 7 |
+
public const string ContactsView = "Contacts.View";
|
| 8 |
+
public const string ContactsCreate = "Contacts.Create";
|
| 9 |
+
public const string ContactsEdit = "Contacts.Edit";
|
| 10 |
+
public const string ContactsDelete = "Contacts.Delete";
|
| 11 |
+
public const string DocumentsManage = "Documents.Manage";
|
| 12 |
+
public const string PhotosManage = "Photos.Manage";
|
| 13 |
+
public const string AdminManageUsers = "Admin.ManageUsers";
|
| 14 |
+
public const string AdminManageGroups = "Admin.ManageGroups";
|
| 15 |
+
public const string AdminManageRights = "Admin.ManageRights";
|
| 16 |
+
|
| 17 |
+
public static readonly IReadOnlyList<RightDefinition> All = new List<RightDefinition>
|
| 18 |
+
{
|
| 19 |
+
new RightDefinition(ContactsView, "Contacts", "View contacts"),
|
| 20 |
+
new RightDefinition(ContactsCreate, "Contacts", "Create contacts"),
|
| 21 |
+
new RightDefinition(ContactsEdit, "Contacts", "Edit contacts"),
|
| 22 |
+
new RightDefinition(ContactsDelete, "Contacts", "Delete contacts"),
|
| 23 |
+
new RightDefinition(PhotosManage, "Photos", "Manage photo gallery"),
|
| 24 |
+
new RightDefinition(DocumentsManage, "Documents", "Manage contact documents"),
|
| 25 |
+
new RightDefinition(AdminManageUsers, "Administration", "Manage users"),
|
| 26 |
+
new RightDefinition(AdminManageGroups, "Administration", "Manage user groups"),
|
| 27 |
+
new RightDefinition(AdminManageRights, "Administration", "Manage rights")
|
| 28 |
+
};
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
public class RightDefinition
|
| 32 |
+
{
|
| 33 |
+
public RightDefinition(string key, string category, string label)
|
| 34 |
+
{
|
| 35 |
+
Key = key;
|
| 36 |
+
Category = category;
|
| 37 |
+
Label = label;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
public string Key { get; }
|
| 41 |
+
public string Category { get; }
|
| 42 |
+
public string Label { get; }
|
| 43 |
+
}
|
| 44 |
+
}
|
ContactManagementAPI/Models/UserGroup.cs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
using System.Collections.Generic;
|
| 3 |
+
using System.ComponentModel.DataAnnotations;
|
| 4 |
+
|
| 5 |
+
namespace ContactManagementAPI.Models
|
| 6 |
+
{
|
| 7 |
+
public class UserGroup
|
| 8 |
+
{
|
| 9 |
+
public int Id { get; set; }
|
| 10 |
+
|
| 11 |
+
[Required]
|
| 12 |
+
[MaxLength(150)]
|
| 13 |
+
public string Name { get; set; } = string.Empty;
|
| 14 |
+
|
| 15 |
+
[MaxLength(500)]
|
| 16 |
+
public string? Description { get; set; }
|
| 17 |
+
|
| 18 |
+
public DateTime CreatedAt { get; set; }
|
| 19 |
+
|
| 20 |
+
public ICollection<AppUser> Users { get; set; } = new List<AppUser>();
|
| 21 |
+
public ICollection<GroupRight> GroupRights { get; set; } = new List<GroupRight>();
|
| 22 |
+
}
|
| 23 |
+
}
|
ContactManagementAPI/Models/UserRight.cs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System.ComponentModel.DataAnnotations;
|
| 2 |
+
|
| 3 |
+
namespace ContactManagementAPI.Models
|
| 4 |
+
{
|
| 5 |
+
public class UserRight
|
| 6 |
+
{
|
| 7 |
+
public int Id { get; set; }
|
| 8 |
+
|
| 9 |
+
public int AppUserId { get; set; }
|
| 10 |
+
public AppUser? AppUser { get; set; }
|
| 11 |
+
|
| 12 |
+
[Required]
|
| 13 |
+
[MaxLength(100)]
|
| 14 |
+
public string RightKey { get; set; } = string.Empty;
|
| 15 |
+
|
| 16 |
+
public bool IsGranted { get; set; }
|
| 17 |
+
}
|
| 18 |
+
}
|
ContactManagementAPI/Program.cs
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using Microsoft.EntityFrameworkCore;
|
| 2 |
+
using ContactManagementAPI.Data;
|
| 3 |
+
using ContactManagementAPI.Services;
|
| 4 |
+
using Microsoft.Data.Sqlite;
|
| 5 |
+
using Microsoft.AspNetCore.HttpOverrides;
|
| 6 |
+
using Microsoft.Extensions.FileProviders;
|
| 7 |
+
|
| 8 |
+
var builder = WebApplication.CreateBuilder(args);
|
| 9 |
+
|
| 10 |
+
// Add services to the container
|
| 11 |
+
builder.Services.AddControllersWithViews()
|
| 12 |
+
.AddJsonOptions(options =>
|
| 13 |
+
{
|
| 14 |
+
// Prevent circular references
|
| 15 |
+
options.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles;
|
| 16 |
+
});
|
| 17 |
+
builder.Services.AddRazorPages();
|
| 18 |
+
builder.Services.AddHttpContextAccessor();
|
| 19 |
+
builder.Services.AddSession(options =>
|
| 20 |
+
{
|
| 21 |
+
options.Cookie.HttpOnly = true;
|
| 22 |
+
options.Cookie.IsEssential = true;
|
| 23 |
+
options.IdleTimeout = TimeSpan.FromHours(2); // Reduced from 8 to 2 hours to prevent memory buildup
|
| 24 |
+
});
|
| 25 |
+
|
| 26 |
+
// Add memory cache with size limit
|
| 27 |
+
builder.Services.AddMemoryCache(options =>
|
| 28 |
+
{
|
| 29 |
+
options.SizeLimit = 1024; // Limit cache size
|
| 30 |
+
});
|
| 31 |
+
|
| 32 |
+
// Configure Antiforgery with SameSite settings
|
| 33 |
+
builder.Services.AddAntiforgery(options =>
|
| 34 |
+
{
|
| 35 |
+
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
|
| 36 |
+
options.Cookie.SameSite = SameSiteMode.Lax;
|
| 37 |
+
});
|
| 38 |
+
|
| 39 |
+
// Configure database connection (SQLite preferred for portable installs)
|
| 40 |
+
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
|
| 41 |
+
?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
|
| 42 |
+
|
| 43 |
+
var useSqlite = connectionString.TrimStart().StartsWith("Data Source=", StringComparison.OrdinalIgnoreCase);
|
| 44 |
+
|
| 45 |
+
if (useSqlite)
|
| 46 |
+
{
|
| 47 |
+
var sqliteBuilder = new SqliteConnectionStringBuilder(connectionString);
|
| 48 |
+
var sqliteDbPathOverride = Environment.GetEnvironmentVariable("SQLITE_DB_PATH");
|
| 49 |
+
var dataSource = sqliteBuilder.DataSource;
|
| 50 |
+
|
| 51 |
+
if (!string.IsNullOrWhiteSpace(sqliteDbPathOverride))
|
| 52 |
+
{
|
| 53 |
+
dataSource = sqliteDbPathOverride;
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
if (string.IsNullOrWhiteSpace(dataSource))
|
| 57 |
+
{
|
| 58 |
+
dataSource = "ContactManagement.db";
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
if (!Path.IsPathRooted(dataSource))
|
| 62 |
+
{
|
| 63 |
+
var appDataFolder = Path.Combine(
|
| 64 |
+
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
| 65 |
+
"ContactManagementSystem");
|
| 66 |
+
|
| 67 |
+
Directory.CreateDirectory(appDataFolder);
|
| 68 |
+
dataSource = Path.Combine(appDataFolder, dataSource);
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
sqliteBuilder.DataSource = dataSource;
|
| 72 |
+
connectionString = sqliteBuilder.ToString();
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
builder.Services.AddDbContext<ApplicationDbContext>(options =>
|
| 76 |
+
{
|
| 77 |
+
if (useSqlite)
|
| 78 |
+
{
|
| 79 |
+
options.UseSqlite(connectionString);
|
| 80 |
+
}
|
| 81 |
+
else
|
| 82 |
+
{
|
| 83 |
+
options.UseSqlServer(connectionString);
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
// Optimize EF Core for better memory management
|
| 87 |
+
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
|
| 88 |
+
options.EnableSensitiveDataLogging(false);
|
| 89 |
+
options.EnableDetailedErrors(false);
|
| 90 |
+
});
|
| 91 |
+
|
| 92 |
+
// Add custom services
|
| 93 |
+
builder.Services.AddScoped<FileUploadService>();
|
| 94 |
+
builder.Services.AddScoped<AuthorizationService>();
|
| 95 |
+
builder.Services.AddScoped<UserContextService>();
|
| 96 |
+
builder.Services.AddScoped<ImportExportService>();
|
| 97 |
+
builder.Services.AddScoped<ContactStatisticsService>();
|
| 98 |
+
builder.Services.AddScoped<AdminHistoryService>();
|
| 99 |
+
|
| 100 |
+
// Configure CORS if needed for future API consumption
|
| 101 |
+
builder.Services.AddCors(options =>
|
| 102 |
+
{
|
| 103 |
+
options.AddPolicy("AllowAll", policy =>
|
| 104 |
+
{
|
| 105 |
+
policy.WithOrigins("http://localhost:5000", "https://localhost:5001")
|
| 106 |
+
.AllowAnyMethod()
|
| 107 |
+
.AllowAnyHeader()
|
| 108 |
+
.AllowCredentials();
|
| 109 |
+
});
|
| 110 |
+
});
|
| 111 |
+
|
| 112 |
+
var app = builder.Build();
|
| 113 |
+
|
| 114 |
+
// Support reverse proxies/load balancers in cloud hosting
|
| 115 |
+
app.UseForwardedHeaders(new ForwardedHeadersOptions
|
| 116 |
+
{
|
| 117 |
+
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
|
| 118 |
+
});
|
| 119 |
+
|
| 120 |
+
var disableHttpsRedirection =
|
| 121 |
+
app.Configuration.GetValue<bool>("DisableHttpsRedirection") ||
|
| 122 |
+
string.Equals(Environment.GetEnvironmentVariable("DISABLE_HTTPS_REDIRECTION"), "true", StringComparison.OrdinalIgnoreCase);
|
| 123 |
+
|
| 124 |
+
// Ensure database exists and seed defaults
|
| 125 |
+
using (var scope = app.Services.CreateScope())
|
| 126 |
+
{
|
| 127 |
+
var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
| 128 |
+
|
| 129 |
+
if (useSqlite)
|
| 130 |
+
{
|
| 131 |
+
dbContext.Database.EnsureCreated();
|
| 132 |
+
}
|
| 133 |
+
else
|
| 134 |
+
{
|
| 135 |
+
dbContext.Database.Migrate();
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
SeedData.Initialize(dbContext);
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
// Configure the HTTP request pipeline
|
| 142 |
+
if (!app.Environment.IsDevelopment())
|
| 143 |
+
{
|
| 144 |
+
app.UseExceptionHandler("/Home/Error");
|
| 145 |
+
app.UseHsts();
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
if (!disableHttpsRedirection)
|
| 149 |
+
{
|
| 150 |
+
app.UseHttpsRedirection();
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
app.UseStaticFiles();
|
| 154 |
+
|
| 155 |
+
var uploadsRoot = Environment.GetEnvironmentVariable("UPLOADS_ROOT");
|
| 156 |
+
if (!string.IsNullOrWhiteSpace(uploadsRoot) && Directory.Exists(uploadsRoot))
|
| 157 |
+
{
|
| 158 |
+
Directory.CreateDirectory(Path.Combine(uploadsRoot, "photos"));
|
| 159 |
+
Directory.CreateDirectory(Path.Combine(uploadsRoot, "documents"));
|
| 160 |
+
|
| 161 |
+
app.UseStaticFiles(new StaticFileOptions
|
| 162 |
+
{
|
| 163 |
+
FileProvider = new PhysicalFileProvider(uploadsRoot),
|
| 164 |
+
RequestPath = "/uploads"
|
| 165 |
+
});
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
app.UseRouting();
|
| 169 |
+
app.UseSession();
|
| 170 |
+
app.UseCors("AllowAll");
|
| 171 |
+
app.UseAuthorization();
|
| 172 |
+
|
| 173 |
+
app.MapControllerRoute(
|
| 174 |
+
name: "default",
|
| 175 |
+
pattern: "{controller=Home}/{action=Index}/{id?}");
|
| 176 |
+
|
| 177 |
+
app.MapRazorPages();
|
| 178 |
+
|
| 179 |
+
app.Run();
|
ContactManagementAPI/Properties/launchSettings.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"iisSettings": {
|
| 3 |
+
"windowsAuthentication": false,
|
| 4 |
+
"anonymousAuthentication": true,
|
| 5 |
+
"iisExpress": {
|
| 6 |
+
"applicationUrl": "http://localhost:7089",
|
| 7 |
+
"sslPort": 44318
|
| 8 |
+
}
|
| 9 |
+
},
|
| 10 |
+
"profiles": {
|
| 11 |
+
"http": {
|
| 12 |
+
"commandName": "Project",
|
| 13 |
+
"dotnetRunMessages": true,
|
| 14 |
+
"launchBrowser": true,
|
| 15 |
+
"applicationUrl": "http://localhost:5000",
|
| 16 |
+
"environmentVariables": {
|
| 17 |
+
"ASPNETCORE_ENVIRONMENT": "Development"
|
| 18 |
+
}
|
| 19 |
+
},
|
| 20 |
+
"https": {
|
| 21 |
+
"commandName": "Project",
|
| 22 |
+
"dotnetRunMessages": true,
|
| 23 |
+
"launchBrowser": true,
|
| 24 |
+
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
| 25 |
+
"environmentVariables": {
|
| 26 |
+
"ASPNETCORE_ENVIRONMENT": "Development"
|
| 27 |
+
}
|
| 28 |
+
},
|
| 29 |
+
"IIS Express": {
|
| 30 |
+
"commandName": "IISExpress",
|
| 31 |
+
"launchBrowser": true,
|
| 32 |
+
"environmentVariables": {
|
| 33 |
+
"ASPNETCORE_ENVIRONMENT": "Development"
|
| 34 |
+
}
|
| 35 |
+
}
|
| 36 |
+
}
|
| 37 |
+
}
|
ContactManagementAPI/Security/RequireRightAttribute.cs
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System.Threading.Tasks;
|
| 2 |
+
using ContactManagementAPI.Models;
|
| 3 |
+
using ContactManagementAPI.Services;
|
| 4 |
+
using Microsoft.AspNetCore.Mvc;
|
| 5 |
+
using Microsoft.AspNetCore.Mvc.Filters;
|
| 6 |
+
|
| 7 |
+
namespace ContactManagementAPI.Security
|
| 8 |
+
{
|
| 9 |
+
public class RequireRightAttribute : TypeFilterAttribute
|
| 10 |
+
{
|
| 11 |
+
public RequireRightAttribute(string rightKey) : base(typeof(RequireRightFilter))
|
| 12 |
+
{
|
| 13 |
+
Arguments = new object[] { rightKey };
|
| 14 |
+
}
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
public class RequireRightFilter : IAsyncActionFilter
|
| 18 |
+
{
|
| 19 |
+
private readonly string _rightKey;
|
| 20 |
+
private readonly UserContextService _userContext;
|
| 21 |
+
private readonly AuthorizationService _authorizationService;
|
| 22 |
+
|
| 23 |
+
public RequireRightFilter(string rightKey, UserContextService userContext, AuthorizationService authorizationService)
|
| 24 |
+
{
|
| 25 |
+
_rightKey = rightKey;
|
| 26 |
+
_userContext = userContext;
|
| 27 |
+
_authorizationService = authorizationService;
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
| 31 |
+
{
|
| 32 |
+
if (!_userContext.UserId.HasValue)
|
| 33 |
+
{
|
| 34 |
+
var returnUrl = context.HttpContext.Request.Path + context.HttpContext.Request.QueryString;
|
| 35 |
+
context.Result = new RedirectToActionResult("Login", "Account", new { returnUrl });
|
| 36 |
+
return;
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
var hasRight = _authorizationService.HasRight(_userContext.UserId.Value, _rightKey);
|
| 40 |
+
if (!hasRight)
|
| 41 |
+
{
|
| 42 |
+
context.Result = new RedirectToActionResult("AccessDenied", "Account", null);
|
| 43 |
+
return;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
await next();
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
}
|
ContactManagementAPI/Services/AdminHistoryService.cs
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System.Text.Json;
|
| 2 |
+
using ContactManagementAPI.Models;
|
| 3 |
+
|
| 4 |
+
namespace ContactManagementAPI.Services
|
| 5 |
+
{
|
| 6 |
+
public class AdminHistoryService
|
| 7 |
+
{
|
| 8 |
+
private readonly string _historyFilePath;
|
| 9 |
+
private static readonly JsonSerializerOptions JsonOptions = new()
|
| 10 |
+
{
|
| 11 |
+
WriteIndented = false
|
| 12 |
+
};
|
| 13 |
+
|
| 14 |
+
public AdminHistoryService(IWebHostEnvironment environment)
|
| 15 |
+
{
|
| 16 |
+
var historyDirectory = Path.Combine(environment.ContentRootPath, "App_Data");
|
| 17 |
+
Directory.CreateDirectory(historyDirectory);
|
| 18 |
+
_historyFilePath = Path.Combine(historyDirectory, "admin-history.jsonl");
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
public void Log(string actionType, string entityType, int? entityId, string performedBy, string details)
|
| 22 |
+
{
|
| 23 |
+
var entry = new AdminHistoryEntry
|
| 24 |
+
{
|
| 25 |
+
ActionType = actionType,
|
| 26 |
+
EntityType = entityType,
|
| 27 |
+
EntityId = entityId,
|
| 28 |
+
PerformedBy = string.IsNullOrWhiteSpace(performedBy) ? "Unknown" : performedBy,
|
| 29 |
+
Details = details,
|
| 30 |
+
PerformedAt = DateTime.Now
|
| 31 |
+
};
|
| 32 |
+
|
| 33 |
+
var line = JsonSerializer.Serialize(entry, JsonOptions);
|
| 34 |
+
File.AppendAllText(_historyFilePath, line + Environment.NewLine);
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
public IReadOnlyList<AdminHistoryEntry> GetLatest(int take = 200)
|
| 38 |
+
{
|
| 39 |
+
if (!File.Exists(_historyFilePath))
|
| 40 |
+
{
|
| 41 |
+
return Array.Empty<AdminHistoryEntry>();
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
var entries = new List<AdminHistoryEntry>();
|
| 45 |
+
var lines = File.ReadLines(_historyFilePath);
|
| 46 |
+
foreach (var line in lines)
|
| 47 |
+
{
|
| 48 |
+
if (string.IsNullOrWhiteSpace(line))
|
| 49 |
+
{
|
| 50 |
+
continue;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
try
|
| 54 |
+
{
|
| 55 |
+
var entry = JsonSerializer.Deserialize<AdminHistoryEntry>(line);
|
| 56 |
+
if (entry != null)
|
| 57 |
+
{
|
| 58 |
+
entries.Add(entry);
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
catch
|
| 62 |
+
{
|
| 63 |
+
// Ignore malformed history lines and continue
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
return entries
|
| 68 |
+
.OrderByDescending(e => e.PerformedAt)
|
| 69 |
+
.Take(take)
|
| 70 |
+
.ToList();
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
}
|
ContactManagementAPI/Services/AuthorizationService.cs
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System.Linq;
|
| 2 |
+
using ContactManagementAPI.Data;
|
| 3 |
+
using ContactManagementAPI.Models;
|
| 4 |
+
using Microsoft.EntityFrameworkCore;
|
| 5 |
+
|
| 6 |
+
namespace ContactManagementAPI.Services
|
| 7 |
+
{
|
| 8 |
+
public class AuthorizationService
|
| 9 |
+
{
|
| 10 |
+
private readonly ApplicationDbContext _context;
|
| 11 |
+
|
| 12 |
+
public AuthorizationService(ApplicationDbContext context)
|
| 13 |
+
{
|
| 14 |
+
_context = context;
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
public bool HasRight(int userId, string rightKey)
|
| 18 |
+
{
|
| 19 |
+
var user = _context.AppUsers
|
| 20 |
+
.AsNoTracking()
|
| 21 |
+
.FirstOrDefault(u => u.Id == userId);
|
| 22 |
+
|
| 23 |
+
if (user == null || !user.IsActive)
|
| 24 |
+
return false;
|
| 25 |
+
|
| 26 |
+
if (user.IsAdmin)
|
| 27 |
+
return true;
|
| 28 |
+
|
| 29 |
+
var userRight = _context.UserRights
|
| 30 |
+
.AsNoTracking()
|
| 31 |
+
.FirstOrDefault(r => r.AppUserId == userId && r.RightKey == rightKey);
|
| 32 |
+
|
| 33 |
+
if (userRight != null)
|
| 34 |
+
return userRight.IsGranted;
|
| 35 |
+
|
| 36 |
+
var groupRight = _context.GroupRights
|
| 37 |
+
.AsNoTracking()
|
| 38 |
+
.FirstOrDefault(r => r.UserGroupId == user.GroupId && r.RightKey == rightKey);
|
| 39 |
+
|
| 40 |
+
return groupRight?.IsGranted ?? false;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
public bool IsAdmin(int userId)
|
| 44 |
+
{
|
| 45 |
+
var user = _context.AppUsers
|
| 46 |
+
.AsNoTracking()
|
| 47 |
+
.FirstOrDefault(u => u.Id == userId);
|
| 48 |
+
|
| 49 |
+
return user?.IsAdmin == true && user.IsActive;
|
| 50 |
+
}
|
| 51 |
+
}
|
| 52 |
+
}
|
ContactManagementAPI/Services/ContactStatisticsService.cs
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using ContactManagementAPI.Models;
|
| 2 |
+
using ContactManagementAPI.Data;
|
| 3 |
+
using Microsoft.EntityFrameworkCore;
|
| 4 |
+
|
| 5 |
+
namespace ContactManagementAPI.Services
|
| 6 |
+
{
|
| 7 |
+
public class ContactStatisticsService
|
| 8 |
+
{
|
| 9 |
+
private readonly ApplicationDbContext _context;
|
| 10 |
+
|
| 11 |
+
public ContactStatisticsService(ApplicationDbContext context)
|
| 12 |
+
{
|
| 13 |
+
_context = context;
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
public async Task<ContactStatistics> GetStatisticsAsync()
|
| 17 |
+
{
|
| 18 |
+
var totalContacts = await _context.Contacts.CountAsync();
|
| 19 |
+
var contactsWithEmail = await _context.Contacts.Where(c => !string.IsNullOrEmpty(c.Email)).CountAsync();
|
| 20 |
+
var contactsWithPhone = await _context.Contacts.Where(c =>
|
| 21 |
+
!string.IsNullOrEmpty(c.Mobile1) || !string.IsNullOrEmpty(c.Mobile2) || !string.IsNullOrEmpty(c.Mobile3)).CountAsync();
|
| 22 |
+
|
| 23 |
+
var topCities = await _context.Contacts
|
| 24 |
+
.Where(c => !string.IsNullOrEmpty(c.City))
|
| 25 |
+
.GroupBy(c => c.City)
|
| 26 |
+
.Select(g => new CityStatistic { City = g.Key, Count = g.Count() })
|
| 27 |
+
.OrderByDescending(x => x.Count)
|
| 28 |
+
.Take(5)
|
| 29 |
+
.ToListAsync();
|
| 30 |
+
|
| 31 |
+
var contactsByGroup = await _context.Contacts
|
| 32 |
+
.Include(c => c.Group)
|
| 33 |
+
.GroupBy(c => c.Group == null ? "Unassigned" : c.Group.Name)
|
| 34 |
+
.Select(g => new GroupStatistic { GroupName = g.Key, Count = g.Count() })
|
| 35 |
+
.OrderByDescending(x => x.Count)
|
| 36 |
+
.ToListAsync();
|
| 37 |
+
|
| 38 |
+
return new ContactStatistics
|
| 39 |
+
{
|
| 40 |
+
TotalContacts = totalContacts,
|
| 41 |
+
ContactsWithEmail = contactsWithEmail,
|
| 42 |
+
ContactsWithPhone = contactsWithPhone,
|
| 43 |
+
TopCities = topCities,
|
| 44 |
+
ContactsByGroup = contactsByGroup,
|
| 45 |
+
LastUpdated = DateTime.Now
|
| 46 |
+
};
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
// Detect potential duplicates
|
| 50 |
+
public async Task<List<ContactDuplicate>> FindDuplicatesAsync()
|
| 51 |
+
{
|
| 52 |
+
var duplicates = new List<ContactDuplicate>();
|
| 53 |
+
var contacts = await _context.Contacts.ToListAsync();
|
| 54 |
+
|
| 55 |
+
for (int i = 0; i < contacts.Count; i++)
|
| 56 |
+
{
|
| 57 |
+
for (int j = i + 1; j < contacts.Count; j++)
|
| 58 |
+
{
|
| 59 |
+
var similarity = CalculateSimilarity(contacts[i], contacts[j]);
|
| 60 |
+
if (similarity >= 0.7) // 70% similarity threshold
|
| 61 |
+
{
|
| 62 |
+
duplicates.Add(new ContactDuplicate
|
| 63 |
+
{
|
| 64 |
+
Contact1Id = contacts[i].Id,
|
| 65 |
+
Contact1Name = $"{contacts[i].FirstName} {contacts[i].LastName}",
|
| 66 |
+
Contact2Id = contacts[j].Id,
|
| 67 |
+
Contact2Name = $"{contacts[j].FirstName} {contacts[j].LastName}",
|
| 68 |
+
SimilarityScore = similarity
|
| 69 |
+
});
|
| 70 |
+
}
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
return duplicates.OrderByDescending(x => x.SimilarityScore).ToList();
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
private double CalculateSimilarity(Contact c1, Contact c2)
|
| 78 |
+
{
|
| 79 |
+
double score = 0;
|
| 80 |
+
int factors = 0;
|
| 81 |
+
|
| 82 |
+
// Compare names
|
| 83 |
+
if (!string.IsNullOrEmpty(c1.FirstName) && !string.IsNullOrEmpty(c2.FirstName))
|
| 84 |
+
{
|
| 85 |
+
if (c1.FirstName.Equals(c2.FirstName, StringComparison.OrdinalIgnoreCase))
|
| 86 |
+
score += 1;
|
| 87 |
+
else if (LevenshteinDistance(c1.FirstName, c2.FirstName) <= 2)
|
| 88 |
+
score += 0.8;
|
| 89 |
+
factors++;
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
if (!string.IsNullOrEmpty(c1.LastName) && !string.IsNullOrEmpty(c2.LastName))
|
| 93 |
+
{
|
| 94 |
+
if (c1.LastName.Equals(c2.LastName, StringComparison.OrdinalIgnoreCase))
|
| 95 |
+
score += 1;
|
| 96 |
+
else if (LevenshteinDistance(c1.LastName, c2.LastName) <= 2)
|
| 97 |
+
score += 0.8;
|
| 98 |
+
factors++;
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
// Compare emails
|
| 102 |
+
if (!string.IsNullOrEmpty(c1.Email) && !string.IsNullOrEmpty(c2.Email))
|
| 103 |
+
{
|
| 104 |
+
if (c1.Email.Equals(c2.Email, StringComparison.OrdinalIgnoreCase))
|
| 105 |
+
score += 2; // High weight for email match
|
| 106 |
+
factors++;
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
// Compare phones
|
| 110 |
+
if (!string.IsNullOrEmpty(c1.Mobile1) && !string.IsNullOrEmpty(c2.Mobile1))
|
| 111 |
+
{
|
| 112 |
+
if (c1.Mobile1.Equals(c2.Mobile1))
|
| 113 |
+
score += 2; // High weight for phone match
|
| 114 |
+
factors++;
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
return factors > 0 ? score / (factors * 1.5) : 0;
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
private int LevenshteinDistance(string s1, string s2)
|
| 121 |
+
{
|
| 122 |
+
var length1 = s1.Length;
|
| 123 |
+
var length2 = s2.Length;
|
| 124 |
+
var d = new int[length1 + 1, length2 + 1];
|
| 125 |
+
|
| 126 |
+
for (int i = 0; i <= length1; i++)
|
| 127 |
+
d[i, 0] = i;
|
| 128 |
+
|
| 129 |
+
for (int j = 0; j <= length2; j++)
|
| 130 |
+
d[0, j] = j;
|
| 131 |
+
|
| 132 |
+
for (int i = 1; i <= length1; i++)
|
| 133 |
+
for (int j = 1; j <= length2; j++)
|
| 134 |
+
{
|
| 135 |
+
int cost = (s1[i - 1] == s2[j - 1]) ? 0 : 1;
|
| 136 |
+
d[i, j] = Math.Min(Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost);
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
return d[length1, length2];
|
| 140 |
+
}
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
public class ContactStatistics
|
| 144 |
+
{
|
| 145 |
+
public int TotalContacts { get; set; }
|
| 146 |
+
public int ContactsWithEmail { get; set; }
|
| 147 |
+
public int ContactsWithPhone { get; set; }
|
| 148 |
+
public List<CityStatistic> TopCities { get; set; } = new();
|
| 149 |
+
public List<GroupStatistic> ContactsByGroup { get; set; } = new();
|
| 150 |
+
public DateTime LastUpdated { get; set; }
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
public class CityStatistic
|
| 154 |
+
{
|
| 155 |
+
public string City { get; set; }
|
| 156 |
+
public int Count { get; set; }
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
public class GroupStatistic
|
| 160 |
+
{
|
| 161 |
+
public string GroupName { get; set; }
|
| 162 |
+
public int Count { get; set; }
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
public class ContactDuplicate
|
| 166 |
+
{
|
| 167 |
+
public int Contact1Id { get; set; }
|
| 168 |
+
public string Contact1Name { get; set; }
|
| 169 |
+
public int Contact2Id { get; set; }
|
| 170 |
+
public string Contact2Name { get; set; }
|
| 171 |
+
public double SimilarityScore { get; set; }
|
| 172 |
+
}
|
| 173 |
+
}
|
ContactManagementAPI/Services/FileUploadService.cs
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using Microsoft.AspNetCore.Http;
|
| 2 |
+
using System;
|
| 3 |
+
using System.IO;
|
| 4 |
+
using System.Threading.Tasks;
|
| 5 |
+
|
| 6 |
+
namespace ContactManagementAPI.Services
|
| 7 |
+
{
|
| 8 |
+
public class FileUploadService
|
| 9 |
+
{
|
| 10 |
+
private readonly IWebHostEnvironment _environment;
|
| 11 |
+
private readonly IConfiguration _configuration;
|
| 12 |
+
private const long MAX_PHOTO_SIZE = 5242880; // 5MB
|
| 13 |
+
private const long MAX_DOCUMENT_SIZE = 10485760; // 10MB
|
| 14 |
+
|
| 15 |
+
public FileUploadService(IWebHostEnvironment environment, IConfiguration configuration)
|
| 16 |
+
{
|
| 17 |
+
_environment = environment;
|
| 18 |
+
_configuration = configuration;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
private string GetUploadsRoot()
|
| 22 |
+
{
|
| 23 |
+
var uploadsRoot = Environment.GetEnvironmentVariable("UPLOADS_ROOT");
|
| 24 |
+
if (!string.IsNullOrWhiteSpace(uploadsRoot))
|
| 25 |
+
{
|
| 26 |
+
Directory.CreateDirectory(uploadsRoot);
|
| 27 |
+
return uploadsRoot;
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
return Path.Combine(_environment.WebRootPath, "uploads");
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
public async Task<(bool Success, string FilePath, string ErrorMessage)> UploadPhotoAsync(IFormFile file, int contactId)
|
| 34 |
+
{
|
| 35 |
+
try
|
| 36 |
+
{
|
| 37 |
+
if (file == null || file.Length == 0)
|
| 38 |
+
return (false, "", "No file selected");
|
| 39 |
+
|
| 40 |
+
if (file.Length > MAX_PHOTO_SIZE)
|
| 41 |
+
return (false, "", "Photo size exceeds maximum limit of 5MB");
|
| 42 |
+
|
| 43 |
+
var allowedExtensions = _configuration.GetSection("FileUpload:AllowedPhotoExtensions").Get<string[]>();
|
| 44 |
+
var fileExtension = Path.GetExtension(file.FileName).ToLower();
|
| 45 |
+
|
| 46 |
+
if (!allowedExtensions.Contains(fileExtension))
|
| 47 |
+
return (false, "", "Invalid file format. Allowed formats: JPG, PNG, GIF, BMP");
|
| 48 |
+
|
| 49 |
+
var uploadPath = Path.Combine(GetUploadsRoot(), "photos");
|
| 50 |
+
if (!Directory.Exists(uploadPath))
|
| 51 |
+
Directory.CreateDirectory(uploadPath);
|
| 52 |
+
|
| 53 |
+
var fileName = $"{contactId}_{DateTime.Now.Ticks}{fileExtension}";
|
| 54 |
+
var filePath = Path.Combine(uploadPath, fileName);
|
| 55 |
+
|
| 56 |
+
using (var stream = new FileStream(filePath, FileMode.Create))
|
| 57 |
+
{
|
| 58 |
+
await file.CopyToAsync(stream);
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
return (true, $"/uploads/photos/{fileName}", "");
|
| 62 |
+
}
|
| 63 |
+
catch (Exception ex)
|
| 64 |
+
{
|
| 65 |
+
return (false, "", $"Error uploading file: {ex.Message}");
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
public async Task<(bool Success, string FilePath, string ErrorMessage)> UploadDocumentAsync(IFormFile file, int contactId)
|
| 70 |
+
{
|
| 71 |
+
try
|
| 72 |
+
{
|
| 73 |
+
if (file == null || file.Length == 0)
|
| 74 |
+
return (false, "", "No file selected");
|
| 75 |
+
|
| 76 |
+
if (file.Length > MAX_DOCUMENT_SIZE)
|
| 77 |
+
return (false, "", "Document size exceeds maximum limit of 10MB");
|
| 78 |
+
|
| 79 |
+
var allowedExtensions = _configuration.GetSection("FileUpload:AllowedDocumentExtensions").Get<string[]>();
|
| 80 |
+
var fileExtension = Path.GetExtension(file.FileName).ToLower();
|
| 81 |
+
|
| 82 |
+
if (!allowedExtensions.Contains(fileExtension))
|
| 83 |
+
return (false, "", "Invalid file format");
|
| 84 |
+
|
| 85 |
+
var uploadPath = Path.Combine(GetUploadsRoot(), "documents");
|
| 86 |
+
if (!Directory.Exists(uploadPath))
|
| 87 |
+
Directory.CreateDirectory(uploadPath);
|
| 88 |
+
|
| 89 |
+
var fileName = $"{contactId}_{DateTime.Now.Ticks}{fileExtension}";
|
| 90 |
+
var filePath = Path.Combine(uploadPath, fileName);
|
| 91 |
+
|
| 92 |
+
using (var stream = new FileStream(filePath, FileMode.Create))
|
| 93 |
+
{
|
| 94 |
+
await file.CopyToAsync(stream);
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
return (true, $"/uploads/documents/{fileName}", "");
|
| 98 |
+
}
|
| 99 |
+
catch (Exception ex)
|
| 100 |
+
{
|
| 101 |
+
return (false, "", $"Error uploading file: {ex.Message}");
|
| 102 |
+
}
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
public bool DeleteFile(string filePath)
|
| 106 |
+
{
|
| 107 |
+
try
|
| 108 |
+
{
|
| 109 |
+
var trimmed = (filePath ?? string.Empty).Trim();
|
| 110 |
+
if (string.IsNullOrWhiteSpace(trimmed))
|
| 111 |
+
{
|
| 112 |
+
return false;
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
var normalized = trimmed.StartsWith("/") ? trimmed : "/" + trimmed;
|
| 116 |
+
var uploadsRoot = GetUploadsRoot();
|
| 117 |
+
string fullPath;
|
| 118 |
+
|
| 119 |
+
if (normalized.StartsWith("/uploads/", StringComparison.OrdinalIgnoreCase))
|
| 120 |
+
{
|
| 121 |
+
var relative = normalized.Substring("/uploads/".Length).Replace('/', Path.DirectorySeparatorChar);
|
| 122 |
+
fullPath = Path.Combine(uploadsRoot, relative);
|
| 123 |
+
}
|
| 124 |
+
else
|
| 125 |
+
{
|
| 126 |
+
fullPath = Path.Combine(_environment.WebRootPath, normalized.TrimStart('/').Replace('/', Path.DirectorySeparatorChar));
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
if (File.Exists(fullPath))
|
| 130 |
+
{
|
| 131 |
+
File.Delete(fullPath);
|
| 132 |
+
return true;
|
| 133 |
+
}
|
| 134 |
+
return false;
|
| 135 |
+
}
|
| 136 |
+
catch
|
| 137 |
+
{
|
| 138 |
+
return false;
|
| 139 |
+
}
|
| 140 |
+
}
|
| 141 |
+
}
|
| 142 |
+
}
|
ContactManagementAPI/Services/ImportExportService.cs
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using ContactManagementAPI.Models;
|
| 2 |
+
using CsvHelper;
|
| 3 |
+
using CsvHelper.Configuration;
|
| 4 |
+
using OfficeOpenXml;
|
| 5 |
+
using QuestPDF.Fluent;
|
| 6 |
+
using QuestPDF.Helpers;
|
| 7 |
+
using QuestPDF.Infrastructure;
|
| 8 |
+
using System.Globalization;
|
| 9 |
+
using System.Text;
|
| 10 |
+
|
| 11 |
+
namespace ContactManagementAPI.Services
|
| 12 |
+
{
|
| 13 |
+
public class ImportExportService
|
| 14 |
+
{
|
| 15 |
+
public ImportExportService()
|
| 16 |
+
{
|
| 17 |
+
// Set EPPlus license context
|
| 18 |
+
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
|
| 19 |
+
|
| 20 |
+
// Set QuestPDF license
|
| 21 |
+
QuestPDF.Settings.License = LicenseType.Community;
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
#region Import Methods
|
| 25 |
+
|
| 26 |
+
public async Task<(List<Contact> contacts, List<string> errors)> ImportFromExcel(Stream stream)
|
| 27 |
+
{
|
| 28 |
+
var contacts = new List<Contact>();
|
| 29 |
+
var errors = new List<string>();
|
| 30 |
+
|
| 31 |
+
try
|
| 32 |
+
{
|
| 33 |
+
using var package = new ExcelPackage(stream);
|
| 34 |
+
var worksheet = package.Workbook.Worksheets.FirstOrDefault();
|
| 35 |
+
|
| 36 |
+
if (worksheet == null)
|
| 37 |
+
{
|
| 38 |
+
errors.Add("No worksheet found in the Excel file.");
|
| 39 |
+
return (contacts, errors);
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
var rowCount = worksheet.Dimension?.Rows ?? 0;
|
| 43 |
+
|
| 44 |
+
// Start from row 2 (skip header)
|
| 45 |
+
for (int row = 2; row <= rowCount; row++)
|
| 46 |
+
{
|
| 47 |
+
try
|
| 48 |
+
{
|
| 49 |
+
var contact = new Contact
|
| 50 |
+
{
|
| 51 |
+
FirstName = worksheet.Cells[row, 1].Value?.ToString() ?? "",
|
| 52 |
+
LastName = worksheet.Cells[row, 2].Value?.ToString() ?? "",
|
| 53 |
+
NickName = worksheet.Cells[row, 3].Value?.ToString(),
|
| 54 |
+
Gender = worksheet.Cells[row, 4].Value?.ToString(),
|
| 55 |
+
DateOfBirth = DateTime.TryParse(worksheet.Cells[row, 5].Value?.ToString(), out var dob) ? dob : null,
|
| 56 |
+
Email = worksheet.Cells[row, 6].Value?.ToString(),
|
| 57 |
+
Mobile1 = worksheet.Cells[row, 7].Value?.ToString(),
|
| 58 |
+
Mobile2 = worksheet.Cells[row, 8].Value?.ToString(),
|
| 59 |
+
Mobile3 = worksheet.Cells[row, 9].Value?.ToString(),
|
| 60 |
+
WhatsAppNumber = worksheet.Cells[row, 10].Value?.ToString(),
|
| 61 |
+
PassportNumber = worksheet.Cells[row, 11].Value?.ToString(),
|
| 62 |
+
PanNumber = worksheet.Cells[row, 12].Value?.ToString(),
|
| 63 |
+
AadharNumber = worksheet.Cells[row, 13].Value?.ToString(),
|
| 64 |
+
DrivingLicenseNumber = worksheet.Cells[row, 14].Value?.ToString(),
|
| 65 |
+
VotersId = worksheet.Cells[row, 15].Value?.ToString(),
|
| 66 |
+
BankAccountNumber = worksheet.Cells[row, 16].Value?.ToString(),
|
| 67 |
+
BankName = worksheet.Cells[row, 17].Value?.ToString(),
|
| 68 |
+
BranchName = worksheet.Cells[row, 18].Value?.ToString(),
|
| 69 |
+
IfscCode = worksheet.Cells[row, 19].Value?.ToString(),
|
| 70 |
+
Address = worksheet.Cells[row, 20].Value?.ToString(),
|
| 71 |
+
City = worksheet.Cells[row, 21].Value?.ToString(),
|
| 72 |
+
State = worksheet.Cells[row, 22].Value?.ToString(),
|
| 73 |
+
PostalCode = worksheet.Cells[row, 23].Value?.ToString(),
|
| 74 |
+
Country = worksheet.Cells[row, 24].Value?.ToString(),
|
| 75 |
+
OtherDetails = worksheet.Cells[row, 25].Value?.ToString(),
|
| 76 |
+
CreatedAt = DateTime.Now,
|
| 77 |
+
UpdatedAt = DateTime.Now
|
| 78 |
+
};
|
| 79 |
+
|
| 80 |
+
if (!string.IsNullOrWhiteSpace(contact.FirstName) || !string.IsNullOrWhiteSpace(contact.LastName))
|
| 81 |
+
{
|
| 82 |
+
contacts.Add(contact);
|
| 83 |
+
}
|
| 84 |
+
}
|
| 85 |
+
catch (Exception ex)
|
| 86 |
+
{
|
| 87 |
+
errors.Add($"Row {row}: {ex.Message}");
|
| 88 |
+
}
|
| 89 |
+
}
|
| 90 |
+
}
|
| 91 |
+
catch (Exception ex)
|
| 92 |
+
{
|
| 93 |
+
errors.Add($"Error reading Excel file: {ex.Message}");
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
return (contacts, errors);
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
public async Task<(List<Contact> contacts, List<string> errors)> ImportFromCsv(Stream stream)
|
| 100 |
+
{
|
| 101 |
+
var contacts = new List<Contact>();
|
| 102 |
+
var errors = new List<string>();
|
| 103 |
+
|
| 104 |
+
try
|
| 105 |
+
{
|
| 106 |
+
using var reader = new StreamReader(stream);
|
| 107 |
+
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
|
| 108 |
+
{
|
| 109 |
+
HasHeaderRecord = true,
|
| 110 |
+
MissingFieldFound = null,
|
| 111 |
+
BadDataFound = null
|
| 112 |
+
};
|
| 113 |
+
|
| 114 |
+
using var csv = new CsvReader(reader, config);
|
| 115 |
+
|
| 116 |
+
csv.Read();
|
| 117 |
+
csv.ReadHeader();
|
| 118 |
+
int rowNumber = 1;
|
| 119 |
+
|
| 120 |
+
while (csv.Read())
|
| 121 |
+
{
|
| 122 |
+
rowNumber++;
|
| 123 |
+
try
|
| 124 |
+
{
|
| 125 |
+
string? ReadField(string name, int index)
|
| 126 |
+
{
|
| 127 |
+
if (csv.TryGetField<string>(name, out var namedValue))
|
| 128 |
+
return namedValue;
|
| 129 |
+
|
| 130 |
+
if (csv.TryGetField<string>(index, out var indexedValue))
|
| 131 |
+
return indexedValue;
|
| 132 |
+
|
| 133 |
+
return null;
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
var contact = new Contact
|
| 137 |
+
{
|
| 138 |
+
FirstName = ReadField("FirstName", 0) ?? "",
|
| 139 |
+
LastName = ReadField("LastName", 1) ?? "",
|
| 140 |
+
NickName = ReadField("NickName", 2),
|
| 141 |
+
Gender = ReadField("Gender", 3),
|
| 142 |
+
DateOfBirth = DateTime.TryParse(ReadField("DateOfBirth", 4), out var dob) ? dob : null,
|
| 143 |
+
Email = ReadField("Email", 5),
|
| 144 |
+
Mobile1 = ReadField("Mobile1", 6),
|
| 145 |
+
Mobile2 = ReadField("Mobile2", 7),
|
| 146 |
+
Mobile3 = ReadField("Mobile3", 8),
|
| 147 |
+
WhatsAppNumber = ReadField("WhatsAppNumber", 9),
|
| 148 |
+
PassportNumber = ReadField("PassportNumber", 10),
|
| 149 |
+
PanNumber = ReadField("PanNumber", 11),
|
| 150 |
+
AadharNumber = ReadField("AadharNumber", 12),
|
| 151 |
+
DrivingLicenseNumber = ReadField("DrivingLicenseNumber", 13),
|
| 152 |
+
VotersId = ReadField("VotersId", 14),
|
| 153 |
+
BankAccountNumber = ReadField("BankAccountNumber", 15),
|
| 154 |
+
BankName = ReadField("BankName", 16),
|
| 155 |
+
BranchName = ReadField("BranchName", 17),
|
| 156 |
+
IfscCode = ReadField("IfscCode", 18),
|
| 157 |
+
Address = ReadField("Address", 19),
|
| 158 |
+
City = ReadField("City", 20),
|
| 159 |
+
State = ReadField("State", 21),
|
| 160 |
+
PostalCode = ReadField("PostalCode", 22),
|
| 161 |
+
Country = ReadField("Country", 23),
|
| 162 |
+
OtherDetails = ReadField("OtherDetails", 24),
|
| 163 |
+
CreatedAt = DateTime.Now,
|
| 164 |
+
UpdatedAt = DateTime.Now
|
| 165 |
+
};
|
| 166 |
+
|
| 167 |
+
if (!string.IsNullOrWhiteSpace(contact.FirstName) || !string.IsNullOrWhiteSpace(contact.LastName))
|
| 168 |
+
{
|
| 169 |
+
contacts.Add(contact);
|
| 170 |
+
}
|
| 171 |
+
}
|
| 172 |
+
catch (Exception ex)
|
| 173 |
+
{
|
| 174 |
+
errors.Add($"Row {rowNumber}: {ex.Message}");
|
| 175 |
+
}
|
| 176 |
+
}
|
| 177 |
+
}
|
| 178 |
+
catch (Exception ex)
|
| 179 |
+
{
|
| 180 |
+
errors.Add($"Error reading CSV file: {ex.Message}");
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
return (contacts, errors);
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
#endregion
|
| 187 |
+
|
| 188 |
+
#region Export Methods
|
| 189 |
+
|
| 190 |
+
public async Task<byte[]> ExportToExcel(List<Contact> contacts)
|
| 191 |
+
{
|
| 192 |
+
using var package = new ExcelPackage();
|
| 193 |
+
var worksheet = package.Workbook.Worksheets.Add("Contacts");
|
| 194 |
+
|
| 195 |
+
// Add headers
|
| 196 |
+
worksheet.Cells[1, 1].Value = "First Name";
|
| 197 |
+
worksheet.Cells[1, 2].Value = "Last Name";
|
| 198 |
+
worksheet.Cells[1, 3].Value = "Nick Name";
|
| 199 |
+
worksheet.Cells[1, 4].Value = "Gender";
|
| 200 |
+
worksheet.Cells[1, 5].Value = "Date Of Birth";
|
| 201 |
+
worksheet.Cells[1, 6].Value = "Email";
|
| 202 |
+
worksheet.Cells[1, 7].Value = "Mobile 1";
|
| 203 |
+
worksheet.Cells[1, 8].Value = "Mobile 2";
|
| 204 |
+
worksheet.Cells[1, 9].Value = "Mobile 3";
|
| 205 |
+
worksheet.Cells[1, 10].Value = "WhatsApp";
|
| 206 |
+
worksheet.Cells[1, 11].Value = "Passport Number";
|
| 207 |
+
worksheet.Cells[1, 12].Value = "PAN Number";
|
| 208 |
+
worksheet.Cells[1, 13].Value = "Aadhar Number";
|
| 209 |
+
worksheet.Cells[1, 14].Value = "Driving License Number";
|
| 210 |
+
worksheet.Cells[1, 15].Value = "Voters ID";
|
| 211 |
+
worksheet.Cells[1, 16].Value = "Bank Account Number";
|
| 212 |
+
worksheet.Cells[1, 17].Value = "Bank Name";
|
| 213 |
+
worksheet.Cells[1, 18].Value = "Branch Name";
|
| 214 |
+
worksheet.Cells[1, 19].Value = "IFSC Code";
|
| 215 |
+
worksheet.Cells[1, 20].Value = "Address";
|
| 216 |
+
worksheet.Cells[1, 21].Value = "City";
|
| 217 |
+
worksheet.Cells[1, 22].Value = "State";
|
| 218 |
+
worksheet.Cells[1, 23].Value = "Postal Code";
|
| 219 |
+
worksheet.Cells[1, 24].Value = "Country";
|
| 220 |
+
worksheet.Cells[1, 25].Value = "Other Details";
|
| 221 |
+
worksheet.Cells[1, 26].Value = "Group";
|
| 222 |
+
worksheet.Cells[1, 27].Value = "Created At";
|
| 223 |
+
|
| 224 |
+
// Style headers
|
| 225 |
+
using (var range = worksheet.Cells[1, 1, 1, 27])
|
| 226 |
+
{
|
| 227 |
+
range.Style.Font.Bold = true;
|
| 228 |
+
range.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
|
| 229 |
+
range.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightBlue);
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
// Add data
|
| 233 |
+
for (int i = 0; i < contacts.Count; i++)
|
| 234 |
+
{
|
| 235 |
+
var contact = contacts[i];
|
| 236 |
+
var row = i + 2;
|
| 237 |
+
|
| 238 |
+
worksheet.Cells[row, 1].Value = contact.FirstName;
|
| 239 |
+
worksheet.Cells[row, 2].Value = contact.LastName;
|
| 240 |
+
worksheet.Cells[row, 3].Value = contact.NickName;
|
| 241 |
+
worksheet.Cells[row, 4].Value = contact.Gender;
|
| 242 |
+
worksheet.Cells[row, 5].Value = contact.DateOfBirth?.ToString("yyyy-MM-dd");
|
| 243 |
+
worksheet.Cells[row, 6].Value = contact.Email;
|
| 244 |
+
worksheet.Cells[row, 7].Value = contact.Mobile1;
|
| 245 |
+
worksheet.Cells[row, 8].Value = contact.Mobile2;
|
| 246 |
+
worksheet.Cells[row, 9].Value = contact.Mobile3;
|
| 247 |
+
worksheet.Cells[row, 10].Value = contact.WhatsAppNumber;
|
| 248 |
+
worksheet.Cells[row, 11].Value = contact.PassportNumber;
|
| 249 |
+
worksheet.Cells[row, 12].Value = contact.PanNumber;
|
| 250 |
+
worksheet.Cells[row, 13].Value = contact.AadharNumber;
|
| 251 |
+
worksheet.Cells[row, 14].Value = contact.DrivingLicenseNumber;
|
| 252 |
+
worksheet.Cells[row, 15].Value = contact.VotersId;
|
| 253 |
+
worksheet.Cells[row, 16].Value = contact.BankAccountNumber;
|
| 254 |
+
worksheet.Cells[row, 17].Value = contact.BankName;
|
| 255 |
+
worksheet.Cells[row, 18].Value = contact.BranchName;
|
| 256 |
+
worksheet.Cells[row, 19].Value = contact.IfscCode;
|
| 257 |
+
worksheet.Cells[row, 20].Value = contact.Address;
|
| 258 |
+
worksheet.Cells[row, 21].Value = contact.City;
|
| 259 |
+
worksheet.Cells[row, 22].Value = contact.State;
|
| 260 |
+
worksheet.Cells[row, 23].Value = contact.PostalCode;
|
| 261 |
+
worksheet.Cells[row, 24].Value = contact.Country;
|
| 262 |
+
worksheet.Cells[row, 25].Value = contact.OtherDetails;
|
| 263 |
+
worksheet.Cells[row, 26].Value = contact.Group?.Name;
|
| 264 |
+
worksheet.Cells[row, 27].Value = contact.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss");
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
// Auto-fit columns
|
| 268 |
+
worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();
|
| 269 |
+
|
| 270 |
+
return await Task.FromResult(package.GetAsByteArray());
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
public async Task<byte[]> ExportToCsv(List<Contact> contacts)
|
| 274 |
+
{
|
| 275 |
+
using var memoryStream = new MemoryStream();
|
| 276 |
+
using var writer = new StreamWriter(memoryStream, Encoding.UTF8);
|
| 277 |
+
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
|
| 278 |
+
|
| 279 |
+
// Write headers
|
| 280 |
+
csv.WriteField("FirstName");
|
| 281 |
+
csv.WriteField("LastName");
|
| 282 |
+
csv.WriteField("NickName");
|
| 283 |
+
csv.WriteField("Gender");
|
| 284 |
+
csv.WriteField("DateOfBirth");
|
| 285 |
+
csv.WriteField("Email");
|
| 286 |
+
csv.WriteField("Mobile1");
|
| 287 |
+
csv.WriteField("Mobile2");
|
| 288 |
+
csv.WriteField("Mobile3");
|
| 289 |
+
csv.WriteField("WhatsAppNumber");
|
| 290 |
+
csv.WriteField("PassportNumber");
|
| 291 |
+
csv.WriteField("PanNumber");
|
| 292 |
+
csv.WriteField("AadharNumber");
|
| 293 |
+
csv.WriteField("DrivingLicenseNumber");
|
| 294 |
+
csv.WriteField("VotersId");
|
| 295 |
+
csv.WriteField("BankAccountNumber");
|
| 296 |
+
csv.WriteField("BankName");
|
| 297 |
+
csv.WriteField("BranchName");
|
| 298 |
+
csv.WriteField("IfscCode");
|
| 299 |
+
csv.WriteField("Address");
|
| 300 |
+
csv.WriteField("City");
|
| 301 |
+
csv.WriteField("State");
|
| 302 |
+
csv.WriteField("PostalCode");
|
| 303 |
+
csv.WriteField("Country");
|
| 304 |
+
csv.WriteField("OtherDetails");
|
| 305 |
+
csv.WriteField("Group");
|
| 306 |
+
csv.WriteField("CreatedAt");
|
| 307 |
+
csv.NextRecord();
|
| 308 |
+
|
| 309 |
+
// Write data
|
| 310 |
+
foreach (var contact in contacts)
|
| 311 |
+
{
|
| 312 |
+
csv.WriteField(contact.FirstName);
|
| 313 |
+
csv.WriteField(contact.LastName);
|
| 314 |
+
csv.WriteField(contact.NickName);
|
| 315 |
+
csv.WriteField(contact.Gender);
|
| 316 |
+
csv.WriteField(contact.DateOfBirth?.ToString("yyyy-MM-dd"));
|
| 317 |
+
csv.WriteField(contact.Email);
|
| 318 |
+
csv.WriteField(contact.Mobile1);
|
| 319 |
+
csv.WriteField(contact.Mobile2);
|
| 320 |
+
csv.WriteField(contact.Mobile3);
|
| 321 |
+
csv.WriteField(contact.WhatsAppNumber);
|
| 322 |
+
csv.WriteField(contact.PassportNumber);
|
| 323 |
+
csv.WriteField(contact.PanNumber);
|
| 324 |
+
csv.WriteField(contact.AadharNumber);
|
| 325 |
+
csv.WriteField(contact.DrivingLicenseNumber);
|
| 326 |
+
csv.WriteField(contact.VotersId);
|
| 327 |
+
csv.WriteField(contact.BankAccountNumber);
|
| 328 |
+
csv.WriteField(contact.BankName);
|
| 329 |
+
csv.WriteField(contact.BranchName);
|
| 330 |
+
csv.WriteField(contact.IfscCode);
|
| 331 |
+
csv.WriteField(contact.Address);
|
| 332 |
+
csv.WriteField(contact.City);
|
| 333 |
+
csv.WriteField(contact.State);
|
| 334 |
+
csv.WriteField(contact.PostalCode);
|
| 335 |
+
csv.WriteField(contact.Country);
|
| 336 |
+
csv.WriteField(contact.OtherDetails);
|
| 337 |
+
csv.WriteField(contact.Group?.Name);
|
| 338 |
+
csv.WriteField(contact.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss"));
|
| 339 |
+
csv.NextRecord();
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
await writer.FlushAsync();
|
| 343 |
+
return memoryStream.ToArray();
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
public async Task<byte[]> ExportToPdf(List<Contact> contacts)
|
| 347 |
+
{
|
| 348 |
+
var document = Document.Create(container =>
|
| 349 |
+
{
|
| 350 |
+
container.Page(page =>
|
| 351 |
+
{
|
| 352 |
+
page.Size(PageSizes.A4.Landscape());
|
| 353 |
+
page.Margin(1, Unit.Centimetre);
|
| 354 |
+
page.PageColor(Colors.White);
|
| 355 |
+
page.DefaultTextStyle(x => x.FontSize(9));
|
| 356 |
+
|
| 357 |
+
page.Header()
|
| 358 |
+
.Text("Contact List")
|
| 359 |
+
.SemiBold().FontSize(20).FontColor(Colors.Blue.Medium);
|
| 360 |
+
|
| 361 |
+
page.Content()
|
| 362 |
+
.PaddingVertical(1, Unit.Centimetre)
|
| 363 |
+
.Table(table =>
|
| 364 |
+
{
|
| 365 |
+
// Define columns
|
| 366 |
+
table.ColumnsDefinition(columns =>
|
| 367 |
+
{
|
| 368 |
+
columns.RelativeColumn(2); // Name
|
| 369 |
+
columns.RelativeColumn(2); // Email
|
| 370 |
+
columns.RelativeColumn(1.5f); // Mobile1
|
| 371 |
+
columns.RelativeColumn(1.5f); // Mobile2
|
| 372 |
+
columns.RelativeColumn(2); // City
|
| 373 |
+
columns.RelativeColumn(1.5f); // State
|
| 374 |
+
});
|
| 375 |
+
|
| 376 |
+
// Header
|
| 377 |
+
table.Header(header =>
|
| 378 |
+
{
|
| 379 |
+
header.Cell().Element(CellStyle).Text("Name").Bold();
|
| 380 |
+
header.Cell().Element(CellStyle).Text("Email").Bold();
|
| 381 |
+
header.Cell().Element(CellStyle).Text("Mobile 1").Bold();
|
| 382 |
+
header.Cell().Element(CellStyle).Text("Mobile 2").Bold();
|
| 383 |
+
header.Cell().Element(CellStyle).Text("City").Bold();
|
| 384 |
+
header.Cell().Element(CellStyle).Text("State").Bold();
|
| 385 |
+
|
| 386 |
+
static IContainer CellStyle(IContainer container)
|
| 387 |
+
{
|
| 388 |
+
return container.DefaultTextStyle(x => x.SemiBold())
|
| 389 |
+
.PaddingVertical(5).BorderBottom(1).BorderColor(Colors.Black);
|
| 390 |
+
}
|
| 391 |
+
});
|
| 392 |
+
|
| 393 |
+
// Data rows
|
| 394 |
+
foreach (var contact in contacts)
|
| 395 |
+
{
|
| 396 |
+
table.Cell().Element(CellStyle).Text($"{contact.FirstName} {contact.LastName}");
|
| 397 |
+
table.Cell().Element(CellStyle).Text(contact.Email ?? "-");
|
| 398 |
+
table.Cell().Element(CellStyle).Text(contact.Mobile1 ?? "-");
|
| 399 |
+
table.Cell().Element(CellStyle).Text(contact.Mobile2 ?? "-");
|
| 400 |
+
table.Cell().Element(CellStyle).Text(contact.City ?? "-");
|
| 401 |
+
table.Cell().Element(CellStyle).Text(contact.State ?? "-");
|
| 402 |
+
|
| 403 |
+
static IContainer CellStyle(IContainer container)
|
| 404 |
+
{
|
| 405 |
+
return container.BorderBottom(1).BorderColor(Colors.Grey.Lighten2)
|
| 406 |
+
.PaddingVertical(5);
|
| 407 |
+
}
|
| 408 |
+
}
|
| 409 |
+
});
|
| 410 |
+
|
| 411 |
+
page.Footer()
|
| 412 |
+
.AlignCenter()
|
| 413 |
+
.Text(x =>
|
| 414 |
+
{
|
| 415 |
+
x.Span("Page ");
|
| 416 |
+
x.CurrentPageNumber();
|
| 417 |
+
x.Span(" of ");
|
| 418 |
+
x.TotalPages();
|
| 419 |
+
x.Span(" | Generated on ");
|
| 420 |
+
x.Span(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
| 421 |
+
});
|
| 422 |
+
});
|
| 423 |
+
});
|
| 424 |
+
|
| 425 |
+
return await Task.FromResult(document.GeneratePdf());
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
#endregion
|
| 429 |
+
|
| 430 |
+
#region Template Methods
|
| 431 |
+
|
| 432 |
+
public async Task<byte[]> GenerateExcelTemplate()
|
| 433 |
+
{
|
| 434 |
+
using var package = new ExcelPackage();
|
| 435 |
+
var worksheet = package.Workbook.Worksheets.Add("Contacts Template");
|
| 436 |
+
|
| 437 |
+
// Add headers
|
| 438 |
+
worksheet.Cells[1, 1].Value = "FirstName";
|
| 439 |
+
worksheet.Cells[1, 2].Value = "LastName";
|
| 440 |
+
worksheet.Cells[1, 3].Value = "NickName";
|
| 441 |
+
worksheet.Cells[1, 4].Value = "Gender";
|
| 442 |
+
worksheet.Cells[1, 5].Value = "DateOfBirth";
|
| 443 |
+
worksheet.Cells[1, 6].Value = "Email";
|
| 444 |
+
worksheet.Cells[1, 7].Value = "Mobile1";
|
| 445 |
+
worksheet.Cells[1, 8].Value = "Mobile2";
|
| 446 |
+
worksheet.Cells[1, 9].Value = "Mobile3";
|
| 447 |
+
worksheet.Cells[1, 10].Value = "WhatsAppNumber";
|
| 448 |
+
worksheet.Cells[1, 11].Value = "PassportNumber";
|
| 449 |
+
worksheet.Cells[1, 12].Value = "PanNumber";
|
| 450 |
+
worksheet.Cells[1, 13].Value = "AadharNumber";
|
| 451 |
+
worksheet.Cells[1, 14].Value = "DrivingLicenseNumber";
|
| 452 |
+
worksheet.Cells[1, 15].Value = "VotersId";
|
| 453 |
+
worksheet.Cells[1, 16].Value = "BankAccountNumber";
|
| 454 |
+
worksheet.Cells[1, 17].Value = "BankName";
|
| 455 |
+
worksheet.Cells[1, 18].Value = "BranchName";
|
| 456 |
+
worksheet.Cells[1, 19].Value = "IfscCode";
|
| 457 |
+
worksheet.Cells[1, 20].Value = "Address";
|
| 458 |
+
worksheet.Cells[1, 21].Value = "City";
|
| 459 |
+
worksheet.Cells[1, 22].Value = "State";
|
| 460 |
+
worksheet.Cells[1, 23].Value = "PostalCode";
|
| 461 |
+
worksheet.Cells[1, 24].Value = "Country";
|
| 462 |
+
worksheet.Cells[1, 25].Value = "OtherDetails";
|
| 463 |
+
|
| 464 |
+
// Style headers
|
| 465 |
+
using (var range = worksheet.Cells[1, 1, 1, 25])
|
| 466 |
+
{
|
| 467 |
+
range.Style.Font.Bold = true;
|
| 468 |
+
range.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
|
| 469 |
+
range.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightGreen);
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
// Add sample row
|
| 473 |
+
worksheet.Cells[2, 1].Value = "John";
|
| 474 |
+
worksheet.Cells[2, 2].Value = "Doe";
|
| 475 |
+
worksheet.Cells[2, 3].Value = "Johnny";
|
| 476 |
+
worksheet.Cells[2, 4].Value = "Male";
|
| 477 |
+
worksheet.Cells[2, 5].Value = "1990-01-01";
|
| 478 |
+
worksheet.Cells[2, 6].Value = "john.doe@example.com";
|
| 479 |
+
worksheet.Cells[2, 7].Value = "+1234567890";
|
| 480 |
+
worksheet.Cells[2, 8].Value = "+0987654321";
|
| 481 |
+
worksheet.Cells[2, 9].Value = "";
|
| 482 |
+
worksheet.Cells[2, 10].Value = "+1234567890";
|
| 483 |
+
worksheet.Cells[2, 11].Value = "P1234567";
|
| 484 |
+
worksheet.Cells[2, 12].Value = "ABCDE1234F";
|
| 485 |
+
worksheet.Cells[2, 13].Value = "1234-5678-9012";
|
| 486 |
+
worksheet.Cells[2, 14].Value = "DL-12345-2020";
|
| 487 |
+
worksheet.Cells[2, 15].Value = "VOTER12345";
|
| 488 |
+
worksheet.Cells[2, 16].Value = "123456789012";
|
| 489 |
+
worksheet.Cells[2, 17].Value = "State Bank";
|
| 490 |
+
worksheet.Cells[2, 18].Value = "Main Branch";
|
| 491 |
+
worksheet.Cells[2, 19].Value = "SBIN0001234";
|
| 492 |
+
worksheet.Cells[2, 20].Value = "123 Main St";
|
| 493 |
+
worksheet.Cells[2, 21].Value = "New York";
|
| 494 |
+
worksheet.Cells[2, 22].Value = "NY";
|
| 495 |
+
worksheet.Cells[2, 23].Value = "10001";
|
| 496 |
+
worksheet.Cells[2, 24].Value = "USA";
|
| 497 |
+
worksheet.Cells[2, 25].Value = "Sample contact";
|
| 498 |
+
|
| 499 |
+
// Auto-fit columns
|
| 500 |
+
worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();
|
| 501 |
+
|
| 502 |
+
return await Task.FromResult(package.GetAsByteArray());
|
| 503 |
+
}
|
| 504 |
+
|
| 505 |
+
public async Task<byte[]> GenerateCsvTemplate()
|
| 506 |
+
{
|
| 507 |
+
using var memoryStream = new MemoryStream();
|
| 508 |
+
using var writer = new StreamWriter(memoryStream, Encoding.UTF8);
|
| 509 |
+
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
|
| 510 |
+
|
| 511 |
+
// Write headers
|
| 512 |
+
csv.WriteField("FirstName");
|
| 513 |
+
csv.WriteField("LastName");
|
| 514 |
+
csv.WriteField("NickName");
|
| 515 |
+
csv.WriteField("Gender");
|
| 516 |
+
csv.WriteField("DateOfBirth");
|
| 517 |
+
csv.WriteField("Email");
|
| 518 |
+
csv.WriteField("Mobile1");
|
| 519 |
+
csv.WriteField("Mobile2");
|
| 520 |
+
csv.WriteField("Mobile3");
|
| 521 |
+
csv.WriteField("WhatsAppNumber");
|
| 522 |
+
csv.WriteField("PassportNumber");
|
| 523 |
+
csv.WriteField("PanNumber");
|
| 524 |
+
csv.WriteField("AadharNumber");
|
| 525 |
+
csv.WriteField("DrivingLicenseNumber");
|
| 526 |
+
csv.WriteField("VotersId");
|
| 527 |
+
csv.WriteField("BankAccountNumber");
|
| 528 |
+
csv.WriteField("BankName");
|
| 529 |
+
csv.WriteField("BranchName");
|
| 530 |
+
csv.WriteField("IfscCode");
|
| 531 |
+
csv.WriteField("Address");
|
| 532 |
+
csv.WriteField("City");
|
| 533 |
+
csv.WriteField("State");
|
| 534 |
+
csv.WriteField("PostalCode");
|
| 535 |
+
csv.WriteField("Country");
|
| 536 |
+
csv.WriteField("OtherDetails");
|
| 537 |
+
csv.NextRecord();
|
| 538 |
+
|
| 539 |
+
// Write sample row
|
| 540 |
+
csv.WriteField("John");
|
| 541 |
+
csv.WriteField("Doe");
|
| 542 |
+
csv.WriteField("Johnny");
|
| 543 |
+
csv.WriteField("Male");
|
| 544 |
+
csv.WriteField("1990-01-01");
|
| 545 |
+
csv.WriteField("john.doe@example.com");
|
| 546 |
+
csv.WriteField("+1234567890");
|
| 547 |
+
csv.WriteField("+0987654321");
|
| 548 |
+
csv.WriteField("");
|
| 549 |
+
csv.WriteField("+1234567890");
|
| 550 |
+
csv.WriteField("P1234567");
|
| 551 |
+
csv.WriteField("ABCDE1234F");
|
| 552 |
+
csv.WriteField("1234-5678-9012");
|
| 553 |
+
csv.WriteField("DL-12345-2020");
|
| 554 |
+
csv.WriteField("VOTER12345");
|
| 555 |
+
csv.WriteField("123456789012");
|
| 556 |
+
csv.WriteField("State Bank");
|
| 557 |
+
csv.WriteField("Main Branch");
|
| 558 |
+
csv.WriteField("SBIN0001234");
|
| 559 |
+
csv.WriteField("123 Main St");
|
| 560 |
+
csv.WriteField("New York");
|
| 561 |
+
csv.WriteField("NY");
|
| 562 |
+
csv.WriteField("10001");
|
| 563 |
+
csv.WriteField("USA");
|
| 564 |
+
csv.WriteField("Sample contact");
|
| 565 |
+
csv.NextRecord();
|
| 566 |
+
|
| 567 |
+
await writer.FlushAsync();
|
| 568 |
+
return memoryStream.ToArray();
|
| 569 |
+
}
|
| 570 |
+
|
| 571 |
+
#endregion
|
| 572 |
+
}
|
| 573 |
+
}
|
ContactManagementAPI/Services/SeedData.cs
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
using System.Linq;
|
| 3 |
+
using System.Text.RegularExpressions;
|
| 4 |
+
using ContactManagementAPI.Data;
|
| 5 |
+
using ContactManagementAPI.Models;
|
| 6 |
+
using Microsoft.AspNetCore.Identity;
|
| 7 |
+
|
| 8 |
+
namespace ContactManagementAPI.Services
|
| 9 |
+
{
|
| 10 |
+
public static class SeedData
|
| 11 |
+
{
|
| 12 |
+
public const string SuperAdminUserName = "abrahamcbe@gmail.com";
|
| 13 |
+
public const string SuperAdminDefaultPassword = "M@ld1ves";
|
| 14 |
+
|
| 15 |
+
private static string GetSuperAdminPassword()
|
| 16 |
+
{
|
| 17 |
+
var fromEnv = Environment.GetEnvironmentVariable("SUPERADMIN_PASSWORD");
|
| 18 |
+
return string.IsNullOrWhiteSpace(fromEnv) ? SuperAdminDefaultPassword : fromEnv;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
public static void Initialize(ApplicationDbContext context)
|
| 22 |
+
{
|
| 23 |
+
var hasher = new PasswordHasher<AppUser>();
|
| 24 |
+
|
| 25 |
+
if (!context.UserGroups.Any())
|
| 26 |
+
{
|
| 27 |
+
var adminGroup = new UserGroup
|
| 28 |
+
{
|
| 29 |
+
Name = "Administrators",
|
| 30 |
+
Description = "System administrators with full access",
|
| 31 |
+
CreatedAt = DateTime.Now
|
| 32 |
+
};
|
| 33 |
+
|
| 34 |
+
context.UserGroups.Add(adminGroup);
|
| 35 |
+
context.SaveChanges();
|
| 36 |
+
|
| 37 |
+
var groupRights = RightsCatalog.All
|
| 38 |
+
.Select(r => new GroupRight
|
| 39 |
+
{
|
| 40 |
+
UserGroupId = adminGroup.Id,
|
| 41 |
+
RightKey = r.Key,
|
| 42 |
+
IsGranted = true
|
| 43 |
+
})
|
| 44 |
+
.ToList();
|
| 45 |
+
|
| 46 |
+
context.GroupRights.AddRange(groupRights);
|
| 47 |
+
context.SaveChanges();
|
| 48 |
+
}
|
| 49 |
+
else
|
| 50 |
+
{
|
| 51 |
+
var adminGroup = context.UserGroups.FirstOrDefault(g => g.Name == "Administrators");
|
| 52 |
+
if (adminGroup != null)
|
| 53 |
+
{
|
| 54 |
+
var existingAdminRights = context.GroupRights
|
| 55 |
+
.Where(r => r.UserGroupId == adminGroup.Id)
|
| 56 |
+
.ToList();
|
| 57 |
+
|
| 58 |
+
foreach (var right in RightsCatalog.All)
|
| 59 |
+
{
|
| 60 |
+
var existing = existingAdminRights.FirstOrDefault(r => r.RightKey == right.Key);
|
| 61 |
+
if (existing == null)
|
| 62 |
+
{
|
| 63 |
+
context.GroupRights.Add(new GroupRight
|
| 64 |
+
{
|
| 65 |
+
UserGroupId = adminGroup.Id,
|
| 66 |
+
RightKey = right.Key,
|
| 67 |
+
IsGranted = true
|
| 68 |
+
});
|
| 69 |
+
}
|
| 70 |
+
else if (!existing.IsGranted)
|
| 71 |
+
{
|
| 72 |
+
existing.IsGranted = true;
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
context.SaveChanges();
|
| 77 |
+
}
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
if (!context.AppUsers.Any())
|
| 81 |
+
{
|
| 82 |
+
var adminGroupId = context.UserGroups
|
| 83 |
+
.Where(g => g.Name == "Administrators")
|
| 84 |
+
.Select(g => g.Id)
|
| 85 |
+
.First();
|
| 86 |
+
|
| 87 |
+
var adminUser = new AppUser
|
| 88 |
+
{
|
| 89 |
+
UserName = "admin",
|
| 90 |
+
FullName = "System Administrator",
|
| 91 |
+
IsAdmin = true,
|
| 92 |
+
IsActive = true,
|
| 93 |
+
GroupId = adminGroupId,
|
| 94 |
+
CreatedAt = DateTime.Now,
|
| 95 |
+
UpdatedAt = DateTime.Now
|
| 96 |
+
};
|
| 97 |
+
|
| 98 |
+
adminUser.PasswordHash = hasher.HashPassword(adminUser, "Admin@123");
|
| 99 |
+
|
| 100 |
+
context.AppUsers.Add(adminUser);
|
| 101 |
+
context.SaveChanges();
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
EnsureSuperAdminUser(context, hasher);
|
| 105 |
+
|
| 106 |
+
EnsureContactGroupUsers(context, hasher);
|
| 107 |
+
|
| 108 |
+
EnsureInitialContacts(context);
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
private static void EnsureInitialContacts(ApplicationDbContext context)
|
| 112 |
+
{
|
| 113 |
+
var now = DateTime.Now;
|
| 114 |
+
|
| 115 |
+
var familyGroupId = context.ContactGroups
|
| 116 |
+
.Where(g => g.Name == "Family")
|
| 117 |
+
.Select(g => (int?)g.Id)
|
| 118 |
+
.FirstOrDefault();
|
| 119 |
+
|
| 120 |
+
void EnsureNamedContact(string firstName, string? lastName, string? nickName)
|
| 121 |
+
{
|
| 122 |
+
var exists = context.Contacts.Any(c => c.FirstName.ToLower() == firstName.ToLower());
|
| 123 |
+
if (exists)
|
| 124 |
+
{
|
| 125 |
+
return;
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
context.Contacts.Add(new Contact
|
| 129 |
+
{
|
| 130 |
+
FirstName = firstName,
|
| 131 |
+
LastName = lastName,
|
| 132 |
+
NickName = nickName,
|
| 133 |
+
Mobile1 = null,
|
| 134 |
+
GroupId = familyGroupId,
|
| 135 |
+
CreatedAt = now,
|
| 136 |
+
UpdatedAt = now,
|
| 137 |
+
OtherDetails = "Seeded default contact (restored if missing)."
|
| 138 |
+
});
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
EnsureNamedContact("Abraham", "CBE", "Abraham");
|
| 142 |
+
EnsureNamedContact("Prema", null, "Prema");
|
| 143 |
+
EnsureNamedContact("Ponnuraj", null, "Ponnuraj");
|
| 144 |
+
|
| 145 |
+
// Add one test contact per contact group (to help validate group scoping after a fresh DB)
|
| 146 |
+
var contactGroups = context.ContactGroups
|
| 147 |
+
.OrderBy(g => g.Id)
|
| 148 |
+
.ToList();
|
| 149 |
+
|
| 150 |
+
foreach (var group in contactGroups)
|
| 151 |
+
{
|
| 152 |
+
var exists = context.Contacts.Any(c => c.GroupId == group.Id && c.OtherDetails == "Seeded test contact for group validation.");
|
| 153 |
+
if (exists)
|
| 154 |
+
{
|
| 155 |
+
continue;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
context.Contacts.Add(new Contact
|
| 159 |
+
{
|
| 160 |
+
FirstName = $"{group.Name} Test",
|
| 161 |
+
LastName = "Contact",
|
| 162 |
+
NickName = group.Name,
|
| 163 |
+
Mobile1 = null,
|
| 164 |
+
GroupId = group.Id,
|
| 165 |
+
CreatedAt = now,
|
| 166 |
+
UpdatedAt = now,
|
| 167 |
+
OtherDetails = "Seeded test contact for group validation."
|
| 168 |
+
});
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
context.SaveChanges();
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
private static void EnsureSuperAdminUser(ApplicationDbContext context, PasswordHasher<AppUser> hasher)
|
| 175 |
+
{
|
| 176 |
+
var adminGroupId = context.UserGroups
|
| 177 |
+
.Where(g => g.Name == "Administrators")
|
| 178 |
+
.Select(g => g.Id)
|
| 179 |
+
.FirstOrDefault();
|
| 180 |
+
|
| 181 |
+
if (adminGroupId <= 0)
|
| 182 |
+
{
|
| 183 |
+
return;
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
var existing = context.AppUsers.FirstOrDefault(u => u.UserName == SuperAdminUserName);
|
| 187 |
+
if (existing == null)
|
| 188 |
+
{
|
| 189 |
+
var password = GetSuperAdminPassword();
|
| 190 |
+
var user = new AppUser
|
| 191 |
+
{
|
| 192 |
+
UserName = SuperAdminUserName,
|
| 193 |
+
FullName = "Abraham",
|
| 194 |
+
IsAdmin = true,
|
| 195 |
+
IsActive = true,
|
| 196 |
+
GroupId = adminGroupId,
|
| 197 |
+
CreatedAt = DateTime.Now,
|
| 198 |
+
UpdatedAt = DateTime.Now
|
| 199 |
+
};
|
| 200 |
+
|
| 201 |
+
user.PasswordHash = hasher.HashPassword(user, password);
|
| 202 |
+
context.AppUsers.Add(user);
|
| 203 |
+
context.SaveChanges();
|
| 204 |
+
return;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
var updated = false;
|
| 208 |
+
var enforcedPassword = GetSuperAdminPassword();
|
| 209 |
+
|
| 210 |
+
if (!existing.IsAdmin)
|
| 211 |
+
{
|
| 212 |
+
existing.IsAdmin = true;
|
| 213 |
+
updated = true;
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
+
if (!existing.IsActive)
|
| 217 |
+
{
|
| 218 |
+
existing.IsActive = true;
|
| 219 |
+
updated = true;
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
if (existing.GroupId != adminGroupId)
|
| 223 |
+
{
|
| 224 |
+
existing.GroupId = adminGroupId;
|
| 225 |
+
updated = true;
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
if (string.IsNullOrWhiteSpace(existing.FullName))
|
| 229 |
+
{
|
| 230 |
+
existing.FullName = "Abraham";
|
| 231 |
+
updated = true;
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
// Enforce Super Admin password so it matches the required credential.
|
| 235 |
+
existing.PasswordHash = hasher.HashPassword(existing, enforcedPassword);
|
| 236 |
+
updated = true;
|
| 237 |
+
|
| 238 |
+
if (updated)
|
| 239 |
+
{
|
| 240 |
+
existing.UpdatedAt = DateTime.Now;
|
| 241 |
+
context.SaveChanges();
|
| 242 |
+
}
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
private static void EnsureContactGroupUsers(ApplicationDbContext context, PasswordHasher<AppUser> hasher)
|
| 246 |
+
{
|
| 247 |
+
var contactGroups = context.ContactGroups
|
| 248 |
+
.OrderBy(g => g.Name)
|
| 249 |
+
.ToList();
|
| 250 |
+
|
| 251 |
+
foreach (var contactGroup in contactGroups)
|
| 252 |
+
{
|
| 253 |
+
var userGroupName = $"ContactGroup - {contactGroup.Name}";
|
| 254 |
+
var userGroup = context.UserGroups.FirstOrDefault(g => g.Name == userGroupName);
|
| 255 |
+
if (userGroup == null)
|
| 256 |
+
{
|
| 257 |
+
userGroup = new UserGroup
|
| 258 |
+
{
|
| 259 |
+
Name = userGroupName,
|
| 260 |
+
Description = $"Full access group for contact group '{contactGroup.Name}'",
|
| 261 |
+
CreatedAt = DateTime.Now
|
| 262 |
+
};
|
| 263 |
+
|
| 264 |
+
context.UserGroups.Add(userGroup);
|
| 265 |
+
context.SaveChanges();
|
| 266 |
+
}
|
| 267 |
+
|
| 268 |
+
var groupRights = context.GroupRights
|
| 269 |
+
.Where(r => r.UserGroupId == userGroup.Id)
|
| 270 |
+
.ToList();
|
| 271 |
+
|
| 272 |
+
foreach (var right in RightsCatalog.All)
|
| 273 |
+
{
|
| 274 |
+
var existing = groupRights.FirstOrDefault(r => r.RightKey == right.Key);
|
| 275 |
+
if (existing == null)
|
| 276 |
+
{
|
| 277 |
+
context.GroupRights.Add(new GroupRight
|
| 278 |
+
{
|
| 279 |
+
UserGroupId = userGroup.Id,
|
| 280 |
+
RightKey = right.Key,
|
| 281 |
+
IsGranted = true
|
| 282 |
+
});
|
| 283 |
+
}
|
| 284 |
+
else if (!existing.IsGranted)
|
| 285 |
+
{
|
| 286 |
+
existing.IsGranted = true;
|
| 287 |
+
}
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
context.SaveChanges();
|
| 291 |
+
|
| 292 |
+
var preferredUserName = BuildGroupUserName(contactGroup.Name);
|
| 293 |
+
var appUser = context.AppUsers.FirstOrDefault(u => u.UserName == preferredUserName);
|
| 294 |
+
if (appUser == null)
|
| 295 |
+
{
|
| 296 |
+
appUser = new AppUser
|
| 297 |
+
{
|
| 298 |
+
UserName = preferredUserName,
|
| 299 |
+
FullName = $"{contactGroup.Name} Group User",
|
| 300 |
+
GroupId = userGroup.Id,
|
| 301 |
+
IsAdmin = false,
|
| 302 |
+
IsActive = true,
|
| 303 |
+
CreatedAt = DateTime.Now,
|
| 304 |
+
UpdatedAt = DateTime.Now
|
| 305 |
+
};
|
| 306 |
+
|
| 307 |
+
appUser.PasswordHash = hasher.HashPassword(appUser, "Group@123");
|
| 308 |
+
context.AppUsers.Add(appUser);
|
| 309 |
+
}
|
| 310 |
+
else
|
| 311 |
+
{
|
| 312 |
+
appUser.GroupId = userGroup.Id;
|
| 313 |
+
appUser.IsActive = true;
|
| 314 |
+
appUser.UpdatedAt = DateTime.Now;
|
| 315 |
+
}
|
| 316 |
+
|
| 317 |
+
context.SaveChanges();
|
| 318 |
+
}
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
private static string BuildGroupUserName(string? groupName)
|
| 322 |
+
{
|
| 323 |
+
var raw = string.IsNullOrWhiteSpace(groupName) ? "group" : groupName.Trim().ToLowerInvariant();
|
| 324 |
+
var slug = Regex.Replace(raw, "[^a-z0-9]+", ".").Trim('.');
|
| 325 |
+
if (string.IsNullOrWhiteSpace(slug))
|
| 326 |
+
{
|
| 327 |
+
slug = "group";
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
+
return $"{slug}.user";
|
| 331 |
+
}
|
| 332 |
+
}
|
| 333 |
+
}
|
ContactManagementAPI/Services/SessionKeys.cs
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
namespace ContactManagementAPI.Services
|
| 2 |
+
{
|
| 3 |
+
public static class SessionKeys
|
| 4 |
+
{
|
| 5 |
+
public const string UserId = "UserId";
|
| 6 |
+
}
|
| 7 |
+
}
|
ContactManagementAPI/Services/UserContextService.cs
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using ContactManagementAPI.Data;
|
| 2 |
+
using ContactManagementAPI.Models;
|
| 3 |
+
using Microsoft.AspNetCore.Http;
|
| 4 |
+
using Microsoft.EntityFrameworkCore;
|
| 5 |
+
|
| 6 |
+
namespace ContactManagementAPI.Services
|
| 7 |
+
{
|
| 8 |
+
public class UserContextService
|
| 9 |
+
{
|
| 10 |
+
private readonly ApplicationDbContext _context;
|
| 11 |
+
private readonly IHttpContextAccessor _httpContextAccessor;
|
| 12 |
+
private readonly AuthorizationService _authorizationService;
|
| 13 |
+
|
| 14 |
+
public UserContextService(ApplicationDbContext context, IHttpContextAccessor httpContextAccessor, AuthorizationService authorizationService)
|
| 15 |
+
{
|
| 16 |
+
_context = context;
|
| 17 |
+
_httpContextAccessor = httpContextAccessor;
|
| 18 |
+
_authorizationService = authorizationService;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
public int? UserId => _httpContextAccessor.HttpContext?.Session.GetInt32(SessionKeys.UserId);
|
| 22 |
+
|
| 23 |
+
public bool IsAuthenticated => UserId.HasValue;
|
| 24 |
+
|
| 25 |
+
public AppUser? CurrentUser
|
| 26 |
+
{
|
| 27 |
+
get
|
| 28 |
+
{
|
| 29 |
+
if (!UserId.HasValue)
|
| 30 |
+
return null;
|
| 31 |
+
|
| 32 |
+
return _context.AppUsers
|
| 33 |
+
.AsNoTracking()
|
| 34 |
+
.Include(u => u.Group)
|
| 35 |
+
.FirstOrDefault(u => u.Id == UserId.Value);
|
| 36 |
+
}
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
public bool HasRight(string rightKey)
|
| 40 |
+
{
|
| 41 |
+
if (!UserId.HasValue)
|
| 42 |
+
return false;
|
| 43 |
+
|
| 44 |
+
return _authorizationService.HasRight(UserId.Value, rightKey);
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
public bool IsAdmin => UserId.HasValue && _authorizationService.IsAdmin(UserId.Value);
|
| 48 |
+
}
|
| 49 |
+
}
|
ContactManagementAPI/ViewModels/AdminViewModels.cs
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
using System;
|
| 2 |
+
using System.Collections.Generic;
|
| 3 |
+
using System.ComponentModel.DataAnnotations;
|
| 4 |
+
|
| 5 |
+
namespace ContactManagementAPI.ViewModels
|
| 6 |
+
{
|
| 7 |
+
public class LoginViewModel
|
| 8 |
+
{
|
| 9 |
+
[Required]
|
| 10 |
+
[MaxLength(100)]
|
| 11 |
+
public string UserName { get; set; } = string.Empty;
|
| 12 |
+
|
| 13 |
+
[Required]
|
| 14 |
+
[DataType(DataType.Password)]
|
| 15 |
+
public string Password { get; set; } = string.Empty;
|
| 16 |
+
|
| 17 |
+
public string? ReturnUrl { get; set; }
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
public class UserCreateViewModel
|
| 21 |
+
{
|
| 22 |
+
[Required]
|
| 23 |
+
[MaxLength(100)]
|
| 24 |
+
public string UserName { get; set; } = string.Empty;
|
| 25 |
+
|
| 26 |
+
[Required]
|
| 27 |
+
[DataType(DataType.Password)]
|
| 28 |
+
public string Password { get; set; } = string.Empty;
|
| 29 |
+
|
| 30 |
+
[MaxLength(200)]
|
| 31 |
+
public string? FullName { get; set; }
|
| 32 |
+
|
| 33 |
+
[Required]
|
| 34 |
+
public int GroupId { get; set; }
|
| 35 |
+
public bool IsAdmin { get; set; }
|
| 36 |
+
public bool IsActive { get; set; } = true;
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
public class UserEditViewModel
|
| 40 |
+
{
|
| 41 |
+
public int Id { get; set; }
|
| 42 |
+
|
| 43 |
+
[Required]
|
| 44 |
+
[MaxLength(100)]
|
| 45 |
+
public string UserName { get; set; } = string.Empty;
|
| 46 |
+
|
| 47 |
+
[MaxLength(200)]
|
| 48 |
+
public string? FullName { get; set; }
|
| 49 |
+
|
| 50 |
+
[DataType(DataType.Password)]
|
| 51 |
+
public string? NewPassword { get; set; }
|
| 52 |
+
|
| 53 |
+
[Required]
|
| 54 |
+
public int GroupId { get; set; }
|
| 55 |
+
public bool IsAdmin { get; set; }
|
| 56 |
+
public bool IsActive { get; set; } = true;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
public class GroupEditViewModel
|
| 60 |
+
{
|
| 61 |
+
public int Id { get; set; }
|
| 62 |
+
|
| 63 |
+
[Required]
|
| 64 |
+
[MaxLength(150)]
|
| 65 |
+
public string Name { get; set; } = string.Empty;
|
| 66 |
+
|
| 67 |
+
[MaxLength(500)]
|
| 68 |
+
public string? Description { get; set; }
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
public class RightAssignmentViewModel
|
| 72 |
+
{
|
| 73 |
+
public string Key { get; set; } = string.Empty;
|
| 74 |
+
public string Category { get; set; } = string.Empty;
|
| 75 |
+
public string Label { get; set; } = string.Empty;
|
| 76 |
+
public bool IsGranted { get; set; }
|
| 77 |
+
public string Selection { get; set; } = "Inherit";
|
| 78 |
+
public bool EffectiveGranted { get; set; }
|
| 79 |
+
public string EffectiveSource { get; set; } = "";
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
public class GroupRightsViewModel
|
| 83 |
+
{
|
| 84 |
+
public int GroupId { get; set; }
|
| 85 |
+
public string GroupName { get; set; } = string.Empty;
|
| 86 |
+
public List<RightAssignmentViewModel> Rights { get; set; } = new();
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
public class UserRightsViewModel
|
| 90 |
+
{
|
| 91 |
+
public int UserId { get; set; }
|
| 92 |
+
public string UserName { get; set; } = string.Empty;
|
| 93 |
+
public string? GroupName { get; set; }
|
| 94 |
+
public List<RightAssignmentViewModel> Rights { get; set; } = new();
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
public class AdminHistoryEntryViewModel
|
| 98 |
+
{
|
| 99 |
+
public string ActionType { get; set; } = string.Empty;
|
| 100 |
+
public string EntityType { get; set; } = string.Empty;
|
| 101 |
+
public int? EntityId { get; set; }
|
| 102 |
+
public string Details { get; set; } = string.Empty;
|
| 103 |
+
public string PerformedBy { get; set; } = string.Empty;
|
| 104 |
+
public DateTime PerformedAt { get; set; }
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
public class AdminHistoryListViewModel
|
| 108 |
+
{
|
| 109 |
+
public List<AdminHistoryEntryViewModel> Entries { get; set; } = new();
|
| 110 |
+
}
|
| 111 |
+
}
|
ContactManagementAPI/Views/Account/AccessDenied.cshtml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
@{
|
| 2 |
+
ViewData["Title"] = "Access Denied";
|
| 3 |
+
}
|
| 4 |
+
|
| 5 |
+
<div class="form-container" style="max-width: 520px; margin: 40px auto; text-align: center;">
|
| 6 |
+
<h2><i class="fas fa-ban"></i> Access Denied</h2>
|
| 7 |
+
<p>You do not have permission to access this page.</p>
|
| 8 |
+
<a href="/" class="btn btn-primary">
|
| 9 |
+
<i class="fas fa-arrow-left"></i> Back to Home
|
| 10 |
+
</a>
|
| 11 |
+
</div>
|
ContactManagementAPI/Views/Account/Login.cshtml
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
@model ContactManagementAPI.ViewModels.LoginViewModel
|
| 2 |
+
@{
|
| 3 |
+
ViewData["Title"] = "Login";
|
| 4 |
+
}
|
| 5 |
+
|
| 6 |
+
<div class="form-container" style="max-width: 520px; margin: 40px auto;">
|
| 7 |
+
<h2><i class="fas fa-sign-in-alt"></i> Sign In</h2>
|
| 8 |
+
|
| 9 |
+
<form method="post" asp-action="Login">
|
| 10 |
+
@Html.AntiForgeryToken()
|
| 11 |
+
<input type="hidden" asp-for="ReturnUrl" />
|
| 12 |
+
|
| 13 |
+
<div class="form-group">
|
| 14 |
+
<label asp-for="UserName"></label>
|
| 15 |
+
<input asp-for="UserName" class="form-control" />
|
| 16 |
+
<span asp-validation-for="UserName" class="text-danger"></span>
|
| 17 |
+
</div>
|
| 18 |
+
|
| 19 |
+
<div class="form-group">
|
| 20 |
+
<label asp-for="Password"></label>
|
| 21 |
+
<input asp-for="Password" class="form-control" type="password" />
|
| 22 |
+
<span asp-validation-for="Password" class="text-danger"></span>
|
| 23 |
+
</div>
|
| 24 |
+
|
| 25 |
+
<div class="form-actions">
|
| 26 |
+
<button type="submit" class="btn btn-primary">
|
| 27 |
+
<i class="fas fa-lock"></i> Login
|
| 28 |
+
</button>
|
| 29 |
+
</div>
|
| 30 |
+
|
| 31 |
+
@if (!ViewData.ModelState.IsValid)
|
| 32 |
+
{
|
| 33 |
+
<div class="alert alert-danger" style="margin-top: 15px;">
|
| 34 |
+
Please check your credentials and try again.
|
| 35 |
+
</div>
|
| 36 |
+
}
|
| 37 |
+
</form>
|
| 38 |
+
</div>
|
| 39 |
+
|
| 40 |
+
@section Scripts {
|
| 41 |
+
<partial name="_ValidationScriptsPartial" />
|
| 42 |
+
}
|