From ba1e644fd8f371149cb31fe5e46675c1a29d9c13 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 2 Jul 2025 09:59:56 +0530 Subject: [PATCH 01/17] Added new parameter uploaded by in documents table --- ..._ForeginKey_In_Decuments_Table.Designer.cs | 3426 +++++++++++++++++ ...ploadedBy_ForeginKey_In_Decuments_Table.cs | 50 + .../ApplicationDbContextModelSnapshot.cs | 11 + Marco.Pms.Model/DocumentManager/Document.cs | 12 +- 4 files changed, 3497 insertions(+), 2 deletions(-) create mode 100644 Marco.Pms.DataAccess/Migrations/20250702042830_Added_UploadedBy_ForeginKey_In_Decuments_Table.Designer.cs create mode 100644 Marco.Pms.DataAccess/Migrations/20250702042830_Added_UploadedBy_ForeginKey_In_Decuments_Table.cs diff --git a/Marco.Pms.DataAccess/Migrations/20250702042830_Added_UploadedBy_ForeginKey_In_Decuments_Table.Designer.cs b/Marco.Pms.DataAccess/Migrations/20250702042830_Added_UploadedBy_ForeginKey_In_Decuments_Table.Designer.cs new file mode 100644 index 0000000..c0c77b8 --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250702042830_Added_UploadedBy_ForeginKey_In_Decuments_Table.Designer.cs @@ -0,0 +1,3426 @@ +// +using System; +using Marco.Pms.DataAccess.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Marco.Pms.DataAccess.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20250702042830_Added_UploadedBy_ForeginKey_In_Decuments_Table")] + partial class Added_UploadedBy_ForeginKey_In_Decuments_Table + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.12") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + //MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ApprovedById") + .HasColumnType("char(36)"); + + b.Property("ApprovedDate") + .HasColumnType("datetime(6)"); + + b.Property("AssignedBy") + .HasColumnType("char(36)"); + + b.Property("AssignmentDate") + .HasColumnType("datetime(6)"); + + b.Property("CompletedTask") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedTask") + .HasColumnType("double"); + + b.Property("ReportedById") + .HasColumnType("char(36)"); + + b.Property("ReportedDate") + .HasColumnType("datetime(6)"); + + b.Property("ReportedTask") + .HasColumnType("double"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkItemId") + .HasColumnType("char(36)"); + + b.Property("WorkStatusId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApprovedById"); + + b.HasIndex("AssignedBy"); + + b.HasIndex("ReportedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkItemId"); + + b.HasIndex("WorkStatusId"); + + b.ToTable("TaskAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("ReferenceId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TaskAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CommentDate") + .HasColumnType("datetime(6)"); + + b.Property("CommentedBy") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentedBy"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("TaskAllocationId"); + + b.HasIndex("TenantId"); + + b.ToTable("TaskMembers"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ApprovedBy") + .HasColumnType("char(36)"); + + b.Property("AttendanceDate") + .HasColumnType("datetime(6)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("InTime") + .HasColumnType("datetime(6)"); + + b.Property("IsApproved") + .HasColumnType("tinyint(1)"); + + b.Property("OutTime") + .HasColumnType("datetime(6)"); + + b.Property("ProjectID") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.ToTable("Attendes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Activity") + .HasColumnType("int"); + + b.Property("ActivityTime") + .HasColumnType("datetime(6)"); + + b.Property("AttendanceId") + .HasColumnType("char(36)"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DocumentId") + .HasColumnType("char(36)"); + + b.Property("EmployeeID") + .HasColumnType("char(36)"); + + b.Property("Latitude") + .HasColumnType("longtext"); + + b.Property("Longitude") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedBy") + .HasColumnType("char(36)"); + + b.Property("UpdatedOn") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("AttendanceId"); + + b.HasIndex("DocumentId"); + + b.HasIndex("EmployeeID"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedBy"); + + b.ToTable("AttendanceLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MPIN") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MPINToken") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("MPINDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ExpriesInSec") + .HasColumnType("int"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("OTP") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("OTPDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("ExpiryDate") + .HasColumnType("datetime(6)"); + + b.Property("IsRevoked") + .HasColumnType("tinyint(1)"); + + b.Property("IsUsed") + .HasColumnType("tinyint(1)"); + + b.Property("RevokedAt") + .HasColumnType("datetime(6)"); + + b.Property("Token") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedByID") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedByID"); + + b.HasIndex("TenantId"); + + b.ToTable("Buckets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Address") + .HasColumnType("longtext"); + + b.Property("ContactCategoryId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Organization") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactCategoryId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Contacts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactCategoryMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("EmailAddress") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsEmails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Note") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("TenantId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ContactNotes"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("IsPrimary") + .HasColumnType("tinyint(1)"); + + b.Property("Label") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.ToTable("ContactsPhones"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactProjectMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactId") + .HasColumnType("char(36)"); + + b.Property("ContactTagId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ContactId"); + + b.HasIndex("ContactTagId"); + + b.ToTable("ContactTagMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ContactTagMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("RefereanceId") + .HasColumnType("char(36)"); + + b.Property("UpdateAt") + .HasColumnType("datetime(6)"); + + b.Property("UpdatedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UpdatedById"); + + b.ToTable("DirectoryUpdateLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BucketId") + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BucketId"); + + b.HasIndex("EmployeeId"); + + b.ToTable("EmployeeBucketMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Base64Data") + .HasColumnType("longtext"); + + b.Property("BatchId") + .HasColumnType("char(36)"); + + b.Property("ContentType") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("S3Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("ThumbS3Key") + .HasColumnType("longtext"); + + b.Property("UploadedAt") + .HasColumnType("datetime(6)"); + + b.Property("UploadedById") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("UploadedById"); + + b.ToTable("Documents"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AadharNumber") + .HasColumnType("longtext"); + + b.Property("ApplicationUserId") + .HasColumnType("varchar(255)"); + + b.Property("BirthDate") + .HasColumnType("datetime(6)"); + + b.Property("CurrentAddress") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("EmergencyContactPerson") + .HasColumnType("longtext"); + + b.Property("EmergencyPhoneNumber") + .HasColumnType("longtext"); + + b.Property("FirstName") + .HasColumnType("longtext"); + + b.Property("Gender") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("JoiningDate") + .HasColumnType("datetime(6)"); + + b.Property("LastName") + .HasColumnType("longtext"); + + b.Property("MiddleName") + .HasColumnType("longtext"); + + b.Property("PanNumber") + .HasColumnType("longtext"); + + b.Property("PermanentAddress") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("Photo") + .HasColumnType("longblob"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationUserId"); + + b.HasIndex("JobRoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("Employees"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("RoleId"); + + b.HasIndex("TenantId"); + + b.ToTable("EmployeeRoleMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EndTime") + .HasColumnType("time(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("StartTime") + .HasColumnType("time(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkShifts"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ActivityCheckList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsChecked") + .HasColumnType("tinyint(1)"); + + b.Property("IsMandatory") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("ActivityCheckLists"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.CheckListMappings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CheckListId") + .HasColumnType("char(36)"); + + b.Property("TaskAllocationId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("CheckListMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("FeatureId") + .HasColumnType("char(36)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("FeatureId"); + + b.ToTable("FeaturePermissions"); + + b.HasData( + new + { + Id = new Guid("6ea44136-987e-44ba-9e5d-1cf8f5837ebc"), + Description = "Access all information related to the project.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project" + }, + new + { + Id = new Guid("172fc9b6-755b-4f62-ab26-55c34a330614"), + Description = "Potentially edit the project name, description, start/end dates, or status.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project" + }, + new + { + Id = new Guid("b94802ce-0689-4643-9e1d-11c86950c35b"), + Description = "The \"Manage Team\" feature allows authorized users to organize project personnel by adding, removing, and assigning employee to projects.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Team" + }, + new + { + Id = new Guid("8d7cc6e3-9147-41f7-aaa7-fa507e450bd4"), + Description = "Grants a user comprehensive read-only access to all details concerning the project's underlying systems, technologies, resources, and configurations", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "View Project Infra" + }, + new + { + Id = new Guid("cf2825ad-453b-46aa-91d9-27c124d63373"), + Description = "This allows them to create, modify, and manage all aspects of the supporting infrastructure.", + FeatureId = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + IsEnabled = true, + Name = "Manage Project Infra" + }, + new + { + Id = new Guid("9fcc5f87-25e3-4846-90ac-67a71ab92e3c"), + Description = "Grants a user comprehensive read-only access to all details associated with tasks within a project. This includes task descriptions, statuses, assignees, due dates, dependencies, progress, history, and any related attachments or discussions.", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "View Task" + }, + new + { + Id = new Guid("08752f33-3b29-4816-b76b-ea8a968ed3c5"), + Description = "This allows them to create new tasks, modify existing task attributes (description, status, assignee, due date, etc.),", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Add/Edit Task" + }, + new + { + Id = new Guid("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"), + Description = "Grants a user the ability to designate team members responsible for specific tasks and to update the completion status or provide progress updates for those tasks", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Assign/Report Progress" + }, + new + { + Id = new Guid("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c"), + Description = "Grants a user the authority to officially confirm the completion or acceptance of a task, often signifying that it meets the required standards or criteria", + FeatureId = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + IsEnabled = true, + Name = "Approve Task" + }, + new + { + Id = new Guid("60611762-7f8a-4fb5-b53f-b1139918796b"), + Description = "Grants a user read-only access to details about the all individuals within the system. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View All Employees" + }, + new + { + Id = new Guid("b82d2b7e-0d52-45f3-997b-c008ea460e7f"), + Description = "Grants a user read-only access to details about the individuals within the system which are is assigned to same projects as user. This typically includes names, contact information, roles, departments, and potentially other relevant employee data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "View Team Members" + }, + new + { + Id = new Guid("a97d366a-c2bb-448d-be93-402bd2324566"), + Description = "Grants a user the authority to create new employee profiles and modify existing employee details within the system. This typically includes adding or updating information such as names, contact details, roles, departments, skills, and potentially other personal or professional data", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Add/Edit Employee" + }, + new + { + Id = new Guid("fbd213e0-0250-46f1-9f5f-4b2a1e6e76a3"), + Description = "Grants a user the authority to manage employee application roles, enabling them to assign or revoke access privileges within the system.", + FeatureId = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + IsEnabled = true, + Name = "Assign Roles" + }, + new + { + Id = new Guid("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Team Attendance " + }, + new + { + Id = new Guid("57802c4a-00aa-4a1f-a048-fd2f70dd44b6"), + Description = "Grants a user the authority to approve requests from employees to adjust or correct their recorded attendance. This typically involves reviewing the reason for the regularization, verifying any supporting documentation, and then officially accepting the changes to the employee's attendance records", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Regularize Attendance" + }, + new + { + Id = new Guid("ccb0589f-712b-43de-92ed-5b6088e7dc4e"), + Description = "Team Attendance refers to tracking and managing the attendance of all team members collectively, often monitored by a team lead or manager.", + FeatureId = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + IsEnabled = true, + Name = "Self Attendance" + }, + new + { + Id = new Guid("5ffbafe0-7ab0-48b1-bb50-c1bf76b65f9d"), + Description = "Grants a user read-only access to foundational or reference data within the system. \"Masters\" typically refer to predefined lists, categories, or templates that are used throughout the application to standardize information and maintain consistency", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "View Masters" + }, + new + { + Id = new Guid("588a8824-f924-4955-82d8-fc51956cf323"), + Description = "Grants a user the authority to create, modify, and delete foundational or reference data within the system. These \"masters\" are typically the core lists, categories, and configurations that other data and functionalities rely upon, such as departments, job titles, product categories", + FeatureId = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + IsEnabled = true, + Name = "Manage Masters" + }, + new + { + Id = new Guid("4286a13b-bb40-4879-8c6d-18e9e393beda"), + Description = "Full control over all directories, including the ability to manage permissions for all directories in the system.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Admin" + }, + new + { + Id = new Guid("62668630-13ce-4f52-a0f0-db38af2230c5"), + Description = "Full control over directories they created or have been assigned. Can also manage permissions for those directories.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory Manager" + }, + new + { + Id = new Guid("0f919170-92d4-4337-abd3-49b66fc871bb"), + Description = "Full control over directories they created. Can view contacts in directories they either created or were assigned to. Can manage permissions only for directories they created.", + FeatureId = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + IsEnabled = true, + Name = "Directory User" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.Property("ApplicationRoleId") + .HasColumnType("char(36)"); + + b.Property("FeaturePermissionId") + .HasColumnType("char(36)"); + + b.HasKey("ApplicationRoleId", "FeaturePermissionId"); + + b.HasIndex("FeaturePermissionId"); + + b.ToTable("RolePermissionMappings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactName") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("DomainName") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OnBoardingDate") + .HasColumnType("datetime(6)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("IndustryId"); + + b.ToTable("Tenants"); + + b.HasData( + new + { + Id = new Guid("b3466e83-7e11-464c-b93a-daf047838b26"), + ContactName = "Admin", + ContactNumber = "123456789", + Description = "", + DomainName = "www.marcobms.org", + IndustryId = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + IsActive = true, + Name = "MarcoBMS", + OnBoardingDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + OragnizationSize = "100-200" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CommentId") + .HasColumnType("char(36)"); + + b.Property("FileId") + .HasColumnType("char(36)"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("CommentId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketAttachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AuthorId") + .HasColumnType("char(36)"); + + b.Property("MessageText") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ParentMessageId") + .HasColumnType("char(36)"); + + b.Property("SentAt") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("TicketComments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreatedById") + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LinkedActivityId") + .HasColumnType("char(36)"); + + b.Property("LinkedProjectId") + .HasColumnType("char(36)"); + + b.Property("PriorityId") + .HasColumnType("char(36)"); + + b.Property("StatusId") + .HasColumnType("char(36)"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TypeId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("PriorityId"); + + b.HasIndex("StatusId"); + + b.HasIndex("TenantId"); + + b.HasIndex("TypeId"); + + b.ToTable("Tickets"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("TagId") + .HasColumnType("char(36)"); + + b.Property("TicketId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TagId"); + + b.HasIndex("TicketId"); + + b.ToTable("TicketTags"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTypeMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTypeMasters"); + + b.HasData( + new + { + Id = new Guid("c74e5480-2b71-483c-8f4a-1a9c69c32603"), + Description = "An identified problem that affects the performance, reliability, or standards of a product or service", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("d1f55eab-9898-4e46-9f03-b263e33e5d38"), + Description = "A support service that assists users with technical issues, requests, or inquiries.", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("MailListId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("Recipient") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Schedule") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("MailListId"); + + b.ToTable("MailDetails"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmailId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeStamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("MailLogs"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Body") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Keywords") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("Title") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("MailingList"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityName") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("UnitOfMeasurement") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ActivityMasters"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("ModuleId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ModuleId"); + + b.ToTable("Features"); + + b.HasData( + new + { + Id = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), + Description = "Manage Project", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Project Management" + }, + new + { + Id = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), + Description = "Manage Tasks", + IsActive = true, + ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Name = "Task Management" + }, + new + { + Id = new Guid("81ab8a87-8ccd-4015-a917-0627cee6a100"), + Description = "Manage Employee", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Employee Management" + }, + new + { + Id = new Guid("52c9cf54-1eb2-44d2-81bb-524cf29c0a94"), + Description = "Attendance", + IsActive = true, + ModuleId = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Name = "Attendance Management" + }, + new + { + Id = new Guid("be3b3afc-6ccf-4566-b9b6-aafcb65546be"), + Description = "Global Masters", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Masters" + }, + new + { + Id = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), + Description = "Managing all directory related rights", + IsActive = true, + ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Name = "Directory Management" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Industry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Industries"); + + b.HasData( + new + { + Id = new Guid("15436ee3-a650-469e-bfc2-59993f7514bb"), + Name = "Information Technology (IT) Services" + }, + new + { + Id = new Guid("0a63e657-2c5f-49b5-854b-42c978293154"), + Name = "Manufacturing & Production" + }, + new + { + Id = new Guid("bdc61e3b-69ea-4394-bab6-079ec135b5bd"), + Name = "Energy & Resources" + }, + new + { + Id = new Guid("5ca200ac-00d7-415e-a410-b948e27ac9d2"), + Name = "Finance & Professional Services" + }, + new + { + Id = new Guid("d5621700-cd87-441f-8cdb-6051ddfc83b4"), + Name = "Hospitals and Healthcare Services" + }, + new + { + Id = new Guid("23608891-657e-40f0-bbd4-2b0a2ec1a76f"), + Name = "Social Services" + }, + new + { + Id = new Guid("a493f4e3-16b1-4411-be3c-6bf2987a3168"), + Name = "Retail & Consumer Services" + }, + new + { + Id = new Guid("e9d8ce92-9371-4ed9-9831-83c07f78edec"), + Name = "Transportation & Logistics" + }, + new + { + Id = new Guid("8a0d6134-2dbe-4e0a-b250-ff34cb7b9df0"), + Name = "Education & Training" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Module", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Key") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Modules"); + + b.HasData( + new + { + Id = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), + Description = "Project Module", + Key = "b04da7e9-0406-409c-ac7f-b97256e6ea02", + Name = "Project" + }, + new + { + Id = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), + Description = "Employee Module", + Key = "0971c7fb-6ce1-458a-ae3f-8d3205893637", + Name = "Employee" + }, + new + { + Id = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), + Description = "Masters Module", + Key = "504ec132-e6a9-422f-8f85-050602cfce05", + Name = "Masters" + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Status") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("StatusMasters"); + + b.HasData( + new + { + Id = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + Status = "Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("cdad86aa-8a56-4ff4-b633-9c629057dfef"), + Status = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("603e994b-a27f-4e5d-a251-f3d69b0498ba"), + Status = "On Hold", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("ef1c356e-0fe0-42df-a5d3-8daee355492d"), + Status = "In Active", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("33deaef9-9af1-4f2a-b443-681ea0d04f81"), + Status = "Completed", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketPriorityMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketPriorityMasters"); + + b.HasData( + new + { + Id = new Guid("188d29b3-10f3-42d0-9587-1a46ae7a0320"), + ColorCode = "008000", + IsDefault = true, + Level = 1, + Name = "Low", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("0919bc84-9f82-4ecf-98c7-962755dd9a97"), + ColorCode = "FFFF00", + IsDefault = true, + Level = 2, + Name = "Medium", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("a13b7e59-16fd-4665-b5cf-a97399e8445a"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 3, + Name = "High", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("f340fbc3-c9fd-46aa-b063-0093418830e4"), + ColorCode = "#FFA500", + IsDefault = true, + Level = 4, + Name = "Critical", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("44a7b91d-a0dd-45d1-8616-4d2f71e16401"), + ColorCode = "#FF0000", + IsDefault = true, + Level = 5, + Name = "Urgent", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketStatusMasters"); + + b.HasData( + new + { + Id = new Guid("6b0c409b-3e80-4165-8b39-f3fcacb4c797"), + ColorCode = "#FFCC99", + Description = "This is a newly created issue.", + IsDefault = true, + Name = "New", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("6c5ac37d-5b7d-40f3-adec-2dabaa5cca86"), + ColorCode = "#E6FF99", + Description = "Assigned to employee or team of employees", + IsDefault = true, + Name = "Assigned", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("7f96bcd5-0c66-411b-8a1d-9d1a4785194e"), + ColorCode = "#99E6FF", + Description = "These issues are currently in progress", + IsDefault = true, + Name = "In Progress", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5c72b630-6923-4215-bf2c-b1622afd76e7"), + ColorCode = "#6c757d", + Description = "These issues are currently under review", + IsDefault = true, + Name = "In Review", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("8ff85685-a875-4f21-aa95-d99551315fcc"), + ColorCode = "#B399FF", + Description = "The following issues are resolved and closed", + IsDefault = true, + Name = "Done", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.TicketTagMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ColorCode") + .HasColumnType("longtext"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("TicketTagMasters"); + + b.HasData( + new + { + Id = new Guid("ef6c2a65-f61d-4537-9650-a7ab7f8d98db"), + ColorCode = "#e59866", + IsDefault = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("5a168569-8ad7-4422-8db6-51ef25caddeb"), + ColorCode = "#85c1e9", + IsDefault = true, + Name = "Help Desk", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkCategoryMasters"); + + b.HasData( + new + { + Id = new Guid("86bb2cc8-f6b5-4fdd-bbee-c389c713a44b"), + Description = "Created new task in a professional or creative context", + IsSystem = true, + Name = "Fresh Work", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("9ebfa19c-53b9-481b-b863-c25d2f843201"), + Description = "Revising, modifying, or correcting a task to improve its quality or fix issues", + IsSystem = true, + Name = "Rework", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("11a79929-1d07-42dc-9e98-82d0d2f4a240"), + Description = "Any defect, deviation, or non-conformance in a task that fails to meet established standards or customer expectations.", + IsSystem = true, + Name = "Quality Issue", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkStatusMasters"); + + b.HasData( + new + { + Id = new Guid("030bb085-e230-4370-aec7-9a74d652864e"), + Description = "Confirm the tasks are actually finished as reported", + IsSystem = true, + Name = "Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("2a1a5b96-cf93-4111-b4b1-76c19d6333b4"), + Description = "Not all tasks are actually finished as reported", + IsSystem = true, + Name = "Partially Approve", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }, + new + { + Id = new Guid("00a062e6-62e6-42c5-b6b1-024328651b72"), + Description = "Tasks are not finished as reported or have any issues in al the tasks", + IsSystem = true, + Name = "NCR", + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("Buildings"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("BuildingId") + .HasColumnType("char(36)"); + + b.Property("FloorName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("BuildingId"); + + b.HasIndex("TenantId"); + + b.ToTable("Floor"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("EndDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProjectAddress") + .HasColumnType("longtext"); + + b.Property("ProjectStatusId") + .HasColumnType("char(36)"); + + b.Property("ShortName") + .HasColumnType("longtext"); + + b.Property("StartDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectStatusId"); + + b.HasIndex("TenantId"); + + b.ToTable("Projects"); + + b.HasData( + new + { + Id = new Guid("85bf587b-7ca9-4685-b77c-d817f5847e85"), + ContactPerson = "Project 1 Contact Person", + EndDate = new DateTime(2026, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + Name = "Project 1", + ProjectAddress = "Project 1 Address", + ProjectStatusId = new Guid("b74da4c2-d07e-46f2-9919-e75e49b12731"), + StartDate = new DateTime(2025, 4, 20, 10, 11, 17, 588, DateTimeKind.Unspecified), + TenantId = new Guid("b3466e83-7e11-464c-b93a-daf047838b26") + }); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("EmployeeId") + .HasColumnType("char(36)"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("JobRoleId") + .HasColumnType("char(36)"); + + b.Property("ProjectId") + .HasColumnType("char(36)"); + + b.Property("ReAllocationDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TenantId"); + + b.ToTable("ProjectAllocations"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AreaName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FloorId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("FloorId"); + + b.HasIndex("TenantId"); + + b.ToTable("WorkAreas"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ActivityId") + .HasColumnType("char(36)"); + + b.Property("CompletedWork") + .HasColumnType("double"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("ParentTaskId") + .HasColumnType("char(36)"); + + b.Property("PlannedWork") + .HasColumnType("double"); + + b.Property("TaskDate") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WorkAreaId") + .HasColumnType("char(36)"); + + b.Property("WorkCategoryId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ActivityId"); + + b.HasIndex("TenantId"); + + b.HasIndex("WorkAreaId"); + + b.HasIndex("WorkCategoryId"); + + b.ToTable("WorkItems"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("Role") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("ApplicationRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.ToTable("JobRoles"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Utilities.Inquiries", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("About") + .HasColumnType("longtext"); + + b.Property("ContactNumber") + .HasColumnType("longtext"); + + b.Property("ContactPerson") + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("IndustryId") + .HasColumnType("char(36)"); + + b.Property("OragnizationSize") + .HasColumnType("longtext"); + + b.Property("OrganizatioinName") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Inquiries"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("varchar(21)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("SecurityStamp") + .HasColumnType("longtext"); + + b.Property("TwoFactorEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + + b.HasDiscriminator().HasValue("IdentityUser"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("ProviderKey") + .HasColumnType("varchar(255)"); + + b.Property("ProviderDisplayName") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("RoleId") + .HasColumnType("varchar(255)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.ApplicationUser", b => + { + b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsRootUser") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasDiscriminator().HasValue("ApplicationUser"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy") + .WithMany() + .HasForeignKey("ApprovedById"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("AssignedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "ReportedBy") + .WithMany() + .HasForeignKey("ReportedById"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkItem", "WorkItem") + .WithMany() + .HasForeignKey("WorkItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkStatusMaster", "WorkStatus") + .WithMany() + .HasForeignKey("WorkStatusId"); + + b.Navigation("ApprovedBy"); + + b.Navigation("Employee"); + + b.Navigation("ReportedBy"); + + b.Navigation("Tenant"); + + b.Navigation("WorkItem"); + + b.Navigation("WorkStatus"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskComment", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("CommentedBy") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Activities.TaskMembers", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Activities.TaskAllocation", "TaskAllocation") + .WithMany() + .HasForeignKey("TaskAllocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("TaskAllocation"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.Attendance", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Approver") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Approver"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.AttendanceModule.AttendanceLog", b => + { + b.HasOne("Marco.Pms.Model.AttendanceModule.Attendance", "Attendance") + .WithMany() + .HasForeignKey("AttendanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.DocumentManager.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedByEmployee") + .WithMany() + .HasForeignKey("UpdatedBy"); + + b.Navigation("Attendance"); + + b.Navigation("Document"); + + b.Navigation("Employee"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedByEmployee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.MPINDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.OTPDetails", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Authentication.RefreshToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Bucket", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedByID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.Contact", b => + { + b.HasOne("Marco.Pms.Model.Directory.ContactCategoryMaster", "ContactCategory") + .WithMany() + .HasForeignKey("ContactCategoryId"); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("ContactCategory"); + + b.Navigation("CreatedBy"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactEmail", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactNote", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Createdby") + .WithMany() + .HasForeignKey("CreatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Contact"); + + b.Navigation("Createdby"); + + b.Navigation("Tenant"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactPhone", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactProjectMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Contact", "Contact") + .WithMany() + .HasForeignKey("ContactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Directory.ContactTagMaster", "ContactTag") + .WithMany() + .HasForeignKey("ContactTagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Contact"); + + b.Navigation("ContactTag"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.ContactTagMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.DirectoryUpdateLog", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("UpdatedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Directory.EmployeeBucketMapping", b => + { + b.HasOne("Marco.Pms.Model.Directory.Bucket", "Bucket") + .WithMany() + .HasForeignKey("BucketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bucket"); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("Marco.Pms.Model.DocumentManager.Document", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Employees.Employee", "UploadedBy") + .WithMany() + .HasForeignKey("UploadedById"); + + b.Navigation("Tenant"); + + b.Navigation("UploadedBy"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.ApplicationUser", "ApplicationUser") + .WithMany() + .HasForeignKey("ApplicationUserId"); + + b.HasOne("Marco.Pms.Model.Roles.JobRole", "JobRole") + .WithMany() + .HasForeignKey("JobRoleId"); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApplicationUser"); + + b.Navigation("JobRole"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.EmployeeRoleMapping", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", "Role") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Role"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Employees.WorkShift", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.FeaturePermission", b => + { + b.HasOne("Marco.Pms.Model.Master.Feature", "Feature") + .WithMany("FeaturePermissions") + .HasForeignKey("FeatureId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Feature"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.RolePermissionMappings", b => + { + b.HasOne("Marco.Pms.Model.Roles.ApplicationRole", null) + .WithMany() + .HasForeignKey("ApplicationRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.FeaturePermission", null) + .WithMany() + .HasForeignKey("FeaturePermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Entitlements.Tenant", b => + { + b.HasOne("Marco.Pms.Model.Master.Industry", "Industry") + .WithMany() + .HasForeignKey("IndustryId"); + + b.Navigation("Industry"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketAttachment", b => + { + b.HasOne("Marco.Pms.Model.Forum.TicketComment", "TicketComment") + .WithMany("Attachments") + .HasForeignKey("CommentId"); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ticket"); + + b.Navigation("TicketComment"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketForum", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketPriorityMaster", "Priority") + .WithMany() + .HasForeignKey("PriorityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.TicketStatusMaster", "TicketStatusMaster") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketTypeMaster", "TicketTypeMaster") + .WithMany() + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Priority"); + + b.Navigation("Tenant"); + + b.Navigation("TicketStatusMaster"); + + b.Navigation("TicketTypeMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketTag", b => + { + b.HasOne("Marco.Pms.Model.Master.TicketTagMaster", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Forum.TicketForum", "Ticket") + .WithMany() + .HasForeignKey("TicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tag"); + + b.Navigation("Ticket"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b => + { + b.HasOne("Marco.Pms.Model.Mail.MailingList", "MailBody") + .WithMany() + .HasForeignKey("MailListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MailBody"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.HasOne("Marco.Pms.Model.Master.Module", "Module") + .WithMany() + .HasForeignKey("ModuleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Module"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.StatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkCategoryMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.WorkStatusMaster", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Building", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Floor", b => + { + b.HasOne("Marco.Pms.Model.Projects.Building", "Building") + .WithMany() + .HasForeignKey("BuildingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Building"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.Project", b => + { + b.HasOne("Marco.Pms.Model.Master.StatusMaster", "ProjectStatus") + .WithMany() + .HasForeignKey("ProjectStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ProjectStatus"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.ProjectAllocation", b => + { + b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.Project", "Project") + .WithMany() + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Project"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkArea", b => + { + b.HasOne("Marco.Pms.Model.Projects.Floor", "Floor") + .WithMany() + .HasForeignKey("FloorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Floor"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Projects.WorkItem", b => + { + b.HasOne("Marco.Pms.Model.Master.ActivityMaster", "ActivityMaster") + .WithMany() + .HasForeignKey("ActivityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Projects.WorkArea", "WorkArea") + .WithMany() + .HasForeignKey("WorkAreaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Marco.Pms.Model.Master.WorkCategoryMaster", "WorkCategoryMaster") + .WithMany() + .HasForeignKey("WorkCategoryId"); + + b.Navigation("ActivityMaster"); + + b.Navigation("Tenant"); + + b.Navigation("WorkArea"); + + b.Navigation("WorkCategoryMaster"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.ApplicationRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", null) + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Roles.JobRole", b => + { + b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant") + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Marco.Pms.Model.Forum.TicketComment", b => + { + b.Navigation("Attachments"); + }); + + modelBuilder.Entity("Marco.Pms.Model.Master.Feature", b => + { + b.Navigation("FeaturePermissions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/20250702042830_Added_UploadedBy_ForeginKey_In_Decuments_Table.cs b/Marco.Pms.DataAccess/Migrations/20250702042830_Added_UploadedBy_ForeginKey_In_Decuments_Table.cs new file mode 100644 index 0000000..fd31771 --- /dev/null +++ b/Marco.Pms.DataAccess/Migrations/20250702042830_Added_UploadedBy_ForeginKey_In_Decuments_Table.cs @@ -0,0 +1,50 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Marco.Pms.DataAccess.Migrations +{ + /// + public partial class Added_UploadedBy_ForeginKey_In_Decuments_Table : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "UploadedById", + table: "Documents", + type: "char(36)", + nullable: true, + collation: "ascii_general_ci"); + + migrationBuilder.CreateIndex( + name: "IX_Documents_UploadedById", + table: "Documents", + column: "UploadedById"); + + migrationBuilder.AddForeignKey( + name: "FK_Documents_Employees_UploadedById", + table: "Documents", + column: "UploadedById", + principalTable: "Employees", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Documents_Employees_UploadedById", + table: "Documents"); + + migrationBuilder.DropIndex( + name: "IX_Documents_UploadedById", + table: "Documents"); + + migrationBuilder.DropColumn( + name: "UploadedById", + table: "Documents"); + } + } +} diff --git a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs index 26a3bdd..258f8bd 100644 --- a/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Marco.Pms.DataAccess/Migrations/ApplicationDbContextModelSnapshot.cs @@ -752,10 +752,15 @@ namespace Marco.Pms.DataAccess.Migrations b.Property("UploadedAt") .HasColumnType("datetime(6)"); + b.Property("UploadedById") + .HasColumnType("char(36)"); + b.HasKey("Id"); b.HasIndex("TenantId"); + b.HasIndex("UploadedById"); + b.ToTable("Documents"); }); @@ -2951,7 +2956,13 @@ namespace Marco.Pms.DataAccess.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("Marco.Pms.Model.Employees.Employee", "UploadedBy") + .WithMany() + .HasForeignKey("UploadedById"); + b.Navigation("Tenant"); + + b.Navigation("UploadedBy"); }); modelBuilder.Entity("Marco.Pms.Model.Employees.Employee", b => diff --git a/Marco.Pms.Model/DocumentManager/Document.cs b/Marco.Pms.Model/DocumentManager/Document.cs index 3652774..bcbe7a7 100644 --- a/Marco.Pms.Model/DocumentManager/Document.cs +++ b/Marco.Pms.Model/DocumentManager/Document.cs @@ -1,4 +1,7 @@ -using Marco.Pms.Model.Utilities; +using System.ComponentModel.DataAnnotations.Schema; +using Marco.Pms.Model.Employees; +using Marco.Pms.Model.Utilities; +using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; namespace Marco.Pms.Model.DocumentManager { @@ -16,10 +19,15 @@ namespace Marco.Pms.Model.DocumentManager /// public string? ThumbS3Key { get; set; } - public string? Base64Data { get; set; } + public string? Base64Data { get; set; } = null; public long FileSize { get; set; } public string ContentType { get; set; } = string.Empty; + public Guid? UploadedById { get; set; } + + [ValidateNever] + [ForeignKey("UploadedById")] + public Employee? UploadedBy { get; set; } public DateTime UploadedAt { get; set; } } } From b77a5b16cdbb3fcd19532c64ede073b82eed7346 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 2 Jul 2025 10:01:10 +0530 Subject: [PATCH 02/17] Storing batch ID when saving any images as well stop storing base64 in database --- Marco.Pms.Model/Mapper/ForumMapper.cs | 14 ++++++--- .../Controllers/AttendanceController.cs | 11 ++++--- .../Controllers/ForumController.cs | 31 +++++++++++++++---- .../Controllers/TaskController.cs | 20 +++++++++--- 4 files changed, 57 insertions(+), 19 deletions(-) diff --git a/Marco.Pms.Model/Mapper/ForumMapper.cs b/Marco.Pms.Model/Mapper/ForumMapper.cs index c5f84ba..cf15331 100644 --- a/Marco.Pms.Model/Mapper/ForumMapper.cs +++ b/Marco.Pms.Model/Mapper/ForumMapper.cs @@ -90,29 +90,35 @@ namespace Marco.Pms.Model.Mapper }; } - public static Document ToDocumentFromForumAttachmentDto(this ForumAttachmentDto AttachmentDto, string objectKey, string thumbS3Key, DateTime uploadedAt, Guid tenantId) + public static Document ToDocumentFromForumAttachmentDto(this ForumAttachmentDto AttachmentDto, string objectKey, string thumbS3Key, DateTime uploadedAt, + Guid tenantId, Guid batchId, Guid loggedInEmployeeId) { return new Document { + BatchId = batchId, + UploadedById = loggedInEmployeeId, FileName = AttachmentDto.FileName, ContentType = AttachmentDto.ContentType, S3Key = objectKey, ThumbS3Key = thumbS3Key, - Base64Data = AttachmentDto.Base64Data, + //Base64Data = AttachmentDto.Base64Data, FileSize = AttachmentDto.FileSize, UploadedAt = uploadedAt, TenantId = tenantId }; } - public static Document ToDocumentFromUpdateAttachmentDto(this UpdateAttachmentDto AttachmentDto, string objectKey, string thumbS3Key, DateTime uploadedAt, Guid tenantId) + public static Document ToDocumentFromUpdateAttachmentDto(this UpdateAttachmentDto AttachmentDto, string objectKey, string thumbS3Key, DateTime uploadedAt, + Guid tenantId, Guid batchId, Guid loggedInEmployeeId) { return new Document { + BatchId = batchId, + UploadedById = loggedInEmployeeId, FileName = AttachmentDto.FileName, ContentType = AttachmentDto.ContentType, S3Key = objectKey, ThumbS3Key = thumbS3Key, - Base64Data = AttachmentDto.Base64Data, + //Base64Data = AttachmentDto.Base64Data, FileSize = AttachmentDto.FileSize, UploadedAt = uploadedAt, TenantId = tenantId diff --git a/Marco.Pms.Services/Controllers/AttendanceController.cs b/Marco.Pms.Services/Controllers/AttendanceController.cs index d23a007..2622323 100644 --- a/Marco.Pms.Services/Controllers/AttendanceController.cs +++ b/Marco.Pms.Services/Controllers/AttendanceController.cs @@ -603,7 +603,8 @@ namespace MarcoBMS.Services.Controllers } Guid tenantId = GetTenantId(); - var currentEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var batchId = Guid.NewGuid(); using var transaction = await _context.Database.BeginTransactionAsync(); try @@ -704,10 +705,12 @@ namespace MarcoBMS.Services.Controllers document = new Document { + BatchId = batchId, + UploadedById = loggedInEmployee.Id, FileName = recordAttendanceDot.Image.FileName ?? "", ContentType = recordAttendanceDot.Image.ContentType, S3Key = objectKey, - Base64Data = recordAttendanceDot.Image.Base64Data, + //Base64Data = recordAttendanceDot.Image.Base64Data, FileSize = recordAttendanceDot.Image.FileSize, UploadedAt = recordAttendanceDot.Date, TenantId = tenantId @@ -728,7 +731,7 @@ namespace MarcoBMS.Services.Controllers Longitude = recordAttendanceDot.Longitude, DocumentId = document?.Id, TenantId = tenantId, - UpdatedBy = recordAttendanceDot.EmployeeID, + UpdatedBy = loggedInEmployee.Id, UpdatedOn = recordAttendanceDot.Date }; _context.AttendanceLogs.Add(attendanceLog); @@ -755,7 +758,7 @@ namespace MarcoBMS.Services.Controllers var notification = new { - LoggedInUserId = currentEmployee.Id, + LoggedInUserId = loggedInEmployee.Id, Keyword = "Attendance", Activity = recordAttendanceDot.Id == Guid.Empty ? 1 : 0, ProjectId = attendance.ProjectID, diff --git a/Marco.Pms.Services/Controllers/ForumController.cs b/Marco.Pms.Services/Controllers/ForumController.cs index f50a077..769c08a 100644 --- a/Marco.Pms.Services/Controllers/ForumController.cs +++ b/Marco.Pms.Services/Controllers/ForumController.cs @@ -48,6 +48,8 @@ namespace Marco.Pms.Services.Controllers return BadRequest(ApiResponse.ErrorResponse("Invalid data", errors, 400)); } Guid tenantId = _userHelper.GetTenantId(); + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var batchId = Guid.NewGuid(); TicketForum ticketForum = createTicketDto.ToTicketForumFromCreateTicketDto(tenantId); _context.Tickets.Add(ticketForum); await _context.SaveChangesAsync(); @@ -79,7 +81,7 @@ namespace Marco.Pms.Services.Controllers string objectKey = $"tenant-{tenantId}/project-{createTicketDto.LinkedProjectId}/froum/{fileName}"; await _s3Service.UploadFileAsync(base64, fileType, objectKey); - Document document = attachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, createTicketDto.CreatedAt, tenantId); + Document document = attachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, createTicketDto.CreatedAt, tenantId, batchId, loggedInEmployee.Id); _context.Documents.Add(document); await _context.SaveChangesAsync(); @@ -162,7 +164,15 @@ namespace Marco.Pms.Services.Controllers return BadRequest(ApiResponse.ErrorResponse("Invalid data", errors, 400)); } Guid tenantId = _userHelper.GetTenantId(); - var existingTicket = await _context.Tickets.Include(t => t.TicketTypeMaster).Include(t => t.TicketStatusMaster).Include(t => t.Priority).AsNoTracking().FirstOrDefaultAsync(t => t.Id == updateTicketDto.Id); + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var batchId = Guid.NewGuid(); + + var existingTicket = await _context.Tickets + .Include(t => t.TicketTypeMaster) + .Include(t => t.TicketStatusMaster) + .Include(t => t.Priority) + .AsNoTracking() + .FirstOrDefaultAsync(t => t.Id == updateTicketDto.Id); if (existingTicket != null) { TicketForum ticketForum = updateTicketDto.ToTicketForumFromUpdateTicketDto(existingTicket); @@ -202,7 +212,7 @@ namespace Marco.Pms.Services.Controllers string objectKey = $"tenant-{tenantId}/project-{updateTicketDto.LinkedProjectId}/froum/{fileName}"; await _s3Service.UploadFileAsync(base64, fileType, objectKey); - Document document = attachmentDto.ToDocumentFromUpdateAttachmentDto(objectKey, objectKey, updateTicketDto.CreatedAt, tenantId); + Document document = attachmentDto.ToDocumentFromUpdateAttachmentDto(objectKey, objectKey, updateTicketDto.CreatedAt, tenantId, batchId, loggedInEmployee.Id); _context.Documents.Add(document); await _context.SaveChangesAsync(); @@ -344,6 +354,9 @@ namespace Marco.Pms.Services.Controllers } Guid tenantId = _userHelper.GetTenantId(); + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var batchId = Guid.NewGuid(); + List attachments = new List(); List documents = new List(); @@ -381,7 +394,7 @@ namespace Marco.Pms.Services.Controllers string objectKey = $"tenant-{tenantId}/project-{ticket.LinkedProjectId}/froum/{fileName}"; await _s3Service.UploadFileAsync(base64, fileType, objectKey); - Document document = attachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, addCommentDto.SentAt, tenantId); + Document document = attachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, addCommentDto.SentAt, tenantId, batchId, loggedInEmployee.Id); _context.Documents.Add(document); await _context.SaveChangesAsync(); @@ -429,6 +442,9 @@ namespace Marco.Pms.Services.Controllers } Guid tenantId = _userHelper.GetTenantId(); + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var batchId = Guid.NewGuid(); + List attachments = new List(); TicketForum? ticket = await _context.Tickets.FirstOrDefaultAsync(t => t.Id == updateCommentDto.TicketId); @@ -473,7 +489,7 @@ namespace Marco.Pms.Services.Controllers string objectKey = $"tenant-{tenantId}/project-{ticket.LinkedProjectId}/froum/{fileName}"; await _s3Service.UploadFileAsync(base64, fileType, objectKey); - Document document = attachmentDto.ToDocumentFromUpdateAttachmentDto(objectKey, objectKey, existingComment.SentAt, tenantId); + Document document = attachmentDto.ToDocumentFromUpdateAttachmentDto(objectKey, objectKey, existingComment.SentAt, tenantId, batchId, loggedInEmployee.Id); _context.Documents.Add(document); await _context.SaveChangesAsync(); @@ -541,6 +557,9 @@ namespace Marco.Pms.Services.Controllers } Guid tenantId = _userHelper.GetTenantId(); + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var batchId = Guid.NewGuid(); + List ticketAttachmentVMs = new List(); List ticketIds = forumAttachmentDtos.Select(f => f.TicketId.HasValue ? f.TicketId.Value : Guid.Empty).ToList(); @@ -579,7 +598,7 @@ namespace Marco.Pms.Services.Controllers string objectKey = $"tenant-{tenantId}/project-{ticket?.LinkedProjectId}/froum/{fileName}"; await _s3Service.UploadFileAsync(base64, fileType, objectKey); - Document document = forumAttachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, forumAttachmentDto.SentAt, tenantId); + Document document = forumAttachmentDto.ToDocumentFromForumAttachmentDto(objectKey, objectKey, forumAttachmentDto.SentAt, tenantId, batchId, loggedInEmployee.Id); _context.Documents.Add(document); await _context.SaveChangesAsync(); diff --git a/Marco.Pms.Services/Controllers/TaskController.cs b/Marco.Pms.Services/Controllers/TaskController.cs index 6b55c3f..5a35baf 100644 --- a/Marco.Pms.Services/Controllers/TaskController.cs +++ b/Marco.Pms.Services/Controllers/TaskController.cs @@ -204,6 +204,7 @@ namespace MarcoBMS.Services.Controllers var building = await _context.Buildings .FirstOrDefaultAsync(b => b.Id == buildingId); + var batchId = Guid.NewGuid(); foreach (var image in reportTask.Images) { @@ -225,10 +226,12 @@ namespace MarcoBMS.Services.Controllers var document = new Document { + BatchId = batchId, + UploadedById = loggedInEmployee.Id, FileName = image.FileName ?? "", ContentType = image.ContentType ?? "", S3Key = objectKey, - Base64Data = image.Base64Data, + //Base64Data = image.Base64Data, FileSize = image.FileSize, UploadedAt = DateTime.UtcNow, TenantId = tenantId @@ -265,7 +268,7 @@ namespace MarcoBMS.Services.Controllers _logger.LogInfo("AddCommentForTask called for TaskAllocationId: {TaskId}", createComment.TaskAllocationId); var tenantId = GetTenantId(); - var employee = await _userHelper.GetCurrentEmployeeAsync(); + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); // Validate Task Allocation and associated WorkItem var taskAllocation = await _context.TaskAllocations @@ -287,13 +290,14 @@ namespace MarcoBMS.Services.Controllers var building = await _context.Buildings.FirstOrDefaultAsync(b => b.Id == buildingId); // Save comment - var comment = createComment.ToCommentFromCommentDto(tenantId, employee.Id); + var comment = createComment.ToCommentFromCommentDto(tenantId, loggedInEmployee.Id); _context.TaskComments.Add(comment); await _context.SaveChangesAsync(); _logger.LogInfo("Comment saved with Id: {CommentId}", comment.Id); // Process image uploads var images = createComment.Images; + var batchId = Guid.NewGuid(); if (images != null && images.Any()) { @@ -319,10 +323,12 @@ namespace MarcoBMS.Services.Controllers var document = new Document { + BatchId = batchId, + UploadedById = loggedInEmployee.Id, FileName = image.FileName ?? string.Empty, ContentType = image.ContentType ?? fileType, S3Key = objectKey, - Base64Data = image.Base64Data, + //Base64Data = image.Base64Data, FileSize = image.FileSize, UploadedAt = DateTime.UtcNow, TenantId = tenantId @@ -731,6 +737,8 @@ namespace MarcoBMS.Services.Controllers var building = await _context.Buildings .FirstOrDefaultAsync(b => b.Id == buildingId); + var batchId = Guid.NewGuid(); + foreach (var image in approveTask.Images) { if (string.IsNullOrEmpty(image.Base64Data)) @@ -749,10 +757,12 @@ namespace MarcoBMS.Services.Controllers var document = new Document { + BatchId = batchId, + UploadedById = loggedInEmployee.Id, FileName = fileName, ContentType = image.ContentType ?? string.Empty, S3Key = objectKey, - Base64Data = image.Base64Data, + //Base64Data = image.Base64Data, FileSize = image.FileSize, UploadedAt = DateTime.UtcNow, TenantId = tenantId From 587e8d2b0b6c341b31122bab4ebd8105e3d10964 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 2 Jul 2025 10:02:22 +0530 Subject: [PATCH 03/17] Added an API to get list of images in provided project. --- .../Controllers/ImageController.cs | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 Marco.Pms.Services/Controllers/ImageController.cs diff --git a/Marco.Pms.Services/Controllers/ImageController.cs b/Marco.Pms.Services/Controllers/ImageController.cs new file mode 100644 index 0000000..7a4c556 --- /dev/null +++ b/Marco.Pms.Services/Controllers/ImageController.cs @@ -0,0 +1,171 @@ +using Marco.Pms.DataAccess.Data; +using Marco.Pms.Model.Employees; +using Marco.Pms.Model.Mapper; +using Marco.Pms.Model.Utilities; +using Marco.Pms.Services.Service; +using MarcoBMS.Services.Helpers; +using MarcoBMS.Services.Service; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace Marco.Pms.Services.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class ImageController : ControllerBase + { + private readonly ApplicationDbContext _context; + private readonly S3UploadService _s3Service; + private readonly UserHelper _userHelper; + private readonly ILoggingService _logger; + private readonly PermissionServices _permission; + private readonly Guid tenantId; + public ImageController(ApplicationDbContext context, S3UploadService s3Service, UserHelper userHelper, ILoggingService logger, PermissionServices permission) + { + _context = context; + _s3Service = s3Service; + _userHelper = userHelper; + _logger = logger; + tenantId = userHelper.GetTenantId(); + _permission = permission; + } + + [HttpGet("images/{projectId}")] + public async Task GetImageList(Guid projectId) + { + _logger.LogInfo("GetImageList called for ProjectId: {ProjectId}", projectId); + + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + + // Step 1: Validate project existence + var isProjectExist = await _context.Projects.AnyAsync(p => p.Id == projectId && p.TenantId == tenantId); + if (!isProjectExist) + { + _logger.LogWarning("Project not found for ProjectId: {ProjectId}", projectId); + return BadRequest(ApiResponse.ErrorResponse("Project not found", "Project not found in database", 400)); + } + + // Step 2: Check permission + var hasPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId.ToString()); + if (!hasPermission) + { + _logger.LogWarning("No access to ProjectId: {ProjectId} for EmployeeId: {EmployeeId}", projectId, loggedInEmployee.Id); + return StatusCode(403, ApiResponse.ErrorResponse("You don't have access", "You don't have access", 403)); + } + + // Step 3: Fetch building > floor > work area > work item hierarchy + var buildings = await _context.Buildings + .Where(b => b.ProjectId == projectId) + .Select(b => new { b.Id, b.Name }) + .ToListAsync(); + + var buildingIds = buildings.Select(b => b.Id).ToList(); + + var floors = await _context.Floor + .Where(f => buildingIds.Contains(f.BuildingId)) + .Select(f => new { f.Id, f.BuildingId, f.FloorName }) + .ToListAsync(); + + var floorIds = floors.Select(f => f.Id).ToList(); + + var workAreas = await _context.WorkAreas + .Where(wa => floorIds.Contains(wa.FloorId)) + .Select(wa => new { wa.Id, wa.FloorId, wa.AreaName }) + .ToListAsync(); + + var workAreaIds = workAreas.Select(wa => wa.Id).ToList(); + + var workItems = await _context.WorkItems + .Include(wi => wi.ActivityMaster) + .Where(wi => workAreaIds.Contains(wi.WorkAreaId)) + .Select(wi => new { wi.Id, wi.WorkAreaId, wi.ActivityMaster }) + .ToListAsync(); + + var workItemIds = workItems.Select(wi => wi.Id).ToList(); + + // Step 4: Fetch task and comment data + var tasks = await _context.TaskAllocations + .Include(t => t.ReportedBy) + .Where(t => workItemIds.Contains(t.WorkItemId)) + .ToListAsync(); + + var taskIds = tasks.Select(t => t.Id).ToList(); + + var comments = await _context.TaskComments + .Include(c => c.Employee) + .Where(c => taskIds.Contains(c.TaskAllocationId)) + .ToListAsync(); + + var commentIds = comments.Select(c => c.Id).ToList(); + + // Step 5: Fetch attachments and related documents + var attachments = await _context.TaskAttachments + .Where(ta => taskIds.Contains(ta.ReferenceId) || commentIds.Contains(ta.ReferenceId)) + .ToListAsync(); + + var documentIds = attachments.Select(ta => ta.DocumentId).ToList(); + + var documents = await _context.Documents + .Include(d => d.UploadedBy) + .Where(d => documentIds.Contains(d.Id)) + .ToListAsync(); + + // Step 6: Prepare view models + var documentVM = documents + .Select(d => + { + var referenceId = attachments + .Where(ta => ta.DocumentId == d.Id) + .Select(ta => ta.ReferenceId) + .FirstOrDefault(); + + var task = tasks.FirstOrDefault(t => t.Id == referenceId); + var comment = comments.FirstOrDefault(c => c.Id == referenceId); + + string source = ""; + Employee? uploadedBy = null; + if (task != null) + { + uploadedBy = task.ReportedBy; + source = "Report"; + } + else if (comment != null) + { + task = tasks.FirstOrDefault(t => t.Id == comment.TaskAllocationId); + uploadedBy = comment.Employee; + source = "Comment"; + } + + var workItem = workItems.FirstOrDefault(wi => wi.Id == task?.WorkItemId); + var workArea = workAreas.FirstOrDefault(wa => wa.Id == workItem?.WorkAreaId); + var floor = floors.FirstOrDefault(f => f.Id == workArea?.FloorId); + var building = buildings.FirstOrDefault(b => b.Id == floor?.BuildingId); + + return new + { + Id = d.Id, + BatchId = d.BatchId, + thumbnailUrl = d.ThumbS3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.ThumbS3Key) : (d.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.S3Key) : null), + ImageUrl = d.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.S3Key) : null, + UploadedBy = d.UploadedBy?.ToBasicEmployeeVMFromEmployee() ?? uploadedBy?.ToBasicEmployeeVMFromEmployee(), + UploadedAt = d.UploadedAt, + Source = source, + ProjectId = projectId, + BuildingId = building?.Id, + BuildingName = building?.Name, + FloorIds = floor?.Id, + FloorName = floor?.FloorName, + WorkAreaId = workArea?.Id, + WorkAreaName = workArea?.AreaName, + TaskId = task?.Id, + ActivityName = workItem?.ActivityMaster?.ActivityName, + CommentId = comment?.Id, + Comment = comment?.Comment + }; + }).ToList(); + + _logger.LogInfo("Image list fetched for ProjectId: {ProjectId}. Total documents: {Count}", projectId, documentVM.Count); + return Ok(ApiResponse.SuccessResponse(documentVM, $"{documentVM.Count} image records fetched successfully", 200)); + } + } +} From afdf51eae3b3a0353b41e0ac6b27f8f718b3e2a4 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 2 Jul 2025 10:03:20 +0530 Subject: [PATCH 04/17] Added an API to get list of Images for provided batch ID --- .../Controllers/ImageController.cs | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/Marco.Pms.Services/Controllers/ImageController.cs b/Marco.Pms.Services/Controllers/ImageController.cs index 7a4c556..2a1b057 100644 --- a/Marco.Pms.Services/Controllers/ImageController.cs +++ b/Marco.Pms.Services/Controllers/ImageController.cs @@ -1,6 +1,8 @@ using Marco.Pms.DataAccess.Data; +using Marco.Pms.Model.Activities; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Mapper; +using Marco.Pms.Model.Projects; using Marco.Pms.Model.Utilities; using Marco.Pms.Services.Service; using MarcoBMS.Services.Helpers; @@ -167,5 +169,108 @@ namespace Marco.Pms.Services.Controllers _logger.LogInfo("Image list fetched for ProjectId: {ProjectId}. Total documents: {Count}", projectId, documentVM.Count); return Ok(ApiResponse.SuccessResponse(documentVM, $"{documentVM.Count} image records fetched successfully", 200)); } + + [HttpGet("batch/{batchId}")] + public async Task GetImagesByBatch(Guid batchId) + { + _logger.LogInfo("GetImagesByBatch called for BatchId: {BatchId}", batchId); + + // Step 1: Get the logged-in employee + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + + // Step 2: Retrieve all documents in the batch + var documents = await _context.Documents + .Include(d => d.UploadedBy) + .Where(d => d.BatchId == batchId) + .ToListAsync(); + + if (!documents.Any()) + { + _logger.LogWarning("No documents found for BatchId: {BatchId}", batchId); + return NotFound(ApiResponse.ErrorResponse("No images found", "No images associated with this batch", 404)); + } + + var documentIds = documents.Select(d => d.Id).ToList(); + + // Step 3: Get task/comment reference IDs linked to these documents + var referenceIds = await _context.TaskAttachments + .Where(ta => documentIds.Contains(ta.DocumentId)) + .Select(ta => ta.ReferenceId) + .Distinct() + .ToListAsync(); + + // Step 4: Try to identify the source of the attachment (task or comment) + var task = await _context.TaskAllocations + .Include(t => t.ReportedBy) + .FirstOrDefaultAsync(t => referenceIds.Contains(t.Id)); + + TaskComment? comment = null; + WorkItem? workItem = null; + Employee? uploadedBy = null; + string source = ""; + + if (task != null) + { + uploadedBy = task.ReportedBy; + workItem = await _context.WorkItems + .Include(wi => wi.ActivityMaster) + .FirstOrDefaultAsync(wi => wi.Id == task.WorkItemId); + source = "Report"; + } + else + { + comment = await _context.TaskComments + .Include(tc => tc.TaskAllocation) + .Include(tc => tc.Employee) + .FirstOrDefaultAsync(tc => referenceIds.Contains(tc.Id)); + var workItemId = comment?.TaskAllocation?.WorkItemId; + + uploadedBy = comment?.Employee; + workItem = await _context.WorkItems + .Include(wi => wi.ActivityMaster) + .FirstOrDefaultAsync(wi => wi.Id == workItemId); + source = "Comment"; + } + + // Step 5: Traverse up to building level + var workAreaId = workItem?.WorkAreaId; + var workArea = await _context.WorkAreas + .Include(wa => wa.Floor) + .FirstOrDefaultAsync(wa => wa.Id == workAreaId); + + var buildingId = workArea?.Floor?.BuildingId; + var building = await _context.Buildings + .FirstOrDefaultAsync(b => b.Id == buildingId); + + // Step 6: Construct the response + var response = documents.Select(d => new + { + Id = d.Id, + BatchId = d.BatchId, + thumbnailUrl = d.ThumbS3Key != null + ? _s3Service.GeneratePreSignedUrlAsync(d.ThumbS3Key) + : (d.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.S3Key) : null), + ImageUrl = d.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.S3Key) : null, + UploadedBy = d.UploadedBy?.ToBasicEmployeeVMFromEmployee() ?? uploadedBy?.ToBasicEmployeeVMFromEmployee(), + UploadedAt = d.UploadedAt, + Source = source, + ProjectId = building?.ProjectId, + BuildingId = building?.Id, + BuildingName = building?.Name, + FloorIds = workArea?.Floor?.Id, + FloorName = workArea?.Floor?.FloorName, + WorkAreaId = workArea?.Id, + WorkAreaName = workArea?.AreaName, + TaskId = task?.Id, + ActivityName = workItem?.ActivityMaster?.ActivityName, + CommentId = comment?.Id, + Comment = comment?.Comment + }).ToList(); + + _logger.LogInfo("Fetched {Count} image(s) for BatchId: {BatchId}", response.Count, batchId); + + return Ok(ApiResponse.SuccessResponse(response, "Images for provided batchId fetched successfully", 200)); + } + } } From 85911c4536a0c12443cc6ca5dcb7374534cb1504 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 2 Jul 2025 10:04:00 +0530 Subject: [PATCH 05/17] Added an API to get persigned url for provided document --- .../Controllers/ImageController.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Marco.Pms.Services/Controllers/ImageController.cs b/Marco.Pms.Services/Controllers/ImageController.cs index 2a1b057..fedc067 100644 --- a/Marco.Pms.Services/Controllers/ImageController.cs +++ b/Marco.Pms.Services/Controllers/ImageController.cs @@ -272,5 +272,44 @@ namespace Marco.Pms.Services.Controllers return Ok(ApiResponse.SuccessResponse(response, "Images for provided batchId fetched successfully", 200)); } + [HttpGet("{documentId}")] + public async Task GetImage(Guid documentId) + { + // Log the start of the image fetch process + _logger.LogInfo("GetImage called for DocumentId: {DocumentId}", documentId); + + // Step 1: Get the currently logged-in employee (for future use like permission checks or auditing) + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + + // Step 2: Fetch the document from the database based on the provided ID + var document = await _context.Documents.FirstOrDefaultAsync(d => d.Id == documentId); + + // Step 3: If document doesn't exist, return a 400 Bad Request response + if (document == null) + { + _logger.LogWarning("Document not found for DocumentId: {DocumentId}", documentId); + return BadRequest(ApiResponse.ErrorResponse("Document not found", "Document not found", 400)); + } + + // Step 4: Generate pre-signed URLs for thumbnail and full image (if keys exist) + string? thumbnailUrl = document.ThumbS3Key != null + ? _s3Service.GeneratePreSignedUrlAsync(document.ThumbS3Key) + : null; + + string? imageUrl = document.S3Key != null + ? _s3Service.GeneratePreSignedUrlAsync(document.S3Key) + : null; + + // Step 5: Prepare the response object + var response = new + { + ThumbnailUrl = thumbnailUrl, + ImageUrl = imageUrl + }; + + // Step 6: Log successful fetch and return the result + _logger.LogInfo("Image fetched successfully for DocumentId: {DocumentId}", documentId); + return Ok(ApiResponse.SuccessResponse(response, "Image fetched successfully", 200)); + } } } From 8353c384a5916a3fb0d5b205e98f9ebccfcb864e Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 2 Jul 2025 10:15:00 +0530 Subject: [PATCH 06/17] Added athorization in controller --- Marco.Pms.Services/Controllers/ImageController.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Marco.Pms.Services/Controllers/ImageController.cs b/Marco.Pms.Services/Controllers/ImageController.cs index fedc067..635d357 100644 --- a/Marco.Pms.Services/Controllers/ImageController.cs +++ b/Marco.Pms.Services/Controllers/ImageController.cs @@ -7,6 +7,7 @@ using Marco.Pms.Model.Utilities; using Marco.Pms.Services.Service; using MarcoBMS.Services.Helpers; using MarcoBMS.Services.Service; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -14,6 +15,7 @@ namespace Marco.Pms.Services.Controllers { [Route("api/[controller]")] [ApiController] + [Authorize] public class ImageController : ControllerBase { private readonly ApplicationDbContext _context; From 1f5a71ef092ad64b72899cad369c35c49b9775a6 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 2 Jul 2025 13:15:28 +0530 Subject: [PATCH 07/17] Added WorkCategoryName and WorkCategoryId Parameters in view models --- Marco.Pms.Services/Controllers/ImageController.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Marco.Pms.Services/Controllers/ImageController.cs b/Marco.Pms.Services/Controllers/ImageController.cs index 635d357..19af70f 100644 --- a/Marco.Pms.Services/Controllers/ImageController.cs +++ b/Marco.Pms.Services/Controllers/ImageController.cs @@ -81,8 +81,9 @@ namespace Marco.Pms.Services.Controllers var workItems = await _context.WorkItems .Include(wi => wi.ActivityMaster) + .Include(wi => wi.WorkCategoryMaster) .Where(wi => workAreaIds.Contains(wi.WorkAreaId)) - .Select(wi => new { wi.Id, wi.WorkAreaId, wi.ActivityMaster }) + .Select(wi => new { wi.Id, wi.WorkAreaId, wi.ActivityMaster, wi.WorkCategoryMaster }) .ToListAsync(); var workItemIds = workItems.Select(wi => wi.Id).ToList(); @@ -163,6 +164,8 @@ namespace Marco.Pms.Services.Controllers WorkAreaName = workArea?.AreaName, TaskId = task?.Id, ActivityName = workItem?.ActivityMaster?.ActivityName, + WorkCategoryId = workItem?.WorkCategoryMaster?.Id, + WorkCategoryName = workItem?.WorkCategoryMaster?.Name, CommentId = comment?.Id, Comment = comment?.Comment }; @@ -216,6 +219,7 @@ namespace Marco.Pms.Services.Controllers uploadedBy = task.ReportedBy; workItem = await _context.WorkItems .Include(wi => wi.ActivityMaster) + .Include(wi => wi.WorkCategoryMaster) .FirstOrDefaultAsync(wi => wi.Id == task.WorkItemId); source = "Report"; } @@ -230,6 +234,7 @@ namespace Marco.Pms.Services.Controllers uploadedBy = comment?.Employee; workItem = await _context.WorkItems .Include(wi => wi.ActivityMaster) + .Include(wi => wi.WorkCategoryMaster) .FirstOrDefaultAsync(wi => wi.Id == workItemId); source = "Comment"; } @@ -265,6 +270,8 @@ namespace Marco.Pms.Services.Controllers WorkAreaName = workArea?.AreaName, TaskId = task?.Id, ActivityName = workItem?.ActivityMaster?.ActivityName, + WorkCategoryId = workItem?.WorkCategoryMaster?.Id, + WorkCategoryName = workItem?.WorkCategoryMaster?.Name, CommentId = comment?.Id, Comment = comment?.Comment }).ToList(); From 62eb914456c0e64f57d1c67070d81e00aa575dfd Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Wed, 2 Jul 2025 17:42:42 +0530 Subject: [PATCH 08/17] Added filter in get image list API --- Marco.Pms.Model/Utilities/ImageFilter.cs | 14 ++ .../Controllers/ImageController.cs | 236 +++++++++++------- 2 files changed, 156 insertions(+), 94 deletions(-) create mode 100644 Marco.Pms.Model/Utilities/ImageFilter.cs diff --git a/Marco.Pms.Model/Utilities/ImageFilter.cs b/Marco.Pms.Model/Utilities/ImageFilter.cs new file mode 100644 index 0000000..a5cb7f7 --- /dev/null +++ b/Marco.Pms.Model/Utilities/ImageFilter.cs @@ -0,0 +1,14 @@ +namespace Marco.Pms.Model.Utilities +{ + public class ImageFilter + { + public List? BuildingIds { get; set; } + public List? FloorIds { get; set; } + public List? WorkAreaIds { get; set; } + public List? WorkCategoryIds { get; set; } + public List? ActivityIds { get; set; } + public List? UploadedByIds { get; set; } + public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } + } +} diff --git a/Marco.Pms.Services/Controllers/ImageController.cs b/Marco.Pms.Services/Controllers/ImageController.cs index 19af70f..eaab3c6 100644 --- a/Marco.Pms.Services/Controllers/ImageController.cs +++ b/Marco.Pms.Services/Controllers/ImageController.cs @@ -1,4 +1,5 @@ -using Marco.Pms.DataAccess.Data; +using System.Text.Json; +using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Activities; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Mapper; @@ -35,9 +36,10 @@ namespace Marco.Pms.Services.Controllers } [HttpGet("images/{projectId}")] - public async Task GetImageList(Guid projectId) + + public async Task GetImageList(Guid projectId, [FromQuery] string? filter) { - _logger.LogInfo("GetImageList called for ProjectId: {ProjectId}", projectId); + _logger.LogInfo("[GetImageList] Called by Employee for ProjectId: {ProjectId}", projectId); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); @@ -45,133 +47,178 @@ namespace Marco.Pms.Services.Controllers var isProjectExist = await _context.Projects.AnyAsync(p => p.Id == projectId && p.TenantId == tenantId); if (!isProjectExist) { - _logger.LogWarning("Project not found for ProjectId: {ProjectId}", projectId); + _logger.LogWarning("[GetImageList] ProjectId: {ProjectId} not found", projectId); return BadRequest(ApiResponse.ErrorResponse("Project not found", "Project not found in database", 400)); } - // Step 2: Check permission + // Step 2: Check project access permission var hasPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId.ToString()); if (!hasPermission) { - _logger.LogWarning("No access to ProjectId: {ProjectId} for EmployeeId: {EmployeeId}", projectId, loggedInEmployee.Id); + _logger.LogWarning("[GetImageList] Access denied for EmployeeId: {EmployeeId} on ProjectId: {ProjectId}", loggedInEmployee.Id, projectId); return StatusCode(403, ApiResponse.ErrorResponse("You don't have access", "You don't have access", 403)); } + // Step 3: Deserialize filter + ImageFilter? imageFilter = null; + if (!string.IsNullOrWhiteSpace(filter)) + { + try + { + var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + string unescapedJsonString = JsonSerializer.Deserialize(filter, options) ?? ""; + imageFilter = JsonSerializer.Deserialize(unescapedJsonString, options); + } + catch (Exception ex) + { + _logger.LogWarning("[GetImageList] Failed to parse filter: {Message}", ex.Message); + } + } + + // Step 4: Extract filter values + var buildingIds = imageFilter?.BuildingIds; + var floorIds = imageFilter?.FloorIds; + var workAreaIds = imageFilter?.WorkAreaIds; + var activityIds = imageFilter?.ActivityIds; + var workCategoryIds = imageFilter?.WorkCategoryIds; + var startDate = imageFilter?.StartDate; + var endDate = imageFilter?.EndDate; + var uploadedByIds = imageFilter?.UploadedByIds; + + // Step 5: Fetch building > floor > area > work item hierarchy // Step 3: Fetch building > floor > work area > work item hierarchy - var buildings = await _context.Buildings + List? buildings = null; + List? floors = null; + List? workAreas = null; + //List? workItems = null; + //List? documents = null; + + if (buildingIds != null && buildingIds.Count > 0) + { + + buildings = await _context.Buildings + .Where(b => b.ProjectId == projectId && buildingIds.Contains(b.Id)) + .ToListAsync(); + } + else + { + buildings = await _context.Buildings .Where(b => b.ProjectId == projectId) - .Select(b => new { b.Id, b.Name }) .ToListAsync(); - var buildingIds = buildings.Select(b => b.Id).ToList(); + buildingIds = buildings.Select(b => b.Id).ToList(); + } - var floors = await _context.Floor + if (floorIds != null && floorIds.Count > 0) + { + floors = await _context.Floor + .Where(f => buildingIds.Contains(f.BuildingId) && floorIds.Contains(f.Id)) + .ToListAsync(); + } + else + { + floors = await _context.Floor .Where(f => buildingIds.Contains(f.BuildingId)) - .Select(f => new { f.Id, f.BuildingId, f.FloorName }) .ToListAsync(); - var floorIds = floors.Select(f => f.Id).ToList(); - - var workAreas = await _context.WorkAreas + floorIds = floors.Select(f => f.Id).ToList(); + } + if (workAreaIds != null && workAreaIds.Count > 0) + { + workAreas = await _context.WorkAreas + .Where(wa => floorIds.Contains(wa.FloorId) && workAreaIds.Contains(wa.Id)) + .ToListAsync(); + } + else + { + workAreas = await _context.WorkAreas .Where(wa => floorIds.Contains(wa.FloorId)) - .Select(wa => new { wa.Id, wa.FloorId, wa.AreaName }) .ToListAsync(); - var workAreaIds = workAreas.Select(wa => wa.Id).ToList(); + workAreaIds = workAreas.Select(wa => wa.Id).ToList(); + } - var workItems = await _context.WorkItems - .Include(wi => wi.ActivityMaster) - .Include(wi => wi.WorkCategoryMaster) - .Where(wi => workAreaIds.Contains(wi.WorkAreaId)) - .Select(wi => new { wi.Id, wi.WorkAreaId, wi.ActivityMaster, wi.WorkCategoryMaster }) - .ToListAsync(); + var workItemsQuery = _context.WorkItems.Include(w => w.ActivityMaster).Include(w => w.WorkCategoryMaster) + .Where(wi => workAreaIds.Contains(wi.WorkAreaId)); + if (activityIds?.Any() == true) workItemsQuery = workItemsQuery.Where(wi => activityIds.Contains(wi.ActivityId)); + if (workCategoryIds?.Any() == true) + { + workItemsQuery = workItemsQuery.Where(wi => wi.WorkCategoryMaster != null && workCategoryIds.Contains(wi.WorkCategoryMaster.Id)); + } + var workItems = await workItemsQuery.ToListAsync(); var workItemIds = workItems.Select(wi => wi.Id).ToList(); - // Step 4: Fetch task and comment data - var tasks = await _context.TaskAllocations - .Include(t => t.ReportedBy) - .Where(t => workItemIds.Contains(t.WorkItemId)) - .ToListAsync(); - + // Step 6: Fetch task allocations and comments + var tasks = await _context.TaskAllocations.Include(t => t.ReportedBy) + .Where(t => workItemIds.Contains(t.WorkItemId)).ToListAsync(); var taskIds = tasks.Select(t => t.Id).ToList(); - var comments = await _context.TaskComments - .Include(c => c.Employee) - .Where(c => taskIds.Contains(c.TaskAllocationId)) - .ToListAsync(); - + var comments = await _context.TaskComments.Include(c => c.Employee) + .Where(c => taskIds.Contains(c.TaskAllocationId)).ToListAsync(); var commentIds = comments.Select(c => c.Id).ToList(); - // Step 5: Fetch attachments and related documents var attachments = await _context.TaskAttachments - .Where(ta => taskIds.Contains(ta.ReferenceId) || commentIds.Contains(ta.ReferenceId)) - .ToListAsync(); + .Where(ta => taskIds.Contains(ta.ReferenceId) || commentIds.Contains(ta.ReferenceId)).ToListAsync(); var documentIds = attachments.Select(ta => ta.DocumentId).ToList(); - var documents = await _context.Documents - .Include(d => d.UploadedBy) - .Where(d => documentIds.Contains(d.Id)) - .ToListAsync(); + // Step 7: Fetch and filter documents + var docQuery = _context.Documents.Include(d => d.UploadedBy) + .Where(d => documentIds.Contains(d.Id) && d.TenantId == tenantId); + if (startDate != null && endDate != null) + { + docQuery = docQuery.Where(d => d.UploadedAt.Date >= startDate.Value.Date && d.UploadedAt.Date <= endDate.Value.Date); + } + var documents = await docQuery.ToListAsync(); - // Step 6: Prepare view models - var documentVM = documents - .Select(d => + // Step 8: Build response + var documentVM = documents.Select(d => + { + var refId = attachments.FirstOrDefault(ta => ta.DocumentId == d.Id)?.ReferenceId; + var task = tasks.FirstOrDefault(t => t.Id == refId); + var comment = comments.FirstOrDefault(c => c.Id == refId); + + var source = task != null ? "Report" : comment != null ? "Comment" : ""; + var uploadedBy = task?.ReportedBy ?? comment?.Employee; + + var workItem = workItems.FirstOrDefault(w => w.Id == task?.WorkItemId); + var workArea = workAreas.FirstOrDefault(wa => wa.Id == workItem?.WorkAreaId); + var floor = floors.FirstOrDefault(f => f.Id == workArea?.FloorId); + var building = buildings.FirstOrDefault(b => b.Id == floor?.BuildingId); + + return new { - var referenceId = attachments - .Where(ta => ta.DocumentId == d.Id) - .Select(ta => ta.ReferenceId) - .FirstOrDefault(); + Id = d.Id, + BatchId = d.BatchId, + thumbnailUrl = d.ThumbS3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.ThumbS3Key) : (d.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.S3Key) : null), + ImageUrl = d.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.S3Key) : null, + UploadedBy = d.UploadedBy?.ToBasicEmployeeVMFromEmployee() ?? uploadedBy?.ToBasicEmployeeVMFromEmployee(), + UploadedAt = d.UploadedAt, + Source = source, + ProjectId = projectId, + BuildingId = building?.Id, + BuildingName = building?.Name, + FloorIds = floor?.Id, + FloorName = floor?.FloorName, + WorkAreaId = workArea?.Id, + WorkAreaName = workArea?.AreaName, + TaskId = task?.Id, + ActivityId = workItem?.ActivityMaster?.Id, + ActivityName = workItem?.ActivityMaster?.ActivityName, + WorkCategoryId = workItem?.WorkCategoryMaster?.Id, + WorkCategoryName = workItem?.WorkCategoryMaster?.Name, + CommentId = comment?.Id, + Comment = comment?.Comment + }; + }).ToList(); - var task = tasks.FirstOrDefault(t => t.Id == referenceId); - var comment = comments.FirstOrDefault(c => c.Id == referenceId); + if (uploadedByIds?.Any() == true) + { + documentVM = documentVM.Where(d => uploadedByIds.Contains(d.UploadedBy?.Id ?? Guid.Empty)).ToList(); + } - string source = ""; - Employee? uploadedBy = null; - if (task != null) - { - uploadedBy = task.ReportedBy; - source = "Report"; - } - else if (comment != null) - { - task = tasks.FirstOrDefault(t => t.Id == comment.TaskAllocationId); - uploadedBy = comment.Employee; - source = "Comment"; - } - - var workItem = workItems.FirstOrDefault(wi => wi.Id == task?.WorkItemId); - var workArea = workAreas.FirstOrDefault(wa => wa.Id == workItem?.WorkAreaId); - var floor = floors.FirstOrDefault(f => f.Id == workArea?.FloorId); - var building = buildings.FirstOrDefault(b => b.Id == floor?.BuildingId); - - return new - { - Id = d.Id, - BatchId = d.BatchId, - thumbnailUrl = d.ThumbS3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.ThumbS3Key) : (d.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.S3Key) : null), - ImageUrl = d.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.S3Key) : null, - UploadedBy = d.UploadedBy?.ToBasicEmployeeVMFromEmployee() ?? uploadedBy?.ToBasicEmployeeVMFromEmployee(), - UploadedAt = d.UploadedAt, - Source = source, - ProjectId = projectId, - BuildingId = building?.Id, - BuildingName = building?.Name, - FloorIds = floor?.Id, - FloorName = floor?.FloorName, - WorkAreaId = workArea?.Id, - WorkAreaName = workArea?.AreaName, - TaskId = task?.Id, - ActivityName = workItem?.ActivityMaster?.ActivityName, - WorkCategoryId = workItem?.WorkCategoryMaster?.Id, - WorkCategoryName = workItem?.WorkCategoryMaster?.Name, - CommentId = comment?.Id, - Comment = comment?.Comment - }; - }).ToList(); - - _logger.LogInfo("Image list fetched for ProjectId: {ProjectId}. Total documents: {Count}", projectId, documentVM.Count); + _logger.LogInfo("[GetImageList] Fetched {Count} documents for ProjectId: {ProjectId}", documentVM.Count, projectId); return Ok(ApiResponse.SuccessResponse(documentVM, $"{documentVM.Count} image records fetched successfully", 200)); } @@ -269,6 +316,7 @@ namespace Marco.Pms.Services.Controllers WorkAreaId = workArea?.Id, WorkAreaName = workArea?.AreaName, TaskId = task?.Id, + ActivityId = workItem?.ActivityMaster?.Id, ActivityName = workItem?.ActivityMaster?.ActivityName, WorkCategoryId = workItem?.WorkCategoryMaster?.Id, WorkCategoryName = workItem?.WorkCategoryMaster?.Name, From a303625d593b4e3ff3def4a7066972ac0210f781 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Thu, 3 Jul 2025 11:32:06 +0530 Subject: [PATCH 09/17] Added a line which is missed while optimizing --- Marco.Pms.Services/Controllers/ImageController.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Marco.Pms.Services/Controllers/ImageController.cs b/Marco.Pms.Services/Controllers/ImageController.cs index eaab3c6..efbd134 100644 --- a/Marco.Pms.Services/Controllers/ImageController.cs +++ b/Marco.Pms.Services/Controllers/ImageController.cs @@ -182,6 +182,11 @@ namespace Marco.Pms.Services.Controllers var source = task != null ? "Report" : comment != null ? "Comment" : ""; var uploadedBy = task?.ReportedBy ?? comment?.Employee; + if (comment != null) + { + task = tasks.FirstOrDefault(t => t.Id == comment.TaskAllocationId); + } + var workItem = workItems.FirstOrDefault(w => w.Id == task?.WorkItemId); var workArea = workAreas.FirstOrDefault(wa => wa.Id == workItem?.WorkAreaId); var floor = floors.FirstOrDefault(f => f.Id == workArea?.FloorId); From c9ff53a7acdf7d16ef0512a29099cacdc56d43cd Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Thu, 3 Jul 2025 12:46:49 +0530 Subject: [PATCH 10/17] Removed double Deserialize --- Marco.Pms.Services/Controllers/ImageController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marco.Pms.Services/Controllers/ImageController.cs b/Marco.Pms.Services/Controllers/ImageController.cs index efbd134..44952c6 100644 --- a/Marco.Pms.Services/Controllers/ImageController.cs +++ b/Marco.Pms.Services/Controllers/ImageController.cs @@ -66,8 +66,8 @@ namespace Marco.Pms.Services.Controllers try { var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; - string unescapedJsonString = JsonSerializer.Deserialize(filter, options) ?? ""; - imageFilter = JsonSerializer.Deserialize(unescapedJsonString, options); + //string unescapedJsonString = JsonSerializer.Deserialize(filter, options) ?? ""; + imageFilter = JsonSerializer.Deserialize(filter, options); } catch (Exception ex) { From 6d8939d942e28b98df084a767ef5b7e58a2b8dcf Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 5 Jul 2025 12:23:28 +0530 Subject: [PATCH 11/17] Added Pagenation to Image List API --- .../Dtos/DocumentManager/DocumentBatchDto.cs | 10 +++ .../Controllers/ImageController.cs | 73 ++++++++++++------- 2 files changed, 58 insertions(+), 25 deletions(-) create mode 100644 Marco.Pms.Model/Dtos/DocumentManager/DocumentBatchDto.cs diff --git a/Marco.Pms.Model/Dtos/DocumentManager/DocumentBatchDto.cs b/Marco.Pms.Model/Dtos/DocumentManager/DocumentBatchDto.cs new file mode 100644 index 0000000..a3befae --- /dev/null +++ b/Marco.Pms.Model/Dtos/DocumentManager/DocumentBatchDto.cs @@ -0,0 +1,10 @@ +using Marco.Pms.Model.DocumentManager; + +namespace Marco.Pms.Model.Dtos.DocumentManager +{ + public class DocumentBatchDto + { + public Guid? BatchId { get; set; } + public List? Documents { get; set; } + } +} diff --git a/Marco.Pms.Services/Controllers/ImageController.cs b/Marco.Pms.Services/Controllers/ImageController.cs index 44952c6..5c3cdc5 100644 --- a/Marco.Pms.Services/Controllers/ImageController.cs +++ b/Marco.Pms.Services/Controllers/ImageController.cs @@ -1,6 +1,7 @@ using System.Text.Json; using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Activities; +using Marco.Pms.Model.Dtos.DocumentManager; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Mapper; using Marco.Pms.Model.Projects; @@ -10,6 +11,7 @@ using MarcoBMS.Services.Helpers; using MarcoBMS.Services.Service; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.CodeAnalysis; using Microsoft.EntityFrameworkCore; namespace Marco.Pms.Services.Controllers @@ -37,7 +39,7 @@ namespace Marco.Pms.Services.Controllers [HttpGet("images/{projectId}")] - public async Task GetImageList(Guid projectId, [FromQuery] string? filter) + public async Task GetImageList(Guid projectId, [FromQuery] string? filter, [FromQuery] int? pageNumber = 1, [FromQuery] int? pageSize = 10) { _logger.LogInfo("[GetImageList] Called by Employee for ProjectId: {ProjectId}", projectId); @@ -66,8 +68,9 @@ namespace Marco.Pms.Services.Controllers try { var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; - //string unescapedJsonString = JsonSerializer.Deserialize(filter, options) ?? ""; - imageFilter = JsonSerializer.Deserialize(filter, options); + string unescapedJsonString = JsonSerializer.Deserialize(filter, options) ?? ""; + imageFilter = JsonSerializer.Deserialize(unescapedJsonString, options); + //imageFilter = JsonSerializer.Deserialize(filter, options); } catch (Exception ex) { @@ -86,12 +89,9 @@ namespace Marco.Pms.Services.Controllers var uploadedByIds = imageFilter?.UploadedByIds; // Step 5: Fetch building > floor > area > work item hierarchy - // Step 3: Fetch building > floor > work area > work item hierarchy List? buildings = null; List? floors = null; List? workAreas = null; - //List? workItems = null; - //List? documents = null; if (buildingIds != null && buildingIds.Count > 0) { @@ -164,18 +164,35 @@ namespace Marco.Pms.Services.Controllers var documentIds = attachments.Select(ta => ta.DocumentId).ToList(); // Step 7: Fetch and filter documents + List documents = new List(); var docQuery = _context.Documents.Include(d => d.UploadedBy) .Where(d => documentIds.Contains(d.Id) && d.TenantId == tenantId); if (startDate != null && endDate != null) { docQuery = docQuery.Where(d => d.UploadedAt.Date >= startDate.Value.Date && d.UploadedAt.Date <= endDate.Value.Date); } - var documents = await docQuery.ToListAsync(); + if (pageNumber != null && pageSize != null) + { + documents = await docQuery + .GroupBy(d => d.BatchId) + .OrderBy(g => g.Key) + .Skip((pageNumber.Value - 1) * pageSize.Value) + .Take(pageSize.Value) + .Select(g => new DocumentBatchDto + { + BatchId = g.Key, + Documents = g.ToList() + }) + .ToListAsync(); + Console.Write("Pagenation Success"); + } + // Step 8: Build response var documentVM = documents.Select(d => { - var refId = attachments.FirstOrDefault(ta => ta.DocumentId == d.Id)?.ReferenceId; + var docIds = d.Documents?.Select(x => x.Id).ToList() ?? new List(); + var refId = attachments.FirstOrDefault(ta => docIds.Contains(ta.DocumentId))?.ReferenceId; var task = tasks.FirstOrDefault(t => t.Id == refId); var comment = comments.FirstOrDefault(c => c.Id == refId); @@ -194,12 +211,16 @@ namespace Marco.Pms.Services.Controllers return new { - Id = d.Id, + BatchId = d.BatchId, - thumbnailUrl = d.ThumbS3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.ThumbS3Key) : (d.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.S3Key) : null), - ImageUrl = d.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.S3Key) : null, - UploadedBy = d.UploadedBy?.ToBasicEmployeeVMFromEmployee() ?? uploadedBy?.ToBasicEmployeeVMFromEmployee(), - UploadedAt = d.UploadedAt, + Documents = d.Documents?.Select(x => new + { + Id = x.Id, + thumbnailUrl = x.ThumbS3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.ThumbS3Key) : (x.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.S3Key) : null), + Url = x.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.S3Key) : null, + UploadedBy = x.UploadedBy?.ToBasicEmployeeVMFromEmployee() ?? uploadedBy?.ToBasicEmployeeVMFromEmployee(), + UploadedAt = x.UploadedAt, + }).ToList(), Source = source, ProjectId = projectId, BuildingId = building?.Id, @@ -220,7 +241,7 @@ namespace Marco.Pms.Services.Controllers if (uploadedByIds?.Any() == true) { - documentVM = documentVM.Where(d => uploadedByIds.Contains(d.UploadedBy?.Id ?? Guid.Empty)).ToList(); + documentVM = documentVM.Where(d => d.Documents != null && d.Documents.Any(x => uploadedByIds.Contains(x.UploadedBy?.Id ?? Guid.Empty))).ToList(); } _logger.LogInfo("[GetImageList] Fetched {Count} documents for ProjectId: {ProjectId}", documentVM.Count, projectId); @@ -302,16 +323,18 @@ namespace Marco.Pms.Services.Controllers .FirstOrDefaultAsync(b => b.Id == buildingId); // Step 6: Construct the response - var response = documents.Select(d => new + var response = new { - Id = d.Id, - BatchId = d.BatchId, - thumbnailUrl = d.ThumbS3Key != null - ? _s3Service.GeneratePreSignedUrlAsync(d.ThumbS3Key) - : (d.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.S3Key) : null), - ImageUrl = d.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(d.S3Key) : null, - UploadedBy = d.UploadedBy?.ToBasicEmployeeVMFromEmployee() ?? uploadedBy?.ToBasicEmployeeVMFromEmployee(), - UploadedAt = d.UploadedAt, + + BatchId = batchId, + Documents = documents?.Select(x => new + { + Id = x.Id, + thumbnailUrl = x.ThumbS3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.ThumbS3Key) : (x.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.S3Key) : null), + Url = x.S3Key != null ? _s3Service.GeneratePreSignedUrlAsync(x.S3Key) : null, + UploadedBy = x.UploadedBy?.ToBasicEmployeeVMFromEmployee() ?? uploadedBy?.ToBasicEmployeeVMFromEmployee(), + UploadedAt = x.UploadedAt, + }).ToList(), Source = source, ProjectId = building?.ProjectId, BuildingId = building?.Id, @@ -327,9 +350,9 @@ namespace Marco.Pms.Services.Controllers WorkCategoryName = workItem?.WorkCategoryMaster?.Name, CommentId = comment?.Id, Comment = comment?.Comment - }).ToList(); + }; - _logger.LogInfo("Fetched {Count} image(s) for BatchId: {BatchId}", response.Count, batchId); + _logger.LogInfo("Fetched {Count} image(s) for BatchId: {BatchId}", response.Documents?.Count ?? 0, batchId); return Ok(ApiResponse.SuccessResponse(response, "Images for provided batchId fetched successfully", 200)); } From 800db99fd9928941ffe521354c02d4b7b3743ca1 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 5 Jul 2025 12:33:10 +0530 Subject: [PATCH 12/17] Removed double Deserialization --- Marco.Pms.Services/Controllers/ImageController.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marco.Pms.Services/Controllers/ImageController.cs b/Marco.Pms.Services/Controllers/ImageController.cs index 5c3cdc5..6c8698a 100644 --- a/Marco.Pms.Services/Controllers/ImageController.cs +++ b/Marco.Pms.Services/Controllers/ImageController.cs @@ -68,9 +68,9 @@ namespace Marco.Pms.Services.Controllers try { var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; - string unescapedJsonString = JsonSerializer.Deserialize(filter, options) ?? ""; - imageFilter = JsonSerializer.Deserialize(unescapedJsonString, options); - //imageFilter = JsonSerializer.Deserialize(filter, options); + //string unescapedJsonString = JsonSerializer.Deserialize(filter, options) ?? ""; + //imageFilter = JsonSerializer.Deserialize(unescapedJsonString, options); + imageFilter = JsonSerializer.Deserialize(filter, options); } catch (Exception ex) { From f9ab7bb3c87131c3516262c09ab4419bcd9218f3 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 5 Jul 2025 13:19:06 +0530 Subject: [PATCH 13/17] Ordered by Uploaded at --- Marco.Pms.Services/Controllers/ImageController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marco.Pms.Services/Controllers/ImageController.cs b/Marco.Pms.Services/Controllers/ImageController.cs index 6c8698a..7c54e9c 100644 --- a/Marco.Pms.Services/Controllers/ImageController.cs +++ b/Marco.Pms.Services/Controllers/ImageController.cs @@ -175,7 +175,7 @@ namespace Marco.Pms.Services.Controllers { documents = await docQuery .GroupBy(d => d.BatchId) - .OrderBy(g => g.Key) + .OrderByDescending(g => g.Max(d => d.UploadedAt)) .Skip((pageNumber.Value - 1) * pageSize.Value) .Take(pageSize.Value) .Select(g => new DocumentBatchDto From 6373da3144b78b9472971d8235509b3c92fb1c8e Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 5 Jul 2025 17:11:59 +0530 Subject: [PATCH 14/17] Added SignalR Integration for Reporting, Commenting, and Approving Tasks --- .../Controllers/TaskController.cs | 61 ++++++++++++------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/Marco.Pms.Services/Controllers/TaskController.cs b/Marco.Pms.Services/Controllers/TaskController.cs index 5a35baf..c0ec5ff 100644 --- a/Marco.Pms.Services/Controllers/TaskController.cs +++ b/Marco.Pms.Services/Controllers/TaskController.cs @@ -6,11 +6,13 @@ using Marco.Pms.Model.Mapper; using Marco.Pms.Model.Projects; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Activities; +using Marco.Pms.Services.Hubs; using Marco.Pms.Services.Service; using MarcoBMS.Services.Helpers; using MarcoBMS.Services.Service; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; using Microsoft.CodeAnalysis; using Microsoft.EntityFrameworkCore; using Document = Marco.Pms.Model.DocumentManager.Document; @@ -27,16 +29,19 @@ namespace MarcoBMS.Services.Controllers private readonly UserHelper _userHelper; private readonly S3UploadService _s3Service; private readonly ILoggingService _logger; + private readonly IHubContext _signalR; private readonly PermissionServices _permissionServices; private readonly Guid Approve_Task; private readonly Guid Assign_Report_Task; - public TaskController(ApplicationDbContext context, UserHelper userHelper, S3UploadService s3Service, ILoggingService logger, PermissionServices permissionServices) + public TaskController(ApplicationDbContext context, UserHelper userHelper, S3UploadService s3Service, ILoggingService logger, PermissionServices permissionServices, + IHubContext signalR) { _context = context; _userHelper = userHelper; _s3Service = s3Service; _logger = logger; + _signalR = signalR; _permissionServices = permissionServices; Approve_Task = Guid.Parse("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c"); Assign_Report_Task = Guid.Parse("6a32379b-8b3f-49a6-8c48-4b7ac1b55dc2"); @@ -194,17 +199,20 @@ namespace MarcoBMS.Services.Controllers var comment = reportTask.ToCommentFromReportTaskDto(tenantId, loggedInEmployee.Id); _context.TaskComments.Add(comment); + var workAreaId = taskAllocation.WorkItem?.WorkAreaId; + var workArea = await _context.WorkAreas.Include(a => a.Floor) + .FirstOrDefaultAsync(a => a.Id == workAreaId) ?? new WorkArea(); + + var buildingId = workArea.Floor?.BuildingId; + + var building = await _context.Buildings + .FirstOrDefaultAsync(b => b.Id == buildingId); + var batchId = Guid.NewGuid(); + var projectId = building?.ProjectId; + if (reportTask.Images?.Any() == true) { - var workAreaId = taskAllocation.WorkItem?.WorkAreaId; - var workArea = await _context.WorkAreas.Include(a => a.Floor) - .FirstOrDefaultAsync(a => a.Id == workAreaId) ?? new WorkArea(); - var buildingId = workArea.Floor?.BuildingId; - - var building = await _context.Buildings - .FirstOrDefaultAsync(b => b.Id == buildingId); - var batchId = Guid.NewGuid(); foreach (var image in reportTask.Images) { @@ -220,7 +228,7 @@ namespace MarcoBMS.Services.Controllers var fileType = _s3Service.GetContentTypeFromBase64(base64); var fileName = _s3Service.GenerateFileName(fileType, tenantId, "task_report"); - var objectKey = $"tenant-{tenantId}/project-{building?.ProjectId}/Actitvity/{fileName}"; + var objectKey = $"tenant-{tenantId}/project-{projectId}/Actitvity/{fileName}"; await _s3Service.UploadFileAsync(base64, fileType, objectKey); @@ -257,6 +265,9 @@ namespace MarcoBMS.Services.Controllers response.Comments = comments.Select(c => c.ToCommentVMFromTaskComment()).ToList(); response.checkList = checkListVMs; + var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Report", ProjectId = projectId }; + await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification); + _logger.LogInfo("Task {TaskId} reported successfully by Employee {EmployeeId}", taskAllocation.Id, loggedInEmployee.Id); return Ok(ApiResponse.SuccessResponse(response, "Task reported successfully", 200)); @@ -288,6 +299,7 @@ namespace MarcoBMS.Services.Controllers var buildingId = workArea.Floor?.BuildingId ?? Guid.Empty; var building = await _context.Buildings.FirstOrDefaultAsync(b => b.Id == buildingId); + var projectId = building?.ProjectId; // Save comment var comment = createComment.ToCommentFromCommentDto(tenantId, loggedInEmployee.Id); @@ -316,7 +328,7 @@ namespace MarcoBMS.Services.Controllers var fileType = _s3Service.GetContentTypeFromBase64(base64); var fileName = _s3Service.GenerateFileName(fileType, tenantId, "task_comment"); - var objectKey = $"tenant-{tenantId}/project-{building?.ProjectId}/Activity/{fileName}"; + var objectKey = $"tenant-{tenantId}/project-{projectId}/Activity/{fileName}"; await _s3Service.UploadFileAsync(base64, fileType, objectKey); _logger.LogInfo("Image uploaded to S3 with key: {ObjectKey}", objectKey); @@ -353,6 +365,9 @@ namespace MarcoBMS.Services.Controllers var response = comment.ToCommentVMFromTaskComment(); _logger.LogInfo("Returning response for commentId: {CommentId}", comment.Id); + var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Report", ProjectId = projectId }; + await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification); + return Ok(ApiResponse.SuccessResponse(response, "Comment saved successfully", 200)); } @@ -725,18 +740,19 @@ namespace MarcoBMS.Services.Controllers }; _context.TaskComments.Add(comment); + var workAreaId = taskAllocation.WorkItem?.WorkAreaId; + var workArea = await _context.WorkAreas.Include(a => a.Floor) + .FirstOrDefaultAsync(a => a.Id == workAreaId) ?? new WorkArea(); + + var buildingId = workArea.Floor?.BuildingId; + + var building = await _context.Buildings + .FirstOrDefaultAsync(b => b.Id == buildingId); + var projectId = building?.ProjectId; + // Handle image attachments, if any if (approveTask.Images?.Count > 0) { - var workAreaId = taskAllocation.WorkItem?.WorkAreaId; - var workArea = await _context.WorkAreas.Include(a => a.Floor) - .FirstOrDefaultAsync(a => a.Id == workAreaId) ?? new WorkArea(); - - var buildingId = workArea.Floor?.BuildingId; - - var building = await _context.Buildings - .FirstOrDefaultAsync(b => b.Id == buildingId); - var batchId = Guid.NewGuid(); foreach (var image in approveTask.Images) @@ -751,7 +767,7 @@ namespace MarcoBMS.Services.Controllers var fileType = _s3Service.GetContentTypeFromBase64(base64); var fileName = _s3Service.GenerateFileName(fileType, tenantId, "task_comment"); - var objectKey = $"tenant-{tenantId}/project-{building?.ProjectId}/Activity/{fileName}"; + var objectKey = $"tenant-{tenantId}/project-{projectId}/Activity/{fileName}"; await _s3Service.UploadFileAsync(base64, fileType, objectKey); @@ -785,6 +801,9 @@ namespace MarcoBMS.Services.Controllers // Commit all changes to the database await _context.SaveChangesAsync(); + var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Report", ProjectId = projectId }; + await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification); + _logger.LogInfo("Task {TaskId} successfully approved by Employee {EmployeeId}", approveTask.Id, loggedInEmployee.Id); return Ok(ApiResponse.SuccessResponse("Task has been approved", "Task has been approved", 200)); From 558fd6bd5b0d4e1cb83ba8d598bdcda11090626d Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Sat, 5 Jul 2025 17:24:57 +0530 Subject: [PATCH 15/17] Corrected Key for signalR --- Marco.Pms.Services/Controllers/TaskController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marco.Pms.Services/Controllers/TaskController.cs b/Marco.Pms.Services/Controllers/TaskController.cs index c0ec5ff..f4f2dfa 100644 --- a/Marco.Pms.Services/Controllers/TaskController.cs +++ b/Marco.Pms.Services/Controllers/TaskController.cs @@ -365,7 +365,7 @@ namespace MarcoBMS.Services.Controllers var response = comment.ToCommentVMFromTaskComment(); _logger.LogInfo("Returning response for commentId: {CommentId}", comment.Id); - var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Report", ProjectId = projectId }; + var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Comment", ProjectId = projectId }; await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification); return Ok(ApiResponse.SuccessResponse(response, "Comment saved successfully", 200)); @@ -801,7 +801,7 @@ namespace MarcoBMS.Services.Controllers // Commit all changes to the database await _context.SaveChangesAsync(); - var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Report", ProjectId = projectId }; + var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Comment", ProjectId = projectId }; await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification); _logger.LogInfo("Task {TaskId} successfully approved by Employee {EmployeeId}", approveTask.Id, loggedInEmployee.Id); From 65f337652323421bcd06742e311b0f33c74beeb6 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 7 Jul 2025 11:21:31 +0530 Subject: [PATCH 16/17] Added new paremeter of NumberOfImages in signalR message object --- Marco.Pms.Services/Controllers/TaskController.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Marco.Pms.Services/Controllers/TaskController.cs b/Marco.Pms.Services/Controllers/TaskController.cs index f4f2dfa..4ad1f85 100644 --- a/Marco.Pms.Services/Controllers/TaskController.cs +++ b/Marco.Pms.Services/Controllers/TaskController.cs @@ -199,6 +199,8 @@ namespace MarcoBMS.Services.Controllers var comment = reportTask.ToCommentFromReportTaskDto(tenantId, loggedInEmployee.Id); _context.TaskComments.Add(comment); + int numberofImages = 0; + var workAreaId = taskAllocation.WorkItem?.WorkAreaId; var workArea = await _context.WorkAreas.Include(a => a.Floor) .FirstOrDefaultAsync(a => a.Id == workAreaId) ?? new WorkArea(); @@ -252,6 +254,7 @@ namespace MarcoBMS.Services.Controllers ReferenceId = reportTask.Id }; _context.TaskAttachments.Add(attachment); + numberofImages += 1; } } @@ -265,7 +268,7 @@ namespace MarcoBMS.Services.Controllers response.Comments = comments.Select(c => c.ToCommentVMFromTaskComment()).ToList(); response.checkList = checkListVMs; - var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Report", ProjectId = projectId }; + var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Report", NumberOfImages = numberofImages, ProjectId = projectId }; await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification); _logger.LogInfo("Task {TaskId} reported successfully by Employee {EmployeeId}", taskAllocation.Id, loggedInEmployee.Id); @@ -310,6 +313,7 @@ namespace MarcoBMS.Services.Controllers // Process image uploads var images = createComment.Images; var batchId = Guid.NewGuid(); + int numberofImages = 0; if (images != null && images.Any()) { @@ -355,6 +359,7 @@ namespace MarcoBMS.Services.Controllers }; _context.TaskAttachments.Add(attachment); + numberofImages += 1; } await _context.SaveChangesAsync(); @@ -365,7 +370,7 @@ namespace MarcoBMS.Services.Controllers var response = comment.ToCommentVMFromTaskComment(); _logger.LogInfo("Returning response for commentId: {CommentId}", comment.Id); - var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Comment", ProjectId = projectId }; + var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Comment", NumberOfImages = numberofImages, ProjectId = projectId }; await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification); return Ok(ApiResponse.SuccessResponse(response, "Comment saved successfully", 200)); @@ -749,6 +754,7 @@ namespace MarcoBMS.Services.Controllers var building = await _context.Buildings .FirstOrDefaultAsync(b => b.Id == buildingId); var projectId = building?.ProjectId; + int numberofImages = 0; // Handle image attachments, if any if (approveTask.Images?.Count > 0) @@ -795,13 +801,14 @@ namespace MarcoBMS.Services.Controllers _context.TaskAttachments.Add(attachment); _logger.LogInfo("Attachment uploaded for Task {TaskId}: {FileName}", approveTask.Id, fileName); + numberofImages += 1; } } // Commit all changes to the database await _context.SaveChangesAsync(); - var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Comment", ProjectId = projectId }; + var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Task_Report", NumberOfImages = numberofImages, ProjectId = projectId }; await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification); _logger.LogInfo("Task {TaskId} successfully approved by Employee {EmployeeId}", approveTask.Id, loggedInEmployee.Id); From 43e2aeb097a55f9123831169edff5d455de9876c Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 7 Jul 2025 13:15:27 +0530 Subject: [PATCH 17/17] Showing the comment added when task is reported --- Marco.Pms.Services/Controllers/ImageController.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Marco.Pms.Services/Controllers/ImageController.cs b/Marco.Pms.Services/Controllers/ImageController.cs index 7c54e9c..48fbc3b 100644 --- a/Marco.Pms.Services/Controllers/ImageController.cs +++ b/Marco.Pms.Services/Controllers/ImageController.cs @@ -203,6 +203,10 @@ namespace Marco.Pms.Services.Controllers { task = tasks.FirstOrDefault(t => t.Id == comment.TaskAllocationId); } + if (task != null) + { + comment = comments.OrderBy(c => c.CommentDate).FirstOrDefault(c => c.TaskAllocationId == task.Id); + } var workItem = workItems.FirstOrDefault(w => w.Id == task?.WorkItemId); var workArea = workAreas.FirstOrDefault(wa => wa.Id == workItem?.WorkAreaId);