From 31530be61a7f9921a5be03e3295dfd80f8d13a30 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Fri, 3 May 2024 20:43:35 +0200 Subject: [PATCH 01/62] (#92) add project structure --- MiniSpace.Services.MediaFiles/Dockerfile | 17 +++++++ MiniSpace.Services.MediaFiles/LICENSE | 21 ++++++++ .../MiniSpace.Services.MediaFiles.sln | 48 +++++++++++++++++++ .../scripts/build.sh | 2 + .../scripts/dockerize-tag-push.sh | 11 +++++ .../scripts/dockerize.sh | 21 ++++++++ .../scripts/start.sh | 4 ++ MiniSpace.Services.MediaFiles/scripts/test.sh | 2 + .../MiniSpace.Services.MediaFiles.Api.csproj | 21 ++++++++ .../Program.cs | 44 +++++++++++++++++ .../Properties/launchSettings.json | 41 ++++++++++++++++ .../appsettings.Development.json | 8 ++++ .../appsettings.json | 9 ++++ ...ace.Services.MediaFiles.Application.csproj | 21 ++++++++ .../MiniSpace.Services.MediaFiles.Core.csproj | 9 ++++ ....Services.MediaFiles.Infrastructure.csproj | 39 +++++++++++++++ 16 files changed, 318 insertions(+) create mode 100644 MiniSpace.Services.MediaFiles/Dockerfile create mode 100644 MiniSpace.Services.MediaFiles/LICENSE create mode 100644 MiniSpace.Services.MediaFiles/MiniSpace.Services.MediaFiles.sln create mode 100644 MiniSpace.Services.MediaFiles/scripts/build.sh create mode 100644 MiniSpace.Services.MediaFiles/scripts/dockerize-tag-push.sh create mode 100644 MiniSpace.Services.MediaFiles/scripts/dockerize.sh create mode 100644 MiniSpace.Services.MediaFiles/scripts/start.sh create mode 100644 MiniSpace.Services.MediaFiles/scripts/test.sh create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/MiniSpace.Services.MediaFiles.Api.csproj create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Properties/launchSettings.json create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.Development.json create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.json create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/MiniSpace.Services.MediaFiles.Core.csproj create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/MiniSpace.Services.MediaFiles.Infrastructure.csproj diff --git a/MiniSpace.Services.MediaFiles/Dockerfile b/MiniSpace.Services.MediaFiles/Dockerfile new file mode 100644 index 000000000..17d4594fb --- /dev/null +++ b/MiniSpace.Services.MediaFiles/Dockerfile @@ -0,0 +1,17 @@ +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /app + +COPY . . + +RUN dotnet publish src/MiniSpace.Services.MediaFiles.Api -c Release -o out + +FROM mcr.microsoft.com/dotnet/aspnet:8.0 +WORKDIR /app + +COPY --from=build /app/out . + +ENV ASPNETCORE_URLS=http://*:80 +ENV ASPNETCORE_ENVIRONMENT=docker +ENV NTRADA_CONFIG=ntrada.docker + +ENTRYPOINT ["dotnet", "MiniSpace.Services.MediaFiles.Api.dll"] diff --git a/MiniSpace.Services.MediaFiles/LICENSE b/MiniSpace.Services.MediaFiles/LICENSE new file mode 100644 index 000000000..b7ea7f0cc --- /dev/null +++ b/MiniSpace.Services.MediaFiles/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 DevMentors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/MiniSpace.Services.MediaFiles/MiniSpace.Services.MediaFiles.sln b/MiniSpace.Services.MediaFiles/MiniSpace.Services.MediaFiles.sln new file mode 100644 index 000000000..c008a6e7e --- /dev/null +++ b/MiniSpace.Services.MediaFiles/MiniSpace.Services.MediaFiles.sln @@ -0,0 +1,48 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{19970311-BECA-46BA-9763-C8CE5FBEC34C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiniSpace.Services.MediaFiles.Api", "src\MiniSpace.Services.MediaFiles.Api\MiniSpace.Services.MediaFiles.Api.csproj", "{E3332633-A8EA-47DD-95BE-2E4AF82A25A1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiniSpace.Services.MediaFiles.Application", "src\MiniSpace.Services.MediaFiles.Application\MiniSpace.Services.MediaFiles.Application.csproj", "{85A84271-21EA-4E82-8023-115BA562BF22}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiniSpace.Services.MediaFiles.Core", "src\MiniSpace.Services.MediaFiles.Core\MiniSpace.Services.MediaFiles.Core.csproj", "{DEED64BD-467A-4880-B078-C4E9FF257CB3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiniSpace.Services.MediaFiles.Infrastructure", "src\MiniSpace.Services.MediaFiles.Infrastructure\MiniSpace.Services.MediaFiles.Infrastructure.csproj", "{D8F4492A-C273-48FE-9611-1AC8E016944B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E3332633-A8EA-47DD-95BE-2E4AF82A25A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E3332633-A8EA-47DD-95BE-2E4AF82A25A1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E3332633-A8EA-47DD-95BE-2E4AF82A25A1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E3332633-A8EA-47DD-95BE-2E4AF82A25A1}.Release|Any CPU.Build.0 = Release|Any CPU + {85A84271-21EA-4E82-8023-115BA562BF22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {85A84271-21EA-4E82-8023-115BA562BF22}.Debug|Any CPU.Build.0 = Debug|Any CPU + {85A84271-21EA-4E82-8023-115BA562BF22}.Release|Any CPU.ActiveCfg = Release|Any CPU + {85A84271-21EA-4E82-8023-115BA562BF22}.Release|Any CPU.Build.0 = Release|Any CPU + {DEED64BD-467A-4880-B078-C4E9FF257CB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DEED64BD-467A-4880-B078-C4E9FF257CB3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DEED64BD-467A-4880-B078-C4E9FF257CB3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DEED64BD-467A-4880-B078-C4E9FF257CB3}.Release|Any CPU.Build.0 = Release|Any CPU + {D8F4492A-C273-48FE-9611-1AC8E016944B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D8F4492A-C273-48FE-9611-1AC8E016944B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D8F4492A-C273-48FE-9611-1AC8E016944B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D8F4492A-C273-48FE-9611-1AC8E016944B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {E3332633-A8EA-47DD-95BE-2E4AF82A25A1} = {19970311-BECA-46BA-9763-C8CE5FBEC34C} + {85A84271-21EA-4E82-8023-115BA562BF22} = {19970311-BECA-46BA-9763-C8CE5FBEC34C} + {DEED64BD-467A-4880-B078-C4E9FF257CB3} = {19970311-BECA-46BA-9763-C8CE5FBEC34C} + {D8F4492A-C273-48FE-9611-1AC8E016944B} = {19970311-BECA-46BA-9763-C8CE5FBEC34C} + EndGlobalSection +EndGlobal diff --git a/MiniSpace.Services.MediaFiles/scripts/build.sh b/MiniSpace.Services.MediaFiles/scripts/build.sh new file mode 100644 index 000000000..3affad0eb --- /dev/null +++ b/MiniSpace.Services.MediaFiles/scripts/build.sh @@ -0,0 +1,2 @@ +#!/bin/bash +dotnet build -c release \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/scripts/dockerize-tag-push.sh b/MiniSpace.Services.MediaFiles/scripts/dockerize-tag-push.sh new file mode 100644 index 000000000..456d4e3c7 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/scripts/dockerize-tag-push.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +export ASPNETCORE_ENVIRONMENT=docker + +cd .. + +docker build -t minispace.services.mediafiles:latest . + +docker tag minispace.services.mediafiles:latest adrianvsaint/minispace.services.mediafiles:latest + +docker push adrianvsaint/minispace.services.mediafiles:latest diff --git a/MiniSpace.Services.MediaFiles/scripts/dockerize.sh b/MiniSpace.Services.MediaFiles/scripts/dockerize.sh new file mode 100644 index 000000000..cfae96799 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/scripts/dockerize.sh @@ -0,0 +1,21 @@ +#!/bin/bash +TAG='' +VERSION_TAG= + +case "$TRAVIS_BRANCH" in + "master") + TAG=latest + VERSION_TAG=$TRAVIS_BUILD_NUMBER + ;; + "develop") + TAG=dev + VERSION_TAG=$TAG-$TRAVIS_BUILD_NUMBER + ;; +esac + +REPOSITORY=$DOCKER_USERNAME/minispace.services.mediafiles + +docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD +docker build -t $REPOSITORY:$TAG -t $REPOSITORY:$VERSION_TAG . +docker push $REPOSITORY:$TAG +docker push $REPOSITORY:$VERSION_TAG \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/scripts/start.sh b/MiniSpace.Services.MediaFiles/scripts/start.sh new file mode 100644 index 000000000..ba33d0a20 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/scripts/start.sh @@ -0,0 +1,4 @@ +#!/bin/bash +export ASPNETCORE_ENVIRONMENT=local +cd src/MiniSpace.Services.MediaFiles.Api +dotnet run diff --git a/MiniSpace.Services.MediaFiles/scripts/test.sh b/MiniSpace.Services.MediaFiles/scripts/test.sh new file mode 100644 index 000000000..6046c35a0 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/scripts/test.sh @@ -0,0 +1,2 @@ +#!/bin/bash +dotnet test \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/MiniSpace.Services.MediaFiles.Api.csproj b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/MiniSpace.Services.MediaFiles.Api.csproj new file mode 100644 index 000000000..667a9e009 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/MiniSpace.Services.MediaFiles.Api.csproj @@ -0,0 +1,21 @@ + + + + net8.0 + disable + enable + true + + + + + + + + + + + + + + diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs new file mode 100644 index 000000000..00ff53936 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs @@ -0,0 +1,44 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +var summaries = new[] +{ + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" +}; + +app.MapGet("/weatherforecast", () => +{ + var forecast = Enumerable.Range(1, 5).Select(index => + new WeatherForecast + ( + DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + Random.Shared.Next(-20, 55), + summaries[Random.Shared.Next(summaries.Length)] + )) + .ToArray(); + return forecast; +}) +.WithName("GetWeatherForecast") +.WithOpenApi(); + +app.Run(); + +record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) +{ + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Properties/launchSettings.json b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Properties/launchSettings.json new file mode 100644 index 000000000..47ef0eb17 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:38277", + "sslPort": 44336 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5276", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7256;http://localhost:5276", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.Development.json b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.Development.json new file mode 100644 index 000000000..0c208ae91 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.json b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.json new file mode 100644 index 000000000..10f68b8c8 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj new file mode 100644 index 000000000..fdf5b09ed --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj @@ -0,0 +1,21 @@ + + + + net8.0 + enable + disable + + + + + + + + + + + + + + + diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/MiniSpace.Services.MediaFiles.Core.csproj b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/MiniSpace.Services.MediaFiles.Core.csproj new file mode 100644 index 000000000..cf309aa85 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/MiniSpace.Services.MediaFiles.Core.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + disable + + + diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/MiniSpace.Services.MediaFiles.Infrastructure.csproj b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/MiniSpace.Services.MediaFiles.Infrastructure.csproj new file mode 100644 index 000000000..f86302bcf --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/MiniSpace.Services.MediaFiles.Infrastructure.csproj @@ -0,0 +1,39 @@ + + + + net8.0 + enable + disable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 52d84f46ea95765dd45d835feeb941f5ef16fe08 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Fri, 3 May 2024 20:49:30 +0200 Subject: [PATCH 02/62] (#92) update appsettings.json --- .../Properties/launchSettings.json | 35 +--- .../appsettings.Development.json | 8 +- .../appsettings.docker.json | 153 ++++++++++++++ .../appsettings.local.json | 195 ++++++++++++++++++ 4 files changed, 359 insertions(+), 32 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.docker.json create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.local.json diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Properties/launchSettings.json b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Properties/launchSettings.json index 47ef0eb17..3387cd0a6 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Properties/launchSettings.json +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Properties/launchSettings.json @@ -1,41 +1,26 @@ { - "$schema": "http://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { - "applicationUrl": "http://localhost:38277", - "sslPort": 44336 + "applicationUrl": "http://localhost:5014" } }, "profiles": { - "http": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "launchUrl": "swagger", - "applicationUrl": "http://localhost:5276", + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": false, "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "local" } }, - "https": { + "MiniSpace.Services.Events": { "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "launchUrl": "swagger", - "applicationUrl": "https://localhost:7256;http://localhost:5276", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "launchUrl": "swagger", + "launchBrowser": false, + "applicationUrl": "http://localhost:5014", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "local" } } } -} +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.Development.json b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.Development.json index 0c208ae91..7a73a41bf 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.Development.json +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.Development.json @@ -1,8 +1,2 @@ { - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - } -} +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.docker.json b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.docker.json new file mode 100644 index 000000000..5d8e69926 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.docker.json @@ -0,0 +1,153 @@ +{ + "app": { + "name": "MiniSpace Media Files Service", + "version": "1" + }, + "consul": { + "enabled": true, + "url": "http://consul:8500", + "service": "mediafiles-service", + "address": "mediafiles-service", + "port": "80", + "pingEnabled": true, + "pingEndpoint": "ping", + "pingInterval": 3, + "removeAfterInterval": 3 + }, + "fabio": { + "enabled": true, + "url": "http://fabio:9999", + "service": "mediafiles-service" + }, + "httpClient": { + "type": "fabio", + "retries": 3, + "services": {} + }, + "jwt": { + "certificate": { + "location": "", + "password": "", + "rawData": "" + }, + "issuerSigningKey": "eiquief5phee9pazo0Faegaez9gohThailiur5woy2befiech1oarai4aiLi6ahVecah3ie9Aiz6Peij", + "expiryMinutes": 60, + "issuer": "minispace", + "validateAudience": false, + "validateIssuer": false, + "validateLifetime": true, + "allowAnonymousEndpoints": ["/sign-in", "/sign-up"] + }, + "logger": { + "console": { + "enabled": true + }, + "elk": { + "enabled": false, + "url": "http://elk:9200" + }, + "file": { + "enabled": false, + "path": "logs/logs.txt", + "interval": "day" + }, + "seq": { + "enabled": true, + "url": "http://seq:5341", + "apiKey": "secret" + } + }, + "jaeger": { + "enabled": true, + "serviceName": "events", + "udpHost": "jaeger", + "udpPort": 6831, + "maxPacketSize": 0, + "sampler": "const", + "excludePaths": ["/", "/ping", "/metrics"] + }, + "metrics": { + "enabled": true, + "influxEnabled": false, + "prometheusEnabled": true, + "influxUrl": "http://influx:8086", + "database": "minispace", + "env": "docker", + "interval": 5 + }, + "mongo": { + "connectionString": "mongodb+srv://minispace-user:9vd6IxYWUuuqhzEH@cluster0.mmhq4pe.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0", + "database": "mediafiles-service", + "seed": false + }, + "rabbitMq": { + "connectionName": "mediafiles-service", + "retries": 3, + "retryInterval": 2, + "conventionsCasing": "snakeCase", + "logger": { + "enabled": true + }, + "username": "guest", + "password": "guest", + "virtualHost": "/", + "port": 5672, + "hostnames": [ + "rabbitmq" + ], + "requestedConnectionTimeout": "00:00:30", + "requestedHeartbeat": "00:01:00", + "socketReadTimeout": "00:00:30", + "socketWriteTimeout": "00:00:30", + "continuationTimeout": "00:00:20", + "handshakeContinuationTimeout": "00:00:10", + "networkRecoveryInterval": "00:00:05", + "exchange": { + "declare": true, + "durable": true, + "autoDelete": false, + "type": "topic", + "name": "events" + }, + "queue": { + "declare": true, + "durable": true, + "exclusive": false, + "autoDelete": false, + "template": "mediafiles-service/{{exchange}}.{{message}}" + }, + "context": { + "enabled": true, + "header": "message_context" + }, + "spanContextHeader": "span_context" + }, + "redis": { + "connectionString": "redis", + "instance": "mediafiles:" + }, + "swagger": { + "enabled": true, + "reDocEnabled": false, + "name": "v1", + "title": "API", + "version": "v1", + "routePrefix": "docs", + "includeSecurity": true + }, + "vault": { + "enabled": false, + "url": "http://vault:8200", + "kv": { + "enabled": false + }, + "pki": { + "enabled": false + }, + "lease": { + "mongo": { + "enabled": false + } + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.local.json b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.local.json new file mode 100644 index 000000000..5647c8fd6 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/appsettings.local.json @@ -0,0 +1,195 @@ +{ + "app": { + "name": "MiniSpace Media Files Service", + "service": "mediafiles-service", + "version": "1" + }, + "consul": { + "enabled": true, + "url": "http://localhost:8500", + "service": "mediafiles-service", + "address": "docker.for.win.localhost", + "port": "5014", + "pingEnabled": false, + "pingEndpoint": "ping", + "pingInterval": 3, + "removeAfterInterval": 3 + }, + "fabio": { + "enabled": true, + "url": "http://localhost:9999", + "service": "mediafiles-service" + }, + "httpClient": { + "type": "direct", + "retries": 3, + "services": { + }, + "requestMasking": { + "enabled": true, + "maskTemplate": "*****" + } + }, + "jwt": { + "issuerSigningKey": "eiquief5phee9pazo0Faegaez9gohThailiur5woy2befiech1oarai4aiLi6ahVecah3ie9Aiz6Peij", + "expiryMinutes": 60, + "issuer": "minispace", + "validateAudience": false, + "validateIssuer": false, + "validateLifetime": false, + "allowAnonymousEndpoints": ["/sign-in", "/sign-up"] + }, + "logger": { + "level": "information", + "excludePaths": ["/", "/ping", "/metrics"], + "excludeProperties": [ + "api_key", + "access_key", + "ApiKey", + "ApiSecret", + "ClientId", + "ClientSecret", + "ConnectionString", + "Password", + "Email", + "Login", + "Secret", + "Token" + ], + "console": { + "enabled": true + }, + "elk": { + "enabled": false, + "url": "http://localhost:9200" + }, + "file": { + "enabled": true, + "path": "logs/logs.txt", + "interval": "day" + }, + "seq": { + "enabled": true, + "url": "http://localhost:5341", + "apiKey": "secret" + }, + "tags": {} + }, + "jaeger": { + "enabled": true, + "serviceName": "mediafiles", + "udpHost": "localhost", + "udpPort": 6831, + "maxPacketSize": 0, + "sampler": "const", + "excludePaths": ["/", "/ping", "/metrics"] + }, + "metrics": { + "enabled": true, + "influxEnabled": false, + "prometheusEnabled": true, + "influxUrl": "http://localhost:8086", + "database": "minispace", + "env": "local", + "interval": 5 + }, + "mongo": { + "connectionString": "mongodb+srv://minispace-user:9vd6IxYWUuuqhzEH@cluster0.mmhq4pe.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0", + "database": "mediafiles-service", + "seed": false + }, + "outbox": { + "enabled": false, + "type": "sequential", + "expiry": 3600, + "intervalMilliseconds": 2000, + "inboxCollection": "inbox", + "outboxCollection": "outbox", + "disableTransactions": true + }, + "rabbitMq": { + "connectionName": "mediafiles-service", + "retries": 3, + "retryInterval": 2, + "conventionsCasing": "snakeCase", + "logger": { + "enabled": true + }, + "username": "guest", + "password": "guest", + "virtualHost": "/", + "port": 5672, + "hostnames": [ + "localhost" + ], + "requestedConnectionTimeout": "00:00:30", + "requestedHeartbeat": "00:01:00", + "socketReadTimeout": "00:00:30", + "socketWriteTimeout": "00:00:30", + "continuationTimeout": "00:00:20", + "handshakeContinuationTimeout": "00:00:10", + "networkRecoveryInterval": "00:00:05", + "exchange": { + "declare": true, + "durable": true, + "autoDelete": false, + "type": "topic", + "name": "mediafiles" + }, + "queue": { + "declare": true, + "durable": true, + "exclusive": false, + "autoDelete": false, + "template": "mediafiles-service/{{exchange}}.{{message}}" + }, + "context": { + "enabled": true, + "header": "message_context" + }, + "spanContextHeader": "span_context" + }, + "redis": { + "connectionString": "localhost", + "instance": "mediafiles:" + }, + "swagger": { + "enabled": true, + "reDocEnabled": false, + "name": "v1", + "title": "API", + "version": "v1", + "routePrefix": "docs", + "includeSecurity": true + }, + "vault": { + "enabled": true, + "url": "http://localhost:8200", + "authType": "token", + "token": "secret", + "username": "user", + "password": "secret", + "kv": { + "enabled": true, + "engineVersion": 2, + "mountPoint": "kv", + "path": "mediafiles-service/settings" + }, + "pki": { + "enabled": true, + "roleName": "mediafiles-service", + "commonName": "mediafiles-service.minispace.io" + }, + "lease": { + "mongo": { + "type": "database", + "roleName": "mediafiles-service", + "enabled": true, + "autoRenewal": true, + "templates": { + "connectionString": "mongodb://{{username}}:{{password}}@localhost:27017" + } + } + } + } +} From 746c3385249a8c8e1b05ed648ac8319bbb5166d5 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Fri, 3 May 2024 20:54:01 +0200 Subject: [PATCH 03/62] (#92) add folder structure --- .../Program.cs | 87 ++++----- .../Commands/ChangeStudentState.cs | 16 ++ .../Commands/CompleteStudentRegistration.cs | 23 +++ .../Commands/DeleteStudent.cs | 11 ++ .../Handlers/ChangeStudentStateHandler.cs | 63 +++++++ .../CompleteStudentRegistrationHandler.cs | 46 +++++ .../Commands/Handlers/DeleteStudentHandler.cs | 42 +++++ .../Commands/Handlers/UpdateStudentHandler.cs | 45 +++++ .../Commands/UpdateStudent.cs | 20 ++ .../ContractAttribute.cs | 7 + .../Dto/StudentDto.cs | 21 +++ .../Dto/StudentEventsDto.cs | 9 + .../Handlers/OrganizerRightsGrantedHandler.cs | 37 ++++ .../Handlers/OrganizerRightsRevokedHandler.cs | 37 ++++ .../External/Handlers/SignedUpHandler.cs | 43 +++++ .../StudentShowedInterestInEventHandler.cs | 37 ++++ .../Handlers/StudentSignedUpToEventHandler.cs | 37 ++++ .../External/Handlers/UserBannedHandler.cs | 37 ++++ .../External/Handlers/UserUnbannedHandler.cs | 37 ++++ .../Events/External/OrganizerRightsGranted.cs | 15 ++ .../Events/External/OrganizerRightsRevoked.cs | 15 ++ .../Events/External/SignedUp.cs | 24 +++ .../External/StudentShowedInterestInEvent.cs | 18 ++ .../Events/External/StudentSignedUpToEvent.cs | 18 ++ .../Events/External/UserBanned.cs | 11 ++ .../Events/External/UserUnbanned.cs | 11 ++ .../Rejected/ChangeStudentStateRejected.cs | 20 ++ .../CompleteStudentRegistrationRejected.cs | 19 ++ .../Events/Rejected/CreateStudentRejected.cs | 18 ++ .../Events/Rejected/DeleteStudentRejected.cs | 18 ++ .../Events/Rejected/UpdateStudentRejected.cs | 18 ++ .../Events/StudentCreated.cs | 16 ++ .../Events/StudentDeleted.cs | 16 ++ .../Events/StudentStateChanged.cs | 20 ++ .../Events/StudentUpdated.cs | 16 ++ .../Exceptions/AppException.cs | 11 ++ .../Exceptions/InvalidRoleException.cs | 13 ++ .../StudentAlreadyCreatedException.cs | 14 ++ .../StudentAlreadyRegisteredException.cs | 14 ++ .../Exceptions/StudentNotFoundException.cs | 13 ++ .../UnauthorizedStudentAccessException.cs | 16 ++ .../Extensions.cs | 16 ++ .../IAppContext.cs | 8 + .../IIdentityContext.cs | 15 ++ ...ace.Services.MediaFiles.Application.csproj | 2 +- .../Queries/GetStudent.cs | 10 + .../Queries/GetStudentEvents.cs | 10 + .../Queries/GetStudents.cs | 9 + .../Services/IDateTimeProvider.cs | 7 + .../Services/IEventMapper.cs | 11 ++ .../Services/IMessageBroker.cs | 10 + .../Entities/AggregateId.cs | 50 +++++ .../Entities/AggregateRoot.cs | 19 ++ .../Entities/State.cs | 10 + .../Entities/Student.cs | 171 ++++++++++++++++++ .../Events/IDomainEvent.cs | 7 + .../Events/StudentRegistrationCompleted.cs | 14 ++ .../Events/StudentStateChanged.cs | 16 ++ .../Events/StudentUpdated.cs | 14 ++ .../CannotChangeStudentStateException.cs | 18 ++ .../CannotUpdateStudentException.cs | 16 ++ .../Exceptions/DomainException.cs | 11 ++ .../Exceptions/InvalidAggregateIdException.cs | 11 ++ .../InvalidStudentDateOfBirthException.cs | 19 ++ .../InvalidStudentDescriptionException.cs | 16 ++ .../InvalidStudentFullNameException.cs | 16 ++ .../InvalidStudentProfileImageException.cs | 16 ++ .../StudentStateAlreadySetException.cs | 18 ++ .../Repositories/IStudentRepository.cs | 12 ++ .../Contexts/AppContext.cs | 27 +++ .../Contexts/AppContextFactory.cs | 35 ++++ .../Contexts/CorrelationContext.cs | 22 +++ .../Contexts/IdentityContext.cs | 41 +++++ .../OutboxCommandHandlerDecorator.cs | 35 ++++ .../Decorators/OutboxEventHandlerDecorator.cs | 35 ++++ .../Exceptions/ExceptionToMessageMapper.cs | 93 ++++++++++ .../Exceptions/ExceptionToResponseMapper.cs | 46 +++++ .../Extensions.cs | 140 ++++++++++++++ .../IAppContextFactory.cs | 9 + .../Logging/Extensions.cs | 21 +++ .../Logging/MessageToLogTemplateMapper.cs | 86 +++++++++ ....Services.MediaFiles.Infrastructure.csproj | 2 +- .../Mongo/Documents/Extensions.cs | 55 ++++++ .../Mongo/Documents/StudentDocument.cs | 24 +++ .../Handlers/GetStudentEventsHandler.cs | 36 ++++ .../Queries/Handlers/GetStudentHandler.cs | 25 +++ .../Queries/Handlers/GetStudentsHandler.cs | 25 +++ .../Repositories/StudentMongoRepository.cs | 33 ++++ .../Services/DateTimeProvider.cs | 9 + .../Services/EventMapper.cs | 29 +++ .../Services/MessageBroker.cs | 84 +++++++++ 91 files changed, 2429 insertions(+), 44 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/ChangeStudentState.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/CompleteStudentRegistration.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/DeleteStudent.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/ChangeStudentStateHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CompleteStudentRegistrationHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteStudentHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UpdateStudentHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UpdateStudent.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/ContractAttribute.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentDto.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentEventsDto.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsGrantedHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsRevokedHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/SignedUpHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentShowedInterestInEventHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentSignedUpToEventHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserBannedHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserUnbannedHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsGranted.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsRevoked.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/SignedUp.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentShowedInterestInEvent.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentSignedUpToEvent.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserBanned.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserUnbanned.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/ChangeStudentStateRejected.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CompleteStudentRegistrationRejected.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CreateStudentRejected.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/DeleteStudentRejected.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/UpdateStudentRejected.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentCreated.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentDeleted.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentStateChanged.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentUpdated.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/AppException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidRoleException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyCreatedException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyRegisteredException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentNotFoundException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedStudentAccessException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Extensions.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/IAppContext.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/IIdentityContext.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudent.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudentEvents.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudents.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IDateTimeProvider.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IEventMapper.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IMessageBroker.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/AggregateId.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/AggregateRoot.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/State.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/Student.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/IDomainEvent.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentRegistrationCompleted.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentStateChanged.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentUpdated.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotChangeStudentStateException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotUpdateStudentException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/DomainException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidAggregateIdException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDateOfBirthException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDescriptionException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentFullNameException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentProfileImageException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/StudentStateAlreadySetException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IStudentRepository.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/AppContext.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/AppContextFactory.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/CorrelationContext.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/IdentityContext.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Decorators/OutboxCommandHandlerDecorator.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Decorators/OutboxEventHandlerDecorator.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Exceptions/ExceptionToMessageMapper.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Exceptions/ExceptionToResponseMapper.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/IAppContextFactory.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/Extensions.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/StudentDocument.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentEventsHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentsHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/StudentMongoRepository.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/DateTimeProvider.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/EventMapper.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/MessageBroker.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs index 00ff53936..a69138c27 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs @@ -1,44 +1,47 @@ -var builder = WebApplication.CreateBuilder(args); - -// Add services to the container. -// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle -builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); - -var app = builder.Build(); - -// Configure the HTTP request pipeline. -if (app.Environment.IsDevelopment()) -{ - app.UseSwagger(); - app.UseSwaggerUI(); -} - -app.UseHttpsRedirection(); - -var summaries = new[] -{ - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" -}; - -app.MapGet("/weatherforecast", () => -{ - var forecast = Enumerable.Range(1, 5).Select(index => - new WeatherForecast - ( - DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - Random.Shared.Next(-20, 55), - summaries[Random.Shared.Next(summaries.Length)] - )) - .ToArray(); - return forecast; -}) -.WithName("GetWeatherForecast") -.WithOpenApi(); - -app.Run(); - -record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) +using System.Collections.Generic; +using System.Threading.Tasks; +using Convey; +using Convey.Logging; +using Convey.Types; +using Convey.WebApi; +using Convey.WebApi.CQRS; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using MiniSpace.Services.MediaFiles.Application; +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Application.Dto; +using MiniSpace.Services.MediaFiles.Application.Queries; +using MiniSpace.Services.MediaFiles.Infrastructure; + +namespace MiniSpace.Services.MediaFiles.Api { - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + public class Program + { + public static async Task Main(string[] args) + => await WebHost.CreateDefaultBuilder(args) + .ConfigureServices(services => services + .AddConvey() + .AddWebApi() + .AddApplication() + .AddInfrastructure() + .Build()) + .Configure(app => app + .UseInfrastructure() + .UseDispatcherEndpoints(endpoints => endpoints + .Get("", ctx => ctx.Response.WriteAsync(ctx.RequestServices.GetService().Name)) + .Get>("students") + .Get("students/{studentId}") + .Put("students/{studentId}") + .Delete("students/{studentId}") + .Post("students", + afterDispatch: (cmd, ctx) => ctx.Response.Created($"students/{cmd.StudentId}")) + .Put("students/{studentId}/state/{state}", + afterDispatch: (cmd, ctx) => ctx.Response.NoContent()) + .Get("students/{studentId}/events"))) + .UseLogging() + .Build() + .RunAsync(); + } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/ChangeStudentState.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/ChangeStudentState.cs new file mode 100644 index 000000000..a222434de --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/ChangeStudentState.cs @@ -0,0 +1,16 @@ +using Convey.CQRS.Commands; + +namespace MiniSpace.Services.MediaFiles.Application.Commands +{ + public class ChangeStudentState : ICommand + { + public Guid StudentId { get; } + public string State { get; } + + public ChangeStudentState(Guid studentId, string state) + { + StudentId = studentId; + State = state; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/CompleteStudentRegistration.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/CompleteStudentRegistration.cs new file mode 100644 index 000000000..136ab2041 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/CompleteStudentRegistration.cs @@ -0,0 +1,23 @@ +using Convey.CQRS.Commands; + +namespace MiniSpace.Services.MediaFiles.Application.Commands +{ + public class CompleteStudentRegistration : ICommand + { + public Guid StudentId { get; } + public string ProfileImage { get; } + public string Description { get; } + public DateTime DateOfBirth { get; } + public bool EmailNotifications { get; } + + public CompleteStudentRegistration(Guid studentId, string profileImage, + string description, DateTime dateOfBirth, bool emailNotifications) + { + StudentId = studentId; + ProfileImage = profileImage; + Description = description; + DateOfBirth = dateOfBirth; + EmailNotifications = emailNotifications; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/DeleteStudent.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/DeleteStudent.cs new file mode 100644 index 000000000..97c223cef --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/DeleteStudent.cs @@ -0,0 +1,11 @@ +using Convey.CQRS.Commands; + +namespace MiniSpace.Services.MediaFiles.Application.Commands +{ + public class DeleteStudent : ICommand + { + public Guid StudentId { get; } + + public DeleteStudent(Guid studentId) => StudentId = studentId; + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/ChangeStudentStateHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/ChangeStudentStateHandler.cs new file mode 100644 index 000000000..846350694 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/ChangeStudentStateHandler.cs @@ -0,0 +1,63 @@ +using Convey.CQRS.Commands; +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Core.Exceptions; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers +{ + public class ChangeStudentStateHandler : ICommandHandler + { + private readonly IStudentRepository _studentRepository; + private readonly IEventMapper _eventMapper; + private readonly IMessageBroker _messageBroker; + + public ChangeStudentStateHandler(IStudentRepository studentRepository, IEventMapper eventMapper, + IMessageBroker messageBroker) + { + _studentRepository = studentRepository; + _eventMapper = eventMapper; + _messageBroker = messageBroker; + } + + public async Task HandleAsync(ChangeStudentState command, CancellationToken cancellationToken = default) + { + var student = await _studentRepository.GetAsync(command.StudentId); + if (student is null) + { + throw new StudentNotFoundException(command.StudentId); + } + + if (!Enum.TryParse(command.State, true, out var state)) + { + throw new CannotChangeStudentStateException(student.Id, State.Unknown); + } + + if (student.State == state) + { + throw new StudentStateAlreadySetException(student.Id, state); + } + + switch (state) + { + case State.Incomplete: + student.SetIncomplete(); + break; + case State.Valid: + student.SetValid(); + break; + case State.Banned: + student.SetBanned(); + break; + default: + throw new CannotChangeStudentStateException(student.Id, state); + } + + await _studentRepository.UpdateAsync(student); + + var events = _eventMapper.MapAll(student.Events); + await _messageBroker.PublishAsync(events.ToArray()); + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CompleteStudentRegistrationHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CompleteStudentRegistrationHandler.cs new file mode 100644 index 000000000..d806d2ffa --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CompleteStudentRegistrationHandler.cs @@ -0,0 +1,46 @@ +using Convey.CQRS.Commands; +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Exceptions; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers +{ + public class CompleteStudentRegistrationHandler : ICommandHandler + { + private readonly IStudentRepository _studentRepository; + private readonly IDateTimeProvider _dateTimeProvider; + private readonly IEventMapper _eventMapper; + private readonly IMessageBroker _messageBroker; + + public CompleteStudentRegistrationHandler(IStudentRepository studentRepository, + IDateTimeProvider dateTimeProvider, IEventMapper eventMapper, IMessageBroker messageBroker) + { + _studentRepository = studentRepository; + _dateTimeProvider = dateTimeProvider; + _eventMapper = eventMapper; + _messageBroker = messageBroker; + } + + public async Task HandleAsync(CompleteStudentRegistration command, CancellationToken cancellationToken = default) + { + var student = await _studentRepository.GetAsync(command.StudentId); + if (student is null) + { + throw new StudentNotFoundException(command.StudentId); + } + + if (student.State is Core.Entities.State.Valid) + { + throw new StudentAlreadyRegisteredException(command.StudentId); + } + + student.CompleteRegistration(command.ProfileImage, command.Description, + command.DateOfBirth, _dateTimeProvider.Now, command.EmailNotifications); + await _studentRepository.UpdateAsync(student); + + var events = _eventMapper.MapAll(student.Events); + await _messageBroker.PublishAsync(events.ToArray()); + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteStudentHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteStudentHandler.cs new file mode 100644 index 000000000..9c30966a9 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteStudentHandler.cs @@ -0,0 +1,42 @@ +using Convey.CQRS.Commands; +using MiniSpace.Services.MediaFiles.Application.Events; +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers +{ + public class DeleteStudentHandler : ICommandHandler + { + private readonly IStudentRepository _studentRepository; + private readonly IAppContext _appContext; + private readonly IMessageBroker _messageBroker; + + public DeleteStudentHandler(IStudentRepository studentRepository, IAppContext appContext, + IMessageBroker messageBroker) + { + _studentRepository = studentRepository; + _appContext = appContext; + _messageBroker = messageBroker; + } + + public async Task HandleAsync(DeleteStudent command, CancellationToken cancellationToken = default) + { + var student = await _studentRepository.GetAsync(command.StudentId); + if (student is null) + { + throw new StudentNotFoundException(command.StudentId); + } + + var identity = _appContext.Identity; + if (identity.IsAuthenticated && identity.Id != student.Id && !identity.IsAdmin) + { + throw new UnauthorizedStudentAccessException(command.StudentId, identity.Id); + } + + await _studentRepository.DeleteAsync(command.StudentId); + + await _messageBroker.PublishAsync(new StudentDeleted(command.StudentId, student.FullName)); + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UpdateStudentHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UpdateStudentHandler.cs new file mode 100644 index 000000000..4c366f2e5 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UpdateStudentHandler.cs @@ -0,0 +1,45 @@ +using Convey.CQRS.Commands; +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers +{ + public class UpdateStudentHandler : ICommandHandler + { + private readonly IStudentRepository _studentRepository; + private readonly IAppContext _appContext; + private readonly IEventMapper _eventMapper; + private readonly IMessageBroker _messageBroker; + + public UpdateStudentHandler(IStudentRepository studentRepository, IAppContext appContext, + IEventMapper eventMapper, IMessageBroker messageBroker) + { + _studentRepository = studentRepository; + _appContext = appContext; + _eventMapper = eventMapper; + _messageBroker = messageBroker; + } + + public async Task HandleAsync(UpdateStudent command, CancellationToken cancellationToken = default) + { + var student = await _studentRepository.GetAsync(command.StudentId); + if (student is null) + { + throw new StudentNotFoundException(command.StudentId); + } + + var identity = _appContext.Identity; + if (identity.IsAuthenticated && identity.Id != student.Id && !identity.IsAdmin) + { + throw new UnauthorizedStudentAccessException(command.StudentId, identity.Id); + } + + student.Update(command.ProfileImage, command.Description, command.EmailNotifications); + await _studentRepository.UpdateAsync(student); + + var events = _eventMapper.MapAll(student.Events); + await _messageBroker.PublishAsync(events.ToArray()); + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UpdateStudent.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UpdateStudent.cs new file mode 100644 index 000000000..941f7c86f --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UpdateStudent.cs @@ -0,0 +1,20 @@ +using Convey.CQRS.Commands; + +namespace MiniSpace.Services.MediaFiles.Application.Commands +{ + public class UpdateStudent : ICommand + { + public Guid StudentId { get; } + public string ProfileImage { get; } + public string Description { get; } + public bool EmailNotifications { get; } + + public UpdateStudent(Guid studentId, string profileImage, string description, bool emailNotifications) + { + StudentId = studentId; + ProfileImage = profileImage; + Description = description; + EmailNotifications = emailNotifications; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/ContractAttribute.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/ContractAttribute.cs new file mode 100644 index 000000000..88c1e41a4 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/ContractAttribute.cs @@ -0,0 +1,7 @@ +namespace MiniSpace.Services.MediaFiles.Application +{ + public class ContractAttribute : Attribute + { + + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentDto.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentDto.cs new file mode 100644 index 000000000..a47ef9635 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentDto.cs @@ -0,0 +1,21 @@ +namespace MiniSpace.Services.MediaFiles.Application.Dto +{ + public class StudentDto + { + public Guid Id { get; set; } + public string Email { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public int NumberOfFriends { get; set; } + public string ProfileImage { get; set; } + public string Description { get; set; } + public DateTime? DateOfBirth { get; set; } + public bool EmailNotifications { get; set; } + public bool IsBanned { get; set; } + public bool IsOrganizer { get; set; } + public string State { get; set; } + public DateTime CreatedAt { get; set; } + public IEnumerable InterestedInEvents { get; set; } + public IEnumerable SignedUpEvents { get; set; } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentEventsDto.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentEventsDto.cs new file mode 100644 index 000000000..932b7c315 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentEventsDto.cs @@ -0,0 +1,9 @@ +namespace MiniSpace.Services.MediaFiles.Application.Dto +{ + public class StudentEventsDto + { + public Guid StudentId { get; set; } + public IEnumerable InterestedInEvents { get; set; } + public IEnumerable SignedUpEvents { get; set; } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsGrantedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsGrantedHandler.cs new file mode 100644 index 000000000..f57936eff --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsGrantedHandler.cs @@ -0,0 +1,37 @@ +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers +{ + public class OrganizerRightsGrantedHandler : IEventHandler + { + private readonly IStudentRepository _studentRepository; + private readonly IEventMapper _eventMapper; + private readonly IMessageBroker _messageBroker; + + public OrganizerRightsGrantedHandler(IStudentRepository studentRepository, + IEventMapper eventMapper, IMessageBroker messageBroker) + { + _studentRepository = studentRepository; + _eventMapper = eventMapper; + _messageBroker = messageBroker; + } + + public async Task HandleAsync(OrganizerRightsGranted @event, CancellationToken cancellationToken) + { + var student = await _studentRepository.GetAsync(@event.UserId); + if (student is null) + { + throw new StudentNotFoundException(@event.UserId); + } + + student.GrantOrganizerRights(); + await _studentRepository.UpdateAsync(student); + + var events = _eventMapper.MapAll(student.Events); + await _messageBroker.PublishAsync(events.ToArray()); + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsRevokedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsRevokedHandler.cs new file mode 100644 index 000000000..8d0089826 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsRevokedHandler.cs @@ -0,0 +1,37 @@ +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers +{ + public class OrganizerRightsRevokedHandler : IEventHandler + { + private readonly IStudentRepository _studentRepository; + private readonly IEventMapper _eventMapper; + private readonly IMessageBroker _messageBroker; + + public OrganizerRightsRevokedHandler(IStudentRepository studentRepository, + IEventMapper eventMapper, IMessageBroker messageBroker) + { + _studentRepository = studentRepository; + _eventMapper = eventMapper; + _messageBroker = messageBroker; + } + + public async Task HandleAsync(OrganizerRightsRevoked @event, CancellationToken cancellationToken) + { + var student = await _studentRepository.GetAsync(@event.UserId); + if (student is null) + { + throw new StudentNotFoundException(@event.UserId); + } + + student.RevokeOrganizerRights(); + await _studentRepository.UpdateAsync(student); + + var events = _eventMapper.MapAll(student.Events); + await _messageBroker.PublishAsync(events.ToArray()); + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/SignedUpHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/SignedUpHandler.cs new file mode 100644 index 000000000..9811ba4fe --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/SignedUpHandler.cs @@ -0,0 +1,43 @@ +using Convey.CQRS.Events; +using Microsoft.Extensions.Logging; +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers +{ + public class SignedUpHandler : IEventHandler + { + private const string RequiredRole = "user"; + private readonly IStudentRepository _studentRepository; + private readonly IDateTimeProvider _dateTimeProvider; + private readonly ILogger _logger; + + public SignedUpHandler(IStudentRepository studentRepository, IDateTimeProvider dateTimeProvider, + ILogger logger) + { + _studentRepository = studentRepository; + _dateTimeProvider = dateTimeProvider; + _logger = logger; + } + + public async Task HandleAsync(SignedUp @event, CancellationToken cancellationToken = default) + { + if (@event.Role != RequiredRole) + { + throw new InvalidRoleException(@event.UserId, @event.Role, RequiredRole); + } + + var student = await _studentRepository.GetAsync(@event.UserId); + if (student is not null) + { + throw new StudentAlreadyCreatedException(student.Id); + } + + var newStudent = new Student(@event.UserId, @event.FirstName, @event.LastName, + @event.Email, _dateTimeProvider.Now); + await _studentRepository.AddAsync(newStudent); + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentShowedInterestInEventHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentShowedInterestInEventHandler.cs new file mode 100644 index 000000000..92b2b4bc4 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentShowedInterestInEventHandler.cs @@ -0,0 +1,37 @@ +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers +{ + public class StudentShowedInterestInEventHandler : IEventHandler + { + private readonly IStudentRepository _studentRepository; + private readonly IEventMapper _eventMapper; + private readonly IMessageBroker _messageBroker; + + public StudentShowedInterestInEventHandler(IStudentRepository studentRepository, + IEventMapper eventMapper, IMessageBroker messageBroker) + { + _studentRepository = studentRepository; + _eventMapper = eventMapper; + _messageBroker = messageBroker; + } + + public async Task HandleAsync(StudentShowedInterestInEvent @event, CancellationToken cancellationToken) + { + var student = await _studentRepository.GetAsync(@event.StudentId); + if (student is null) + { + throw new StudentNotFoundException(@event.StudentId); + } + + student.AddInterestedInEvent(@event.EventId); + await _studentRepository.UpdateAsync(student); + + var events = _eventMapper.MapAll(student.Events); + await _messageBroker.PublishAsync(events.ToArray()); + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentSignedUpToEventHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentSignedUpToEventHandler.cs new file mode 100644 index 000000000..5356ca003 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentSignedUpToEventHandler.cs @@ -0,0 +1,37 @@ +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers +{ + public class StudentSignedUpToEventHandler : IEventHandler + { + private readonly IStudentRepository _studentRepository; + private readonly IEventMapper _eventMapper; + private readonly IMessageBroker _messageBroker; + + public StudentSignedUpToEventHandler(IStudentRepository studentRepository, + IEventMapper eventMapper, IMessageBroker messageBroker) + { + _studentRepository = studentRepository; + _eventMapper = eventMapper; + _messageBroker = messageBroker; + } + + public async Task HandleAsync(StudentSignedUpToEvent studentSignedUpToEvent, CancellationToken cancellationToken) + { + var student = await _studentRepository.GetAsync(studentSignedUpToEvent.StudentId); + if (student is null) + { + throw new StudentNotFoundException(studentSignedUpToEvent.StudentId); + } + + student.AddSignedUpEvent(studentSignedUpToEvent.EventId); + await _studentRepository.UpdateAsync(student); + + var events = _eventMapper.MapAll(student.Events); + await _messageBroker.PublishAsync(events.ToArray()); + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserBannedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserBannedHandler.cs new file mode 100644 index 000000000..9fbc8cc46 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserBannedHandler.cs @@ -0,0 +1,37 @@ +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers +{ + public class UserBannedHandler : IEventHandler + { + private readonly IStudentRepository _studentRepository; + private readonly IEventMapper _eventMapper; + private readonly IMessageBroker _messageBroker; + + public UserBannedHandler(IStudentRepository studentRepository, + IEventMapper eventMapper, IMessageBroker messageBroker) + { + _studentRepository = studentRepository; + _eventMapper = eventMapper; + _messageBroker = messageBroker; + } + + public async Task HandleAsync(UserBanned @event, CancellationToken cancellationToken) + { + var student = await _studentRepository.GetAsync(@event.UserId); + if (student is null) + { + throw new StudentNotFoundException(@event.UserId); + } + + student.Ban(); + await _studentRepository.UpdateAsync(student); + + var events = _eventMapper.MapAll(student.Events); + await _messageBroker.PublishAsync(events.ToArray()); + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserUnbannedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserUnbannedHandler.cs new file mode 100644 index 000000000..91ac019fb --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserUnbannedHandler.cs @@ -0,0 +1,37 @@ +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers +{ + public class UserUnbannedHandler : IEventHandler + { + private readonly IStudentRepository _studentRepository; + private readonly IEventMapper _eventMapper; + private readonly IMessageBroker _messageBroker; + + public UserUnbannedHandler(IStudentRepository studentRepository, + IEventMapper eventMapper, IMessageBroker messageBroker) + { + _studentRepository = studentRepository; + _eventMapper = eventMapper; + _messageBroker = messageBroker; + } + + public async Task HandleAsync(UserUnbanned @event, CancellationToken cancellationToken) + { + var student = await _studentRepository.GetAsync(@event.UserId); + if (student is null) + { + throw new StudentNotFoundException(@event.UserId); + } + + student.Unban(); + await _studentRepository.UpdateAsync(student); + + var events = _eventMapper.MapAll(student.Events); + await _messageBroker.PublishAsync(events.ToArray()); + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsGranted.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsGranted.cs new file mode 100644 index 000000000..ed819c1ff --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsGranted.cs @@ -0,0 +1,15 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("identity")] + public class OrganizerRightsGranted : IEvent + { + public Guid UserId { get; } + public OrganizerRightsGranted(Guid userId) + { + UserId = userId; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsRevoked.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsRevoked.cs new file mode 100644 index 000000000..efe5adfac --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsRevoked.cs @@ -0,0 +1,15 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("identity")] + public class OrganizerRightsRevoked : IEvent + { + public Guid UserId { get; } + public OrganizerRightsRevoked(Guid userId) + { + UserId = userId; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/SignedUp.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/SignedUp.cs new file mode 100644 index 000000000..14a3a5032 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/SignedUp.cs @@ -0,0 +1,24 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("identity")] + public class SignedUp : IEvent + { + public Guid UserId { get; } + public string FirstName { get; } + public string LastName { get; } + public string Email { get; } + public string Role { get; } + + public SignedUp(Guid userId, string firstName, string lastName, string email, string role) + { + UserId = userId; + FirstName = firstName; + LastName = lastName; + Email = email; + Role = role; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentShowedInterestInEvent.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentShowedInterestInEvent.cs new file mode 100644 index 000000000..4fe380afd --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentShowedInterestInEvent.cs @@ -0,0 +1,18 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("events")] + public class StudentShowedInterestInEvent : IEvent + { + public Guid EventId { get; } + public Guid StudentId { get; } + + public StudentShowedInterestInEvent(Guid eventId, Guid studentId) + { + EventId = eventId; + StudentId = studentId; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentSignedUpToEvent.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentSignedUpToEvent.cs new file mode 100644 index 000000000..4b8ae6ff5 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentSignedUpToEvent.cs @@ -0,0 +1,18 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("events")] + public class StudentSignedUpToEvent : IEvent + { + public Guid EventId { get; } + public Guid StudentId { get; } + + public StudentSignedUpToEvent(Guid eventId, Guid studentId) + { + EventId = eventId; + StudentId = studentId; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserBanned.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserBanned.cs new file mode 100644 index 000000000..cc567c35d --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserBanned.cs @@ -0,0 +1,11 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("identity")] + public class UserBanned(Guid userId) : IEvent + { + public Guid UserId { get; } = userId; + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserUnbanned.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserUnbanned.cs new file mode 100644 index 000000000..ec423a19a --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserUnbanned.cs @@ -0,0 +1,11 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("identity")] + public class UserUnbanned(Guid userId) : IEvent + { + public Guid UserId { get; } = userId; + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/ChangeStudentStateRejected.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/ChangeStudentStateRejected.cs new file mode 100644 index 000000000..1d31c01dc --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/ChangeStudentStateRejected.cs @@ -0,0 +1,20 @@ +using Convey.CQRS.Events; + +namespace MiniSpace.Services.MediaFiles.Application.Events.Rejected +{ + public class ChangeStudentStateRejected : IRejectedEvent + { + public Guid StudentId { get; } + public string State { get; } + public string Reason { get; } + public string Code { get; } + + public ChangeStudentStateRejected(Guid studentId, string state, string reason, string code) + { + StudentId = studentId; + State = state; + Reason = reason; + Code = code; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CompleteStudentRegistrationRejected.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CompleteStudentRegistrationRejected.cs new file mode 100644 index 000000000..63be697a4 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CompleteStudentRegistrationRejected.cs @@ -0,0 +1,19 @@ +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Commands; + +namespace MiniSpace.Services.MediaFiles.Application.Events.Rejected +{ + public class CompleteStudentRegistrationRejected : IRejectedEvent + { + public Guid StudentId { get; } + public string Reason { get; } + public string Code { get; } + + public CompleteStudentRegistrationRejected(Guid studentId, string reason, string code) + { + StudentId = studentId; + Reason = reason; + Code = code; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CreateStudentRejected.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CreateStudentRejected.cs new file mode 100644 index 000000000..2fa8f4497 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CreateStudentRejected.cs @@ -0,0 +1,18 @@ +using Convey.CQRS.Events; + +namespace MiniSpace.Services.MediaFiles.Application.Events.Rejected +{ + public class CreateStudentRejected : IRejectedEvent + { + public Guid StudentId { get; } + public string Reason { get; } + public string Code { get; } + + public CreateStudentRejected(Guid studentId, string reason, string code) + { + StudentId = studentId; + Reason = reason; + Code = code; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/DeleteStudentRejected.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/DeleteStudentRejected.cs new file mode 100644 index 000000000..6034f3586 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/DeleteStudentRejected.cs @@ -0,0 +1,18 @@ +using Convey.CQRS.Events; + +namespace MiniSpace.Services.MediaFiles.Application.Events.Rejected +{ + public class DeleteStudentRejected : IRejectedEvent + { + public Guid StudentId { get; } + public string Reason { get; } + public string Code { get; } + + public DeleteStudentRejected(Guid studentId, string reason, string code) + { + StudentId = studentId; + Reason = reason; + Code = code; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/UpdateStudentRejected.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/UpdateStudentRejected.cs new file mode 100644 index 000000000..8e812d66a --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/UpdateStudentRejected.cs @@ -0,0 +1,18 @@ +using Convey.CQRS.Events; + +namespace MiniSpace.Services.MediaFiles.Application.Events.Rejected +{ + public class UpdateStudentRejected : IRejectedEvent + { + public Guid StudentId { get; } + public string Reason { get; } + public string Code { get; } + + public UpdateStudentRejected(Guid studentId, string reason, string code) + { + StudentId = studentId; + Reason = reason; + Code = code; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentCreated.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentCreated.cs new file mode 100644 index 000000000..6b6eecad0 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentCreated.cs @@ -0,0 +1,16 @@ +using Convey.CQRS.Events; + +namespace MiniSpace.Services.MediaFiles.Application.Events +{ + public class StudentCreated : IEvent + { + public Guid StudentId { get; } + public string FullName { get; } + + public StudentCreated(Guid studentId, string fullName) + { + StudentId = studentId; + FullName = fullName; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentDeleted.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentDeleted.cs new file mode 100644 index 000000000..0c150f8fe --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentDeleted.cs @@ -0,0 +1,16 @@ +using Convey.CQRS.Events; + +namespace MiniSpace.Services.MediaFiles.Application.Events +{ + public class StudentDeleted : IEvent + { + public Guid StudentId { get; } + public string FullName { get; } + + public StudentDeleted(Guid studentId, string fullName) + { + StudentId = studentId; + FullName = fullName; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentStateChanged.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentStateChanged.cs new file mode 100644 index 000000000..3f1087d70 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentStateChanged.cs @@ -0,0 +1,20 @@ +using Convey.CQRS.Events; + +namespace MiniSpace.Services.MediaFiles.Application.Events +{ + public class StudentStateChanged : IEvent + { + public Guid StudentId { get; } + public string FullName { get; } + public string CurrentState { get; } + public string PreviousState { get; } + + public StudentStateChanged(Guid studentId, string fullName, string currentState, string previousState) + { + StudentId = studentId; + FullName = fullName; + CurrentState = currentState; + PreviousState = previousState; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentUpdated.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentUpdated.cs new file mode 100644 index 000000000..337fbfa51 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentUpdated.cs @@ -0,0 +1,16 @@ +using Convey.CQRS.Events; + +namespace MiniSpace.Services.MediaFiles.Application.Events +{ + public class StudentUpdated : IEvent + { + public Guid StudentId { get; } + public string FullName { get; } + + public StudentUpdated(Guid studentId, string fullName) + { + StudentId = studentId; + FullName = fullName; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/AppException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/AppException.cs new file mode 100644 index 000000000..4447155a7 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/AppException.cs @@ -0,0 +1,11 @@ +namespace MiniSpace.Services.MediaFiles.Application.Exceptions +{ + public class AppException : Exception + { + public virtual string Code { get; } + + protected AppException(string message) : base(message) + { + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidRoleException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidRoleException.cs new file mode 100644 index 000000000..5b6776e16 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidRoleException.cs @@ -0,0 +1,13 @@ +namespace MiniSpace.Services.MediaFiles.Application.Exceptions +{ + public class InvalidRoleException : AppException + { + public override string Code { get; } = "invalid_role"; + + public InvalidRoleException(Guid userId, string role, string requiredRole) + : base($"Student account will not be created for the user with id: {userId} " + + $"due to the invalid role: {role} (required: {requiredRole}).") + { + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyCreatedException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyCreatedException.cs new file mode 100644 index 000000000..ed2ea0910 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyCreatedException.cs @@ -0,0 +1,14 @@ +namespace MiniSpace.Services.MediaFiles.Application.Exceptions +{ + public class StudentAlreadyCreatedException : AppException + { + public override string Code { get; } = "student_already_created"; + public Guid StudentId { get; } + + public StudentAlreadyCreatedException(Guid studentId) + : base($"Student with id: {studentId} was already created.") + { + StudentId = studentId; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyRegisteredException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyRegisteredException.cs new file mode 100644 index 000000000..01f9b33ab --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyRegisteredException.cs @@ -0,0 +1,14 @@ +namespace MiniSpace.Services.MediaFiles.Application.Exceptions +{ + public class StudentAlreadyRegisteredException : AppException + { + public override string Code { get; } = "student_already_registered"; + public Guid Id { get; } + + public StudentAlreadyRegisteredException(Guid id) + : base($"Student with id: {id} has already been registered.") + { + Id = id; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentNotFoundException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentNotFoundException.cs new file mode 100644 index 000000000..d43aeee94 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentNotFoundException.cs @@ -0,0 +1,13 @@ +namespace MiniSpace.Services.MediaFiles.Application.Exceptions +{ + public class StudentNotFoundException : AppException + { + public override string Code { get; } = "student_not_found"; + public Guid Id { get; } + + public StudentNotFoundException(Guid id) : base($"Student with id: {id} was not found.") + { + Id = id; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedStudentAccessException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedStudentAccessException.cs new file mode 100644 index 000000000..738c13d9a --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedStudentAccessException.cs @@ -0,0 +1,16 @@ +namespace MiniSpace.Services.MediaFiles.Application.Exceptions +{ + public class UnauthorizedStudentAccessException : AppException + { + public override string Code { get; } = "unauthorized_student_access"; + public Guid StudentId { get; } + public Guid UserId { get; } + + public UnauthorizedStudentAccessException(Guid studentId, Guid userId) + : base($"Unauthorized access to student with id: '{studentId}' by user with id: '{userId}'.") + { + StudentId = studentId; + UserId = userId; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Extensions.cs new file mode 100644 index 000000000..6553ffbae --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Extensions.cs @@ -0,0 +1,16 @@ +using Convey; +using Convey.CQRS.Commands; +using Convey.CQRS.Events; + +namespace MiniSpace.Services.MediaFiles.Application +{ + public static class Extensions + { + public static IConveyBuilder AddApplication(this IConveyBuilder builder) + => builder + .AddCommandHandlers() + .AddEventHandlers() + .AddInMemoryCommandDispatcher() + .AddInMemoryEventDispatcher(); + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/IAppContext.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/IAppContext.cs new file mode 100644 index 000000000..d3084031f --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/IAppContext.cs @@ -0,0 +1,8 @@ +namespace MiniSpace.Services.MediaFiles.Application +{ + public interface IAppContext + { + string RequestId { get; } + IIdentityContext Identity { get; } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/IIdentityContext.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/IIdentityContext.cs new file mode 100644 index 000000000..b0748b5e8 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/IIdentityContext.cs @@ -0,0 +1,15 @@ +namespace MiniSpace.Services.MediaFiles.Application +{ + public interface IIdentityContext + { + Guid Id { get; } + string Role { get; } + string Name { get; } + string Email { get; } + bool IsAuthenticated { get; } + bool IsAdmin { get; } + bool IsBanned { get; } + bool IsOrganizer { get; } + IDictionary Claims { get; } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj index fdf5b09ed..95d9be543 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj @@ -15,7 +15,7 @@ - + diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudent.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudent.cs new file mode 100644 index 000000000..6a13df988 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudent.cs @@ -0,0 +1,10 @@ +using Convey.CQRS.Queries; +using MiniSpace.Services.MediaFiles.Application.Dto; + +namespace MiniSpace.Services.MediaFiles.Application.Queries +{ + public class GetStudent : IQuery + { + public Guid StudentId { get; set; } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudentEvents.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudentEvents.cs new file mode 100644 index 000000000..024be5ff9 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudentEvents.cs @@ -0,0 +1,10 @@ +using Convey.CQRS.Queries; +using MiniSpace.Services.MediaFiles.Application.Dto; + +namespace MiniSpace.Services.MediaFiles.Application.Queries +{ + public class GetStudentEvents: IQuery + { + public Guid StudentId { get; set; } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudents.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudents.cs new file mode 100644 index 000000000..f4c90f67d --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudents.cs @@ -0,0 +1,9 @@ +using Convey.CQRS.Queries; +using MiniSpace.Services.MediaFiles.Application.Dto; + +namespace MiniSpace.Services.MediaFiles.Application.Queries +{ + public class GetStudents : IQuery> + { + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IDateTimeProvider.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IDateTimeProvider.cs new file mode 100644 index 000000000..9cb5354b8 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IDateTimeProvider.cs @@ -0,0 +1,7 @@ +namespace MiniSpace.Services.MediaFiles.Application.Services +{ + public interface IDateTimeProvider + { + DateTime Now { get; } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IEventMapper.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IEventMapper.cs new file mode 100644 index 000000000..b26bb7e2e --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IEventMapper.cs @@ -0,0 +1,11 @@ +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Core.Events; + +namespace MiniSpace.Services.MediaFiles.Application.Services +{ + public interface IEventMapper + { + IEvent Map(IDomainEvent @event); + IEnumerable MapAll(IEnumerable events); + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IMessageBroker.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IMessageBroker.cs new file mode 100644 index 000000000..2af117300 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IMessageBroker.cs @@ -0,0 +1,10 @@ +using Convey.CQRS.Events; + +namespace MiniSpace.Services.MediaFiles.Application.Services +{ + public interface IMessageBroker + { + Task PublishAsync(params IEvent[] events); + Task PublishAsync(IEnumerable events); + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/AggregateId.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/AggregateId.cs new file mode 100644 index 000000000..922491499 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/AggregateId.cs @@ -0,0 +1,50 @@ +using MiniSpace.Services.MediaFiles.Core.Exceptions; + +namespace MiniSpace.Services.MediaFiles.Core.Entities +{ + public class AggregateId : IEquatable + { + public Guid Value { get; } + + public AggregateId() + { + Value = Guid.NewGuid(); + } + + public AggregateId(Guid value) + { + if (value == Guid.Empty) + { + throw new InvalidAggregateIdException(); + } + + Value = value; + } + + public bool Equals(AggregateId other) + { + if (ReferenceEquals(null, other)) return false; + return ReferenceEquals(this, other) || Value.Equals(other.Value); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + return obj.GetType() == GetType() && Equals((AggregateId) obj); + } + + public override int GetHashCode() + { + return Value.GetHashCode(); + } + + public static implicit operator Guid(AggregateId id) + => id.Value; + + public static implicit operator AggregateId(Guid id) + => new AggregateId(id); + + public override string ToString() => Value.ToString(); + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/AggregateRoot.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/AggregateRoot.cs new file mode 100644 index 000000000..fca21a6dd --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/AggregateRoot.cs @@ -0,0 +1,19 @@ +using MiniSpace.Services.MediaFiles.Core.Events; + +namespace MiniSpace.Services.MediaFiles.Core.Entities +{ + public abstract class AggregateRoot + { + private readonly List _events = new List(); + public IEnumerable Events => _events; + public AggregateId Id { get; protected set; } + public int Version { get; protected set; } + + protected void AddEvent(IDomainEvent @event) + { + _events.Add(@event); + } + + public void ClearEvents() => _events.Clear(); + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/State.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/State.cs new file mode 100644 index 000000000..06677796f --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/State.cs @@ -0,0 +1,10 @@ +namespace MiniSpace.Services.MediaFiles.Core.Entities +{ + public enum State + { + Unknown, + Valid, + Incomplete, + Banned + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/Student.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/Student.cs new file mode 100644 index 000000000..534a81117 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/Student.cs @@ -0,0 +1,171 @@ +using MiniSpace.Services.MediaFiles.Core.Events; +using MiniSpace.Services.MediaFiles.Core.Exceptions; + +namespace MiniSpace.Services.MediaFiles.Core.Entities +{ + public class Student : AggregateRoot + { + private ISet _interestedInEvents = new HashSet(); + private ISet _signedUpEvents = new HashSet(); + + public string Email { get; private set; } + public string FirstName { get; private set; } + public string LastName { get; private set; } + public string FullName => $"{FirstName} {LastName}"; + public int NumberOfFriends { get; private set; } + public string ProfileImage { get; private set; } + public string Description { get; private set; } + public DateTime? DateOfBirth { get; private set; } + public bool EmailNotifications { get; private set; } + public bool IsBanned { get; private set; } + public bool IsOrganizer { get; private set; } + public State State { get; private set; } + public DateTime CreatedAt { get; private set; } + + public IEnumerable InterestedInEvents + { + get => _interestedInEvents; + set => _interestedInEvents = new HashSet(value); + } + public IEnumerable SignedUpEvents + { + get => _signedUpEvents; + set => _signedUpEvents = new HashSet(value); + } + + public Student(Guid id, string firstName, string lastName, string email, DateTime createdAt) + : this(id, email, createdAt, firstName, lastName, 0, string.Empty, string.Empty, null, + false, false, false, State.Incomplete, Enumerable.Empty(), Enumerable.Empty()) + { + CheckFullName(firstName, lastName); + } + + public Student(Guid id, string email, DateTime createdAt, string firstName, string lastName, + int numberOfFriends, string profileImage, string description, DateTime? dateOfBirth, + bool emailNotifications, bool isBanned, bool isOrganizer, State state, + IEnumerable interestedInEvents = null, IEnumerable signedUpEvents = null) + { + Id = id; + Email = email; + CreatedAt = createdAt; + FirstName = firstName; + LastName = lastName; + NumberOfFriends = numberOfFriends; + ProfileImage = profileImage; + Description = description; + DateOfBirth = dateOfBirth; + EmailNotifications = emailNotifications; + IsBanned = isBanned; + IsOrganizer = isOrganizer; + State = state; + InterestedInEvents = interestedInEvents ?? Enumerable.Empty(); + SignedUpEvents = signedUpEvents ?? Enumerable.Empty(); + } + + public void SetIncomplete() => SetState(State.Incomplete); + public void SetValid() => SetState(State.Valid); + public void SetBanned() => SetState(State.Banned); + + private void SetState(State state) + { + var previousState = State; + State = state; + AddEvent(new StudentStateChanged(this, previousState)); + } + + public void CompleteRegistration(string profileImage, string description, + DateTime dateOfBirth, DateTime now, bool emailNotifications) + { + CheckProfileImage(profileImage); + CheckDescription(description); + CheckDateOfBirth(dateOfBirth, now); + + if (State != State.Incomplete) + { + throw new CannotChangeStudentStateException(Id, State); + } + + ProfileImage = profileImage; + Description = description; + DateOfBirth = dateOfBirth; + EmailNotifications = emailNotifications; + + State = State.Valid; + AddEvent(new StudentRegistrationCompleted(this)); + } + + public void Update(string profileImage, string description, bool emailNotifications) + { + CheckProfileImage(profileImage); + CheckDescription(description); + + if (State != State.Valid) + { + throw new CannotUpdateStudentException(Id); + } + + ProfileImage = profileImage; + Description = description; + EmailNotifications = emailNotifications; + + AddEvent(new StudentUpdated(this)); + } + + private void CheckFullName(string firstName, string lastName) + { + if (string.IsNullOrWhiteSpace(firstName) || string.IsNullOrWhiteSpace(lastName)) + { + throw new InvalidStudentFullNameException(Id, $"{firstName} {lastName}"); + } + } + + private void CheckProfileImage(string profileImage) + { + if (string.IsNullOrWhiteSpace(profileImage)) + { + throw new InvalidStudentProfileImageException(Id, profileImage); + } + } + + private void CheckDescription(string description) + { + if (string.IsNullOrWhiteSpace(description)) + { + throw new InvalidStudentDescriptionException(Id, description); + } + } + + private void CheckDateOfBirth(DateTime dateOfBirth, DateTime now) + { + if (dateOfBirth >= now) + { + throw new InvalidStudentDateOfBirthException(Id, dateOfBirth, now); + } + } + + public void AddInterestedInEvent(Guid eventId) + { + if (eventId == Guid.Empty) + { + return; + } + + _interestedInEvents.Add(eventId); + } + + public void AddSignedUpEvent(Guid eventId) + { + if (eventId == Guid.Empty) + { + return; + } + + _signedUpEvents.Add(eventId); + } + + public void Ban() => IsBanned = true; + public void Unban() => IsBanned = false; + public void GrantOrganizerRights() => IsOrganizer = true; + public void RevokeOrganizerRights() => IsOrganizer = false; + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/IDomainEvent.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/IDomainEvent.cs new file mode 100644 index 000000000..ecf21afe6 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/IDomainEvent.cs @@ -0,0 +1,7 @@ +namespace MiniSpace.Services.MediaFiles.Core.Events +{ + public interface IDomainEvent + { + + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentRegistrationCompleted.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentRegistrationCompleted.cs new file mode 100644 index 000000000..7b143d578 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentRegistrationCompleted.cs @@ -0,0 +1,14 @@ +using MiniSpace.Services.MediaFiles.Core.Entities; + +namespace MiniSpace.Services.MediaFiles.Core.Events +{ + public class StudentRegistrationCompleted : IDomainEvent + { + public Student Student { get; } + + public StudentRegistrationCompleted(Student student) + { + Student = student; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentStateChanged.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentStateChanged.cs new file mode 100644 index 000000000..864c8f4ed --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentStateChanged.cs @@ -0,0 +1,16 @@ +using MiniSpace.Services.MediaFiles.Core.Entities; + +namespace MiniSpace.Services.MediaFiles.Core.Events +{ + public class StudentStateChanged : IDomainEvent + { + public Student Student { get; } + public State PreviousState { get; } + + public StudentStateChanged(Student student, State previousState) + { + Student = student; + PreviousState = previousState; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentUpdated.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentUpdated.cs new file mode 100644 index 000000000..90e26b9a1 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentUpdated.cs @@ -0,0 +1,14 @@ +using MiniSpace.Services.MediaFiles.Core.Entities; + +namespace MiniSpace.Services.MediaFiles.Core.Events +{ + public class StudentUpdated : IDomainEvent + { + public Student Student { get; } + + public StudentUpdated(Student student) + { + Student = student; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotChangeStudentStateException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotChangeStudentStateException.cs new file mode 100644 index 000000000..84a08f925 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotChangeStudentStateException.cs @@ -0,0 +1,18 @@ +using MiniSpace.Services.MediaFiles.Core.Entities; + +namespace MiniSpace.Services.MediaFiles.Core.Exceptions +{ + public class CannotChangeStudentStateException : DomainException + { + public override string Code { get; } = "cannot_change_student_state"; + public Guid Id { get; } + public State State { get; } + + public CannotChangeStudentStateException(Guid id, State state) : base( + $"Cannot change student: {id} state to: {state}.") + { + Id = id; + State = state; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotUpdateStudentException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotUpdateStudentException.cs new file mode 100644 index 000000000..60b2c2987 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotUpdateStudentException.cs @@ -0,0 +1,16 @@ +using MiniSpace.Services.MediaFiles.Core.Entities; + +namespace MiniSpace.Services.MediaFiles.Core.Exceptions +{ + public class CannotUpdateStudentException : DomainException + { + public override string Code { get; } = "cannot_update_student"; + public Guid Id { get; } + + public CannotUpdateStudentException(Guid id) : base( + $"Cannot update student: {id}.") + { + Id = id; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/DomainException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/DomainException.cs new file mode 100644 index 000000000..cc1f19637 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/DomainException.cs @@ -0,0 +1,11 @@ +namespace MiniSpace.Services.MediaFiles.Core.Exceptions +{ + public abstract class DomainException : Exception + { + public virtual string Code { get; } + + protected DomainException(string message) : base(message) + { + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidAggregateIdException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidAggregateIdException.cs new file mode 100644 index 000000000..fc759d722 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidAggregateIdException.cs @@ -0,0 +1,11 @@ +namespace MiniSpace.Services.MediaFiles.Core.Exceptions +{ + public class InvalidAggregateIdException : DomainException + { + public override string Code { get; } = "invalid_aggregate_id"; + + public InvalidAggregateIdException() : base($"Invalid aggregate id.") + { + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDateOfBirthException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDateOfBirthException.cs new file mode 100644 index 000000000..510f8870e --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDateOfBirthException.cs @@ -0,0 +1,19 @@ +namespace MiniSpace.Services.MediaFiles.Core.Exceptions +{ + public class InvalidStudentDateOfBirthException : DomainException + { + public override string Code { get; } = "invalid_student_date_of_birth"; + public Guid Id; + public DateTime DateOfBirth { get; } + public DateTime Now { get; } + + public InvalidStudentDateOfBirthException(Guid id, DateTime dateOfBirth, DateTime now) : base( + $"Student with id: {id} has invalid date of birth. Today date: " + + $"'{now}' must be greater than date of birth: '{dateOfBirth}'.") + { + Id = id; + DateOfBirth = dateOfBirth; + Now = now; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDescriptionException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDescriptionException.cs new file mode 100644 index 000000000..987259abf --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDescriptionException.cs @@ -0,0 +1,16 @@ +namespace MiniSpace.Services.MediaFiles.Core.Exceptions +{ + public class InvalidStudentDescriptionException : DomainException + { + public override string Code { get; } = "invalid_student_description"; + public Guid Id { get; } + public string Description { get; } + + public InvalidStudentDescriptionException(Guid id, string description) : base( + $"Student with id: {id} has invalid description.") + { + Id = id; + Description = description; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentFullNameException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentFullNameException.cs new file mode 100644 index 000000000..01969834e --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentFullNameException.cs @@ -0,0 +1,16 @@ +namespace MiniSpace.Services.MediaFiles.Core.Exceptions +{ + public class InvalidStudentFullNameException : DomainException + { + public override string Code { get; } = "invalid_student_full_name"; + public Guid Id { get; } + public string FullName { get; } + + public InvalidStudentFullNameException(Guid id, string fullName) : base( + $"Student with id: {id} has invalid full name.") + { + Id = id; + FullName = fullName; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentProfileImageException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentProfileImageException.cs new file mode 100644 index 000000000..9b51d71d5 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentProfileImageException.cs @@ -0,0 +1,16 @@ +namespace MiniSpace.Services.MediaFiles.Core.Exceptions +{ + public class InvalidStudentProfileImageException : DomainException + { + public override string Code { get; } = "invalid_student_profile_image"; + public Guid Id { get; } + public string ProfileImage { get; } + + public InvalidStudentProfileImageException(Guid id, string profileImage) : base( + $"Student with id: {id} has invalid profile image.") + { + Id = id; + ProfileImage = profileImage; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/StudentStateAlreadySetException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/StudentStateAlreadySetException.cs new file mode 100644 index 000000000..1098d4b96 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/StudentStateAlreadySetException.cs @@ -0,0 +1,18 @@ +using MiniSpace.Services.MediaFiles.Core.Entities; + +namespace MiniSpace.Services.MediaFiles.Core.Exceptions +{ + public class StudentStateAlreadySetException : DomainException + { + public override string Code { get; } = "student_state_already_set"; + public Guid Id { get; } + public State State { get; } + + public StudentStateAlreadySetException(Guid id, State state) : base( + $"Student: {id} has state already set to: {state}.") + { + Id = id; + State = state; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IStudentRepository.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IStudentRepository.cs new file mode 100644 index 000000000..d461b354e --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IStudentRepository.cs @@ -0,0 +1,12 @@ +using MiniSpace.Services.MediaFiles.Core.Entities; + +namespace MiniSpace.Services.MediaFiles.Core.Repositories +{ + public interface IStudentRepository + { + Task GetAsync(Guid id); + Task AddAsync(Student student); + Task UpdateAsync(Student student); + Task DeleteAsync(Guid id); + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/AppContext.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/AppContext.cs new file mode 100644 index 000000000..7d9aa35b8 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/AppContext.cs @@ -0,0 +1,27 @@ +using MiniSpace.Services.MediaFiles.Application; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Contexts +{ + internal class AppContext : IAppContext + { + public string RequestId { get; } + public IIdentityContext Identity { get; } + + internal AppContext() : this(Guid.NewGuid().ToString("N"), IdentityContext.Empty) + { + } + + internal AppContext(CorrelationContext context) : this(context.CorrelationId, + context.User is null ? IdentityContext.Empty : new IdentityContext(context.User)) + { + } + + internal AppContext(string requestId, IIdentityContext identity) + { + RequestId = requestId; + Identity = identity; + } + + internal static IAppContext Empty => new AppContext(); + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/AppContextFactory.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/AppContextFactory.cs new file mode 100644 index 000000000..db1770db5 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/AppContextFactory.cs @@ -0,0 +1,35 @@ +using Convey.MessageBrokers; +using Microsoft.AspNetCore.Http; +using Newtonsoft.Json; +using MiniSpace.Services.MediaFiles.Application; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Contexts +{ + internal sealed class AppContextFactory : IAppContextFactory + { + private readonly ICorrelationContextAccessor _contextAccessor; + private readonly IHttpContextAccessor _httpContextAccessor; + + public AppContextFactory(ICorrelationContextAccessor contextAccessor, IHttpContextAccessor httpContextAccessor) + { + _contextAccessor = contextAccessor; + _httpContextAccessor = httpContextAccessor; + } + + public IAppContext Create() + { + if (_contextAccessor.CorrelationContext is { }) + { + var payload = JsonConvert.SerializeObject(_contextAccessor.CorrelationContext); + + return string.IsNullOrWhiteSpace(payload) + ? AppContext.Empty + : new AppContext(JsonConvert.DeserializeObject(payload)); + } + + var context = _httpContextAccessor.GetCorrelationContext(); + + return context is null ? AppContext.Empty : new AppContext(context); + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/CorrelationContext.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/CorrelationContext.cs new file mode 100644 index 000000000..1ba6bbba4 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/CorrelationContext.cs @@ -0,0 +1,22 @@ +namespace MiniSpace.Services.MediaFiles.Infrastructure.Contexts +{ + internal class CorrelationContext + { + public string CorrelationId { get; set; } + public string SpanContext { get; set; } + public UserContext User { get; set; } + public string ResourceId { get; set; } + public string TraceId { get; set; } + public string ConnectionId { get; set; } + public string Name { get; set; } + public DateTime CreatedAt { get; set; } + + public class UserContext + { + public string Id { get; set; } + public bool IsAuthenticated { get; set; } + public string Role { get; set; } + public IDictionary Claims { get; set; } + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/IdentityContext.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/IdentityContext.cs new file mode 100644 index 000000000..10515178b --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Contexts/IdentityContext.cs @@ -0,0 +1,41 @@ +using MiniSpace.Services.MediaFiles.Application; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Contexts +{ + internal class IdentityContext : IIdentityContext + { + public Guid Id { get; } + public string Role { get; } = string.Empty; + public string Name { get; } = string.Empty; + public string Email { get; } = string.Empty; + public bool IsAuthenticated { get; } + public bool IsAdmin { get; } + public bool IsBanned { get; } + public bool IsOrganizer { get; } + public IDictionary Claims { get; } = new Dictionary(); + + internal IdentityContext() + { + } + + internal IdentityContext(CorrelationContext.UserContext context) + : this(context.Id, context.Role, context.IsAuthenticated, context.Claims) + { + } + + internal IdentityContext(string id, string role, bool isAuthenticated, IDictionary claims) + { + Id = Guid.TryParse(id, out var userId) ? userId : Guid.Empty; + Role = role ?? string.Empty; + IsAuthenticated = isAuthenticated; + IsAdmin = Role.Equals("admin", StringComparison.InvariantCultureIgnoreCase); + IsBanned = Role.Equals("banned", StringComparison.InvariantCultureIgnoreCase); + IsOrganizer = Role.Equals("organizer", StringComparison.InvariantCultureIgnoreCase); + Claims = claims ?? new Dictionary(); + Name = Claims.TryGetValue("name", out var name) ? name : string.Empty; + Email = Claims.TryGetValue("email", out var email) ? email : string.Empty; + } + + internal static IIdentityContext Empty => new IdentityContext(); + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Decorators/OutboxCommandHandlerDecorator.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Decorators/OutboxCommandHandlerDecorator.cs new file mode 100644 index 000000000..cce8e588e --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Decorators/OutboxCommandHandlerDecorator.cs @@ -0,0 +1,35 @@ +using Convey.CQRS.Commands; +using Convey.MessageBrokers; +using Convey.MessageBrokers.Outbox; +using Convey.Types; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Decorators +{ + [Decorator] + internal sealed class OutboxCommandHandlerDecorator : ICommandHandler + where TCommand : class, ICommand + { + private readonly ICommandHandler _handler; + private readonly IMessageOutbox _outbox; + private readonly string _messageId; + private readonly bool _enabled; + + public OutboxCommandHandlerDecorator(ICommandHandler handler, IMessageOutbox outbox, + OutboxOptions outboxOptions, IMessagePropertiesAccessor messagePropertiesAccessor) + { + _handler = handler; + _outbox = outbox; + _enabled = outboxOptions.Enabled; + + var messageProperties = messagePropertiesAccessor.MessageProperties; + _messageId = string.IsNullOrWhiteSpace(messageProperties?.MessageId) + ? Guid.NewGuid().ToString("N") + : messageProperties.MessageId; + } + + public Task HandleAsync(TCommand command, CancellationToken cancellationToken) + => _enabled + ? _outbox.HandleAsync(_messageId, () => _handler.HandleAsync(command)) + : _handler.HandleAsync(command); + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Decorators/OutboxEventHandlerDecorator.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Decorators/OutboxEventHandlerDecorator.cs new file mode 100644 index 000000000..2fe4847f6 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Decorators/OutboxEventHandlerDecorator.cs @@ -0,0 +1,35 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; +using Convey.MessageBrokers.Outbox; +using Convey.Types; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Decorators +{ + [Decorator] + internal sealed class OutboxEventHandlerDecorator : IEventHandler + where TEvent : class, IEvent + { + private readonly IEventHandler _handler; + private readonly IMessageOutbox _outbox; + private readonly string _messageId; + private readonly bool _enabled; + + public OutboxEventHandlerDecorator(IEventHandler handler, IMessageOutbox outbox, + OutboxOptions outboxOptions, IMessagePropertiesAccessor messagePropertiesAccessor) + { + _handler = handler; + _outbox = outbox; + _enabled = outboxOptions.Enabled; + + var messageProperties = messagePropertiesAccessor.MessageProperties; + _messageId = string.IsNullOrWhiteSpace(messageProperties?.MessageId) + ? Guid.NewGuid().ToString("N") + : messageProperties.MessageId; + } + + public Task HandleAsync(TEvent @event, CancellationToken cancellationToken) + => _enabled + ? _outbox.HandleAsync(_messageId, () => _handler.HandleAsync(@event)) + : _handler.HandleAsync(@event); + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Exceptions/ExceptionToMessageMapper.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Exceptions/ExceptionToMessageMapper.cs new file mode 100644 index 000000000..1909a49f7 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Exceptions/ExceptionToMessageMapper.cs @@ -0,0 +1,93 @@ +using Convey.MessageBrokers.RabbitMQ; +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Application.Events.Rejected; +using MiniSpace.Services.MediaFiles.Application.Events.External; +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Core.Exceptions; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Exceptions +{ + internal sealed class ExceptionToMessageMapper : IExceptionToMessageMapper + { + public object Map(Exception exception, object message) + => exception switch + + { + CannotChangeStudentStateException ex => message switch + { + ChangeStudentState _ => new ChangeStudentStateRejected(ex.Id, + ex.State.ToString().ToLowerInvariant(), ex.Message, ex.Code), + CompleteStudentRegistration _ => new CompleteStudentRegistrationRejected(ex.Id, ex.Message, + ex.Code), + _ => null + }, + CannotUpdateStudentException ex => message switch + { + UpdateStudent command => new UpdateStudentRejected(command.StudentId, ex.Message, ex.Code), + _ => null, + }, + InvalidStudentDateOfBirthException ex => message switch + { + CompleteStudentRegistration _ => new CompleteStudentRegistrationRejected(ex.Id, ex.Message, + ex.Code), + _ => null, + }, + InvalidStudentDescriptionException ex => message switch + { + CompleteStudentRegistration _ => new CompleteStudentRegistrationRejected(ex.Id, ex.Message, + ex.Code), + UpdateStudent command => new UpdateStudentRejected(command.StudentId, ex.Message, ex.Code), + _ => null, + }, + InvalidStudentFullNameException ex => message switch + { + CompleteStudentRegistration _ => new CompleteStudentRegistrationRejected(ex.Id, ex.Message, + ex.Code), + _ => null, + }, + InvalidStudentProfileImageException ex => message switch + { + CompleteStudentRegistration _ => new CompleteStudentRegistrationRejected(ex.Id, ex.Message, + ex.Code), + UpdateStudent command => new UpdateStudentRejected(command.StudentId, ex.Message, ex.Code), + _ => null, + }, + InvalidRoleException ex => message switch + { + SignedUp ev => new CreateStudentRejected(ev.UserId, ex.Message, ex.Code), + _ => null, + }, + StudentAlreadyCreatedException ex => message switch + { + SignedUp ev => new CreateStudentRejected(ev.UserId, ex.Message, ex.Code), + _ => null, + }, + StudentAlreadyRegisteredException ex => message switch + { + CompleteStudentRegistration _ => new CompleteStudentRegistrationRejected(ex.Id, ex.Message, + ex.Code), + _ => null, + }, + StudentNotFoundException ex => message switch + { + CompleteStudentRegistration _ => new CompleteStudentRegistrationRejected(ex.Id, ex.Message, + ex.Code), + DeleteStudent command => new DeleteStudentRejected(command.StudentId, ex.Message, ex.Code), + UpdateStudent command => new UpdateStudentRejected(command.StudentId, ex.Message, ex.Code), + _ => null, + }, + StudentStateAlreadySetException ex => message switch + { + ChangeStudentState _ => new ChangeStudentStateRejected(ex.Id, + ex.State.ToString().ToLowerInvariant(), ex.Message, ex.Code), + _ => null + }, + UnauthorizedStudentAccessException ex => message switch + { + DeleteStudent command => new DeleteStudentRejected(command.StudentId, ex.Message, ex.Code), + _ => null, + }, + _ => null + }; + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Exceptions/ExceptionToResponseMapper.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Exceptions/ExceptionToResponseMapper.cs new file mode 100644 index 000000000..48a0dab98 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Exceptions/ExceptionToResponseMapper.cs @@ -0,0 +1,46 @@ +using System.Collections.Concurrent; +using System.Net; +using Convey; +using Convey.WebApi.Exceptions; +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Core.Exceptions; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Exceptions +{ + internal sealed class ExceptionToResponseMapper : IExceptionToResponseMapper + { + private static readonly ConcurrentDictionary Codes = new ConcurrentDictionary(); + + public ExceptionResponse Map(Exception exception) + => exception switch + { + DomainException ex => new ExceptionResponse(new {code = GetCode(ex), reason = ex.Message}, + HttpStatusCode.BadRequest), + AppException ex => new ExceptionResponse(new {code = GetCode(ex), reason = ex.Message}, + HttpStatusCode.BadRequest), + _ => new ExceptionResponse(new {code = "error", reason = "There was an error."}, + HttpStatusCode.BadRequest) + }; + + private static string GetCode(Exception exception) + { + var type = exception.GetType(); + if (Codes.TryGetValue(type, out var code)) + { + return code; + } + + var exceptionCode = exception switch + { + DomainException domainException when !string.IsNullOrWhiteSpace(domainException.Code) => domainException + .Code, + AppException appException when !string.IsNullOrWhiteSpace(appException.Code) => appException.Code, + _ => exception.GetType().Name.Underscore().Replace("_exception", string.Empty) + }; + + Codes.TryAdd(type, exceptionCode); + + return exceptionCode; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs new file mode 100644 index 000000000..5c0541209 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs @@ -0,0 +1,140 @@ +using System.Text; +using Convey; +using Convey.CQRS.Commands; +using Convey.CQRS.Events; +using Convey.CQRS.Queries; +using Convey.Discovery.Consul; +using Convey.Docs.Swagger; +using Convey.HTTP; +using Convey.LoadBalancing.Fabio; +using Convey.MessageBrokers; +using Convey.MessageBrokers.CQRS; +using Convey.MessageBrokers.Outbox; +using Convey.MessageBrokers.Outbox.Mongo; +using Convey.MessageBrokers.RabbitMQ; +using Convey.Metrics.AppMetrics; +using Convey.Persistence.MongoDB; +using Convey.Persistence.Redis; +using Convey.Security; +using Convey.Tracing.Jaeger; +using Convey.Tracing.Jaeger.RabbitMQ; +using Convey.WebApi; +using Convey.WebApi.CQRS; +using Convey.WebApi.Security; +using Convey.WebApi.Swagger; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using MiniSpace.Services.MediaFiles.Application; +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Application.Events.External; +using MiniSpace.Services.MediaFiles.Application.Events.External.Handlers; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Repositories; +using MiniSpace.Services.MediaFiles.Infrastructure.Contexts; +using MiniSpace.Services.MediaFiles.Infrastructure.Decorators; +using MiniSpace.Services.MediaFiles.Infrastructure.Exceptions; +using MiniSpace.Services.MediaFiles.Infrastructure.Logging; +using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; +using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Repositories; +using MiniSpace.Services.MediaFiles.Infrastructure.Services; + +namespace MiniSpace.Services.MediaFiles.Infrastructure +{ + public static class Extensions + { + public static IConveyBuilder AddInfrastructure(this IConveyBuilder builder) + { + builder.Services.AddTransient(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(ctx => ctx.GetRequiredService().Create()); + builder.Services.TryDecorate(typeof(ICommandHandler<>), typeof(OutboxCommandHandlerDecorator<>)); + builder.Services.TryDecorate(typeof(IEventHandler<>), typeof(OutboxEventHandlerDecorator<>)); + + return builder + .AddErrorHandler() + .AddQueryHandlers() + .AddInMemoryQueryDispatcher() + .AddHttpClient() + .AddConsul() + .AddFabio() + .AddRabbitMq(plugins: p => p.AddJaegerRabbitMqPlugin()) + .AddMessageOutbox(o => o.AddMongo()) + .AddExceptionToMessageMapper() + .AddMongo() + .AddRedis() + .AddMetrics() + .AddJaeger() + .AddHandlersLogging() + .AddMongoRepository("students") + .AddWebApiSwaggerDocs() + .AddCertificateAuthentication() + .AddSecurity(); + } + + public static IApplicationBuilder UseInfrastructure(this IApplicationBuilder app) + { + app.UseErrorHandler() + .UseSwaggerDocs() + .UseJaeger() + .UseConvey() + .UsePublicContracts() + .UseMetrics() + .UseCertificateAuthentication() + .UseRabbitMq() + .SubscribeCommand() + .SubscribeCommand() + .SubscribeCommand() + .SubscribeCommand() + .SubscribeEvent() + .SubscribeEvent() + .SubscribeEvent() + .SubscribeEvent() + .SubscribeEvent() + .SubscribeEvent() + .SubscribeEvent(); + + return app; + } + + internal static CorrelationContext GetCorrelationContext(this IHttpContextAccessor accessor) + => accessor.HttpContext?.Request.Headers.TryGetValue("Correlation-Context", out var json) is true + ? JsonConvert.DeserializeObject(json.FirstOrDefault()) + : null; + + internal static IDictionary GetHeadersToForward(this IMessageProperties messageProperties) + { + const string sagaHeader = "Saga"; + if (messageProperties?.Headers is null || !messageProperties.Headers.TryGetValue(sagaHeader, out var saga)) + { + return null; + } + + return saga is null + ? null + : new Dictionary + { + [sagaHeader] = saga + }; + } + + internal static string GetSpanContext(this IMessageProperties messageProperties, string header) + { + if (messageProperties is null) + { + return string.Empty; + } + + if (messageProperties.Headers.TryGetValue(header, out var span) && span is byte[] spanBytes) + { + return Encoding.UTF8.GetString(spanBytes); + } + + return string.Empty; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/IAppContextFactory.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/IAppContextFactory.cs new file mode 100644 index 000000000..f6a451f19 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/IAppContextFactory.cs @@ -0,0 +1,9 @@ +using MiniSpace.Services.MediaFiles.Application; + +namespace MiniSpace.Services.MediaFiles.Infrastructure +{ + public interface IAppContextFactory + { + IAppContext Create(); + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/Extensions.cs new file mode 100644 index 000000000..51efcb88e --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/Extensions.cs @@ -0,0 +1,21 @@ +using Convey; +using Convey.Logging.CQRS; +using Microsoft.Extensions.DependencyInjection; +using MiniSpace.Services.MediaFiles.Application.Commands; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Logging +{ + internal static class Extensions + { + public static IConveyBuilder AddHandlersLogging(this IConveyBuilder builder) + { + var assembly = typeof(UpdateStudent).Assembly; + + builder.Services.AddSingleton(new MessageToLogTemplateMapper()); + + return builder + .AddCommandHandlersLogging(assembly) + .AddEventHandlersLogging(assembly); + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs new file mode 100644 index 000000000..4395c971a --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs @@ -0,0 +1,86 @@ +using Convey.Logging.CQRS; +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Application.Events.External; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Logging +{ + internal sealed class MessageToLogTemplateMapper : IMessageToLogTemplateMapper + { + private static IReadOnlyDictionary MessageTemplates + => new Dictionary + { + { + typeof(UpdateStudent), new HandlerLogTemplate + { + After = "Updated the student with id: {StudentId}." + } + }, + { + typeof(DeleteStudent), new HandlerLogTemplate + { + After = "Deleted the student with id: {StudentId}." + } + }, + { + typeof(CompleteStudentRegistration), new HandlerLogTemplate + { + After = "Completed a registration for the student with id: {StudentId}." + } + }, + { + typeof(ChangeStudentState), new HandlerLogTemplate + { + After = "Changed a student with id: {StudentId} state to: {State}." + } + }, + { + typeof(SignedUp), new HandlerLogTemplate + { + After = "Created a new student with id: {UserId}." + } + }, + { + typeof(StudentShowedInterestInEvent), new HandlerLogTemplate + { + After = "A student with id: {StudentId} has been interested in the event with id: {EventId}." + } + }, + { + typeof(StudentSignedUpToEvent), new HandlerLogTemplate + { + After = "A student with id: {StudentId} has signed up for the event with id: {EventId}." + } + }, + { + typeof(UserBanned), new HandlerLogTemplate + { + After = "A student with id: {UserId} has been banned." + } + }, + { + typeof(UserUnbanned), new HandlerLogTemplate + { + After = "A student with id: {UserId} has been unbanned." + } + }, + { + typeof(OrganizerRightsGranted), new HandlerLogTemplate + { + After = "Organizer rights has been granted for student with id: {UserId}." + } + }, + { + typeof(OrganizerRightsRevoked), new HandlerLogTemplate + { + After = "Organizer rights has been revoked for student with id: {UserId}." + } + } + }; + + public HandlerLogTemplate Map(TMessage message) where TMessage : class + { + var key = message.GetType(); + return MessageTemplates.TryGetValue(key, out var template) ? template : null; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/MiniSpace.Services.MediaFiles.Infrastructure.csproj b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/MiniSpace.Services.MediaFiles.Infrastructure.csproj index f86302bcf..ff97df7c1 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/MiniSpace.Services.MediaFiles.Infrastructure.csproj +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/MiniSpace.Services.MediaFiles.Infrastructure.csproj @@ -33,7 +33,7 @@ - + diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs new file mode 100644 index 000000000..66eb0444d --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs @@ -0,0 +1,55 @@ +using MiniSpace.Services.MediaFiles.Application.Dto; +using MiniSpace.Services.MediaFiles.Core.Entities; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents +{ + public static class Extensions + { + public static Student AsEntity(this StudentDocument document) + => new Student(document.Id, document.Email, document.CreatedAt, document.FirstName, + document.LastName, document.NumberOfFriends, document.ProfileImage, + document.Description, document.DateOfBirth, document.EmailNotifications, + document.IsBanned, document.IsOrganizer, document.State, + document.InterestedInEvents, document.SignedUpEvents); + + public static StudentDocument AsDocument(this Student entity) + => new StudentDocument() + { + Id = entity.Id, + Email = entity.Email, + FirstName = entity.FirstName, + LastName = entity.LastName, + NumberOfFriends = entity.NumberOfFriends, + ProfileImage = entity.ProfileImage, + Description = entity.Description, + DateOfBirth = entity.DateOfBirth, + EmailNotifications = entity.EmailNotifications, + IsBanned = entity.IsBanned, + IsOrganizer = entity.IsOrganizer, + State = entity.State, + CreatedAt = entity.CreatedAt, + InterestedInEvents = entity.InterestedInEvents, + SignedUpEvents = entity.SignedUpEvents + }; + + public static StudentDto AsDto(this StudentDocument document) + => new StudentDto() + { + Id = document.Id, + Email = document.Email, + FirstName = document.FirstName, + LastName = document.LastName, + NumberOfFriends = document.NumberOfFriends, + ProfileImage = document.ProfileImage, + Description = document.Description, + DateOfBirth = document.DateOfBirth, + EmailNotifications = document.EmailNotifications, + IsBanned = document.IsBanned, + IsOrganizer = document.IsOrganizer, + State = document.State.ToString().ToLowerInvariant(), + CreatedAt = document.CreatedAt, + InterestedInEvents = document.InterestedInEvents, + SignedUpEvents = document.SignedUpEvents + }; + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/StudentDocument.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/StudentDocument.cs new file mode 100644 index 000000000..840e02917 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/StudentDocument.cs @@ -0,0 +1,24 @@ +using Convey.Types; +using MiniSpace.Services.MediaFiles.Core.Entities; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents +{ + public class StudentDocument : IIdentifiable + { + public Guid Id { get; set; } + public string Email { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public int NumberOfFriends { get; set; } + public string ProfileImage { get; set; } + public string Description { get; set; } + public DateTime? DateOfBirth { get; set; } + public bool EmailNotifications { get; set; } + public bool IsBanned { get; set; } + public bool IsOrganizer { get; set; } + public State State { get; set; } + public DateTime CreatedAt { get; set; } + public IEnumerable InterestedInEvents { get; set; } + public IEnumerable SignedUpEvents { get; set; } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentEventsHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentEventsHandler.cs new file mode 100644 index 000000000..6fe8210a0 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentEventsHandler.cs @@ -0,0 +1,36 @@ +using Convey.CQRS.Queries; +using Convey.Persistence.MongoDB; +using MiniSpace.Services.MediaFiles.Application.Dto; +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Application.Queries; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Queries.Handlers +{ + public class GetStudentEventsHandler : IQueryHandler + { + private readonly IMongoRepository _studentRepository; + + public GetStudentEventsHandler(IMongoRepository repository) + => _studentRepository = repository; + + public async Task HandleAsync(GetStudentEvents query, CancellationToken cancellationToken) + { + var document = await _studentRepository.GetAsync(p => p.Id == query.StudentId); + if(document is null) + { + throw new StudentNotFoundException(query.StudentId); + } + + var studentEvents = new StudentEventsDto() + { + StudentId = document.Id, + InterestedInEvents = document.InterestedInEvents, + SignedUpEvents = document.SignedUpEvents + }; + + return studentEvents; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentHandler.cs new file mode 100644 index 000000000..a907378cd --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentHandler.cs @@ -0,0 +1,25 @@ +using Convey.CQRS.Queries; +using Convey.Persistence.MongoDB; +using MiniSpace.Services.MediaFiles.Application.Dto; +using MiniSpace.Services.MediaFiles.Application.Queries; +using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Queries.Handlers +{ + public class GetStudentHandler : IQueryHandler + { + private readonly IMongoRepository _studentRepository; + + public GetStudentHandler(IMongoRepository studentRepository) + { + _studentRepository = studentRepository; + } + + public async Task HandleAsync(GetStudent query, CancellationToken cancellationToken) + { + var document = await _studentRepository.GetAsync(p => p.Id == query.StudentId); + + return document?.AsDto(); + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentsHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentsHandler.cs new file mode 100644 index 000000000..f9aa08db8 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentsHandler.cs @@ -0,0 +1,25 @@ +using Convey.CQRS.Queries; +using Convey.Persistence.MongoDB; +using MiniSpace.Services.MediaFiles.Application.Dto; +using MiniSpace.Services.MediaFiles.Application.Queries; +using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Queries.Handlers +{ + public class GetStudentsHandler : IQueryHandler> + { + private readonly IMongoRepository _studentRepository; + + public GetStudentsHandler(IMongoRepository studentRepository) + { + _studentRepository = studentRepository; + } + + public async Task> HandleAsync(GetStudents query, CancellationToken cancellationToken) + { + var students = await _studentRepository.FindAsync(_ => true); + + return students.Select(p => p.AsDto()); + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/StudentMongoRepository.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/StudentMongoRepository.cs new file mode 100644 index 000000000..8002609e8 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/StudentMongoRepository.cs @@ -0,0 +1,33 @@ +using Convey.Persistence.MongoDB; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Core.Repositories; +using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Repositories +{ + public class StudentMongoRepository : IStudentRepository + { + private readonly IMongoRepository _repository; + + public StudentMongoRepository(IMongoRepository repository) + { + _repository = repository; + } + + public async Task GetAsync(Guid id) + { + var student = await _repository.GetAsync(o => o.Id == id); + + return student?.AsEntity(); + } + + public Task AddAsync(Student student) + => _repository.AddAsync(student.AsDocument()); + + public Task UpdateAsync(Student student) + => _repository.UpdateAsync(student.AsDocument()); + + public Task DeleteAsync(Guid id) + => _repository.DeleteAsync(id); + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/DateTimeProvider.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/DateTimeProvider.cs new file mode 100644 index 000000000..539d6089b --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/DateTimeProvider.cs @@ -0,0 +1,9 @@ +using MiniSpace.Services.MediaFiles.Application.Services; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Services +{ + internal sealed class DateTimeProvider : IDateTimeProvider + { + public DateTime Now => DateTime.UtcNow; + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/EventMapper.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/EventMapper.cs new file mode 100644 index 000000000..891e1042c --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/EventMapper.cs @@ -0,0 +1,29 @@ +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core; +using MiniSpace.Services.MediaFiles.Core.Events; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Services +{ + public class EventMapper : IEventMapper + { + public IEnumerable MapAll(IEnumerable events) + => events.Select(Map); + + public IEvent Map(IDomainEvent @event) + { + switch (@event) + { + case StudentRegistrationCompleted e: + return new Application.Events.StudentCreated(e.Student.Id, e.Student.FullName); + case StudentUpdated e: + return new Application.Events.StudentUpdated(e.Student.Id, e.Student.FullName); + case StudentStateChanged e: + return new Application.Events.StudentStateChanged(e.Student.Id, e.Student.FullName, + e.Student.State.ToString().ToLowerInvariant(), e.PreviousState.ToString().ToLowerInvariant()); + } + + return null; + } + } +} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/MessageBroker.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/MessageBroker.cs new file mode 100644 index 000000000..5c35834ef --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/MessageBroker.cs @@ -0,0 +1,84 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; +using Convey.MessageBrokers.Outbox; +using Convey.MessageBrokers.RabbitMQ; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using OpenTracing; +using MiniSpace.Services.MediaFiles.Application.Services; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Services +{ + internal sealed class MessageBroker : IMessageBroker + { + private const string DefaultSpanContextHeader = "span_context"; + private readonly IBusPublisher _busPublisher; + private readonly IMessageOutbox _outbox; + private readonly ICorrelationContextAccessor _contextAccessor; + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly IMessagePropertiesAccessor _messagePropertiesAccessor; + private readonly ITracer _tracer; + private readonly ILogger _logger; + private readonly string _spanContextHeader; + + public MessageBroker(IBusPublisher busPublisher, IMessageOutbox outbox, + ICorrelationContextAccessor contextAccessor, IHttpContextAccessor httpContextAccessor, + IMessagePropertiesAccessor messagePropertiesAccessor, RabbitMqOptions options, ITracer tracer, + ILogger logger) + { + _busPublisher = busPublisher; + _outbox = outbox; + _contextAccessor = contextAccessor; + _httpContextAccessor = httpContextAccessor; + _messagePropertiesAccessor = messagePropertiesAccessor; + _tracer = tracer; + _logger = logger; + _spanContextHeader = string.IsNullOrWhiteSpace(options.SpanContextHeader) + ? DefaultSpanContextHeader + : options.SpanContextHeader; + } + + public Task PublishAsync(params IEvent[] events) => PublishAsync(events?.AsEnumerable()); + + public async Task PublishAsync(IEnumerable events) + { + if (events is null) + { + return; + } + + var messageProperties = _messagePropertiesAccessor.MessageProperties; + var originatedMessageId = messageProperties?.MessageId; + var correlationId = messageProperties?.CorrelationId; + var spanContext = messageProperties?.GetSpanContext(_spanContextHeader); + if (string.IsNullOrWhiteSpace(spanContext)) + { + spanContext = _tracer.ActiveSpan is null ? string.Empty : _tracer.ActiveSpan.Context.ToString(); + } + + var headers = messageProperties.GetHeadersToForward(); + var correlationContext = _contextAccessor.CorrelationContext ?? + _httpContextAccessor.GetCorrelationContext(); + + foreach (var @event in events) + { + if (@event is null) + { + continue; + } + + var messageId = Guid.NewGuid().ToString("N"); + _logger.LogTrace($"Publishing integration event: {@event.GetType().Name} [id: '{messageId}']."); + if (_outbox.Enabled) + { + await _outbox.SendAsync(@event, originatedMessageId, messageId, correlationId, spanContext, + correlationContext, headers); + continue; + } + + await _busPublisher.PublishAsync(@event, messageId, correlationId, spanContext, correlationContext, + headers); + } + } + } +} From e43b14fdaa6c1387ebe9390154444e1535c45e1f Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 4 May 2024 19:04:04 +0200 Subject: [PATCH 04/62] (#92) remove unnecessary files --- .../Program.cs | 10 +- .../Commands/ChangeStudentState.cs | 16 -- .../Commands/CompleteStudentRegistration.cs | 23 --- .../Commands/DeleteStudent.cs | 11 -- .../Handlers/ChangeStudentStateHandler.cs | 63 ------- .../CompleteStudentRegistrationHandler.cs | 46 ----- .../Commands/Handlers/DeleteStudentHandler.cs | 42 ----- .../Commands/Handlers/UpdateStudentHandler.cs | 45 ----- .../Commands/UpdateStudent.cs | 20 -- .../Dto/StudentDto.cs | 21 --- .../Dto/StudentEventsDto.cs | 9 - .../Handlers/OrganizerRightsGrantedHandler.cs | 37 ---- .../Handlers/OrganizerRightsRevokedHandler.cs | 37 ---- .../External/Handlers/SignedUpHandler.cs | 43 ----- .../StudentShowedInterestInEventHandler.cs | 37 ---- .../Handlers/StudentSignedUpToEventHandler.cs | 37 ---- .../External/Handlers/UserBannedHandler.cs | 37 ---- .../External/Handlers/UserUnbannedHandler.cs | 37 ---- .../Events/External/OrganizerRightsGranted.cs | 15 -- .../Events/External/OrganizerRightsRevoked.cs | 15 -- .../Events/External/SignedUp.cs | 24 --- .../External/StudentShowedInterestInEvent.cs | 18 -- .../Events/External/StudentSignedUpToEvent.cs | 18 -- .../Events/External/UserBanned.cs | 11 -- .../Events/External/UserUnbanned.cs | 11 -- .../Rejected/ChangeStudentStateRejected.cs | 20 -- .../CompleteStudentRegistrationRejected.cs | 19 -- .../Events/Rejected/CreateStudentRejected.cs | 18 -- .../Events/Rejected/DeleteStudentRejected.cs | 18 -- .../Events/Rejected/UpdateStudentRejected.cs | 18 -- .../Events/StudentCreated.cs | 16 -- .../Events/StudentDeleted.cs | 16 -- .../Events/StudentStateChanged.cs | 20 -- .../Events/StudentUpdated.cs | 16 -- .../Exceptions/InvalidRoleException.cs | 13 -- .../StudentAlreadyCreatedException.cs | 14 -- .../StudentAlreadyRegisteredException.cs | 14 -- .../Exceptions/StudentNotFoundException.cs | 13 -- .../UnauthorizedStudentAccessException.cs | 16 -- .../Queries/GetStudent.cs | 10 - .../Queries/GetStudentEvents.cs | 10 - .../Queries/GetStudents.cs | 9 - .../Entities/State.cs | 10 - .../Entities/Student.cs | 171 ------------------ .../Events/StudentRegistrationCompleted.cs | 14 -- .../Events/StudentStateChanged.cs | 16 -- .../Events/StudentUpdated.cs | 14 -- .../CannotChangeStudentStateException.cs | 18 -- .../CannotUpdateStudentException.cs | 16 -- .../Exceptions/InvalidAggregateIdException.cs | 11 -- .../InvalidStudentDateOfBirthException.cs | 19 -- .../InvalidStudentDescriptionException.cs | 16 -- .../InvalidStudentFullNameException.cs | 16 -- .../InvalidStudentProfileImageException.cs | 16 -- .../StudentStateAlreadySetException.cs | 18 -- .../Repositories/IStudentRepository.cs | 12 -- .../Mongo/Documents/Extensions.cs | 55 ------ .../Mongo/Documents/StudentDocument.cs | 24 --- .../Handlers/GetStudentEventsHandler.cs | 36 ---- .../Queries/Handlers/GetStudentHandler.cs | 25 --- .../Queries/Handlers/GetStudentsHandler.cs | 25 --- .../Repositories/StudentMongoRepository.cs | 33 ---- 62 files changed, 1 insertion(+), 1507 deletions(-) delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/ChangeStudentState.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/CompleteStudentRegistration.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/DeleteStudent.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/ChangeStudentStateHandler.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CompleteStudentRegistrationHandler.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteStudentHandler.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UpdateStudentHandler.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UpdateStudent.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentDto.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentEventsDto.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsGrantedHandler.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsRevokedHandler.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/SignedUpHandler.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentShowedInterestInEventHandler.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentSignedUpToEventHandler.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserBannedHandler.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserUnbannedHandler.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsGranted.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsRevoked.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/SignedUp.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentShowedInterestInEvent.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentSignedUpToEvent.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserBanned.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserUnbanned.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/ChangeStudentStateRejected.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CompleteStudentRegistrationRejected.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CreateStudentRejected.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/DeleteStudentRejected.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/UpdateStudentRejected.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentCreated.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentDeleted.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentStateChanged.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentUpdated.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidRoleException.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyCreatedException.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyRegisteredException.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentNotFoundException.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedStudentAccessException.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudent.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudentEvents.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudents.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/State.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/Student.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentRegistrationCompleted.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentStateChanged.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentUpdated.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotChangeStudentStateException.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotUpdateStudentException.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidAggregateIdException.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDateOfBirthException.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDescriptionException.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentFullNameException.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentProfileImageException.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/StudentStateAlreadySetException.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IStudentRepository.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/StudentDocument.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentEventsHandler.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentHandler.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentsHandler.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/StudentMongoRepository.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs index a69138c27..a4e56e2a8 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs @@ -31,15 +31,7 @@ public static async Task Main(string[] args) .UseInfrastructure() .UseDispatcherEndpoints(endpoints => endpoints .Get("", ctx => ctx.Response.WriteAsync(ctx.RequestServices.GetService().Name)) - .Get>("students") - .Get("students/{studentId}") - .Put("students/{studentId}") - .Delete("students/{studentId}") - .Post("students", - afterDispatch: (cmd, ctx) => ctx.Response.Created($"students/{cmd.StudentId}")) - .Put("students/{studentId}/state/{state}", - afterDispatch: (cmd, ctx) => ctx.Response.NoContent()) - .Get("students/{studentId}/events"))) + )) .UseLogging() .Build() .RunAsync(); diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/ChangeStudentState.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/ChangeStudentState.cs deleted file mode 100644 index a222434de..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/ChangeStudentState.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Convey.CQRS.Commands; - -namespace MiniSpace.Services.MediaFiles.Application.Commands -{ - public class ChangeStudentState : ICommand - { - public Guid StudentId { get; } - public string State { get; } - - public ChangeStudentState(Guid studentId, string state) - { - StudentId = studentId; - State = state; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/CompleteStudentRegistration.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/CompleteStudentRegistration.cs deleted file mode 100644 index 136ab2041..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/CompleteStudentRegistration.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Convey.CQRS.Commands; - -namespace MiniSpace.Services.MediaFiles.Application.Commands -{ - public class CompleteStudentRegistration : ICommand - { - public Guid StudentId { get; } - public string ProfileImage { get; } - public string Description { get; } - public DateTime DateOfBirth { get; } - public bool EmailNotifications { get; } - - public CompleteStudentRegistration(Guid studentId, string profileImage, - string description, DateTime dateOfBirth, bool emailNotifications) - { - StudentId = studentId; - ProfileImage = profileImage; - Description = description; - DateOfBirth = dateOfBirth; - EmailNotifications = emailNotifications; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/DeleteStudent.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/DeleteStudent.cs deleted file mode 100644 index 97c223cef..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/DeleteStudent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Convey.CQRS.Commands; - -namespace MiniSpace.Services.MediaFiles.Application.Commands -{ - public class DeleteStudent : ICommand - { - public Guid StudentId { get; } - - public DeleteStudent(Guid studentId) => StudentId = studentId; - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/ChangeStudentStateHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/ChangeStudentStateHandler.cs deleted file mode 100644 index 846350694..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/ChangeStudentStateHandler.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Convey.CQRS.Commands; -using MiniSpace.Services.MediaFiles.Application.Exceptions; -using MiniSpace.Services.MediaFiles.Application.Services; -using MiniSpace.Services.MediaFiles.Core.Entities; -using MiniSpace.Services.MediaFiles.Core.Exceptions; -using MiniSpace.Services.MediaFiles.Core.Repositories; - -namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers -{ - public class ChangeStudentStateHandler : ICommandHandler - { - private readonly IStudentRepository _studentRepository; - private readonly IEventMapper _eventMapper; - private readonly IMessageBroker _messageBroker; - - public ChangeStudentStateHandler(IStudentRepository studentRepository, IEventMapper eventMapper, - IMessageBroker messageBroker) - { - _studentRepository = studentRepository; - _eventMapper = eventMapper; - _messageBroker = messageBroker; - } - - public async Task HandleAsync(ChangeStudentState command, CancellationToken cancellationToken = default) - { - var student = await _studentRepository.GetAsync(command.StudentId); - if (student is null) - { - throw new StudentNotFoundException(command.StudentId); - } - - if (!Enum.TryParse(command.State, true, out var state)) - { - throw new CannotChangeStudentStateException(student.Id, State.Unknown); - } - - if (student.State == state) - { - throw new StudentStateAlreadySetException(student.Id, state); - } - - switch (state) - { - case State.Incomplete: - student.SetIncomplete(); - break; - case State.Valid: - student.SetValid(); - break; - case State.Banned: - student.SetBanned(); - break; - default: - throw new CannotChangeStudentStateException(student.Id, state); - } - - await _studentRepository.UpdateAsync(student); - - var events = _eventMapper.MapAll(student.Events); - await _messageBroker.PublishAsync(events.ToArray()); - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CompleteStudentRegistrationHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CompleteStudentRegistrationHandler.cs deleted file mode 100644 index d806d2ffa..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CompleteStudentRegistrationHandler.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Convey.CQRS.Commands; -using MiniSpace.Services.MediaFiles.Application.Exceptions; -using MiniSpace.Services.MediaFiles.Application.Services; -using MiniSpace.Services.MediaFiles.Core.Exceptions; -using MiniSpace.Services.MediaFiles.Core.Repositories; - -namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers -{ - public class CompleteStudentRegistrationHandler : ICommandHandler - { - private readonly IStudentRepository _studentRepository; - private readonly IDateTimeProvider _dateTimeProvider; - private readonly IEventMapper _eventMapper; - private readonly IMessageBroker _messageBroker; - - public CompleteStudentRegistrationHandler(IStudentRepository studentRepository, - IDateTimeProvider dateTimeProvider, IEventMapper eventMapper, IMessageBroker messageBroker) - { - _studentRepository = studentRepository; - _dateTimeProvider = dateTimeProvider; - _eventMapper = eventMapper; - _messageBroker = messageBroker; - } - - public async Task HandleAsync(CompleteStudentRegistration command, CancellationToken cancellationToken = default) - { - var student = await _studentRepository.GetAsync(command.StudentId); - if (student is null) - { - throw new StudentNotFoundException(command.StudentId); - } - - if (student.State is Core.Entities.State.Valid) - { - throw new StudentAlreadyRegisteredException(command.StudentId); - } - - student.CompleteRegistration(command.ProfileImage, command.Description, - command.DateOfBirth, _dateTimeProvider.Now, command.EmailNotifications); - await _studentRepository.UpdateAsync(student); - - var events = _eventMapper.MapAll(student.Events); - await _messageBroker.PublishAsync(events.ToArray()); - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteStudentHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteStudentHandler.cs deleted file mode 100644 index 9c30966a9..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteStudentHandler.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Convey.CQRS.Commands; -using MiniSpace.Services.MediaFiles.Application.Events; -using MiniSpace.Services.MediaFiles.Application.Exceptions; -using MiniSpace.Services.MediaFiles.Application.Services; -using MiniSpace.Services.MediaFiles.Core.Repositories; - -namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers -{ - public class DeleteStudentHandler : ICommandHandler - { - private readonly IStudentRepository _studentRepository; - private readonly IAppContext _appContext; - private readonly IMessageBroker _messageBroker; - - public DeleteStudentHandler(IStudentRepository studentRepository, IAppContext appContext, - IMessageBroker messageBroker) - { - _studentRepository = studentRepository; - _appContext = appContext; - _messageBroker = messageBroker; - } - - public async Task HandleAsync(DeleteStudent command, CancellationToken cancellationToken = default) - { - var student = await _studentRepository.GetAsync(command.StudentId); - if (student is null) - { - throw new StudentNotFoundException(command.StudentId); - } - - var identity = _appContext.Identity; - if (identity.IsAuthenticated && identity.Id != student.Id && !identity.IsAdmin) - { - throw new UnauthorizedStudentAccessException(command.StudentId, identity.Id); - } - - await _studentRepository.DeleteAsync(command.StudentId); - - await _messageBroker.PublishAsync(new StudentDeleted(command.StudentId, student.FullName)); - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UpdateStudentHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UpdateStudentHandler.cs deleted file mode 100644 index 4c366f2e5..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UpdateStudentHandler.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Convey.CQRS.Commands; -using MiniSpace.Services.MediaFiles.Application.Exceptions; -using MiniSpace.Services.MediaFiles.Application.Services; -using MiniSpace.Services.MediaFiles.Core.Repositories; - -namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers -{ - public class UpdateStudentHandler : ICommandHandler - { - private readonly IStudentRepository _studentRepository; - private readonly IAppContext _appContext; - private readonly IEventMapper _eventMapper; - private readonly IMessageBroker _messageBroker; - - public UpdateStudentHandler(IStudentRepository studentRepository, IAppContext appContext, - IEventMapper eventMapper, IMessageBroker messageBroker) - { - _studentRepository = studentRepository; - _appContext = appContext; - _eventMapper = eventMapper; - _messageBroker = messageBroker; - } - - public async Task HandleAsync(UpdateStudent command, CancellationToken cancellationToken = default) - { - var student = await _studentRepository.GetAsync(command.StudentId); - if (student is null) - { - throw new StudentNotFoundException(command.StudentId); - } - - var identity = _appContext.Identity; - if (identity.IsAuthenticated && identity.Id != student.Id && !identity.IsAdmin) - { - throw new UnauthorizedStudentAccessException(command.StudentId, identity.Id); - } - - student.Update(command.ProfileImage, command.Description, command.EmailNotifications); - await _studentRepository.UpdateAsync(student); - - var events = _eventMapper.MapAll(student.Events); - await _messageBroker.PublishAsync(events.ToArray()); - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UpdateStudent.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UpdateStudent.cs deleted file mode 100644 index 941f7c86f..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UpdateStudent.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Convey.CQRS.Commands; - -namespace MiniSpace.Services.MediaFiles.Application.Commands -{ - public class UpdateStudent : ICommand - { - public Guid StudentId { get; } - public string ProfileImage { get; } - public string Description { get; } - public bool EmailNotifications { get; } - - public UpdateStudent(Guid studentId, string profileImage, string description, bool emailNotifications) - { - StudentId = studentId; - ProfileImage = profileImage; - Description = description; - EmailNotifications = emailNotifications; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentDto.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentDto.cs deleted file mode 100644 index a47ef9635..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentDto.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace MiniSpace.Services.MediaFiles.Application.Dto -{ - public class StudentDto - { - public Guid Id { get; set; } - public string Email { get; set; } - public string FirstName { get; set; } - public string LastName { get; set; } - public int NumberOfFriends { get; set; } - public string ProfileImage { get; set; } - public string Description { get; set; } - public DateTime? DateOfBirth { get; set; } - public bool EmailNotifications { get; set; } - public bool IsBanned { get; set; } - public bool IsOrganizer { get; set; } - public string State { get; set; } - public DateTime CreatedAt { get; set; } - public IEnumerable InterestedInEvents { get; set; } - public IEnumerable SignedUpEvents { get; set; } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentEventsDto.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentEventsDto.cs deleted file mode 100644 index 932b7c315..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/StudentEventsDto.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace MiniSpace.Services.MediaFiles.Application.Dto -{ - public class StudentEventsDto - { - public Guid StudentId { get; set; } - public IEnumerable InterestedInEvents { get; set; } - public IEnumerable SignedUpEvents { get; set; } - } -} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsGrantedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsGrantedHandler.cs deleted file mode 100644 index f57936eff..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsGrantedHandler.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Convey.CQRS.Events; -using MiniSpace.Services.MediaFiles.Application.Exceptions; -using MiniSpace.Services.MediaFiles.Application.Services; -using MiniSpace.Services.MediaFiles.Core.Repositories; - -namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers -{ - public class OrganizerRightsGrantedHandler : IEventHandler - { - private readonly IStudentRepository _studentRepository; - private readonly IEventMapper _eventMapper; - private readonly IMessageBroker _messageBroker; - - public OrganizerRightsGrantedHandler(IStudentRepository studentRepository, - IEventMapper eventMapper, IMessageBroker messageBroker) - { - _studentRepository = studentRepository; - _eventMapper = eventMapper; - _messageBroker = messageBroker; - } - - public async Task HandleAsync(OrganizerRightsGranted @event, CancellationToken cancellationToken) - { - var student = await _studentRepository.GetAsync(@event.UserId); - if (student is null) - { - throw new StudentNotFoundException(@event.UserId); - } - - student.GrantOrganizerRights(); - await _studentRepository.UpdateAsync(student); - - var events = _eventMapper.MapAll(student.Events); - await _messageBroker.PublishAsync(events.ToArray()); - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsRevokedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsRevokedHandler.cs deleted file mode 100644 index 8d0089826..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/OrganizerRightsRevokedHandler.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Convey.CQRS.Events; -using MiniSpace.Services.MediaFiles.Application.Exceptions; -using MiniSpace.Services.MediaFiles.Application.Services; -using MiniSpace.Services.MediaFiles.Core.Repositories; - -namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers -{ - public class OrganizerRightsRevokedHandler : IEventHandler - { - private readonly IStudentRepository _studentRepository; - private readonly IEventMapper _eventMapper; - private readonly IMessageBroker _messageBroker; - - public OrganizerRightsRevokedHandler(IStudentRepository studentRepository, - IEventMapper eventMapper, IMessageBroker messageBroker) - { - _studentRepository = studentRepository; - _eventMapper = eventMapper; - _messageBroker = messageBroker; - } - - public async Task HandleAsync(OrganizerRightsRevoked @event, CancellationToken cancellationToken) - { - var student = await _studentRepository.GetAsync(@event.UserId); - if (student is null) - { - throw new StudentNotFoundException(@event.UserId); - } - - student.RevokeOrganizerRights(); - await _studentRepository.UpdateAsync(student); - - var events = _eventMapper.MapAll(student.Events); - await _messageBroker.PublishAsync(events.ToArray()); - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/SignedUpHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/SignedUpHandler.cs deleted file mode 100644 index 9811ba4fe..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/SignedUpHandler.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Convey.CQRS.Events; -using Microsoft.Extensions.Logging; -using MiniSpace.Services.MediaFiles.Application.Exceptions; -using MiniSpace.Services.MediaFiles.Application.Services; -using MiniSpace.Services.MediaFiles.Core.Entities; -using MiniSpace.Services.MediaFiles.Core.Repositories; - -namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers -{ - public class SignedUpHandler : IEventHandler - { - private const string RequiredRole = "user"; - private readonly IStudentRepository _studentRepository; - private readonly IDateTimeProvider _dateTimeProvider; - private readonly ILogger _logger; - - public SignedUpHandler(IStudentRepository studentRepository, IDateTimeProvider dateTimeProvider, - ILogger logger) - { - _studentRepository = studentRepository; - _dateTimeProvider = dateTimeProvider; - _logger = logger; - } - - public async Task HandleAsync(SignedUp @event, CancellationToken cancellationToken = default) - { - if (@event.Role != RequiredRole) - { - throw new InvalidRoleException(@event.UserId, @event.Role, RequiredRole); - } - - var student = await _studentRepository.GetAsync(@event.UserId); - if (student is not null) - { - throw new StudentAlreadyCreatedException(student.Id); - } - - var newStudent = new Student(@event.UserId, @event.FirstName, @event.LastName, - @event.Email, _dateTimeProvider.Now); - await _studentRepository.AddAsync(newStudent); - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentShowedInterestInEventHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentShowedInterestInEventHandler.cs deleted file mode 100644 index 92b2b4bc4..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentShowedInterestInEventHandler.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Convey.CQRS.Events; -using MiniSpace.Services.MediaFiles.Application.Exceptions; -using MiniSpace.Services.MediaFiles.Application.Services; -using MiniSpace.Services.MediaFiles.Core.Repositories; - -namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers -{ - public class StudentShowedInterestInEventHandler : IEventHandler - { - private readonly IStudentRepository _studentRepository; - private readonly IEventMapper _eventMapper; - private readonly IMessageBroker _messageBroker; - - public StudentShowedInterestInEventHandler(IStudentRepository studentRepository, - IEventMapper eventMapper, IMessageBroker messageBroker) - { - _studentRepository = studentRepository; - _eventMapper = eventMapper; - _messageBroker = messageBroker; - } - - public async Task HandleAsync(StudentShowedInterestInEvent @event, CancellationToken cancellationToken) - { - var student = await _studentRepository.GetAsync(@event.StudentId); - if (student is null) - { - throw new StudentNotFoundException(@event.StudentId); - } - - student.AddInterestedInEvent(@event.EventId); - await _studentRepository.UpdateAsync(student); - - var events = _eventMapper.MapAll(student.Events); - await _messageBroker.PublishAsync(events.ToArray()); - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentSignedUpToEventHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentSignedUpToEventHandler.cs deleted file mode 100644 index 5356ca003..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentSignedUpToEventHandler.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Convey.CQRS.Events; -using MiniSpace.Services.MediaFiles.Application.Exceptions; -using MiniSpace.Services.MediaFiles.Application.Services; -using MiniSpace.Services.MediaFiles.Core.Repositories; - -namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers -{ - public class StudentSignedUpToEventHandler : IEventHandler - { - private readonly IStudentRepository _studentRepository; - private readonly IEventMapper _eventMapper; - private readonly IMessageBroker _messageBroker; - - public StudentSignedUpToEventHandler(IStudentRepository studentRepository, - IEventMapper eventMapper, IMessageBroker messageBroker) - { - _studentRepository = studentRepository; - _eventMapper = eventMapper; - _messageBroker = messageBroker; - } - - public async Task HandleAsync(StudentSignedUpToEvent studentSignedUpToEvent, CancellationToken cancellationToken) - { - var student = await _studentRepository.GetAsync(studentSignedUpToEvent.StudentId); - if (student is null) - { - throw new StudentNotFoundException(studentSignedUpToEvent.StudentId); - } - - student.AddSignedUpEvent(studentSignedUpToEvent.EventId); - await _studentRepository.UpdateAsync(student); - - var events = _eventMapper.MapAll(student.Events); - await _messageBroker.PublishAsync(events.ToArray()); - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserBannedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserBannedHandler.cs deleted file mode 100644 index 9fbc8cc46..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserBannedHandler.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Convey.CQRS.Events; -using MiniSpace.Services.MediaFiles.Application.Exceptions; -using MiniSpace.Services.MediaFiles.Application.Services; -using MiniSpace.Services.MediaFiles.Core.Repositories; - -namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers -{ - public class UserBannedHandler : IEventHandler - { - private readonly IStudentRepository _studentRepository; - private readonly IEventMapper _eventMapper; - private readonly IMessageBroker _messageBroker; - - public UserBannedHandler(IStudentRepository studentRepository, - IEventMapper eventMapper, IMessageBroker messageBroker) - { - _studentRepository = studentRepository; - _eventMapper = eventMapper; - _messageBroker = messageBroker; - } - - public async Task HandleAsync(UserBanned @event, CancellationToken cancellationToken) - { - var student = await _studentRepository.GetAsync(@event.UserId); - if (student is null) - { - throw new StudentNotFoundException(@event.UserId); - } - - student.Ban(); - await _studentRepository.UpdateAsync(student); - - var events = _eventMapper.MapAll(student.Events); - await _messageBroker.PublishAsync(events.ToArray()); - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserUnbannedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserUnbannedHandler.cs deleted file mode 100644 index 91ac019fb..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/UserUnbannedHandler.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Convey.CQRS.Events; -using MiniSpace.Services.MediaFiles.Application.Exceptions; -using MiniSpace.Services.MediaFiles.Application.Services; -using MiniSpace.Services.MediaFiles.Core.Repositories; - -namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers -{ - public class UserUnbannedHandler : IEventHandler - { - private readonly IStudentRepository _studentRepository; - private readonly IEventMapper _eventMapper; - private readonly IMessageBroker _messageBroker; - - public UserUnbannedHandler(IStudentRepository studentRepository, - IEventMapper eventMapper, IMessageBroker messageBroker) - { - _studentRepository = studentRepository; - _eventMapper = eventMapper; - _messageBroker = messageBroker; - } - - public async Task HandleAsync(UserUnbanned @event, CancellationToken cancellationToken) - { - var student = await _studentRepository.GetAsync(@event.UserId); - if (student is null) - { - throw new StudentNotFoundException(@event.UserId); - } - - student.Unban(); - await _studentRepository.UpdateAsync(student); - - var events = _eventMapper.MapAll(student.Events); - await _messageBroker.PublishAsync(events.ToArray()); - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsGranted.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsGranted.cs deleted file mode 100644 index ed819c1ff..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsGranted.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Convey.CQRS.Events; -using Convey.MessageBrokers; - -namespace MiniSpace.Services.MediaFiles.Application.Events.External -{ - [Message("identity")] - public class OrganizerRightsGranted : IEvent - { - public Guid UserId { get; } - public OrganizerRightsGranted(Guid userId) - { - UserId = userId; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsRevoked.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsRevoked.cs deleted file mode 100644 index efe5adfac..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/OrganizerRightsRevoked.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Convey.CQRS.Events; -using Convey.MessageBrokers; - -namespace MiniSpace.Services.MediaFiles.Application.Events.External -{ - [Message("identity")] - public class OrganizerRightsRevoked : IEvent - { - public Guid UserId { get; } - public OrganizerRightsRevoked(Guid userId) - { - UserId = userId; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/SignedUp.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/SignedUp.cs deleted file mode 100644 index 14a3a5032..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/SignedUp.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Convey.CQRS.Events; -using Convey.MessageBrokers; - -namespace MiniSpace.Services.MediaFiles.Application.Events.External -{ - [Message("identity")] - public class SignedUp : IEvent - { - public Guid UserId { get; } - public string FirstName { get; } - public string LastName { get; } - public string Email { get; } - public string Role { get; } - - public SignedUp(Guid userId, string firstName, string lastName, string email, string role) - { - UserId = userId; - FirstName = firstName; - LastName = lastName; - Email = email; - Role = role; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentShowedInterestInEvent.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentShowedInterestInEvent.cs deleted file mode 100644 index 4fe380afd..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentShowedInterestInEvent.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Convey.CQRS.Events; -using Convey.MessageBrokers; - -namespace MiniSpace.Services.MediaFiles.Application.Events.External -{ - [Message("events")] - public class StudentShowedInterestInEvent : IEvent - { - public Guid EventId { get; } - public Guid StudentId { get; } - - public StudentShowedInterestInEvent(Guid eventId, Guid studentId) - { - EventId = eventId; - StudentId = studentId; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentSignedUpToEvent.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentSignedUpToEvent.cs deleted file mode 100644 index 4b8ae6ff5..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentSignedUpToEvent.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Convey.CQRS.Events; -using Convey.MessageBrokers; - -namespace MiniSpace.Services.MediaFiles.Application.Events.External -{ - [Message("events")] - public class StudentSignedUpToEvent : IEvent - { - public Guid EventId { get; } - public Guid StudentId { get; } - - public StudentSignedUpToEvent(Guid eventId, Guid studentId) - { - EventId = eventId; - StudentId = studentId; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserBanned.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserBanned.cs deleted file mode 100644 index cc567c35d..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserBanned.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Convey.CQRS.Events; -using Convey.MessageBrokers; - -namespace MiniSpace.Services.MediaFiles.Application.Events.External -{ - [Message("identity")] - public class UserBanned(Guid userId) : IEvent - { - public Guid UserId { get; } = userId; - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserUnbanned.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserUnbanned.cs deleted file mode 100644 index ec423a19a..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/UserUnbanned.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Convey.CQRS.Events; -using Convey.MessageBrokers; - -namespace MiniSpace.Services.MediaFiles.Application.Events.External -{ - [Message("identity")] - public class UserUnbanned(Guid userId) : IEvent - { - public Guid UserId { get; } = userId; - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/ChangeStudentStateRejected.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/ChangeStudentStateRejected.cs deleted file mode 100644 index 1d31c01dc..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/ChangeStudentStateRejected.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Convey.CQRS.Events; - -namespace MiniSpace.Services.MediaFiles.Application.Events.Rejected -{ - public class ChangeStudentStateRejected : IRejectedEvent - { - public Guid StudentId { get; } - public string State { get; } - public string Reason { get; } - public string Code { get; } - - public ChangeStudentStateRejected(Guid studentId, string state, string reason, string code) - { - StudentId = studentId; - State = state; - Reason = reason; - Code = code; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CompleteStudentRegistrationRejected.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CompleteStudentRegistrationRejected.cs deleted file mode 100644 index 63be697a4..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CompleteStudentRegistrationRejected.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Convey.CQRS.Events; -using MiniSpace.Services.MediaFiles.Application.Commands; - -namespace MiniSpace.Services.MediaFiles.Application.Events.Rejected -{ - public class CompleteStudentRegistrationRejected : IRejectedEvent - { - public Guid StudentId { get; } - public string Reason { get; } - public string Code { get; } - - public CompleteStudentRegistrationRejected(Guid studentId, string reason, string code) - { - StudentId = studentId; - Reason = reason; - Code = code; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CreateStudentRejected.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CreateStudentRejected.cs deleted file mode 100644 index 2fa8f4497..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/CreateStudentRejected.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Convey.CQRS.Events; - -namespace MiniSpace.Services.MediaFiles.Application.Events.Rejected -{ - public class CreateStudentRejected : IRejectedEvent - { - public Guid StudentId { get; } - public string Reason { get; } - public string Code { get; } - - public CreateStudentRejected(Guid studentId, string reason, string code) - { - StudentId = studentId; - Reason = reason; - Code = code; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/DeleteStudentRejected.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/DeleteStudentRejected.cs deleted file mode 100644 index 6034f3586..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/DeleteStudentRejected.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Convey.CQRS.Events; - -namespace MiniSpace.Services.MediaFiles.Application.Events.Rejected -{ - public class DeleteStudentRejected : IRejectedEvent - { - public Guid StudentId { get; } - public string Reason { get; } - public string Code { get; } - - public DeleteStudentRejected(Guid studentId, string reason, string code) - { - StudentId = studentId; - Reason = reason; - Code = code; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/UpdateStudentRejected.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/UpdateStudentRejected.cs deleted file mode 100644 index 8e812d66a..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/Rejected/UpdateStudentRejected.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Convey.CQRS.Events; - -namespace MiniSpace.Services.MediaFiles.Application.Events.Rejected -{ - public class UpdateStudentRejected : IRejectedEvent - { - public Guid StudentId { get; } - public string Reason { get; } - public string Code { get; } - - public UpdateStudentRejected(Guid studentId, string reason, string code) - { - StudentId = studentId; - Reason = reason; - Code = code; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentCreated.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentCreated.cs deleted file mode 100644 index 6b6eecad0..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentCreated.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Convey.CQRS.Events; - -namespace MiniSpace.Services.MediaFiles.Application.Events -{ - public class StudentCreated : IEvent - { - public Guid StudentId { get; } - public string FullName { get; } - - public StudentCreated(Guid studentId, string fullName) - { - StudentId = studentId; - FullName = fullName; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentDeleted.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentDeleted.cs deleted file mode 100644 index 0c150f8fe..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentDeleted.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Convey.CQRS.Events; - -namespace MiniSpace.Services.MediaFiles.Application.Events -{ - public class StudentDeleted : IEvent - { - public Guid StudentId { get; } - public string FullName { get; } - - public StudentDeleted(Guid studentId, string fullName) - { - StudentId = studentId; - FullName = fullName; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentStateChanged.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentStateChanged.cs deleted file mode 100644 index 3f1087d70..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentStateChanged.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Convey.CQRS.Events; - -namespace MiniSpace.Services.MediaFiles.Application.Events -{ - public class StudentStateChanged : IEvent - { - public Guid StudentId { get; } - public string FullName { get; } - public string CurrentState { get; } - public string PreviousState { get; } - - public StudentStateChanged(Guid studentId, string fullName, string currentState, string previousState) - { - StudentId = studentId; - FullName = fullName; - CurrentState = currentState; - PreviousState = previousState; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentUpdated.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentUpdated.cs deleted file mode 100644 index 337fbfa51..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/StudentUpdated.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Convey.CQRS.Events; - -namespace MiniSpace.Services.MediaFiles.Application.Events -{ - public class StudentUpdated : IEvent - { - public Guid StudentId { get; } - public string FullName { get; } - - public StudentUpdated(Guid studentId, string fullName) - { - StudentId = studentId; - FullName = fullName; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidRoleException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidRoleException.cs deleted file mode 100644 index 5b6776e16..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidRoleException.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace MiniSpace.Services.MediaFiles.Application.Exceptions -{ - public class InvalidRoleException : AppException - { - public override string Code { get; } = "invalid_role"; - - public InvalidRoleException(Guid userId, string role, string requiredRole) - : base($"Student account will not be created for the user with id: {userId} " + - $"due to the invalid role: {role} (required: {requiredRole}).") - { - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyCreatedException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyCreatedException.cs deleted file mode 100644 index ed2ea0910..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyCreatedException.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace MiniSpace.Services.MediaFiles.Application.Exceptions -{ - public class StudentAlreadyCreatedException : AppException - { - public override string Code { get; } = "student_already_created"; - public Guid StudentId { get; } - - public StudentAlreadyCreatedException(Guid studentId) - : base($"Student with id: {studentId} was already created.") - { - StudentId = studentId; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyRegisteredException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyRegisteredException.cs deleted file mode 100644 index 01f9b33ab..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentAlreadyRegisteredException.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace MiniSpace.Services.MediaFiles.Application.Exceptions -{ - public class StudentAlreadyRegisteredException : AppException - { - public override string Code { get; } = "student_already_registered"; - public Guid Id { get; } - - public StudentAlreadyRegisteredException(Guid id) - : base($"Student with id: {id} has already been registered.") - { - Id = id; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentNotFoundException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentNotFoundException.cs deleted file mode 100644 index d43aeee94..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/StudentNotFoundException.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace MiniSpace.Services.MediaFiles.Application.Exceptions -{ - public class StudentNotFoundException : AppException - { - public override string Code { get; } = "student_not_found"; - public Guid Id { get; } - - public StudentNotFoundException(Guid id) : base($"Student with id: {id} was not found.") - { - Id = id; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedStudentAccessException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedStudentAccessException.cs deleted file mode 100644 index 738c13d9a..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedStudentAccessException.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace MiniSpace.Services.MediaFiles.Application.Exceptions -{ - public class UnauthorizedStudentAccessException : AppException - { - public override string Code { get; } = "unauthorized_student_access"; - public Guid StudentId { get; } - public Guid UserId { get; } - - public UnauthorizedStudentAccessException(Guid studentId, Guid userId) - : base($"Unauthorized access to student with id: '{studentId}' by user with id: '{userId}'.") - { - StudentId = studentId; - UserId = userId; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudent.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudent.cs deleted file mode 100644 index 6a13df988..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudent.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Convey.CQRS.Queries; -using MiniSpace.Services.MediaFiles.Application.Dto; - -namespace MiniSpace.Services.MediaFiles.Application.Queries -{ - public class GetStudent : IQuery - { - public Guid StudentId { get; set; } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudentEvents.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudentEvents.cs deleted file mode 100644 index 024be5ff9..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudentEvents.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Convey.CQRS.Queries; -using MiniSpace.Services.MediaFiles.Application.Dto; - -namespace MiniSpace.Services.MediaFiles.Application.Queries -{ - public class GetStudentEvents: IQuery - { - public Guid StudentId { get; set; } - } -} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudents.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudents.cs deleted file mode 100644 index f4c90f67d..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetStudents.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Convey.CQRS.Queries; -using MiniSpace.Services.MediaFiles.Application.Dto; - -namespace MiniSpace.Services.MediaFiles.Application.Queries -{ - public class GetStudents : IQuery> - { - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/State.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/State.cs deleted file mode 100644 index 06677796f..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/State.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace MiniSpace.Services.MediaFiles.Core.Entities -{ - public enum State - { - Unknown, - Valid, - Incomplete, - Banned - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/Student.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/Student.cs deleted file mode 100644 index 534a81117..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/Student.cs +++ /dev/null @@ -1,171 +0,0 @@ -using MiniSpace.Services.MediaFiles.Core.Events; -using MiniSpace.Services.MediaFiles.Core.Exceptions; - -namespace MiniSpace.Services.MediaFiles.Core.Entities -{ - public class Student : AggregateRoot - { - private ISet _interestedInEvents = new HashSet(); - private ISet _signedUpEvents = new HashSet(); - - public string Email { get; private set; } - public string FirstName { get; private set; } - public string LastName { get; private set; } - public string FullName => $"{FirstName} {LastName}"; - public int NumberOfFriends { get; private set; } - public string ProfileImage { get; private set; } - public string Description { get; private set; } - public DateTime? DateOfBirth { get; private set; } - public bool EmailNotifications { get; private set; } - public bool IsBanned { get; private set; } - public bool IsOrganizer { get; private set; } - public State State { get; private set; } - public DateTime CreatedAt { get; private set; } - - public IEnumerable InterestedInEvents - { - get => _interestedInEvents; - set => _interestedInEvents = new HashSet(value); - } - public IEnumerable SignedUpEvents - { - get => _signedUpEvents; - set => _signedUpEvents = new HashSet(value); - } - - public Student(Guid id, string firstName, string lastName, string email, DateTime createdAt) - : this(id, email, createdAt, firstName, lastName, 0, string.Empty, string.Empty, null, - false, false, false, State.Incomplete, Enumerable.Empty(), Enumerable.Empty()) - { - CheckFullName(firstName, lastName); - } - - public Student(Guid id, string email, DateTime createdAt, string firstName, string lastName, - int numberOfFriends, string profileImage, string description, DateTime? dateOfBirth, - bool emailNotifications, bool isBanned, bool isOrganizer, State state, - IEnumerable interestedInEvents = null, IEnumerable signedUpEvents = null) - { - Id = id; - Email = email; - CreatedAt = createdAt; - FirstName = firstName; - LastName = lastName; - NumberOfFriends = numberOfFriends; - ProfileImage = profileImage; - Description = description; - DateOfBirth = dateOfBirth; - EmailNotifications = emailNotifications; - IsBanned = isBanned; - IsOrganizer = isOrganizer; - State = state; - InterestedInEvents = interestedInEvents ?? Enumerable.Empty(); - SignedUpEvents = signedUpEvents ?? Enumerable.Empty(); - } - - public void SetIncomplete() => SetState(State.Incomplete); - public void SetValid() => SetState(State.Valid); - public void SetBanned() => SetState(State.Banned); - - private void SetState(State state) - { - var previousState = State; - State = state; - AddEvent(new StudentStateChanged(this, previousState)); - } - - public void CompleteRegistration(string profileImage, string description, - DateTime dateOfBirth, DateTime now, bool emailNotifications) - { - CheckProfileImage(profileImage); - CheckDescription(description); - CheckDateOfBirth(dateOfBirth, now); - - if (State != State.Incomplete) - { - throw new CannotChangeStudentStateException(Id, State); - } - - ProfileImage = profileImage; - Description = description; - DateOfBirth = dateOfBirth; - EmailNotifications = emailNotifications; - - State = State.Valid; - AddEvent(new StudentRegistrationCompleted(this)); - } - - public void Update(string profileImage, string description, bool emailNotifications) - { - CheckProfileImage(profileImage); - CheckDescription(description); - - if (State != State.Valid) - { - throw new CannotUpdateStudentException(Id); - } - - ProfileImage = profileImage; - Description = description; - EmailNotifications = emailNotifications; - - AddEvent(new StudentUpdated(this)); - } - - private void CheckFullName(string firstName, string lastName) - { - if (string.IsNullOrWhiteSpace(firstName) || string.IsNullOrWhiteSpace(lastName)) - { - throw new InvalidStudentFullNameException(Id, $"{firstName} {lastName}"); - } - } - - private void CheckProfileImage(string profileImage) - { - if (string.IsNullOrWhiteSpace(profileImage)) - { - throw new InvalidStudentProfileImageException(Id, profileImage); - } - } - - private void CheckDescription(string description) - { - if (string.IsNullOrWhiteSpace(description)) - { - throw new InvalidStudentDescriptionException(Id, description); - } - } - - private void CheckDateOfBirth(DateTime dateOfBirth, DateTime now) - { - if (dateOfBirth >= now) - { - throw new InvalidStudentDateOfBirthException(Id, dateOfBirth, now); - } - } - - public void AddInterestedInEvent(Guid eventId) - { - if (eventId == Guid.Empty) - { - return; - } - - _interestedInEvents.Add(eventId); - } - - public void AddSignedUpEvent(Guid eventId) - { - if (eventId == Guid.Empty) - { - return; - } - - _signedUpEvents.Add(eventId); - } - - public void Ban() => IsBanned = true; - public void Unban() => IsBanned = false; - public void GrantOrganizerRights() => IsOrganizer = true; - public void RevokeOrganizerRights() => IsOrganizer = false; - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentRegistrationCompleted.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentRegistrationCompleted.cs deleted file mode 100644 index 7b143d578..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentRegistrationCompleted.cs +++ /dev/null @@ -1,14 +0,0 @@ -using MiniSpace.Services.MediaFiles.Core.Entities; - -namespace MiniSpace.Services.MediaFiles.Core.Events -{ - public class StudentRegistrationCompleted : IDomainEvent - { - public Student Student { get; } - - public StudentRegistrationCompleted(Student student) - { - Student = student; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentStateChanged.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentStateChanged.cs deleted file mode 100644 index 864c8f4ed..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentStateChanged.cs +++ /dev/null @@ -1,16 +0,0 @@ -using MiniSpace.Services.MediaFiles.Core.Entities; - -namespace MiniSpace.Services.MediaFiles.Core.Events -{ - public class StudentStateChanged : IDomainEvent - { - public Student Student { get; } - public State PreviousState { get; } - - public StudentStateChanged(Student student, State previousState) - { - Student = student; - PreviousState = previousState; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentUpdated.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentUpdated.cs deleted file mode 100644 index 90e26b9a1..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Events/StudentUpdated.cs +++ /dev/null @@ -1,14 +0,0 @@ -using MiniSpace.Services.MediaFiles.Core.Entities; - -namespace MiniSpace.Services.MediaFiles.Core.Events -{ - public class StudentUpdated : IDomainEvent - { - public Student Student { get; } - - public StudentUpdated(Student student) - { - Student = student; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotChangeStudentStateException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotChangeStudentStateException.cs deleted file mode 100644 index 84a08f925..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotChangeStudentStateException.cs +++ /dev/null @@ -1,18 +0,0 @@ -using MiniSpace.Services.MediaFiles.Core.Entities; - -namespace MiniSpace.Services.MediaFiles.Core.Exceptions -{ - public class CannotChangeStudentStateException : DomainException - { - public override string Code { get; } = "cannot_change_student_state"; - public Guid Id { get; } - public State State { get; } - - public CannotChangeStudentStateException(Guid id, State state) : base( - $"Cannot change student: {id} state to: {state}.") - { - Id = id; - State = state; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotUpdateStudentException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotUpdateStudentException.cs deleted file mode 100644 index 60b2c2987..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/CannotUpdateStudentException.cs +++ /dev/null @@ -1,16 +0,0 @@ -using MiniSpace.Services.MediaFiles.Core.Entities; - -namespace MiniSpace.Services.MediaFiles.Core.Exceptions -{ - public class CannotUpdateStudentException : DomainException - { - public override string Code { get; } = "cannot_update_student"; - public Guid Id { get; } - - public CannotUpdateStudentException(Guid id) : base( - $"Cannot update student: {id}.") - { - Id = id; - } - } -} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidAggregateIdException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidAggregateIdException.cs deleted file mode 100644 index fc759d722..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidAggregateIdException.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace MiniSpace.Services.MediaFiles.Core.Exceptions -{ - public class InvalidAggregateIdException : DomainException - { - public override string Code { get; } = "invalid_aggregate_id"; - - public InvalidAggregateIdException() : base($"Invalid aggregate id.") - { - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDateOfBirthException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDateOfBirthException.cs deleted file mode 100644 index 510f8870e..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDateOfBirthException.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace MiniSpace.Services.MediaFiles.Core.Exceptions -{ - public class InvalidStudentDateOfBirthException : DomainException - { - public override string Code { get; } = "invalid_student_date_of_birth"; - public Guid Id; - public DateTime DateOfBirth { get; } - public DateTime Now { get; } - - public InvalidStudentDateOfBirthException(Guid id, DateTime dateOfBirth, DateTime now) : base( - $"Student with id: {id} has invalid date of birth. Today date: " + - $"'{now}' must be greater than date of birth: '{dateOfBirth}'.") - { - Id = id; - DateOfBirth = dateOfBirth; - Now = now; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDescriptionException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDescriptionException.cs deleted file mode 100644 index 987259abf..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentDescriptionException.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace MiniSpace.Services.MediaFiles.Core.Exceptions -{ - public class InvalidStudentDescriptionException : DomainException - { - public override string Code { get; } = "invalid_student_description"; - public Guid Id { get; } - public string Description { get; } - - public InvalidStudentDescriptionException(Guid id, string description) : base( - $"Student with id: {id} has invalid description.") - { - Id = id; - Description = description; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentFullNameException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentFullNameException.cs deleted file mode 100644 index 01969834e..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentFullNameException.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace MiniSpace.Services.MediaFiles.Core.Exceptions -{ - public class InvalidStudentFullNameException : DomainException - { - public override string Code { get; } = "invalid_student_full_name"; - public Guid Id { get; } - public string FullName { get; } - - public InvalidStudentFullNameException(Guid id, string fullName) : base( - $"Student with id: {id} has invalid full name.") - { - Id = id; - FullName = fullName; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentProfileImageException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentProfileImageException.cs deleted file mode 100644 index 9b51d71d5..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidStudentProfileImageException.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace MiniSpace.Services.MediaFiles.Core.Exceptions -{ - public class InvalidStudentProfileImageException : DomainException - { - public override string Code { get; } = "invalid_student_profile_image"; - public Guid Id { get; } - public string ProfileImage { get; } - - public InvalidStudentProfileImageException(Guid id, string profileImage) : base( - $"Student with id: {id} has invalid profile image.") - { - Id = id; - ProfileImage = profileImage; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/StudentStateAlreadySetException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/StudentStateAlreadySetException.cs deleted file mode 100644 index 1098d4b96..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/StudentStateAlreadySetException.cs +++ /dev/null @@ -1,18 +0,0 @@ -using MiniSpace.Services.MediaFiles.Core.Entities; - -namespace MiniSpace.Services.MediaFiles.Core.Exceptions -{ - public class StudentStateAlreadySetException : DomainException - { - public override string Code { get; } = "student_state_already_set"; - public Guid Id { get; } - public State State { get; } - - public StudentStateAlreadySetException(Guid id, State state) : base( - $"Student: {id} has state already set to: {state}.") - { - Id = id; - State = state; - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IStudentRepository.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IStudentRepository.cs deleted file mode 100644 index d461b354e..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IStudentRepository.cs +++ /dev/null @@ -1,12 +0,0 @@ -using MiniSpace.Services.MediaFiles.Core.Entities; - -namespace MiniSpace.Services.MediaFiles.Core.Repositories -{ - public interface IStudentRepository - { - Task GetAsync(Guid id); - Task AddAsync(Student student); - Task UpdateAsync(Student student); - Task DeleteAsync(Guid id); - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs deleted file mode 100644 index 66eb0444d..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs +++ /dev/null @@ -1,55 +0,0 @@ -using MiniSpace.Services.MediaFiles.Application.Dto; -using MiniSpace.Services.MediaFiles.Core.Entities; - -namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents -{ - public static class Extensions - { - public static Student AsEntity(this StudentDocument document) - => new Student(document.Id, document.Email, document.CreatedAt, document.FirstName, - document.LastName, document.NumberOfFriends, document.ProfileImage, - document.Description, document.DateOfBirth, document.EmailNotifications, - document.IsBanned, document.IsOrganizer, document.State, - document.InterestedInEvents, document.SignedUpEvents); - - public static StudentDocument AsDocument(this Student entity) - => new StudentDocument() - { - Id = entity.Id, - Email = entity.Email, - FirstName = entity.FirstName, - LastName = entity.LastName, - NumberOfFriends = entity.NumberOfFriends, - ProfileImage = entity.ProfileImage, - Description = entity.Description, - DateOfBirth = entity.DateOfBirth, - EmailNotifications = entity.EmailNotifications, - IsBanned = entity.IsBanned, - IsOrganizer = entity.IsOrganizer, - State = entity.State, - CreatedAt = entity.CreatedAt, - InterestedInEvents = entity.InterestedInEvents, - SignedUpEvents = entity.SignedUpEvents - }; - - public static StudentDto AsDto(this StudentDocument document) - => new StudentDto() - { - Id = document.Id, - Email = document.Email, - FirstName = document.FirstName, - LastName = document.LastName, - NumberOfFriends = document.NumberOfFriends, - ProfileImage = document.ProfileImage, - Description = document.Description, - DateOfBirth = document.DateOfBirth, - EmailNotifications = document.EmailNotifications, - IsBanned = document.IsBanned, - IsOrganizer = document.IsOrganizer, - State = document.State.ToString().ToLowerInvariant(), - CreatedAt = document.CreatedAt, - InterestedInEvents = document.InterestedInEvents, - SignedUpEvents = document.SignedUpEvents - }; - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/StudentDocument.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/StudentDocument.cs deleted file mode 100644 index 840e02917..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/StudentDocument.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Convey.Types; -using MiniSpace.Services.MediaFiles.Core.Entities; - -namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents -{ - public class StudentDocument : IIdentifiable - { - public Guid Id { get; set; } - public string Email { get; set; } - public string FirstName { get; set; } - public string LastName { get; set; } - public int NumberOfFriends { get; set; } - public string ProfileImage { get; set; } - public string Description { get; set; } - public DateTime? DateOfBirth { get; set; } - public bool EmailNotifications { get; set; } - public bool IsBanned { get; set; } - public bool IsOrganizer { get; set; } - public State State { get; set; } - public DateTime CreatedAt { get; set; } - public IEnumerable InterestedInEvents { get; set; } - public IEnumerable SignedUpEvents { get; set; } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentEventsHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentEventsHandler.cs deleted file mode 100644 index 6fe8210a0..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentEventsHandler.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Convey.CQRS.Queries; -using Convey.Persistence.MongoDB; -using MiniSpace.Services.MediaFiles.Application.Dto; -using MiniSpace.Services.MediaFiles.Application.Exceptions; -using MiniSpace.Services.MediaFiles.Application.Queries; -using MiniSpace.Services.MediaFiles.Core.Entities; -using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; - -namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Queries.Handlers -{ - public class GetStudentEventsHandler : IQueryHandler - { - private readonly IMongoRepository _studentRepository; - - public GetStudentEventsHandler(IMongoRepository repository) - => _studentRepository = repository; - - public async Task HandleAsync(GetStudentEvents query, CancellationToken cancellationToken) - { - var document = await _studentRepository.GetAsync(p => p.Id == query.StudentId); - if(document is null) - { - throw new StudentNotFoundException(query.StudentId); - } - - var studentEvents = new StudentEventsDto() - { - StudentId = document.Id, - InterestedInEvents = document.InterestedInEvents, - SignedUpEvents = document.SignedUpEvents - }; - - return studentEvents; - } - } -} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentHandler.cs deleted file mode 100644 index a907378cd..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentHandler.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Convey.CQRS.Queries; -using Convey.Persistence.MongoDB; -using MiniSpace.Services.MediaFiles.Application.Dto; -using MiniSpace.Services.MediaFiles.Application.Queries; -using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; - -namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Queries.Handlers -{ - public class GetStudentHandler : IQueryHandler - { - private readonly IMongoRepository _studentRepository; - - public GetStudentHandler(IMongoRepository studentRepository) - { - _studentRepository = studentRepository; - } - - public async Task HandleAsync(GetStudent query, CancellationToken cancellationToken) - { - var document = await _studentRepository.GetAsync(p => p.Id == query.StudentId); - - return document?.AsDto(); - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentsHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentsHandler.cs deleted file mode 100644 index f9aa08db8..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetStudentsHandler.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Convey.CQRS.Queries; -using Convey.Persistence.MongoDB; -using MiniSpace.Services.MediaFiles.Application.Dto; -using MiniSpace.Services.MediaFiles.Application.Queries; -using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; - -namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Queries.Handlers -{ - public class GetStudentsHandler : IQueryHandler> - { - private readonly IMongoRepository _studentRepository; - - public GetStudentsHandler(IMongoRepository studentRepository) - { - _studentRepository = studentRepository; - } - - public async Task> HandleAsync(GetStudents query, CancellationToken cancellationToken) - { - var students = await _studentRepository.FindAsync(_ => true); - - return students.Select(p => p.AsDto()); - } - } -} diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/StudentMongoRepository.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/StudentMongoRepository.cs deleted file mode 100644 index 8002609e8..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/StudentMongoRepository.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Convey.Persistence.MongoDB; -using MiniSpace.Services.MediaFiles.Core.Entities; -using MiniSpace.Services.MediaFiles.Core.Repositories; -using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; - -namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Repositories -{ - public class StudentMongoRepository : IStudentRepository - { - private readonly IMongoRepository _repository; - - public StudentMongoRepository(IMongoRepository repository) - { - _repository = repository; - } - - public async Task GetAsync(Guid id) - { - var student = await _repository.GetAsync(o => o.Id == id); - - return student?.AsEntity(); - } - - public Task AddAsync(Student student) - => _repository.AddAsync(student.AsDocument()); - - public Task UpdateAsync(Student student) - => _repository.UpdateAsync(student.AsDocument()); - - public Task DeleteAsync(Guid id) - => _repository.DeleteAsync(id); - } -} From caba8ce1758607b58c1bbb7d57afa938f3eb1809 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 4 May 2024 20:53:58 +0200 Subject: [PATCH 05/62] (#92) add upload endpoint declaration --- .../Program.cs | 4 +- .../Handlers/UploadMediaFileHandler.cs | 13 +++ .../Commands/UploadMediaFile.cs | 17 ++++ .../Exceptions/InvalidAggregateIdException.cs | 11 +++ .../Exceptions/ExceptionToMessageMapper.cs | 79 ------------------- .../Extensions.cs | 28 +++---- .../Logging/Extensions.cs | 2 +- .../Logging/MessageToLogTemplateMapper.cs | 68 +--------------- .../Services/EventMapper.cs | 8 +- 9 files changed, 56 insertions(+), 174 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidAggregateIdException.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs index a4e56e2a8..8328923de 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs @@ -11,8 +11,6 @@ using Microsoft.Extensions.DependencyInjection; using MiniSpace.Services.MediaFiles.Application; using MiniSpace.Services.MediaFiles.Application.Commands; -using MiniSpace.Services.MediaFiles.Application.Dto; -using MiniSpace.Services.MediaFiles.Application.Queries; using MiniSpace.Services.MediaFiles.Infrastructure; namespace MiniSpace.Services.MediaFiles.Api @@ -31,6 +29,8 @@ public static async Task Main(string[] args) .UseInfrastructure() .UseDispatcherEndpoints(endpoints => endpoints .Get("", ctx => ctx.Response.WriteAsync(ctx.RequestServices.GetService().Name)) + .Post("media-files") + //afterDispatch: (cmd, ctx) => ctx.Response.Created($"media-files/{cmd.MediaFileId}")) )) .UseLogging() .Build() diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs new file mode 100644 index 000000000..9ef95baa8 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs @@ -0,0 +1,13 @@ +using Convey.CQRS.Commands; + +namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers +{ + public class UploadMediaFileHandler: ICommandHandler + { + + public Task HandleAsync(UploadMediaFile command, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs new file mode 100644 index 000000000..9af5c336e --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs @@ -0,0 +1,17 @@ +using Convey.CQRS.Commands; +using Microsoft.AspNetCore.Http; + +namespace MiniSpace.Services.MediaFiles.Application.Commands +{ + public class UploadMediaFile : ICommand + { + //public Guid MediaFileId { get; } + public IFormFile File { get; } + + public UploadMediaFile(IFormFile file) + { + //MediaFileId = mediaFileId == Guid.Empty ? Guid.NewGuid() : mediaFileId; + File = file; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidAggregateIdException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidAggregateIdException.cs new file mode 100644 index 000000000..376f91b1a --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Exceptions/InvalidAggregateIdException.cs @@ -0,0 +1,11 @@ +namespace MiniSpace.Services.MediaFiles.Core.Exceptions +{ + public class InvalidAggregateIdException : DomainException + { + public override string Code { get; } = "invalid_aggregate_id"; + + public InvalidAggregateIdException() : base($"Invalid aggregate id.") + { + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Exceptions/ExceptionToMessageMapper.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Exceptions/ExceptionToMessageMapper.cs index 1909a49f7..da84e4638 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Exceptions/ExceptionToMessageMapper.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Exceptions/ExceptionToMessageMapper.cs @@ -1,9 +1,4 @@ using Convey.MessageBrokers.RabbitMQ; -using MiniSpace.Services.MediaFiles.Application.Commands; -using MiniSpace.Services.MediaFiles.Application.Events.Rejected; -using MiniSpace.Services.MediaFiles.Application.Events.External; -using MiniSpace.Services.MediaFiles.Application.Exceptions; -using MiniSpace.Services.MediaFiles.Core.Exceptions; namespace MiniSpace.Services.MediaFiles.Infrastructure.Exceptions { @@ -13,80 +8,6 @@ public object Map(Exception exception, object message) => exception switch { - CannotChangeStudentStateException ex => message switch - { - ChangeStudentState _ => new ChangeStudentStateRejected(ex.Id, - ex.State.ToString().ToLowerInvariant(), ex.Message, ex.Code), - CompleteStudentRegistration _ => new CompleteStudentRegistrationRejected(ex.Id, ex.Message, - ex.Code), - _ => null - }, - CannotUpdateStudentException ex => message switch - { - UpdateStudent command => new UpdateStudentRejected(command.StudentId, ex.Message, ex.Code), - _ => null, - }, - InvalidStudentDateOfBirthException ex => message switch - { - CompleteStudentRegistration _ => new CompleteStudentRegistrationRejected(ex.Id, ex.Message, - ex.Code), - _ => null, - }, - InvalidStudentDescriptionException ex => message switch - { - CompleteStudentRegistration _ => new CompleteStudentRegistrationRejected(ex.Id, ex.Message, - ex.Code), - UpdateStudent command => new UpdateStudentRejected(command.StudentId, ex.Message, ex.Code), - _ => null, - }, - InvalidStudentFullNameException ex => message switch - { - CompleteStudentRegistration _ => new CompleteStudentRegistrationRejected(ex.Id, ex.Message, - ex.Code), - _ => null, - }, - InvalidStudentProfileImageException ex => message switch - { - CompleteStudentRegistration _ => new CompleteStudentRegistrationRejected(ex.Id, ex.Message, - ex.Code), - UpdateStudent command => new UpdateStudentRejected(command.StudentId, ex.Message, ex.Code), - _ => null, - }, - InvalidRoleException ex => message switch - { - SignedUp ev => new CreateStudentRejected(ev.UserId, ex.Message, ex.Code), - _ => null, - }, - StudentAlreadyCreatedException ex => message switch - { - SignedUp ev => new CreateStudentRejected(ev.UserId, ex.Message, ex.Code), - _ => null, - }, - StudentAlreadyRegisteredException ex => message switch - { - CompleteStudentRegistration _ => new CompleteStudentRegistrationRejected(ex.Id, ex.Message, - ex.Code), - _ => null, - }, - StudentNotFoundException ex => message switch - { - CompleteStudentRegistration _ => new CompleteStudentRegistrationRejected(ex.Id, ex.Message, - ex.Code), - DeleteStudent command => new DeleteStudentRejected(command.StudentId, ex.Message, ex.Code), - UpdateStudent command => new UpdateStudentRejected(command.StudentId, ex.Message, ex.Code), - _ => null, - }, - StudentStateAlreadySetException ex => message switch - { - ChangeStudentState _ => new ChangeStudentStateRejected(ex.Id, - ex.State.ToString().ToLowerInvariant(), ex.Message, ex.Code), - _ => null - }, - UnauthorizedStudentAccessException ex => message switch - { - DeleteStudent command => new DeleteStudentRejected(command.StudentId, ex.Message, ex.Code), - _ => null, - }, _ => null }; } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs index 5c0541209..6e2b23ef8 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs @@ -28,16 +28,11 @@ using Newtonsoft.Json; using MiniSpace.Services.MediaFiles.Application; using MiniSpace.Services.MediaFiles.Application.Commands; -using MiniSpace.Services.MediaFiles.Application.Events.External; -using MiniSpace.Services.MediaFiles.Application.Events.External.Handlers; using MiniSpace.Services.MediaFiles.Application.Services; -using MiniSpace.Services.MediaFiles.Core.Repositories; using MiniSpace.Services.MediaFiles.Infrastructure.Contexts; using MiniSpace.Services.MediaFiles.Infrastructure.Decorators; using MiniSpace.Services.MediaFiles.Infrastructure.Exceptions; using MiniSpace.Services.MediaFiles.Infrastructure.Logging; -using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; -using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Repositories; using MiniSpace.Services.MediaFiles.Infrastructure.Services; namespace MiniSpace.Services.MediaFiles.Infrastructure @@ -46,7 +41,7 @@ public static class Extensions { public static IConveyBuilder AddInfrastructure(this IConveyBuilder builder) { - builder.Services.AddTransient(); + //builder.Services.AddTransient(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddTransient(); @@ -70,7 +65,7 @@ public static IConveyBuilder AddInfrastructure(this IConveyBuilder builder) .AddMetrics() .AddJaeger() .AddHandlersLogging() - .AddMongoRepository("students") + //.AddMongoRepository("students") .AddWebApiSwaggerDocs() .AddCertificateAuthentication() .AddSecurity(); @@ -86,17 +81,14 @@ public static IApplicationBuilder UseInfrastructure(this IApplicationBuilder app .UseMetrics() .UseCertificateAuthentication() .UseRabbitMq() - .SubscribeCommand() - .SubscribeCommand() - .SubscribeCommand() - .SubscribeCommand() - .SubscribeEvent() - .SubscribeEvent() - .SubscribeEvent() - .SubscribeEvent() - .SubscribeEvent() - .SubscribeEvent() - .SubscribeEvent(); + .SubscribeCommand(); + //.SubscribeEvent() + //.SubscribeEvent() + //.SubscribeEvent() + //.SubscribeEvent() + //.SubscribeEvent() + //.SubscribeEvent() + //.SubscribeEvent(); return app; } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/Extensions.cs index 51efcb88e..e358df03b 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/Extensions.cs @@ -9,7 +9,7 @@ internal static class Extensions { public static IConveyBuilder AddHandlersLogging(this IConveyBuilder builder) { - var assembly = typeof(UpdateStudent).Assembly; + var assembly = typeof(UploadMediaFile).Assembly; builder.Services.AddSingleton(new MessageToLogTemplateMapper()); diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs index 4395c971a..5b779f3a6 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs @@ -1,6 +1,5 @@ using Convey.Logging.CQRS; using MiniSpace.Services.MediaFiles.Application.Commands; -using MiniSpace.Services.MediaFiles.Application.Events.External; namespace MiniSpace.Services.MediaFiles.Infrastructure.Logging { @@ -9,72 +8,7 @@ internal sealed class MessageToLogTemplateMapper : IMessageToLogTemplateMapper private static IReadOnlyDictionary MessageTemplates => new Dictionary { - { - typeof(UpdateStudent), new HandlerLogTemplate - { - After = "Updated the student with id: {StudentId}." - } - }, - { - typeof(DeleteStudent), new HandlerLogTemplate - { - After = "Deleted the student with id: {StudentId}." - } - }, - { - typeof(CompleteStudentRegistration), new HandlerLogTemplate - { - After = "Completed a registration for the student with id: {StudentId}." - } - }, - { - typeof(ChangeStudentState), new HandlerLogTemplate - { - After = "Changed a student with id: {StudentId} state to: {State}." - } - }, - { - typeof(SignedUp), new HandlerLogTemplate - { - After = "Created a new student with id: {UserId}." - } - }, - { - typeof(StudentShowedInterestInEvent), new HandlerLogTemplate - { - After = "A student with id: {StudentId} has been interested in the event with id: {EventId}." - } - }, - { - typeof(StudentSignedUpToEvent), new HandlerLogTemplate - { - After = "A student with id: {StudentId} has signed up for the event with id: {EventId}." - } - }, - { - typeof(UserBanned), new HandlerLogTemplate - { - After = "A student with id: {UserId} has been banned." - } - }, - { - typeof(UserUnbanned), new HandlerLogTemplate - { - After = "A student with id: {UserId} has been unbanned." - } - }, - { - typeof(OrganizerRightsGranted), new HandlerLogTemplate - { - After = "Organizer rights has been granted for student with id: {UserId}." - } - }, - { - typeof(OrganizerRightsRevoked), new HandlerLogTemplate - { - After = "Organizer rights has been revoked for student with id: {UserId}." - } - } + }; public HandlerLogTemplate Map(TMessage message) where TMessage : class diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/EventMapper.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/EventMapper.cs index 891e1042c..ff2fb0c3f 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/EventMapper.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/EventMapper.cs @@ -14,13 +14,7 @@ public IEvent Map(IDomainEvent @event) { switch (@event) { - case StudentRegistrationCompleted e: - return new Application.Events.StudentCreated(e.Student.Id, e.Student.FullName); - case StudentUpdated e: - return new Application.Events.StudentUpdated(e.Student.Id, e.Student.FullName); - case StudentStateChanged e: - return new Application.Events.StudentStateChanged(e.Student.Id, e.Student.FullName, - e.Student.State.ToString().ToLowerInvariant(), e.PreviousState.ToString().ToLowerInvariant()); + } return null; From aa56461339c7013f18927153389631d6506bf48b Mon Sep 17 00:00:00 2001 From: eggwhat Date: Wed, 8 May 2024 17:51:03 +0200 Subject: [PATCH 06/62] (#92) add GridFS service --- .../Commands/UploadMediaFile.cs | 10 +++---- ...ace.Services.MediaFiles.Application.csproj | 1 + .../Services/IGridFSService.cs | 10 +++++++ .../Extensions.cs | 9 +++++- ....Services.MediaFiles.Infrastructure.csproj | 1 + .../Services/GridFSService.cs | 30 +++++++++++++++++++ 6 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IGridFSService.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/GridFSService.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs index 9af5c336e..0ff323c62 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs @@ -5,13 +5,13 @@ namespace MiniSpace.Services.MediaFiles.Application.Commands { public class UploadMediaFile : ICommand { - //public Guid MediaFileId { get; } - public IFormFile File { get; } + public string FileName { get; set; } + public string Base64Content { get; set; } - public UploadMediaFile(IFormFile file) + public UploadMediaFile(string fileName, string base64Content) { - //MediaFileId = mediaFileId == Guid.Empty ? Guid.NewGuid() : mediaFileId; - File = file; + FileName = fileName; + Base64Content = base64Content; } } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj index 95d9be543..366eb3723 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj @@ -12,6 +12,7 @@ + diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IGridFSService.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IGridFSService.cs new file mode 100644 index 000000000..6cb0c2e09 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IGridFSService.cs @@ -0,0 +1,10 @@ +using MongoDB.Bson; + +namespace MiniSpace.Services.MediaFiles.Application.Services +{ + public interface IGridFSService + { + Task UploadFileAsync(string fileName, Stream fileStream); + Task DownloadFileAsync(ObjectId fileId, Stream destination); + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs index 6e2b23ef8..b0fdb5db6 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs @@ -34,6 +34,7 @@ using MiniSpace.Services.MediaFiles.Infrastructure.Exceptions; using MiniSpace.Services.MediaFiles.Infrastructure.Logging; using MiniSpace.Services.MediaFiles.Infrastructure.Services; +using MongoDB.Driver; namespace MiniSpace.Services.MediaFiles.Infrastructure { @@ -49,6 +50,13 @@ public static IConveyBuilder AddInfrastructure(this IConveyBuilder builder) builder.Services.AddTransient(ctx => ctx.GetRequiredService().Create()); builder.Services.TryDecorate(typeof(ICommandHandler<>), typeof(OutboxCommandHandlerDecorator<>)); builder.Services.TryDecorate(typeof(IEventHandler<>), typeof(OutboxEventHandlerDecorator<>)); + builder.Services.AddSingleton(serviceProvider => + { + var mongoDbOptions = serviceProvider.GetRequiredService(); + var mongoClient = new MongoClient(mongoDbOptions.ConnectionString); + var database = mongoClient.GetDatabase(mongoDbOptions.Database); + return new GridFSService(database); + }); return builder .AddErrorHandler() @@ -60,7 +68,6 @@ public static IConveyBuilder AddInfrastructure(this IConveyBuilder builder) .AddRabbitMq(plugins: p => p.AddJaegerRabbitMqPlugin()) .AddMessageOutbox(o => o.AddMongo()) .AddExceptionToMessageMapper() - .AddMongo() .AddRedis() .AddMetrics() .AddJaeger() diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/MiniSpace.Services.MediaFiles.Infrastructure.csproj b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/MiniSpace.Services.MediaFiles.Infrastructure.csproj index ff97df7c1..cbe16ffa6 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/MiniSpace.Services.MediaFiles.Infrastructure.csproj +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/MiniSpace.Services.MediaFiles.Infrastructure.csproj @@ -30,6 +30,7 @@ + diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/GridFSService.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/GridFSService.cs new file mode 100644 index 000000000..bd1b90e15 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/GridFSService.cs @@ -0,0 +1,30 @@ +using MiniSpace.Services.MediaFiles.Application.Services; +using MongoDB.Bson; +using MongoDB.Driver; +using MongoDB.Driver.GridFS; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Services +{ + public class GridFSService: IGridFSService + { + private readonly IMongoDatabase _database; + private readonly GridFSBucket _gridFSBucket; + + public GridFSService(IMongoDatabase database) + { + _database = database; + _gridFSBucket = new GridFSBucket(_database); + } + + public async Task UploadFileAsync(string fileName, Stream fileStream) + { + ObjectId fileId = await _gridFSBucket.UploadFromStreamAsync(fileName, fileStream); + return fileId; + } + + public async Task DownloadFileAsync(ObjectId fileId, Stream destination) + { + await _gridFSBucket.DownloadToStreamAsync(fileId, destination); + } + } +} \ No newline at end of file From 0c647b668eae0efe2b8a5748ca7c5da3edfe5f2a Mon Sep 17 00:00:00 2001 From: eggwhat Date: Wed, 8 May 2024 18:44:38 +0200 Subject: [PATCH 07/62] (#92) add handler for uploading file --- .../Handlers/UploadMediaFileHandler.cs | 18 ++++++++-- .../Events/MediaFileUploaded.cs | 16 +++++++++ .../Queries/GetMediaFile.cs | 10 ++++++ .../Entities/ContextType.cs | 9 +++++ .../Extensions.cs | 1 + .../Queries/Handlers/GetMediaFilesHandler.cs | 33 +++++++++++++++++++ 6 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/MediaFileUploaded.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetMediaFile.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/ContextType.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFilesHandler.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs index 9ef95baa8..3a09912da 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs @@ -1,13 +1,27 @@ using Convey.CQRS.Commands; +using MiniSpace.Services.MediaFiles.Application.Events; +using MiniSpace.Services.MediaFiles.Application.Services; namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers { public class UploadMediaFileHandler: ICommandHandler { + private readonly IGridFSService _gridFSService; + private readonly IMessageBroker _messageBroker; - public Task HandleAsync(UploadMediaFile command, CancellationToken cancellationToken) + public UploadMediaFileHandler(IGridFSService gridFSService, IMessageBroker messageBroker) { - throw new NotImplementedException(); + _gridFSService = gridFSService; + _messageBroker = messageBroker; + } + + public async Task HandleAsync(UploadMediaFile command, CancellationToken cancellationToken) + { + byte[] bytes = Convert.FromBase64String(command.Base64Content); + MemoryStream stream = new MemoryStream(bytes); + + var objectId = await _gridFSService.UploadFileAsync(command.FileName, stream); + await _messageBroker.PublishAsync(new MediaFileUploaded(Guid.Empty, command.FileName)); } } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/MediaFileUploaded.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/MediaFileUploaded.cs new file mode 100644 index 000000000..5f2cf96ad --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/MediaFileUploaded.cs @@ -0,0 +1,16 @@ +using Convey.CQRS.Events; + +namespace MiniSpace.Services.MediaFiles.Application.Events +{ + public class MediaFileUploaded : IEvent + { + public Guid Id { get; } + public string FileName { get; } + + public MediaFileUploaded(Guid id, string fileName) + { + Id = id; + FileName = fileName; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetMediaFile.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetMediaFile.cs new file mode 100644 index 000000000..9f8cb2eee --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetMediaFile.cs @@ -0,0 +1,10 @@ +using Convey.CQRS.Queries; +using Microsoft.AspNetCore.Mvc; + +namespace MiniSpace.Services.MediaFiles.Application.Queries +{ + public class GetMediaFile : IQuery + { + public Guid MediaFileId { get; set; } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/ContextType.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/ContextType.cs new file mode 100644 index 000000000..c93a71bd3 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/ContextType.cs @@ -0,0 +1,9 @@ +namespace MiniSpace.Services.MediaFiles.Core.Entities +{ + public enum ContextType + { + Event, + Post, + StudentProfile, + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs index b0fdb5db6..78c945a6f 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs @@ -68,6 +68,7 @@ public static IConveyBuilder AddInfrastructure(this IConveyBuilder builder) .AddRabbitMq(plugins: p => p.AddJaegerRabbitMqPlugin()) .AddMessageOutbox(o => o.AddMongo()) .AddExceptionToMessageMapper() + .AddMongo() .AddRedis() .AddMetrics() .AddJaeger() diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFilesHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFilesHandler.cs new file mode 100644 index 000000000..b73b8f9dc --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFilesHandler.cs @@ -0,0 +1,33 @@ +using Convey.CQRS.Queries; +using Microsoft.AspNetCore.Mvc; +using MiniSpace.Services.MediaFiles.Application.Queries; +using MiniSpace.Services.MediaFiles.Application.Services; +using MongoDB.Bson; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Queries.Handlers +{ + public class GetMediaFilesHandler : IQueryHandler + { + private readonly IGridFSService _gridFSService; + + public GetMediaFilesHandler(IGridFSService gridFSService) + { + _gridFSService = gridFSService; + } + + public async Task HandleAsync(GetMediaFile query, CancellationToken cancellationToken) + { + ObjectId objectId; + if (!ObjectId.TryParse(query.MediaFileId.ToString(), out objectId)) + { + return null; + } + + var fileStream = new MemoryStream(); + await _gridFSService.DownloadFileAsync(objectId, fileStream); + + fileStream.Seek(0, SeekOrigin.Begin); + return new FileStreamResult(fileStream, "image/jpeg"); + } + } +} \ No newline at end of file From ff12d948418e8fbbc2790818c15e2769050bf324 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Wed, 8 May 2024 18:49:56 +0200 Subject: [PATCH 08/62] (#92) add wrapper class for storing media source info --- .../Entities/FileSourceInfo.cs | 11 +++++++++++ .../MiniSpace.Services.MediaFiles.Core.csproj | 4 ++++ 2 files changed, 15 insertions(+) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs new file mode 100644 index 000000000..73e632d91 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs @@ -0,0 +1,11 @@ +using MongoDB.Bson; + +namespace MiniSpace.Services.MediaFiles.Core.Entities +{ + public class FileSourceInfo: AggregateRoot + { + public Guid SourceId { get; set; } + public ContextType SourceType { get; set; } + public ObjectId FileId { get; set; } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/MiniSpace.Services.MediaFiles.Core.csproj b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/MiniSpace.Services.MediaFiles.Core.csproj index cf309aa85..4e485b559 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/MiniSpace.Services.MediaFiles.Core.csproj +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/MiniSpace.Services.MediaFiles.Core.csproj @@ -6,4 +6,8 @@ disable + + + + From de1b6d7ba1c9f0beee736329fa31d65bde074c96 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Wed, 8 May 2024 19:00:01 +0200 Subject: [PATCH 09/62] (#92) add file source info repository --- .../Entities/FileSourceInfo.cs | 8 ++++ .../Repositories/IFileSourceInfoRepository.cs | 13 ++++++ .../Extensions.cs | 6 ++- .../Mongo/Documents/Extensions.cs | 19 +++++++++ .../Mongo/Documents/FileSourceInfoDocument.cs | 14 +++++++ .../FileSourceInfoMongoRepository.cs | 42 +++++++++++++++++++ 6 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IFileSourceInfoRepository.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/FileSourceInfoMongoRepository.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs index 73e632d91..6a2288bf9 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs @@ -7,5 +7,13 @@ public class FileSourceInfo: AggregateRoot public Guid SourceId { get; set; } public ContextType SourceType { get; set; } public ObjectId FileId { get; set; } + + public FileSourceInfo(Guid id, Guid sourceId, ContextType sourceType, ObjectId fileId) + { + Id = id; + SourceId = sourceId; + SourceType = sourceType; + FileId = fileId; + } } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IFileSourceInfoRepository.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IFileSourceInfoRepository.cs new file mode 100644 index 000000000..45b6cc48c --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IFileSourceInfoRepository.cs @@ -0,0 +1,13 @@ +using MiniSpace.Services.MediaFiles.Core.Entities; + +namespace MiniSpace.Services.MediaFiles.Core.Repositories +{ + public interface IFileSourceInfoRepository + { + Task GetAsync(Guid id); + Task AddAsync(FileSourceInfo fileSourceInfo); + Task UpdateAsync(FileSourceInfo fileSourceInfo); + Task DeleteAsync(Guid id); + Task ExistsAsync(Guid id); + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs index 78c945a6f..6627c0105 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs @@ -29,10 +29,12 @@ using MiniSpace.Services.MediaFiles.Application; using MiniSpace.Services.MediaFiles.Application.Commands; using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Repositories; using MiniSpace.Services.MediaFiles.Infrastructure.Contexts; using MiniSpace.Services.MediaFiles.Infrastructure.Decorators; using MiniSpace.Services.MediaFiles.Infrastructure.Exceptions; using MiniSpace.Services.MediaFiles.Infrastructure.Logging; +using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; using MiniSpace.Services.MediaFiles.Infrastructure.Services; using MongoDB.Driver; @@ -42,7 +44,7 @@ public static class Extensions { public static IConveyBuilder AddInfrastructure(this IConveyBuilder builder) { - //builder.Services.AddTransient(); + builder.Services.AddTransient(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddTransient(); @@ -73,7 +75,7 @@ public static IConveyBuilder AddInfrastructure(this IConveyBuilder builder) .AddMetrics() .AddJaeger() .AddHandlersLogging() - //.AddMongoRepository("students") + .AddMongoRepository("fileSourceInfos") .AddWebApiSwaggerDocs() .AddCertificateAuthentication() .AddSecurity(); diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs new file mode 100644 index 000000000..d32e6541e --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs @@ -0,0 +1,19 @@ +using MiniSpace.Services.MediaFiles.Core.Entities; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents +{ + public static class Extensions + { + public static FileSourceInfoDocument AsDocument(this FileSourceInfo fileSourceInfo) + => new FileSourceInfoDocument + { + Id = fileSourceInfo.Id, + SourceId = fileSourceInfo.SourceId, + SourceType = fileSourceInfo.SourceType, + FileId = fileSourceInfo.FileId + }; + + public static FileSourceInfo AsEntity(this FileSourceInfoDocument document) + => new FileSourceInfo(document.Id, document.SourceId, document.SourceType, document.FileId); + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs new file mode 100644 index 000000000..75f961aca --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs @@ -0,0 +1,14 @@ +using Convey.Types; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MongoDB.Bson; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents +{ + public class FileSourceInfoDocument : IIdentifiable + { + public Guid Id { get; set; } + public Guid SourceId { get; set; } + public ContextType SourceType { get; set; } + public ObjectId FileId { get; set; } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/FileSourceInfoMongoRepository.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/FileSourceInfoMongoRepository.cs new file mode 100644 index 000000000..0826cc8bc --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/FileSourceInfoMongoRepository.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Convey.Persistence.MongoDB; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Core.Repositories; +using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; +using MongoDB.Driver; +using MongoDB.Driver.Linq; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Repositories +{ + public class FileSourceInfoMongoRepository : IFileSourceInfoRepository + { + private readonly IMongoRepository _repository; + + public FileSourceInfoMongoRepository(IMongoRepository repository) + { + _repository = repository; + } + + public async Task GetAsync(Guid id) + { + var fileSourceInfo = await _repository.GetAsync(s => s.Id == id); + + return fileSourceInfo?.AsEntity(); + } + + public Task AddAsync(FileSourceInfo fileSourceInfo) + => _repository.AddAsync(fileSourceInfo.AsDocument()); + + public Task UpdateAsync(FileSourceInfo fileSourceInfo) + => _repository.UpdateAsync(fileSourceInfo.AsDocument()); + + public Task DeleteAsync(Guid id) + => _repository.DeleteAsync(id); + + public Task ExistsAsync(Guid id) + => _repository.ExistsAsync(s => s.Id == id); + } +} \ No newline at end of file From d0a571ecf9330af71aef679d008137b71da4b832 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Wed, 8 May 2024 19:15:52 +0200 Subject: [PATCH 10/62] (#92) update upload media files handler --- .../Program.cs | 4 ++-- .../Handlers/UploadMediaFileHandler.cs | 18 +++++++++++++++--- .../Commands/UploadMediaFile.cs | 8 +++++++- .../Exceptions/InvalidContextTypeException.cs | 13 +++++++++++++ .../Extensions.cs | 3 ++- .../Logging/MessageToLogTemplateMapper.cs | 7 ++++++- 6 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidContextTypeException.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs index 8328923de..3987934c3 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs @@ -29,8 +29,8 @@ public static async Task Main(string[] args) .UseInfrastructure() .UseDispatcherEndpoints(endpoints => endpoints .Get("", ctx => ctx.Response.WriteAsync(ctx.RequestServices.GetService().Name)) - .Post("media-files") - //afterDispatch: (cmd, ctx) => ctx.Response.Created($"media-files/{cmd.MediaFileId}")) + .Post("media-files", + afterDispatch: (cmd, ctx) => ctx.Response.Created($"media-files/{cmd.MediaFileId}")) )) .UseLogging() .Build() diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs index 3a09912da..9a784025e 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs @@ -1,27 +1,39 @@ using Convey.CQRS.Commands; using MiniSpace.Services.MediaFiles.Application.Events; +using MiniSpace.Services.MediaFiles.Application.Exceptions; using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Core.Repositories; namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers { public class UploadMediaFileHandler: ICommandHandler { + private readonly IFileSourceInfoRepository _fileSourceInfoRepository; private readonly IGridFSService _gridFSService; private readonly IMessageBroker _messageBroker; - public UploadMediaFileHandler(IGridFSService gridFSService, IMessageBroker messageBroker) + public UploadMediaFileHandler(IFileSourceInfoRepository fileSourceInfoRepository, IGridFSService gridFSService, + IMessageBroker messageBroker) { + _fileSourceInfoRepository = fileSourceInfoRepository; _gridFSService = gridFSService; _messageBroker = messageBroker; } public async Task HandleAsync(UploadMediaFile command, CancellationToken cancellationToken) { + if (!Enum.TryParse(command.SourceType, out ContextType sourceType)) + { + throw new InvalidContextTypeException(command.SourceType); + } byte[] bytes = Convert.FromBase64String(command.Base64Content); - MemoryStream stream = new MemoryStream(bytes); + var stream = new MemoryStream(bytes); var objectId = await _gridFSService.UploadFileAsync(command.FileName, stream); - await _messageBroker.PublishAsync(new MediaFileUploaded(Guid.Empty, command.FileName)); + var fileSourceInfo = new FileSourceInfo(command.MediaFileId, command.SourceId, sourceType, objectId); + await _fileSourceInfoRepository.AddAsync(fileSourceInfo); + await _messageBroker.PublishAsync(new MediaFileUploaded(command.MediaFileId, command.FileName)); } } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs index 0ff323c62..38aafc70d 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs @@ -5,11 +5,17 @@ namespace MiniSpace.Services.MediaFiles.Application.Commands { public class UploadMediaFile : ICommand { + public Guid MediaFileId { get; set; } + public Guid SourceId { get; set; } + public string SourceType { get; set; } public string FileName { get; set; } public string Base64Content { get; set; } - public UploadMediaFile(string fileName, string base64Content) + public UploadMediaFile(Guid mediaFileId, Guid sourceId, string sourceType, string fileName, string base64Content) { + MediaFileId = mediaFileId == Guid.Empty ? Guid.NewGuid() : mediaFileId; + SourceId = sourceId; + SourceType = sourceType; FileName = fileName; Base64Content = base64Content; } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidContextTypeException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidContextTypeException.cs new file mode 100644 index 000000000..9efdbe128 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidContextTypeException.cs @@ -0,0 +1,13 @@ +namespace MiniSpace.Services.MediaFiles.Application.Exceptions +{ + public class InvalidContextTypeException : AppException + { + public override string Code { get; } = "invalid_context_type"; + public string ContextType { get; } + + public InvalidContextTypeException(string contextType) : base($"Invalid context type: {contextType}.") + { + ContextType = contextType; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs index 6627c0105..8b42043ca 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs @@ -35,6 +35,7 @@ using MiniSpace.Services.MediaFiles.Infrastructure.Exceptions; using MiniSpace.Services.MediaFiles.Infrastructure.Logging; using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; +using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Repositories; using MiniSpace.Services.MediaFiles.Infrastructure.Services; using MongoDB.Driver; @@ -44,7 +45,7 @@ public static class Extensions { public static IConveyBuilder AddInfrastructure(this IConveyBuilder builder) { - builder.Services.AddTransient(); + builder.Services.AddTransient(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddTransient(); diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs index 5b779f3a6..a12c818e3 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs @@ -8,7 +8,12 @@ internal sealed class MessageToLogTemplateMapper : IMessageToLogTemplateMapper private static IReadOnlyDictionary MessageTemplates => new Dictionary { - + { + typeof(UploadMediaFile), new HandlerLogTemplate + { + After = "Uploaded media file with ID: {MediaFileId} and name: {FileName}.", + } + }, }; public HandlerLogTemplate Map(TMessage message) where TMessage : class From 9f37f5b174ee523a3e8e484f2d525f56eb9c1499 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Wed, 8 May 2024 19:58:20 +0200 Subject: [PATCH 11/62] (#92) update query GetMediaFile --- .../Program.cs | 4 +++ .../Handlers/UploadMediaFileHandler.cs | 2 +- .../Dto/FileDto.cs | 20 ++++++++++++++ .../Queries/GetMediaFile.cs | 3 ++- .../Entities/FileSourceInfo.cs | 4 ++- .../Mongo/Documents/Extensions.cs | 5 ++-- .../Mongo/Documents/FileSourceInfoDocument.cs | 1 + .../Queries/Handlers/GetMediaFilesHandler.cs | 26 +++++++++++++------ 8 files changed, 52 insertions(+), 13 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs index 3987934c3..e48b936a2 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs @@ -8,9 +8,12 @@ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using MiniSpace.Services.MediaFiles.Application; using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Application.Dto; +using MiniSpace.Services.MediaFiles.Application.Queries; using MiniSpace.Services.MediaFiles.Infrastructure; namespace MiniSpace.Services.MediaFiles.Api @@ -29,6 +32,7 @@ public static async Task Main(string[] args) .UseInfrastructure() .UseDispatcherEndpoints(endpoints => endpoints .Get("", ctx => ctx.Response.WriteAsync(ctx.RequestServices.GetService().Name)) + .Get("media-files/{mediaFileId}") .Post("media-files", afterDispatch: (cmd, ctx) => ctx.Response.Created($"media-files/{cmd.MediaFileId}")) )) diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs index 9a784025e..f24f88882 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs @@ -31,7 +31,7 @@ public async Task HandleAsync(UploadMediaFile command, CancellationToken cancell var stream = new MemoryStream(bytes); var objectId = await _gridFSService.UploadFileAsync(command.FileName, stream); - var fileSourceInfo = new FileSourceInfo(command.MediaFileId, command.SourceId, sourceType, objectId); + var fileSourceInfo = new FileSourceInfo(command.MediaFileId, command.SourceId, sourceType, objectId, command.FileName); await _fileSourceInfoRepository.AddAsync(fileSourceInfo); await _messageBroker.PublishAsync(new MediaFileUploaded(command.MediaFileId, command.FileName)); } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs new file mode 100644 index 000000000..cee2ceb24 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs @@ -0,0 +1,20 @@ +namespace MiniSpace.Services.MediaFiles.Application.Dto +{ + public class FileDto + { + public Guid MediaFileId { get; set; } + public Guid SourceId { get; set; } + public string SourceType { get; set; } + public string FileName { get; set; } + public string Base64Content { get; set; } + + public FileDto(Guid mediaFileId, Guid sourceId, string sourceType, string fileName, string base64Content) + { + MediaFileId = mediaFileId == Guid.Empty ? Guid.NewGuid() : mediaFileId; + SourceId = sourceId; + SourceType = sourceType; + FileName = fileName; + Base64Content = base64Content; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetMediaFile.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetMediaFile.cs index 9f8cb2eee..06ad3f327 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetMediaFile.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetMediaFile.cs @@ -1,9 +1,10 @@ using Convey.CQRS.Queries; using Microsoft.AspNetCore.Mvc; +using MiniSpace.Services.MediaFiles.Application.Dto; namespace MiniSpace.Services.MediaFiles.Application.Queries { - public class GetMediaFile : IQuery + public class GetMediaFile : IQuery { public Guid MediaFileId { get; set; } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs index 6a2288bf9..ed0745116 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs @@ -7,13 +7,15 @@ public class FileSourceInfo: AggregateRoot public Guid SourceId { get; set; } public ContextType SourceType { get; set; } public ObjectId FileId { get; set; } + public string FileName { get; set; } - public FileSourceInfo(Guid id, Guid sourceId, ContextType sourceType, ObjectId fileId) + public FileSourceInfo(Guid id, Guid sourceId, ContextType sourceType, ObjectId fileId, string fileName) { Id = id; SourceId = sourceId; SourceType = sourceType; FileId = fileId; + FileName = fileName; } } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs index d32e6541e..4821030e1 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs @@ -10,10 +10,11 @@ public static FileSourceInfoDocument AsDocument(this FileSourceInfo fileSourceIn Id = fileSourceInfo.Id, SourceId = fileSourceInfo.SourceId, SourceType = fileSourceInfo.SourceType, - FileId = fileSourceInfo.FileId + FileId = fileSourceInfo.FileId, + FileName = fileSourceInfo.FileName }; public static FileSourceInfo AsEntity(this FileSourceInfoDocument document) - => new FileSourceInfo(document.Id, document.SourceId, document.SourceType, document.FileId); + => new FileSourceInfo(document.Id, document.SourceId, document.SourceType, document.FileId, document.FileName); } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs index 75f961aca..d5a4032c4 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs @@ -10,5 +10,6 @@ public class FileSourceInfoDocument : IIdentifiable public Guid SourceId { get; set; } public ContextType SourceType { get; set; } public ObjectId FileId { get; set; } + public string FileName { get; set; } } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFilesHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFilesHandler.cs index b73b8f9dc..59725b8f5 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFilesHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFilesHandler.cs @@ -1,33 +1,43 @@ using Convey.CQRS.Queries; +using Convey.Persistence.MongoDB; using Microsoft.AspNetCore.Mvc; +using Microsoft.Net.Http.Headers; +using MiniSpace.Services.MediaFiles.Application.Dto; using MiniSpace.Services.MediaFiles.Application.Queries; using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; using MongoDB.Bson; namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Queries.Handlers { - public class GetMediaFilesHandler : IQueryHandler + public class GetMediaFilesHandler : IQueryHandler { + private readonly IMongoRepository _fileSourceInfoRepository; private readonly IGridFSService _gridFSService; - public GetMediaFilesHandler(IGridFSService gridFSService) + public GetMediaFilesHandler(IMongoRepository fileSourceInfoRepository, + IGridFSService gridFSService) { + _fileSourceInfoRepository = fileSourceInfoRepository; _gridFSService = gridFSService; } - public async Task HandleAsync(GetMediaFile query, CancellationToken cancellationToken) + public async Task HandleAsync(GetMediaFile query, CancellationToken cancellationToken) { - ObjectId objectId; - if (!ObjectId.TryParse(query.MediaFileId.ToString(), out objectId)) + var fileSourceInfo = await _fileSourceInfoRepository.GetAsync(query.MediaFileId); + if (fileSourceInfo is null) { return null; } var fileStream = new MemoryStream(); - await _gridFSService.DownloadFileAsync(objectId, fileStream); - + await _gridFSService.DownloadFileAsync(fileSourceInfo.FileId, fileStream); fileStream.Seek(0, SeekOrigin.Begin); - return new FileStreamResult(fileStream, "image/jpeg"); + byte[] fileContent = fileStream.ToArray(); + var base64String = Convert.ToBase64String(fileContent); + + return new FileDto(query.MediaFileId, fileSourceInfo.SourceId, fileSourceInfo.SourceType.ToString(), + fileSourceInfo.FileName, base64String); } } } \ No newline at end of file From 905a10c27a2dd8aa28e5a19bc7b7e31510dff80e Mon Sep 17 00:00:00 2001 From: eggwhat Date: Thu, 9 May 2024 00:25:07 +0200 Subject: [PATCH 12/62] (#92) add uploaderId field --- .../Commands/Handlers/UploadMediaFileHandler.cs | 13 +++++++++++-- .../Commands/UploadMediaFile.cs | 5 ++++- .../Dto/FileDto.cs | 5 ++++- .../UnauthorizedMediaFileUploadException.cs | 16 ++++++++++++++++ .../Entities/FileSourceInfo.cs | 5 ++++- .../Mongo/Documents/Extensions.cs | 4 +++- .../Mongo/Documents/FileSourceInfoDocument.cs | 1 + .../Queries/Handlers/GetMediaFilesHandler.cs | 2 +- 8 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedMediaFileUploadException.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs index f24f88882..920e982b6 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs @@ -11,18 +11,26 @@ public class UploadMediaFileHandler: ICommandHandler { private readonly IFileSourceInfoRepository _fileSourceInfoRepository; private readonly IGridFSService _gridFSService; + private readonly IAppContext _appContext; private readonly IMessageBroker _messageBroker; public UploadMediaFileHandler(IFileSourceInfoRepository fileSourceInfoRepository, IGridFSService gridFSService, - IMessageBroker messageBroker) + IAppContext appContext, IMessageBroker messageBroker) { _fileSourceInfoRepository = fileSourceInfoRepository; _gridFSService = gridFSService; + _appContext = appContext; _messageBroker = messageBroker; } public async Task HandleAsync(UploadMediaFile command, CancellationToken cancellationToken) { + var identity = _appContext.Identity; + if(identity.IsAuthenticated && identity.Id != command.UploaderId) + { + throw new UnauthorizedMediaFileUploadException(identity.Id, command.UploaderId); + } + if (!Enum.TryParse(command.SourceType, out ContextType sourceType)) { throw new InvalidContextTypeException(command.SourceType); @@ -31,7 +39,8 @@ public async Task HandleAsync(UploadMediaFile command, CancellationToken cancell var stream = new MemoryStream(bytes); var objectId = await _gridFSService.UploadFileAsync(command.FileName, stream); - var fileSourceInfo = new FileSourceInfo(command.MediaFileId, command.SourceId, sourceType, objectId, command.FileName); + var fileSourceInfo = new FileSourceInfo(command.MediaFileId, command.SourceId, sourceType, + command.UploaderId, objectId, command.FileName); await _fileSourceInfoRepository.AddAsync(fileSourceInfo); await _messageBroker.PublishAsync(new MediaFileUploaded(command.MediaFileId, command.FileName)); } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs index 38aafc70d..6bc3c4230 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs @@ -8,14 +8,17 @@ public class UploadMediaFile : ICommand public Guid MediaFileId { get; set; } public Guid SourceId { get; set; } public string SourceType { get; set; } + public Guid UploaderId { get; set; } public string FileName { get; set; } public string Base64Content { get; set; } - public UploadMediaFile(Guid mediaFileId, Guid sourceId, string sourceType, string fileName, string base64Content) + public UploadMediaFile(Guid mediaFileId, Guid sourceId, string sourceType, Guid uploaderId, + string fileName, string base64Content) { MediaFileId = mediaFileId == Guid.Empty ? Guid.NewGuid() : mediaFileId; SourceId = sourceId; SourceType = sourceType; + UploaderId = uploaderId; FileName = fileName; Base64Content = base64Content; } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs index cee2ceb24..99b48507e 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs @@ -5,14 +5,17 @@ public class FileDto public Guid MediaFileId { get; set; } public Guid SourceId { get; set; } public string SourceType { get; set; } + public Guid UploaderId { get; set; } public string FileName { get; set; } public string Base64Content { get; set; } - public FileDto(Guid mediaFileId, Guid sourceId, string sourceType, string fileName, string base64Content) + public FileDto(Guid mediaFileId, Guid sourceId, string sourceType, Guid uploaderId, + string fileName, string base64Content) { MediaFileId = mediaFileId == Guid.Empty ? Guid.NewGuid() : mediaFileId; SourceId = sourceId; SourceType = sourceType; + UploaderId = uploaderId; FileName = fileName; Base64Content = base64Content; } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedMediaFileUploadException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedMediaFileUploadException.cs new file mode 100644 index 000000000..91ad23b02 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedMediaFileUploadException.cs @@ -0,0 +1,16 @@ +namespace MiniSpace.Services.MediaFiles.Application.Exceptions +{ + public class UnauthorizedMediaFileUploadException : AppException + { + public override string Code { get; } = "unauthorized_media_file_upload"; + public Guid IdentityId { get; } + public Guid UploaderId { get; } + + public UnauthorizedMediaFileUploadException(Guid identityId, Guid uploaderId) + : base($"User with ID: {uploaderId} is not authorized to upload media files. Identity ID: {identityId}.") + { + IdentityId = identityId; + UploaderId = uploaderId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs index ed0745116..a24bf37ed 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs @@ -6,14 +6,17 @@ public class FileSourceInfo: AggregateRoot { public Guid SourceId { get; set; } public ContextType SourceType { get; set; } + public Guid UploaderId { get; set; } public ObjectId FileId { get; set; } public string FileName { get; set; } - public FileSourceInfo(Guid id, Guid sourceId, ContextType sourceType, ObjectId fileId, string fileName) + public FileSourceInfo(Guid id, Guid sourceId, ContextType sourceType, Guid uploaderId, + ObjectId fileId, string fileName) { Id = id; SourceId = sourceId; SourceType = sourceType; + UploaderId = uploaderId; FileId = fileId; FileName = fileName; } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs index 4821030e1..1f2dc8224 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs @@ -10,11 +10,13 @@ public static FileSourceInfoDocument AsDocument(this FileSourceInfo fileSourceIn Id = fileSourceInfo.Id, SourceId = fileSourceInfo.SourceId, SourceType = fileSourceInfo.SourceType, + UploaderId = fileSourceInfo.UploaderId, FileId = fileSourceInfo.FileId, FileName = fileSourceInfo.FileName }; public static FileSourceInfo AsEntity(this FileSourceInfoDocument document) - => new FileSourceInfo(document.Id, document.SourceId, document.SourceType, document.FileId, document.FileName); + => new FileSourceInfo(document.Id, document.SourceId, document.SourceType, document.UploaderId, + document.FileId, document.FileName); } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs index d5a4032c4..a3addea5b 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs @@ -9,6 +9,7 @@ public class FileSourceInfoDocument : IIdentifiable public Guid Id { get; set; } public Guid SourceId { get; set; } public ContextType SourceType { get; set; } + public Guid UploaderId { get; set; } public ObjectId FileId { get; set; } public string FileName { get; set; } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFilesHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFilesHandler.cs index 59725b8f5..9aea7df05 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFilesHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFilesHandler.cs @@ -37,7 +37,7 @@ public async Task HandleAsync(GetMediaFile query, CancellationToken can var base64String = Convert.ToBase64String(fileContent); return new FileDto(query.MediaFileId, fileSourceInfo.SourceId, fileSourceInfo.SourceType.ToString(), - fileSourceInfo.FileName, base64String); + fileSourceInfo.UploaderId, fileSourceInfo.FileName, base64String); } } } \ No newline at end of file From 8f88068e38666017c76823737507987f6e5c9420 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 00:30:30 +0200 Subject: [PATCH 13/62] (#92) and command and handler for deleting media file --- .../Program.cs | 1 + .../Commands/DeleteMediaFile.cs | 9 ++++ .../Handlers/DeleteMediaFileHandler.cs | 44 +++++++++++++++++++ .../Events/MediaFileDeleted.cs | 14 ++++++ .../Exceptions/MediaFileNotFoundException.cs | 14 ++++++ .../UnauthorizedMediaFileAccessException.cs | 18 ++++++++ .../Services/IGridFSService.cs | 1 + .../Services/GridFSService.cs | 5 +++ 8 files changed, 106 insertions(+) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/DeleteMediaFile.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteMediaFileHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/MediaFileDeleted.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/MediaFileNotFoundException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedMediaFileAccessException.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs index e48b936a2..434c231f0 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs @@ -35,6 +35,7 @@ public static async Task Main(string[] args) .Get("media-files/{mediaFileId}") .Post("media-files", afterDispatch: (cmd, ctx) => ctx.Response.Created($"media-files/{cmd.MediaFileId}")) + .Delete("media-files/{mediaFileId}") )) .UseLogging() .Build() diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/DeleteMediaFile.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/DeleteMediaFile.cs new file mode 100644 index 000000000..902fdefea --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/DeleteMediaFile.cs @@ -0,0 +1,9 @@ +using Convey.CQRS.Commands; + +namespace MiniSpace.Services.MediaFiles.Application.Commands +{ + public class DeleteMediaFile: ICommand + { + public Guid MediaFileId { get; set; } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteMediaFileHandler.cs new file mode 100644 index 000000000..cf9f7c2c7 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteMediaFileHandler.cs @@ -0,0 +1,44 @@ +using Convey.CQRS.Commands; +using MiniSpace.Services.MediaFiles.Application.Events; +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers +{ + public class DeleteMediaFileHandler: ICommandHandler + { + private readonly IFileSourceInfoRepository _fileSourceInfoRepository; + private readonly IGridFSService _gridFSService; + private readonly IAppContext _appContext; + private readonly IMessageBroker _messageBroker; + + public DeleteMediaFileHandler(IFileSourceInfoRepository fileSourceInfoRepository, IGridFSService gridFSService, + IAppContext appContext, IMessageBroker messageBroker) + { + _fileSourceInfoRepository = fileSourceInfoRepository; + _gridFSService = gridFSService; + _appContext = appContext; + _messageBroker = messageBroker; + } + + public async Task HandleAsync(DeleteMediaFile command, CancellationToken cancellationToken) + { + var fileSourceInfo = await _fileSourceInfoRepository.GetAsync(command.MediaFileId); + if (fileSourceInfo is null) + { + throw new MediaFileNotFoundException(command.MediaFileId); + } + + var identity = _appContext.Identity; + if(identity.IsAuthenticated && identity.Id != fileSourceInfo.UploaderId && !identity.IsAdmin) + { + throw new UnauthorizedMediaFileAccessException(fileSourceInfo.Id, identity.Id, fileSourceInfo.UploaderId); + } + + await _gridFSService.DeleteFileAsync(fileSourceInfo.FileId); + await _fileSourceInfoRepository.DeleteAsync(command.MediaFileId); + await _messageBroker.PublishAsync(new MediaFileDeleted(command.MediaFileId)); + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/MediaFileDeleted.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/MediaFileDeleted.cs new file mode 100644 index 000000000..dba259c5a --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/MediaFileDeleted.cs @@ -0,0 +1,14 @@ +using Convey.CQRS.Events; + +namespace MiniSpace.Services.MediaFiles.Application.Events +{ + public class MediaFileDeleted: IEvent + { + public Guid MediaFileId { get; } + + public MediaFileDeleted(Guid mediaFileId) + { + MediaFileId = mediaFileId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/MediaFileNotFoundException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/MediaFileNotFoundException.cs new file mode 100644 index 000000000..9c9bd144a --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/MediaFileNotFoundException.cs @@ -0,0 +1,14 @@ +namespace MiniSpace.Services.MediaFiles.Application.Exceptions +{ + public class MediaFileNotFoundException: AppException + { + public override string Code { get; } = "media_file_not_found"; + public Guid MediaFileId { get; } + + public MediaFileNotFoundException(Guid mediaFileId) + : base($"Media file with ID: {mediaFileId} was not found.") + { + MediaFileId = mediaFileId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedMediaFileAccessException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedMediaFileAccessException.cs new file mode 100644 index 000000000..e0b0e9395 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/UnauthorizedMediaFileAccessException.cs @@ -0,0 +1,18 @@ +namespace MiniSpace.Services.MediaFiles.Application.Exceptions +{ + public class UnauthorizedMediaFileAccessException: AppException + { + public override string Code { get; } = "unauthorized_media_file_access"; + public Guid MediaFileId { get; } + public Guid UserId { get; } + public Guid UploaderId { get; } + + public UnauthorizedMediaFileAccessException(Guid mediaFileId, Guid userId, Guid uploaderId) + : base($"User with ID: {userId} tried to access media file with ID: {mediaFileId} uploaded by user with ID: {uploaderId}.") + { + MediaFileId = mediaFileId; + UserId = userId; + UploaderId = uploaderId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IGridFSService.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IGridFSService.cs index 6cb0c2e09..0f40c2100 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IGridFSService.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IGridFSService.cs @@ -6,5 +6,6 @@ public interface IGridFSService { Task UploadFileAsync(string fileName, Stream fileStream); Task DownloadFileAsync(ObjectId fileId, Stream destination); + Task DeleteFileAsync(ObjectId fileId); } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/GridFSService.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/GridFSService.cs index bd1b90e15..35c7e60a4 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/GridFSService.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/GridFSService.cs @@ -26,5 +26,10 @@ public async Task DownloadFileAsync(ObjectId fileId, Stream destination) { await _gridFSBucket.DownloadToStreamAsync(fileId, destination); } + + public async Task DeleteFileAsync(ObjectId fileId) + { + await _gridFSBucket.DeleteAsync(fileId); + } } } \ No newline at end of file From dde5b624ad30ce73fb353de61a63b54297f2ccd2 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 00:55:38 +0200 Subject: [PATCH 14/62] (#92) add external events --- .../Handlers/DeleteMediaFileHandler.cs | 3 ++- .../Events/External/EventCreated.cs | 18 ++++++++++++++++++ .../External/Handlers/StudentCreatedHandler.cs | 6 ++++++ .../Events/External/PostCreated.cs | 18 ++++++++++++++++++ .../Events/External/StudentCreated.cs | 18 ++++++++++++++++++ .../Events/External/StudentUpdated.cs | 18 ++++++++++++++++++ .../Events/MediaFileDeleted.cs | 6 +++++- .../Extensions.cs | 9 ++------- 8 files changed, 87 insertions(+), 9 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/EventCreated.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentCreatedHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/PostCreated.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentCreated.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentUpdated.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteMediaFileHandler.cs index cf9f7c2c7..b025de766 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteMediaFileHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteMediaFileHandler.cs @@ -38,7 +38,8 @@ public async Task HandleAsync(DeleteMediaFile command, CancellationToken cancell await _gridFSService.DeleteFileAsync(fileSourceInfo.FileId); await _fileSourceInfoRepository.DeleteAsync(command.MediaFileId); - await _messageBroker.PublishAsync(new MediaFileDeleted(command.MediaFileId)); + await _messageBroker.PublishAsync(new MediaFileDeleted(command.MediaFileId, + fileSourceInfo.SourceId, fileSourceInfo.SourceType.ToString())); } } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/EventCreated.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/EventCreated.cs new file mode 100644 index 000000000..6bac7fdc7 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/EventCreated.cs @@ -0,0 +1,18 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("events")] + public class EventCreated : IEvent + { + public Guid EventId { get; } + public IEnumerable MediaFilesIds { get; } + + public EventCreated(Guid eventId, IEnumerable mediaFilesIds) + { + EventId = eventId; + MediaFilesIds = mediaFilesIds; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentCreatedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentCreatedHandler.cs new file mode 100644 index 000000000..b00ffb5d2 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentCreatedHandler.cs @@ -0,0 +1,6 @@ +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers; + +public class StudentCreatedHandler +{ + +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/PostCreated.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/PostCreated.cs new file mode 100644 index 000000000..2c54d7f29 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/PostCreated.cs @@ -0,0 +1,18 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("posts")] + public class PostCreated : IEvent + { + public Guid PostId { get; } + public IEnumerable MediaFilesIds { get; } + + public PostCreated(Guid postId, IEnumerable mediaFilesIds) + { + PostId = postId; + MediaFilesIds = mediaFilesIds; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentCreated.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentCreated.cs new file mode 100644 index 000000000..0726ee120 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentCreated.cs @@ -0,0 +1,18 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("students")] + public class StudentCreated : IEvent + { + public Guid StudentId { get; } + public Guid MediaFileId { get; } + + public StudentCreated(Guid studentId, Guid mediaFileId) + { + StudentId = studentId; + MediaFileId = mediaFileId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentUpdated.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentUpdated.cs new file mode 100644 index 000000000..43ebef223 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentUpdated.cs @@ -0,0 +1,18 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("students")] + public class StudentUpdated : IEvent + { + public Guid StudentId { get; } + public Guid MediaFileId { get; } + + public StudentUpdated(Guid studentId, Guid mediaFileId) + { + StudentId = studentId; + MediaFileId = mediaFileId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/MediaFileDeleted.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/MediaFileDeleted.cs index dba259c5a..a7eb41a84 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/MediaFileDeleted.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/MediaFileDeleted.cs @@ -5,10 +5,14 @@ namespace MiniSpace.Services.MediaFiles.Application.Events public class MediaFileDeleted: IEvent { public Guid MediaFileId { get; } + public Guid SourceId { get; } + public string Source { get; } - public MediaFileDeleted(Guid mediaFileId) + public MediaFileDeleted(Guid mediaFileId, Guid sourceId, string source) { MediaFileId = mediaFileId; + SourceId = sourceId; + Source = source; } } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs index 8b42043ca..a0d853296 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs @@ -92,14 +92,9 @@ public static IApplicationBuilder UseInfrastructure(this IApplicationBuilder app .UseMetrics() .UseCertificateAuthentication() .UseRabbitMq() - .SubscribeCommand(); + .SubscribeCommand() + .SubscribeCommand(); //.SubscribeEvent() - //.SubscribeEvent() - //.SubscribeEvent() - //.SubscribeEvent() - //.SubscribeEvent() - //.SubscribeEvent() - //.SubscribeEvent(); return app; } From d7d46079353beeaba86f15c38614d63e6040e459 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 01:15:30 +0200 Subject: [PATCH 15/62] (#92) add external events handlers --- .../External/Handlers/EventCreatedHandler.cs | 37 +++++++++++++++++++ .../External/Handlers/PostCreatedHandler.cs | 37 +++++++++++++++++++ .../Handlers/StudentCreatedHandler.cs | 37 +++++++++++++++++-- .../Handlers/StudentUpdatedHandler.cs | 37 +++++++++++++++++++ .../Repositories/IFileSourceInfoRepository.cs | 1 + .../Extensions.cs | 8 +++- .../FileSourceInfoMongoRepository.cs | 8 ++++ 7 files changed, 160 insertions(+), 5 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventCreatedHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostCreatedHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentUpdatedHandler.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventCreatedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventCreatedHandler.cs new file mode 100644 index 000000000..be62db8e6 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventCreatedHandler.cs @@ -0,0 +1,37 @@ +using Convey.CQRS.Commands; +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers +{ + public class EventCreatedHandler : IEventHandler + { + private readonly IFileSourceInfoRepository _fileSourceInfoRepository; + private readonly ICommandDispatcher _commandDispatcher; + + public EventCreatedHandler(IFileSourceInfoRepository fileSourceInfoRepository, ICommandDispatcher commandDispatcher) + { + _fileSourceInfoRepository = fileSourceInfoRepository; + _commandDispatcher = commandDispatcher; + } + + public async Task HandleAsync(EventCreated @event, CancellationToken cancellationToken) + { + var fileSourceInfos = + await _fileSourceInfoRepository.FindAsync(@event.EventId, ContextType.Event); + foreach (var fileSourceInfo in fileSourceInfos) + { + if(!@event.MediaFilesIds.Contains(fileSourceInfo.Id)) + { + await _commandDispatcher.SendAsync(new DeleteMediaFile + { + MediaFileId = fileSourceInfo.Id + }, + cancellationToken); + } + } + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostCreatedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostCreatedHandler.cs new file mode 100644 index 000000000..bd36ee387 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostCreatedHandler.cs @@ -0,0 +1,37 @@ +using Convey.CQRS.Commands; +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers +{ + public class PostCreatedHandler : IEventHandler + { + private readonly IFileSourceInfoRepository _fileSourceInfoRepository; + private readonly ICommandDispatcher _commandDispatcher; + + public PostCreatedHandler(IFileSourceInfoRepository fileSourceInfoRepository, ICommandDispatcher commandDispatcher) + { + _fileSourceInfoRepository = fileSourceInfoRepository; + _commandDispatcher = commandDispatcher; + } + + public async Task HandleAsync(PostCreated @event, CancellationToken cancellationToken) + { + var fileSourceInfos = + await _fileSourceInfoRepository.FindAsync(@event.PostId, ContextType.Post); + foreach (var fileSourceInfo in fileSourceInfos) + { + if(!@event.MediaFilesIds.Contains(fileSourceInfo.Id)) + { + await _commandDispatcher.SendAsync(new DeleteMediaFile + { + MediaFileId = fileSourceInfo.Id + }, + cancellationToken); + } + } + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentCreatedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentCreatedHandler.cs index b00ffb5d2..afb80dc1f 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentCreatedHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentCreatedHandler.cs @@ -1,6 +1,37 @@ -namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers; +using Convey.CQRS.Commands; +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Core.Repositories; -public class StudentCreatedHandler +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers { - + public class StudentCreatedHandler : IEventHandler + { + private readonly IFileSourceInfoRepository _fileSourceInfoRepository; + private readonly ICommandDispatcher _commandDispatcher; + + public StudentCreatedHandler(IFileSourceInfoRepository fileSourceInfoRepository, ICommandDispatcher commandDispatcher) + { + _fileSourceInfoRepository = fileSourceInfoRepository; + _commandDispatcher = commandDispatcher; + } + + public async Task HandleAsync(StudentCreated @event, CancellationToken cancellationToken) + { + var fileSourceInfos = + await _fileSourceInfoRepository.FindAsync(@event.StudentId, ContextType.StudentProfile); + foreach (var fileSourceInfo in fileSourceInfos) + { + if (fileSourceInfo.Id != @event.MediaFileId) + { + await _commandDispatcher.SendAsync(new DeleteMediaFile + { + MediaFileId = fileSourceInfo.Id + }, + cancellationToken); + } + } + } + } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentUpdatedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentUpdatedHandler.cs new file mode 100644 index 000000000..760ff17ce --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentUpdatedHandler.cs @@ -0,0 +1,37 @@ +using Convey.CQRS.Commands; +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers +{ + public class StudentUpdatedHandler : IEventHandler + { + private readonly IFileSourceInfoRepository _fileSourceInfoRepository; + private readonly ICommandDispatcher _commandDispatcher; + + public StudentUpdatedHandler(IFileSourceInfoRepository fileSourceInfoRepository, ICommandDispatcher commandDispatcher) + { + _fileSourceInfoRepository = fileSourceInfoRepository; + _commandDispatcher = commandDispatcher; + } + + public async Task HandleAsync(StudentUpdated @event, CancellationToken cancellationToken) + { + var fileSourceInfos = + await _fileSourceInfoRepository.FindAsync(@event.StudentId, ContextType.StudentProfile); + foreach (var fileSourceInfo in fileSourceInfos) + { + if (fileSourceInfo.Id != @event.MediaFileId) + { + await _commandDispatcher.SendAsync(new DeleteMediaFile + { + MediaFileId = fileSourceInfo.Id + }, + cancellationToken); + } + } + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IFileSourceInfoRepository.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IFileSourceInfoRepository.cs index 45b6cc48c..8038922d2 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IFileSourceInfoRepository.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IFileSourceInfoRepository.cs @@ -9,5 +9,6 @@ public interface IFileSourceInfoRepository Task UpdateAsync(FileSourceInfo fileSourceInfo); Task DeleteAsync(Guid id); Task ExistsAsync(Guid id); + Task> FindAsync(Guid sourceId, ContextType sourceType); } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs index a0d853296..d2d5334de 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs @@ -28,6 +28,7 @@ using Newtonsoft.Json; using MiniSpace.Services.MediaFiles.Application; using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Application.Events.External; using MiniSpace.Services.MediaFiles.Application.Services; using MiniSpace.Services.MediaFiles.Core.Repositories; using MiniSpace.Services.MediaFiles.Infrastructure.Contexts; @@ -93,8 +94,11 @@ public static IApplicationBuilder UseInfrastructure(this IApplicationBuilder app .UseCertificateAuthentication() .UseRabbitMq() .SubscribeCommand() - .SubscribeCommand(); - //.SubscribeEvent() + .SubscribeCommand() + .SubscribeEvent() + .SubscribeEvent() + .SubscribeEvent() + .SubscribeEvent(); return app; } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/FileSourceInfoMongoRepository.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/FileSourceInfoMongoRepository.cs index 0826cc8bc..038221a1b 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/FileSourceInfoMongoRepository.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/FileSourceInfoMongoRepository.cs @@ -38,5 +38,13 @@ public Task DeleteAsync(Guid id) public Task ExistsAsync(Guid id) => _repository.ExistsAsync(s => s.Id == id); + + public async Task> FindAsync(Guid sourceId, ContextType sourceType) + { + var fileSourceInfos = await _repository.FindAsync( + s => s.SourceId == sourceId && s.SourceType == sourceType); + + return fileSourceInfos?.Select(s => s.AsEntity()); + } } } \ No newline at end of file From fab3364e740f768500d6cd4b639ae1858661f2aa Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 01:21:32 +0200 Subject: [PATCH 16/62] (#92) udpate logging messages --- .../Logging/MessageToLogTemplateMapper.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs index a12c818e3..7cc16a06f 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs @@ -1,5 +1,6 @@ using Convey.Logging.CQRS; using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Application.Events.External; namespace MiniSpace.Services.MediaFiles.Infrastructure.Logging { @@ -14,6 +15,40 @@ private static IReadOnlyDictionary MessageTemplates After = "Uploaded media file with ID: {MediaFileId} and name: {FileName}.", } }, + { + typeof(DeleteMediaFile), new HandlerLogTemplate + { + After = "Deleted media file with ID: {MediaFileId}.", + } + }, + { + typeof(StudentCreated), + new HandlerLogTemplate + { + After = "Cleaned unmatched files for student with ID: {StudentId}.", + } + }, + { + typeof(StudentUpdated), + new HandlerLogTemplate + { + After = "Cleaned unmatched files for student with ID: {StudentId}.", + } + }, + { + typeof(PostCreated), + new HandlerLogTemplate + { + After = "Cleaned unmatched files for post with ID: {PostId}.", + } + }, + { + typeof(EventCreated), + new HandlerLogTemplate + { + After = "Cleaned unmatched files for event with ID: {EventId}.", + } + }, }; public HandlerLogTemplate Map(TMessage message) where TMessage : class From e11b53dd971ce3c7bcee4869ea3939d598691aab Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 01:37:38 +0200 Subject: [PATCH 17/62] (#31) add media files service --- .../src/MiniSpace.APIGateway/ntrada.yml | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.yml b/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.yml index 09bbf1df4..130b05224 100644 --- a/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.yml +++ b/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.yml @@ -588,13 +588,39 @@ modules: downstream: posts-service/posts/{postId} auth: true - services: posts-service: localUrl: localhost:5013 url: posts-service + + - + mediafiles: + path: /media-files + routes: + - upstream: / + method: POST + use: downstream + downstream: mediafiles-service/media-files + auth: true + + - upstream: /{mediaFileId} + method: GET + use: downstream + downstream: mediafiles-service/media-files/{mediaFileId} + + - upstream: /{mediaFileId} + method: DELETE + use: downstream + downstream: mediafiles-service/media-files/{mediaFileId} + auth: true + + services: + mediafiles-service: + localUrl: localhost:5014 + url: mediafiles-service + + organizations: path: /organizations From e160d079ca98f31726c23a2300b91f830d4903be Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 12:53:27 +0200 Subject: [PATCH 18/62] (#30) update add event handler to handle media files --- .../Commands/AddEvent.cs | 7 ++++++- .../Commands/Handlers/AddEventHandler.cs | 8 +++++--- .../DTO/EventDto.cs | 3 ++- .../Events/EventCreated.cs | 4 +++- .../InvalidEventMediaFilesSizeException.cs | 13 +++++++++++++ .../Services/IEventValidator.cs | 2 ++ .../Entities/Event.cs | 15 ++++++++------- .../Mongo/Documents/EventDocument.cs | 2 +- .../Mongo/Documents/Extensions.cs | 7 +++++-- .../Services/EventValidator.cs | 9 +++++++++ 10 files changed, 54 insertions(+), 16 deletions(-) create mode 100644 MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidEventMediaFilesSizeException.cs diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/AddEvent.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/AddEvent.cs index 8573c7592..74fc0bfea 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/AddEvent.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/AddEvent.cs @@ -1,4 +1,6 @@ using System; +using System.Collections; +using System.Collections.Generic; using Convey.CQRS.Commands; using MiniSpace.Services.Events.Core.Entities; @@ -18,6 +20,7 @@ public class AddEvent : ICommand public string ApartmentNumber { get; } public string City { get; } public string ZipCode { get; } + public IEnumerable MediaFiles { get; } public string Description { get; } public int Capacity { get; } public decimal Fee { get; } @@ -26,7 +29,8 @@ public class AddEvent : ICommand public AddEvent(Guid eventId, string name, Guid organizerId, Guid organizationId, string startDate, string endDate, string buildingName, string street, string buildingNumber, string apartmentNumber, - string city, string zipCode, string description, int capacity, decimal fee, string category, string publishDate) + string city, string zipCode, IEnumerable mediaFiles, string description, int capacity, decimal fee, + string category, string publishDate) { EventId = eventId == Guid.Empty ? Guid.NewGuid() : eventId; Name = name; @@ -40,6 +44,7 @@ public AddEvent(Guid eventId, string name, Guid organizerId, Guid organizationId ApartmentNumber = apartmentNumber; City = city; ZipCode = zipCode; + MediaFiles = mediaFiles; Description = description; Capacity = capacity; Fee = fee; diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/AddEventHandler.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/AddEventHandler.cs index 9c284e67b..b766ff50c 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/AddEventHandler.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/AddEventHandler.cs @@ -50,6 +50,7 @@ public async Task HandleAsync(AddEvent command, CancellationToken cancellationTo _eventValidator.ValidateDates(startDate, endDate, "event_start_date", "event_end_date"); var address = new Address(command.BuildingName, command.Street, command.BuildingNumber, command.ApartmentNumber, command.City, command.ZipCode); + _eventValidator.ValidateMediaFiles(command.MediaFiles.ToList()); _eventValidator.ValidateCapacity(command.Capacity); _eventValidator.ValidateFee(command.Fee); var category = _eventValidator.ParseCategory(command.Category); @@ -75,12 +76,13 @@ public async Task HandleAsync(AddEvent command, CancellationToken cancellationTo throw new OrganizerDoesNotBelongToOrganizationException(command.OrganizerId, command.OrganizationId); } - var organizer = new Organizer(command.OrganizerId, identity.Name, identity.Email, command.OrganizerId, organization.Name); + var organizer = new Organizer(command.OrganizerId, identity.Name, identity.Email, + command.OrganizerId, organization.Name); var @event = Event.Create(command.EventId, command.Name, command.Description, startDate, endDate, - address, command.Capacity, command.Fee, category, state, publishDate, organizer, now); + address, command.MediaFiles, command.Capacity, command.Fee, category, state, publishDate, organizer, now); await _eventRepository.AddAsync(@event); - await _messageBroker.PublishAsync(new EventCreated(@event.Id, @event.Organizer.Id)); + await _messageBroker.PublishAsync(new EventCreated(@event.Id, @event.Organizer.Id, @event.MediaFiles)); } } } \ No newline at end of file diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/DTO/EventDto.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/DTO/EventDto.cs index aa1352062..46fcd76b9 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/DTO/EventDto.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/DTO/EventDto.cs @@ -15,7 +15,7 @@ public class EventDto public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } public AddressDto Location { get; set; } - //public string Image { get; set; } + public IEnumerable MediaFiles { get; set; } public int InterestedStudents { get; set; } public int SignedUpStudents { get; set; } public int Capacity { get; set; } @@ -43,6 +43,7 @@ public EventDto(Event @event, Guid studentId) StartDate = @event.StartDate; EndDate = @event.EndDate; Location = new AddressDto(@event.Location); + MediaFiles = @event.MediaFiles; InterestedStudents = @event.InterestedStudents.Count(); SignedUpStudents = @event.SignedUpStudents.Count(); Capacity = @event.Capacity; diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventCreated.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventCreated.cs index 0df57828b..d4cb5f55f 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventCreated.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventCreated.cs @@ -1,11 +1,13 @@ using System; +using System.Collections.Generic; using Convey.CQRS.Events; namespace MiniSpace.Services.Events.Application.Events { - public class EventCreated(Guid eventId, Guid organizerId) : IEvent + public class EventCreated(Guid eventId, Guid organizerId, IEnumerable mediaFilesIds) : IEvent { public Guid EventId { get; set; } = eventId; public Guid OrganizerId { get; set; } = organizerId; + public IEnumerable MediaFilesIds { get; } = mediaFilesIds; } } \ No newline at end of file diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidEventMediaFilesSizeException.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidEventMediaFilesSizeException.cs new file mode 100644 index 000000000..f2e365b8a --- /dev/null +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidEventMediaFilesSizeException.cs @@ -0,0 +1,13 @@ +namespace MiniSpace.Services.Events.Application.Exceptions +{ + public class InvalidEventMediaFilesSizeException : AppException + { + public override string Code { get; } = "invalid_media_files_size"; + public int Size { get; } + + public InvalidEventMediaFilesSizeException(int size) : base($"Invalid media files size: {size}. It must be less or equal 5.") + { + Size = size; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Services/IEventValidator.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Services/IEventValidator.cs index cf1ad68b6..2f15e6ec2 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Services/IEventValidator.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Services/IEventValidator.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using MiniSpace.Services.Events.Core.Entities; namespace MiniSpace.Services.Events.Application.Services @@ -13,6 +14,7 @@ public interface IEventValidator (int pageNumber, int pageSize) PageFilter(int pageNumber, int pageSize); void ValidateName(string name); void ValidateDescription(string description); + void ValidateMediaFiles(List mediaFiles); void ValidateCapacity(int capacity); void ValidateFee(decimal fee); void ValidateUpdatedCapacity(int currentCapacity, int newCapacity); diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Entities/Event.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Entities/Event.cs index da9c0ffe0..59e118b65 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Entities/Event.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Entities/Event.cs @@ -17,7 +17,7 @@ public class Event: AggregateRoot public DateTime StartDate { get; private set; } public DateTime EndDate { get; private set; } public Address Location { get; private set; } - //public string Image { get; set; } + public IEnumerable MediaFiles { get; set; } public int Capacity { get; private set; } public decimal Fee { get; private set; } public Category Category { get; private set; } @@ -44,8 +44,8 @@ public IEnumerable Ratings } public Event(AggregateId id, string name, string description, DateTime startDate, DateTime endDate, - Address location, int capacity, decimal fee, Category category, State state, DateTime publishDate, - Organizer organizer, DateTime updatedAt, IEnumerable interestedStudents = null, + Address location, IEnumerable mediaFiles, int capacity, decimal fee, Category category, State state, + DateTime publishDate, Organizer organizer, DateTime updatedAt, IEnumerable interestedStudents = null, IEnumerable signedUpStudents = null, IEnumerable ratings = null) { Id = id; @@ -54,6 +54,7 @@ public Event(AggregateId id, string name, string description, DateTime startDat StartDate = startDate; EndDate = endDate; Location = location; + MediaFiles = mediaFiles; Capacity = capacity; Fee = fee; Category = category; @@ -67,11 +68,11 @@ public Event(AggregateId id, string name, string description, DateTime startDat } public static Event Create(AggregateId id, string name, string description, DateTime startDate, DateTime endDate, - Address location, int capacity, decimal fee, Category category, State state, DateTime publishDate, - Organizer organizer, DateTime now) + Address location, IEnumerable mediaFiles, int capacity, decimal fee, Category category, State state, + DateTime publishDate, Organizer organizer, DateTime now) { - var @event = new Event(id, name, description, startDate, endDate, location, capacity, fee, category, - state, publishDate, organizer, now); + var @event = new Event(id, name, description, startDate, endDate, location, mediaFiles, capacity, fee, + category, state, publishDate, organizer, now); return @event; } diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Mongo/Documents/EventDocument.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Mongo/Documents/EventDocument.cs index dffb5c2f7..6ac0ea993 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Mongo/Documents/EventDocument.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Mongo/Documents/EventDocument.cs @@ -15,7 +15,7 @@ public class EventDocument : IIdentifiable public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } public Address Location { get; set; } - //public string Image { get; set; } + public IEnumerable MediaFiles { get; set; } public IEnumerable InterestedStudents { get; set; } public IEnumerable SignedUpStudents { get; set; } public int Capacity { get; set; } diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Mongo/Documents/Extensions.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Mongo/Documents/Extensions.cs index 5464f8410..17b065488 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Mongo/Documents/Extensions.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Mongo/Documents/Extensions.cs @@ -18,6 +18,7 @@ public static EventDto AsDto(this EventDocument document, Guid studentId) StartDate = document.StartDate, EndDate = document.EndDate, Location = document.Location.AsDto(), + MediaFiles = document.MediaFiles, InterestedStudents = document.InterestedStudents.Count(), SignedUpStudents = document.SignedUpStudents.Count(), Capacity = document.Capacity, @@ -45,8 +46,9 @@ public static EventDto AsDtoWithFriends(this EventDocument document, Guid studen public static Event AsEntity(this EventDocument document) => new (document.Id, document.Name, document.Description, document.StartDate, document.EndDate, - document.Location, document.Capacity, document.Fee, document.Category, document.State, document.PublishDate, - document.Organizer, document.UpdatedAt,document.InterestedStudents, document.SignedUpStudents, document.Ratings); + document.Location, document.MediaFiles, document.Capacity, document.Fee, document.Category, + document.State, document.PublishDate, document.Organizer, document.UpdatedAt,document.InterestedStudents, + document.SignedUpStudents, document.Ratings); public static EventDocument AsDocument(this Event entity) => new () @@ -58,6 +60,7 @@ public static EventDocument AsDocument(this Event entity) StartDate = entity.StartDate, EndDate = entity.EndDate, Location = entity.Location, + MediaFiles = entity.MediaFiles, InterestedStudents = entity.InterestedStudents, SignedUpStudents = entity.SignedUpStudents, Capacity = entity.Capacity, diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Services/EventValidator.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Services/EventValidator.cs index 780893f12..1c9359eb7 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Services/EventValidator.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Services/EventValidator.cs @@ -1,5 +1,8 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.Globalization; +using System.Linq; using MiniSpace.Services.Events.Application.Exceptions; using MiniSpace.Services.Events.Application.Services; using MiniSpace.Services.Events.Core.Entities; @@ -73,6 +76,12 @@ public void ValidateDescription(string description) throw new InvalidEventDescriptionException(description); } + public void ValidateMediaFiles(List mediaFiles) + { + if (mediaFiles.Count > 5) + throw new InvalidEventMediaFilesSizeException(mediaFiles.Count); + } + public void ValidateCapacity(int capacity) { if (capacity <= 0 || capacity > 1000) From 730c1268c7911444090dc61c19de7d57a1f449f7 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 13:00:12 +0200 Subject: [PATCH 19/62] (#30) update handlers for updating and deleting an event --- .../Commands/Handlers/DeleteEventHandler.cs | 2 +- .../Commands/Handlers/UpdateEventHandler.cs | 7 +++++-- .../Commands/UpdateEvent.cs | 7 ++++++- .../Events/EventCreated.cs | 2 +- .../Events/EventDeleted.cs | 4 +++- .../Events/EventUpdated.cs | 5 ++++- 6 files changed, 20 insertions(+), 7 deletions(-) diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/DeleteEventHandler.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/DeleteEventHandler.cs index bc8736389..ef9365b25 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/DeleteEventHandler.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/DeleteEventHandler.cs @@ -37,7 +37,7 @@ public async Task HandleAsync(DeleteEvent command, CancellationToken cancellatio } await _eventRepository.DeleteAsync(command.EventId); - await _messageBroker.PublishAsync(new EventDeleted(command.EventId)); + await _messageBroker.PublishAsync(new EventDeleted(command.EventId, @event.MediaFiles)); } } } \ No newline at end of file diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/UpdateEventHandler.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/UpdateEventHandler.cs index de8ea2789..8b689f914 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/UpdateEventHandler.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/UpdateEventHandler.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System.Linq; +using System.Threading; using System.Threading.Tasks; using Convey.CQRS.Commands; using MiniSpace.Services.Events.Application.Events; @@ -54,6 +55,7 @@ public async Task HandleAsync(UpdateEvent command, CancellationToken cancellatio var address = @event.Location.Update(command.BuildingName, command.Street, command.BuildingNumber, command.ApartmentNumber, command.City, command.ZipCode); + _eventValidator.ValidateMediaFiles(command.MediaFiles.ToList()); var capacity = command.Capacity == 0 ? @event.Capacity : command.Capacity; _eventValidator.ValidateUpdatedCapacity(capacity, @event.Capacity); var fee = command.Fee == 0 ? @event.Fee : command.Fee; @@ -71,7 +73,8 @@ public async Task HandleAsync(UpdateEvent command, CancellationToken cancellatio @event.Update(name, description, startDate, endDate, address, capacity, fee, category, state, publishDate, now); await _eventRepository.UpdateAsync(@event); - await _messageBroker.PublishAsync(new EventUpdated(@event.Id, _dateTimeProvider.Now, identity.Id)); + await _messageBroker.PublishAsync(new EventUpdated(@event.Id, _dateTimeProvider.Now, + identity.Id, @event.MediaFiles)); } } } \ No newline at end of file diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/UpdateEvent.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/UpdateEvent.cs index 7cc856df7..c58f4b248 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/UpdateEvent.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/UpdateEvent.cs @@ -1,4 +1,6 @@ using System; +using System.Collections; +using System.Collections.Generic; using Convey.CQRS.Commands; namespace MiniSpace.Services.Events.Application.Commands @@ -16,6 +18,7 @@ public class UpdateEvent : ICommand public string ApartmentNumber { get; } public string City { get; } public string ZipCode { get; } + public IEnumerable MediaFiles { get; } public string Description { get; } public int Capacity { get; } public decimal Fee { get; } @@ -24,7 +27,8 @@ public class UpdateEvent : ICommand public UpdateEvent(Guid eventId, string name, Guid organizerId, string startDate, string endDate, string buildingName, string street, string buildingNumber, string apartmentNumber, string city, - string zipCode, string description, int capacity, decimal fee, string category, string publishDate) + string zipCode, IEnumerable mediaFiles, string description, int capacity, decimal fee, + string category, string publishDate) { EventId = eventId; Name = name; @@ -37,6 +41,7 @@ public UpdateEvent(Guid eventId, string name, Guid organizerId, string startDate ApartmentNumber = apartmentNumber; City = city; ZipCode = zipCode; + MediaFiles = mediaFiles; Description = description; Capacity = capacity; Fee = fee; diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventCreated.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventCreated.cs index d4cb5f55f..7888984c9 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventCreated.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventCreated.cs @@ -8,6 +8,6 @@ public class EventCreated(Guid eventId, Guid organizerId, IEnumerable medi { public Guid EventId { get; set; } = eventId; public Guid OrganizerId { get; set; } = organizerId; - public IEnumerable MediaFilesIds { get; } = mediaFilesIds; + public IEnumerable MediaFilesIds { get; set; } = mediaFilesIds; } } \ No newline at end of file diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventDeleted.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventDeleted.cs index a39a19cb8..f6f8083b8 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventDeleted.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventDeleted.cs @@ -1,10 +1,12 @@ using System; +using System.Collections.Generic; using Convey.CQRS.Events; namespace MiniSpace.Services.Events.Application.Events { - public class EventDeleted(Guid eventId) : IEvent + public class EventDeleted(Guid eventId, IEnumerable mediaFilesIds) : IEvent { public Guid EventId { get; set; } = eventId; + public IEnumerable MediaFilesIds { get; set; } = mediaFilesIds; } } \ No newline at end of file diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventUpdated.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventUpdated.cs index c0e79da44..ce9291901 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventUpdated.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventUpdated.cs @@ -1,12 +1,15 @@ using System; +using System.Collections; +using System.Collections.Generic; using Convey.CQRS.Events; namespace MiniSpace.Services.Events.Application.Events { - public class EventUpdated(Guid eventId, DateTime updatedAt, Guid updatedBy) : IEvent + public class EventUpdated(Guid eventId, DateTime updatedAt, Guid updatedBy, IEnumerable mediaFilesIds) : IEvent { public Guid EventId { get; set; } = eventId; public DateTime UpdatedAt { get; set; } = updatedAt; public Guid UpdatedBy { get; set; } = updatedBy; + public IEnumerable MediaFilesIds { get; set; } = mediaFilesIds; } } \ No newline at end of file From cfc334c108d39cad59854b0e884a2c9e15c7897a Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 13:11:09 +0200 Subject: [PATCH 20/62] (#30) add external event MediaFileDeleted --- .../Handlers/MediaFileDeletedHandler.cs | 32 +++++++++++++++++++ .../Events/External/MediaFileDeleted.cs | 21 ++++++++++++ .../Entities/Event.cs | 9 ++++++ .../Exceptions/MediaFileNotFoundException.cs | 18 +++++++++++ 4 files changed, 80 insertions(+) create mode 100644 MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/External/Handlers/MediaFileDeletedHandler.cs create mode 100644 MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/External/MediaFileDeleted.cs create mode 100644 MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Exceptions/MediaFileNotFoundException.cs diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/External/Handlers/MediaFileDeletedHandler.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/External/Handlers/MediaFileDeletedHandler.cs new file mode 100644 index 000000000..c020a9f18 --- /dev/null +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/External/Handlers/MediaFileDeletedHandler.cs @@ -0,0 +1,32 @@ +using System.Threading; +using System.Threading.Tasks; +using Convey.CQRS.Events; +using MiniSpace.Services.Events.Core.Repositories; + +namespace MiniSpace.Services.Events.Application.Events.External.Handlers +{ + public class MediaFileDeletedHandler: IEventHandler + { + private readonly IEventRepository _eventRepository; + + public MediaFileDeletedHandler(IEventRepository eventRepository) + { + _eventRepository = eventRepository; + } + + public async Task HandleAsync(MediaFileDeleted @event, CancellationToken cancellationToken) + { + if(@event.Source.ToLowerInvariant() != "events") + { + return; + } + + var foundEvent = await _eventRepository.GetAsync(@event.SourceId); + if(foundEvent != null) + { + foundEvent.RemoveMediaFile(@event.MediaFileId); + await _eventRepository.UpdateAsync(foundEvent); + } + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/External/MediaFileDeleted.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/External/MediaFileDeleted.cs new file mode 100644 index 000000000..b3b300b9d --- /dev/null +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/External/MediaFileDeleted.cs @@ -0,0 +1,21 @@ +using System; +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.Events.Application.Events.External +{ + [Message("mediafiles")] + public class MediaFileDeleted: IEvent + { + public Guid MediaFileId { get; } + public Guid SourceId { get; } + public string Source { get; } + + public MediaFileDeleted(Guid mediaFileId, Guid sourceId, string source) + { + MediaFileId = mediaFileId; + SourceId = sourceId; + Source = source; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Entities/Event.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Entities/Event.cs index 59e118b65..9f1d6c830 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Entities/Event.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Entities/Event.cs @@ -214,6 +214,15 @@ private void ChangeState(State state) State = state; } + public void RemoveMediaFile(Guid mediaFileId) + { + var mediaFile = MediaFiles.SingleOrDefault(mf => mf == mediaFileId); + if (mediaFile == Guid.Empty) + { + throw new MediaFileNotFoundException(mediaFileId, Id); + } + } + public bool IsOrganizer(Guid organizerId) => Organizer.Id == organizerId; } diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Exceptions/MediaFileNotFoundException.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Exceptions/MediaFileNotFoundException.cs new file mode 100644 index 000000000..305ba98d0 --- /dev/null +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Exceptions/MediaFileNotFoundException.cs @@ -0,0 +1,18 @@ +using System; + +namespace MiniSpace.Services.Events.Core.Exceptions +{ + public class MediaFileNotFoundException : DomainException + { + public override string Code { get; } = "media_file_not_found"; + public Guid MediaFileId { get; } + public Guid EventId { get; } + + public MediaFileNotFoundException(Guid mediaFileId, Guid eventId) + : base($"Media file with ID: '{mediaFileId}' was not found for event with ID: {eventId}.") + { + MediaFileId = mediaFileId; + EventId = eventId; + } + } +} \ No newline at end of file From 242f1db939abfff54f4608ecbf8ef3a3da41884a Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 13:20:11 +0200 Subject: [PATCH 21/62] (#32) update post entities for media files --- .../Dto/PostDto.cs | 2 +- .../Events/PostCreated.cs | 4 +++- .../Events/PostDeleted.cs | 4 +++- .../Events/PostUpdated.cs | 4 +++- .../Entities/Post.cs | 16 ++++++++-------- .../Mongo/Documents/Extensions.cs | 6 +++--- .../Mongo/Documents/PostDocument.cs | 2 +- 7 files changed, 22 insertions(+), 16 deletions(-) diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/PostDto.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/PostDto.cs index cfce86bad..49c7359cb 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/PostDto.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Dto/PostDto.cs @@ -6,7 +6,7 @@ public class PostDto public Guid EventId { get; set; } public Guid OrganizerId { get; set; } public string TextContent { get; set; } - public string MediaContent { get; set; } + public IEnumerable MediaFiles { get; set; } public string State { get; set; } public DateTime? PublishDate { get; set; } public DateTime CreatedAt { get; set; } diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostCreated.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostCreated.cs index 6675de454..bf44c36ed 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostCreated.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostCreated.cs @@ -5,10 +5,12 @@ namespace MiniSpace.Services.Posts.Application.Events public class PostCreated : IEvent { public Guid PostId { get; } + public IEnumerable MediaFilesIds { get; } - public PostCreated(Guid postId) + public PostCreated(Guid postId, IEnumerable mediaFilesIds) { PostId = postId; + MediaFilesIds = mediaFilesIds; } } } diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostDeleted.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostDeleted.cs index 1b20677ad..12500b790 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostDeleted.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostDeleted.cs @@ -5,10 +5,12 @@ namespace MiniSpace.Services.Posts.Application.Events public class PostDeleted : IEvent { public Guid PostId { get; } + public IEnumerable MediaFilesIds { get; } - public PostDeleted(Guid postId) + public PostDeleted(Guid postId, IEnumerable mediaFilesIds) { PostId = postId; + MediaFilesIds = mediaFilesIds; } } } diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostUpdated.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostUpdated.cs index f6471e54f..e1a6a3d95 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostUpdated.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostUpdated.cs @@ -5,10 +5,12 @@ namespace MiniSpace.Services.Posts.Application.Events public class PostUpdated : IEvent { public Guid PostId { get; } + public IEnumerable MediaFilesIds { get; } - public PostUpdated(Guid postId) + public PostUpdated(Guid postId, IEnumerable mediaFilesIds) { PostId = postId; + MediaFilesIds = mediaFilesIds; } } } diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Entities/Post.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Entities/Post.cs index d97c788c3..fd9c011ca 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Entities/Post.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Entities/Post.cs @@ -7,20 +7,20 @@ public class Post : AggregateRoot public Guid EventId { get; private set; } public Guid OrganizerId { get; private set; } public string TextContent { get; private set; } - public string MediaContent { get; private set; } + public IEnumerable MediaFiles { get; private set; } public State State { get; private set; } public DateTime? PublishDate { get; private set; } public DateTime CreatedAt { get; private set; } public DateTime? UpdatedAt { get; private set; } - public Post(Guid id, Guid eventId, Guid organizerId, string textContent, - string mediaContent, DateTime createdAt, State state, DateTime? publishDate, DateTime? updatedAt = null) + public Post(Guid id, Guid eventId, Guid organizerId, string textContent, IEnumerable mediaFiles, + DateTime createdAt, State state, DateTime? publishDate, DateTime? updatedAt = null) { Id = id; EventId = eventId; OrganizerId = organizerId; TextContent = textContent; - MediaContent = mediaContent; + MediaFiles = mediaFiles; CreatedAt = createdAt; UpdatedAt = updatedAt; State = state; @@ -68,19 +68,19 @@ public bool UpdateState(DateTime now) } public static Post Create(AggregateId id, Guid eventId, Guid studentId, string textContent, - string mediaContent, DateTime createdAt, State state, DateTime? publishDate) + IEnumerable mediaFiles, DateTime createdAt, State state, DateTime? publishDate) { CheckTextContent(id, textContent); - return new Post(id, eventId, studentId, textContent, mediaContent, createdAt, state, publishDate); + return new Post(id, eventId, studentId, textContent, mediaFiles, createdAt, state, publishDate); } - public void Update(string textContent, string mediaContent, DateTime now) + public void Update(string textContent, IEnumerable mediaFiles, DateTime now) { CheckTextContent(Id, textContent); TextContent = textContent; - MediaContent = mediaContent; + MediaFiles = mediaFiles; UpdatedAt = now; } diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Documents/Extensions.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Documents/Extensions.cs index 86c7f63da..f02e7606b 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Documents/Extensions.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Documents/Extensions.cs @@ -7,7 +7,7 @@ public static class Extensions { public static Post AsEntity(this PostDocument document) => new Post(document.Id, document.EventId, document.OrganizerId, document.TextContent, - document.MediaContent, document.CreatedAt, document.State, document.PublishDate, document.UpdatedAt); + document.MediaFiles, document.CreatedAt, document.State, document.PublishDate, document.UpdatedAt); public static PostDocument AsDocument(this Post entity) => new PostDocument() @@ -16,7 +16,7 @@ public static PostDocument AsDocument(this Post entity) EventId = entity.EventId, OrganizerId = entity.OrganizerId, TextContent = entity.TextContent, - MediaContent = entity.MediaContent, + MediaFiles = entity.MediaFiles, CreatedAt = entity.CreatedAt, UpdatedAt = entity.UpdatedAt, State = entity.State, @@ -30,7 +30,7 @@ public static PostDto AsDto(this PostDocument document) EventId = document.EventId, OrganizerId = document.OrganizerId, TextContent = document.TextContent, - MediaContent = document.MediaContent, + MediaFiles = document.MediaFiles, CreatedAt = document.CreatedAt, UpdatedAt = document.UpdatedAt, State = document.State.ToString().ToLowerInvariant(), diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Documents/PostDocument.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Documents/PostDocument.cs index 7ca45ee4e..12af21c96 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Documents/PostDocument.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Documents/PostDocument.cs @@ -9,7 +9,7 @@ public class PostDocument : IIdentifiable public Guid EventId { get; set; } public Guid OrganizerId { get; set; } public string TextContent { get; set; } - public string MediaContent { get; set; } + public IEnumerable MediaFiles { get; set; } public State State { get; set; } public DateTime? PublishDate { get; set; } public DateTime CreatedAt { get; set; } From f61e755156a73c46d49167c6c788a1ec13f21fe3 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 13:30:24 +0200 Subject: [PATCH 22/62] (#32) update post handlers to publish updated events --- .../Commands/CreatePost.cs | 6 +++--- .../Commands/Handlers/CreatePostHandler.cs | 10 ++++++++-- .../Commands/Handlers/DeletePostHandler.cs | 2 +- .../Commands/Handlers/UpdatePostHandler.cs | 10 ++++++++-- .../Commands/UpdatePost.cs | 6 +++--- .../InvalidNumberOfPostMediaFilesException.cs | 16 ++++++++++++++++ 6 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Exceptions/InvalidNumberOfPostMediaFilesException.cs diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/CreatePost.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/CreatePost.cs index 0291c545f..24c50dbb3 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/CreatePost.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/CreatePost.cs @@ -8,18 +8,18 @@ public class CreatePost : ICommand public Guid EventId { get; } public Guid OrganizerId { get; } public string TextContent { get; } - public string MediaContent { get; } + public IEnumerable MediaFiles { get; } public string State { get; } public DateTime? PublishDate { get; } public CreatePost(Guid postId, Guid eventId, Guid organizerId, string textContent, - string mediaContent, string state, DateTime? publishDate) + IEnumerable mediaFiles, string state, DateTime? publishDate) { PostId = postId == Guid.Empty ? Guid.NewGuid() : postId; EventId = eventId; OrganizerId = organizerId; TextContent = textContent; - MediaContent = mediaContent; + MediaFiles = mediaFiles; State = state; PublishDate = publishDate; } diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/CreatePostHandler.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/CreatePostHandler.cs index 132d00a84..5ea7fda5a 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/CreatePostHandler.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/CreatePostHandler.cs @@ -44,6 +44,12 @@ public async Task HandleAsync(CreatePost command, CancellationToken cancellation { throw new InvalidPostStateException(command.State); } + + var mediaFiles = command.MediaFiles.ToList(); + if(mediaFiles.Count > 3) + { + throw new InvalidNumberOfPostMediaFilesException(command.PostId, mediaFiles.Count); + } switch (newState) { @@ -54,10 +60,10 @@ public async Task HandleAsync(CreatePost command, CancellationToken cancellation } var post = Post.Create(command.PostId, command.EventId, command.OrganizerId, command.TextContent, - command.MediaContent, _dateTimeProvider.Now, newState, command.PublishDate); + command.MediaFiles, _dateTimeProvider.Now, newState, command.PublishDate); await _postRepository.AddAsync(post); - await _messageBroker.PublishAsync(new PostCreated(command.PostId)); + await _messageBroker.PublishAsync(new PostCreated(command.PostId, post.MediaFiles)); } } } diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/DeletePostHandler.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/DeletePostHandler.cs index 1430155a5..5060e706e 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/DeletePostHandler.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/DeletePostHandler.cs @@ -42,7 +42,7 @@ public async Task HandleAsync(DeletePost command, CancellationToken cancellation await _postRepository.DeleteAsync(command.PostId); - await _messageBroker.PublishAsync(new PostDeleted(command.PostId)); + await _messageBroker.PublishAsync(new PostDeleted(command.PostId, post.MediaFiles)); } } } diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/UpdatePostHandler.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/UpdatePostHandler.cs index f14af1fab..ee725ab9e 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/UpdatePostHandler.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/UpdatePostHandler.cs @@ -42,10 +42,16 @@ public async Task HandleAsync(UpdatePost command, CancellationToken cancellation throw new UnauthorizedPostOperationException(command.PostId, identity.Id); } - post.Update(command.TextContent, command.MediaContent, _dateTimeProvider.Now); + var mediaFiles = command.MediaFiles.ToList(); + if(mediaFiles.Count > 3) + { + throw new InvalidNumberOfPostMediaFilesException(post.Id, mediaFiles.Count); + } + + post.Update(command.TextContent, command.MediaFiles, _dateTimeProvider.Now); await _postRepository.UpdateAsync(post); - await _messageBroker.PublishAsync(new PostUpdated(command.PostId)); + await _messageBroker.PublishAsync(new PostUpdated(command.PostId, post.MediaFiles)); } } } diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/UpdatePost.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/UpdatePost.cs index 00f6d6f40..e180055a3 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/UpdatePost.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/UpdatePost.cs @@ -6,13 +6,13 @@ public class UpdatePost : ICommand { public Guid PostId { get; } public string TextContent { get; } - public string MediaContent { get; } + public IEnumerable MediaFiles { get; } - public UpdatePost(Guid postId, string textContent, string mediaContent) + public UpdatePost(Guid postId, string textContent, IEnumerable mediaFiles) { PostId = postId; TextContent = textContent; - MediaContent = mediaContent; + MediaFiles = mediaFiles; } } } diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Exceptions/InvalidNumberOfPostMediaFilesException.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Exceptions/InvalidNumberOfPostMediaFilesException.cs new file mode 100644 index 000000000..481fd5d4e --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Exceptions/InvalidNumberOfPostMediaFilesException.cs @@ -0,0 +1,16 @@ +namespace MiniSpace.Services.Posts.Application.Exceptions +{ + public class InvalidNumberOfPostMediaFilesException : AppException + { + public override string Code { get; } = "invalid_number_of_post_media_files"; + public Guid PostId { get; } + public int MediaSizeNumber { get; } + + public InvalidNumberOfPostMediaFilesException(Guid postId, int mediaFilesNumber) + : base($"Invalid media files number: {mediaFilesNumber} for post with ID: '{postId}'. It should be less or equal 3.") + { + PostId = postId; + MediaSizeNumber = mediaFilesNumber; + } + } +} \ No newline at end of file From d1442930bd502315eaded1f05b6029b420570a7b Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 13:37:15 +0200 Subject: [PATCH 23/62] (#32) add external event MediaFileDeleted --- .../Handlers/MediaFileDeletedHandler.cs | 33 +++++++++++++++++++ .../Events/External/MediaFileDeleted.cs | 20 +++++++++++ .../Entities/Post.cs | 9 +++++ .../Exceptions/MediaFileNotFoundException.cs | 16 +++++++++ 4 files changed, 78 insertions(+) create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/External/Handlers/MediaFileDeletedHandler.cs create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/External/MediaFileDeleted.cs create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Exceptions/MediaFileNotFoundException.cs diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/External/Handlers/MediaFileDeletedHandler.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/External/Handlers/MediaFileDeletedHandler.cs new file mode 100644 index 000000000..971421190 --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/External/Handlers/MediaFileDeletedHandler.cs @@ -0,0 +1,33 @@ +using Convey.CQRS.Events; +using MiniSpace.Services.Posts.Application.Services; +using MiniSpace.Services.Posts.Core.Repositories; + +namespace MiniSpace.Services.Posts.Application.Events.External.Handlers +{ + public class MediaFileDeletedHandler: IEventHandler + { + private readonly IPostRepository _postRepository; + private readonly IDateTimeProvider _dateTimeProvider; + + public MediaFileDeletedHandler(IPostRepository postRepository, IDateTimeProvider dateTimeProvider) + { + _postRepository = postRepository; + _dateTimeProvider = dateTimeProvider; + } + + public async Task HandleAsync(MediaFileDeleted @event, CancellationToken cancellationToken) + { + if(@event.Source.ToLowerInvariant() != "post") + { + return; + } + + var post = await _postRepository.GetAsync(@event.SourceId); + if(post != null) + { + post.RemoveMediaFile(@event.MediaFileId, _dateTimeProvider.Now); + await _postRepository.UpdateAsync(post); + } + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/External/MediaFileDeleted.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/External/MediaFileDeleted.cs new file mode 100644 index 000000000..f79ca8647 --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/External/MediaFileDeleted.cs @@ -0,0 +1,20 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.Posts.Application.Events.External +{ + [Message("mediafiles")] + public class MediaFileDeleted: IEvent + { + public Guid MediaFileId { get; } + public Guid SourceId { get; } + public string Source { get; } + + public MediaFileDeleted(Guid mediaFileId, Guid sourceId, string source) + { + MediaFileId = mediaFileId; + SourceId = sourceId; + Source = source; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Entities/Post.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Entities/Post.cs index fd9c011ca..ab2769461 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Entities/Post.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Entities/Post.cs @@ -84,6 +84,15 @@ public void Update(string textContent, IEnumerable mediaFiles, DateTime no UpdatedAt = now; } + public void RemoveMediaFile(Guid mediaFileId, DateTime now) + { + var mediaFile = MediaFiles.SingleOrDefault(mf => mf == mediaFileId); + if (mediaFile == Guid.Empty) + { + throw new MediaFileNotFoundException(mediaFileId, Id); + } + } + private static void CheckTextContent(AggregateId id, string textContent) { if (string.IsNullOrWhiteSpace(textContent) || textContent.Length > 5000) diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Exceptions/MediaFileNotFoundException.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Exceptions/MediaFileNotFoundException.cs new file mode 100644 index 000000000..4a68fdb63 --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Exceptions/MediaFileNotFoundException.cs @@ -0,0 +1,16 @@ +namespace MiniSpace.Services.Posts.Core.Exceptions +{ + public class MediaFileNotFoundException : DomainException + { + public override string Code { get; } = "media_file_not_found"; + public Guid MediaFileId { get; } + public Guid PostId { get; } + + public MediaFileNotFoundException(Guid mediaFileId, Guid postId) + : base($"Media file with ID: '{mediaFileId}' for post with ID: {postId} was not found.") + { + MediaFileId = mediaFileId; + PostId = postId; + } + } +} \ No newline at end of file From 9cfd48db2b2fff3bf29b838358def6e850773972 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 13:41:21 +0200 Subject: [PATCH 24/62] (#30) fix typo --- .../External/Handlers/MediaFileDeletedHandler.cs | 2 +- .../InvalidEventMediaFilesSizeException.cs | 13 ------------- .../InvalidNumberOfEventMediaFilesException.cs | 15 +++++++++++++++ .../Services/EventValidator.cs | 2 +- 4 files changed, 17 insertions(+), 15 deletions(-) delete mode 100644 MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidEventMediaFilesSizeException.cs create mode 100644 MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidNumberOfEventMediaFilesException.cs diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/External/Handlers/MediaFileDeletedHandler.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/External/Handlers/MediaFileDeletedHandler.cs index c020a9f18..74369f69c 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/External/Handlers/MediaFileDeletedHandler.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/External/Handlers/MediaFileDeletedHandler.cs @@ -16,7 +16,7 @@ public MediaFileDeletedHandler(IEventRepository eventRepository) public async Task HandleAsync(MediaFileDeleted @event, CancellationToken cancellationToken) { - if(@event.Source.ToLowerInvariant() != "events") + if(@event.Source.ToLowerInvariant() != "event") { return; } diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidEventMediaFilesSizeException.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidEventMediaFilesSizeException.cs deleted file mode 100644 index f2e365b8a..000000000 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidEventMediaFilesSizeException.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace MiniSpace.Services.Events.Application.Exceptions -{ - public class InvalidEventMediaFilesSizeException : AppException - { - public override string Code { get; } = "invalid_media_files_size"; - public int Size { get; } - - public InvalidEventMediaFilesSizeException(int size) : base($"Invalid media files size: {size}. It must be less or equal 5.") - { - Size = size; - } - } -} \ No newline at end of file diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidNumberOfEventMediaFilesException.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidNumberOfEventMediaFilesException.cs new file mode 100644 index 000000000..8c1fe1627 --- /dev/null +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidNumberOfEventMediaFilesException.cs @@ -0,0 +1,15 @@ +using System; + +namespace MiniSpace.Services.Events.Application.Exceptions +{ + public class InvalidNumberOfEventMediaFilesException : AppException + { + public override string Code { get; } = "invalid_number_of_event_media_files"; + public int MediaFilesNumber { get; } + public InvalidNumberOfEventMediaFilesException(int mediaFilesNumber) + : base($"Invalid media files number: {mediaFilesNumber}. It must be less or equal 5.") + { + MediaFilesNumber = mediaFilesNumber; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Services/EventValidator.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Services/EventValidator.cs index 1c9359eb7..351272dec 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Services/EventValidator.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Services/EventValidator.cs @@ -79,7 +79,7 @@ public void ValidateDescription(string description) public void ValidateMediaFiles(List mediaFiles) { if (mediaFiles.Count > 5) - throw new InvalidEventMediaFilesSizeException(mediaFiles.Count); + throw new InvalidNumberOfEventMediaFilesException(mediaFiles.Count); } public void ValidateCapacity(int capacity) From e4623583dde9fdd596290ba09376616032200494 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 13:52:51 +0200 Subject: [PATCH 25/62] (#34) update student entities --- .../Commands/CompleteStudentRegistration.cs | 4 ++-- .../Dto/StudentDto.cs | 2 +- .../Entities/Student.cs | 20 +++++-------------- .../Mongo/Documents/StudentDocument.cs | 2 +- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/CompleteStudentRegistration.cs b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/CompleteStudentRegistration.cs index 11713de39..7c159bb66 100644 --- a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/CompleteStudentRegistration.cs +++ b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/CompleteStudentRegistration.cs @@ -5,12 +5,12 @@ namespace MiniSpace.Services.Students.Application.Commands public class CompleteStudentRegistration : ICommand { public Guid StudentId { get; } - public string ProfileImage { get; } + public Guid ProfileImage { get; } public string Description { get; } public DateTime DateOfBirth { get; } public bool EmailNotifications { get; } - public CompleteStudentRegistration(Guid studentId, string profileImage, + public CompleteStudentRegistration(Guid studentId, Guid profileImage, string description, DateTime dateOfBirth, bool emailNotifications) { StudentId = studentId; diff --git a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Dto/StudentDto.cs b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Dto/StudentDto.cs index 6f8d2768b..25dc39f02 100644 --- a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Dto/StudentDto.cs +++ b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Dto/StudentDto.cs @@ -7,7 +7,7 @@ public class StudentDto public string FirstName { get; set; } public string LastName { get; set; } public int NumberOfFriends { get; set; } - public string ProfileImage { get; set; } + public Guid ProfileImage { get; set; } public string Description { get; set; } public DateTime? DateOfBirth { get; set; } public bool EmailNotifications { get; set; } diff --git a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Core/Entities/Student.cs b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Core/Entities/Student.cs index e627dd49a..77d386595 100644 --- a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Core/Entities/Student.cs +++ b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Core/Entities/Student.cs @@ -13,7 +13,7 @@ public class Student : AggregateRoot public string LastName { get; private set; } public string FullName => $"{FirstName} {LastName}"; public int NumberOfFriends { get; private set; } - public string ProfileImage { get; private set; } + public Guid ProfileImage { get; private set; } public string Description { get; private set; } public DateTime? DateOfBirth { get; private set; } public bool EmailNotifications { get; private set; } @@ -34,14 +34,14 @@ public IEnumerable SignedUpEvents } public Student(Guid id, string firstName, string lastName, string email, DateTime createdAt) - : this(id, email, createdAt, firstName, lastName, 0, string.Empty, string.Empty, null, + : this(id, email, createdAt, firstName, lastName, 0, Guid.Empty, string.Empty, null, false, false, false, State.Incomplete, Enumerable.Empty(), Enumerable.Empty()) { CheckFullName(firstName, lastName); } public Student(Guid id, string email, DateTime createdAt, string firstName, string lastName, - int numberOfFriends, string profileImage, string description, DateTime? dateOfBirth, + int numberOfFriends, Guid profileImage, string description, DateTime? dateOfBirth, bool emailNotifications, bool isBanned, bool isOrganizer, State state, IEnumerable interestedInEvents = null, IEnumerable signedUpEvents = null) { @@ -73,10 +73,9 @@ private void SetState(State state) AddEvent(new StudentStateChanged(this, previousState)); } - public void CompleteRegistration(string profileImage, string description, + public void CompleteRegistration(Guid profileImage, string description, DateTime dateOfBirth, DateTime now, bool emailNotifications) { - CheckProfileImage(profileImage); CheckDescription(description); CheckDateOfBirth(dateOfBirth, now); @@ -94,9 +93,8 @@ public void CompleteRegistration(string profileImage, string description, AddEvent(new StudentRegistrationCompleted(this)); } - public void Update(string profileImage, string description, bool emailNotifications) + public void Update(Guid profileImage, string description, bool emailNotifications) { - CheckProfileImage(profileImage); CheckDescription(description); if (State != State.Valid) @@ -119,14 +117,6 @@ private void CheckFullName(string firstName, string lastName) } } - private void CheckProfileImage(string profileImage) - { - if (string.IsNullOrWhiteSpace(profileImage)) - { - throw new InvalidStudentProfileImageException(Id, profileImage); - } - } - private void CheckDescription(string description) { if (string.IsNullOrWhiteSpace(description)) diff --git a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Infrastructure/Mongo/Documents/StudentDocument.cs b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Infrastructure/Mongo/Documents/StudentDocument.cs index 194ef0035..694a8fd18 100644 --- a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Infrastructure/Mongo/Documents/StudentDocument.cs +++ b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Infrastructure/Mongo/Documents/StudentDocument.cs @@ -10,7 +10,7 @@ public class StudentDocument : IIdentifiable public string FirstName { get; set; } public string LastName { get; set; } public int NumberOfFriends { get; set; } - public string ProfileImage { get; set; } + public Guid ProfileImage { get; set; } public string Description { get; set; } public DateTime? DateOfBirth { get; set; } public bool EmailNotifications { get; set; } From 7319347e4cc00c7e1b13b983fc1386f1f8807f22 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 13:56:26 +0200 Subject: [PATCH 26/62] (#34) update command handlers to publish updated events --- .../Commands/Handlers/DeleteStudentHandler.cs | 2 +- .../Commands/UpdateStudent.cs | 4 ++-- .../Events/StudentCreated.cs | 4 +++- .../Events/StudentDeleted.cs | 4 +++- .../Events/StudentUpdated.cs | 4 +++- .../Services/EventMapper.cs | 4 ++-- 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/Handlers/DeleteStudentHandler.cs b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/Handlers/DeleteStudentHandler.cs index 4a2a7a363..15c48818c 100644 --- a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/Handlers/DeleteStudentHandler.cs +++ b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/Handlers/DeleteStudentHandler.cs @@ -36,7 +36,7 @@ public async Task HandleAsync(DeleteStudent command, CancellationToken cancellat await _studentRepository.DeleteAsync(command.StudentId); - await _messageBroker.PublishAsync(new StudentDeleted(command.StudentId, student.FullName)); + await _messageBroker.PublishAsync(new StudentDeleted(command.StudentId, student.FullName, student.ProfileImage)); } } } diff --git a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/UpdateStudent.cs b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/UpdateStudent.cs index d76bb3ba2..ecd0e256f 100644 --- a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/UpdateStudent.cs +++ b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/UpdateStudent.cs @@ -5,11 +5,11 @@ namespace MiniSpace.Services.Students.Application.Commands public class UpdateStudent : ICommand { public Guid StudentId { get; } - public string ProfileImage { get; } + public Guid ProfileImage { get; } public string Description { get; } public bool EmailNotifications { get; } - public UpdateStudent(Guid studentId, string profileImage, string description, bool emailNotifications) + public UpdateStudent(Guid studentId, Guid profileImage, string description, bool emailNotifications) { StudentId = studentId; ProfileImage = profileImage; diff --git a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentCreated.cs b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentCreated.cs index ec71658d1..6028518c9 100644 --- a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentCreated.cs +++ b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentCreated.cs @@ -6,11 +6,13 @@ public class StudentCreated : IEvent { public Guid StudentId { get; } public string FullName { get; } + public Guid MediaFileId { get; } - public StudentCreated(Guid studentId, string fullName) + public StudentCreated(Guid studentId, string fullName, Guid mediaFileId) { StudentId = studentId; FullName = fullName; + MediaFileId = mediaFileId; } } } diff --git a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentDeleted.cs b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentDeleted.cs index 462ac877d..d93acdb70 100644 --- a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentDeleted.cs +++ b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentDeleted.cs @@ -6,11 +6,13 @@ public class StudentDeleted : IEvent { public Guid StudentId { get; } public string FullName { get; } + public Guid MediaFileId { get; } - public StudentDeleted(Guid studentId, string fullName) + public StudentDeleted(Guid studentId, string fullName, Guid mediaFileId) { StudentId = studentId; FullName = fullName; + MediaFileId = mediaFileId; } } } diff --git a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentUpdated.cs b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentUpdated.cs index fa4324046..3968ccd09 100644 --- a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentUpdated.cs +++ b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentUpdated.cs @@ -6,11 +6,13 @@ public class StudentUpdated : IEvent { public Guid StudentId { get; } public string FullName { get; } + public Guid MediaFileId { get; } - public StudentUpdated(Guid studentId, string fullName) + public StudentUpdated(Guid studentId, string fullName, Guid mediaFileId) { StudentId = studentId; FullName = fullName; + MediaFileId = mediaFileId; } } } diff --git a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Infrastructure/Services/EventMapper.cs b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Infrastructure/Services/EventMapper.cs index 890c60219..f540eca2a 100644 --- a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Infrastructure/Services/EventMapper.cs +++ b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Infrastructure/Services/EventMapper.cs @@ -15,9 +15,9 @@ public IEvent Map(IDomainEvent @event) switch (@event) { case StudentRegistrationCompleted e: - return new Application.Events.StudentCreated(e.Student.Id, e.Student.FullName); + return new Application.Events.StudentCreated(e.Student.Id, e.Student.FullName, e.Student.ProfileImage); case StudentUpdated e: - return new Application.Events.StudentUpdated(e.Student.Id, e.Student.FullName); + return new Application.Events.StudentUpdated(e.Student.Id, e.Student.FullName, e.Student.ProfileImage); case StudentStateChanged e: return new Application.Events.StudentStateChanged(e.Student.Id, e.Student.FullName, e.Student.State.ToString().ToLowerInvariant(), e.PreviousState.ToString().ToLowerInvariant()); From 1d2d8683330320594ddb816c0b536cb39d8ab507 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 14:01:52 +0200 Subject: [PATCH 27/62] (#30) add external event MediaFileDeleted --- .../Handlers/MediaFileDeletedHandler.cs | 30 +++++++++++++++++++ .../Events/External/MediaFileDeleted.cs | 20 +++++++++++++ .../Entities/Student.cs | 10 +++++++ 3 files changed, 60 insertions(+) create mode 100644 MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/External/Handlers/MediaFileDeletedHandler.cs create mode 100644 MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/External/MediaFileDeleted.cs diff --git a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/External/Handlers/MediaFileDeletedHandler.cs b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/External/Handlers/MediaFileDeletedHandler.cs new file mode 100644 index 000000000..bb3dfc3f4 --- /dev/null +++ b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/External/Handlers/MediaFileDeletedHandler.cs @@ -0,0 +1,30 @@ +using Convey.CQRS.Events; +using MiniSpace.Services.Students.Core.Repositories; + +namespace MiniSpace.Services.Students.Application.Events.External.Handlers +{ + public class MediaFileDeletedHandler: IEventHandler + { + private readonly IStudentRepository _studentRepository; + + public MediaFileDeletedHandler(IStudentRepository studentRepository) + { + _studentRepository = studentRepository; + } + + public async Task HandleAsync(MediaFileDeleted @event, CancellationToken cancellationToken) + { + if(@event.Source.ToLowerInvariant() != "studentprofile") + { + return; + } + + var student = await _studentRepository.GetAsync(@event.SourceId); + if(student != null) + { + student.RemoveProfileImage(@event.MediaFileId); + await _studentRepository.UpdateAsync(student); + } + } + } +} diff --git a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/External/MediaFileDeleted.cs b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/External/MediaFileDeleted.cs new file mode 100644 index 000000000..98e856a63 --- /dev/null +++ b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/External/MediaFileDeleted.cs @@ -0,0 +1,20 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.Students.Application.Events.External +{ + [Message("mediafiles")] + public class MediaFileDeleted: IEvent + { + public Guid MediaFileId { get; } + public Guid SourceId { get; } + public string Source { get; } + + public MediaFileDeleted(Guid mediaFileId, Guid sourceId, string source) + { + MediaFileId = mediaFileId; + SourceId = sourceId; + Source = source; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Core/Entities/Student.cs b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Core/Entities/Student.cs index 77d386595..faf6ac56e 100644 --- a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Core/Entities/Student.cs +++ b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Core/Entities/Student.cs @@ -152,6 +152,16 @@ public void AddSignedUpEvent(Guid eventId) _signedUpEvents.Add(eventId); } + + public void RemoveProfileImage(Guid mediaFileId) + { + if (ProfileImage != mediaFileId) + { + return; + } + + ProfileImage = Guid.Empty; + } public void Ban() => IsBanned = true; public void Unban() => IsBanned = false; From 551aa1c51340e9a5f90697d644b5e4b449f408ee Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 14:12:59 +0200 Subject: [PATCH 28/62] (#92) add missing external events --- .../Events/External/EventDeleted.cs | 16 ++++++++ .../Events/External/EventUpdated.cs | 18 +++++++++ .../External/Handlers/EventDeletedHandler.cs | 34 +++++++++++++++++ .../External/Handlers/EventUpdatedHandler.cs | 37 +++++++++++++++++++ .../External/Handlers/PostDeletedHandler.cs | 34 +++++++++++++++++ .../External/Handlers/PostUpdatedHandler.cs | 37 +++++++++++++++++++ .../Handlers/StudentDeletedHandler.cs | 34 +++++++++++++++++ .../Events/External/PostDeleted.cs | 16 ++++++++ .../Events/External/PostUpdated.cs | 18 +++++++++ .../Events/External/StudentDeleted.cs | 16 ++++++++ 10 files changed, 260 insertions(+) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/EventDeleted.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/EventUpdated.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventDeletedHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventUpdatedHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostDeletedHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostUpdatedHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentDeletedHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/PostDeleted.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/PostUpdated.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentDeleted.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/EventDeleted.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/EventDeleted.cs new file mode 100644 index 000000000..a47fa908f --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/EventDeleted.cs @@ -0,0 +1,16 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("events")] + public class EventDeleted : IEvent + { + public Guid EventId { get; } + + public EventDeleted(Guid eventId) + { + EventId = eventId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/EventUpdated.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/EventUpdated.cs new file mode 100644 index 000000000..b333bd6fe --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/EventUpdated.cs @@ -0,0 +1,18 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("events")] + public class EventUpdated : IEvent + { + public Guid EventId { get; } + public IEnumerable MediaFilesIds { get; } + + public EventUpdated(Guid eventId, IEnumerable mediaFilesIds) + { + EventId = eventId; + MediaFilesIds = mediaFilesIds; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventDeletedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventDeletedHandler.cs new file mode 100644 index 000000000..6c9eabf1f --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventDeletedHandler.cs @@ -0,0 +1,34 @@ +using Convey.CQRS.Commands; +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers +{ + public class EventDeletedHandler : IEventHandler + { + private readonly IFileSourceInfoRepository _fileSourceInfoRepository; + private readonly ICommandDispatcher _commandDispatcher; + + public EventDeletedHandler(IFileSourceInfoRepository fileSourceInfoRepository, ICommandDispatcher commandDispatcher) + { + _fileSourceInfoRepository = fileSourceInfoRepository; + _commandDispatcher = commandDispatcher; + } + + public async Task HandleAsync(EventDeleted @event, CancellationToken cancellationToken) + { + var fileSourceInfos = + await _fileSourceInfoRepository.FindAsync(@event.EventId, ContextType.Event); + foreach (var fileSourceInfo in fileSourceInfos) + { + await _commandDispatcher.SendAsync(new DeleteMediaFile + { + MediaFileId = fileSourceInfo.Id + }, + cancellationToken); + } + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventUpdatedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventUpdatedHandler.cs new file mode 100644 index 000000000..cba84e886 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventUpdatedHandler.cs @@ -0,0 +1,37 @@ +using Convey.CQRS.Commands; +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers +{ + public class EventUpdatedHandler : IEventHandler + { + private readonly IFileSourceInfoRepository _fileSourceInfoRepository; + private readonly ICommandDispatcher _commandDispatcher; + + public EventUpdatedHandler(IFileSourceInfoRepository fileSourceInfoRepository, ICommandDispatcher commandDispatcher) + { + _fileSourceInfoRepository = fileSourceInfoRepository; + _commandDispatcher = commandDispatcher; + } + + public async Task HandleAsync(EventUpdated @event, CancellationToken cancellationToken) + { + var fileSourceInfos = + await _fileSourceInfoRepository.FindAsync(@event.EventId, ContextType.Event); + foreach (var fileSourceInfo in fileSourceInfos) + { + if(!@event.MediaFilesIds.Contains(fileSourceInfo.Id)) + { + await _commandDispatcher.SendAsync(new DeleteMediaFile + { + MediaFileId = fileSourceInfo.Id + }, + cancellationToken); + } + } + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostDeletedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostDeletedHandler.cs new file mode 100644 index 000000000..92e6d5ab8 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostDeletedHandler.cs @@ -0,0 +1,34 @@ +using Convey.CQRS.Commands; +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers +{ + public class PostDeletedHandler : IEventHandler + { + private readonly IFileSourceInfoRepository _fileSourceInfoRepository; + private readonly ICommandDispatcher _commandDispatcher; + + public PostDeletedHandler(IFileSourceInfoRepository fileSourceInfoRepository, ICommandDispatcher commandDispatcher) + { + _fileSourceInfoRepository = fileSourceInfoRepository; + _commandDispatcher = commandDispatcher; + } + + public async Task HandleAsync(PostDeleted @event, CancellationToken cancellationToken) + { + var fileSourceInfos = + await _fileSourceInfoRepository.FindAsync(@event.PostId, ContextType.Post); + foreach (var fileSourceInfo in fileSourceInfos) + { + await _commandDispatcher.SendAsync(new DeleteMediaFile + { + MediaFileId = fileSourceInfo.Id + }, + cancellationToken); + } + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostUpdatedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostUpdatedHandler.cs new file mode 100644 index 000000000..b10fcb9cb --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostUpdatedHandler.cs @@ -0,0 +1,37 @@ +using Convey.CQRS.Commands; +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers +{ + public class PostUpdatedHandler : IEventHandler + { + private readonly IFileSourceInfoRepository _fileSourceInfoRepository; + private readonly ICommandDispatcher _commandDispatcher; + + public PostUpdatedHandler(IFileSourceInfoRepository fileSourceInfoRepository, ICommandDispatcher commandDispatcher) + { + _fileSourceInfoRepository = fileSourceInfoRepository; + _commandDispatcher = commandDispatcher; + } + + public async Task HandleAsync(PostUpdated @event, CancellationToken cancellationToken) + { + var fileSourceInfos = + await _fileSourceInfoRepository.FindAsync(@event.PostId, ContextType.Post); + foreach (var fileSourceInfo in fileSourceInfos) + { + if(!@event.MediaFilesIds.Contains(fileSourceInfo.Id)) + { + await _commandDispatcher.SendAsync(new DeleteMediaFile + { + MediaFileId = fileSourceInfo.Id + }, + cancellationToken); + } + } + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentDeletedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentDeletedHandler.cs new file mode 100644 index 000000000..45db72b19 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentDeletedHandler.cs @@ -0,0 +1,34 @@ +using Convey.CQRS.Commands; +using Convey.CQRS.Events; +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers +{ + public class StudentDeletedHandler : IEventHandler + { + private readonly IFileSourceInfoRepository _fileSourceInfoRepository; + private readonly ICommandDispatcher _commandDispatcher; + + public StudentDeletedHandler(IFileSourceInfoRepository fileSourceInfoRepository, ICommandDispatcher commandDispatcher) + { + _fileSourceInfoRepository = fileSourceInfoRepository; + _commandDispatcher = commandDispatcher; + } + + public async Task HandleAsync(StudentDeleted @event, CancellationToken cancellationToken) + { + var fileSourceInfos = + await _fileSourceInfoRepository.FindAsync(@event.StudentId, ContextType.StudentProfile); + foreach (var fileSourceInfo in fileSourceInfos) + { + await _commandDispatcher.SendAsync(new DeleteMediaFile + { + MediaFileId = fileSourceInfo.Id + }, + cancellationToken); + } + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/PostDeleted.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/PostDeleted.cs new file mode 100644 index 000000000..210b1542f --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/PostDeleted.cs @@ -0,0 +1,16 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("posts")] + public class PostDeleted : IEvent + { + public Guid PostId { get; } + + public PostDeleted(Guid postId) + { + PostId = postId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/PostUpdated.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/PostUpdated.cs new file mode 100644 index 000000000..a162cf8fa --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/PostUpdated.cs @@ -0,0 +1,18 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("posts")] + public class PostUpdated : IEvent + { + public Guid PostId { get; } + public IEnumerable MediaFilesIds { get; } + + public PostUpdated(Guid postId, IEnumerable mediaFilesIds) + { + PostId = postId; + MediaFilesIds = mediaFilesIds; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentDeleted.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentDeleted.cs new file mode 100644 index 000000000..5c666e72d --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/StudentDeleted.cs @@ -0,0 +1,16 @@ +using Convey.CQRS.Events; +using Convey.MessageBrokers; + +namespace MiniSpace.Services.MediaFiles.Application.Events.External +{ + [Message("students")] + public class StudentDeleted : IEvent + { + public Guid StudentId { get; } + + public StudentDeleted(Guid studentId) + { + StudentId = studentId; + } + } +} \ No newline at end of file From 4b2c1155e232d65f54cdbd21ebd80fee21016a1e Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 14:14:47 +0200 Subject: [PATCH 29/62] (#34) remove redundant field in event --- .../Commands/Handlers/DeleteStudentHandler.cs | 2 +- .../Events/StudentDeleted.cs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/Handlers/DeleteStudentHandler.cs b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/Handlers/DeleteStudentHandler.cs index 15c48818c..4a2a7a363 100644 --- a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/Handlers/DeleteStudentHandler.cs +++ b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Commands/Handlers/DeleteStudentHandler.cs @@ -36,7 +36,7 @@ public async Task HandleAsync(DeleteStudent command, CancellationToken cancellat await _studentRepository.DeleteAsync(command.StudentId); - await _messageBroker.PublishAsync(new StudentDeleted(command.StudentId, student.FullName, student.ProfileImage)); + await _messageBroker.PublishAsync(new StudentDeleted(command.StudentId, student.FullName)); } } } diff --git a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentDeleted.cs b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentDeleted.cs index d93acdb70..462ac877d 100644 --- a/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentDeleted.cs +++ b/MiniSpace.Services.Students/src/MiniSpace.Services.Students.Application/Events/StudentDeleted.cs @@ -6,13 +6,11 @@ public class StudentDeleted : IEvent { public Guid StudentId { get; } public string FullName { get; } - public Guid MediaFileId { get; } - public StudentDeleted(Guid studentId, string fullName, Guid mediaFileId) + public StudentDeleted(Guid studentId, string fullName) { StudentId = studentId; FullName = fullName; - MediaFileId = mediaFileId; } } } From 72c8fa0fcb6b0a0dba0b51117c03284778dd940b Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 14:15:40 +0200 Subject: [PATCH 30/62] (#32) remove redundant field in event --- .../Commands/Handlers/DeletePostHandler.cs | 2 +- .../Events/PostDeleted.cs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/DeletePostHandler.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/DeletePostHandler.cs index 5060e706e..1430155a5 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/DeletePostHandler.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/DeletePostHandler.cs @@ -42,7 +42,7 @@ public async Task HandleAsync(DeletePost command, CancellationToken cancellation await _postRepository.DeleteAsync(command.PostId); - await _messageBroker.PublishAsync(new PostDeleted(command.PostId, post.MediaFiles)); + await _messageBroker.PublishAsync(new PostDeleted(command.PostId)); } } } diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostDeleted.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostDeleted.cs index 12500b790..1b20677ad 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostDeleted.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Events/PostDeleted.cs @@ -5,12 +5,10 @@ namespace MiniSpace.Services.Posts.Application.Events public class PostDeleted : IEvent { public Guid PostId { get; } - public IEnumerable MediaFilesIds { get; } - public PostDeleted(Guid postId, IEnumerable mediaFilesIds) + public PostDeleted(Guid postId) { PostId = postId; - MediaFilesIds = mediaFilesIds; } } } From 476c15e4ca3c0ae3ea812ff26a97828e213bd940 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 14:16:35 +0200 Subject: [PATCH 31/62] (#30) remove redundant field in event --- .../Commands/Handlers/DeleteEventHandler.cs | 2 +- .../Events/EventDeleted.cs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/DeleteEventHandler.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/DeleteEventHandler.cs index ef9365b25..bc8736389 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/DeleteEventHandler.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/DeleteEventHandler.cs @@ -37,7 +37,7 @@ public async Task HandleAsync(DeleteEvent command, CancellationToken cancellatio } await _eventRepository.DeleteAsync(command.EventId); - await _messageBroker.PublishAsync(new EventDeleted(command.EventId, @event.MediaFiles)); + await _messageBroker.PublishAsync(new EventDeleted(command.EventId)); } } } \ No newline at end of file diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventDeleted.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventDeleted.cs index f6f8083b8..9c74a3d37 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventDeleted.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/EventDeleted.cs @@ -4,9 +4,8 @@ namespace MiniSpace.Services.Events.Application.Events { - public class EventDeleted(Guid eventId, IEnumerable mediaFilesIds) : IEvent + public class EventDeleted(Guid eventId) : IEvent { public Guid EventId { get; set; } = eventId; - public IEnumerable MediaFilesIds { get; set; } = mediaFilesIds; } } \ No newline at end of file From 684efb81df06a60e957d3820f18166f8e11315ea Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 14:42:23 +0200 Subject: [PATCH 32/62] (#92) add new fields CreatedAt and State --- .../Commands/Handlers/UploadMediaFileHandler.cs | 6 ++++-- .../Dto/FileDto.cs | 8 ++++++-- .../Entities/FileSourceInfo.cs | 8 ++++++-- .../MiniSpace.Services.MediaFiles.Core/Entities/State.cs | 8 ++++++++ .../Mongo/Documents/Extensions.cs | 4 +++- .../Mongo/Documents/FileSourceInfoDocument.cs | 2 ++ .../{GetMediaFilesHandler.cs => GetMediaFileHandler.cs} | 7 ++++--- 7 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/State.cs rename MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/{GetMediaFilesHandler.cs => GetMediaFileHandler.cs} (81%) diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs index 920e982b6..dced9da8a 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs @@ -11,14 +11,16 @@ public class UploadMediaFileHandler: ICommandHandler { private readonly IFileSourceInfoRepository _fileSourceInfoRepository; private readonly IGridFSService _gridFSService; + private readonly IDateTimeProvider _dateTimeProvider; private readonly IAppContext _appContext; private readonly IMessageBroker _messageBroker; public UploadMediaFileHandler(IFileSourceInfoRepository fileSourceInfoRepository, IGridFSService gridFSService, - IAppContext appContext, IMessageBroker messageBroker) + IDateTimeProvider dateTimeProvider, IAppContext appContext, IMessageBroker messageBroker) { _fileSourceInfoRepository = fileSourceInfoRepository; _gridFSService = gridFSService; + _dateTimeProvider = dateTimeProvider; _appContext = appContext; _messageBroker = messageBroker; } @@ -40,7 +42,7 @@ public async Task HandleAsync(UploadMediaFile command, CancellationToken cancell var objectId = await _gridFSService.UploadFileAsync(command.FileName, stream); var fileSourceInfo = new FileSourceInfo(command.MediaFileId, command.SourceId, sourceType, - command.UploaderId, objectId, command.FileName); + command.UploaderId, State.Unassociated, _dateTimeProvider.Now, objectId, command.FileName); await _fileSourceInfoRepository.AddAsync(fileSourceInfo); await _messageBroker.PublishAsync(new MediaFileUploaded(command.MediaFileId, command.FileName)); } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs index 99b48507e..27aabb0c8 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs @@ -5,17 +5,21 @@ public class FileDto public Guid MediaFileId { get; set; } public Guid SourceId { get; set; } public string SourceType { get; set; } + public string State { get; set; } + public DateTime CreatedAt { get; set; } public Guid UploaderId { get; set; } public string FileName { get; set; } public string Base64Content { get; set; } - public FileDto(Guid mediaFileId, Guid sourceId, string sourceType, Guid uploaderId, - string fileName, string base64Content) + public FileDto(Guid mediaFileId, Guid sourceId, string sourceType, Guid uploaderId, string state, + DateTime createdAt, string fileName, string base64Content) { MediaFileId = mediaFileId == Guid.Empty ? Guid.NewGuid() : mediaFileId; SourceId = sourceId; SourceType = sourceType; UploaderId = uploaderId; + State = state; + CreatedAt = createdAt; FileName = fileName; Base64Content = base64Content; } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs index a24bf37ed..5459bbad0 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs @@ -7,16 +7,20 @@ public class FileSourceInfo: AggregateRoot public Guid SourceId { get; set; } public ContextType SourceType { get; set; } public Guid UploaderId { get; set; } + public State State { get; set; } + public DateTime CreatedAt { get; set; } public ObjectId FileId { get; set; } public string FileName { get; set; } - public FileSourceInfo(Guid id, Guid sourceId, ContextType sourceType, Guid uploaderId, - ObjectId fileId, string fileName) + public FileSourceInfo(Guid id, Guid sourceId, ContextType sourceType, Guid uploaderId, State state, + DateTime createdAt, ObjectId fileId, string fileName) { Id = id; SourceId = sourceId; SourceType = sourceType; UploaderId = uploaderId; + State = state; + CreatedAt = createdAt; FileId = fileId; FileName = fileName; } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/State.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/State.cs new file mode 100644 index 000000000..45aa55612 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/State.cs @@ -0,0 +1,8 @@ +namespace MiniSpace.Services.MediaFiles.Core.Entities +{ + public enum State + { + Associated, + Unassociated + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs index 1f2dc8224..a11bd8503 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs @@ -11,12 +11,14 @@ public static FileSourceInfoDocument AsDocument(this FileSourceInfo fileSourceIn SourceId = fileSourceInfo.SourceId, SourceType = fileSourceInfo.SourceType, UploaderId = fileSourceInfo.UploaderId, + State = fileSourceInfo.State, + CreatedAt = fileSourceInfo.CreatedAt, FileId = fileSourceInfo.FileId, FileName = fileSourceInfo.FileName }; public static FileSourceInfo AsEntity(this FileSourceInfoDocument document) => new FileSourceInfo(document.Id, document.SourceId, document.SourceType, document.UploaderId, - document.FileId, document.FileName); + document.State, document.CreatedAt, document.FileId, document.FileName); } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs index a3addea5b..4ebbd38a6 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs @@ -10,6 +10,8 @@ public class FileSourceInfoDocument : IIdentifiable public Guid SourceId { get; set; } public ContextType SourceType { get; set; } public Guid UploaderId { get; set; } + public State State { get; set; } + public DateTime CreatedAt { get; set; } public ObjectId FileId { get; set; } public string FileName { get; set; } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFilesHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFileHandler.cs similarity index 81% rename from MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFilesHandler.cs rename to MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFileHandler.cs index 9aea7df05..08f6e8a1c 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFilesHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFileHandler.cs @@ -10,12 +10,12 @@ namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Queries.Handlers { - public class GetMediaFilesHandler : IQueryHandler + public class GetMediaFileHandler : IQueryHandler { private readonly IMongoRepository _fileSourceInfoRepository; private readonly IGridFSService _gridFSService; - public GetMediaFilesHandler(IMongoRepository fileSourceInfoRepository, + public GetMediaFileHandler(IMongoRepository fileSourceInfoRepository, IGridFSService gridFSService) { _fileSourceInfoRepository = fileSourceInfoRepository; @@ -37,7 +37,8 @@ public async Task HandleAsync(GetMediaFile query, CancellationToken can var base64String = Convert.ToBase64String(fileContent); return new FileDto(query.MediaFileId, fileSourceInfo.SourceId, fileSourceInfo.SourceType.ToString(), - fileSourceInfo.UploaderId, fileSourceInfo.FileName, base64String); + fileSourceInfo.UploaderId, fileSourceInfo.State.ToString().ToLower(), fileSourceInfo.CreatedAt, + fileSourceInfo.FileName, base64String); } } } \ No newline at end of file From f200c2dba049e2f1090c3ed5aac4933bfbd5f5e5 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 14:58:54 +0200 Subject: [PATCH 33/62] (#92) add background worker to delete unassociated files --- .../Commands/CleanupUnassociatedFiles.cs | 14 +++++ .../CleanupUnassociatedFilesHandler.cs | 39 +++++++++++++ .../FileCleanupBackgroundWorkerStarted.cs | 14 +++++ .../FileCleanupBackgroundWorkerStopped.cs | 14 +++++ .../Events/UnassociatedFilesCleaned.cs | 14 +++++ .../Repositories/IFileSourceInfoRepository.cs | 1 + .../Extensions.cs | 3 + .../FileSourceInfoMongoRepository.cs | 8 +++ .../Services/Workers/FileCleanupWorker.cs | 57 +++++++++++++++++++ 9 files changed, 164 insertions(+) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/CleanupUnassociatedFiles.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CleanupUnassociatedFilesHandler.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/FileCleanupBackgroundWorkerStarted.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/FileCleanupBackgroundWorkerStopped.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/UnassociatedFilesCleaned.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/Workers/FileCleanupWorker.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/CleanupUnassociatedFiles.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/CleanupUnassociatedFiles.cs new file mode 100644 index 000000000..e97742e97 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/CleanupUnassociatedFiles.cs @@ -0,0 +1,14 @@ +using Convey.CQRS.Commands; + +namespace MiniSpace.Services.MediaFiles.Application.Commands +{ + public class CleanupUnassociatedFiles: ICommand + { + public DateTime Now { get; set; } + + public CleanupUnassociatedFiles(DateTime now) + { + Now = now; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CleanupUnassociatedFilesHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CleanupUnassociatedFilesHandler.cs new file mode 100644 index 000000000..e620304e1 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CleanupUnassociatedFilesHandler.cs @@ -0,0 +1,39 @@ +using Convey.CQRS.Commands; +using MiniSpace.Services.MediaFiles.Application.Events; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Core.Entities; +using MiniSpace.Services.MediaFiles.Core.Repositories; + +namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers +{ + public class CleanupUnassociatedFilesHandler: ICommandHandler + { + private readonly IFileSourceInfoRepository _fileSourceInfoRepository; + private readonly IGridFSService _gridFSService; + private readonly IMessageBroker _messageBroker; + + public CleanupUnassociatedFilesHandler(IFileSourceInfoRepository fileSourceInfoRepository, IGridFSService gridFSService, + IMessageBroker messageBroker) + { + _fileSourceInfoRepository = fileSourceInfoRepository; + _gridFSService = gridFSService; + _messageBroker = messageBroker; + } + + public async Task HandleAsync(CleanupUnassociatedFiles command, CancellationToken cancellationToken) + { + var unassociatedFileSourceInfos = await _fileSourceInfoRepository.GetAllUnassociatedAsync(); + foreach (var file in unassociatedFileSourceInfos) + { + if ((command.Now - file.CreatedAt).TotalDays < 1) + { + continue; + } + await _gridFSService.DeleteFileAsync(file.FileId); + await _fileSourceInfoRepository.DeleteAsync(file.Id); + } + + await _messageBroker.PublishAsync(new UnassociatedFilesCleaned(command.Now)); + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/FileCleanupBackgroundWorkerStarted.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/FileCleanupBackgroundWorkerStarted.cs new file mode 100644 index 000000000..4781c5057 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/FileCleanupBackgroundWorkerStarted.cs @@ -0,0 +1,14 @@ +using Convey.CQRS.Events; + +namespace MiniSpace.Services.MediaFiles.Application.Events +{ + public class FileCleanupBackgroundWorkerStarted: IEvent + { + public DateTime StartedAt { get; } + + public FileCleanupBackgroundWorkerStarted(DateTime startedAt) + { + StartedAt = startedAt; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/FileCleanupBackgroundWorkerStopped.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/FileCleanupBackgroundWorkerStopped.cs new file mode 100644 index 000000000..5bcd641fc --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/FileCleanupBackgroundWorkerStopped.cs @@ -0,0 +1,14 @@ +using Convey.CQRS.Events; + +namespace MiniSpace.Services.MediaFiles.Application.Events +{ + public class FileCleanupBackgroundWorkerStopped: IEvent + { + public DateTime StoppedAt { get; } + + public FileCleanupBackgroundWorkerStopped(DateTime stoppedAt) + { + StoppedAt = stoppedAt; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/UnassociatedFilesCleaned.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/UnassociatedFilesCleaned.cs new file mode 100644 index 000000000..757821ca7 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/UnassociatedFilesCleaned.cs @@ -0,0 +1,14 @@ +using Convey.CQRS.Events; + +namespace MiniSpace.Services.MediaFiles.Application.Events +{ + public class UnassociatedFilesCleaned: IEvent + { + public DateTime OccurredAt { get; } + + public UnassociatedFilesCleaned(DateTime occurredAt) + { + OccurredAt = occurredAt; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IFileSourceInfoRepository.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IFileSourceInfoRepository.cs index 8038922d2..5095eadc5 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IFileSourceInfoRepository.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Repositories/IFileSourceInfoRepository.cs @@ -5,6 +5,7 @@ namespace MiniSpace.Services.MediaFiles.Core.Repositories public interface IFileSourceInfoRepository { Task GetAsync(Guid id); + Task> GetAllUnassociatedAsync(); Task AddAsync(FileSourceInfo fileSourceInfo); Task UpdateAsync(FileSourceInfo fileSourceInfo); Task DeleteAsync(Guid id); diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs index d2d5334de..76baf3d0f 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs @@ -38,6 +38,7 @@ using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Repositories; using MiniSpace.Services.MediaFiles.Infrastructure.Services; +using MiniSpace.Services.MediaFiles.Infrastructure.Services.Workers; using MongoDB.Driver; namespace MiniSpace.Services.MediaFiles.Infrastructure @@ -61,6 +62,7 @@ public static IConveyBuilder AddInfrastructure(this IConveyBuilder builder) var database = mongoClient.GetDatabase(mongoDbOptions.Database); return new GridFSService(database); }); + builder.Services.AddHostedService(); return builder .AddErrorHandler() @@ -95,6 +97,7 @@ public static IApplicationBuilder UseInfrastructure(this IApplicationBuilder app .UseRabbitMq() .SubscribeCommand() .SubscribeCommand() + .SubscribeCommand() .SubscribeEvent() .SubscribeEvent() .SubscribeEvent() diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/FileSourceInfoMongoRepository.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/FileSourceInfoMongoRepository.cs index 038221a1b..c3e80cbc3 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/FileSourceInfoMongoRepository.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Repositories/FileSourceInfoMongoRepository.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -26,6 +27,13 @@ public async Task GetAsync(Guid id) return fileSourceInfo?.AsEntity(); } + + public async Task> GetAllUnassociatedAsync() + { + var fileSourceInfos = await _repository.FindAsync(s => s.State == State.Unassociated); + + return fileSourceInfos?.Select(s => s.AsEntity()); + } public Task AddAsync(FileSourceInfo fileSourceInfo) => _repository.AddAsync(fileSourceInfo.AsDocument()); diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/Workers/FileCleanupWorker.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/Workers/FileCleanupWorker.cs new file mode 100644 index 000000000..243d9da1b --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/Workers/FileCleanupWorker.cs @@ -0,0 +1,57 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Convey.CQRS.Commands; +using Convey.Persistence.MongoDB; +using Microsoft.Extensions.Hosting; +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Application.Events; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Services.Workers +{ + public class FileCleanupWorker: BackgroundService + { + private readonly IMessageBroker _messageBroker; + private readonly ICommandDispatcher _commandDispatcher; + private readonly IDateTimeProvider _dateTimeProvider; + private const int MinutesInterval = 10; + + public FileCleanupWorker(IMessageBroker messageBroker, ICommandDispatcher commandDispatcher, + IDateTimeProvider dateTimeProvider) + { + _messageBroker = messageBroker; + _commandDispatcher = commandDispatcher; + _dateTimeProvider = dateTimeProvider; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + await _messageBroker.PublishAsync(new FileCleanupBackgroundWorkerStarted(_dateTimeProvider.Now)); + while (!stoppingToken.IsCancellationRequested) + { + try + { + var now = _dateTimeProvider.Now; + var minutes = now.Minute; + if (minutes % MinutesInterval == 0) + { + await _commandDispatcher.SendAsync(new CleanupUnassociatedFiles(now), stoppingToken); + } + + var nextTime = now.AddMinutes(MinutesInterval - (minutes % MinutesInterval)).AddSeconds(-now.Second) + .AddMilliseconds(-now.Millisecond); + var delay = nextTime - now; + + await Task.Delay(delay, stoppingToken); + } + catch (TaskCanceledException) + { + await _messageBroker.PublishAsync(new FileCleanupBackgroundWorkerStopped(_dateTimeProvider.Now)); + return; + } + } + } + } +} \ No newline at end of file From 2ab36f0ba3c8410b3bf9ae3ee022fd162ff79da9 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 15:09:33 +0200 Subject: [PATCH 34/62] (#92) update event handlers --- .../Events/External/Handlers/EventCreatedHandler.cs | 13 ++++--------- .../Events/External/Handlers/EventDeletedHandler.cs | 7 ++----- .../Events/External/Handlers/EventUpdatedHandler.cs | 13 +++++++------ .../Events/External/Handlers/PostCreatedHandler.cs | 9 +++------ .../Events/External/Handlers/PostDeletedHandler.cs | 7 ++----- .../Events/External/Handlers/PostUpdatedHandler.cs | 13 +++++++------ .../External/Handlers/StudentCreatedHandler.cs | 9 +++------ .../External/Handlers/StudentDeletedHandler.cs | 7 ++----- .../External/Handlers/StudentUpdatedHandler.cs | 13 +++++++------ .../Entities/FileSourceInfo.cs | 10 ++++++++++ .../Logging/MessageToLogTemplateMapper.cs | 7 +++++++ 11 files changed, 54 insertions(+), 54 deletions(-) diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventCreatedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventCreatedHandler.cs index be62db8e6..d27af87e5 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventCreatedHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventCreatedHandler.cs @@ -9,12 +9,10 @@ namespace MiniSpace.Services.MediaFiles.Application.Events.External.Handlers public class EventCreatedHandler : IEventHandler { private readonly IFileSourceInfoRepository _fileSourceInfoRepository; - private readonly ICommandDispatcher _commandDispatcher; - public EventCreatedHandler(IFileSourceInfoRepository fileSourceInfoRepository, ICommandDispatcher commandDispatcher) + public EventCreatedHandler(IFileSourceInfoRepository fileSourceInfoRepository) { _fileSourceInfoRepository = fileSourceInfoRepository; - _commandDispatcher = commandDispatcher; } public async Task HandleAsync(EventCreated @event, CancellationToken cancellationToken) @@ -23,13 +21,10 @@ public async Task HandleAsync(EventCreated @event, CancellationToken cancellatio await _fileSourceInfoRepository.FindAsync(@event.EventId, ContextType.Event); foreach (var fileSourceInfo in fileSourceInfos) { - if(!@event.MediaFilesIds.Contains(fileSourceInfo.Id)) + if(@event.MediaFilesIds.Contains(fileSourceInfo.Id)) { - await _commandDispatcher.SendAsync(new DeleteMediaFile - { - MediaFileId = fileSourceInfo.Id - }, - cancellationToken); + fileSourceInfo.Associate(); + await _fileSourceInfoRepository.UpdateAsync(fileSourceInfo); } } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventDeletedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventDeletedHandler.cs index 6c9eabf1f..b007b0ae3 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventDeletedHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventDeletedHandler.cs @@ -23,11 +23,8 @@ public async Task HandleAsync(EventDeleted @event, CancellationToken cancellatio await _fileSourceInfoRepository.FindAsync(@event.EventId, ContextType.Event); foreach (var fileSourceInfo in fileSourceInfos) { - await _commandDispatcher.SendAsync(new DeleteMediaFile - { - MediaFileId = fileSourceInfo.Id - }, - cancellationToken); + fileSourceInfo.Unassociate(); + await _fileSourceInfoRepository.UpdateAsync(fileSourceInfo); } } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventUpdatedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventUpdatedHandler.cs index cba84e886..060861ca0 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventUpdatedHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/EventUpdatedHandler.cs @@ -23,14 +23,15 @@ public async Task HandleAsync(EventUpdated @event, CancellationToken cancellatio await _fileSourceInfoRepository.FindAsync(@event.EventId, ContextType.Event); foreach (var fileSourceInfo in fileSourceInfos) { - if(!@event.MediaFilesIds.Contains(fileSourceInfo.Id)) + if(@event.MediaFilesIds.Contains(fileSourceInfo.Id)) { - await _commandDispatcher.SendAsync(new DeleteMediaFile - { - MediaFileId = fileSourceInfo.Id - }, - cancellationToken); + fileSourceInfo.Associate(); } + else + { + fileSourceInfo.Unassociate(); + } + await _fileSourceInfoRepository.UpdateAsync(fileSourceInfo); } } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostCreatedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostCreatedHandler.cs index bd36ee387..fa18b9ced 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostCreatedHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostCreatedHandler.cs @@ -23,13 +23,10 @@ public async Task HandleAsync(PostCreated @event, CancellationToken cancellation await _fileSourceInfoRepository.FindAsync(@event.PostId, ContextType.Post); foreach (var fileSourceInfo in fileSourceInfos) { - if(!@event.MediaFilesIds.Contains(fileSourceInfo.Id)) + if(@event.MediaFilesIds.Contains(fileSourceInfo.Id)) { - await _commandDispatcher.SendAsync(new DeleteMediaFile - { - MediaFileId = fileSourceInfo.Id - }, - cancellationToken); + fileSourceInfo.Associate(); + await _fileSourceInfoRepository.UpdateAsync(fileSourceInfo); } } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostDeletedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostDeletedHandler.cs index 92e6d5ab8..4c0c6a592 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostDeletedHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostDeletedHandler.cs @@ -23,11 +23,8 @@ public async Task HandleAsync(PostDeleted @event, CancellationToken cancellation await _fileSourceInfoRepository.FindAsync(@event.PostId, ContextType.Post); foreach (var fileSourceInfo in fileSourceInfos) { - await _commandDispatcher.SendAsync(new DeleteMediaFile - { - MediaFileId = fileSourceInfo.Id - }, - cancellationToken); + fileSourceInfo.Unassociate(); + await _fileSourceInfoRepository.UpdateAsync(fileSourceInfo); } } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostUpdatedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostUpdatedHandler.cs index b10fcb9cb..7f7732ac2 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostUpdatedHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/PostUpdatedHandler.cs @@ -23,14 +23,15 @@ public async Task HandleAsync(PostUpdated @event, CancellationToken cancellation await _fileSourceInfoRepository.FindAsync(@event.PostId, ContextType.Post); foreach (var fileSourceInfo in fileSourceInfos) { - if(!@event.MediaFilesIds.Contains(fileSourceInfo.Id)) + if(@event.MediaFilesIds.Contains(fileSourceInfo.Id)) { - await _commandDispatcher.SendAsync(new DeleteMediaFile - { - MediaFileId = fileSourceInfo.Id - }, - cancellationToken); + fileSourceInfo.Associate(); } + else + { + fileSourceInfo.Unassociate(); + } + await _fileSourceInfoRepository.UpdateAsync(fileSourceInfo); } } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentCreatedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentCreatedHandler.cs index afb80dc1f..0e1050a04 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentCreatedHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentCreatedHandler.cs @@ -23,13 +23,10 @@ public async Task HandleAsync(StudentCreated @event, CancellationToken cancellat await _fileSourceInfoRepository.FindAsync(@event.StudentId, ContextType.StudentProfile); foreach (var fileSourceInfo in fileSourceInfos) { - if (fileSourceInfo.Id != @event.MediaFileId) + if (fileSourceInfo.Id == @event.MediaFileId) { - await _commandDispatcher.SendAsync(new DeleteMediaFile - { - MediaFileId = fileSourceInfo.Id - }, - cancellationToken); + fileSourceInfo.Associate(); + await _fileSourceInfoRepository.UpdateAsync(fileSourceInfo); } } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentDeletedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentDeletedHandler.cs index 45db72b19..dfbf9cf71 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentDeletedHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentDeletedHandler.cs @@ -23,11 +23,8 @@ public async Task HandleAsync(StudentDeleted @event, CancellationToken cancellat await _fileSourceInfoRepository.FindAsync(@event.StudentId, ContextType.StudentProfile); foreach (var fileSourceInfo in fileSourceInfos) { - await _commandDispatcher.SendAsync(new DeleteMediaFile - { - MediaFileId = fileSourceInfo.Id - }, - cancellationToken); + fileSourceInfo.Unassociate(); + await _fileSourceInfoRepository.UpdateAsync(fileSourceInfo); } } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentUpdatedHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentUpdatedHandler.cs index 760ff17ce..e630a5f8b 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentUpdatedHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Events/External/Handlers/StudentUpdatedHandler.cs @@ -23,14 +23,15 @@ public async Task HandleAsync(StudentUpdated @event, CancellationToken cancellat await _fileSourceInfoRepository.FindAsync(@event.StudentId, ContextType.StudentProfile); foreach (var fileSourceInfo in fileSourceInfos) { - if (fileSourceInfo.Id != @event.MediaFileId) + if (fileSourceInfo.Id == @event.MediaFileId) { - await _commandDispatcher.SendAsync(new DeleteMediaFile - { - MediaFileId = fileSourceInfo.Id - }, - cancellationToken); + fileSourceInfo.Associate(); } + else + { + fileSourceInfo.Unassociate(); + } + await _fileSourceInfoRepository.UpdateAsync(fileSourceInfo); } } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs index 5459bbad0..1b05daf8b 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs @@ -24,5 +24,15 @@ public FileSourceInfo(Guid id, Guid sourceId, ContextType sourceType, Guid uploa FileId = fileId; FileName = fileName; } + + public void Associate() + { + State = State.Associated; + } + + public void Unassociate() + { + State = State.Unassociated; + } } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs index 7cc16a06f..66ecba4d0 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs @@ -49,6 +49,13 @@ private static IReadOnlyDictionary MessageTemplates After = "Cleaned unmatched files for event with ID: {EventId}.", } }, + { + typeof(CleanupUnassociatedFiles), + new HandlerLogTemplate + { + After = "Cleaned unmatched files for all entities at {Now}." + } + }, }; public HandlerLogTemplate Map(TMessage message) where TMessage : class From c804b8d3c194cd7ea0ad0f7be6040dd164d93584 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 17:17:06 +0200 Subject: [PATCH 35/62] (#32) update CreatePost to force passing PostId generated before request --- .../MiniSpace.Services.Posts.Application/Commands/CreatePost.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/CreatePost.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/CreatePost.cs index 24c50dbb3..fdb630f37 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/CreatePost.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/CreatePost.cs @@ -15,7 +15,7 @@ public class CreatePost : ICommand public CreatePost(Guid postId, Guid eventId, Guid organizerId, string textContent, IEnumerable mediaFiles, string state, DateTime? publishDate) { - PostId = postId == Guid.Empty ? Guid.NewGuid() : postId; + PostId = postId; EventId = eventId; OrganizerId = organizerId; TextContent = textContent; From 62f0203c55c92bb50ea11966ff1e0514a0cfa3a2 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 19:21:42 +0200 Subject: [PATCH 36/62] (#30) update create event command to force passing EventId in request --- .../src/MiniSpace.Services.Events.Api/Program.cs | 2 +- .../Commands/{AddEvent.cs => CreateEvent.cs} | 6 +++--- .../{AddEventHandler.cs => CreateEventHandler.cs} | 11 ++++++++--- ...AddEventRejected.cs => CreateEventRejected.cs} | 2 +- .../Exceptions/InvalidEventIdException.cs | 15 +++++++++++++++ .../Repositories/IEventRepository.cs | 1 + .../Exceptions/ExceptionToMessageMapper.cs | 10 +++++----- .../Extensions.cs | 2 +- .../Logging/MessageToLogTemplateMapper.cs | 4 ++-- .../Mongo/Repositories/EventMongoRepository.cs | 1 + 10 files changed, 38 insertions(+), 16 deletions(-) rename MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/{AddEvent.cs => CreateEvent.cs} (89%) rename MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/{AddEventHandler.cs => CreateEventHandler.cs} (90%) rename MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/Rejected/{AddEventRejected.cs => CreateEventRejected.cs} (78%) create mode 100644 MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidEventIdException.cs diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Api/Program.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Api/Program.cs index c1b8e8662..451a53565 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Api/Program.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Api/Program.cs @@ -47,7 +47,7 @@ public static async Task Main(string[] args) .UseDispatcherEndpoints(endpoints => endpoints .Get("events/{eventId}") .Put("events/{eventId}") - .Post("events", + .Post("events", afterDispatch: (cmd, ctx) => ctx.Response.Created($"events/{cmd.EventId}")) .Delete("events/{eventId}") .Post("events/{eventId}/sign-up") diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/AddEvent.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/CreateEvent.cs similarity index 89% rename from MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/AddEvent.cs rename to MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/CreateEvent.cs index 74fc0bfea..bcb0ab00a 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/AddEvent.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/CreateEvent.cs @@ -6,7 +6,7 @@ namespace MiniSpace.Services.Events.Application.Commands { - public class AddEvent : ICommand + public class CreateEvent : ICommand { public Guid EventId { get; } public string Name { get; } @@ -27,12 +27,12 @@ public class AddEvent : ICommand public string Category { get; } public string PublishDate { get; } - public AddEvent(Guid eventId, string name, Guid organizerId, Guid organizationId, string startDate, + public CreateEvent(Guid eventId, string name, Guid organizerId, Guid organizationId, string startDate, string endDate, string buildingName, string street, string buildingNumber, string apartmentNumber, string city, string zipCode, IEnumerable mediaFiles, string description, int capacity, decimal fee, string category, string publishDate) { - EventId = eventId == Guid.Empty ? Guid.NewGuid() : eventId; + EventId = eventId; Name = name; OrganizerId = organizerId; OrganizationId = organizationId; diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/AddEventHandler.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/CreateEventHandler.cs similarity index 90% rename from MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/AddEventHandler.cs rename to MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/CreateEventHandler.cs index b766ff50c..13f82c327 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/AddEventHandler.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Commands/Handlers/CreateEventHandler.cs @@ -12,7 +12,7 @@ namespace MiniSpace.Services.Events.Application.Commands.Handlers { - public class AddEventHandler: ICommandHandler + public class CreateEventHandler: ICommandHandler { private readonly IEventRepository _eventRepository; private readonly IMessageBroker _messageBroker; @@ -21,7 +21,7 @@ public class AddEventHandler: ICommandHandler private readonly IEventValidator _eventValidator; private readonly IAppContext _appContext; - public AddEventHandler(IEventRepository eventRepository, IMessageBroker messageBroker, + public CreateEventHandler(IEventRepository eventRepository, IMessageBroker messageBroker, IOrganizationsServiceClient organizationsServiceClient, IDateTimeProvider dateTimeProvider, IEventValidator eventValidator, IAppContext appContext) { @@ -33,13 +33,18 @@ public AddEventHandler(IEventRepository eventRepository, IMessageBroker messageB _appContext = appContext; } - public async Task HandleAsync(AddEvent command, CancellationToken cancellationToken) + public async Task HandleAsync(CreateEvent command, CancellationToken cancellationToken) { var identity = _appContext.Identity; if (!identity.IsOrganizer) throw new AuthorizedUserIsNotAnOrganizerException(identity.Id); if(identity.Id != command.OrganizerId) throw new OrganizerCannotAddEventForAnotherOrganizerException(identity.Id, command.OrganizerId); + + if (command.EventId == Guid.Empty || await _eventRepository.ExistsAsync(command.EventId)) + { + throw new InvalidEventIdException(command.EventId); + } _eventValidator.ValidateName(command.Name); _eventValidator.ValidateDescription(command.Description); diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/Rejected/AddEventRejected.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/Rejected/CreateEventRejected.cs similarity index 78% rename from MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/Rejected/AddEventRejected.cs rename to MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/Rejected/CreateEventRejected.cs index 54e972866..50daa4279 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/Rejected/AddEventRejected.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Events/Rejected/CreateEventRejected.cs @@ -5,7 +5,7 @@ namespace MiniSpace.Services.Events.Application.Events.Rejected { - public class AddEventRejected(Guid organizerId, string reason, string code) : IRejectedEvent + public class CreateEventRejected(Guid organizerId, string reason, string code) : IRejectedEvent { public Guid OrganizerId { get; } = organizerId; public string Reason { get; } = reason; diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidEventIdException.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidEventIdException.cs new file mode 100644 index 000000000..89fcea7f5 --- /dev/null +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Application/Exceptions/InvalidEventIdException.cs @@ -0,0 +1,15 @@ +using System; + +namespace MiniSpace.Services.Events.Application.Exceptions +{ + public class InvalidEventIdException : AppException + { + public override string Code { get; } = "invalid_event_id"; + public Guid EventId { get; } + + public InvalidEventIdException(Guid eventId) : base($"Invalid event id: {eventId}.") + { + EventId = eventId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Repositories/IEventRepository.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Repositories/IEventRepository.cs index bed362306..65936de8a 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Repositories/IEventRepository.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Core/Repositories/IEventRepository.cs @@ -13,6 +13,7 @@ public interface IEventRepository Task AddAsync(Event @event); Task UpdateAsync(Event @event); Task DeleteAsync(Guid id); + Task ExistsAsync(Guid id); Task<(IEnumerable events, int pageNumber,int pageSize, int totalPages, int totalElements)> BrowseEventsAsync( int pageNumber, int pageSize, string name, string organizer, DateTime dateFrom, DateTime dateTo, Category? category, State? state, IEnumerable friends, EventEngagementType? friendsEngagementType, diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Exceptions/ExceptionToMessageMapper.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Exceptions/ExceptionToMessageMapper.cs index 28d680eea..75f68674f 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Exceptions/ExceptionToMessageMapper.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Exceptions/ExceptionToMessageMapper.cs @@ -12,7 +12,7 @@ public object Map(Exception exception, object message) => exception switch { // TODO: Add more exceptions - AuthorizedUserIsNotAnOrganizerException ex => new AddEventRejected(ex.UserId, ex.Message, ex.Code), + AuthorizedUserIsNotAnOrganizerException ex => new CreateEventRejected(ex.UserId, ex.Message, ex.Code), EventNotFoundException ex => message switch { @@ -30,25 +30,25 @@ EventNotFoundException ex InvalidEventCategoryException ex => message switch { - AddEvent m => new AddEventRejected(m.OrganizerId, ex.Message, ex.Code), + CreateEvent m => new CreateEventRejected(m.OrganizerId, ex.Message, ex.Code), _ => null }, InvalidEventDateTimeException ex => message switch { - AddEvent m => new AddEventRejected(m.OrganizerId, ex.Message, ex.Code), + CreateEvent m => new CreateEventRejected(m.OrganizerId, ex.Message, ex.Code), _ => null }, InvalidEventDateTimeOrderException ex => message switch { - AddEvent m => new AddEventRejected(m.OrganizerId, ex.Message, ex.Code), + CreateEvent m => new CreateEventRejected(m.OrganizerId, ex.Message, ex.Code), _ => null }, OrganizerCannotAddEventForAnotherOrganizerException ex => message switch { - AddEvent m => new AddEventRejected(m.OrganizerId, ex.Message, ex.Code), + CreateEvent m => new CreateEventRejected(m.OrganizerId, ex.Message, ex.Code), _ => null }, StudentNotFoundException ex diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Extensions.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Extensions.cs index 49a53898c..f38ac1665 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Extensions.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Extensions.cs @@ -103,7 +103,7 @@ public static IApplicationBuilder UseInfrastructure(this IApplicationBuilder app .UseMetrics() .UseAuthentication() .UseRabbitMq() - .SubscribeCommand() + .SubscribeCommand() .SubscribeCommand() .SubscribeCommand() .SubscribeCommand() diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Logging/MessageToLogTemplateMapper.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Logging/MessageToLogTemplateMapper.cs index f9dec514b..614512d2b 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Logging/MessageToLogTemplateMapper.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Logging/MessageToLogTemplateMapper.cs @@ -14,10 +14,10 @@ private static IReadOnlyDictionary MessageTemplates => new Dictionary { { - typeof(AddEvent), + typeof(CreateEvent), new HandlerLogTemplate { - After = "Added an event with id: {EventId}." + After = "Created an event with id: {EventId}." } }, { diff --git a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Mongo/Repositories/EventMongoRepository.cs b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Mongo/Repositories/EventMongoRepository.cs index af2c686d7..9d2485ccf 100644 --- a/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Mongo/Repositories/EventMongoRepository.cs +++ b/MiniSpace.Services.Events/src/MiniSpace.Services.Events.Infrastructure/Mongo/Repositories/EventMongoRepository.cs @@ -86,5 +86,6 @@ public async Task> GetAllAsync() public Task AddAsync(Event @event) => _repository.AddAsync(@event.AsDocument()); public Task UpdateAsync(Event @event) => _repository.UpdateAsync(@event.AsDocument()); public Task DeleteAsync(Guid id) => _repository.DeleteAsync(id); + public Task ExistsAsync(Guid id) => _repository.ExistsAsync(e => e.Id == id); } } \ No newline at end of file From 30153df6303e346519e4ce5cec036a2d35188e39 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 19:24:53 +0200 Subject: [PATCH 37/62] (#32) add postId validation to enforce sending not empty Guid in request --- .../Commands/Handlers/CreatePostHandler.cs | 5 +++++ .../Exceptions/InvalidPostIdException.cs | 12 ++++++++++++ .../Repositories/IPostRepository.cs | 1 + .../Mongo/Repositories/PostMongoRepository.cs | 3 +++ 4 files changed, 21 insertions(+) create mode 100644 MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Exceptions/InvalidPostIdException.cs diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/CreatePostHandler.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/CreatePostHandler.cs index 5ea7fda5a..44811ab9b 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/CreatePostHandler.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Commands/Handlers/CreatePostHandler.cs @@ -39,6 +39,11 @@ public async Task HandleAsync(CreatePost command, CancellationToken cancellation { throw new UnauthorizedPostCreationAttemptException(identity.Id, command.EventId); } + + if(command.PostId == Guid.Empty || await _postRepository.ExistsAsync(command.PostId)) + { + throw new InvalidPostIdException(command.PostId); + } if (!Enum.TryParse(command.State, true, out var newState)) { diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Exceptions/InvalidPostIdException.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Exceptions/InvalidPostIdException.cs new file mode 100644 index 000000000..13b2d64b0 --- /dev/null +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Application/Exceptions/InvalidPostIdException.cs @@ -0,0 +1,12 @@ +namespace MiniSpace.Services.Posts.Application.Exceptions +{ + public class InvalidPostIdException : AppException + { + public Guid PostId { get; } + + public InvalidPostIdException(Guid postId) : base($"Invalid post id: {postId}") + { + PostId = postId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Repositories/IPostRepository.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Repositories/IPostRepository.cs index cb9a727d7..56566f803 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Repositories/IPostRepository.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Core/Repositories/IPostRepository.cs @@ -10,5 +10,6 @@ public interface IPostRepository Task AddAsync(Post post); Task UpdateAsync(Post post); Task DeleteAsync(Guid id); + Task ExistsAsync(Guid id); } } diff --git a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/PostMongoRepository.cs b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/PostMongoRepository.cs index 7d6985b1d..86d5c5ff8 100644 --- a/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/PostMongoRepository.cs +++ b/MiniSpace.Services.Posts/src/MiniSpace.Services.Posts.Infrastructure/Mongo/Repositories/PostMongoRepository.cs @@ -46,5 +46,8 @@ public Task UpdateAsync(Post post) public Task DeleteAsync(Guid id) => _repository.DeleteAsync(id); + + public Task ExistsAsync(Guid id) + => _repository.ExistsAsync(p => p.Id == id); } } From f97cd0debff9ea9b862df602a4198a83686a3d2f Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 12 May 2024 19:41:58 +0200 Subject: [PATCH 38/62] (#92) update logging messages --- .../Logging/MessageToLogTemplateMapper.cs | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs index 66ecba4d0..706960785 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Logging/MessageToLogTemplateMapper.cs @@ -25,28 +25,63 @@ private static IReadOnlyDictionary MessageTemplates typeof(StudentCreated), new HandlerLogTemplate { - After = "Cleaned unmatched files for student with ID: {StudentId}.", + After = "Associated profile picture with ID: {MediaFileId} for student with ID: {StudentId}.", } }, { typeof(StudentUpdated), new HandlerLogTemplate { - After = "Cleaned unmatched files for student with ID: {StudentId}.", + After = "Associated profile picture with ID: {MediaFileId} for student with ID: {StudentId}.", + } + }, + { + typeof(StudentDeleted), + new HandlerLogTemplate + { + After = "Deleted all media files for student with ID: {StudentId}.", } }, { typeof(PostCreated), new HandlerLogTemplate { - After = "Cleaned unmatched files for post with ID: {PostId}.", + After = "Associated media files for post with ID: {PostId}.", + } + }, + { + typeof(PostUpdated), + new HandlerLogTemplate + { + After = "Associated media files for post with ID: {PostId}.", + } + }, + { + typeof(PostDeleted), + new HandlerLogTemplate + { + After = "Deleted all media files for post with ID: {PostId}.", } }, { typeof(EventCreated), new HandlerLogTemplate { - After = "Cleaned unmatched files for event with ID: {EventId}.", + After = "Associated media files for event with ID: {EventId}.", + } + }, + { + typeof(EventUpdated), + new HandlerLogTemplate + { + After = "Associated media files for event with ID: {EventId}.", + } + }, + { + typeof(EventDeleted), + new HandlerLogTemplate + { + After = "Deleted all media files for event with ID: {EventId}.", } }, { From 6a2b24f780ac66981cc61c1eb18b1ac24b9ccf28 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 12:09:16 +0200 Subject: [PATCH 39/62] (#92) update uploading image to keep original image --- .../Commands/Handlers/UploadMediaFileHandler.cs | 13 ++++++++++--- .../Dto/FileDto.cs | 2 +- ...MiniSpace.Services.MediaFiles.Application.csproj | 1 + .../Entities/FileSourceInfo.cs | 4 +++- .../Mongo/Documents/Extensions.cs | 3 ++- .../Mongo/Documents/FileSourceInfoDocument.cs | 1 + 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs index dced9da8a..cb028e0d4 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs @@ -4,6 +4,8 @@ using MiniSpace.Services.MediaFiles.Application.Services; using MiniSpace.Services.MediaFiles.Core.Entities; using MiniSpace.Services.MediaFiles.Core.Repositories; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Formats.Webp; namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers { @@ -37,12 +39,17 @@ public async Task HandleAsync(UploadMediaFile command, CancellationToken cancell { throw new InvalidContextTypeException(command.SourceType); } + byte[] bytes = Convert.FromBase64String(command.Base64Content); - var stream = new MemoryStream(bytes); + using var inStream = new MemoryStream(bytes); + using var myImage = await Image.LoadAsync(inStream, cancellationToken); + using var outStream = new MemoryStream(); + await myImage.SaveAsync(outStream, new WebpEncoder(), cancellationToken); - var objectId = await _gridFSService.UploadFileAsync(command.FileName, stream); + var originalObjectId = await _gridFSService.UploadFileAsync(command.FileName, inStream); + var objectId = await _gridFSService.UploadFileAsync(command.FileName, outStream); var fileSourceInfo = new FileSourceInfo(command.MediaFileId, command.SourceId, sourceType, - command.UploaderId, State.Unassociated, _dateTimeProvider.Now, objectId, command.FileName); + command.UploaderId, State.Unassociated, _dateTimeProvider.Now, originalObjectId,objectId, command.FileName); await _fileSourceInfoRepository.AddAsync(fileSourceInfo); await _messageBroker.PublishAsync(new MediaFileUploaded(command.MediaFileId, command.FileName)); } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs index 27aabb0c8..05425b355 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs @@ -14,7 +14,7 @@ public class FileDto public FileDto(Guid mediaFileId, Guid sourceId, string sourceType, Guid uploaderId, string state, DateTime createdAt, string fileName, string base64Content) { - MediaFileId = mediaFileId == Guid.Empty ? Guid.NewGuid() : mediaFileId; + MediaFileId = mediaFileId; SourceId = sourceId; SourceType = sourceType; UploaderId = uploaderId; diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj index 366eb3723..a4867130e 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/MiniSpace.Services.MediaFiles.Application.csproj @@ -13,6 +13,7 @@ + diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs index 1b05daf8b..0dc2f2947 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs @@ -9,11 +9,12 @@ public class FileSourceInfo: AggregateRoot public Guid UploaderId { get; set; } public State State { get; set; } public DateTime CreatedAt { get; set; } + public ObjectId OriginalFileId { get; set; } public ObjectId FileId { get; set; } public string FileName { get; set; } public FileSourceInfo(Guid id, Guid sourceId, ContextType sourceType, Guid uploaderId, State state, - DateTime createdAt, ObjectId fileId, string fileName) + DateTime createdAt, ObjectId originalFileId, ObjectId fileId, string fileName) { Id = id; SourceId = sourceId; @@ -21,6 +22,7 @@ public FileSourceInfo(Guid id, Guid sourceId, ContextType sourceType, Guid uploa UploaderId = uploaderId; State = state; CreatedAt = createdAt; + OriginalFileId = originalFileId; FileId = fileId; FileName = fileName; } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs index a11bd8503..e05dc1364 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs @@ -13,12 +13,13 @@ public static FileSourceInfoDocument AsDocument(this FileSourceInfo fileSourceIn UploaderId = fileSourceInfo.UploaderId, State = fileSourceInfo.State, CreatedAt = fileSourceInfo.CreatedAt, + OriginalFileId = fileSourceInfo.OriginalFileId, FileId = fileSourceInfo.FileId, FileName = fileSourceInfo.FileName }; public static FileSourceInfo AsEntity(this FileSourceInfoDocument document) => new FileSourceInfo(document.Id, document.SourceId, document.SourceType, document.UploaderId, - document.State, document.CreatedAt, document.FileId, document.FileName); + document.State, document.CreatedAt, document.OriginalFileId, document.FileId, document.FileName); } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs index 4ebbd38a6..ba7df5670 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs @@ -12,6 +12,7 @@ public class FileSourceInfoDocument : IIdentifiable public Guid UploaderId { get; set; } public State State { get; set; } public DateTime CreatedAt { get; set; } + public ObjectId OriginalFileId { get; set; } public ObjectId FileId { get; set; } public string FileName { get; set; } } From e8c7533d81acda86e6be9d45cbaaf8061cc4ad25 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 12:14:50 +0200 Subject: [PATCH 40/62] (#92) update deleting files to delete original file as well --- .../Commands/Handlers/CleanupUnassociatedFilesHandler.cs | 2 ++ .../Commands/Handlers/DeleteMediaFileHandler.cs | 1 + 2 files changed, 3 insertions(+) diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CleanupUnassociatedFilesHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CleanupUnassociatedFilesHandler.cs index e620304e1..53946e804 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CleanupUnassociatedFilesHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/CleanupUnassociatedFilesHandler.cs @@ -29,6 +29,8 @@ public async Task HandleAsync(CleanupUnassociatedFiles command, CancellationToke { continue; } + + await _gridFSService.DeleteFileAsync(file.OriginalFileId); await _gridFSService.DeleteFileAsync(file.FileId); await _fileSourceInfoRepository.DeleteAsync(file.Id); } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteMediaFileHandler.cs index b025de766..d3c005d49 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteMediaFileHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/DeleteMediaFileHandler.cs @@ -36,6 +36,7 @@ public async Task HandleAsync(DeleteMediaFile command, CancellationToken cancell throw new UnauthorizedMediaFileAccessException(fileSourceInfo.Id, identity.Id, fileSourceInfo.UploaderId); } + await _gridFSService.DeleteFileAsync(fileSourceInfo.OriginalFileId); await _gridFSService.DeleteFileAsync(fileSourceInfo.FileId); await _fileSourceInfoRepository.DeleteAsync(command.MediaFileId); await _messageBroker.PublishAsync(new MediaFileDeleted(command.MediaFileId, From 21eb9811ae27367763ef6f8de806c659842265d8 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 13:02:08 +0200 Subject: [PATCH 41/62] (#92) add file size validation --- .../Handlers/UploadMediaFileHandler.cs | 9 +++++++-- .../Exceptions/InvalidFileSizeException.cs | 16 ++++++++++++++++ .../Services/IFileValidator.cs | 7 +++++++ .../Extensions.cs | 1 + .../Services/FileValidator.cs | 19 +++++++++++++++++++ 5 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileSizeException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IFileValidator.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs index cb028e0d4..21c753d17 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs @@ -12,15 +12,18 @@ namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers public class UploadMediaFileHandler: ICommandHandler { private readonly IFileSourceInfoRepository _fileSourceInfoRepository; + private readonly IFileValidator _fileValidator; private readonly IGridFSService _gridFSService; private readonly IDateTimeProvider _dateTimeProvider; private readonly IAppContext _appContext; private readonly IMessageBroker _messageBroker; - public UploadMediaFileHandler(IFileSourceInfoRepository fileSourceInfoRepository, IGridFSService gridFSService, - IDateTimeProvider dateTimeProvider, IAppContext appContext, IMessageBroker messageBroker) + public UploadMediaFileHandler(IFileSourceInfoRepository fileSourceInfoRepository, IFileValidator fileValidator, + IGridFSService gridFSService, IDateTimeProvider dateTimeProvider, IAppContext appContext, + IMessageBroker messageBroker) { _fileSourceInfoRepository = fileSourceInfoRepository; + _fileValidator = fileValidator; _gridFSService = gridFSService; _dateTimeProvider = dateTimeProvider; _appContext = appContext; @@ -41,6 +44,8 @@ public async Task HandleAsync(UploadMediaFile command, CancellationToken cancell } byte[] bytes = Convert.FromBase64String(command.Base64Content); + _fileValidator.ValidateFileSize(bytes.Length); + using var inStream = new MemoryStream(bytes); using var myImage = await Image.LoadAsync(inStream, cancellationToken); using var outStream = new MemoryStream(); diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileSizeException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileSizeException.cs new file mode 100644 index 000000000..884805289 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileSizeException.cs @@ -0,0 +1,16 @@ +namespace MiniSpace.Services.MediaFiles.Application.Exceptions +{ + public class InvalidFileSizeException : AppException + { + public override string Code { get; } = "invalid_file_size_exception"; + public int FileSize { get; } + public int MaxFileSize { get; } + + public InvalidFileSizeException(int fileSize, int maxFileSize) + : base($"Invalid file size: {fileSize}. Maximum valid file size: {maxFileSize}.") + { + FileSize = fileSize; + MaxFileSize = maxFileSize; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IFileValidator.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IFileValidator.cs new file mode 100644 index 000000000..a9288a3d2 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IFileValidator.cs @@ -0,0 +1,7 @@ +namespace MiniSpace.Services.MediaFiles.Application.Services +{ + public interface IFileValidator + { + public void ValidateFileSize(int size); + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs index 76baf3d0f..80169233c 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs @@ -48,6 +48,7 @@ public static class Extensions public static IConveyBuilder AddInfrastructure(this IConveyBuilder builder) { builder.Services.AddTransient(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddTransient(); diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs new file mode 100644 index 000000000..028832256 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs @@ -0,0 +1,19 @@ +using MiniSpace.Services.MediaFiles.Application.Exceptions; +using MiniSpace.Services.MediaFiles.Application.Services; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Services +{ + public class FileValidator : IFileValidator + { + private const int MaxFileSize = 200_000; + + public void ValidateFileSize(int size) + { + if (size > MaxFileSize) + { + throw new InvalidFileSizeException(size, MaxFileSize); + } + } + + } +} \ No newline at end of file From 9cb201c6846aa4a7756673e3fd6a36d4d69b4e17 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 13:32:40 +0200 Subject: [PATCH 42/62] (#92) add file extension --- .../Handlers/UploadMediaFileHandler.cs | 5 ++++- .../Commands/UploadMediaFile.cs | 4 +++- .../Exceptions/InvalidFileContextType.cs | 6 ++++++ .../Entities/FileSourceInfo.cs | 4 +++- .../Mongo/Documents/Extensions.cs | 4 +++- .../Mongo/Documents/FileSourceInfoDocument.cs | 1 + .../Services/FileValidator.cs | 20 +++++++++++++++++++ 7 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileContextType.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs index 21c753d17..4125be105 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs @@ -43,6 +43,8 @@ public async Task HandleAsync(UploadMediaFile command, CancellationToken cancell throw new InvalidContextTypeException(command.SourceType); } + _fileValidator. + byte[] bytes = Convert.FromBase64String(command.Base64Content); _fileValidator.ValidateFileSize(bytes.Length); @@ -54,7 +56,8 @@ public async Task HandleAsync(UploadMediaFile command, CancellationToken cancell var originalObjectId = await _gridFSService.UploadFileAsync(command.FileName, inStream); var objectId = await _gridFSService.UploadFileAsync(command.FileName, outStream); var fileSourceInfo = new FileSourceInfo(command.MediaFileId, command.SourceId, sourceType, - command.UploaderId, State.Unassociated, _dateTimeProvider.Now, originalObjectId,objectId, command.FileName); + command.UploaderId, State.Unassociated, _dateTimeProvider.Now, originalObjectId, + command.FileContextType, objectId, command.FileName); await _fileSourceInfoRepository.AddAsync(fileSourceInfo); await _messageBroker.PublishAsync(new MediaFileUploaded(command.MediaFileId, command.FileName)); } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs index 6bc3c4230..5acf5a034 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs @@ -10,16 +10,18 @@ public class UploadMediaFile : ICommand public string SourceType { get; set; } public Guid UploaderId { get; set; } public string FileName { get; set; } + public string FileContextType { get; set; } public string Base64Content { get; set; } public UploadMediaFile(Guid mediaFileId, Guid sourceId, string sourceType, Guid uploaderId, - string fileName, string base64Content) + string fileName, string fileContextType, string base64Content) { MediaFileId = mediaFileId == Guid.Empty ? Guid.NewGuid() : mediaFileId; SourceId = sourceId; SourceType = sourceType; UploaderId = uploaderId; FileName = fileName; + FileContextType = fileContextType; Base64Content = base64Content; } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileContextType.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileContextType.cs new file mode 100644 index 000000000..bf656af09 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileContextType.cs @@ -0,0 +1,6 @@ +namespace MiniSpace.Services.MediaFiles.Application.Exceptions; + +public class InvalidFileContextType +{ + +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs index 0dc2f2947..fdc1814fd 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs @@ -10,11 +10,12 @@ public class FileSourceInfo: AggregateRoot public State State { get; set; } public DateTime CreatedAt { get; set; } public ObjectId OriginalFileId { get; set; } + public string OriginalFileContextType { get; set; } public ObjectId FileId { get; set; } public string FileName { get; set; } public FileSourceInfo(Guid id, Guid sourceId, ContextType sourceType, Guid uploaderId, State state, - DateTime createdAt, ObjectId originalFileId, ObjectId fileId, string fileName) + DateTime createdAt, ObjectId originalFileId, string originalFileContextType, ObjectId fileId, string fileName) { Id = id; SourceId = sourceId; @@ -23,6 +24,7 @@ public FileSourceInfo(Guid id, Guid sourceId, ContextType sourceType, Guid uploa State = state; CreatedAt = createdAt; OriginalFileId = originalFileId; + OriginalFileContextType = originalFileContextType; FileId = fileId; FileName = fileName; } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs index e05dc1364..357893125 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs @@ -14,12 +14,14 @@ public static FileSourceInfoDocument AsDocument(this FileSourceInfo fileSourceIn State = fileSourceInfo.State, CreatedAt = fileSourceInfo.CreatedAt, OriginalFileId = fileSourceInfo.OriginalFileId, + OriginalFileContextType = fileSourceInfo.OriginalFileContextType, FileId = fileSourceInfo.FileId, FileName = fileSourceInfo.FileName }; public static FileSourceInfo AsEntity(this FileSourceInfoDocument document) => new FileSourceInfo(document.Id, document.SourceId, document.SourceType, document.UploaderId, - document.State, document.CreatedAt, document.OriginalFileId, document.FileId, document.FileName); + document.State, document.CreatedAt, document.OriginalFileId, document.OriginalFileContextType, + document.FileId, document.FileName); } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs index ba7df5670..512f2edd6 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs @@ -13,6 +13,7 @@ public class FileSourceInfoDocument : IIdentifiable public State State { get; set; } public DateTime CreatedAt { get; set; } public ObjectId OriginalFileId { get; set; } + public string OriginalFileContextType { get; set; } public ObjectId FileId { get; set; } public string FileName { get; set; } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs index 028832256..7c714b804 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs @@ -7,6 +7,18 @@ public class FileValidator : IFileValidator { private const int MaxFileSize = 200_000; + private readonly Dictionary _mimeTypes = new Dictionary() + { + { "FFD8FFE0", "image/jpeg" }, + { "FFD8FFE1", "image/jpeg" }, + { "FFD8FFE2", "image/jpeg" }, + { "89504E47", "image/png" }, + { "47494638", "image/gif" }, + { "49492A00", "image/tiff" }, + { "4D4D002A", "image/tiff" }, + { "424D", "image/bmp" } + }; + public void ValidateFileSize(int size) { if (size > MaxFileSize) @@ -14,6 +26,14 @@ public void ValidateFileSize(int size) throw new InvalidFileSizeException(size, MaxFileSize); } } + + public void ValidateFileExtensions(byte[] bytes, string contextType) + { + if (!_mimeTypes.ContainsValue(contextType)) + { + throw new InvalidFileContextTypeException(contextType); + } + } } } \ No newline at end of file From 7e4f48e33752b9fa86b8be3aafa8e2aa488222de Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 13:58:11 +0200 Subject: [PATCH 43/62] (#92) update validator --- .../Commands/Handlers/UploadMediaFileHandler.cs | 5 ++--- .../Commands/UploadMediaFile.cs | 6 +++--- .../FileTypeDoesNotMatchContentTypeException.cs | 16 ++++++++++++++++ .../InvalidFileContentTypeException.cs | 13 +++++++++++++ .../Exceptions/InvalidFileContextType.cs | 6 ------ .../Exceptions/InvalidFileSizeException.cs | 2 +- .../Services/IFileValidator.cs | 1 + .../Entities/FileSourceInfo.cs | 6 +++--- .../Mongo/Documents/Extensions.cs | 4 ++-- .../Mongo/Documents/FileSourceInfoDocument.cs | 2 +- .../Services/FileValidator.cs | 13 ++++++++++--- 11 files changed, 52 insertions(+), 22 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/FileTypeDoesNotMatchContentTypeException.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileContentTypeException.cs delete mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileContextType.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs index 4125be105..229526815 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs @@ -43,10 +43,9 @@ public async Task HandleAsync(UploadMediaFile command, CancellationToken cancell throw new InvalidContextTypeException(command.SourceType); } - _fileValidator. - byte[] bytes = Convert.FromBase64String(command.Base64Content); _fileValidator.ValidateFileSize(bytes.Length); + _fileValidator.ValidateFileExtensions(bytes, command.FileContentType); using var inStream = new MemoryStream(bytes); using var myImage = await Image.LoadAsync(inStream, cancellationToken); @@ -57,7 +56,7 @@ public async Task HandleAsync(UploadMediaFile command, CancellationToken cancell var objectId = await _gridFSService.UploadFileAsync(command.FileName, outStream); var fileSourceInfo = new FileSourceInfo(command.MediaFileId, command.SourceId, sourceType, command.UploaderId, State.Unassociated, _dateTimeProvider.Now, originalObjectId, - command.FileContextType, objectId, command.FileName); + command.FileContentType, objectId, command.FileName); await _fileSourceInfoRepository.AddAsync(fileSourceInfo); await _messageBroker.PublishAsync(new MediaFileUploaded(command.MediaFileId, command.FileName)); } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs index 5acf5a034..459373162 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/UploadMediaFile.cs @@ -10,18 +10,18 @@ public class UploadMediaFile : ICommand public string SourceType { get; set; } public Guid UploaderId { get; set; } public string FileName { get; set; } - public string FileContextType { get; set; } + public string FileContentType { get; set; } public string Base64Content { get; set; } public UploadMediaFile(Guid mediaFileId, Guid sourceId, string sourceType, Guid uploaderId, - string fileName, string fileContextType, string base64Content) + string fileName, string fileContentType, string base64Content) { MediaFileId = mediaFileId == Guid.Empty ? Guid.NewGuid() : mediaFileId; SourceId = sourceId; SourceType = sourceType; UploaderId = uploaderId; FileName = fileName; - FileContextType = fileContextType; + FileContentType = fileContentType; Base64Content = base64Content; } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/FileTypeDoesNotMatchContentTypeException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/FileTypeDoesNotMatchContentTypeException.cs new file mode 100644 index 000000000..942623598 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/FileTypeDoesNotMatchContentTypeException.cs @@ -0,0 +1,16 @@ +namespace MiniSpace.Services.MediaFiles.Application.Exceptions +{ + public class FileTypeDoesNotMatchContentTypeException : AppException + { + public override string Code { get; } = "file_type_does_not_match_content_type"; + public string FileType { get; } + public string ContentType { get; } + + public FileTypeDoesNotMatchContentTypeException(string fileType, string contentType) + : base($"File extension: {fileType} is not matching content type: {contentType}") + { + FileType = fileType; + ContentType = contentType; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileContentTypeException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileContentTypeException.cs new file mode 100644 index 000000000..7afb2e5d4 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileContentTypeException.cs @@ -0,0 +1,13 @@ +namespace MiniSpace.Services.MediaFiles.Application.Exceptions +{ + public class InvalidFileContentTypeException : AppException + { + public override string Code { get; } = "invalid_file_content_type"; + public string ContentType { get; } + + public InvalidFileContentTypeException(string contentType) : base($"Invalid file content type: {contentType}.") + { + ContentType = contentType; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileContextType.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileContextType.cs deleted file mode 100644 index bf656af09..000000000 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileContextType.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace MiniSpace.Services.MediaFiles.Application.Exceptions; - -public class InvalidFileContextType -{ - -} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileSizeException.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileSizeException.cs index 884805289..e570dec7c 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileSizeException.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Exceptions/InvalidFileSizeException.cs @@ -2,7 +2,7 @@ { public class InvalidFileSizeException : AppException { - public override string Code { get; } = "invalid_file_size_exception"; + public override string Code { get; } = "invalid_file_size"; public int FileSize { get; } public int MaxFileSize { get; } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IFileValidator.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IFileValidator.cs index a9288a3d2..b6450def4 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IFileValidator.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IFileValidator.cs @@ -3,5 +3,6 @@ public interface IFileValidator { public void ValidateFileSize(int size); + public void ValidateFileExtensions(byte[] bytes, string contentType); } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs index fdc1814fd..84e52e5c5 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Core/Entities/FileSourceInfo.cs @@ -10,12 +10,12 @@ public class FileSourceInfo: AggregateRoot public State State { get; set; } public DateTime CreatedAt { get; set; } public ObjectId OriginalFileId { get; set; } - public string OriginalFileContextType { get; set; } + public string OriginalFileContentType { get; set; } public ObjectId FileId { get; set; } public string FileName { get; set; } public FileSourceInfo(Guid id, Guid sourceId, ContextType sourceType, Guid uploaderId, State state, - DateTime createdAt, ObjectId originalFileId, string originalFileContextType, ObjectId fileId, string fileName) + DateTime createdAt, ObjectId originalFileId, string originalFileContentType, ObjectId fileId, string fileName) { Id = id; SourceId = sourceId; @@ -24,7 +24,7 @@ public FileSourceInfo(Guid id, Guid sourceId, ContextType sourceType, Guid uploa State = state; CreatedAt = createdAt; OriginalFileId = originalFileId; - OriginalFileContextType = originalFileContextType; + OriginalFileContentType = originalFileContentType; FileId = fileId; FileName = fileName; } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs index 357893125..ca41d0535 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/Extensions.cs @@ -14,14 +14,14 @@ public static FileSourceInfoDocument AsDocument(this FileSourceInfo fileSourceIn State = fileSourceInfo.State, CreatedAt = fileSourceInfo.CreatedAt, OriginalFileId = fileSourceInfo.OriginalFileId, - OriginalFileContextType = fileSourceInfo.OriginalFileContextType, + OriginalFileContentType = fileSourceInfo.OriginalFileContentType, FileId = fileSourceInfo.FileId, FileName = fileSourceInfo.FileName }; public static FileSourceInfo AsEntity(this FileSourceInfoDocument document) => new FileSourceInfo(document.Id, document.SourceId, document.SourceType, document.UploaderId, - document.State, document.CreatedAt, document.OriginalFileId, document.OriginalFileContextType, + document.State, document.CreatedAt, document.OriginalFileId, document.OriginalFileContentType, document.FileId, document.FileName); } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs index 512f2edd6..8aba3c17a 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Documents/FileSourceInfoDocument.cs @@ -13,7 +13,7 @@ public class FileSourceInfoDocument : IIdentifiable public State State { get; set; } public DateTime CreatedAt { get; set; } public ObjectId OriginalFileId { get; set; } - public string OriginalFileContextType { get; set; } + public string OriginalFileContentType { get; set; } public ObjectId FileId { get; set; } public string FileName { get; set; } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs index 7c714b804..7d1daf3e5 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs @@ -27,11 +27,18 @@ public void ValidateFileSize(int size) } } - public void ValidateFileExtensions(byte[] bytes, string contextType) + public void ValidateFileExtensions(byte[] bytes, string contentType) { - if (!_mimeTypes.ContainsValue(contextType)) + if (!_mimeTypes.ContainsValue(contentType)) { - throw new InvalidFileContextTypeException(contextType); + throw new InvalidFileContentTypeException(contentType); + } + + string hex = BitConverter.ToString(bytes, 0, 4).Replace("-", string.Empty); + _mimeTypes.TryGetValue(hex, out var mimeType); + if (mimeType != contentType) + { + throw new FileTypeDoesNotMatchContentTypeException(mimeType, contentType); } } From 53dd4c6536da25d7c7e6639fff77cfde2de3e871 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 14:08:40 +0200 Subject: [PATCH 44/62] (#92) update validator to include webp original images --- .../Services/FileValidator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs index 7d1daf3e5..d43a8e20a 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs @@ -5,7 +5,7 @@ namespace MiniSpace.Services.MediaFiles.Infrastructure.Services { public class FileValidator : IFileValidator { - private const int MaxFileSize = 200_000; + private const int MaxFileSize = 1_000_000; private readonly Dictionary _mimeTypes = new Dictionary() { @@ -16,7 +16,7 @@ public class FileValidator : IFileValidator { "47494638", "image/gif" }, { "49492A00", "image/tiff" }, { "4D4D002A", "image/tiff" }, - { "424D", "image/bmp" } + { "52494646", "image/webp" } }; public void ValidateFileSize(int size) From 66779d9098cfae8246c56f952aae339a39af6a56 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 14:17:36 +0200 Subject: [PATCH 45/62] (#92) add endpoint for getting original media file --- .../Program.cs | 1 + .../Dto/FileDto.cs | 4 +- .../Queries/GetOriginalMediaFile.cs | 10 +++++ .../Queries/Handlers/GetMediaFileHandler.cs | 3 +- .../Handlers/GetOriginalMediaFileHandler.cs | 44 +++++++++++++++++++ 5 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetOriginalMediaFile.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetOriginalMediaFileHandler.cs diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs index 434c231f0..dc1761162 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs @@ -33,6 +33,7 @@ public static async Task Main(string[] args) .UseDispatcherEndpoints(endpoints => endpoints .Get("", ctx => ctx.Response.WriteAsync(ctx.RequestServices.GetService().Name)) .Get("media-files/{mediaFileId}") + .Get("media-files/{mediaFileId}/original") .Post("media-files", afterDispatch: (cmd, ctx) => ctx.Response.Created($"media-files/{cmd.MediaFileId}")) .Delete("media-files/{mediaFileId}") diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs index 05425b355..e794c5c31 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileDto.cs @@ -9,10 +9,11 @@ public class FileDto public DateTime CreatedAt { get; set; } public Guid UploaderId { get; set; } public string FileName { get; set; } + public string FileContentType { get; set; } public string Base64Content { get; set; } public FileDto(Guid mediaFileId, Guid sourceId, string sourceType, Guid uploaderId, string state, - DateTime createdAt, string fileName, string base64Content) + DateTime createdAt, string fileName, string fileContentType, string base64Content) { MediaFileId = mediaFileId; SourceId = sourceId; @@ -21,6 +22,7 @@ public FileDto(Guid mediaFileId, Guid sourceId, string sourceType, Guid uploader State = state; CreatedAt = createdAt; FileName = fileName; + FileContentType = fileContentType; Base64Content = base64Content; } } diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetOriginalMediaFile.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetOriginalMediaFile.cs new file mode 100644 index 000000000..09c9fdf65 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Queries/GetOriginalMediaFile.cs @@ -0,0 +1,10 @@ +using Convey.CQRS.Queries; +using MiniSpace.Services.MediaFiles.Application.Dto; + +namespace MiniSpace.Services.MediaFiles.Application.Queries +{ + public class GetOriginalMediaFile : IQuery + { + public Guid MediaFileId { get; set; } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFileHandler.cs index 08f6e8a1c..2d5abd75a 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFileHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetMediaFileHandler.cs @@ -14,6 +14,7 @@ public class GetMediaFileHandler : IQueryHandler { private readonly IMongoRepository _fileSourceInfoRepository; private readonly IGridFSService _gridFSService; + private const string FileContentType = "image/webp"; public GetMediaFileHandler(IMongoRepository fileSourceInfoRepository, IGridFSService gridFSService) @@ -38,7 +39,7 @@ public async Task HandleAsync(GetMediaFile query, CancellationToken can return new FileDto(query.MediaFileId, fileSourceInfo.SourceId, fileSourceInfo.SourceType.ToString(), fileSourceInfo.UploaderId, fileSourceInfo.State.ToString().ToLower(), fileSourceInfo.CreatedAt, - fileSourceInfo.FileName, base64String); + fileSourceInfo.FileName, FileContentType, base64String); } } } \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetOriginalMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetOriginalMediaFileHandler.cs new file mode 100644 index 000000000..3e8edf827 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Mongo/Queries/Handlers/GetOriginalMediaFileHandler.cs @@ -0,0 +1,44 @@ +using Convey.CQRS.Queries; +using Convey.Persistence.MongoDB; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Net.Http.Headers; +using MiniSpace.Services.MediaFiles.Application.Dto; +using MiniSpace.Services.MediaFiles.Application.Queries; +using MiniSpace.Services.MediaFiles.Application.Services; +using MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Documents; +using MongoDB.Bson; + +namespace MiniSpace.Services.MediaFiles.Infrastructure.Mongo.Queries.Handlers +{ + public class GetOriginalMediaFileHandler : IQueryHandler + { + private readonly IMongoRepository _fileSourceInfoRepository; + private readonly IGridFSService _gridFSService; + + public GetOriginalMediaFileHandler(IMongoRepository fileSourceInfoRepository, + IGridFSService gridFSService) + { + _fileSourceInfoRepository = fileSourceInfoRepository; + _gridFSService = gridFSService; + } + + public async Task HandleAsync(GetOriginalMediaFile query, CancellationToken cancellationToken) + { + var fileSourceInfo = await _fileSourceInfoRepository.GetAsync(query.MediaFileId); + if (fileSourceInfo is null) + { + return null; + } + + var fileStream = new MemoryStream(); + await _gridFSService.DownloadFileAsync(fileSourceInfo.OriginalFileId, fileStream); + fileStream.Seek(0, SeekOrigin.Begin); + byte[] fileContent = fileStream.ToArray(); + var base64String = Convert.ToBase64String(fileContent); + + return new FileDto(query.MediaFileId, fileSourceInfo.SourceId, fileSourceInfo.SourceType.ToString(), + fileSourceInfo.UploaderId, fileSourceInfo.State.ToString().ToLower(), fileSourceInfo.CreatedAt, + fileSourceInfo.FileName, fileSourceInfo.OriginalFileContentType, base64String); + } + } +} \ No newline at end of file From 4f3da326e927e35fa2dd4ee5add435b9582d054c Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 14:48:54 +0200 Subject: [PATCH 46/62] (#92) fix issue with stream position --- .../Commands/Handlers/UploadMediaFileHandler.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs index 229526815..87f5e842b 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs @@ -51,6 +51,8 @@ public async Task HandleAsync(UploadMediaFile command, CancellationToken cancell using var myImage = await Image.LoadAsync(inStream, cancellationToken); using var outStream = new MemoryStream(); await myImage.SaveAsync(outStream, new WebpEncoder(), cancellationToken); + inStream.Position = 0; + outStream.Position = 0; var originalObjectId = await _gridFSService.UploadFileAsync(command.FileName, inStream); var objectId = await _gridFSService.UploadFileAsync(command.FileName, outStream); From 92495c82c25bda0cebe819922e3f9d1c3fb1507b Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 14:49:22 +0200 Subject: [PATCH 47/62] (#31) add endpoint for getting original media file --- MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.yml b/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.yml index 89aed770a..731257a35 100644 --- a/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.yml +++ b/MiniSpace.APIGateway/src/MiniSpace.APIGateway/ntrada.yml @@ -614,6 +614,11 @@ modules: use: downstream downstream: mediafiles-service/media-files/{mediaFileId} + - upstream: /{mediaFileId}/original + method: GET + use: downstream + downstream: mediafiles-service/media-files/{mediaFileId}/original + - upstream: /{mediaFileId} method: DELETE use: downstream From cfb907aadcbc6adeff99cf7e0124353a00c705a2 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 16:26:46 +0200 Subject: [PATCH 48/62] (#92)(#57) add media files service --- .../Areas/MediaFiles/IMediaFilesService.cs | 16 +++++++ .../Areas/MediaFiles/MediaFilesService.cs | 46 +++++++++++++++++++ .../src/MiniSpace.Web/DTO/FileDto.cs | 17 +++++++ 3 files changed, 79 insertions(+) create mode 100644 MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/IMediaFilesService.cs create mode 100644 MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/MediaFilesService.cs create mode 100644 MiniSpace.Web/src/MiniSpace.Web/DTO/FileDto.cs diff --git a/MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/IMediaFilesService.cs b/MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/IMediaFilesService.cs new file mode 100644 index 000000000..bbdc40b85 --- /dev/null +++ b/MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/IMediaFilesService.cs @@ -0,0 +1,16 @@ +using System; +using System.Threading.Tasks; +using MiniSpace.Web.DTO; +using MiniSpace.Web.HttpClients; + +namespace MiniSpace.Web.Areas.MediaFiles +{ + public interface IMediaFilesService + { + public Task GetFileAsync(Guid fileId); + public Task GetOriginalFileAsync(Guid fileId); + public Task> UploadMediaFileAsync(Guid sourceId, string sourceType, Guid uploaderId, + string fileName, string fileContentType, string base64Content); + public Task DeleteMediaFileAsync(Guid fileId); + } +} \ No newline at end of file diff --git a/MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/MediaFilesService.cs b/MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/MediaFilesService.cs new file mode 100644 index 000000000..758d55f64 --- /dev/null +++ b/MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/MediaFilesService.cs @@ -0,0 +1,46 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using MiniSpace.Web.Areas.Identity; +using MiniSpace.Web.DTO; +using MiniSpace.Web.HttpClients; + +namespace MiniSpace.Web.Areas.MediaFiles +{ + public class MediaFilesService : IMediaFilesService + { + private readonly IHttpClient _httpClient; + private readonly IIdentityService _identityService; + + public MediaFilesService(IHttpClient httpClient, IIdentityService identityService) + { + _httpClient = httpClient; + _identityService = identityService; + } + + public Task GetFileAsync(Guid fileId) + { + return _httpClient.GetAsync($"media-files/{fileId}"); + } + + public Task GetOriginalFileAsync(Guid fileId) + { + return _httpClient.GetAsync($"media-files/{fileId}/original"); + } + + public Task> UploadMediaFileAsync(Guid sourceId, string sourceType, Guid uploaderId, string fileName, + string fileContentType, string base64Content) + { + _httpClient.SetAccessToken(_identityService.JwtDto.AccessToken); + return _httpClient.PostAsync("media-files", new {sourceId, sourceType, uploaderId, + fileName, fileContentType, base64Content }); + } + + public Task DeleteMediaFileAsync(Guid fileId) + { + _httpClient.SetAccessToken(_identityService.JwtDto.AccessToken); + return _httpClient.DeleteAsync($"media-files/{fileId}"); + } + + } +} \ No newline at end of file diff --git a/MiniSpace.Web/src/MiniSpace.Web/DTO/FileDto.cs b/MiniSpace.Web/src/MiniSpace.Web/DTO/FileDto.cs new file mode 100644 index 000000000..7b2075b5e --- /dev/null +++ b/MiniSpace.Web/src/MiniSpace.Web/DTO/FileDto.cs @@ -0,0 +1,17 @@ +using System; + +namespace MiniSpace.Web.DTO +{ + public class FileDto + { + public Guid MediaFileId { get; set; } + public Guid SourceId { get; set; } + public string SourceType { get; set; } + public string State { get; set; } + public DateTime CreatedAt { get; set; } + public Guid UploaderId { get; set; } + public string FileName { get; set; } + public string FileContentType { get; set; } + public string Base64Content { get; set; } + } +} \ No newline at end of file From dcbe3940d9e89520057da8aa7a22d9e8b45869f7 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 16:51:43 +0200 Subject: [PATCH 49/62] (#92)(#57) update students service --- .../MiniSpace.Web/Areas/Students/IStudentsService.cs | 4 ++-- .../MiniSpace.Web/Areas/Students/StudentsService.cs | 4 ++-- MiniSpace.Web/src/MiniSpace.Web/DTO/StudentDto.cs | 2 +- .../MiniSpace.Web/DTO/Types/MediaFileContextType.cs | 9 +++++++++ .../Models/Students/CompleteRegistrationModel.cs | 2 +- .../Pages/Account/CompleteRegistration.razor | 11 +++++++++-- MiniSpace.Web/src/MiniSpace.Web/Startup.cs | 2 ++ 7 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 MiniSpace.Web/src/MiniSpace.Web/DTO/Types/MediaFileContextType.cs diff --git a/MiniSpace.Web/src/MiniSpace.Web/Areas/Students/IStudentsService.cs b/MiniSpace.Web/src/MiniSpace.Web/Areas/Students/IStudentsService.cs index 1cbed12d1..0514d4e03 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Areas/Students/IStudentsService.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Areas/Students/IStudentsService.cs @@ -13,8 +13,8 @@ public interface IStudentsService void ClearStudentDto(); Task GetStudentAsync(Guid studentId); Task> GetStudentsAsync(); - Task UpdateStudentAsync(Guid studentId, string profileImage, string description, bool emailNotifications); - Task> CompleteStudentRegistrationAsync(Guid studentId, string profileImage, + Task UpdateStudentAsync(Guid studentId, Guid profileImage, string description, bool emailNotifications); + Task> CompleteStudentRegistrationAsync(Guid studentId, Guid profileImage, string description, DateTime dateOfBirth, bool emailNotifications); Task GetStudentStateAsync(Guid studentId); } diff --git a/MiniSpace.Web/src/MiniSpace.Web/Areas/Students/StudentsService.cs b/MiniSpace.Web/src/MiniSpace.Web/Areas/Students/StudentsService.cs index a5ec57ac8..d0757b6e8 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Areas/Students/StudentsService.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Areas/Students/StudentsService.cs @@ -45,14 +45,14 @@ public Task> GetStudentsAsync() return _httpClient.GetAsync>("students"); } - public Task UpdateStudentAsync(Guid studentId, string profileImage, string description, bool emailNotifications) + public Task UpdateStudentAsync(Guid studentId, Guid profileImage, string description, bool emailNotifications) { _httpClient.SetAccessToken(_identityService.JwtDto.AccessToken); return _httpClient.PutAsync($"students/{studentId}", new {studentId, profileImage, description, emailNotifications}); } - public Task> CompleteStudentRegistrationAsync(Guid studentId, string profileImage, + public Task> CompleteStudentRegistrationAsync(Guid studentId, Guid profileImage, string description, DateTime dateOfBirth, bool emailNotifications) => _httpClient.PostAsync("students", new {studentId, profileImage, description, dateOfBirth, emailNotifications}); diff --git a/MiniSpace.Web/src/MiniSpace.Web/DTO/StudentDto.cs b/MiniSpace.Web/src/MiniSpace.Web/DTO/StudentDto.cs index 0400d6cd8..a09c52928 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/DTO/StudentDto.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/DTO/StudentDto.cs @@ -10,7 +10,7 @@ public class StudentDto public string FirstName { get; set; } public string LastName { get; set; } public int NumberOfFriends { get; set; } - public string ProfileImage { get; set; } + public Guid ProfileImage { get; set; } public string Description { get; set; } public DateTime DateOfBirth { get; set; } public bool EmailNotifications { get; set; } diff --git a/MiniSpace.Web/src/MiniSpace.Web/DTO/Types/MediaFileContextType.cs b/MiniSpace.Web/src/MiniSpace.Web/DTO/Types/MediaFileContextType.cs new file mode 100644 index 000000000..9cbe6b2ea --- /dev/null +++ b/MiniSpace.Web/src/MiniSpace.Web/DTO/Types/MediaFileContextType.cs @@ -0,0 +1,9 @@ +namespace MiniSpace.Web.DTO.Types +{ + public enum MediaFileContextType + { + Event, + Post, + StudentProfile, + } +} \ No newline at end of file diff --git a/MiniSpace.Web/src/MiniSpace.Web/Models/Students/CompleteRegistrationModel.cs b/MiniSpace.Web/src/MiniSpace.Web/Models/Students/CompleteRegistrationModel.cs index 5938dfe67..b7b904a1e 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Models/Students/CompleteRegistrationModel.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Models/Students/CompleteRegistrationModel.cs @@ -5,7 +5,7 @@ namespace MiniSpace.Web.Models.Students public class CompleteRegistrationModel { public Guid StudentId { get; set; } - public string ProfileImage { get; set; } + public Guid ProfileImage { get; set; } public string Description { get; set; } public DateTime DateOfBirth { get; set; } public bool EmailNotifications { get; set; } diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/CompleteRegistration.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/CompleteRegistration.razor index 6566fe092..f9c3767a6 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/CompleteRegistration.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/CompleteRegistration.razor @@ -5,9 +5,12 @@ @using MiniSpace.Web.Models.Students @using System.IO @using MiniSpace.Web.Areas.Http +@using MiniSpace.Web.Areas.MediaFiles +@using MiniSpace.Web.DTO.Types @using Radzen @inject IIdentityService IdentityService @inject IStudentsService StudentsService +@inject IMediaFilesService MediaFilesService @inject IErrorMapperService ErrorMapperService @inject NavigationManager NavigationManager @@ -66,7 +69,7 @@ if (IdentityService.IsAuthenticated) { completeRegistrationModel.StudentId = IdentityService.UserDto.Id; - completeRegistrationModel.ProfileImage = "null"; + completeRegistrationModel.ProfileImage = Guid.Empty; completeRegistrationModel.DateOfBirth = DateTime.Now; } } @@ -118,7 +121,11 @@ long maxFileSize = 10 * 1024 * 1024; var stream = file.OpenReadStream(maxFileSize); byte[] bytes = await ReadFully(stream); - completeRegistrationModel.ProfileImage = Convert.ToBase64String(bytes); + var base64Content = Convert.ToBase64String(bytes); + var response = await MediaFilesService.UploadMediaFileAsync(IdentityService.UserDto.Id, + MediaFileContextType.StudentProfile.ToString(), IdentityService.UserDto.Id, + file.Name, file.ContentType, base64Content); + if(response) stream.Close(); } catch (Exception ex) diff --git a/MiniSpace.Web/src/MiniSpace.Web/Startup.cs b/MiniSpace.Web/src/MiniSpace.Web/Startup.cs index 09227b190..72400cfaf 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Startup.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Startup.cs @@ -23,6 +23,7 @@ using MiniSpace.Web.Areas.Friends; using Microsoft.AspNetCore.Components.Authorization; using Blazored.LocalStorage; +using MiniSpace.Web.Areas.MediaFiles; namespace MiniSpace.Web { @@ -65,6 +66,7 @@ public void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); From 98055efad52b4b6b6f9338dab90a1fb5ba062cd0 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 17:03:09 +0200 Subject: [PATCH 50/62] (#92) add media files service --- .../Program.cs | 12 +++++++++--- .../Dto/FileUploadResponseDto.cs | 12 ++++++++++++ .../Services/IMediaFilesService.cs | 10 ++++++++++ .../Extensions.cs | 1 + .../Services/MediaFilesService.cs} | 19 ++++++++++++------- 5 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileUploadResponseDto.cs create mode 100644 MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IMediaFilesService.cs rename MiniSpace.Services.MediaFiles/src/{MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs => MiniSpace.Services.MediaFiles.Infrastructure/Services/MediaFilesService.cs} (81%) diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs index dc1761162..ea28dcc14 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Api/Program.cs @@ -14,6 +14,7 @@ using MiniSpace.Services.MediaFiles.Application.Commands; using MiniSpace.Services.MediaFiles.Application.Dto; using MiniSpace.Services.MediaFiles.Application.Queries; +using MiniSpace.Services.MediaFiles.Application.Services; using MiniSpace.Services.MediaFiles.Infrastructure; namespace MiniSpace.Services.MediaFiles.Api @@ -30,12 +31,17 @@ public static async Task Main(string[] args) .Build()) .Configure(app => app .UseInfrastructure() + .UseEndpoints(endpoints => endpoints + .Post("media-files", async (cmd, ctx) => + { + var fileId = await ctx.RequestServices.GetService().UploadAsync(cmd); + await ctx.Response.WriteJsonAsync(fileId); + }) + ) .UseDispatcherEndpoints(endpoints => endpoints .Get("", ctx => ctx.Response.WriteAsync(ctx.RequestServices.GetService().Name)) .Get("media-files/{mediaFileId}") - .Get("media-files/{mediaFileId}/original") - .Post("media-files", - afterDispatch: (cmd, ctx) => ctx.Response.Created($"media-files/{cmd.MediaFileId}")) + .Get("media-files/{mediaFileId}/original") .Delete("media-files/{mediaFileId}") )) .UseLogging() diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileUploadResponseDto.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileUploadResponseDto.cs new file mode 100644 index 000000000..257152cb8 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Dto/FileUploadResponseDto.cs @@ -0,0 +1,12 @@ +namespace MiniSpace.Services.MediaFiles.Application.Dto +{ + public class FileUploadResponseDto + { + public Guid FileId { get; set; } + + public FileUploadResponseDto(Guid fileId) + { + FileId = fileId; + } + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IMediaFilesService.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IMediaFilesService.cs new file mode 100644 index 000000000..1a3893fd1 --- /dev/null +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Services/IMediaFilesService.cs @@ -0,0 +1,10 @@ +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Application.Dto; + +namespace MiniSpace.Services.MediaFiles.Application.Services +{ + public interface IMediaFilesService + { + public Task UploadAsync(UploadMediaFile command); + } +} \ No newline at end of file diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs index 80169233c..0cec9be95 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Extensions.cs @@ -53,6 +53,7 @@ public static IConveyBuilder AddInfrastructure(this IConveyBuilder builder) builder.Services.AddSingleton(); builder.Services.AddTransient(); builder.Services.AddTransient(); + builder.Services.AddTransient(); builder.Services.AddTransient(ctx => ctx.GetRequiredService().Create()); builder.Services.TryDecorate(typeof(ICommandHandler<>), typeof(OutboxCommandHandlerDecorator<>)); builder.Services.TryDecorate(typeof(IEventHandler<>), typeof(OutboxEventHandlerDecorator<>)); diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/MediaFilesService.cs similarity index 81% rename from MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs rename to MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/MediaFilesService.cs index 87f5e842b..4d540f282 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Application/Commands/Handlers/UploadMediaFileHandler.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/MediaFilesService.cs @@ -1,4 +1,6 @@ -using Convey.CQRS.Commands; +using MiniSpace.Services.MediaFiles.Application; +using MiniSpace.Services.MediaFiles.Application.Commands; +using MiniSpace.Services.MediaFiles.Application.Dto; using MiniSpace.Services.MediaFiles.Application.Events; using MiniSpace.Services.MediaFiles.Application.Exceptions; using MiniSpace.Services.MediaFiles.Application.Services; @@ -7,9 +9,9 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Webp; -namespace MiniSpace.Services.MediaFiles.Application.Commands.Handlers +namespace MiniSpace.Services.MediaFiles.Infrastructure.Services { - public class UploadMediaFileHandler: ICommandHandler + public class MediaFilesService: IMediaFilesService { private readonly IFileSourceInfoRepository _fileSourceInfoRepository; private readonly IFileValidator _fileValidator; @@ -18,7 +20,7 @@ public class UploadMediaFileHandler: ICommandHandler private readonly IAppContext _appContext; private readonly IMessageBroker _messageBroker; - public UploadMediaFileHandler(IFileSourceInfoRepository fileSourceInfoRepository, IFileValidator fileValidator, + public MediaFilesService(IFileSourceInfoRepository fileSourceInfoRepository, IFileValidator fileValidator, IGridFSService gridFSService, IDateTimeProvider dateTimeProvider, IAppContext appContext, IMessageBroker messageBroker) { @@ -30,7 +32,7 @@ public UploadMediaFileHandler(IFileSourceInfoRepository fileSourceInfoRepository _messageBroker = messageBroker; } - public async Task HandleAsync(UploadMediaFile command, CancellationToken cancellationToken) + public async Task UploadAsync(UploadMediaFile command) { var identity = _appContext.Identity; if(identity.IsAuthenticated && identity.Id != command.UploaderId) @@ -48,9 +50,9 @@ public async Task HandleAsync(UploadMediaFile command, CancellationToken cancell _fileValidator.ValidateFileExtensions(bytes, command.FileContentType); using var inStream = new MemoryStream(bytes); - using var myImage = await Image.LoadAsync(inStream, cancellationToken); + using var myImage = await Image.LoadAsync(inStream); using var outStream = new MemoryStream(); - await myImage.SaveAsync(outStream, new WebpEncoder(), cancellationToken); + await myImage.SaveAsync(outStream, new WebpEncoder()); inStream.Position = 0; outStream.Position = 0; @@ -61,6 +63,9 @@ public async Task HandleAsync(UploadMediaFile command, CancellationToken cancell command.FileContentType, objectId, command.FileName); await _fileSourceInfoRepository.AddAsync(fileSourceInfo); await _messageBroker.PublishAsync(new MediaFileUploaded(command.MediaFileId, command.FileName)); + + return new FileUploadResponseDto(fileSourceInfo.Id); } + } } \ No newline at end of file From f620c8b25a4d183c2a77003a2fee3057788e860f Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 17:24:12 +0200 Subject: [PATCH 51/62] (#92)(#57) update page for showing account and completing registration --- .../Areas/Friends/FriendsService.cs | 2 +- .../Areas/MediaFiles/IMediaFilesService.cs | 4 ++-- .../Areas/MediaFiles/MediaFilesService.cs | 4 ++-- .../DTO/FileUploadResponseDto.cs | 9 ++++++++ .../Pages/Account/CompleteRegistration.razor | 5 ++++- .../Pages/Account/ShowAccount.razor | 21 +++++++++++++++++-- .../MiniSpace.Web/Pages/Friends/Friends.razor | 2 +- .../Pages/Friends/FriendsSearch.razor | 4 ++-- 8 files changed, 40 insertions(+), 11 deletions(-) create mode 100644 MiniSpace.Web/src/MiniSpace.Web/DTO/FileUploadResponseDto.cs diff --git a/MiniSpace.Web/src/MiniSpace.Web/Areas/Friends/FriendsService.cs b/MiniSpace.Web/src/MiniSpace.Web/Areas/Friends/FriendsService.cs index cd3684a96..92fdea873 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Areas/Friends/FriendsService.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Areas/Friends/FriendsService.cs @@ -166,7 +166,7 @@ public async Task> GetSentFriendRequestsAsync() var userDetails = await GetUserDetails(request.InviteeId); request.InviteeName = userDetails.FirstName + " " + userDetails.LastName; request.InviteeEmail = userDetails.Email; - request.InviteeImage = userDetails.ProfileImage; + //request.InviteeImage = userDetails.ProfileImage; } return friendRequests; diff --git a/MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/IMediaFilesService.cs b/MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/IMediaFilesService.cs index bbdc40b85..10de21231 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/IMediaFilesService.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/IMediaFilesService.cs @@ -9,8 +9,8 @@ public interface IMediaFilesService { public Task GetFileAsync(Guid fileId); public Task GetOriginalFileAsync(Guid fileId); - public Task> UploadMediaFileAsync(Guid sourceId, string sourceType, Guid uploaderId, - string fileName, string fileContentType, string base64Content); + public Task> UploadMediaFileAsync(Guid sourceId, string sourceType, + Guid uploaderId, string fileName, string fileContentType, string base64Content); public Task DeleteMediaFileAsync(Guid fileId); } } \ No newline at end of file diff --git a/MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/MediaFilesService.cs b/MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/MediaFilesService.cs index 758d55f64..c34371437 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/MediaFilesService.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Areas/MediaFiles/MediaFilesService.cs @@ -28,11 +28,11 @@ public Task GetOriginalFileAsync(Guid fileId) return _httpClient.GetAsync($"media-files/{fileId}/original"); } - public Task> UploadMediaFileAsync(Guid sourceId, string sourceType, Guid uploaderId, string fileName, + public Task> UploadMediaFileAsync(Guid sourceId, string sourceType, Guid uploaderId, string fileName, string fileContentType, string base64Content) { _httpClient.SetAccessToken(_identityService.JwtDto.AccessToken); - return _httpClient.PostAsync("media-files", new {sourceId, sourceType, uploaderId, + return _httpClient.PostAsync("media-files", new {sourceId, sourceType, uploaderId, fileName, fileContentType, base64Content }); } diff --git a/MiniSpace.Web/src/MiniSpace.Web/DTO/FileUploadResponseDto.cs b/MiniSpace.Web/src/MiniSpace.Web/DTO/FileUploadResponseDto.cs new file mode 100644 index 000000000..cfb4804c5 --- /dev/null +++ b/MiniSpace.Web/src/MiniSpace.Web/DTO/FileUploadResponseDto.cs @@ -0,0 +1,9 @@ +using System; + +namespace MiniSpace.Web.DTO +{ + public class FileUploadResponseDto + { + public Guid FileId { get; set; } + } +} \ No newline at end of file diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/CompleteRegistration.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/CompleteRegistration.razor index f9c3767a6..d6ea78f57 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/CompleteRegistration.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/CompleteRegistration.razor @@ -125,7 +125,10 @@ var response = await MediaFilesService.UploadMediaFileAsync(IdentityService.UserDto.Id, MediaFileContextType.StudentProfile.ToString(), IdentityService.UserDto.Id, file.Name, file.ContentType, base64Content); - if(response) + if (response.Content != null && response.Content.FileId != Guid.Empty) + { + completeRegistrationModel.ProfileImage = response.Content.FileId; + } stream.Close(); } catch (Exception ex) diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/ShowAccount.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/ShowAccount.razor index 9e320d9df..2b5321a9a 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/ShowAccount.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/ShowAccount.razor @@ -3,9 +3,12 @@ @using MiniSpace.Web.Components @using MiniSpace.Web.DTO @using System.IO +@using MiniSpace.Web.Areas.MediaFiles +@using MiniSpace.Web.DTO.Types @using Radzen @inject IIdentityService IdentityService @inject IStudentsService StudentsService +@inject IMediaFilesService MediaFilesService @inject NavigationManager NavigationManager

Your account

@@ -14,7 +17,7 @@ { - @@ -88,6 +91,7 @@ else @code { private StudentDto studentDto = new(); private bool editionDisabled = true; + private string profileImage = string.Empty; protected override async Task OnInitializedAsync() { @@ -95,6 +99,12 @@ else { await StudentsService.UpdateStudentDto(IdentityService.UserDto.Id); studentDto = StudentsService.StudentDto; + StateHasChanged(); + if (studentDto.ProfileImage != Guid.Empty) + { + var imageResponse = await MediaFilesService.GetFileAsync(studentDto.ProfileImage); + profileImage = imageResponse.Base64Content; + } } } @@ -125,7 +135,14 @@ else long maxFileSize = 10 * 1024 * 1024; var stream = file.OpenReadStream(maxFileSize); byte[] bytes = await ReadFully(stream); - studentDto.ProfileImage = Convert.ToBase64String(bytes); + var base64Content = Convert.ToBase64String(bytes); + var response = await MediaFilesService.UploadMediaFileAsync(IdentityService.UserDto.Id, + MediaFileContextType.StudentProfile.ToString(), IdentityService.UserDto.Id, + file.Name, file.ContentType, base64Content); + if (response.Content != null && response.Content.FileId != Guid.Empty) + { + studentDto.ProfileImage = response.Content.FileId; + } stream.Close(); } catch (Exception ex) diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/Friends.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/Friends.razor index 633ea8d04..96d71a868 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/Friends.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/Friends.razor @@ -20,7 +20,7 @@ foreach (var friend in friends) {
- Friend Image + @*Friend Image*@
@friend.StudentDetails.FirstName @friend.StudentDetails.LastName

@friend.StudentDetails.Email

diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/FriendsSearch.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/FriendsSearch.razor index 32213280c..85fc4383a 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/FriendsSearch.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/FriendsSearch.razor @@ -22,7 +22,7 @@ @foreach (var student in students) {
- Student Image + @*Student Image*@
@student.FirstName @student.LastName

Email: @student.Email

@@ -60,7 +60,7 @@
- Profile Image + @*Profile Image*@

@student?.FirstName @student?.LastName

    From c9f3e611537588dcddd41372d90cad2a5bcad76d Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 17:49:47 +0200 Subject: [PATCH 52/62] (#92) add more file extension compatibility --- .../Services/FileValidator.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs index d43a8e20a..590fe9821 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs @@ -9,9 +9,11 @@ public class FileValidator : IFileValidator private readonly Dictionary _mimeTypes = new Dictionary() { + { "FFD8FFDB", "image/jpeg" }, { "FFD8FFE0", "image/jpeg" }, { "FFD8FFE1", "image/jpeg" }, { "FFD8FFE2", "image/jpeg" }, + { "FFD8FFEE", "image/jpeg" }, { "89504E47", "image/png" }, { "47494638", "image/gif" }, { "49492A00", "image/tiff" }, From 49ead2431facff328466404cd42accc5f1409807 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 18:17:49 +0200 Subject: [PATCH 53/62] (#92)(#57) update show account page --- .../Pages/Account/ShowAccount.razor | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/ShowAccount.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/ShowAccount.razor index 2b5321a9a..c474547e9 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/ShowAccount.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Account/ShowAccount.razor @@ -74,6 +74,15 @@ + + @if (isUploading) + { + + + + } + @@ -92,6 +101,8 @@ else private StudentDto studentDto = new(); private bool editionDisabled = true; private string profileImage = string.Empty; + private TaskCompletionSource clientChangeCompletionSource; + private bool isUploading = false; protected override async Task OnInitializedAsync() { @@ -116,6 +127,10 @@ else private async Task HandleUpdateStudent() { + if (clientChangeCompletionSource != null) + { + await clientChangeCompletionSource.Task; + } editionDisabled = true; await StudentsService.UpdateStudentAsync(studentDto.Id, studentDto.ProfileImage, studentDto.Description, studentDto.EmailNotifications); @@ -125,10 +140,13 @@ else async void OnClientChange(UploadChangeEventArgs args) { Console.WriteLine("Client-side upload changed"); + clientChangeCompletionSource = new TaskCompletionSource(); foreach (var file in args.Files) { Console.WriteLine($"File: {file.Name} / {file.Size} bytes"); + isUploading = true; + StateHasChanged(); try { @@ -143,11 +161,19 @@ else { studentDto.ProfileImage = response.Content.FileId; } + stream.Close(); + clientChangeCompletionSource.SetResult(true); } catch (Exception ex) - { + { Console.WriteLine($"Client-side file read error: {ex.Message}"); + clientChangeCompletionSource.SetResult(false); + } + finally + { + isUploading = false; + StateHasChanged(); } } } From 7a7b8591fb652962e9234cf835574e8cf6d0306d Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 18:35:29 +0200 Subject: [PATCH 54/62] (#92)(#57) update friends page --- .../Pages/Friends/FriendsSearch.razor | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/FriendsSearch.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/FriendsSearch.razor index 85fc4383a..0ab2fca16 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/FriendsSearch.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/FriendsSearch.razor @@ -7,7 +7,9 @@ @inject IFriendsService FriendsService @using MiniSpace.Web.DTO @using MiniSpace.Web.Areas.Identity +@using MiniSpace.Web.Areas.MediaFiles @inject IIdentityService IdentityService +@inject IMediaFilesService MediaFilesService @inject Radzen.NotificationService NotificationService @inject IJSRuntime JSRuntime @@ -22,7 +24,10 @@ @foreach (var student in students) {
    - @*Student Image*@ + @if(images.ContainsKey(student.Id)) + { + Student Image + }
    @student.FirstName @student.LastName

    Email: @student.Email

    @@ -60,7 +65,7 @@
    - @*Profile Image*@ + Profile Image

    @student?.FirstName @student?.LastName

      @@ -254,11 +259,26 @@ private int currentPage = 1; private int pageSize = 10; private int totalStudents; + private Dictionary images = new (); protected override async Task OnInitializedAsync() { - sentRequests = await FriendsService.GetSentFriendRequestsAsync(); + sentRequests = await FriendsService.GetSentFriendRequestsAsync(); await LoadStudents(); StateHasChanged(); + + var tasks = new List(); + foreach (var student in students) + { + tasks.Add(FetchImageAsync(student)); + } + + await Task.WhenAll(tasks); + } + + private async Task FetchImageAsync(StudentDto student) + { + var result = await MediaFilesService.GetFileAsync(student.ProfileImage); + images.Add(student.Id, result.Base64Content); } @* private async Task LoadStudents() { @@ -321,13 +341,13 @@ var currentUserId = IdentityService.GetCurrentUserId(); await FriendsService.InviteStudent(currentUserId, studentId); - var student = students.FirstOrDefault(s => s.Id == studentId); + var student = students.FirstOrDefault(s => s.Id == studentId); if (student != null) { student.InvitationSent = true; student.IsInvitationPending = true; } - sentRequests = await FriendsService.GetSentFriendRequestsAsync(); + sentRequests = await FriendsService.GetSentFriendRequestsAsync(); NotificationService.Notify(Radzen.NotificationSeverity.Success, "Invitation Sent", "The invitation has been successfully sent.", 10000); await JSRuntime.InvokeVoidAsync("playNotificationSound"); StateHasChanged(); From db0902921c3547886ca1aebe9f41afd4da28e986 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 18:49:43 +0200 Subject: [PATCH 55/62] (#57) fix issue when searching without specifying anything --- .../src/MiniSpace.Web/Pages/Friends/FriendsSearch.razor | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/FriendsSearch.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/FriendsSearch.razor index 0ab2fca16..8229792f8 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/FriendsSearch.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Friends/FriendsSearch.razor @@ -26,7 +26,7 @@
      @if(images.ContainsKey(student.Id)) { - Student Image + Student Image }
      @student.FirstName @student.LastName
      @@ -326,6 +326,10 @@ } private void SearchFriends() { + if (string.IsNullOrWhiteSpace(searchTerm)) + { + return; + } students = students.Where(s => s.FirstName.Contains(searchTerm, StringComparison.OrdinalIgnoreCase) || s.LastName.Contains(searchTerm, StringComparison.OrdinalIgnoreCase)).ToList(); } From 396a6c11a8dce1255c4ab59ba1b2da3719f5a586 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sat, 18 May 2024 19:18:15 +0200 Subject: [PATCH 56/62] (#92) add more file extension compatibility --- .../Services/FileValidator.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs index 590fe9821..30cf2b34d 100644 --- a/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs +++ b/MiniSpace.Services.MediaFiles/src/MiniSpace.Services.MediaFiles.Infrastructure/Services/FileValidator.cs @@ -18,7 +18,8 @@ public class FileValidator : IFileValidator { "47494638", "image/gif" }, { "49492A00", "image/tiff" }, { "4D4D002A", "image/tiff" }, - { "52494646", "image/webp" } + { "52494646", "image/webp" }, + { "57454250", "image/webp" } }; public void ValidateFileSize(int size) From eff136a5e9db7bb895085eecff66e50e593201e7 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 19 May 2024 01:48:31 +0200 Subject: [PATCH 57/62] (#57) update posts page --- .../Areas/Posts/IPostsService.cs | 2 +- .../MiniSpace.Web/Areas/Posts/PostsService.cs | 5 +- .../src/MiniSpace.Web/MiniSpace.Web.csproj | 2 +- .../Models/Posts/CreatePostModel.cs | 4 +- .../Pages/Posts/PostCreate.razor | 102 +++++++++++++++++- 5 files changed, 107 insertions(+), 8 deletions(-) diff --git a/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/IPostsService.cs b/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/IPostsService.cs index 81ce84a83..3a6bc32ff 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/IPostsService.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/IPostsService.cs @@ -11,7 +11,7 @@ public interface IPostsService Task GetPostAsync(Guid postId); Task ChangePostStateAsync(Guid postId, string state, DateTime publishDate); Task> CreatePostAsync(Guid postId, Guid eventId, Guid organizerId, string textContext, - string mediaContext, string state, DateTime? publishDate); + IEnumerable mediaFiles, string state, DateTime? publishDate); Task DeletePostAsync(Guid postId); Task> GetPostsAsync(Guid eventId); Task> UpdatePostAsync(Guid postId, string textContent, string mediaContent); diff --git a/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/PostsService.cs b/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/PostsService.cs index 541ad86ba..937e9e23c 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/PostsService.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/PostsService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; using MiniSpace.Web.Areas.Identity; @@ -30,11 +31,11 @@ public Task ChangePostStateAsync(Guid postId, string state, DateTime publishDate } public Task> CreatePostAsync(Guid postId, Guid eventId, Guid organizerId, string textContent, - string mediaContext, string state, DateTime? publishDate) + IEnumerable mediaFiles, string state, DateTime? publishDate) { _httpClient.SetAccessToken(_identityService.JwtDto.AccessToken); return _httpClient.PostAsync("posts", new {postId, eventId, organizerId, textContent, - mediaContext, state, publishDate}); + mediaFiles, state, publishDate}); } public Task DeletePostAsync(Guid postId) diff --git a/MiniSpace.Web/src/MiniSpace.Web/MiniSpace.Web.csproj b/MiniSpace.Web/src/MiniSpace.Web/MiniSpace.Web.csproj index 1df37b7db..de79ee777 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/MiniSpace.Web.csproj +++ b/MiniSpace.Web/src/MiniSpace.Web/MiniSpace.Web.csproj @@ -13,7 +13,7 @@ - + diff --git a/MiniSpace.Web/src/MiniSpace.Web/Models/Posts/CreatePostModel.cs b/MiniSpace.Web/src/MiniSpace.Web/Models/Posts/CreatePostModel.cs index d2316ace8..eb3da90e3 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Models/Posts/CreatePostModel.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Models/Posts/CreatePostModel.cs @@ -1,4 +1,6 @@ using System; +using System.Collections; +using System.Collections.Generic; namespace MiniSpace.Web.Models.Posts { @@ -8,7 +10,7 @@ public class CreatePostModel public Guid EventId { get; set; } public Guid OrganizerId { get; set; } public string TextContent { get; set; } - public string MediaContent { get; set; } + public IEnumerable MediaFiles { get; set; } public string State { get; set; } public DateTime PublishDate { get; set; } } diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor index c7901269f..e1b29da83 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor @@ -1,12 +1,16 @@ @page "/events/{EventId}/posts/create" @using MiniSpace.Web.Areas.Identity @using MiniSpace.Web.Areas.Http +@using MiniSpace.Web.Areas.MediaFiles @using MiniSpace.Web.Areas.Posts @using MiniSpace.Web.DTO +@using MiniSpace.Web.DTO.Types @using MiniSpace.Web.Models.Posts @using Radzen +@using System.IO @inject IIdentityService IdentityService @inject IPostsService PostsService +@inject IMediaFilesService MediaFilesService @inject IErrorMapperService ErrorMapperService @inject NavigationManager NavigationManager @@ -50,6 +54,25 @@ } + + + + + @if (isUploading) + { + + + + } + + + Choose files to upload (max 3) + + + + @@ -72,11 +95,14 @@ private CreatePostModel createPostModel = new() { TextContent = "Lorem ipsum!", - MediaContent = "" }; private bool showError = false; private string errorMessage = string.Empty; private int publishInfo = 1; + private TaskCompletionSource clientChangeCompletionSource; + private bool isUploading = false; + private Dictionary images = new (); + RadzenUpload uploadDD; private static bool ValidateDate(DateTime dateTime) { @@ -88,7 +114,7 @@ if (IdentityService.IsAuthenticated && IdentityService.GetCurrentUserRole() == "organizer") { organizerId = IdentityService.GetCurrentUserId(); - + createPostModel.PostId = new Guid(); createPostModel.EventId = new Guid(EventId); createPostModel.OrganizerId = organizerId; } @@ -97,7 +123,7 @@ private async Task HandleCreatePost() { var response = await PostsService.CreatePostAsync(Guid.Empty, createPostModel.EventId, - createPostModel.OrganizerId, createPostModel.TextContent, createPostModel.MediaContent, + createPostModel.OrganizerId, createPostModel.TextContent, images.Select(i => i.Value), publishInfo == 2 ? "ToBePublished" : "Published", publishInfo == 2 ? createPostModel.PublishDate.ToUniversalTime() : null); @@ -111,4 +137,74 @@ NavigationManager.NavigateTo($"/events/{EventId}"); } } + + async void OnClientChange(UploadChangeEventArgs args) + { + Console.WriteLine("Client-side upload changed"); + clientChangeCompletionSource = new TaskCompletionSource(); + var uploadedImages = new Dictionary(); + isUploading = true; + + foreach (var file in args.Files) + { + StateHasChanged(); + if (images.TryGetValue(file.Name, out var imageId)) + { + uploadedImages.Add(file.Name, imageId); + continue; + } + + try + { + long maxFileSize = 10 * 1024 * 1024; + var stream = file.OpenReadStream(maxFileSize); + byte[] bytes = await ReadFully(stream); + var base64Content = Convert.ToBase64String(bytes); + var response = await MediaFilesService.UploadMediaFileAsync(createPostModel.PostId, + MediaFileContextType.Post.ToString(), IdentityService.UserDto.Id, + file.Name, file.ContentType, base64Content); + if (response.Content != null && response.Content.FileId != Guid.Empty) + { + uploadedImages.Add(file.Name, response.Content.FileId); + } + stream.Close(); + } + catch (Exception ex) + { + Console.WriteLine($"Client-side file read error: {ex.Message}"); + } + finally + { + StateHasChanged(); + } + } + images = uploadedImages; + isUploading = false; + clientChangeCompletionSource.SetResult(true); + } + + private static async Task ReadFully(Stream input) + { + byte[] buffer = new byte[16*1024]; + using MemoryStream ms = new MemoryStream(); + int read; + while ((read = await input.ReadAsync(buffer, 0, buffer.Length)) > 0) + { + ms.Write(buffer, 0, read); + } + return ms.ToArray(); + } + + void OnProgress(UploadProgressArgs args, string name) + { + Console.WriteLine($"{args.Progress}% '{name}' / {args.Loaded} of {args.Total} bytes."); + + if (args.Progress == 100) + { + foreach (var file in args.Files) + { + Console.WriteLine($"Uploaded: {file.Name} / {file.Size} bytes"); + } + } + } } From 7307524ee779525bf4548cd3d2861945c833da66 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 19 May 2024 01:53:43 +0200 Subject: [PATCH 58/62] (#57) fix issue with progress bar --- MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor index e1b29da83..eabec7c7f 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor @@ -175,11 +175,12 @@ } finally { - StateHasChanged(); + } } - images = uploadedImages; isUploading = false; + StateHasChanged(); + images = uploadedImages; clientChangeCompletionSource.SetResult(true); } From b557b75c29b695dac1a226f4cd0b38dc67a996cb Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 19 May 2024 11:43:26 +0200 Subject: [PATCH 59/62] (#57) fix issue with postId --- .../src/MiniSpace.Web/Pages/Posts/PostCreate.razor | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor index eabec7c7f..f66dc6cdb 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor @@ -114,7 +114,7 @@ if (IdentityService.IsAuthenticated && IdentityService.GetCurrentUserRole() == "organizer") { organizerId = IdentityService.GetCurrentUserId(); - createPostModel.PostId = new Guid(); + createPostModel.PostId = Guid.NewGuid(); createPostModel.EventId = new Guid(EventId); createPostModel.OrganizerId = organizerId; } @@ -122,7 +122,11 @@ private async Task HandleCreatePost() { - var response = await PostsService.CreatePostAsync(Guid.Empty, createPostModel.EventId, + if (clientChangeCompletionSource != null) + { + await clientChangeCompletionSource.Task; + } + var response = await PostsService.CreatePostAsync(createPostModel.PostId, createPostModel.EventId, createPostModel.OrganizerId, createPostModel.TextContent, images.Select(i => i.Value), publishInfo == 2 ? "ToBePublished" : "Published", publishInfo == 2 ? createPostModel.PublishDate.ToUniversalTime() : null); From 0e622da423aca1da2443c2ab791806af36cd52a6 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 19 May 2024 12:19:00 +0200 Subject: [PATCH 60/62] (#57) update event and post models --- .../Areas/Events/EventsService.cs | 14 +-- .../Areas/Events/IEventsService.cs | 10 +-- .../Areas/Posts/IPostsService.cs | 2 +- .../MiniSpace.Web/Areas/Posts/PostsService.cs | 4 +- .../src/MiniSpace.Web/DTO/EventDto.cs | 1 + .../src/MiniSpace.Web/DTO/PostDto.cs | 3 +- .../Models/Events/CreateEventModel.cs | 2 + .../Models/Events/UpdateEventModel.cs | 2 + .../Models/Posts/UpdatePostModel.cs | 3 +- .../Pages/Events/EventCreate.razor | 89 ++++++++++++++++++- .../Pages/Events/EventUpdate.razor | 3 +- .../Pages/Posts/PostCreate.razor | 16 +--- .../Pages/Posts/PostUpdate.razor | 4 +- 13 files changed, 116 insertions(+), 37 deletions(-) diff --git a/MiniSpace.Web/src/MiniSpace.Web/Areas/Events/EventsService.cs b/MiniSpace.Web/src/MiniSpace.Web/Areas/Events/EventsService.cs index adfd03736..ea252e425 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Areas/Events/EventsService.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Areas/Events/EventsService.cs @@ -33,25 +33,25 @@ public Task>> GetStudentEventsAsync(Guid $"events/student/{studentId}?engagementType={engagementType}&page={page}&numberOfResults={numberOfResults}"); } - public Task> AddEventAsync(Guid eventId, string name, Guid organizerId, Guid organizationId, + public Task> CreateEventAsync(Guid eventId, string name, Guid organizerId, Guid organizationId, Guid rootOrganizationId, string startDate, string endDate, string buildingName, string street, - string buildingNumber, string apartmentNumber, string city, string zipCode, string description, - int capacity, decimal fee, string category, string publishDate) + string buildingNumber, string apartmentNumber, string city, string zipCode, IEnumerable mediaFiles, + string description, int capacity, decimal fee, string category, string publishDate) { _httpClient.SetAccessToken(_identityService.JwtDto.AccessToken); return _httpClient.PostAsync("events", new {eventId, name, organizerId, organizationId, rootOrganizationId, startDate, endDate, buildingName, street, buildingNumber, apartmentNumber, city, - zipCode, description, capacity, fee, category, publishDate}); + zipCode, mediaFiles, description, capacity, fee, category, publishDate}); } public Task> UpdateEventAsync(Guid eventId, string name, Guid organizerId, string startDate, string endDate, string buildingName, string street, string buildingNumber, string apartmentNumber, string city, string zipCode, - string description, int capacity, decimal fee, string category, string publishDate) + IEnumerable mediaFiles, string description, int capacity, decimal fee, string category, string publishDate) { _httpClient.SetAccessToken(_identityService.JwtDto.AccessToken); return _httpClient.PutAsync($"events/{eventId}", new {eventId, name, organizerId, - startDate, endDate, buildingName, street, buildingNumber, apartmentNumber, city, zipCode, description, - capacity, fee, category, publishDate}); + startDate, endDate, buildingName, street, buildingNumber, apartmentNumber, city, zipCode, mediaFiles, + description, capacity, fee, category, publishDate}); } public Task DeleteEventAsync(Guid eventId) diff --git a/MiniSpace.Web/src/MiniSpace.Web/Areas/Events/IEventsService.cs b/MiniSpace.Web/src/MiniSpace.Web/Areas/Events/IEventsService.cs index 000bfb59f..7b55fcc18 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Areas/Events/IEventsService.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Areas/Events/IEventsService.cs @@ -13,14 +13,14 @@ public interface IEventsService Task GetEventAsync(Guid eventId); Task>> GetStudentEventsAsync(Guid studentId, string engagementType, int page, int numberOfResults); - Task> AddEventAsync(Guid eventId, string name, Guid organizerId, Guid organizationId, + Task> CreateEventAsync(Guid eventId, string name, Guid organizerId, Guid organizationId, Guid rootOrganizationId, string startDate, string endDate, string buildingName, string street, - string buildingNumber, string apartmentNumber, string city, string zipCode, string description, - int capacity, decimal fee, string category, string publishDate); + string buildingNumber, string apartmentNumber, string city, string zipCode, IEnumerable mediaFiles, + string description, int capacity, decimal fee, string category, string publishDate); Task> UpdateEventAsync(Guid eventId, string name, Guid organizerId, string startDate, string endDate, string buildingName, string street, string buildingNumber, - string apartmentNumber, string city, string zipCode, string description, int capacity, decimal fee, - string category, string publishDate); + string apartmentNumber, string city, string zipCode, IEnumerable mediaFiles, string description, + int capacity, decimal fee, string category, string publishDate); Task DeleteEventAsync(Guid eventId); Task SignUpToEventAsync(Guid eventId, Guid studentId); Task CancelSignUpToEventAsync(Guid eventId, Guid studentId); diff --git a/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/IPostsService.cs b/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/IPostsService.cs index 3a6bc32ff..d89577bc7 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/IPostsService.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/IPostsService.cs @@ -14,6 +14,6 @@ Task> CreatePostAsync(Guid postId, Guid eventId, Guid organ IEnumerable mediaFiles, string state, DateTime? publishDate); Task DeletePostAsync(Guid postId); Task> GetPostsAsync(Guid eventId); - Task> UpdatePostAsync(Guid postId, string textContent, string mediaContent); + Task> UpdatePostAsync(Guid postId, string textContent, IEnumerable mediaFiles); } } \ No newline at end of file diff --git a/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/PostsService.cs b/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/PostsService.cs index 937e9e23c..1b575c05d 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/PostsService.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Areas/Posts/PostsService.cs @@ -49,10 +49,10 @@ public Task> GetPostsAsync(Guid eventId) return _httpClient.GetAsync>($"posts?eventId={eventId}"); } - public Task> UpdatePostAsync(Guid postId, string textContent, string mediaContent) + public Task> UpdatePostAsync(Guid postId, string textContent, IEnumerable mediaFiles) { _httpClient.SetAccessToken(_identityService.JwtDto.AccessToken); - return _httpClient.PutAsync($"posts/{postId}", new {postId, textContent, mediaContent}); + return _httpClient.PutAsync($"posts/{postId}", new {postId, textContent, mediaFiles}); } } } \ No newline at end of file diff --git a/MiniSpace.Web/src/MiniSpace.Web/DTO/EventDto.cs b/MiniSpace.Web/src/MiniSpace.Web/DTO/EventDto.cs index 4e4f40d1f..de41f57dd 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/DTO/EventDto.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/DTO/EventDto.cs @@ -12,6 +12,7 @@ public class EventDto public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } public AddressDto Location { get; set; } + public IEnumerable MediaFiles { get; set; } public int InterestedStudents { get; set; } public int SignedUpStudents { get; set; } public int Capacity { get; set; } diff --git a/MiniSpace.Web/src/MiniSpace.Web/DTO/PostDto.cs b/MiniSpace.Web/src/MiniSpace.Web/DTO/PostDto.cs index 966461718..47961054e 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/DTO/PostDto.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/DTO/PostDto.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace MiniSpace.Web.DTO { @@ -8,7 +9,7 @@ public class PostDto public Guid EventId { get; set; } public Guid OrganizerId { get; set; } public string TextContent { get; set; } - public string MediaContent { get; set; } + public IEnumerable MediaFiles { get; set; } public string State { get; set; } public DateTime? PublishDate { get; set; } public DateTime CreatedAt { get; set; } diff --git a/MiniSpace.Web/src/MiniSpace.Web/Models/Events/CreateEventModel.cs b/MiniSpace.Web/src/MiniSpace.Web/Models/Events/CreateEventModel.cs index cf6129ab6..f37f70062 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Models/Events/CreateEventModel.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Models/Events/CreateEventModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using MiniSpace.Web.DTO; namespace MiniSpace.Web.Models.Events @@ -17,6 +18,7 @@ public class CreateEventModel public string ApartmentNumber { get; set; } public string City { get; set; } public string ZipCode { get; set; } + public IEnumerable MediaFiles { get; } public string Description { get; set; } public int Capacity { get; set; } public decimal Fee { get; set; } diff --git a/MiniSpace.Web/src/MiniSpace.Web/Models/Events/UpdateEventModel.cs b/MiniSpace.Web/src/MiniSpace.Web/Models/Events/UpdateEventModel.cs index f25a8a737..fcc96338a 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Models/Events/UpdateEventModel.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Models/Events/UpdateEventModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace MiniSpace.Web.Models.Events { @@ -15,6 +16,7 @@ public class UpdateEventModel public string ApartmentNumber { get; set; } public string City { get; set; } public string ZipCode { get; set; } + public IEnumerable MediaFiles { get; set; } public string Description { get; set; } public int Capacity { get; set; } public decimal Fee { get; set; } diff --git a/MiniSpace.Web/src/MiniSpace.Web/Models/Posts/UpdatePostModel.cs b/MiniSpace.Web/src/MiniSpace.Web/Models/Posts/UpdatePostModel.cs index 679923924..4762b1b49 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Models/Posts/UpdatePostModel.cs +++ b/MiniSpace.Web/src/MiniSpace.Web/Models/Posts/UpdatePostModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace MiniSpace.Web.Models.Posts { @@ -6,6 +7,6 @@ public class UpdatePostModel { public Guid PostId { get; set; } public string TextContent { get; set; } - public string MediaContent { get; set; } + public IEnumerable MediaFiles { get; set; } } } diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Events/EventCreate.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Events/EventCreate.razor index bb1dec9ad..01c9b5105 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Events/EventCreate.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Events/EventCreate.razor @@ -2,13 +2,17 @@ @using MiniSpace.Web.Areas.Identity @using MiniSpace.Web.Areas.Events @using MiniSpace.Web.Areas.Http +@using MiniSpace.Web.Areas.MediaFiles @using MiniSpace.Web.Areas.Organizations @using MiniSpace.Web.DTO +@using MiniSpace.Web.DTO.Types @using MiniSpace.Web.Models.Events @using Radzen +@using System.IO @inject IIdentityService IdentityService @inject IEventsService EventsService @inject IOrganizationsService OrganizationsService +@inject IMediaFilesService MediaFilesService @inject IErrorMapperService ErrorMapperService @inject NavigationManager NavigationManager @@ -127,6 +131,25 @@ } + + + + + @if (isUploading) + { + + + + } + + + Choose files to upload (max 5) + + + + @@ -159,6 +182,9 @@ private Guid organizerId; private bool pageInitialized = false; private bool organizationsFound = false; + private TaskCompletionSource clientChangeCompletionSource; + private bool isUploading = false; + private Dictionary images = new (); private CreateEventModel _createEventModel = new() { @@ -211,6 +237,7 @@ if (organizations.Any()) { organizationsFound = true; + _createEventModel.EventId = Guid.NewGuid(); _createEventModel.OrganizerId = organizerId; _createEventModel.Organization = organizations.First(); } @@ -221,12 +248,12 @@ private async Task HandleCreateEvent() { - var response = await EventsService.AddEventAsync(Guid.Empty, _createEventModel.Name, + var response = await EventsService.CreateEventAsync(_createEventModel.EventId, _createEventModel.Name, _createEventModel.OrganizerId, _createEventModel.Organization.Id, _createEventModel.Organization.RootId, _createEventModel.StartDate.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ"), _createEventModel.EndDate.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ"), _createEventModel.BuildingName, _createEventModel.Street, _createEventModel.BuildingNumber, - _createEventModel.ApartmentNumber, _createEventModel.City, _createEventModel.ZipCode, + _createEventModel.ApartmentNumber, _createEventModel.City, _createEventModel.ZipCode, images.Select(o => o.Value), _createEventModel.Description, _createEventModel.Capacity, _createEventModel.Fee, _createEventModel.Category, publishInfo == 2 ? _createEventModel.PublishDate.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ") : string.Empty); @@ -240,4 +267,62 @@ NavigationManager.NavigateTo("/events/organize"); } } + + async void OnClientChange(UploadChangeEventArgs args) + { + Console.WriteLine("Client-side upload changed"); + clientChangeCompletionSource = new TaskCompletionSource(); + var uploadedImages = new Dictionary(); + isUploading = true; + + foreach (var file in args.Files) + { + StateHasChanged(); + if (images.TryGetValue(file.Name, out var imageId)) + { + uploadedImages.Add(file.Name, imageId); + continue; + } + + try + { + long maxFileSize = 10 * 1024 * 1024; + var stream = file.OpenReadStream(maxFileSize); + byte[] bytes = await ReadFully(stream); + var base64Content = Convert.ToBase64String(bytes); + var response = await MediaFilesService.UploadMediaFileAsync(_createEventModel.EventId, + MediaFileContextType.Event.ToString(), IdentityService.UserDto.Id, + file.Name, file.ContentType, base64Content); + if (response.Content != null && response.Content.FileId != Guid.Empty) + { + uploadedImages.Add(file.Name, response.Content.FileId); + } + stream.Close(); + } + catch (Exception ex) + { + Console.WriteLine($"Client-side file read error: {ex.Message}"); + } + finally + { + + } + } + isUploading = false; + StateHasChanged(); + images = uploadedImages; + clientChangeCompletionSource.SetResult(true); + } + + private static async Task ReadFully(Stream input) + { + byte[] buffer = new byte[16*1024]; + using MemoryStream ms = new MemoryStream(); + int read; + while ((read = await input.ReadAsync(buffer, 0, buffer.Length)) > 0) + { + ms.Write(buffer, 0, read); + } + return ms.ToArray(); + } } diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Events/EventUpdate.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Events/EventUpdate.razor index cf3d23504..5d97365d9 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Events/EventUpdate.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Events/EventUpdate.razor @@ -195,6 +195,7 @@ updateEventModel.ApartmentNumber = eventDto.Location.ApartmentNumber; updateEventModel.City = eventDto.Location.City; updateEventModel.ZipCode = eventDto.Location.ZipCode; + updateEventModel.MediaFiles = eventDto.MediaFiles; updateEventModel.Description = eventDto.Description; updateEventModel.Capacity = eventDto.Capacity; updateEventModel.Fee = eventDto.Fee; @@ -211,7 +212,7 @@ updateEventModel.StartDate.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ"), updateEventModel.EndDate.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ"), updateEventModel.BuildingName, updateEventModel.Street, updateEventModel.BuildingNumber, - updateEventModel.ApartmentNumber, updateEventModel.City, updateEventModel.ZipCode, + updateEventModel.ApartmentNumber, updateEventModel.City, updateEventModel.ZipCode, updateEventModel.MediaFiles, updateEventModel.Description, updateEventModel.Capacity, updateEventModel.Fee, updateEventModel.Category, publishInfo == 2 ? updateEventModel.PublishDate.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ") : string.Empty); diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor index f66dc6cdb..059cc6c6b 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostCreate.razor @@ -54,7 +54,7 @@ } - + @@ -102,7 +102,6 @@ private TaskCompletionSource clientChangeCompletionSource; private bool isUploading = false; private Dictionary images = new (); - RadzenUpload uploadDD; private static bool ValidateDate(DateTime dateTime) { @@ -199,17 +198,4 @@ } return ms.ToArray(); } - - void OnProgress(UploadProgressArgs args, string name) - { - Console.WriteLine($"{args.Progress}% '{name}' / {args.Loaded} of {args.Total} bytes."); - - if (args.Progress == 100) - { - foreach (var file in args.Files) - { - Console.WriteLine($"Uploaded: {file.Name} / {file.Size} bytes"); - } - } - } } diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostUpdate.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostUpdate.razor index e0fac9bec..0d92ed9dd 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostUpdate.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Posts/PostUpdate.razor @@ -82,7 +82,7 @@ postDto = await PostsService.GetPostAsync(new Guid(PostId)); updatePostModel.PostId = postDto.Id; updatePostModel.TextContent = postDto.TextContent; - updatePostModel.MediaContent = postDto.MediaContent; + updatePostModel.MediaFiles = postDto.MediaFiles; } pageInitialized = true; @@ -91,7 +91,7 @@ private async Task HandleUpdatePost() { var response = await PostsService.UpdatePostAsync(updatePostModel.PostId, - updatePostModel.TextContent, updatePostModel.MediaContent); + updatePostModel.TextContent, updatePostModel.MediaFiles); if (response.ErrorMessage != null) { From 032c829000d3f3a3f02ad5da46781eb5955c0ad3 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 19 May 2024 12:44:39 +0200 Subject: [PATCH 61/62] (#57) fix create event page view --- .../Pages/Events/EventCreate.razor | 63 ++++++++++--------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/MiniSpace.Web/src/MiniSpace.Web/Pages/Events/EventCreate.razor b/MiniSpace.Web/src/MiniSpace.Web/Pages/Events/EventCreate.razor index 01c9b5105..be8e71706 100644 --- a/MiniSpace.Web/src/MiniSpace.Web/Pages/Events/EventCreate.razor +++ b/MiniSpace.Web/src/MiniSpace.Web/Pages/Events/EventCreate.razor @@ -83,16 +83,16 @@ - - - - - - - + + + + + + + - - - - - @if (isUploading) - { - - - - } - - - Choose files to upload (max 5) - - - - @@ -167,7 +148,29 @@ - + + + + + + + @if (isUploading) + { + + + + } + + + Choose files to upload (max 5) + + + + + + From 4698c51d4f19e502d8edf5cdcd33f837189ff310 Mon Sep 17 00:00:00 2001 From: eggwhat Date: Sun, 19 May 2024 13:25:34 +0200 Subject: [PATCH 62/62] (#133) integrate mediafiles image with dockerhub --- MiniSpace/compose/services.yml | 9 +++++++++ MiniSpace/scripts/dockerize-all.sh | 1 + 2 files changed, 10 insertions(+) diff --git a/MiniSpace/compose/services.yml b/MiniSpace/compose/services.yml index 86000600e..551033ebe 100644 --- a/MiniSpace/compose/services.yml +++ b/MiniSpace/compose/services.yml @@ -75,6 +75,15 @@ services: networks: - minispace + mediafiles-service: + image: adrianvsaint/minispace.services.mediafiles:latest + container_name: mediafiles-service + restart: unless-stopped + ports: + - 5014:80 + networks: + - minispace + organizations-service: image: adrianvsaint/minispace.services.organizations:latest container_name: organizations-service diff --git a/MiniSpace/scripts/dockerize-all.sh b/MiniSpace/scripts/dockerize-all.sh index f2889fe36..1a5fca3e2 100755 --- a/MiniSpace/scripts/dockerize-all.sh +++ b/MiniSpace/scripts/dockerize-all.sh @@ -10,6 +10,7 @@ directories=( "MiniSpace.Services.Reactions" "MiniSpace.Services.Posts" "MiniSpace.Services.Comments" + "MiniSpace.Services.MediaFiles" "MiniSpace.Services.Organizations" )