diff --git a/src/backend/server/.dockerignore b/src/backend/server/.dockerignore new file mode 100644 index 0000000..753c928 --- /dev/null +++ b/src/backend/server/.dockerignore @@ -0,0 +1,3 @@ +Dockerfile +bin/ +obj/ diff --git a/src/backend/server/Dockerfile b/src/backend/server/Dockerfile index 21d696b..aa3561a 100644 --- a/src/backend/server/Dockerfile +++ b/src/backend/server/Dockerfile @@ -23,5 +23,8 @@ RUN dotnet publish "Todo.Api.csproj" -c Release -o /app/publish FROM base AS final WORKDIR /app + +ENV ASPNETCORE_URLS=http://+:80 + COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "Todo.Api.dll"] diff --git a/src/backend/server/src/Todo.Api/Program.cs b/src/backend/server/src/Todo.Api/Program.cs index 0a1fca6..9e2d293 100644 --- a/src/backend/server/src/Todo.Api/Program.cs +++ b/src/backend/server/src/Todo.Api/Program.cs @@ -11,12 +11,10 @@ namespace Todo.Api { public class Program { - public static void Main(string[] args) - { + public static void Main(string[] args) => CreateHostBuilder(args).Build().Run(); - } - public static IHostBuilder CreateHostBuilder(string[] args) => + private static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); } diff --git a/src/backend/server/src/Todo.Api/Properties/launchSettings.json b/src/backend/server/src/Todo.Api/Properties/launchSettings.json index b89443e..7793e59 100644 --- a/src/backend/server/src/Todo.Api/Properties/launchSettings.json +++ b/src/backend/server/src/Todo.Api/Properties/launchSettings.json @@ -16,7 +16,12 @@ "launchUrl": "swagger", "applicationUrl": "http://localhost:5000", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "Development", + "MONGODB__Username": "root", + "MONGODB__Password": "example", + "MONGODB__Database": "todo", + "MONGODB__Host": "localhost", + "MONGODB__Port": "27017" } } } diff --git a/src/backend/server/src/Todo.Api/Startup.cs b/src/backend/server/src/Todo.Api/Startup.cs index 3c8121b..112cc28 100644 --- a/src/backend/server/src/Todo.Api/Startup.cs +++ b/src/backend/server/src/Todo.Api/Startup.cs @@ -37,7 +37,7 @@ namespace Todo.Api c.SwaggerDoc("v1", new OpenApiInfo { Title = "Todo.Api", Version = "v1" }); }); - services.AddPersistence(); + services.AddPersistence(Configuration); services.AddSignalR(); } diff --git a/src/backend/server/src/Todo.Core/DependencyInjection.cs b/src/backend/server/src/Todo.Core/DependencyInjection.cs index 3187069..b1925cd 100644 --- a/src/backend/server/src/Todo.Core/DependencyInjection.cs +++ b/src/backend/server/src/Todo.Core/DependencyInjection.cs @@ -7,5 +7,4 @@ namespace Todo.Core; public static class DependencyInjection { - } \ No newline at end of file diff --git a/src/backend/server/src/Todo.Persistence/DependencyInjection.cs b/src/backend/server/src/Todo.Persistence/DependencyInjection.cs index c17caa1..154cdbf 100644 --- a/src/backend/server/src/Todo.Persistence/DependencyInjection.cs +++ b/src/backend/server/src/Todo.Persistence/DependencyInjection.cs @@ -2,17 +2,31 @@ global using System; global using System.Threading.Tasks; global using System.Linq; global using System.Collections.Generic; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Todo.Core.Interfaces.Persistence; +using Todo.Persistence.Mongo; using Todo.Persistence.Mongo.Repositories; namespace Todo.Persistence { public static class DependencyInjection { - public static IServiceCollection AddPersistence(this IServiceCollection services) => + public static IServiceCollection AddPersistence(this IServiceCollection services, IConfiguration configuration) + { + + var options = configuration.GetRequiredSection("MONGODB"); + Console.WriteLine(options.Value); + services + .AddOptions() + .Bind(options) + .ValidateDataAnnotations(); + + return services + .AddSingleton() .AddScoped() .AddScoped(); + } } } \ No newline at end of file diff --git a/src/backend/server/src/Todo.Persistence/Mongo/Migrations.cs b/src/backend/server/src/Todo.Persistence/Mongo/Migrations.cs index c89ad32..d0cf070 100644 --- a/src/backend/server/src/Todo.Persistence/Mongo/Migrations.cs +++ b/src/backend/server/src/Todo.Persistence/Mongo/Migrations.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; using MongoDB.Driver; using Todo.Persistence.Mongo.Repositories.Dtos; @@ -10,8 +11,8 @@ namespace Todo.Persistence.Mongo { Task.Run(async () => { - var conn = new MongoClient("mongodb://root:example@localhost:27017"); - var database = conn.GetDatabase("todo"); + var connectionHandler = app.ApplicationServices.GetRequiredService(); + var database = connectionHandler.CreateDatabaseConnection(); await CreateIndexes(database); }).Wait(10000); diff --git a/src/backend/server/src/Todo.Persistence/Mongo/MongoDbConnectionHandler.cs b/src/backend/server/src/Todo.Persistence/Mongo/MongoDbConnectionHandler.cs new file mode 100644 index 0000000..1f39b12 --- /dev/null +++ b/src/backend/server/src/Todo.Persistence/Mongo/MongoDbConnectionHandler.cs @@ -0,0 +1,30 @@ +using Microsoft.Extensions.Options; +using MongoDB.Driver; + +namespace Todo.Persistence.Mongo; + +public class MongoDbConnectionHandler +{ + private readonly IOptionsMonitor _optionsMonitor; + + public MongoDbConnectionHandler(IOptionsMonitor optionsMonitor) + { + _optionsMonitor = optionsMonitor; + } + + public IMongoDatabase CreateDatabaseConnection() + { + var options = _optionsMonitor.CurrentValue; + + return CreateConnectionFromOptions(options); + } + + private static IMongoDatabase CreateConnectionFromOptions(MongoDbOptions options) + { + var conn = new MongoClient( + $"mongodb://{options.Username}:{options.Password}@{options.Host}:{options.Port}"); + var database = conn.GetDatabase(options.Database); + + return database; + } +} \ No newline at end of file diff --git a/src/backend/server/src/Todo.Persistence/Mongo/MongoDbOptions.cs b/src/backend/server/src/Todo.Persistence/Mongo/MongoDbOptions.cs new file mode 100644 index 0000000..ea6ce42 --- /dev/null +++ b/src/backend/server/src/Todo.Persistence/Mongo/MongoDbOptions.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace Todo.Persistence.Mongo; + +public class MongoDbOptions +{ + public const string MongoDb = "MongoDb"; + + [Required] public string Username { get; set; } + [Required] public string Password { get; set; } + [Required] public string Host { get; set; } + [Required] public string Port { get; set; } + [Required] public string Database { get; set; } +} \ No newline at end of file diff --git a/src/backend/server/src/Todo.Persistence/Mongo/Repositories/TodoRepository.cs b/src/backend/server/src/Todo.Persistence/Mongo/Repositories/TodoRepository.cs index daaba12..b475b39 100644 --- a/src/backend/server/src/Todo.Persistence/Mongo/Repositories/TodoRepository.cs +++ b/src/backend/server/src/Todo.Persistence/Mongo/Repositories/TodoRepository.cs @@ -8,10 +8,9 @@ public class TodoRepository : ITodoRepository { private readonly IMongoCollection _todosCollection; - public TodoRepository() + public TodoRepository(MongoDbConnectionHandler mongoDbConnectionHandler) { - var conn = new MongoClient("mongodb://root:example@localhost:27017"); - var database = conn.GetDatabase("todo"); + var database = mongoDbConnectionHandler.CreateDatabaseConnection(); _todosCollection = database.GetCollection("todos"); } diff --git a/src/backend/server/src/Todo.Persistence/Mongo/Repositories/UserRepository.cs b/src/backend/server/src/Todo.Persistence/Mongo/Repositories/UserRepository.cs index 472efff..23ca4bd 100644 --- a/src/backend/server/src/Todo.Persistence/Mongo/Repositories/UserRepository.cs +++ b/src/backend/server/src/Todo.Persistence/Mongo/Repositories/UserRepository.cs @@ -9,11 +9,9 @@ namespace Todo.Persistence.Mongo.Repositories { private readonly IMongoCollection _usersCollection; - public UserRepository() + public UserRepository(MongoDbConnectionHandler mongoDbConnectionHandler) { - var conn = new MongoClient("mongodb://root:example@localhost:27017"); - var database = conn.GetDatabase("todo"); - + var database = mongoDbConnectionHandler.CreateDatabaseConnection(); _usersCollection = database.GetCollection("users"); } diff --git a/src/client/.dockerignore b/src/client/.dockerignore new file mode 100644 index 0000000..4327ebe --- /dev/null +++ b/src/client/.dockerignore @@ -0,0 +1,6 @@ +Dockerfile +.dockerignore +node_modules +npm-debug.log +README.md +.next diff --git a/src/client/Dockerfile b/src/client/Dockerfile new file mode 100644 index 0000000..60a1205 --- /dev/null +++ b/src/client/Dockerfile @@ -0,0 +1,43 @@ +# Install dependencies only when needed +FROM node:14-alpine AS deps +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +RUN apk add --no-cache libc6-compat +WORKDIR /app +COPY package.json yarn.lock ./ +RUN yarn install --frozen-lockfile + +# Rebuild the source code only when needed +FROM node:14-alpine AS builder +WORKDIR /app +COPY . . +COPY --from=deps /app/node_modules ./node_modules +RUN yarn build + +# Production image, copy all the files and run next +FROM node:14-alpine AS runner +WORKDIR /app + +ENV NODE_ENV production + +RUN addgroup -g 1001 -S nodejs +RUN adduser -S nextjs -u 1001 + +# You only need to copy next.config.js if you are NOT using the default configuration +# COPY --from=builder /app/next.config.js ./ +COPY --from=builder /app/src/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/package.json ./package.json + +USER nextjs + +EXPOSE 3000 + +ENV PORT 3000 + +# Next.js collects completely anonymous telemetry data about general usage. +# Learn more here: https://nextjs.org/telemetry +# Uncomment the following line in case you want to disable telemetry. +# ENV NEXT_TELEMETRY_DISABLED 1 + +CMD ["node_modules/.bin/next", "start"] diff --git a/src/client/src/core/actions/todos.ts b/src/client/src/core/actions/todos.ts deleted file mode 100644 index ee6050e..0000000 --- a/src/client/src/core/actions/todos.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { StatusState, Todo } from "@src/core/entities/todo"; - -export const createTodo = (name: string): Todo => ({ - name, - status: StatusState.notDone, -}); - -const createDoneTodo = (name: string) => ({ - ...createTodo(name), - status: true, -}); - -const todos: Todo[] = [ - createTodo("go to dentist"), - createTodo("Check e-Boks"), - createDoneTodo("Check and clean mail"), -]; -export const getInboxTodos = () => todos; diff --git a/src/docker-compose.yml b/src/docker-compose.yml index bff3237..573ca06 100644 --- a/src/docker-compose.yml +++ b/src/docker-compose.yml @@ -1,3 +1,5 @@ +version: "3" + services: db: build: @@ -7,3 +9,23 @@ services: environment: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: example + + server: + build: + context: backend/server + ports: + - 5000:80 + environment: + MONGODB__Username: root + MONGODB__Password: example + MONGODB__Host: db + MONGODB__Port: 27017 + MONGODB__Database: todo + depends_on: + - db + + client: + build: + context: client + ports: + - 3000:3000