.NET 8 backend with Zitadel JWT auth, TheMealDB integration, weekly meal plan generation, shopping list aggregation. Vue 3 + Tailwind 4 frontend with dark emerald theme, manual OIDC PKCE auth, all views implemented. Multi-stage Dockerfile with nginx reverse proxy. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
75 lines
2.1 KiB
C#
75 lines
2.1 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using MealPlanner.Models;
|
|
using MealPlanner.Services;
|
|
|
|
namespace MealPlanner.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("api/recipes")]
|
|
[Authorize]
|
|
public class RecipeController(RecipeService recipeService) : ControllerBase
|
|
{
|
|
private string UserId => User.FindFirst("sub")?.Value ?? throw new UnauthorizedAccessException();
|
|
|
|
[HttpGet]
|
|
public async Task<IActionResult> GetOwn()
|
|
{
|
|
var recipes = await recipeService.GetOwnRecipesAsync(UserId);
|
|
return Ok(recipes);
|
|
}
|
|
|
|
[HttpGet("{id:guid}")]
|
|
public async Task<IActionResult> GetById(Guid id)
|
|
{
|
|
var recipe = await recipeService.GetByIdOrFetchAsync(id);
|
|
if (recipe is null) return NotFound();
|
|
return Ok(recipe);
|
|
}
|
|
|
|
[HttpPost]
|
|
public async Task<IActionResult> Create([FromBody] Recipe recipe)
|
|
{
|
|
var created = await recipeService.CreateAsync(UserId, recipe);
|
|
return CreatedAtAction(nameof(GetById), new { id = created.Id }, created);
|
|
}
|
|
|
|
[HttpPut("{id:guid}")]
|
|
public async Task<IActionResult> Update(Guid id, [FromBody] Recipe recipe)
|
|
{
|
|
try
|
|
{
|
|
var updated = await recipeService.UpdateAsync(id, UserId, recipe);
|
|
if (updated is null) return NotFound();
|
|
return Ok(updated);
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
return Forbid();
|
|
}
|
|
}
|
|
|
|
[HttpDelete("{id:guid}")]
|
|
public async Task<IActionResult> Delete(Guid id)
|
|
{
|
|
try
|
|
{
|
|
var deleted = await recipeService.DeleteAsync(id, UserId);
|
|
if (!deleted) return NotFound();
|
|
return NoContent();
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
return Forbid();
|
|
}
|
|
}
|
|
|
|
[HttpGet("search")]
|
|
public async Task<IActionResult> Search([FromQuery] string q)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(q)) return BadRequest("Query parameter 'q' is required.");
|
|
var results = await recipeService.SearchAsync(q, UserId);
|
|
return Ok(results);
|
|
}
|
|
}
|