Skip to content
21 changes: 21 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Deploy to EC2
on:
push:
branches: [main]

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: SSH and deploy
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_KEY }}
script: |
cd /home/ec2-user/ValuationBackend
git pull
dotnet restore
sudo dotnet publish -c Release -o /var/app
sudo systemctl restart valuation-backend
16 changes: 8 additions & 8 deletions Controllers/LAMasterfileController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,33 @@ public LAMasterfileController(ILAMasterfileService service)
}

[HttpGet]
public ActionResult<LAMasterfileResponse> GetAll([FromQuery] int pageNumber = 0, [FromQuery] int pageSize = 15, [FromQuery] string sortBy = "")
public ActionResult<LAMasterfileResponse> GetAll([FromQuery] int pageNumber = 0, [FromQuery] int pageSize = 15, [FromQuery] string sortBy = "", [FromQuery] int? assignedToUserId = null)
{
// Adjust pageNumber to be 1-based for internal logic
var page = pageNumber + 1;
return Ok(_service.GetPaged(page, pageSize, sortBy));
return Ok(_service.GetPaged(page, pageSize, sortBy, assignedToUserId));
}

[HttpGet("paged")]
public ActionResult<LAMasterfileResponse> GetPaged([FromQuery] int page = 1, [FromQuery] int pageSize = 10, [FromQuery] string sortBy = "")
public ActionResult<LAMasterfileResponse> GetPaged([FromQuery] int page = 1, [FromQuery] int pageSize = 10, [FromQuery] string sortBy = "", [FromQuery] int? assignedToUserId = null)
{
return Ok(_service.GetPaged(page, pageSize, sortBy));
return Ok(_service.GetPaged(page, pageSize, sortBy, assignedToUserId));
}

[HttpPost("search")]
[HttpPost("filter")]
public ActionResult<LAMasterfileResponse> Search([FromBody] LAQueryRequest request, [FromQuery] string sortBy = "")
public ActionResult<LAMasterfileResponse> Search([FromBody] LAQueryRequest request, [FromQuery] string sortBy = "", [FromQuery] int? assignedToUserId = null)
{
var query = request.Query.ToLower();
var response = _service.Search(query, sortBy);
var response = _service.Search(query, sortBy, assignedToUserId);
return Ok(response);
}

[HttpPost("search/paged")]
public ActionResult<LAMasterfileResponse> SearchPaged([FromBody] LAQueryRequest request, [FromQuery] int page = 1, [FromQuery] int pageSize = 10, [FromQuery] string sortBy = "")
public ActionResult<LAMasterfileResponse> SearchPaged([FromBody] LAQueryRequest request, [FromQuery] int page = 1, [FromQuery] int pageSize = 10, [FromQuery] string sortBy = "", [FromQuery] int? assignedToUserId = null)
{
var query = request.Query.ToLower();
var response = _service.SearchPaged(query, page, pageSize, sortBy);
var response = _service.SearchPaged(query, page, pageSize, sortBy, assignedToUserId);
return Ok(response);
}
}
Expand Down
3 changes: 2 additions & 1 deletion Controllers/ProfileController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ public IActionResult GetUserProfile([FromBody] UserProfileRequest request)
empEmail = user.EmpEmail,
empId = user.EmpId,
position = user.Position,
assignedDivision = user.AssignedDivision
assignedDivision = user.AssignedDivision,
profilePicture = user.ProfilePicture != null ? Convert.ToBase64String(user.ProfilePicture) : null
});
}
}
Expand Down
43 changes: 43 additions & 0 deletions Controllers/UserProfileController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ValuationBackend.Data;

namespace ValuationBackend.Controllers
{
public class ProfilePictureUploadDto
{
public int UserId { get; set; }
public IFormFile Image { get; set; }
}

[ApiController]
[Route("api/[controller]")]
public class UserProfileController : ControllerBase
{
private readonly AppDbContext _context;

public UserProfileController(AppDbContext context)
{
_context = context;
}

[HttpPost("upload-profile-picture")]
public async Task<IActionResult> UploadProfilePicture([FromForm] ProfilePictureUploadDto dto)
{
if (dto.Image == null || dto.Image.Length == 0)
return BadRequest("No image uploaded.");

var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == dto.UserId);
if (user == null)
return NotFound("User not found.");

using var ms = new MemoryStream();
await dto.Image.CopyToAsync(ms);
user.ProfilePicture = ms.ToArray();

await _context.SaveChangesAsync();

return Ok("Profile picture updated.");
}
}
}
18 changes: 12 additions & 6 deletions Controllers/UserTaskController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,18 @@ public ActionResult<UserTaskOverviewResponse> GetTaskOverview([FromBody] UserTas
{
var userTasks = _context.UserTasks.Where(t => t.Username == request.Username).ToList();

var laAssigned = userTasks.Count(t => t.TaskType == "LA");
var laCompleted = userTasks.Count(t => t.TaskType == "LA" && t.IsCompleted);
var mrAssigned = userTasks.Count(t => t.TaskType == "MR");
var mrCompleted = userTasks.Count(t => t.TaskType == "MR" && t.IsCompleted);
var lmAssigned = userTasks.Count(t => t.TaskType == "LM");
var lmCompleted = userTasks.Count(t => t.TaskType == "LM" && t.IsCompleted);
// Debug log: print all userTasks for this user
Console.WriteLine($"UserTasks for {request.Username}: {string.Join(", ", userTasks.Select(t => $"{t.TaskType}:{t.IsCompleted}"))}");

var laAssigned = userTasks.Count(t => t.TaskType != null && t.TaskType.ToUpper() == "LA");
var laCompleted = userTasks.Count(t => t.TaskType != null && t.TaskType.ToUpper() == "LA" && t.IsCompleted);
var mrAssigned = userTasks.Count(t => t.TaskType != null && t.TaskType.ToUpper() == "MR");
var mrCompleted = userTasks.Count(t => t.TaskType != null && t.TaskType.ToUpper() == "MR" && t.IsCompleted);
var lmAssigned = userTasks.Count(t => t.TaskType != null && t.TaskType.ToUpper() == "LM");
var lmCompleted = userTasks.Count(t => t.TaskType != null && t.TaskType.ToUpper() == "LM" && t.IsCompleted);

// Debug log: print computed counts
Console.WriteLine($"LA: {laAssigned}, MR: {mrAssigned}, LM: {lmAssigned}, LA Done: {laCompleted}, MR Done: {mrCompleted}, LM Done: {lmCompleted}");

return Ok(new UserTaskOverviewResponse
{
Expand Down
204 changes: 204 additions & 0 deletions Controllers/iteration2/OfficesRatingCardController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using ValuationBackend.Models.iteration2.DTOs;
using ValuationBackend.services.iteration2;

namespace ValuationBackend.Controllers.iteration2
{
[Route("api/[controller]")]
[ApiController]
public class OfficesRatingCardController : ControllerBase
{
private readonly IOfficesRatingCardService _service;
private readonly ILogger<OfficesRatingCardController> _logger;

public OfficesRatingCardController(
IOfficesRatingCardService service,
ILogger<OfficesRatingCardController> logger)
{
_service = service;
_logger = logger;
}

/// <summary>
/// Get all offices rating cards
/// </summary>
[HttpGet]
public async Task<ActionResult<IEnumerable<OfficesRatingCardDto>>> GetAll()
{
try
{
var result = await _service.GetAllAsync();
return Ok(result);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving all offices rating cards");
return StatusCode(500, "An error occurred while retrieving offices rating cards.");
}
}

/// <summary>
/// Get offices rating card by ID
/// </summary>
[HttpGet("{id}")]
public async Task<ActionResult<OfficesRatingCardDto>> GetById(int id)
{
try
{
var result = await _service.GetByIdAsync(id);
return Ok(result);
}
catch (KeyNotFoundException)
{
return NotFound($"OfficesRatingCard with ID {id} not found.");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving offices rating card with ID {Id}", id);
return StatusCode(500, "An error occurred while retrieving the offices rating card.");
}
}

/// <summary>
/// Get offices rating card by Asset ID
/// </summary>
[HttpGet("asset/{assetId}")]
public async Task<ActionResult<OfficesRatingCardDto>> GetByAssetId(int assetId)
{
try
{
var result = await _service.GetByAssetIdAsync(assetId);
return Ok(result);
}
catch (KeyNotFoundException)
{
return NotFound($"OfficesRatingCard for Asset ID {assetId} not found.");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving offices rating card for Asset ID {AssetId}", assetId);
return StatusCode(500, "An error occurred while retrieving the offices rating card.");
}
}

/// <summary>
/// Create a new offices rating card
/// </summary>
[HttpPost("asset/{assetId}")]
public async Task<ActionResult<OfficesRatingCardDto>> Create(int assetId, [FromBody] CreateOfficesRatingCardDto dto)
{
try
{
if (dto == null)
{
return BadRequest("Invalid offices rating card data.");
}

// Ensure the assetId from route matches the one in the body
dto.AssetId = assetId;

if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

var result = await _service.CreateAsync(dto);
return CreatedAtAction(nameof(GetById), new { id = result.Id }, result);
}
catch (InvalidOperationException ex)
{
return Conflict(ex.Message);
}
catch (KeyNotFoundException ex)
{
return NotFound(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error creating offices rating card for Asset ID {AssetId}", assetId);
return StatusCode(500, "An error occurred while creating the offices rating card.");
}
}

/// <summary>
/// Update an existing offices rating card
/// </summary>
[HttpPut("{id}")]
public async Task<ActionResult<OfficesRatingCardDto>> Update(int id, [FromBody] UpdateOfficesRatingCardDto dto)
{
try
{
if (dto == null)
{
return BadRequest("Invalid offices rating card data.");
}

if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

var result = await _service.UpdateAsync(id, dto);
return Ok(result);
}
catch (KeyNotFoundException)
{
return NotFound($"OfficesRatingCard with ID {id} not found.");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error updating offices rating card with ID {Id}", id);
return StatusCode(500, "An error occurred while updating the offices rating card.");
}
}

/// <summary>
/// Delete an offices rating card
/// </summary>
[HttpDelete("{id}")]
public async Task<ActionResult> Delete(int id)
{
try
{
var result = await _service.DeleteAsync(id);
if (!result)
{
return NotFound($"OfficesRatingCard with ID {id} not found.");
}

return NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting offices rating card with ID {Id}", id);
return StatusCode(500, "An error occurred while deleting the offices rating card.");
}
}

/// <summary>
/// Get autofill data for offices rating card
/// </summary>
[HttpGet("autofill/{assetId}")]
public async Task<ActionResult<OfficesRatingCardAutofillDto>> GetAutofillData(int assetId)
{
try
{
var result = await _service.GetAutofillDataAsync(assetId);
return Ok(result);
}
catch (KeyNotFoundException)
{
return NotFound($"Asset with ID {assetId} not found.");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving autofill data for Asset ID {AssetId}", assetId);
return StatusCode(500, "An error occurred while retrieving autofill data.");
}
}
}
}
3 changes: 3 additions & 0 deletions Data/AppDbContext.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore;
using ValuationBackend.Models;
using ValuationBackend.Models.iteration2.RatingCards;

namespace ValuationBackend.Data
{
Expand Down Expand Up @@ -55,6 +56,8 @@ public AppDbContext(DbContextOptions<AppDbContext> options)

public DbSet<DomesticRatingCard> DomesticRatingCards { get; set; }

public DbSet<OfficesRatingCard> OfficesRatingCards { get; set; }

public DbSet<Asset> Assets { get; set; }

public DbSet<PropertyCategory> PropertyCategories { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion Data/DBInitializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public static void Initialize(AppDbContext context)
UpdateUserTaskUserIds(context);

// Remove UserTasks that are not LM (Land Miscellaneous)
RemoveNonLMUserTasks(context);
// RemoveNonLMUserTasks(context);

// Initialize Master Data
InitializeMasterData(context); // Initialize Land Aquisition Master Files
Expand Down
3 changes: 3 additions & 0 deletions Extensions/RepositoryExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using ValuationBackend.Repositories;
using ValuationBackend.repositories;
using ValuationBackend.repositories.iteration2;

namespace ValuationBackend.Extensions
{
Expand All @@ -22,6 +24,7 @@ public static IServiceCollection AddRepositories(this IServiceCollection service
services.AddScoped<IAssetDivisionRepository, AssetDivisionRepository>();
services.AddScoped<IReconciliationRepository, ReconciliationRepository>();
services.AddScoped<IDomesticRatingCardRepository, DomesticRatingCardRepository>();
services.AddScoped<IOfficesRatingCardRepository, OfficesRatingCardRepository>();
services.AddScoped<ILAMasterfileRepository, LAMasterfileRepository>();
services.AddScoped<IRequestTypeRepository, RequestTypeRepository>();
services.AddScoped<IRequestRepository, RequestRepository>();
Expand Down
Loading