### IStoryBaseModel Interface and Mocking Example Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Defines the IStoryBaseModel interface for decoupling the data layer and demonstrates its use in unit tests with a mock object. Registration in Startup.cs shows how to register the service for dependency injection. ```csharp // Interface (Base/Stories/StoryBaseModel.cs): public interface IStoryBaseModel { List GetStoriesList(int projectId); TransactionResult UpdateStoryDetails(StoryObjects newStoryDetails); TransactionResult DeleteStory(int storyId); } ``` ```csharp // Registration in Startup.cs (scoped per HTTP request): services.AddScoped(); ``` ```csharp // Unit test with a mock (using any mocking framework, e.g. Moq): var mockStory = new Mock(); mockStory.Setup(m => m.GetStoriesList(7)).Returns(new List { new StoryObjects { StoryId = 1, Title = "Login story", Priority = "High" } }); mockStory.Setup(m => m.UpdateStoryDetails(It.IsAny())) .Returns(new TransactionResult { IsSuccess = true, IsNewRecord = true }); var controller = new StoriesController(mockStory.Object); var result = controller.AddUpdate( data: JsonConvert.SerializeObject(new StoryObjects { Title = "New story" }), projectId: 7 ) as JsonResult; // result.Value → { status = true, message = "New story added successfully." } ``` -------------------------------- ### Get Project Stories View Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Validates access, fetches project metadata, and renders the Stories grid view for a given project. ```APIDOC ## GET /projects/{projectId} — Stories View ### Description Fetches project metadata and renders the Stories grid view for a given project after validating user access. ### Method GET ### Endpoint /projects/{projectId} ### Parameters #### Path Parameters - **projectId** (int) - Required - The ID of the project to retrieve. ### Response #### Success Response (200) - **ProjectName** (string) - The name of the project. - **Description** (string) - The description of the project. ### Response Example (ViewBag properties) ```json { "ProjectName": "Example Project", "Description": "This is an example project." } ``` ### Error Response #### Access Denied (403 Forbidden or similar) - **Content** (string) - "You dont have permission to access this project." ``` -------------------------------- ### Add or Update Story - JavaScript Client Example Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Demonstrates how to add or update a story using a JavaScript client, sending a JSON-serialized 'StoryObjects' via a POST request. Handles new records (StoryId: 0) and updates. ```javascript // Route: POST /story/addupdate?projectId=7 // Query param: data = JSON-serialized StoryObjects // JavaScript client example (Syncfusion Grid CRUD adapter): fetch('/story/addupdate?projectId=7', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ data: JSON.stringify({ StoryId: 0, // 0 = new record; >0 = update Title: "As a user, I can reset my password", ThemeName: "Security", EpicName: "Authentication", Priority: "High", StoryPoints: 3, Benifit: 8, Penalty: 5, SprintName: "Sprint 1", Release: "v1.0", AssigneeName:"alice" }) }) }); // New: { "status": true, "message": "New story added successfully." } // Update: { "status": true, "message": "Story details updated successfully." } // Error: { "status": false, "message": "Unexpected error occurred." } ``` -------------------------------- ### Get Paginated Story List - C# Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Handles POST requests to retrieve a paginated list of stories for a given project, supporting server-side operations like sorting, filtering, and searching. ```csharp // Route: POST /storieslist/7 // Body (JSON): DataManager object // Response: { result: StoryObjects[], count: int } public JsonResult StoriesList([FromBody] DataManager dataManager, int projectId) { StoryModel story = new StoryModel(this.iStoryBaseModel); var list = story.GetStoriesList(dataManager, projectId); return this.Json(new { result = list, count = story.TotalListCount }); } ``` ```json // Example DataManager request body: { "Skip": 0, "Take": 20, "RequiresCounts": true, "Sorted": [{ "name": "Title", "direction": "ascending" }], "Where": [{ "field": "Priority", "operator": "equal", "value": "High" }], "Search": [{ "fields": ["Title","ThemeName"], "key": "auth", "operator": "contains" }] } ``` ```plaintext // Each StoryObjects item in the response: // { StoryId, TaskId, Title, ThemeName, EpicName, Priority, Milestone, Release, // Status, Benifit, Penalty, StoryPoints, Tag, SortOrder, SprintName, AssigneeName } ``` -------------------------------- ### List Projects Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Retrieves a list of projects owned by the current user or projects the user has access to, based on the provided filter. This endpoint is accessible via a GET request to /project. ```APIDOC ## GET /project — List Projects ### Description Returns the Projects view pre-loaded with the current user's owned projects. Supports an optional `projectId` filter via the `LoadProject` partial-view endpoint. ### Method GET ### Endpoint /project ### Parameters #### Query Parameters - **filter** (string) - Optional - Specifies the type of projects to retrieve. Supported values are "" (owned projects), "all" (all accessible projects), and "favourites" (favourite accessible projects). ### Response #### Success Response (200) - **ProjectListObjects** (array) - A list of project objects, where each object contains: - **ProjectId** (int) - The unique identifier for the project. - **ProjectName** (string) - The name of the project. - **ProjectDescription** (string) - A description of the project. - **CreatedBy** (string) - The email address of the user who created the project. - **CreatedOn** (datetime) - The date and time the project was created. - **IsOwner** (bool) - Indicates if the current user is the owner of the project. - **Email** (string) - The email address associated with the project access. - **IsFavourite** (bool) - Indicates if the project is marked as a favourite by the user. ### Request Example ```csharp // No request body for GET request ``` ### Response Example ```json { "example": "[ { ProjectId: 1, ProjectName: \"Project Alpha\", ProjectDescription: \"First project\", CreatedBy: \"user@example.com\", CreatedOn: \"2023-01-01T10:00:00Z\", IsOwner: true, Email: \"user@example.com\", IsFavourite: false } ]" } ``` ``` -------------------------------- ### Configure Database and Google OAuth Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Configure database connection strings and Google OAuth credentials in appsettings.json. Register services in Startup.ConfigureServices, including EF Core, Identity, story data-access, and Google OAuth. ```json // appsettings.json { "ConnectionStrings": { "DefaultConnection": "user id=myuser;password=mypassword;Server=myserver;Database=TaskPlanner;" }, "Authentication": { "Google": { "ClientId": "YOUR_GOOGLE_CLIENT_ID", "ClientSecret": "YOUR_GOOGLE_CLIENT_SECRET" } } } ``` ```csharp // Startup.cs – relevant ConfigureServices excerpt public void ConfigureServices(IServiceCollection services) { // Wire EF Core connection string into the custom DbContext TaskPlannerEntities.ConnectionString = Configuration.GetConnectionString("DefaultConnection"); services.AddDbContext(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity() .AddEntityFrameworkStores() .AddDefaultTokenProviders(); // Register story data-access service for DI into StoriesController services.AddScoped(); // Google OAuth services.AddAuthentication().AddGoogle(googleOptions => { googleOptions.ClientId = Configuration["Authentication:Google:ClientId"]; googleOptions.ClientSecret = Configuration["Authentication:Google:ClientSecret"]; }); // Global authorization: every route requires an authenticated user services.AddMvc(config => { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); config.Filters.Add(new AuthorizeFilter(policy)); }); } ``` -------------------------------- ### Render Project Stories View Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Validates user access, fetches project metadata, and renders the Stories grid view. Includes an access guard that returns a plain-text error if the user lacks permission. ```csharp // Route: GET /projects/7 → StoriesController.Stories(projectId: 7) public IActionResult Stories(int projectId) { var currentUserEmail = User.Identity.Name; // Access guard — returns plain-text error if user has no permission if (!Permission.IsUserHasAccessToProject(currentUserEmail, projectId)) return Content("You dont have permission to access this project."); StoryModel story = new StoryModel(this.iStoryBaseModel); var details = story.GetProjectDetails(projectId); // details.ProjectName, details.Description available in ViewBag ViewBag.ProjectId = projectId; ViewBag.ProjectName = details.ProjectName; ViewBag.ProjectDescription = details.Description; return View(); } ``` -------------------------------- ### Create or Update a Project Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Creates a new project or updates an existing one. Responds with a JSON status object. ```APIDOC ## POST /project/updateproject — Create or Update a Project Creates a new project (and its initial `ProjectPermission` row for the owner) or updates an existing one. Responds with a JSON status object. ### Method POST ### Endpoint /project/updateproject ### Query Parameters - **projectname** (string) - Required - The name of the project. - **description** (string) - Optional - The description of the project. - **projectId** (integer) - Optional - The ID of the project to update. If not provided or 0, a new project is created. ### Request Example ``` POST /project/updateproject?projectname=Acme+V2&description=Q3+roadmap ``` ### Response Example Success Response (200): ```json { "status": true, "message": "New project created successfully." } ``` ### Request Example (Update) ``` POST /project/updateproject?projectname=Acme+V2+Updated&description=Revised+scope&projectId=7 ``` ### Response Example (Update) Success Response (200): ```json { "status": true, "message": "Project Updated successfully." } ``` ``` -------------------------------- ### Project Permission Checks - C# Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Contains static helper methods to check user ownership and general access rights for a given project. Demonstrates typical guard patterns in controller actions. ```csharp // Permission.IsUserOwnerOfProject — joins AspNetUsers → Projects on Owner field bool isOwner = Permission.IsUserOwnerOfProject("alice@gmail.com", projectId: 7); // Returns true only if the Projects.Owner column matches the user's AspNetUsers.Id // Permission.IsUserHasAccessToProject — checks ownership OR active ProjectPermission row bool canView = Permission.IsUserHasAccessToProject("bob@gmail.com", projectId: 7); // Returns true if: // a) user is the project owner, OR // b) an active ProjectPermissions row exists for (projectId, emailId) // Typical guard pattern in controllers: if (!Permission.IsUserOwnerOfProject(User.Identity.Name, projectId)) return this.Json(new { isSuccess = false, message = "Permission Denied" }); if (!Permission.IsUserHasAccessToProject(User.Identity.Name, projectId)) return Content("You dont have permission to access this project."); ``` -------------------------------- ### Create or Update Project Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Use this endpoint to create a new project by omitting projectId or update an existing one by providing a valid projectId. The handler performs database operations within a transaction. ```csharp // Route: POST /project/updateproject // Handler: ProjectController.AddProjectAsync(description, projectname, projectId) // Create a new project (omit projectId or pass ""): // POST /project/updateproject?projectname=Acme+V2&description=Q3+roadmap // → { "status": true, "message": "New project created successfully." } // Update an existing project (pass projectId > 0): // POST /project/updateproject?projectname=Acme+V2+Updated&description=Revised+scope&projectId=7 // → { "status": true, "message": "Project Updated successfully." } // Internal model path (ProjectViewModel.UpdateProjectDetails): public TransactionResult UpdateProjectDetails(ProjectListObjects newProjectDetails, string email) { using (var context = new TaskPlannerEntities()) { if (newProjectDetails.ProjectId > 0) { // Update existing var proj = context.Projects .Where(i => i.ProjectId == newProjectDetails.ProjectId && i.IsActive) .FirstOrDefault(); proj.ProjectName = newProjectDetails.ProjectName; proj.Description = newProjectDetails.ProjectDescription; } else { // Insert new project + owner permission in one transaction var newProject = new Project { ProjectName = newProjectDetails.ProjectName, Description = newProjectDetails.ProjectDescription, CreatedBy = newProjectDetails.CreatedBy, Owner = newProjectDetails.CreatedBy, CreatedOn = DateTime.Now, IsActive = true }; context.Projects.Add(newProject); context.ProjectPermissions.Add(new ProjectPermission { ProjectId = newProject.ProjectId, EmailId = email, UpdatedOn = DateTime.Now, IsActive = true }); } context.SaveChanges(); } // Returns TransactionResult { IsSuccess = true } } ``` -------------------------------- ### List User Projects Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Retrieves the Projects view pre-loaded with the current user's owned projects. Supports optional filtering by project ID via the LoadProject partial-view endpoint. ```csharp // Route registered in Startup: GET /project → ProjectController.Projects() // Returns: View populated with ProjectObjects // ProjectController.cs [HttpGet("/project", Name = "Project_List")] public IActionResult Projects() { var currentUserEmail = User.Identity.Name; // e.g. "alice@gmail.com" var projectList = ProjectModel.GetProjectList("", currentUserEmail); return this.View("~/Views/Project/Projects.cshtml", projectList); } // ProjectModel.GetProjectList — three supported filter values: // "" → only projects owned by currentUserEmail // "all" → all projects where user has ProjectPermission // "favourites"→ favourite projects the user has permission for var owned = ProjectModel.GetProjectList("", "alice@gmail.com"); var allShared = ProjectModel.GetProjectList("all", "alice@gmail.com"); var favourites = ProjectModel.GetProjectList("favourites", "alice@gmail.com"); // Each list entry is a ProjectListObjects: // { ProjectId, ProjectName, ProjectDescription, CreatedBy, CreatedOn, IsOwner, Email, IsFavourite } ``` -------------------------------- ### Permission Model Helpers Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Provides static helper methods to check user permissions for project access and ownership. ```APIDOC ## Permission Model Helpers ### Description Two static helpers guard every sensitive operation — one checks ownership (required for delete), the other checks any access (required for the stories view). ### Methods #### `Permission.IsUserOwnerOfProject(string userEmail, int projectId)` Checks if the specified user is the owner of the project. - **Parameters** - **userEmail** (string) - Required - The email address of the user. - **projectId** (int) - Required - The ID of the project. - **Returns** - (bool) - `true` if the user is the owner, `false` otherwise. #### `Permission.IsUserHasAccessToProject(string userEmail, int projectId)` Checks if the specified user has access to the project (either as owner or via project permissions). - **Parameters** - **userEmail** (string) - Required - The email address of the user. - **projectId** (int) - Required - The ID of the project. - **Returns** - (bool) - `true` if the user has access, `false` otherwise. ### Usage Example (Typical guard pattern in controllers) ```csharp // Check if user is owner before allowing deletion if (!Permission.IsUserOwnerOfProject(User.Identity.Name, projectId)) return this.Json(new { isSuccess = false, message = "Permission Denied" }); // Check if user has access before allowing view if (!Permission.IsUserHasAccessToProject(User.Identity.Name, projectId)) return Content("You dont have permission to access this project."); ``` ``` -------------------------------- ### Internal Auto-Upsert Logic - C# Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Illustrates the internal logic for automatically creating or updating lookup entities like Themes, Epics, and Priorities based on provided names during story operations. ```csharp // Internal auto-upsert for lookup entities (StoryBaseModel): // GetThemeId("Security", projectId, userId) → finds or inserts Theme row, returns ThemeId // GetEpicId("Authentication", projectId, userId) → finds or inserts Epic row, returns EpicId // GetPriorityId("High", userId) → finds or inserts Priority row, returns PriorityId ``` -------------------------------- ### TransactionResult Usage Pattern Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Illustrates the common usage pattern for handling TransactionResult objects returned from model methods. It shows how to check for success and provide appropriate JSON responses. ```csharp // Usage pattern across all model methods: TransactionResult result = someViewModel.SomeOperation(...); if (result.IsSuccess) { string msg = result.IsNewRecord ? "Created." : "Updated."; return this.Json(new { status = true, message = msg }); } else { // result.Exception contains full stack trace for server-side logging return this.Json(new { status = false, message = "Unexpected error occurred." }); } ``` -------------------------------- ### Project Sharing - Grant and Revoke Permissions Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Manages project sharing by granting or revoking user access via email. Revoking permissions also removes the project from the user's favorites. ```APIDOC ## Project Sharing - Grant Access ### Description Grants access to another user by their email address. The owner is prevented from sharing with themselves. ### Method GET/POST ### Endpoint /project/shareemail/{projectId}/{email} ### Parameters #### Path Parameters - **projectId** (int) - Required - The ID of the project to share. - **email** (string) - Required - The email address of the user to grant access to. ### Response #### Success Response (200) - **status** (bool) - Indicates if the operation was successful. - **message** (string) - A message describing the result (e.g., "Permission added successfully."). ### Response Example ```json { "status": true, "message": "Permission added successfully." } ``` ## Project Sharing - Revoke Access ### Description Revokes access for a user by their permission ID. This action also removes the project from that user's favourites. ### Method GET/POST ### Endpoint /project/removepermission/{permissionId} ### Parameters #### Path Parameters - **permissionId** (int) - Required - The ID of the permission to revoke. ### Response #### Success Response (200) - **status** (bool) - Indicates if the operation was successful. - **message** (string) - A message describing the result (e.g., "Project permission is removed."). ### Response Example ```json { "status": true, "message": "Project permission is removed." } ``` ``` -------------------------------- ### Toggle Project Favourite Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Adds or removes a project from the authenticated user's favourites list. It uses the ASP.NET Identity `NameIdentifier` claim as the user ID. ```APIDOC ## POST /project/favourite ### Description Adds or removes a project from the authenticated user's favourites list. ### Method POST ### Endpoint /project/favourite/ ### Query Parameters - **projectId** (int) - Required - The ID of the project to toggle. - **isFavourite** (bool) - Required - True to add to favourites, false to remove. ### Response #### Success Response (200) - **isSuccess** (bool) - Indicates if the operation was successful. - **message** (string) - A message describing the result (e.g., "Added to favourite", "Removed from favourite"). ### Request Example ```json { "projectId": 7, "isFavourite": true } ``` ### Response Example ```json { "isSuccess": true, "message": "Added to favourite" } ``` ``` -------------------------------- ### Delete Project Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt This endpoint performs a soft delete by setting the 'IsActive' flag to false. Only the project owner can initiate this action; others will receive a permission-denied response. The underlying method modifies the database without physically removing records. ```csharp // Route: POST /project/delete/7 // Owner check performed before deletion [HttpPost("/project/delete/{projectId}", Name = "Project_Delete")] public JsonResult DeleteProject(int projectId) { var currentUserEmail = User.Identity.Name; bool isOwner = Permission.IsUserOwnerOfProject(currentUserEmail, projectId); if (!isOwner) return this.Json(new { isSuccess = false, message = "Permission Denied" }); var res = new ProjectViewModel().DeleteProject(projectId); // Success: { "isSuccess": true, "message": "Project deleted successfully" } // Failure: { "isSuccess": false, "message": "Unexpected error occurred" } return res.IsSuccess ? this.Json(new { isSuccess = true, message = "Project deleted successfully" }) : this.Json(new { isSuccess = false, message = "Unexpected error occurred" }); } // Underlying soft-delete (sets IsActive = false — no rows are physically removed): public TransactionResult DeleteProject(int projectId) { using (var context = new TaskPlannerEntities()) { context.Projects .Where(i => i.IsActive && i.ProjectId == projectId) .ToList() .ForEach(i => i.IsActive = false); context.SaveChanges(); } return new TransactionResult { IsSuccess = true }; } ``` -------------------------------- ### Manage Project Sharing Permissions Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Grants or revokes project access for a user via their email. The owner cannot share with themselves. Revoking permission also removes the project from the user's favorites. The `IsUserHasAccessToProject` method checks if a user owns the project or has an active permission row. ```csharp // GRANT — Route: GET/POST /project/shareemail/{projectId}/{email} public JsonResult ShareEmail(int projectId, string email = "") { var currentUserEmail = User.Identity.Name.ToLower().Trim(); email = email.ToLower().Trim(); if (email == currentUserEmail) return this.Json(new { status = true, message = "Owner already has permission for project." }); var res = new ProjectViewModel().UpdateProjectPermissionList(projectId, email, true); // Success: { "status": true, "message": "Permission added successfully." } // Failure: { "status": false, "message": "Unexpected error occurred." } } ``` ```csharp // REVOKE — Route: GET/POST /project/removepermission/{permissionId} public JsonResult RemovePermission(int permissionId) { var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); var res = new ProjectViewModel().RemoveProjectPermission(permissionId, userId); // Also soft-deletes all Favourite rows for that user/project combination // Success: { "status": true, "message": "Project permission is removed." } } ``` ```csharp // Permission.IsUserHasAccessToProject — used before loading the Stories view: bool hasAccess = Permission.IsUserHasAccessToProject("bob@gmail.com", projectId: 7); // Returns true if user owns the project OR has an active ProjectPermission row ``` -------------------------------- ### Add or Update a Story Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Creates a new story or updates an existing one. Themes, Epics, and Priorities are auto-created on first use (upsert by name). ```APIDOC ## POST /story/addupdate ### Description Creates a new story or updates an existing one. Themes, Epics, and Priorities are auto-created on first use (upsert by name). ### Method POST ### Endpoint /story/addupdate ### Parameters #### Query Parameters - **projectId** (int) - Required - The ID of the project to which the story belongs. - **data** (string) - Required - A JSON-serialized string representing the Story Object to add or update. #### Request Body (for `data` query parameter) - **StoryId** (int) - Required - 0 for a new record, or the existing Story ID for an update. - **Title** (string) - Required - The title of the story. - **ThemeName** (string) - Required - The name of the theme. Will be auto-created if it doesn't exist. - **EpicName** (string) - Required - The name of the epic. Will be auto-created if it doesn't exist. - **Priority** (string) - Required - The priority of the story. Will be auto-created if it doesn't exist. - **StoryPoints** (int) - Optional - The story points assigned to the story. - **Benifit** (int) - Optional - The benefit value of the story. - **Penalty** (int) - Optional - The penalty value of the story. - **SprintName** (string) - Optional - The name of the sprint the story is in. - **Release** (string) - Optional - The release version the story is associated with. - **AssigneeName** (string) - Optional - The name of the user assigned to the story. ### Response #### Success Response (200) - **status** (bool) - Indicates if the operation was successful. - **message** (string) - A message describing the outcome of the operation. ### Request Example (JavaScript client) ```javascript fetch('/story/addupdate?projectId=7', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ data: JSON.stringify({ StoryId: 0, // 0 = new record; >0 = update Title: "As a user, I can reset my password", ThemeName: "Security", EpicName: "Authentication", Priority: "High", StoryPoints: 3, Benifit: 8, Penalty: 5, SprintName: "Sprint 1", Release: "v1.0", AssigneeName:"alice" }) }) }); ``` ### Response Example ```json { "status": true, "message": "New story added successfully." } ``` ``` -------------------------------- ### Delete a Project Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Soft-deletes a project by setting its `IsActive` status to false. Only the project owner can perform this action. ```APIDOC ## POST /project/delete/{projectId} — Delete a Project Soft-deletes a project (sets `IsActive = false`). Only the project owner can invoke this endpoint; non-owners receive a permission-denied response. ### Method POST ### Endpoint /project/delete/{projectId} ### Path Parameters - **projectId** (integer) - Required - The ID of the project to delete. ### Response Example Success Response (200): ```json { "isSuccess": true, "message": "Project deleted successfully" } ``` Error Response (403 Forbidden): ```json { "isSuccess": false, "message": "Permission Denied" } ``` Error Response (500 Internal Server Error): ```json { "isSuccess": false, "message": "Unexpected error occurred" } ``` ``` -------------------------------- ### Delete Story - C# Controller and Model Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Provides the C# controller action and underlying model logic for soft-deleting a story by setting its 'IsActive' flag to false. Includes success and failure response formats. ```csharp // Route: POST /story/delete/42 public ActionResult Delete(int storyId) { StoryModel story = new StoryModel(this.iStoryBaseModel); var res = story.DeleteStory(storyId); // Success: { "status": true, "message": "Story deleted successfully." } // Failure: { "status": false, "message": "Unexpected error occurred." } } ``` ```csharp // Underlying soft-delete in StoryBaseModel: public TransactionResult DeleteStory(int storyId) { using (var context = new TaskPlannerEntities()) { context.Stories .Where(i => i.IsActive && i.StoryId == storyId) .ToList() .ForEach(i => { i.UpdatedOn = DateTime.Now; i.IsActive = false; }); context.SaveChanges(); } return new TransactionResult { IsSuccess = true }; } ``` -------------------------------- ### Toggle Project Favourite Status Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Adds or removes a project from the authenticated user's favourites list. Uses the ASP.NET Identity NameIdentifier claim as the user ID. The UpdateFavouriteList method re-activates soft-deleted rows instead of inserting duplicates. ```csharp // Route: POST /project/favourite?projectId=7&isFavourite=true [HttpPost("/project/favourite/", Name = "Project_Favourite")] public JsonResult UpdateFavourite(int projectId, bool isFavourite) { var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); var res = new ProjectViewModel().UpdateFavouriteList(projectId, userId, isFavourite); // Add: { "isSuccess": true, "message": "Added to favourite" } // Remove: { "isSuccess": true, "message": "Removed from favourite" } // Error: { "isSuccess": false, "message": "Unexpected error occurred" } } ``` ```csharp // ProjectViewModel.UpdateFavouriteList — re-activates soft-deleted rows instead of inserting duplicates: public TransactionResult UpdateFavouriteList(int projectId, string userId, bool isFavouriteListAdded) { using (var context = new TaskPlannerEntities()) { var existing = context.Favourites .Where(i => i.ProjectId == projectId && i.UserId == userId).ToList(); if (isFavouriteListAdded) { if (existing.Any(i => !i.IsActive)) existing.Where(i => !i.IsActive).ToList() .ForEach(i => { i.IsActive = true; i.UpdatedOn = DateTime.Now; }); else context.Favourites.Add(new Favourite { ProjectId = projectId, UserId = userId, UpdatedOn = DateTime.Now, IsActive = true }); } else { existing.Where(i => i.IsActive).ToList() .ForEach(i => { i.IsActive = false; i.UpdatedOn = DateTime.Now; }); } context.SaveChanges(); } return new TransactionResult { IsSuccess = true }; } ``` -------------------------------- ### Paginated Story List Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Retrieves a paginated list of stories, supporting server-side operations like sorting, filtering, and searching via a DataManager object in the request body. ```APIDOC ## POST /storieslist/{projectId} ### Description Returns a JSON payload used by the Syncfusion Grid. Supports server-side sorting, filtering, searching, and paging via a `DataManager` body. ### Method POST ### Endpoint /storieslist/{projectId} ### Parameters #### Path Parameters - **projectId** (int) - Required - The ID of the project to retrieve stories from. #### Request Body - **DataManager** (object) - Required - An object containing pagination, sorting, filtering, and searching parameters. - **Skip** (int) - Optional - The number of records to skip. - **Take** (int) - Optional - The number of records to return. - **RequiresCounts** (bool) - Optional - Whether to return the total count of records. - **Sorted** (array) - Optional - An array of sort objects. - **name** (string) - The field to sort by. - **direction** (string) - The sort direction ('ascending' or 'descending'). - **Where** (array) - Optional - An array of filter objects. - **field** (string) - The field to filter on. - **operator** (string) - The filter operator (e.g., 'equal', 'contains'). - **value** (any) - The value to filter by. - **Search** (array) - Optional - An array of search objects. - **fields** (array) - The fields to search within. - **key** (string) - The search term. - **operator** (string) - The search operator (e.g., 'contains'). ### Response #### Success Response (200) - **result** (array) - An array of Story Objects. - **StoryId** (int) - The unique identifier for the story. - **TaskId** (int) - The associated task ID. - **Title** (string) - The title of the story. - **ThemeName** (string) - The name of the theme the story belongs to. - **EpicName** (string) - The name of the epic the story belongs to. - **Priority** (string) - The priority level of the story. - **Milestone** (string) - The milestone the story is part of. - **Release** (string) - The release version the story is associated with. - **Status** (string) - The current status of the story. - **Benifit** (int) - The benefit value of the story. - **Penalty** (int) - The penalty value of the story. - **StoryPoints** (int) - The story points assigned to the story. - **Tag** (string) - Any tags associated with the story. - **SortOrder** (int) - The sort order of the story. - **SprintName** (string) - The name of the sprint the story is in. - **AssigneeName** (string) - The name of the user assigned to the story. - **count** (int) - The total number of stories matching the criteria. ### Request Example ```json { "Skip": 0, "Take": 20, "RequiresCounts": true, "Sorted": [{ "name": "Title", "direction": "ascending" }], "Where": [{ "field": "Priority", "operator": "equal", "value": "High" }], "Search": [{ "fields": ["Title","ThemeName"], "key": "auth", "operator": "contains" }] } ``` ### Response Example ```json { "result": [ { "StoryId": 1, "TaskId": 101, "Title": "User Login", "ThemeName": "Authentication", "EpicName": "User Management", "Priority": "High", "Milestone": "M1", "Release": "v1.0", "Status": "In Progress", "Benifit": 10, "Penalty": 5, "StoryPoints": 5, "Tag": "auth", "SortOrder": 1, "SprintName": "Sprint 1", "AssigneeName": "alice" } ], "count": 1 } ``` ``` -------------------------------- ### TransactionResult Class Definition Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Defines the TransactionResult class, a uniform return object for all write operations. It encapsulates success/failure state, new record status, optional ID, and exception details. ```csharp // Objects/TransactionResult.cs public class TransactionResult { public bool IsSuccess { get; set; } // true = operation succeeded public bool IsNewRecord { get; set; } // true = INSERT (not UPDATE) public int? Id { get; set; } // inserted row ID when applicable public Exception Exception { get; set; } // populated on catch public string Message { get; set; } public string ErrorMessage{ get; set; } } ``` -------------------------------- ### Delete a Story Source: https://context7.com/bharatdwarkani/taskplanner/llms.txt Soft-deletes a story by setting its `IsActive` flag to `false`. ```APIDOC ## POST /story/delete/{storyId} ### Description Soft-deletes a story by setting its `IsActive` flag to `false`. ### Method POST ### Endpoint /story/delete/{storyId} ### Parameters #### Path Parameters - **storyId** (int) - Required - The ID of the story to delete. ### Response #### Success Response (200) - **status** (bool) - Indicates if the operation was successful. - **message** (string) - A message describing the outcome of the operation. ### Response Example ```json { "status": true, "message": "Story deleted successfully." } ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.