Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/deploy-docsify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Deploy Docsify to GitHub Pages

on:
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: "pages"
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Pages
uses: actions/configure-pages@v5

- name: Upload Docs artifact
uses: actions/upload-pages-artifact@v3
with:
path: docs

deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: github-pages
url: ${{ steps.deploy.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deploy
uses: actions/deploy-pages@v4

- name: Show deployed link
run: echo "Docs available at ${{ steps.deploy.outputs.page_url }}"
3 changes: 2 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<PackageVersion Include="Mapster" Version="7.4.0" />
<PackageVersion Include="Mapster.DependencyInjection" Version="1.0.1" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication" Version="2.3.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.23" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.11" />
<PackageVersion Include="Microsoft.AspNetCore.Http" Version="2.3.0" />
<PackageVersion Include="Microsoft.AspNetCore.Http.Extensions" Version="2.3.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.11" />
Expand Down Expand Up @@ -48,5 +48,6 @@
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.11" />
<PackageVersion Include="Google.Apis.Auth" Version="1.68.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.0.2" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR" Version="1.2.9" />
</ItemGroup>
</Project>
127 changes: 127 additions & 0 deletions SnakeAid.Api/Controllers/FirstAidGuidelineController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using MapsterMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SnakeAid.Core.Meta;
using SnakeAid.Core.Requests.FirstAidGuideline;
using SnakeAid.Core.Responses.FirstAidGuideline;
using SnakeAid.Core.Validators;
using SnakeAid.Service.Interfaces;
using Swashbuckle.AspNetCore.Annotations;

namespace SnakeAid.Api.Controllers
{
[Route("api/first-aid-guidelines")]
[ApiController]
public class FirstAidGuidelineController : BaseController<FirstAidGuidelineController>
{
private readonly IFirstAidGuidelineService _guidelineService;

public FirstAidGuidelineController(
ILogger<FirstAidGuidelineController> logger,
IHttpContextAccessor httpContextAccessor,
IMapper mapper,
IFirstAidGuidelineService guidelineService)
: base(logger, httpContextAccessor, mapper)
{
_guidelineService = guidelineService;
}

/// <summary>
/// Create a new first aid guideline
/// </summary>
[HttpPost]
[ValidateModel]
[SwaggerOperation(Summary = "Create First Aid Guideline", Description = "Create a new first aid guideline (Admin only)")]
[SwaggerResponse(200, "Created successfully", typeof(ApiResponse<FirstAidGuidelineResponse>))]
[SwaggerResponse(400, "Validation error")]
[SwaggerResponse(401, "Unauthorized")]
[SwaggerResponse(403, "Forbidden")]
public async Task<IActionResult> CreateFirstAidGuideline([FromBody] CreateFirstAidGuidelineRequest request)
{
var result = await _guidelineService.CreateFirstAidGuidelineAsync(request);
return StatusCode(result.StatusCode, result);
}

/// <summary>
/// Get first aid guideline by ID
/// </summary>
[HttpGet("{id}")]
[SwaggerOperation(Summary = "Get First Aid Guideline by ID", Description = "Get detailed information of a first aid guideline")]
[SwaggerResponse(200, "Success", typeof(ApiResponse<FirstAidGuidelineResponse>))]
[SwaggerResponse(404, "Guideline not found")]
public async Task<IActionResult> GetFirstAidGuidelineById(int id)
{
var result = await _guidelineService.GetFirstAidGuidelineByIdAsync(id);
return StatusCode(result.StatusCode, result);
}

/// <summary>
/// Get list of first aid guidelines with pagination and filters
/// </summary>
[HttpGet("filter")]
[SwaggerOperation(Summary = "Filter First Aid Guidelines", Description = "Get paginated list of first aid guidelines with optional filters")]
[SwaggerResponse(200, "Success", typeof(ApiResponse<PagedData<FirstAidGuidelineResponse>>))]
public async Task<IActionResult> FilterFirstAidGuidelines([FromQuery] GetFirstAidGuidelineRequest request)
{
var result = await _guidelineService.FilterFirstAidGuidelinesAsync(request);
return StatusCode(result.StatusCode, result);
}

/// <summary>
/// Get all first aid guidelines without pagination
/// </summary>
[HttpGet]
[SwaggerOperation(Summary = "Get All First Aid Guidelines", Description = "Get all first aid guidelines without pagination")]
[SwaggerResponse(200, "Success", typeof(ApiResponse<List<FirstAidGuidelineResponse>>))]
public async Task<IActionResult> GetAllFirstAidGuideline()
{
var result = await _guidelineService.GetAllFirstAidGuidelineAsync();
return StatusCode(result.StatusCode, result);
}

/// <summary>
/// Get first aid guidelines by snake species ID
/// </summary>
[HttpGet("by-snake-species/{snakeSpeciesId}")]
[SwaggerOperation(Summary = "Get First Aid Guidelines by Snake Species", Description = "Get first aid guidelines based on the venom types of a specific snake species")]
[SwaggerResponse(200, "Success", typeof(ApiResponse<List<FirstAidGuidelineResponse>>))]
[SwaggerResponse(404, "Snake species not found")]
public async Task<IActionResult> GetFirstAidGuidelinesBySnakeSpecies(int snakeSpeciesId)
{
var result = await _guidelineService.GetFirstAidGuidelinesBySnakeSpeciesIdAsync(snakeSpeciesId);
return StatusCode(result.StatusCode, result);
}

/// <summary>
/// Update an existing first aid guideline
/// </summary>
[HttpPut("{id}")]
[ValidateModel]
[SwaggerOperation(Summary = "Update First Aid Guideline", Description = "Update an existing first aid guideline (Admin only)")]
[SwaggerResponse(200, "Updated successfully", typeof(ApiResponse<FirstAidGuidelineResponse>))]
[SwaggerResponse(400, "Validation error")]
[SwaggerResponse(401, "Unauthorized")]
[SwaggerResponse(403, "Forbidden")]
[SwaggerResponse(404, "Guideline not found")]
public async Task<IActionResult> UpdateFirstAidGuideline(int id, [FromBody] UpdateFirstAidGuidelineRequest request)
{
var result = await _guidelineService.UpdateFirstAidGuidelineAsync(id, request);
return StatusCode(result.StatusCode, result);
}

/// <summary>
/// Delete a first aid guideline
/// </summary>
[HttpDelete("{id}")]
[SwaggerOperation(Summary = "Delete First Aid Guideline", Description = "Delete a first aid guideline (Admin only)")]
[SwaggerResponse(200, "Deleted successfully", typeof(ApiResponse<bool>))]
[SwaggerResponse(401, "Unauthorized")]
[SwaggerResponse(403, "Forbidden")]
[SwaggerResponse(404, "Guideline not found")]
public async Task<IActionResult> DeleteFirstAidGuideline(int id)
{
var result = await _guidelineService.DeleteFirstAidGuidelineAsync(id);
return StatusCode(result.StatusCode, result);
}
}
}
149 changes: 149 additions & 0 deletions SnakeAid.Api/Controllers/SignalRTestController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using SnakeAid.Api.Hubs;
using SnakeAid.Core.Meta;

namespace SnakeAid.Api.Controllers;

[ApiController]
[Route("api/[controller]")]
public class SignalRTestController : ControllerBase
{
private readonly IHubContext<TestChatHub> _hubContext;

public SignalRTestController(IHubContext<TestChatHub> hubContext)
{
_hubContext = hubContext;
}

[HttpGet("test-connection")]
public async Task<IActionResult> TestConnection()
{
try
{
return Ok(new ApiResponse<object>
{
StatusCode = 200,
Message = "SignalR hub is working correctly. Connect to /chat-hub for WebSocket connection.",
IsSuccess = true,
Data = new { HubEndpoint = "/chat-hub", Status = "Available" }
});
}
catch (Exception ex)
{
return StatusCode(500, new ApiResponse<object>
{
StatusCode = 500,
Message = $"SignalR test failed: {ex.Message}",
IsSuccess = false,
Data = null
});
}
}

[HttpPost("send-test-message")]
public async Task<IActionResult> SendTestMessage([FromBody] TestMessageRequest request)
{
try
{
var messageData = new
{
UserId = "server",
UserName = "Server",
Message = request.Message,
Timestamp = DateTime.UtcNow,
MessageId = Guid.NewGuid().ToString()
};

await _hubContext.Clients.All.SendAsync("ReceiveMessage", messageData);

return Ok(new ApiResponse<object>
{
StatusCode = 200,
Message = "Message sent successfully",
IsSuccess = true,
Data = null
});
}
catch (Exception ex)
{
return StatusCode(500, new ApiResponse<object>
{
StatusCode = 500,
Message = $"Failed to send message: {ex.Message}",
IsSuccess = false,
Data = null
});
}
}

[HttpGet("connected-users")]
public async Task<IActionResult> GetConnectedUsers()
{
try
{
// This is a simple endpoint to trigger user list update
await _hubContext.Clients.All.SendAsync("RequestUserListUpdate");
return Ok(new ApiResponse<object>
{
StatusCode = 200,
Message = "User list update requested",
IsSuccess = true,
Data = null
});
}
catch (Exception ex)
{
return StatusCode(500, new ApiResponse<object>
{
StatusCode = 500,
Message = $"Failed to request user list: {ex.Message}",
IsSuccess = false,
Data = null
});
}
}

[HttpPost("broadcast")]
public async Task<IActionResult> BroadcastMessage([FromBody] BroadcastRequest request)
{
try
{
await _hubContext.Clients.All.SendAsync("ServerBroadcast", new
{
Message = request.Message,
Timestamp = DateTime.UtcNow,
Type = request.Type ?? "info"
});

return Ok(new ApiResponse<object>
{
StatusCode = 200,
Message = "Broadcast sent successfully",
IsSuccess = true,
Data = null
});
}
catch (Exception ex)
{
return StatusCode(500, new ApiResponse<object>
{
StatusCode = 500,
Message = $"Failed to broadcast: {ex.Message}",
IsSuccess = false,
Data = null
});
}
}
}

public class TestMessageRequest
{
public string Message { get; set; } = string.Empty;
}

public class BroadcastRequest
{
public string Message { get; set; } = string.Empty;
public string? Type { get; set; } // info, warning, error, success
}
15 changes: 15 additions & 0 deletions SnakeAid.Api/Controllers/SnakebiteIncidentController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SnakeAid.Core.Meta;
using SnakeAid.Core.Requests;
using SnakeAid.Core.Requests.RescueRequestSession;
using SnakeAid.Core.Requests.SnakebiteIncident;
using SnakeAid.Core.Responses.Auth;
Expand Down Expand Up @@ -61,5 +62,19 @@ public async Task<IActionResult> RaiseSessionRange(Guid incidentId)
var result = await _incidentService.RaiseSessionRangeAsync(request);
return StatusCode(result.StatusCode, result);
}

/// <summary>
/// Update symptom report with time-based severity calculation
/// </summary>
[HttpPut("{incidentId}/symptoms-tracking")]
[SwaggerOperation(Summary = "Update Symptom Report", Description = "Update incident symptoms and calculate severity based on elapsed time")]
[SwaggerResponse(200, "Symptom report updated successfully", typeof(ApiResponse<UpdateSymptomReportResponse>))]
[SwaggerResponse(404, "Incident not found")]
[SwaggerResponse(422, "Validation error")]
public async Task<IActionResult> UpdateSymptomReport(Guid incidentId, [FromBody] UpdateSymptomReportRequest request)
{
var result = await _incidentService.UpdateSymptomReportAsync(incidentId, request);
return StatusCode(result.StatusCode, result);
}
}
}
Loading