Skip to content
Open
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
73 changes: 15 additions & 58 deletions Controllers/TodoItemsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,106 +4,63 @@
using System.Linq;
using System.Threading.Tasks;
using TodoApi.Models;
using TodoApiDTO.Data;
using TodoApiDTO.Services.Interfaces;

namespace TodoApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
private readonly TodoContext _context;
private readonly ITodoItemService _todoItemService;

public TodoItemsController(TodoContext context)
public TodoItemsController(ITodoItemService todoItemService)
{
_context = context;
_todoItemService = todoItemService;
}

[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
var todoItems = await _todoItemService.GetTodoItems();
return Ok(todoItems);
}

[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
var todoItem = await _todoItemService.GetTodoItem(id);

if (todoItem == null)
{
return NotFound();
}

return ItemToDTO(todoItem);
return Ok(todoItem);
}

[HttpPut("{id}")]
public async Task<IActionResult> UpdateTodoItem(long id, TodoItemDTO todoItemDTO)
{
if (id != todoItemDTO.Id)
{
return BadRequest();
}

var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}

todoItem.Name = todoItemDTO.Name;
todoItem.IsComplete = todoItemDTO.IsComplete;

try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}

return NoContent();
var result = await _todoItemService.UpdateTodoItem(id, todoItemDTO);
return result;
}

[HttpPost]
public async Task<ActionResult<TodoItemDTO>> CreateTodoItem(TodoItemDTO todoItemDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoItemDTO.IsComplete,
Name = todoItemDTO.Name
};

_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();

return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
var createdItem = await _todoItemService.CreateTodoItem(todoItemDTO);
return CreatedAtAction(nameof(GetTodoItem), new { id = createdItem.Id }, createdItem);
}

[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);

if (todoItem == null)
{
return NotFound();
}

_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();

return NoContent();
var result = await _todoItemService.DeleteTodoItem(id);
return result;
}

private bool TodoItemExists(long id) =>
_context.TodoItems.Any(e => e.Id == id);

private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
Expand Down
17 changes: 17 additions & 0 deletions CreateTableQuery.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
DROP TABLE TodoItems;

CREATE TABLE TodoItems (
id BIGINT NOT NULL PRIMARY KEY IDENTITY,
name VARCHAR(200) NOT NULL,
isComplete BIT NOT NULL,
secret VARCHAR(200)
);

INSERT INTO TodoItems (name, isComplete, secret)
VALUES
('Add Swagger', 1, 'Placeholder'),
('Integrate SQL in the project', 1, 'Placeholder'),
('Add Logging in file', 0, 'Placeholder'),
('Separate Business Layers', 0, 'Placeholder'),
('Refactoring', 0 , 'Placeholder')

3 changes: 2 additions & 1 deletion Models/TodoContext.cs → Data/TodoContext.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi.Models
namespace TodoApiDTO.Data
{
public class TodoContext : DbContext
{
Expand Down
39 changes: 39 additions & 0 deletions Logs202306221707.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
2023-06-22 17:07:04.674 +04:00 [INF] User profile is available. Using 'C:\Users\David\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.
2023-06-22 17:07:05.234 +04:00 [INF] Application started. Press Ctrl+C to shut down.
2023-06-22 17:07:05.243 +04:00 [INF] Hosting environment: Development
2023-06-22 17:07:05.246 +04:00 [INF] Content root path: C:\Users\David\Source\Repos\VelvetechTestTask
2023-06-22 17:07:05.273 +04:00 [INF] Request starting HTTP/2.0 GET https://localhost:44331/api/todoitems
2023-06-22 17:07:05.341 +04:00 [INF] Executing endpoint 'TodoApi.Controllers.TodoItemsController.GetTodoItems (TodoApiDTO)'
2023-06-22 17:07:05.410 +04:00 [INF] Route matched with {action = "GetTodoItems", controller = "TodoItems"}. Executing controller action with signature System.Threading.Tasks.Task`1[Microsoft.AspNetCore.Mvc.ActionResult`1[System.Collections.Generic.IEnumerable`1[TodoApi.Models.TodoItemDTO]]] GetTodoItems() on controller TodoApi.Controllers.TodoItemsController (TodoApiDTO).
2023-06-22 17:07:05.967 +04:00 [INF] Entity Framework Core 3.1.0 initialized 'TodoContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: None
2023-06-22 17:07:06.537 +04:00 [INF] Executed DbCommand (38ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT [t].[Id], [t].[IsComplete], [t].[Name], [t].[Secret]
FROM [TodoItems] AS [t]
2023-06-22 17:07:06.616 +04:00 [INF] Executing ObjectResult, writing value of type 'System.Collections.Generic.List`1[[TodoApi.Models.TodoItemDTO, TodoApiDTO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'.
2023-06-22 17:07:06.738 +04:00 [INF] Executed action TodoApi.Controllers.TodoItemsController.GetTodoItems (TodoApiDTO) in 1322.1577ms
2023-06-22 17:07:06.740 +04:00 [INF] Executed endpoint 'TodoApi.Controllers.TodoItemsController.GetTodoItems (TodoApiDTO)'
2023-06-22 17:07:06.751 +04:00 [INF] Request finished in 1483.5408ms 200 application/json; charset=utf-8
2023-06-22 17:07:12.178 +04:00 [INF] Request starting HTTP/2.0 GET https://localhost:44331/api/todoitems/1
2023-06-22 17:07:12.183 +04:00 [INF] Executing endpoint 'TodoApi.Controllers.TodoItemsController.GetTodoItem (TodoApiDTO)'
2023-06-22 17:07:12.196 +04:00 [INF] Route matched with {action = "GetTodoItem", controller = "TodoItems"}. Executing controller action with signature System.Threading.Tasks.Task`1[Microsoft.AspNetCore.Mvc.ActionResult`1[TodoApi.Models.TodoItemDTO]] GetTodoItem(Int64) on controller TodoApi.Controllers.TodoItemsController (TodoApiDTO).
2023-06-22 17:07:12.238 +04:00 [INF] Entity Framework Core 3.1.0 initialized 'TodoContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: None
2023-06-22 17:07:12.318 +04:00 [INF] Executed DbCommand (39ms) [Parameters=[@__p_0='?' (DbType = Int64)], CommandType='"Text"', CommandTimeout='30']
SELECT TOP(1) [t].[Id], [t].[IsComplete], [t].[Name], [t].[Secret]
FROM [TodoItems] AS [t]
WHERE [t].[Id] = @__p_0
2023-06-22 17:07:12.321 +04:00 [INF] Executing ObjectResult, writing value of type 'TodoApi.Models.TodoItemDTO'.
2023-06-22 17:07:12.323 +04:00 [INF] Executed action TodoApi.Controllers.TodoItemsController.GetTodoItem (TodoApiDTO) in 126.6063ms
2023-06-22 17:07:12.323 +04:00 [INF] Executed endpoint 'TodoApi.Controllers.TodoItemsController.GetTodoItem (TodoApiDTO)'
2023-06-22 17:07:12.323 +04:00 [INF] Request finished in 145.5845ms 200 application/json; charset=utf-8
2023-06-22 17:07:15.623 +04:00 [INF] Request starting HTTP/2.0 GET https://localhost:44331/api/todoitems/6
2023-06-22 17:07:15.625 +04:00 [INF] Executing endpoint 'TodoApi.Controllers.TodoItemsController.GetTodoItem (TodoApiDTO)'
2023-06-22 17:07:15.625 +04:00 [INF] Route matched with {action = "GetTodoItem", controller = "TodoItems"}. Executing controller action with signature System.Threading.Tasks.Task`1[Microsoft.AspNetCore.Mvc.ActionResult`1[TodoApi.Models.TodoItemDTO]] GetTodoItem(Int64) on controller TodoApi.Controllers.TodoItemsController (TodoApiDTO).
2023-06-22 17:07:15.635 +04:00 [INF] Entity Framework Core 3.1.0 initialized 'TodoContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: None
2023-06-22 17:07:15.644 +04:00 [INF] Executed DbCommand (4ms) [Parameters=[@__p_0='?' (DbType = Int64)], CommandType='"Text"', CommandTimeout='30']
SELECT TOP(1) [t].[Id], [t].[IsComplete], [t].[Name], [t].[Secret]
FROM [TodoItems] AS [t]
WHERE [t].[Id] = @__p_0
2023-06-22 17:07:15.649 +04:00 [INF] Executing ObjectResult, writing value of type 'Microsoft.AspNetCore.Mvc.ProblemDetails'.
2023-06-22 17:07:15.655 +04:00 [INF] Executed action TodoApi.Controllers.TodoItemsController.GetTodoItem (TodoApiDTO) in 29.833ms
2023-06-22 17:07:15.655 +04:00 [INF] Executed endpoint 'TodoApi.Controllers.TodoItemsController.GetTodoItem (TodoApiDTO)'
2023-06-22 17:07:15.656 +04:00 [INF] Request finished in 33.5163ms 404 application/problem+json; charset=utf-8
1 change: 1 addition & 0 deletions Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "api/todoitems",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
Expand Down
16 changes: 16 additions & 0 deletions Services/Interfaces/ITodoItemService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
using TodoApi.Models;

namespace TodoApiDTO.Services.Interfaces
{
public interface ITodoItemService
{
Task<List<TodoItemDTO>> GetTodoItems();
Task<TodoItemDTO> CreateTodoItem(TodoItemDTO todoItemDTO);
Task<TodoItemDTO> GetTodoItem(long id);
Task<IActionResult> UpdateTodoItem(long id, TodoItemDTO todoItemDTO);
Task<IActionResult> DeleteTodoItem(long id);
}
}
112 changes: 112 additions & 0 deletions Services/TodoItemService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
using TodoApiDTO.Data;
using TodoApiDTO.Services.Interfaces;

namespace TodoApiDTO.Services
{
public class TodoItemService : ITodoItemService
{
private readonly TodoContext _context;

public TodoItemService(TodoContext context)
{
_context = context;
}

public async Task<List<TodoItemDTO>> GetTodoItems()
{
var todoItems = await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();

return todoItems;
}

public async Task<TodoItemDTO> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);

if (todoItem == null)
{
return null;
}

var todoItemDTO = ItemToDTO(todoItem);
return todoItemDTO;
}

public async Task<IActionResult> UpdateTodoItem(long id, TodoItemDTO todoItemDTO)
{
if (id != todoItemDTO.Id)
{
return new BadRequestResult();
}

var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return new NotFoundResult();
}

todoItem.Name = todoItemDTO.Name;
todoItem.IsComplete = todoItemDTO.IsComplete;

try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return new NotFoundResult();
}

return new NoContentResult();
}

public async Task<TodoItemDTO> CreateTodoItem(TodoItemDTO todoItemDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoItemDTO.IsComplete,
Name = todoItemDTO.Name
};

_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();

return ItemToDTO(todoItem);
}

public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);

if (todoItem == null)
{
return new NotFoundResult();
}

_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();

return new NoContentResult();
}

private bool TodoItemExists(long id) =>
_context.TodoItems.Any(e => e.Id == id);


private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
};
}
}
Loading