From 8304d65e65fdfd5f4fc90c97ed5075148ccf467e Mon Sep 17 00:00:00 2001 From: ivan-pelly Date: Sat, 21 Feb 2026 10:57:12 -0800 Subject: [PATCH] API Silent Merge fail --- api/Program.cs | 47 +++++++++++++++++++ api/api.csproj | 2 + api/appsettings.json | 8 ++++ api/src/BaseClasses/BaseController.cs | 6 +-- api/src/Controllers/StudentController.cs | 12 ++--- .../DataTransferObjects/CreateStudentDto.cs | 4 +- .../DataTransferObjects/UpdateStudentDto.cs | 2 +- .../Models/DatabaseObjects/dbStudent.cs | 4 +- .../Repositories/StudentRepository.cs | 18 +++---- .../Models/ResponseTypes/StudentResponse.cs | 4 +- 10 files changed, 82 insertions(+), 25 deletions(-) diff --git a/api/Program.cs b/api/Program.cs index c4dff81..548945c 100644 --- a/api/Program.cs +++ b/api/Program.cs @@ -1,9 +1,52 @@ +using System.Text; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.IdentityModel.Tokens; using WinStudentGoalTracker.Api.Configuration; +using WinStudentGoalTracker.Services; var builder = WebApplication.CreateBuilder(args); ConfigHelper.Configuration = builder.Configuration; +var jwtKey = builder.Configuration["Jwt:Key"] ?? "super_secret_key_change_me_in_production_123!"; +var jwtIssuer = builder.Configuration["Jwt:Issuer"] ?? "WinStudentGoalTrackerAPI"; + +builder.Services.AddAuthentication(options => +{ + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; +}) +.AddJwtBearer(options => +{ + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true, + ValidateAudience = false, + ValidateLifetime = true, + ValidateIssuerSigningKey = true, + ValidIssuer = jwtIssuer, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey)), + ClockSkew = TimeSpan.Zero, + RoleClaimType = System.Security.Claims.ClaimTypes.Role + }; +}); + +builder.Services.AddAuthorization(); + +builder.Services.AddScoped(); + +builder.Services.AddHttpClient(client => +{ + client.BaseAddress = new Uri("https://stt.opelly.me"); + client.Timeout = TimeSpan.FromMinutes(5); +}); + +builder.Services.AddHttpClient(client => +{ + client.BaseAddress = new Uri(builder.Configuration["Ollama:BaseUrl"] ?? "https://llm.opelly.me"); + client.Timeout = TimeSpan.FromMinutes(3); +}); + builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); @@ -25,6 +68,10 @@ if (app.Environment.IsDevelopment()) app.UseCors(); app.UseHttpsRedirection(); + +app.UseAuthentication(); +app.UseAuthorization(); + app.MapControllers(); app.Run(); diff --git a/api/api.csproj b/api/api.csproj index 4b8535c..ab39f78 100644 --- a/api/api.csproj +++ b/api/api.csproj @@ -8,8 +8,10 @@ + + diff --git a/api/appsettings.json b/api/appsettings.json index a76fc22..88d864b 100644 --- a/api/appsettings.json +++ b/api/appsettings.json @@ -2,6 +2,14 @@ "ConnectionStrings": { "DefaultConnection": "Server=localhost;Port=3306;Database=win_student_goal_tracker;Uid=root;Pwd=change_me;" }, + "Jwt": { + "Key": "super_secret_key_change_me_in_production_123!", + "Issuer": "WinStudentGoalTrackerAPI" + }, + "Ollama": { + "BaseUrl": "https://llm.opelly.me", + "Model": "gpt-oss:20b" + }, "Logging": { "LogLevel": { "Default": "Information", diff --git a/api/src/BaseClasses/BaseController.cs b/api/src/BaseClasses/BaseController.cs index dc09d65..83cb0c7 100644 --- a/api/src/BaseClasses/BaseController.cs +++ b/api/src/BaseClasses/BaseController.cs @@ -5,14 +5,14 @@ namespace WinStudentGoalTracker.BaseClasses; public class BaseController : ControllerBase { - protected (int userId, ActionResult? error) GetUserIdFromClaims() + protected (Guid userId, ActionResult? error) GetUserIdFromClaims() { var userIdClaim = User.FindFirst("user_id")?.Value ?? User.FindFirst(ClaimTypes.NameIdentifier)?.Value; - if (string.IsNullOrWhiteSpace(userIdClaim) || !int.TryParse(userIdClaim, out var userId)) + if (string.IsNullOrWhiteSpace(userIdClaim) || !Guid.TryParse(userIdClaim, out var userId)) { - return (0, Unauthorized("Missing or invalid user_id claim.")); + return (Guid.Empty, Unauthorized("Missing or invalid user_id claim.")); } return (userId, null); diff --git a/api/src/Controllers/StudentController.cs b/api/src/Controllers/StudentController.cs index 57c78f8..1cac137 100644 --- a/api/src/Controllers/StudentController.cs +++ b/api/src/Controllers/StudentController.cs @@ -29,10 +29,10 @@ public class StudentController : BaseController }); } - [HttpGet("{idStudent:int}")] + [HttpGet("{idStudent:guid}")] [ProducesResponseType(typeof(ResponseResult), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ResponseResult), StatusCodes.Status404NotFound)] - public async Task>> GetById(int idStudent) + public async Task>> GetById(Guid idStudent) { var student = await _studentRepository.GetByIdAsync(idStudent); if (student is null) @@ -84,10 +84,10 @@ public class StudentController : BaseController }); } - [HttpPut("{idStudent:int}")] + [HttpPut("{idStudent:guid}")] [ProducesResponseType(typeof(ResponseResult), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ResponseResult), StatusCodes.Status404NotFound)] - public async Task>> Update(int idStudent, [FromBody] UpdateStudentDto request) + public async Task>> Update(Guid idStudent, [FromBody] UpdateStudentDto request) { var existing = await _studentRepository.GetByIdAsync(idStudent); if (existing is null) @@ -118,10 +118,10 @@ public class StudentController : BaseController }); } - [HttpDelete("{idStudent:int}")] + [HttpDelete("{idStudent:guid}")] [ProducesResponseType(typeof(ResponseResult), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ResponseResult), StatusCodes.Status404NotFound)] - public async Task>> Delete(int idStudent) + public async Task>> Delete(Guid idStudent) { var deleted = await _studentRepository.DeleteAsync(idStudent); if (!deleted) diff --git a/api/src/DataAccess/Models/DataTransferObjects/CreateStudentDto.cs b/api/src/DataAccess/Models/DataTransferObjects/CreateStudentDto.cs index a958b9b..b0e1c19 100644 --- a/api/src/DataAccess/Models/DataTransferObjects/CreateStudentDto.cs +++ b/api/src/DataAccess/Models/DataTransferObjects/CreateStudentDto.cs @@ -2,8 +2,8 @@ namespace WinStudentGoalTracker.DataAccess; public class CreateStudentDto { - public required int IdStudent { get; set; } - public int? IdProgram { get; set; } + public required Guid IdStudent { get; set; } + public Guid? IdProgram { get; set; } public string? Identifier { get; set; } public int? ProgramYear { get; set; } public DateTime? EnrollmentDate { get; set; } diff --git a/api/src/DataAccess/Models/DataTransferObjects/UpdateStudentDto.cs b/api/src/DataAccess/Models/DataTransferObjects/UpdateStudentDto.cs index 212fde7..fa721cc 100644 --- a/api/src/DataAccess/Models/DataTransferObjects/UpdateStudentDto.cs +++ b/api/src/DataAccess/Models/DataTransferObjects/UpdateStudentDto.cs @@ -2,7 +2,7 @@ namespace WinStudentGoalTracker.DataAccess; public class UpdateStudentDto { - public int? IdProgram { get; set; } + public Guid? IdProgram { get; set; } public string? Identifier { get; set; } public int? ProgramYear { get; set; } public DateTime? EnrollmentDate { get; set; } diff --git a/api/src/DataAccess/Models/DatabaseObjects/dbStudent.cs b/api/src/DataAccess/Models/DatabaseObjects/dbStudent.cs index 8a5b50e..0f87a9b 100644 --- a/api/src/DataAccess/Models/DatabaseObjects/dbStudent.cs +++ b/api/src/DataAccess/Models/DatabaseObjects/dbStudent.cs @@ -2,8 +2,8 @@ namespace WinStudentGoalTracker.DataAccess; public class dbStudent { - public required int IdStudent { get; set; } - public int? IdProgram { get; set; } + public required Guid IdStudent { get; set; } + public Guid? IdProgram { get; set; } public string? Identifier { get; set; } public int? ProgramYear { get; set; } public DateTime? EnrollmentDate { get; set; } diff --git a/api/src/DataAccess/Repositories/StudentRepository.cs b/api/src/DataAccess/Repositories/StudentRepository.cs index 9dbbebb..c646958 100644 --- a/api/src/DataAccess/Repositories/StudentRepository.cs +++ b/api/src/DataAccess/Repositories/StudentRepository.cs @@ -16,12 +16,12 @@ public class StudentRepository commandType: CommandType.StoredProcedure); } - public async Task GetByIdAsync(int idStudent) + public async Task GetByIdAsync(Guid idStudent) { using var db = Connection; return await db.QuerySingleOrDefaultAsync( "sp_Student_GetById", - new { p_id_student = idStudent }, + new { p_id_student = idStudent.ToString() }, commandType: CommandType.StoredProcedure); } @@ -32,8 +32,8 @@ public class StudentRepository "sp_Student_Insert", new { - p_id_student = dto.IdStudent, - p_id_program = dto.IdProgram, + p_id_student = dto.IdStudent.ToString(), + p_id_program = dto.IdProgram?.ToString(), p_identifier = dto.Identifier, p_program_year = dto.ProgramYear, p_enrollment_date = dto.EnrollmentDate, @@ -42,15 +42,15 @@ public class StudentRepository commandType: CommandType.StoredProcedure); } - public async Task UpdateAsync(int idStudent, UpdateStudentDto dto) + public async Task UpdateAsync(Guid idStudent, UpdateStudentDto dto) { using var db = Connection; var rowsAffected = await db.ExecuteScalarAsync( "sp_Student_Update", new { - p_id_student = idStudent, - p_id_program = dto.IdProgram, + p_id_student = idStudent.ToString(), + p_id_program = dto.IdProgram?.ToString(), p_identifier = dto.Identifier, p_program_year = dto.ProgramYear, p_enrollment_date = dto.EnrollmentDate, @@ -60,12 +60,12 @@ public class StudentRepository return rowsAffected > 0; } - public async Task DeleteAsync(int idStudent) + public async Task DeleteAsync(Guid idStudent) { using var db = Connection; var rowsAffected = await db.ExecuteScalarAsync( "sp_Student_Delete", - new { p_id_student = idStudent }, + new { p_id_student = idStudent.ToString() }, commandType: CommandType.StoredProcedure); return rowsAffected > 0; } diff --git a/api/src/Models/ResponseTypes/StudentResponse.cs b/api/src/Models/ResponseTypes/StudentResponse.cs index b0aed06..c538431 100644 --- a/api/src/Models/ResponseTypes/StudentResponse.cs +++ b/api/src/Models/ResponseTypes/StudentResponse.cs @@ -4,8 +4,8 @@ namespace WinStudentGoalTracker.Models; public class StudentResponse { - public int IdStudent { get; set; } - public int? IdProgram { get; set; } + public Guid IdStudent { get; set; } + public Guid? IdProgram { get; set; } public string? Identifier { get; set; } public int? ProgramYear { get; set; } public DateTime? EnrollmentDate { get; set; }