Add mongo
This commit is contained in:
parent
08623e9975
commit
2e737359c7
1
src/backend/db/Dockerfile
Normal file
1
src/backend/db/Dockerfile
Normal file
@ -0,0 +1 @@
|
||||
FROM mongo
|
@ -0,0 +1,37 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Todo.Core.Entities;
|
||||
using Todo.Core.Interfaces.Persistence;
|
||||
|
||||
namespace Todo.Api.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/auth")]
|
||||
[Authorize]
|
||||
[AllowAnonymous]
|
||||
public class AuthController : ControllerBase
|
||||
{
|
||||
private readonly IUserRepository _userRepository;
|
||||
|
||||
public AuthController(IUserRepository userRepository)
|
||||
{
|
||||
_userRepository = userRepository;
|
||||
}
|
||||
|
||||
public record RegisterUserRequest
|
||||
{
|
||||
[Required] public string Email { get; init; }
|
||||
[Required] public string Password { get; init; }
|
||||
}
|
||||
|
||||
[HttpPost("register")]
|
||||
public async Task<IActionResult> Register([FromBody] RegisterUserRequest request)
|
||||
{
|
||||
var user = await _userRepository.Register(request.Email, request.Password);
|
||||
|
||||
return Ok(user);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Todo.Core.Interfaces.Persistence;
|
||||
|
||||
namespace Todo.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("/api/todos")]
|
||||
public class TodosController : ControllerBase
|
||||
{
|
||||
private readonly ITodoRepository _todoRepository;
|
||||
|
||||
public TodosController(ITodoRepository todoRepository)
|
||||
{
|
||||
_todoRepository = todoRepository;
|
||||
}
|
||||
|
||||
public record CreateTodoRequest
|
||||
{
|
||||
[Required] public string Title { get; init; }
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<Core.Entities.Todo>> CreateTodo([FromBody] CreateTodoRequest request)
|
||||
{
|
||||
var todo = await _todoRepository.CreateTodoAsync(request.Title);
|
||||
|
||||
return Ok(todo);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<IEnumerable<Core.Entities.Todo>>> GetTodos()
|
||||
{
|
||||
var todos = await _todoRepository.GetTodosAsync();
|
||||
|
||||
return Ok(todos);
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
|
||||
WORKDIR /app
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["Todo.Api/Todo.Api.csproj", "Todo.Api/"]
|
||||
RUN dotnet restore "Todo.Api/Todo.Api.csproj"
|
||||
|
@ -1,13 +1,32 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Todo.Core.Interfaces.Persistence;
|
||||
|
||||
namespace Todo.Api.Hubs
|
||||
{
|
||||
public class TodoHub : Hub
|
||||
{
|
||||
private readonly ITodoRepository _todoRepository;
|
||||
|
||||
public TodoHub(ITodoRepository todoRepository)
|
||||
{
|
||||
_todoRepository = todoRepository;
|
||||
}
|
||||
|
||||
public async Task GetInboxTodos()
|
||||
{
|
||||
await Clients.Caller.SendAsync("InboxTodos", "some data");
|
||||
}
|
||||
|
||||
public async Task CreateTodo(string createTodoRequest)
|
||||
{
|
||||
var todo = JsonSerializer.Deserialize<Core.Entities.Todo>(createTodoRequest);
|
||||
if (todo is null)
|
||||
throw new InvalidOperationException("Failed to create todo because of invalid request");
|
||||
|
||||
await _todoRepository.CreateTodoAsync(todo.Title);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
||||
global using System.Linq;
|
||||
global using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
@ -1,17 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.HttpsPolicy;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Todo.Api.Hubs;
|
||||
using Todo.Persistence;
|
||||
using Todo.Persistence.Mongo;
|
||||
|
||||
namespace Todo.Api
|
||||
{
|
||||
@ -42,12 +37,15 @@ namespace Todo.Api
|
||||
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Todo.Api", Version = "v1" });
|
||||
});
|
||||
|
||||
services.AddPersistence();
|
||||
services.AddSignalR();
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
app.MigrateMongoDb();
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
</PropertyGroup>
|
||||
|
||||
@ -9,4 +9,9 @@
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Todo.Core\Todo.Core.csproj" />
|
||||
<ProjectReference Include="..\Todo.Persistence\Todo.Persistence.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -1,15 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Todo.Api
|
||||
{
|
||||
public class WeatherForecast
|
||||
{
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
public int TemperatureC { get; set; }
|
||||
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
|
||||
public string Summary { get; set; }
|
||||
}
|
||||
}
|
11
src/backend/server/Todo/Todo.Core/DependencyInjection.cs
Normal file
11
src/backend/server/Todo/Todo.Core/DependencyInjection.cs
Normal file
@ -0,0 +1,11 @@
|
||||
global using System;
|
||||
global using System.Linq;
|
||||
global using System.Threading.Tasks;
|
||||
global using System.Collections.Generic;
|
||||
|
||||
namespace Todo.Core;
|
||||
|
||||
public static class DependencyInjection
|
||||
{
|
||||
|
||||
}
|
7
src/backend/server/Todo/Todo.Core/Entities/Todo.cs
Normal file
7
src/backend/server/Todo/Todo.Core/Entities/Todo.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Todo.Core.Entities;
|
||||
|
||||
public record Todo
|
||||
{
|
||||
public string Id { get; init; }
|
||||
public string Title { get; init; }
|
||||
}
|
8
src/backend/server/Todo/Todo.Core/Entities/User.cs
Normal file
8
src/backend/server/Todo/Todo.Core/Entities/User.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace Todo.Core.Entities
|
||||
{
|
||||
public class User
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Email { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
|
||||
namespace Todo.Core.Interfaces.Persistence;
|
||||
|
||||
public interface ITodoRepository
|
||||
{
|
||||
Task<Entities.Todo> CreateTodoAsync(string title);
|
||||
Task<IEnumerable<Entities.Todo>> GetTodosAsync();
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using Todo.Core.Entities;
|
||||
|
||||
namespace Todo.Core.Interfaces.Persistence;
|
||||
|
||||
public interface IUserRepository
|
||||
{
|
||||
Task<User> Register(string email, string password);
|
||||
}
|
7
src/backend/server/Todo/Todo.Core/Todo.Core.csproj
Normal file
7
src/backend/server/Todo/Todo.Core/Todo.Core.csproj
Normal file
@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,16 @@
|
||||
global using System;
|
||||
global using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Todo.Core.Interfaces.Persistence;
|
||||
using Todo.Persistence.Mongo.Repositories;
|
||||
|
||||
namespace Todo.Persistence
|
||||
{
|
||||
public static class DependencyInjection
|
||||
{
|
||||
public static IServiceCollection AddPersistence(this IServiceCollection services) =>
|
||||
services
|
||||
.AddScoped<IUserRepository, UserRepository>()
|
||||
.AddScoped<ITodoRepository, TodoRepository>();
|
||||
}
|
||||
}
|
36
src/backend/server/Todo/Todo.Persistence/Mongo/Migrations.cs
Normal file
36
src/backend/server/Todo/Todo.Persistence/Mongo/Migrations.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using MongoDB.Driver;
|
||||
using Todo.Persistence.Mongo.Repositories.Dtos;
|
||||
|
||||
namespace Todo.Persistence.Mongo
|
||||
{
|
||||
public static class Migrations
|
||||
{
|
||||
public static IApplicationBuilder MigrateMongoDb(this IApplicationBuilder app)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var conn = new MongoClient("mongodb://root:example@localhost:27017");
|
||||
var database = conn.GetDatabase("todo");
|
||||
|
||||
await CreateIndexes(database);
|
||||
}).Wait(10000);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
private static async Task CreateIndexes(IMongoDatabase mongoDatabase)
|
||||
{
|
||||
Console.WriteLine("Running: CreateIndexes");
|
||||
var collection = mongoDatabase.GetCollection<MongoUser>("users");
|
||||
var indexKeysDefinition = Builders<MongoUser>.IndexKeys.Ascending(user => user.Email);
|
||||
var indexModel =
|
||||
new CreateIndexModel<MongoUser>(indexKeysDefinition, new CreateIndexOptions() { Unique = true });
|
||||
|
||||
await collection.Indexes.CreateOneAsync(indexModel);
|
||||
Console.WriteLine("Finished: CreateIndexes");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
|
||||
namespace Todo.Persistence.Mongo.Repositories.Dtos;
|
||||
|
||||
public record MongoTodo
|
||||
{
|
||||
[BsonId]
|
||||
[BsonRepresentation(BsonType.ObjectId)]
|
||||
public string Id { get; init; }
|
||||
|
||||
[BsonRequired] public string Title { get; init; }
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
|
||||
namespace Todo.Persistence.Mongo.Repositories.Dtos
|
||||
{
|
||||
public record MongoUser
|
||||
{
|
||||
[BsonId]
|
||||
[BsonRepresentation(BsonType.ObjectId)]
|
||||
public string Id { get; init; }
|
||||
|
||||
[BsonRequired] public string Email { get; init; }
|
||||
[BsonRequired] public string Password { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Driver;
|
||||
using Todo.Core.Interfaces.Persistence;
|
||||
using Todo.Persistence.Mongo.Repositories.Dtos;
|
||||
|
||||
namespace Todo.Persistence.Mongo.Repositories;
|
||||
|
||||
public class TodoRepository : ITodoRepository
|
||||
{
|
||||
private readonly IMongoCollection<MongoTodo> _todosCollection;
|
||||
|
||||
public TodoRepository()
|
||||
{
|
||||
var conn = new MongoClient("mongodb://root:example@localhost:27017");
|
||||
var database = conn.GetDatabase("todo");
|
||||
|
||||
_todosCollection = database.GetCollection<MongoTodo>("todos");
|
||||
}
|
||||
|
||||
public async Task<Core.Entities.Todo> CreateTodoAsync(string title)
|
||||
{
|
||||
var todo = new MongoTodo() { Title = title };
|
||||
await _todosCollection.InsertOneAsync(todo);
|
||||
return new Core.Entities.Todo() { Id = todo.Id, Title = todo.Title };
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Core.Entities.Todo>> GetTodosAsync()
|
||||
{
|
||||
var todos = await _todosCollection.FindAsync(_ => true);
|
||||
return todos
|
||||
.ToEnumerable()
|
||||
.Select(t =>
|
||||
new Core.Entities.Todo() { Id = t.Id, Title = t.Title });
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Driver;
|
||||
using Todo.Core.Entities;
|
||||
using Todo.Core.Interfaces.Persistence;
|
||||
using Todo.Persistence.Mongo.Repositories.Dtos;
|
||||
|
||||
namespace Todo.Persistence.Mongo.Repositories
|
||||
{
|
||||
public class UserRepository : IUserRepository
|
||||
{
|
||||
private readonly IMongoCollection<MongoUser> _usersCollection;
|
||||
|
||||
public UserRepository()
|
||||
{
|
||||
var conn = new MongoClient("mongodb://root:example@localhost:27017");
|
||||
var database = conn.GetDatabase("todo");
|
||||
|
||||
_usersCollection = database.GetCollection<MongoUser>("users");
|
||||
}
|
||||
|
||||
public async Task<User> Register(string email, string password)
|
||||
{
|
||||
var dtoUser = new MongoUser() { Email = email, Password = password };
|
||||
await _usersCollection.InsertOneAsync(dtoUser);
|
||||
return new User() { Email = dtoUser.Email, Id = dtoUser.Id };
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MongoDB.Driver" Version="2.13.2" />
|
||||
<PackageReference Include="MongoDB.Driver.Core" Version="2.13.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Todo.Core\Todo.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -2,6 +2,10 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Todo.Api", "Todo.Api\Todo.Api.csproj", "{FA037FDE-DAA4-4A95-ABA5-64DCFEDDBA4E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Todo.Persistence", "Todo.Persistence\Todo.Persistence.csproj", "{7636E7CC-C9A5-41D4-BBFE-B107497A5C8A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Todo.Core", "Todo.Core\Todo.Core.csproj", "{F134CAB6-15A5-45CB-8782-B61AB67B5C9C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -12,5 +16,13 @@ Global
|
||||
{FA037FDE-DAA4-4A95-ABA5-64DCFEDDBA4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FA037FDE-DAA4-4A95-ABA5-64DCFEDDBA4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FA037FDE-DAA4-4A95-ABA5-64DCFEDDBA4E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7636E7CC-C9A5-41D4-BBFE-B107497A5C8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7636E7CC-C9A5-41D4-BBFE-B107497A5C8A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7636E7CC-C9A5-41D4-BBFE-B107497A5C8A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7636E7CC-C9A5-41D4-BBFE-B107497A5C8A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F134CAB6-15A5-45CB-8782-B61AB67B5C9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F134CAB6-15A5-45CB-8782-B61AB67B5C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F134CAB6-15A5-45CB-8782-B61AB67B5C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F134CAB6-15A5-45CB-8782-B61AB67B5C9C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
7
src/backend/server/Todo/global.json
Normal file
7
src/backend/server/Todo/global.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "6.0",
|
||||
"rollForward": "latestMajor",
|
||||
"allowPrerelease": true
|
||||
}
|
||||
}
|
9
src/docker-compose.yml
Normal file
9
src/docker-compose.yml
Normal file
@ -0,0 +1,9 @@
|
||||
services:
|
||||
db:
|
||||
build:
|
||||
context: backend/db
|
||||
ports:
|
||||
- 27017:27017
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
MONGO_INITDB_ROOT_PASSWORD: example
|
Loading…
Reference in New Issue
Block a user