diff --git a/.github/workflows/update-iteration.yml b/.github/workflows/update-iteration.yml index 2d38d0afb..d6b926b7d 100644 --- a/.github/workflows/update-iteration.yml +++ b/.github/workflows/update-iteration.yml @@ -2,8 +2,8 @@ name: Move Tasks To New Iteration on: schedule: - # Runs "at 05:00 GMT+2, only on Thursday" - - cron: '0 3 * * 4' + # Runs "at 05:00 GMT+2, everyday" + - cron: '0 3 * * *' jobs: move-to-next-iteration: diff --git a/Dockerfile.dbupdate b/Dockerfile.dbupdate new file mode 100644 index 000000000..8b501d6e3 --- /dev/null +++ b/Dockerfile.dbupdate @@ -0,0 +1,26 @@ +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +WORKDIR /app + +# copy dependencies +COPY ./Streetcode/DbUpdate/DbUpdate.csproj ./DbUpdate/ +COPY ./Streetcode/DbUpdate/*.cs ./DbUpdate/ +COPY ./Streetcode/DbUpdate/appsettings.Local.json ./DbUpdate/ +COPY ./Streetcode/DbUpdate/appsettings.IntegrationTests.json ./DbUpdate/ +COPY ./Streetcode ./Streetcode/ +COPY ./Streetcode/Streetcode.DAL/Persistence/ScriptsMigration ./Streetcode.DAL/Persistence/ScriptsMigration/ + +RUN dotnet restore ./DbUpdate/DbUpdate.csproj + + +# build +RUN dotnet build ./DbUpdate/DbUpdate.csproj -c Release -o /app/build + +# publishishing application +FROM build AS publish +RUN dotnet publish ./DbUpdate/DbUpdate.csproj -c Release -o /app/publish + +FROM mcr.microsoft.com/dotnet/runtime:7.0 AS runtime +WORKDIR /app +COPY --from=publish /app/publish . + +CMD ["dotnet", "DbUpdate.dll"] \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile index d54602026..f98fba86b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,6 +1,8 @@ def CODE_VERSION = '' def IS_IMAGE_BUILDED = false +def IS_DBUPDATE_IMAGE_BUILDED = false def IS_IMAGE_PUSH = false +def IS_DBUPDATE_IMAGE_PUSH = false def isSuccess def preDeployFrontStage def preDeployBackStage @@ -45,9 +47,14 @@ pipeline { stage('Setup dependencies') { steps { script { - sh 'dotnet tool update --global dotnet-coverage' + sh 'rm -rf ~/.dotnet/tools/dotnet-coverage || true' + sh 'rm -rf ~/.dotnet/tools/dotnet-sonarscanner || true' + sh 'rm -rf ~/.dotnet/tools/GitVersion.Tool || true' + + sh 'dotnet tool update --global dotnet-coverage --version 17.13.1' sh 'dotnet tool update --global dotnet-sonarscanner' sh 'dotnet tool update --global GitVersion.Tool --version 5.12.0' + sh 'docker image prune --force --all --filter "until=72h"' sh 'docker system prune --force --all --filter "until=72h"' @@ -84,10 +91,10 @@ pipeline { steps { parallel( Unit_test: { - sh 'dotnet test ./Streetcode/Streetcode.XUnitTest/Streetcode.XUnitTest.csproj --configuration Release' + sh 'dotnet test ./Streetcode/Streetcode.XUnitTest/Streetcode.XUnitTest.csproj --configuration Release --no-build' }, Integration_test: { - sh 'dotnet test ./Streetcode/Streetcode.XIntegrationTest/Streetcode.XIntegrationTest.csproj --configuration Release' + sh 'dotnet test ./Streetcode/Streetcode.XIntegrationTest/Streetcode.XIntegrationTest.csproj --configuration Release --no-build' } ) } @@ -116,8 +123,8 @@ pipeline { /d:sonar.pullrequest.branch=$PR_BRANCH \ /d:sonar.pullrequest.base=$PR_BASE - dotnet build ./Streetcode/Streetcode.sln --configuration Release - dotnet-coverage collect "dotnet test ./Streetcode/Streetcode.sln --configuration Release" -f xml -o "coverage.xml" + dotnet build ./Streetcode/Streetcode.sln --configuration Release -p:WarningLevel=0 + dotnet-coverage collect "dotnet test ./Streetcode/Streetcode.sln --configuration Release --no-build" -f xml -o "coverage.xml" dotnet sonarscanner end /d:sonar.token=$SONAR ''' } else { @@ -129,8 +136,8 @@ pipeline { /d:sonar.host.url="https://sonarcloud.io" \ /d:sonar.cs.vscoveragexml.reportsPaths="**/coverage.xml" \ - dotnet build ./Streetcode/Streetcode.sln --configuration Release - dotnet-coverage collect "dotnet test ./Streetcode/Streetcode.sln --configuration Release" -f xml -o "coverage.xml" + dotnet build ./Streetcode/Streetcode.sln --configuration Release -p:WarningLevel=0 + dotnet-coverage collect "dotnet test ./Streetcode/Streetcode.sln --configuration Release --no-build" -f xml -o "coverage.xml" dotnet sonarscanner end /d:sonar.token=$SONAR ''' } @@ -138,7 +145,7 @@ pipeline { } } } - stage('Build image') { + stage('Build images') { when { branch pattern: "release/[0-9].[0-9].[0-9]", comparator: "REGEXP" @@ -146,38 +153,45 @@ pipeline { steps { script { withCredentials([usernamePassword(credentialsId: 'docker-login-streetcode', passwordVariable: 'password', usernameVariable: 'username')]){ - sh "docker build -t ${username}/streetcode:latest ." + // Build the backend image + sh "docker build -f Dockerfile -t ${username}/streetcode:${env.CODE_VERSION} ." IS_IMAGE_BUILDED = true + + // Build the dbupdate image + sh "docker build -f Dockerfile.dbupdate -t ${username}/dbupdate:${env.CODE_VERSION} ." + IS_DBUPDATE_IMAGE_BUILDED = true } } } } - stage('Push image') { + stage('Push images') { when { - expression { IS_IMAGE_BUILDED == true } + expression { IS_IMAGE_BUILDED == true && IS_DBUPDATE_IMAGE_BUILDED == true } } steps { script { withCredentials([usernamePassword(credentialsId: 'docker-login-streetcode', passwordVariable: 'password', usernameVariable: 'username')]){ sh 'echo "${password}" | docker login -u "${username}" --password-stdin' - sh "docker push ${username}/streetcode:latest" - sh "docker tag ${username}/streetcode:latest ${username}/streetcode:${env.CODE_VERSION}" + sh "docker push ${username}/streetcode:${env.CODE_VERSION}" IS_IMAGE_PUSH = true - + + sh "docker push ${username}/dbupdate:${env.CODE_VERSION}" + IS_DBUPDATE_IMAGE_PUSH = true + } } } } stage('Deploy Stage'){ when { - expression { IS_IMAGE_PUSH == true } + expression { IS_IMAGE_PUSH == true && IS_DBUPDATE_IMAGE_PUSH == true } } steps { input message: 'Do you want to approve Staging deployment?', ok: 'Yes', submitter: 'admin_1, ira_zavushchak , dev' script { checkout scmGit( - branches: [[name: 'main']], + branches: [[name: 'feature/add-init-container']], userRemoteConfigs: [[credentialsId: 'StreetcodeGithubCreds', url: 'git@github.com:ita-social-projects/Streetcode-DevOps.git']]) preDeployBackStage = sh(script: 'docker container inspect $(docker container ls -aq) --format "{{.Config.Image}}" | grep "streetcodeua/streetcode:" | perl -pe \'($_)=/([0-9]+([.][0-9]+)+)/\'', returnStdout: true).trim() @@ -195,7 +209,7 @@ pipeline { sh 'docker system prune --force --filter "until=72h"' sh """ export DOCKER_TAG_BACKEND=${env.CODE_VERSION} export DOCKER_TAG_FRONTEND=${preDeployFrontStage} - docker stop backend frontend nginx loki certbot + docker stop backend frontend nginx loki certbot dbupdate docker container prune -f docker volume prune -f docker network prune -f @@ -207,7 +221,7 @@ pipeline { } stage('WHAT IS THE NEXT STEP') { when { - expression { IS_IMAGE_PUSH == true } + expression { IS_IMAGE_PUSH == true && IS_DBUPDATE_IMAGE_PUSH == true } } steps { script { @@ -228,7 +242,7 @@ pipeline { sh """ export DOCKER_TAG_BACKEND=${preDeployBackStage} export DOCKER_TAG_FRONTEND=${preDeployFrontStage} - docker stop backend frontend nginx loki certbot + docker stop backend frontend nginx loki certbot dbupdate docker container prune -f docker volume prune -f docker network prune -f @@ -245,7 +259,9 @@ pipeline { } } } + /* + stage('Deploy prod') { agent { label 'production' @@ -286,7 +302,9 @@ pipeline { } } } + */ + stage('Sync after release') { when { expression { isSuccess == '1' } @@ -340,7 +358,9 @@ pipeline { } } } + */ + } post { always { @@ -349,3 +369,4 @@ post { } } } + diff --git a/Streetcode/DbUpdate/DbUpdate.csproj b/Streetcode/DbUpdate/DbUpdate.csproj index 6d6674574..f1a1b2efc 100644 --- a/Streetcode/DbUpdate/DbUpdate.csproj +++ b/Streetcode/DbUpdate/DbUpdate.csproj @@ -11,7 +11,11 @@ + + + + @@ -21,11 +25,27 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + PreserveNewest + + + + PreserveNewest + - + + + + + + true diff --git a/Streetcode/DbUpdate/Program.cs b/Streetcode/DbUpdate/Program.cs index 92d226671..cde0cd386 100644 --- a/Streetcode/DbUpdate/Program.cs +++ b/Streetcode/DbUpdate/Program.cs @@ -1,4 +1,5 @@ -using DbUp; +using System.Reflection; +using DbUp; using Microsoft.Extensions.Configuration; public class Program @@ -8,22 +9,20 @@ static int Main(string[] args) string rootDirectory = GetRootFolderPath(); string pathToSqlScripts = Path.Combine( rootDirectory, - "Streetcode", - "Streetcode.DAL", - "Persistence", "ScriptsMigration"); var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Local"; var configuration = new ConfigurationBuilder() - .SetBasePath(Path.Combine(rootDirectory, "Streetcode", "Streetcode.WebApi")) - .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .SetBasePath(rootDirectory) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{environment}.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables("STREETCODE_") .Build(); var connectionString = configuration.GetConnectionString("DefaultConnection"); + Console.WriteLine($"Connection string: {connectionString}"); var upgrader = DeployChanges.To .SqlDatabase(connectionString) @@ -50,16 +49,16 @@ static int Main(string[] args) return 0; } - private static string GetRootFolderPath() - { - // By root folder we mean folder, that contains .gitignore file. - string currentDirectoryPath = Directory.GetCurrentDirectory(); - var directory = new DirectoryInfo(currentDirectoryPath); - while (directory is not null && !directory.GetFiles(".gitignore").Any()) - { - directory = directory.Parent; - } - - return directory?.FullName ?? throw new NullReferenceException("Cannot find root folder"); + private static string GetRootFolderPath() + { + string codeBase = Assembly.GetExecutingAssembly().CodeBase; + if (codeBase == null) + { + throw new NullReferenceException("Cannot find root folder"); + } + + UriBuilder uri = new UriBuilder(codeBase); + string path = Uri.UnescapeDataString(uri.Path); + return Path.GetDirectoryName(path) !; } } \ No newline at end of file diff --git a/Streetcode/DbUpdate/appsettings.IntegrationTests.json b/Streetcode/DbUpdate/appsettings.IntegrationTests.json new file mode 100644 index 000000000..f827a5951 --- /dev/null +++ b/Streetcode/DbUpdate/appsettings.IntegrationTests.json @@ -0,0 +1,5 @@ +{ + "ConnectionStrings": { + "DefaultConnection": "Server=localhost,1455;Database=Streetcode_IntegrationTests_Db;User Id=sa;Password=sdlLKMCD234!@#lkcmds;MultipleActiveResultSets=True;TrustServerCertificate=true" + } +} \ No newline at end of file diff --git a/Streetcode/DbUpdate/appsettings.Local.json b/Streetcode/DbUpdate/appsettings.Local.json new file mode 100644 index 000000000..bd35fe812 --- /dev/null +++ b/Streetcode/DbUpdate/appsettings.Local.json @@ -0,0 +1,5 @@ +{ + "ConnectionStrings": { + "DefaultConnection": "Server=localhost, 1433;Database=test-db;User Id=sa;Password=Admin@1234;MultipleActiveResultSets=true;TrustServerCertificate=true" + } +} diff --git a/Streetcode/Streetcode.BLL/Attributes/Authentication/ValidEmailAttribute.cs b/Streetcode/Streetcode.BLL/Attributes/Authentication/ValidEmailAttribute.cs index e34ae6ef0..7f831886d 100644 --- a/Streetcode/Streetcode.BLL/Attributes/Authentication/ValidEmailAttribute.cs +++ b/Streetcode/Streetcode.BLL/Attributes/Authentication/ValidEmailAttribute.cs @@ -3,6 +3,7 @@ namespace Streetcode.BLL.Attributes.Authentication { + [AttributeUsage(AttributeTargets.Property)] public class ValidEmailAttribute : ValidationAttribute { protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) @@ -19,7 +20,7 @@ public class ValidEmailAttribute : ValidationAttribute return new ValidationResult("Attribute cannot be applied to non-string property"); } - if (!Regex.IsMatch(email, @"^[^@\s]+@[^@\s]+\.(com|net|org|gov|ua)$", RegexOptions.None, TimeSpan.FromMilliseconds(100))) + if (!Regex.IsMatch(email, @"^(?!.*\.\.)[a-zA-Z0-9_%+-]+(?:\.[a-zA-Z0-9_%+-]+)*@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", RegexOptions.None, TimeSpan.FromMilliseconds(100))) { return new ValidationResult("Incorrect email address format"); } diff --git a/Streetcode/Streetcode.BLL/DTO/Authentication/GoogleLogin/GoogleLoginRequest.cs b/Streetcode/Streetcode.BLL/DTO/Authentication/GoogleLogin/GoogleLoginRequest.cs new file mode 100644 index 000000000..c7dae6603 --- /dev/null +++ b/Streetcode/Streetcode.BLL/DTO/Authentication/GoogleLogin/GoogleLoginRequest.cs @@ -0,0 +1,7 @@ +namespace Streetcode.BLL.DTO.Authentication.GoogleLogin +{ + public class GoogleLoginRequest + { + public string IdToken { get; set; } = string.Empty; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/DTO/Authentication/Login/LoginRequestDTO.cs b/Streetcode/Streetcode.BLL/DTO/Authentication/Login/LoginRequestDTO.cs index 987708121..27878c9b3 100644 --- a/Streetcode/Streetcode.BLL/DTO/Authentication/Login/LoginRequestDTO.cs +++ b/Streetcode/Streetcode.BLL/DTO/Authentication/Login/LoginRequestDTO.cs @@ -1,13 +1,14 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using Streetcode.BLL.Constants.Authentication; +using Streetcode.BLL.Attributes.Authentication; namespace Streetcode.BLL.DTO.Authentication.Login; public class LoginRequestDTO { [Required] - [EmailAddress] + [ValidEmail] [DefaultValue(AuthConstants.Email)] public string Login { get; set; } = null!; diff --git a/Streetcode/Streetcode.BLL/DTO/Authentication/Register/RegisterRequestDTO.cs b/Streetcode/Streetcode.BLL/DTO/Authentication/Register/RegisterRequestDTO.cs index edc2e8129..ea3d22343 100644 --- a/Streetcode/Streetcode.BLL/DTO/Authentication/Register/RegisterRequestDTO.cs +++ b/Streetcode/Streetcode.BLL/DTO/Authentication/Register/RegisterRequestDTO.cs @@ -1,7 +1,5 @@ -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; using Streetcode.BLL.Attributes.Authentication; -using Streetcode.BLL.Constants.Authentication; namespace Streetcode.BLL.DTO.Authentication.Register; @@ -9,30 +7,24 @@ public class RegisterRequestDTO { [Required] [MaxLength(50)] - [DefaultValue(AuthConstants.Name)] public string Name { get; set; } = null!; [Required] [MaxLength(50)] - [DefaultValue(AuthConstants.Surname)] public string Surname { get; set; } = null!; [Required] - [EmailAddress] - [DefaultValue(AuthConstants.Email)] - [RegularExpression(@"[^\.\-_](?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*|""(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*"")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])", ErrorMessage = "The Email field doesn't contain a valid email address")] + [ValidEmail] public string Email { get; set; } = null!; [Required] [MaxLength(30, ErrorMessage = "Password maximum length is 30")] [StrongPassword] - [DefaultValue(AuthConstants.Password)] public string Password { get; set; } = null!; [Required] [Display(Name = "Confirm password")] [MaxLength(30, ErrorMessage = "Password maximum length is 30")] - [DefaultValue("")] [Compare(nameof(Password))] public string PasswordConfirmation { get; set; } = null!; } diff --git a/Streetcode/Streetcode.BLL/DTO/Streetcode/Create/StreetcodeCreateDTO.cs b/Streetcode/Streetcode.BLL/DTO/Streetcode/Create/StreetcodeCreateDTO.cs index e19dd07a8..6a76d6cae 100644 --- a/Streetcode/Streetcode.BLL/DTO/Streetcode/Create/StreetcodeCreateDTO.cs +++ b/Streetcode/Streetcode.BLL/DTO/Streetcode/Create/StreetcodeCreateDTO.cs @@ -3,29 +3,40 @@ using Streetcode.BLL.DTO.AdditionalContent.Tag; using Streetcode.BLL.DTO.Analytics; using Streetcode.BLL.DTO.Media.Video; -using Streetcode.BLL.DTO.Partners; using Streetcode.BLL.DTO.Sources; using Streetcode.BLL.DTO.Streetcode.RelatedFigure; using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; using Streetcode.BLL.DTO.Streetcode.TextContent.Text; -namespace Streetcode.BLL.DTO.Streetcode.Create +namespace Streetcode.BLL.DTO.Streetcode.Create; + +public class StreetcodeCreateDTO : StreetcodeCreateUpdateDTO { - public class StreetcodeCreateDTO : StreetcodeCreateUpdateDTO - { - public string? ARBlockURL { get; set; } - public int ViewCount { get; set; } - public TextCreateDTO? Text { get; set; } - public int? AudioId { get; set; } - public IEnumerable ImagesIds { get; set; } = null!; // one image black and white is required at front-end side, so at least one will be passed - public IEnumerable Tags { get; set; } = null!; - public IEnumerable Subtitles { get; set; } = null!; // subtitles are only in one example - public IEnumerable Facts { get; set; } = null!; - public IEnumerable? Videos { get; set; } = null!; // video is only one - public IEnumerable RelatedFigures { get; set; } = null!; - public IEnumerable Partners { get; set; } = null!; - public IEnumerable StreetcodeCategoryContents { get; set; } = null!; - public IEnumerable Coordinates { get; set; } = null!; - public IEnumerable StatisticRecords { get; set; } = null!; - } -} + public string? ArBlockUrl { get; set; } + + public int ViewCount { get; set; } + + public TextCreateDTO? Text { get; set; } + + public int? AudioId { get; set; } + + public IEnumerable ImagesIds { get; set; } = new List(); + + public IEnumerable? Tags { get; set; } = new List(); + + public IEnumerable? Subtitles { get; set; } = new List(); + + public IEnumerable? Facts { get; set; } = new List(); + + public IEnumerable? Videos { get; set; } = new List(); + + public IEnumerable? RelatedFigures { get; set; } = new List(); + + public IEnumerable? Partners { get; set; } = new List(); + + public IEnumerable? StreetcodeCategoryContents { get; set; } = new List(); + + public IEnumerable? Coordinates { get; set; } = new List(); + + public IEnumerable? StatisticRecords { get; set; } = new List(); +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/DTO/Streetcode/StreetcodeCreateUpdateDTO.cs b/Streetcode/Streetcode.BLL/DTO/Streetcode/StreetcodeCreateUpdateDTO.cs index 328f42a5b..2da0033b4 100644 --- a/Streetcode/Streetcode.BLL/DTO/Streetcode/StreetcodeCreateUpdateDTO.cs +++ b/Streetcode/Streetcode.BLL/DTO/Streetcode/StreetcodeCreateUpdateDTO.cs @@ -1,5 +1,4 @@ -using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; -using Streetcode.BLL.DTO.Media.Art; +using Streetcode.BLL.DTO.Media.Art; using Streetcode.BLL.DTO.Media.Create; using Streetcode.BLL.DTO.Media.Images; using Streetcode.BLL.DTO.Timeline.Update; @@ -11,20 +10,36 @@ namespace Streetcode.BLL.DTO.Streetcode; public abstract class StreetcodeCreateUpdateDTO { public string? FirstName { get; set; } + public string? LastName { get; set; } + public int Index { get; set; } - public string? Teaser { get; set; } // in the requirements it's not specified whether it is a mandatory property or not - public string DateString { get; set; } = null!; // date in a pretty format - public string? Alias { get; set; } // this is "Короткий опис (для зв'язків історії)" - public StreetcodeStatus Status { get; set; } // passed as a number - public StreetcodeType StreetcodeType { get; set; } // an event or a person - public string Title { get; set; } = null!; // this is "Назва стріткоду" - public string TransliterationUrl { get; set; } = null!; // this is "URL" + + public string? Teaser { get; set; } + + public string DateString { get; set; } = null!; + + public string? Alias { get; set; } + + public StreetcodeStatus Status { get; set; } + + public StreetcodeType StreetcodeType { get; set; } + + public string Title { get; set; } = null!; + + public string TransliterationUrl { get; set; } = null!; + public DateTime EventStartOrPersonBirthDate { get; set; } + public DateTime? EventEndOrPersonDeathDate { get; set; } - public IEnumerable Toponyms { get; set; } = null!; - public IEnumerable TimelineItems { get; set; } = null!; - public IEnumerable? ImagesDetails { get; set; } // strange behaviour, a random number is passed as 'Alt' property - public IEnumerable StreetcodeArtSlides { get; set; } = null!; - public List Arts { get; set; } = null!; + + public IEnumerable? Toponyms { get; set; } = new List(); + + public IEnumerable? TimelineItems { get; set; } = new List(); + + public IEnumerable ImagesDetails { get; set; } = new List(); + + public IEnumerable? StreetcodeArtSlides { get; set; } = new List(); + + public List? Arts { get; set; } = new List(); } \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/DTO/Streetcode/StreetcodeFavouriteDTO.cs b/Streetcode/Streetcode.BLL/DTO/Streetcode/StreetcodeFavouriteDTO.cs new file mode 100644 index 000000000..9aec4a255 --- /dev/null +++ b/Streetcode/Streetcode.BLL/DTO/Streetcode/StreetcodeFavouriteDTO.cs @@ -0,0 +1,14 @@ +using Streetcode.DAL.Enums; + +namespace Streetcode.BLL.DTO.Streetcode +{ + public class StreetcodeFavouriteDto + { + public int Id { get; set; } + public string Title { get; set; } = null!; + public string? Alias { get; set; } + public int ImageId { get; set; } + public string TransliterationUrl { get; set; } = null!; + public StreetcodeType Type { get; set; } + } +} diff --git a/Streetcode/Streetcode.BLL/DTO/Streetcode/TextContent/Fact/FactUpdateCreateDto.cs b/Streetcode/Streetcode.BLL/DTO/Streetcode/TextContent/Fact/FactUpdateCreateDto.cs index 7047918a3..d3c6d827d 100644 --- a/Streetcode/Streetcode.BLL/DTO/Streetcode/TextContent/Fact/FactUpdateCreateDto.cs +++ b/Streetcode/Streetcode.BLL/DTO/Streetcode/TextContent/Fact/FactUpdateCreateDto.cs @@ -1,11 +1,16 @@ -namespace Streetcode.BLL.DTO.Streetcode.TextContent.Fact +namespace Streetcode.BLL.DTO.Streetcode.TextContent.Fact; + +public abstract class FactUpdateCreateDto { - public abstract class FactUpdateCreateDto - { - public string Title { get; set; } - public int ImageId { get; set; } - public string FactContent { get; set; } - public int Index { get; set; } - public string? ImageDescription { get; set; } - } -} \ No newline at end of file + public string Title { get; set; } + + public int ImageId { get; set; } + + public string FactContent { get; set; } + + public int StreetcodeId { get; set; } + + public int Index { get; set; } + + public string? ImageDescription { get; set; } +} diff --git a/Streetcode/Streetcode.BLL/DTO/Streetcode/TextContent/Fact/StreetcodeFactUpdateDTO.cs b/Streetcode/Streetcode.BLL/DTO/Streetcode/TextContent/Fact/StreetcodeFactUpdateDTO.cs index 1a52ae47c..9237af32c 100644 --- a/Streetcode/Streetcode.BLL/DTO/Streetcode/TextContent/Fact/StreetcodeFactUpdateDTO.cs +++ b/Streetcode/Streetcode.BLL/DTO/Streetcode/TextContent/Fact/StreetcodeFactUpdateDTO.cs @@ -1,12 +1,11 @@ using Streetcode.BLL.DTO.Streetcode.Update.Interfaces; using Streetcode.BLL.Enums; -namespace Streetcode.BLL.DTO.Streetcode.TextContent.Fact +namespace Streetcode.BLL.DTO.Streetcode.TextContent.Fact; + +public class StreetcodeFactUpdateDTO : FactUpdateCreateDto, IModelState { - public class StreetcodeFactUpdateDTO : FactUpdateCreateDto, IModelState - { public int Id { get; set; } + public ModelState ModelState { get; set; } - public int StreetcodeId { get; set; } - } } diff --git a/Streetcode/Streetcode.BLL/DTO/Streetcode/Update/StreetcodeUpdateDTO.cs b/Streetcode/Streetcode.BLL/DTO/Streetcode/Update/StreetcodeUpdateDTO.cs index 59116c2bb..ef6df33b4 100644 --- a/Streetcode/Streetcode.BLL/DTO/Streetcode/Update/StreetcodeUpdateDTO.cs +++ b/Streetcode/Streetcode.BLL/DTO/Streetcode/Update/StreetcodeUpdateDTO.cs @@ -1,9 +1,7 @@ using Streetcode.BLL.DTO.AdditionalContent.Subtitles; using Streetcode.BLL.DTO.AdditionalContent.Tag; using Streetcode.BLL.DTO.Analytics.Update; -using Streetcode.BLL.DTO.Media.Art; using Streetcode.BLL.DTO.Media.Audio; -using Streetcode.BLL.DTO.Media.Create; using Streetcode.BLL.DTO.Media.Images; using Streetcode.BLL.DTO.Media.Video; using Streetcode.BLL.DTO.Partners.Update; @@ -11,27 +9,34 @@ using Streetcode.BLL.DTO.Streetcode.RelatedFigure; using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; using Streetcode.BLL.DTO.Streetcode.TextContent.Text; -using Streetcode.BLL.DTO.Timeline.Update; -using Streetcode.BLL.DTO.Toponyms; -using Streetcode.BLL.DTO.Transactions; -using Streetcode.DAL.Enums; -namespace Streetcode.BLL.DTO.Streetcode.Update +namespace Streetcode.BLL.DTO.Streetcode.Update; + +public class StreetcodeUpdateDTO : StreetcodeCreateUpdateDTO { - public class StreetcodeUpdateDTO : StreetcodeCreateUpdateDTO - { - public int Id { get; set; } - public TextUpdateDTO? Text { get; set; } - public string? ARBlockUrl { get; set; } - public IEnumerable Subtitles { get; set; } = null!; - public IEnumerable Facts { get; set; } - public IEnumerable? Videos { get; set; } - public IEnumerable Audios { get; set; } = null!; - public IEnumerable RelatedFigures { get; set; } = null!; - public IEnumerable Partners { get; set; } = null!; - public IEnumerable Tags { get; set; } = null!; - public IEnumerable StatisticRecords { get; set; } - public IEnumerable Images { get; set; } = null!; - public IEnumerable StreetcodeCategoryContents { get; set; } - } -} + public int Id { get; set; } + + public TextUpdateDTO? Text { get; set; } + + public string? ArBlockUrl { get; set; } + + public IEnumerable? Subtitles { get; set; } = new List(); + + public IEnumerable? Facts { get; set; } = new List(); + + public IEnumerable? Videos { get; set; } = new List(); + + public IEnumerable? Audios { get; set; } = new List(); + + public IEnumerable? RelatedFigures { get; set; } = new List(); + + public IEnumerable? Partners { get; set; } = new List(); + + public IEnumerable? Tags { get; set; } = new List(); + + public IEnumerable? StatisticRecords { get; set; } = new List(); + + public IEnumerable Images { get; set; } = new List(); + + public IEnumerable? StreetcodeCategoryContents { get; set; } = new List(); +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/DTO/Timeline/GetAllHistoricalContextDTO.cs b/Streetcode/Streetcode.BLL/DTO/Timeline/GetAllHistoricalContextDTO.cs index 3a9797b95..475df7568 100644 --- a/Streetcode/Streetcode.BLL/DTO/Timeline/GetAllHistoricalContextDTO.cs +++ b/Streetcode/Streetcode.BLL/DTO/Timeline/GetAllHistoricalContextDTO.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Streetcode.BLL.DTO.Timeline +namespace Streetcode.BLL.DTO.Timeline { public class GetAllHistoricalContextDTO { diff --git a/Streetcode/Streetcode.BLL/DTO/Transactions/TransactionLinkUpdateDTO.cs b/Streetcode/Streetcode.BLL/DTO/Transactions/TransactionLinkUpdateDTO.cs deleted file mode 100644 index fefdd0045..000000000 --- a/Streetcode/Streetcode.BLL/DTO/Transactions/TransactionLinkUpdateDTO.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Streetcode.BLL.DTO.Streetcode.Update.Interfaces; -using Streetcode.BLL.Enums; - -namespace Streetcode.BLL.DTO.Transactions -{ - public class TransactionLinkUpdateDTO : TransactLinkDTO, IModelState - { - public ModelState ModelState { get; set; } - } -} diff --git a/Streetcode/Streetcode.BLL/DTO/Users/Password/UpdateForgotPasswordDTO.cs b/Streetcode/Streetcode.BLL/DTO/Users/Password/UpdateForgotPasswordDTO.cs index 8b6bdf7d5..dd2e37ab0 100644 --- a/Streetcode/Streetcode.BLL/DTO/Users/Password/UpdateForgotPasswordDTO.cs +++ b/Streetcode/Streetcode.BLL/DTO/Users/Password/UpdateForgotPasswordDTO.cs @@ -1,5 +1,5 @@ using System.ComponentModel.DataAnnotations; -using Microsoft.AspNetCore.Mvc; +using Streetcode.BLL.Attributes.Authentication; namespace Streetcode.BLL.DTO.Users.Password; @@ -7,7 +7,9 @@ public class UpdateForgotPasswordDTO { public string Token { get; set; } public string Username { get; set; } + [StrongPassword] public string Password { get; set; } = null!; [Compare(nameof(Password))] + [StrongPassword] public string ConfirmPassword { get; set; } = null!; } \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/Interfaces/Authentication/IGoogleService.cs b/Streetcode/Streetcode.BLL/Interfaces/Authentication/IGoogleService.cs new file mode 100644 index 000000000..d3134ea81 --- /dev/null +++ b/Streetcode/Streetcode.BLL/Interfaces/Authentication/IGoogleService.cs @@ -0,0 +1,9 @@ +using Google.Apis.Auth; + +namespace Streetcode.BLL.Interfaces.Authentication +{ + public interface IGoogleService + { + Task ValidateGoogleToken(string id); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/Mapping/Streetcode/RelatedFigureProfile.cs b/Streetcode/Streetcode.BLL/Mapping/Streetcode/RelatedFigureProfile.cs index c1b3bd5b9..67fd01dde 100644 --- a/Streetcode/Streetcode.BLL/Mapping/Streetcode/RelatedFigureProfile.cs +++ b/Streetcode/Streetcode.BLL/Mapping/Streetcode/RelatedFigureProfile.cs @@ -25,5 +25,8 @@ public RelatedFigureProfile() CreateMap(); CreateMap(); + CreateMap() + .ForPath(dto => dto.ImageId, conf => conf + .MapFrom(e => e.Images.Select(i => i.Id).LastOrDefault())).ReverseMap(); } } diff --git a/Streetcode/Streetcode.BLL/Mapping/Streetcode/StreetcodeProfile.cs b/Streetcode/Streetcode.BLL/Mapping/Streetcode/StreetcodeProfile.cs index a89ee398e..c1df1f03f 100644 --- a/Streetcode/Streetcode.BLL/Mapping/Streetcode/StreetcodeProfile.cs +++ b/Streetcode/Streetcode.BLL/Mapping/Streetcode/StreetcodeProfile.cs @@ -1,5 +1,4 @@ using AutoMapper; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Streetcode.BLL.DTO.Streetcode; using Streetcode.BLL.DTO.Streetcode.Create; using Streetcode.BLL.DTO.Streetcode.Update; @@ -7,8 +6,6 @@ using Streetcode.DAL.Entities.Streetcode; using Streetcode.DAL.Entities.Streetcode.Types; using Streetcode.DAL.Enums; -using Streetcode.DAL.Repositories.Interfaces.Base; -using StringToDateTimeConverter = Streetcode.BLL.Mapping.Converters.StringToDateTimeConverter; namespace Streetcode.BLL.Mapping.Streetcode; @@ -27,6 +24,12 @@ public StreetcodeProfile() .ForPath(dto => dto.ImageId, conf => conf .MapFrom(e => e.Images.Select(i => i.Id).FirstOrDefault())); + CreateMap() + .ForMember(x => x.Type, conf => conf.MapFrom(s => GetStreetcodeType(s))) + .ForPath(dto => dto.ImageId, conf => conf + .MapFrom(e => e.Images.Select(i => i.Id).FirstOrDefault())) + .ReverseMap(); + CreateMap() .ForMember(x => x.Arts, conf => conf.Ignore()) .ForMember(x => x.StreetcodeArtSlides, conf => conf.Ignore()) @@ -50,7 +53,7 @@ public StreetcodeProfile() .ForMember(x => x.StatisticRecords, conf => conf.Ignore()) .ForMember(x => x.StreetcodeArtSlides, conf => conf.Ignore()) .ForMember(x => x.Facts, conf => conf.Ignore()) - .ForPath(x => x.TransactionLink!.Url, conf => conf.MapFrom(x => x.ARBlockUrl)) + .ForPath(x => x.TransactionLink!.Url, conf => conf.MapFrom(x => x.ArBlockUrl)) .ReverseMap(); CreateMap() @@ -62,13 +65,10 @@ public StreetcodeProfile() .ReverseMap(); } - private StreetcodeType GetStreetcodeType(StreetcodeContent streetcode) - { - if(streetcode is EventStreetcode) + private static StreetcodeType GetStreetcodeType(StreetcodeContent streetcode) => + streetcode switch { - return StreetcodeType.Event; - } - - return StreetcodeType.Person; - } + EventStreetcode => StreetcodeType.Event, + _ => StreetcodeType.Person + }; } diff --git a/Streetcode/Streetcode.BLL/Mapping/Transactions/TransactionLinkProfile.cs b/Streetcode/Streetcode.BLL/Mapping/Transactions/TransactionLinkProfile.cs index ce6ce15b7..27967bfed 100644 --- a/Streetcode/Streetcode.BLL/Mapping/Transactions/TransactionLinkProfile.cs +++ b/Streetcode/Streetcode.BLL/Mapping/Transactions/TransactionLinkProfile.cs @@ -10,8 +10,5 @@ public TransactionLinkProfile() { CreateMap() .ReverseMap(); - - CreateMap() - .ReverseMap(); } } \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/Create/CreateStatisticRecordCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/Create/CreateStatisticRecordCommand.cs deleted file mode 100644 index 1904e0154..000000000 --- a/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/Create/CreateStatisticRecordCommand.cs +++ /dev/null @@ -1,9 +0,0 @@ -using FluentResults; -using MediatR; -using Streetcode.BLL.DTO.Analytics; - -namespace Streetcode.BLL.MediatR.Analytics.StatisticRecord.Create -{ - public record CreateStatisticRecordCommand(StatisticRecordDTO StatisticRecordDTO) - : IRequest>; -} diff --git a/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/Create/CreateStatisticRecordHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/Create/CreateStatisticRecordHandler.cs deleted file mode 100644 index 2df57f4bd..000000000 --- a/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/Create/CreateStatisticRecordHandler.cs +++ /dev/null @@ -1,77 +0,0 @@ -using AutoMapper; -using FluentResults; -using MediatR; -using Microsoft.Extensions.Localization; -using Streetcode.BLL.DTO.Analytics; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Repositories.Interfaces.Base; - -using Entity = Streetcode.DAL.Entities.Analytics.StatisticRecord; - -namespace Streetcode.BLL.MediatR.Analytics.StatisticRecord.Create -{ - public class CreateStatisticRecordHandler : IRequestHandler> - { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repositoryWrapper; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerNo; - private readonly IStringLocalizer _stringLocalizer; - - public CreateStatisticRecordHandler( - IMapper mapper, - IRepositoryWrapper repositoryWrapper, - ILoggerService logger, - IStringLocalizer stringLocalizer, - IStringLocalizer stringLocalizerNo) - { - _mapper = mapper; - _repositoryWrapper = repositoryWrapper; - _logger = logger; - _stringLocalizer = stringLocalizer; - _stringLocalizerNo = stringLocalizerNo; - } - - public async Task> Handle(CreateStatisticRecordCommand request, CancellationToken cancellationToken) - { - var statRecord = _mapper.Map(request.StatisticRecordDTO); - - if (statRecord == null) - { - string errorMsg = _stringLocalizerNo["NoMappedRecord"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } - - var createdRecord = _repositoryWrapper.StatisticRecordRepository.Create(statRecord); - - if (createdRecord == null) - { - string errorMsg = _stringLocalizer["NoCreatedRecord"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } - - var resultIsSuccess = await _repositoryWrapper.SaveChangesAsync() > 0; - - if (!resultIsSuccess) - { - string errorMsg = _stringLocalizer["CannotSaveCreatedRecord"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } - - var mappedCreatedRecord = _mapper.Map(createdRecord); - - if (mappedCreatedRecord == null) - { - string errorMsg = _stringLocalizer["NoMappedCreatedRecord"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } - - return Result.Ok(mappedCreatedRecord); - } - } -} diff --git a/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/Delete/DeleteStatisticRecordHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/Delete/DeleteStatisticRecordHandler.cs index eb18ba18d..6cdb0b8a4 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/Delete/DeleteStatisticRecordHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/Delete/DeleteStatisticRecordHandler.cs @@ -1,5 +1,4 @@ -using AutoMapper; -using FluentResults; +using FluentResults; using MediatR; using Microsoft.Extensions.Localization; using Streetcode.BLL.Interfaces.Logging; @@ -10,20 +9,17 @@ namespace Streetcode.BLL.MediatR.Analytics.StatisticRecord.Delete { public class DeleteStatisticRecordHandler : IRequestHandler> { - private readonly IMapper _mapper; private readonly IRepositoryWrapper _repositoryWrapper; private readonly ILoggerService _logger; private readonly IStringLocalizer _stringLocalizerCannotFind; private readonly IStringLocalizer _stringLocalizerFailedToDelete; public DeleteStatisticRecordHandler( - IMapper mapper, IRepositoryWrapper repositoryWrapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind, IStringLocalizer stringLocalizerFailedToDelete) { - _mapper = mapper; _repositoryWrapper = repositoryWrapper; _logger = logger; _stringLocalizerCannotFind = stringLocalizerCannotFind; @@ -44,7 +40,7 @@ public async Task> Handle(DeleteStatisticRecordCommand request, Can _repositoryWrapper.StatisticRecordRepository.Delete(statRecord); - var resultIsSuccess = _repositoryWrapper.SaveChanges() > 0; + var resultIsSuccess = await _repositoryWrapper.SaveChangesAsync() > 0; if (resultIsSuccess) { diff --git a/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/ExistByQrId/ExistStatisticRecordByQrIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/ExistByQrId/ExistStatisticRecordByQrIdHandler.cs index de54ee00a..0de3c143b 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/ExistByQrId/ExistStatisticRecordByQrIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/ExistByQrId/ExistStatisticRecordByQrIdHandler.cs @@ -1,19 +1,15 @@ -using AutoMapper; -using FluentResults; +using FluentResults; using MediatR; -using Streetcode.BLL.Interfaces.Logging; using Streetcode.DAL.Repositories.Interfaces.Base; namespace Streetcode.BLL.MediatR.Analytics.StatisticRecord.ExistByQrId { public class ExistStatisticRecordByQrIdHandler : IRequestHandler> { - private readonly IMapper _mapper; private readonly IRepositoryWrapper _repository; - public ExistStatisticRecordByQrIdHandler(IMapper mapper, IRepositoryWrapper repository) + public ExistStatisticRecordByQrIdHandler(IRepositoryWrapper repository) { - _mapper = mapper; _repository = repository; } diff --git a/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/GetAll/GetAllStatisticRecordsQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/GetAll/GetAllStatisticRecordsQuery.cs index 9559e8405..31924bf73 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/GetAll/GetAllStatisticRecordsQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/GetAll/GetAllStatisticRecordsQuery.cs @@ -4,6 +4,6 @@ namespace Streetcode.BLL.MediatR.Analytics.StatisticRecord.GetAll { - public record GetAllStatisticRecordsQuery() + public record GetAllStatisticRecordsQuery : IRequest>>; } diff --git a/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/GetAllByStreetcodeId/GetAllStatisticRecordsByStreetcodeIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/GetAllByStreetcodeId/GetAllStatisticRecordsByStreetcodeIdHandler.cs index a9f679d3b..04a0fddf4 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/GetAllByStreetcodeId/GetAllStatisticRecordsByStreetcodeIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/GetAllByStreetcodeId/GetAllStatisticRecordsByStreetcodeIdHandler.cs @@ -10,26 +10,23 @@ namespace Streetcode.BLL.MediatR.Analytics.StatisticRecord.GetAllByStreetcodeId { - internal class GetAllStatisticRecordsByStreetcodeIdHandler : IRequestHandler>> + public class GetAllStatisticRecordsByStreetcodeIdHandler : IRequestHandler>> { private readonly IRepositoryWrapper _repository; private readonly IMapper _mapper; private readonly ILoggerService _logger; private readonly IStringLocalizer _stringLocalizerCannotFind; - private readonly IStringLocalizer _stringLocalizerCannotMap; public GetAllStatisticRecordsByStreetcodeIdHandler( IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, - IStringLocalizer stringLocalizerCannotFind, - IStringLocalizer stringLocalizerCannotMap) + IStringLocalizer stringLocalizerCannotFind) { _repository = repositoryWrapper; _mapper = mapper; _logger = logger; _stringLocalizerCannotFind = stringLocalizerCannotFind; - _stringLocalizerCannotMap = stringLocalizerCannotMap; } public async Task>> Handle(GetAllStatisticRecordsByStreetcodeIdQuery request, CancellationToken cancellationToken) @@ -38,7 +35,7 @@ public async Task>> Handle(GetAllStatisti predicate: st => st.StreetcodeCoordinate.StreetcodeId == request.streetcodeId, include: st => st.Include(st => st.StreetcodeCoordinate)); - if (statisticRecords is null) + if (!statisticRecords.Any()) { string errorMsg = _stringLocalizerCannotFind["CannotFindRecordWithStreetcodeId", request.streetcodeId]; _logger.LogError(request, errorMsg); @@ -47,13 +44,6 @@ public async Task>> Handle(GetAllStatisti var statisticRecordsDTOs = _mapper.Map>(statisticRecords); - if (statisticRecordsDTOs is null) - { - string errorMsg = _stringLocalizerCannotMap["CannotMapRecord"]; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } - return Result.Ok(statisticRecordsDTOs); } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/UpdateCount/UpdateCountStatisticRecordHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/UpdateCount/UpdateCountStatisticRecordHandler.cs index 8bf9eea44..2d22b8fe2 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/UpdateCount/UpdateCountStatisticRecordHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Analytics/StatisticRecord/UpdateCount/UpdateCountStatisticRecordHandler.cs @@ -1,5 +1,4 @@ -using AutoMapper; -using FluentResults; +using FluentResults; using MediatR; using Streetcode.BLL.Interfaces.Logging; using Microsoft.Extensions.Localization; @@ -44,7 +43,7 @@ public async Task> Handle(UpdateCountStatisticRecordCommand request _repositoryWrapper.StatisticRecordRepository.Update(statRecord); - var resultIsSuccess = _repositoryWrapper.SaveChanges() > 0; + var resultIsSuccess = await _repositoryWrapper.SaveChangesAsync() > 0; if (!resultIsSuccess) { diff --git a/Streetcode/Streetcode.BLL/MediatR/Authentication/LoginGoogle/LoginGoogleHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Authentication/LoginGoogle/LoginGoogleHandler.cs index b10faba91..bf1a62f36 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Authentication/LoginGoogle/LoginGoogleHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Authentication/LoginGoogle/LoginGoogleHandler.cs @@ -1,7 +1,6 @@ using System.IdentityModel.Tokens.Jwt; using AutoMapper; using FluentResults; -using Google.Apis.Auth; using MediatR; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Configuration; @@ -18,34 +17,31 @@ namespace Streetcode.BLL.MediatR.Authentication.LoginGoogle; public class LoginGoogleHandler : IRequestHandler> { private const string LoginProvider = "Google"; - private readonly IConfiguration _configuration; private readonly IMapper _mapper; private readonly ITokenService _tokenService; private readonly ILoggerService _logger; private readonly UserManager _userManager; + private readonly IGoogleService _googleService; public LoginGoogleHandler( - IConfiguration configuration, IMapper mapper, ITokenService tokenService, ILoggerService logger, - UserManager userManager) + UserManager userManager, + IGoogleService googleService) { - _configuration = configuration; _mapper = mapper; _tokenService = tokenService; _logger = logger; _userManager = userManager; + _googleService = googleService; } public async Task> Handle(LoginGoogleQuery request, CancellationToken cancellationToken) { try { - var payload = await GoogleJsonWebSignature.ValidateAsync(request.idToken, new GoogleJsonWebSignature.ValidationSettings - { - Audience = new[] { _configuration["Authentication:Google:ClientId"] } - }); + var payload = await _googleService.ValidateGoogleToken(request.idToken); var user = await _userManager.FindByEmailAsync(payload.Email); if (user == null) diff --git a/Streetcode/Streetcode.BLL/MediatR/Authentication/Logout/LogoutCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Authentication/Logout/LogoutCommand.cs index ce58d3a7e..d31e2d5e1 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Authentication/Logout/LogoutCommand.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Authentication/Logout/LogoutCommand.cs @@ -3,4 +3,4 @@ namespace Streetcode.BLL.MediatR.Authentication.Logout; -public record LogoutCommand(string UserId) : IRequest; +public record LogoutCommand : IRequest; diff --git a/Streetcode/Streetcode.BLL/MediatR/Authentication/Logout/LogoutHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Authentication/Logout/LogoutHandler.cs index a9502ca83..cd5b92cb2 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Authentication/Logout/LogoutHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Authentication/Logout/LogoutHandler.cs @@ -1,7 +1,7 @@ using FluentResults; using MediatR; -using Microsoft.EntityFrameworkCore; -using Streetcode.DAL.Persistence; +using Microsoft.AspNetCore.Http; +using Streetcode.BLL.Util.Helpers; using Streetcode.DAL.Repositories.Interfaces.Base; namespace Streetcode.BLL.MediatR.Authentication.Logout; @@ -9,15 +9,20 @@ namespace Streetcode.BLL.MediatR.Authentication.Logout; public class LogoutHandler : IRequestHandler { private readonly IRepositoryWrapper _repositoryWrapper; + private readonly IHttpContextAccessor _httpContextAccessor; - public LogoutHandler(IRepositoryWrapper repositoryWrapper) + public LogoutHandler( + IRepositoryWrapper repositoryWrapper, + IHttpContextAccessor httpContextAccessor) { _repositoryWrapper = repositoryWrapper; + _httpContextAccessor = httpContextAccessor; } public async Task Handle(LogoutCommand request, CancellationToken cancellationToken) { - var user = await _repositoryWrapper.UserRepository.GetFirstOrDefaultAsync(u => u.Id == request.UserId); + var userUserName = HttpContextHelper.GetCurrentUserName(_httpContextAccessor); + var user = await _repositoryWrapper.UserRepository.GetFirstOrDefaultAsync(u => u.UserName == userUserName); if (user == null) { @@ -34,10 +39,8 @@ public async Task Handle(LogoutCommand request, CancellationToken cancel { return Result.Ok(); } - else - { - string errorMsg = "Failed to logout"; - return Result.Fail(new Error(errorMsg)); - } + + string errorMsg = "Failed to logout"; + return Result.Fail(new Error(errorMsg)); } } \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Email/SendEmailHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Email/SendEmailHandler.cs index 4023f85fc..f2f3c153a 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Email/SendEmailHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Email/SendEmailHandler.cs @@ -7,7 +7,6 @@ using Streetcode.BLL.Factories.MessageDataFactory.Abstracts; using Streetcode.BLL.Interfaces.Email; using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.Models.Email.Messages; namespace Streetcode.BLL.MediatR.Email { @@ -69,12 +68,10 @@ public async Task> Handle(SendEmailCommand request, CancellationTok { return Result.Ok(Unit.Value); } - else - { - string errorMsg = _stringLocalizer["FailedToSendEmailMessage"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + + string errorMsg = _stringLocalizer["FailedToSendEmailMessage"].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(new Error(errorMsg)); } } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Instagram/GetAll/GetAllPostsHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Instagram/GetAll/GetAllPostsHandler.cs deleted file mode 100644 index 44d885850..000000000 --- a/Streetcode/Streetcode.BLL/MediatR/Instagram/GetAll/GetAllPostsHandler.cs +++ /dev/null @@ -1,24 +0,0 @@ -using FluentResults; -using MediatR; -using Streetcode.BLL.Interfaces.Instagram; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.DAL.Entities.Instagram; - -namespace Streetcode.BLL.MediatR.Instagram.GetAll -{ - public class GetAllPostsHandler : IRequestHandler>> - { - private readonly IInstagramService _instagramService; - - public GetAllPostsHandler(IInstagramService instagramService) - { - _instagramService = instagramService; - } - - public async Task>> Handle(GetAllPostsQuery request, CancellationToken cancellationToken) - { - var result = await _instagramService.GetPostsAsync(); - return Result.Ok(result); - } - } -} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Instagram/GetAll/GetAllPostsQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Instagram/GetAll/GetAllPostsQuery.cs deleted file mode 100644 index f5cce0128..000000000 --- a/Streetcode/Streetcode.BLL/MediatR/Instagram/GetAll/GetAllPostsQuery.cs +++ /dev/null @@ -1,7 +0,0 @@ -using FluentResults; -using MediatR; -using Streetcode.DAL.Entities.Instagram; - -namespace Streetcode.BLL.MediatR.Instagram.GetAll; - -public record GetAllPostsQuery : IRequest>>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Media/Image/GetAll/GetAllImagesHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Media/Image/GetAll/GetAllImagesHandler.cs deleted file mode 100644 index 64f6e4144..000000000 --- a/Streetcode/Streetcode.BLL/MediatR/Media/Image/GetAll/GetAllImagesHandler.cs +++ /dev/null @@ -1,50 +0,0 @@ -using AutoMapper; -using FluentResults; -using MediatR; -using Microsoft.Extensions.Localization; -using Streetcode.BLL.DTO.Media.Images; -using Streetcode.BLL.Interfaces.BlobStorage; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Repositories.Interfaces.Base; - -namespace Streetcode.BLL.MediatR.Media.Image.GetAll; - -public class GetAllImagesHandler : IRequestHandler>> -{ - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repositoryWrapper; - private readonly IBlobService _blobService; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerCannotFind; - - public GetAllImagesHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, IBlobService blobService, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) - { - _repositoryWrapper = repositoryWrapper; - _mapper = mapper; - _blobService = blobService; - _logger = logger; - _stringLocalizerCannotFind = stringLocalizerCannotFind; - } - - public async Task>> Handle(GetAllImagesQuery request, CancellationToken cancellationToken) - { - var images = await _repositoryWrapper.ImageRepository.GetAllAsync(); - - if (images is null) - { - string errorMsg = _stringLocalizerCannotFind["CannotFindAnyImage"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } - - var imageDtos = _mapper.Map>(images); - - foreach (var image in imageDtos) - { - image.Base64 = _blobService.FindFileInStorageAsBase64(image.BlobName); - } - - return Result.Ok(imageDtos); - } -} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Media/Image/GetAll/GetAllImagesQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Media/Image/GetAll/GetAllImagesQuery.cs deleted file mode 100644 index db74acdae..000000000 --- a/Streetcode/Streetcode.BLL/MediatR/Media/Image/GetAll/GetAllImagesQuery.cs +++ /dev/null @@ -1,7 +0,0 @@ -using FluentResults; -using MediatR; -using Streetcode.BLL.DTO.Media.Images; - -namespace Streetcode.BLL.MediatR.Media.Image.GetAll; - -public record GetAllImagesQuery : IRequest>>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Partners/GetToUpdateByStreetcodeId/GetPartnersToUpdateByStreetcodeIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Partners/GetToUpdateByStreetcodeId/GetPartnersToUpdateByStreetcodeIdHandler.cs index 2a79134db..d48d5104e 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Partners/GetToUpdateByStreetcodeId/GetPartnersToUpdateByStreetcodeIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Partners/GetToUpdateByStreetcodeId/GetPartnersToUpdateByStreetcodeIdHandler.cs @@ -32,11 +32,12 @@ public async Task>> Handle(GetPartnersToUpdateByS predicate: p => p.Streetcodes.Any(sc => sc.Id == request.StreetcodeId), include: p => p.Include(pl => pl.PartnerSourceLinks)); + // even if there are no partners, we still want to return an empty enumerable if (!partners.Any()) { - string errorMsg = _stringLocalizerCannotFind["CannotFindPartnersByStreetcodeId", request.StreetcodeId].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); + string message = "Returning empty enumerable of partners to update"; + _logger.LogInformation(message); + return Result.Ok(Enumerable.Empty()); } return Result.Ok(value: _mapper.Map>(partners)); diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Create/CreateFactCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Create/CreateFactCommand.cs index afe8173c0..fbb98a772 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Create/CreateFactCommand.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Create/CreateFactCommand.cs @@ -4,4 +4,5 @@ namespace Streetcode.BLL.MediatR.Streetcode.Fact.Create; -public record CreateFactCommand(StreetcodeFactCreateDTO Fact) : IRequest>; \ No newline at end of file +public record CreateFactCommand(StreetcodeFactCreateDTO Fact) + : IRequest>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Create/CreateFactHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Create/CreateFactHandler.cs index 0ac08f331..44c7c572f 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Create/CreateFactHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Create/CreateFactHandler.cs @@ -5,6 +5,7 @@ using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; +using FactEntity = Streetcode.DAL.Entities.Streetcode.TextContent.Fact; namespace Streetcode.BLL.MediatR.Streetcode.Fact.Create; @@ -32,27 +33,25 @@ public CreateFactHandler( public async Task> Handle(CreateFactCommand request, CancellationToken cancellationToken) { - var fact = _mapper.Map(request.Fact); + var fact = _mapper.Map(request.Fact); if (fact is null) { - string errorMsg = _stringLocalizerCannot["CannotConvertNullToFact"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); + var errorMessage = _stringLocalizerCannot["CannotConvertNullToFact"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } - _repositoryWrapper.FactRepository.Create(fact); - + await _repositoryWrapper.FactRepository.CreateAsync(fact); var resultIsSuccess = await _repositoryWrapper.SaveChangesAsync() > 0; - if (resultIsSuccess) - { - return Result.Ok(Unit.Value); - } - else + + if (!resultIsSuccess) { - string errorMsg = _stringLocalizerFailed["FailedToCreateFact"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); + var errorMessage = _stringLocalizerFailed["FailedToCreateFact"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } + + return Result.Ok(Unit.Value); } -} \ No newline at end of file +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Delete/DeleteFactCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Delete/DeleteFactCommand.cs index e0d1d2715..d4a63f69d 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Delete/DeleteFactCommand.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Delete/DeleteFactCommand.cs @@ -4,4 +4,4 @@ namespace Streetcode.BLL.MediatR.Streetcode.Fact.Delete; public record DeleteFactCommand(int Id) - : IRequest>; \ No newline at end of file + : IRequest>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Delete/DeleteFactHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Delete/DeleteFactHandler.cs index a5ab05a15..a12ab4091 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Delete/DeleteFactHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Delete/DeleteFactHandler.cs @@ -28,27 +28,25 @@ public DeleteFactHandler( public async Task> Handle(DeleteFactCommand request, CancellationToken cancellationToken) { - var fact = await _repositoryWrapper.FactRepository.GetFirstOrDefaultAsync(f => f.Id == request.Id); + var fact = await _repositoryWrapper.FactRepository.GetFirstOrDefaultAsync(x => x.Id == request.Id); if (fact is null) { - string errorMsg = _stringLocalizerCannotFind["CannotFindFactWithCorrespondingCategoryId", request.Id].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); + var errorMessage = _stringLocalizerCannotFind["CannotFindFactWithCorrespondingCategoryId", request.Id].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } _repositoryWrapper.FactRepository.Delete(fact); - var resultIsSuccess = await _repositoryWrapper.SaveChangesAsync() > 0; - if (resultIsSuccess) - { - return Result.Ok(Unit.Value); - } - else + + if (!resultIsSuccess) { - string errorMsg = _stringLocalizerFailedToDelete["FailedToDeleteFact"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); + var errorMessage = _stringLocalizerFailedToDelete["FailedToDeleteFact"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } + + return Result.Ok(Unit.Value); } -} \ No newline at end of file +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetAll/GetAllFactsHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetAll/GetAllFactsHandler.cs index ee2170cf5..301c0d440 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetAll/GetAllFactsHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetAll/GetAllFactsHandler.cs @@ -1,10 +1,7 @@ using AutoMapper; using FluentResults; using MediatR; -using Microsoft.Extensions.Localization; using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; namespace Streetcode.BLL.MediatR.Streetcode.Fact.GetAll; @@ -13,28 +10,17 @@ public class GetAllFactsHandler : IRequestHandler _stringLocalizeCannotFind; - public GetAllFactsHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizeCannotFind) + public GetAllFactsHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper) { _repositoryWrapper = repositoryWrapper; _mapper = mapper; - _logger = logger; - _stringLocalizeCannotFind = stringLocalizeCannotFind; } public async Task>> Handle(GetAllFactsQuery request, CancellationToken cancellationToken) { var facts = await _repositoryWrapper.FactRepository.GetAllAsync(); - if (facts is null) - { - string errorMsg = _stringLocalizeCannotFind["CannotFindAnyFact"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } - return Result.Ok(_mapper.Map>(facts)); } -} \ No newline at end of file +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetAll/GetAllFactsQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetAll/GetAllFactsQuery.cs index b261ec871..b09e38ffd 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetAll/GetAllFactsQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetAll/GetAllFactsQuery.cs @@ -4,4 +4,5 @@ namespace Streetcode.BLL.MediatR.Streetcode.Fact.GetAll; -public record GetAllFactsQuery : IRequest>>; \ No newline at end of file +public record GetAllFactsQuery + : IRequest>>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetById/GetFactByIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetById/GetFactByIdHandler.cs index 101fc2402..ea1fe2437 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetById/GetFactByIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetById/GetFactByIdHandler.cs @@ -16,7 +16,11 @@ public class GetFactByIdHandler : IRequestHandler _stringLocalizerCannotFind; - public GetFactByIdHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) + public GetFactByIdHandler( + IRepositoryWrapper repositoryWrapper, + IMapper mapper, + ILoggerService logger, + IStringLocalizer stringLocalizerCannotFind) { _repositoryWrapper = repositoryWrapper; _mapper = mapper; @@ -26,15 +30,15 @@ public GetFactByIdHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, public async Task> Handle(GetFactByIdQuery request, CancellationToken cancellationToken) { - var facts = await _repositoryWrapper.FactRepository.GetFirstOrDefaultAsync(f => f.Id == request.Id); + var facts = await _repositoryWrapper.FactRepository.GetFirstOrDefaultAsync(x => x.Id == request.Id); if (facts is null) { - string errorMsg = _stringLocalizerCannotFind["CannotFindFactWithCorrespondingCategoryId", request.Id].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); + var errorMessage = _stringLocalizerCannotFind["CannotFindFactWithCorrespondingCategoryId", request.Id].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } return Result.Ok(_mapper.Map(facts)); } -} \ No newline at end of file +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetByStreetcodeId/GetFactByStreetcodeIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetByStreetcodeId/GetFactByStreetcodeIdHandler.cs index 5f737290a..935989625 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetByStreetcodeId/GetFactByStreetcodeIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetByStreetcodeId/GetFactByStreetcodeIdHandler.cs @@ -16,7 +16,11 @@ public class GetFactByStreetcodeIdHandler : IRequestHandler _stringLocalizerCannotFind; - public GetFactByStreetcodeIdHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) + public GetFactByStreetcodeIdHandler( + IRepositoryWrapper repositoryWrapper, + IMapper mapper, + ILoggerService logger, + IStringLocalizer stringLocalizerCannotFind) { _repositoryWrapper = repositoryWrapper; _mapper = mapper; @@ -26,16 +30,16 @@ public GetFactByStreetcodeIdHandler(IRepositoryWrapper repositoryWrapper, IMappe public async Task>> Handle(GetFactByStreetcodeIdQuery request, CancellationToken cancellationToken) { - var facts = await _repositoryWrapper.FactRepository - .GetAllAsync(f => f.StreetcodeId == request.StreetcodeId); + var facts = await _repositoryWrapper.FactRepository.GetAllAsync(x => x.StreetcodeId == request.StreetcodeId); + var factsList = facts.ToList(); - if (!facts.Any()) + if (!factsList.Any()) { - string message = "Returning empty enumerable of facts"; - _logger.LogInformation(message); + var infoMessage = _stringLocalizerCannotFind["CannotFindAnyFact"].Value; + _logger.LogInformation(infoMessage); return Result.Ok(Enumerable.Empty()); } - return Result.Ok(_mapper.Map>(facts.OrderBy(f => f.Index))); + return Result.Ok(_mapper.Map>(factsList.OrderBy(f => f.Index))); } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetByStreetcodeId/GetFactByStreetcodeIdQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetByStreetcodeId/GetFactByStreetcodeIdQuery.cs index f30d04d64..a5be27954 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetByStreetcodeId/GetFactByStreetcodeIdQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/GetByStreetcodeId/GetFactByStreetcodeIdQuery.cs @@ -5,4 +5,4 @@ namespace Streetcode.BLL.MediatR.Streetcode.Fact.GetByStreetcodeId; public record GetFactByStreetcodeIdQuery(int StreetcodeId) - : IRequest>>; \ No newline at end of file + : IRequest>>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Update/UpdateFactCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Update/UpdateFactCommand.cs index 92541e4ca..83b81f650 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Update/UpdateFactCommand.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Update/UpdateFactCommand.cs @@ -4,5 +4,5 @@ namespace Streetcode.BLL.MediatR.Streetcode.Fact.Update; -public record UpdateFactCommand(FactDto Fact) - : IRequest>; \ No newline at end of file +public record UpdateFactCommand(StreetcodeFactUpdateDTO Fact) + : IRequest>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Update/UpdateFactHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Update/UpdateFactHandler.cs index 92de321d5..c55a86999 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Update/UpdateFactHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Fact/Update/UpdateFactHandler.cs @@ -5,6 +5,7 @@ using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; +using FactEntity = Streetcode.DAL.Entities.Streetcode.TextContent.Fact; namespace Streetcode.BLL.MediatR.Streetcode.Fact.Update; @@ -32,27 +33,25 @@ public UpdateFactHandler( public async Task> Handle(UpdateFactCommand request, CancellationToken cancellationToken) { - var fact = _mapper.Map(request.Fact); + var fact = _mapper.Map(request.Fact); if (fact is null) { - string errorMsg = _stringLocalizerCannotConvert["CannotConvertNullToFact"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); + var errorMessage = _stringLocalizerCannotConvert["CannotConvertNullToFact"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } _repositoryWrapper.FactRepository.Update(fact); - var resultIsSuccess = await _repositoryWrapper.SaveChangesAsync() > 0; - if(resultIsSuccess) - { - return Result.Ok(Unit.Value); - } - else + + if (!resultIsSuccess) { - string errorMsg = _stringLocalizerFailedToUpdate["FailedToUpdateFact"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); + var errorMessage = _stringLocalizerFailedToUpdate["FailedToUpdateFact"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } + + return Result.Ok(Unit.Value); } -} \ No newline at end of file +} diff --git "a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/\320\241reate/CreateRelatedFigureCommand.cs" b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/Create/CreateRelatedFigureCommand.cs similarity index 100% rename from "Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/\320\241reate/CreateRelatedFigureCommand.cs" rename to Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/Create/CreateRelatedFigureCommand.cs diff --git "a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/\320\241reate/CreateRelatedFigureHandler.cs" b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/Create/CreateRelatedFigureHandler.cs similarity index 76% rename from "Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/\320\241reate/CreateRelatedFigureHandler.cs" rename to Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/Create/CreateRelatedFigureHandler.cs index b22f24b0e..9050b5eae 100644 --- "a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/\320\241reate/CreateRelatedFigureHandler.cs" +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/Create/CreateRelatedFigureHandler.cs @@ -1,29 +1,27 @@ -using AutoMapper; -using FluentResults; +using FluentResults; using MediatR; using Microsoft.Extensions.Localization; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; +using Entity = Streetcode.DAL.Entities.Streetcode.RelatedFigure; namespace Streetcode.BLL.MediatR.Streetcode.RelatedFigure.Create; public class CreateRelatedFigureHandler : IRequestHandler> { - private readonly IMapper _mapper; private readonly IRepositoryWrapper _repositoryWrapper; private readonly ILoggerService _logger; private readonly IStringLocalizer _stringLocalizerNo; private readonly IStringLocalizer _stringLocalizerFailed; + public CreateRelatedFigureHandler( IRepositoryWrapper repositoryWrapper, - IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerNo, IStringLocalizer stringLocalizerFailed) { _repositoryWrapper = repositoryWrapper; - _mapper = mapper; _logger = logger; _stringLocalizerFailed = stringLocalizerFailed; _stringLocalizerNo = stringLocalizerNo; @@ -36,14 +34,14 @@ public async Task> Handle(CreateRelatedFigureCommand request, Cance if (observerEntity is null) { - string errorMsg = _stringLocalizerNo["NoExistingStreetcodeWithId", request.ObserverId].Value; + var errorMsg = _stringLocalizerNo["NoExistingStreetcodeWithId", request.ObserverId].Value; _logger.LogError(request, errorMsg); return Result.Fail(new Error(errorMsg)); } if (targetEntity is null) { - string errorMsg = _stringLocalizerNo["NoExistingStreetcodeWithId", request.TargetId].Value; + var errorMsg = _stringLocalizerNo["NoExistingStreetcodeWithId", request.TargetId].Value; _logger.LogError(request, errorMsg); return Result.Fail(new Error(errorMsg)); } @@ -54,29 +52,27 @@ public async Task> Handle(CreateRelatedFigureCommand request, Cance if (existingRelation is not null) { - string errorMsg = _stringLocalizerFailed["TheStreetcodesAreAlreadyLinked"].Value; + var errorMsg = _stringLocalizerFailed["TheStreetcodesAreAlreadyLinked"].Value; _logger.LogError(request, errorMsg); return Result.Fail(new Error(errorMsg)); } - var relation = new DAL.Entities.Streetcode.RelatedFigure + var relation = new Entity { ObserverId = observerEntity.Id, TargetId = targetEntity.Id, }; - _repositoryWrapper.RelatedFigureRepository.Create(relation); + await _repositoryWrapper.RelatedFigureRepository.CreateAsync(relation); var resultIsSuccess = await _repositoryWrapper.SaveChangesAsync() > 0; if(resultIsSuccess) { return Result.Ok(Unit.Value); } - else - { - string errorMsg = _stringLocalizerFailed["FailedToCreateRelation"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + + var finalErrorMsg = _stringLocalizerFailed["FailedToCreateRelation"].Value; + _logger.LogError(request, finalErrorMsg); + return Result.Fail(new Error(finalErrorMsg)); } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/Delete/DeleteRelatedFigureHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/Delete/DeleteRelatedFigureHandler.cs index 60f200b17..d63bb7de6 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/Delete/DeleteRelatedFigureHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/Delete/DeleteRelatedFigureHandler.cs @@ -29,13 +29,13 @@ public DeleteRelatedFigureHandler( public async Task> Handle(DeleteRelatedFigureCommand request, CancellationToken cancellationToken) { var relation = await _repositoryWrapper.RelatedFigureRepository - .GetFirstOrDefaultAsync(rel => - rel.ObserverId == request.ObserverId && - rel.TargetId == request.TargetId); + .GetFirstOrDefaultAsync(rel => + rel.ObserverId == request.ObserverId && + rel.TargetId == request.TargetId); if (relation is null) { - string errorMsg = _stringLocalizerCannotFind["CannotFindRelationBetweenStreetcodesWithCorrespondingIds", request.ObserverId, request.TargetId].Value; + var errorMsg = _stringLocalizerCannotFind["CannotFindRelationBetweenStreetcodesWithCorrespondingIds", request.ObserverId, request.TargetId].Value; _logger.LogError(request, errorMsg); return Result.Fail(new Error(errorMsg)); } @@ -47,11 +47,9 @@ public async Task> Handle(DeleteRelatedFigureCommand request, Cance { return Result.Ok(Unit.Value); } - else - { - string errorMsg = _stringLocalizerFailedToDelete["FailedToDeleteRelation"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + + var finalErrorMsg = _stringLocalizerFailedToDelete["FailedToDeleteRelation"].Value; + _logger.LogError(request, finalErrorMsg); + return Result.Fail(new Error(finalErrorMsg)); } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByStreetcodeId/GetRelatedFiguresByStreetcodeIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByStreetcodeId/GetRelatedFiguresByStreetcodeIdHandler.cs index bf4687d1e..fea4ded80 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByStreetcodeId/GetRelatedFiguresByStreetcodeIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByStreetcodeId/GetRelatedFiguresByStreetcodeIdHandler.cs @@ -3,65 +3,64 @@ using FluentResults; using MediatR; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Localization; using Streetcode.BLL.DTO.Streetcode.RelatedFigure; -using Streetcode.DAL.Entities.Streetcode; using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Enums; using Streetcode.DAL.Repositories.Interfaces.Base; namespace Streetcode.BLL.MediatR.Streetcode.RelatedFigure.GetByStreetcodeId; -public class GetRelatedFiguresByStreetcodeIdHandler : IRequestHandler?>> +public class GetRelatedFiguresByStreetcodeIdHandler : IRequestHandler>> { private readonly IMapper _mapper; private readonly IRepositoryWrapper _repositoryWrapper; private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerCannotFind; - public GetRelatedFiguresByStreetcodeIdHandler(IMapper mapper, IRepositoryWrapper repositoryWrapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) + public GetRelatedFiguresByStreetcodeIdHandler( + IMapper mapper, + IRepositoryWrapper repositoryWrapper, + ILoggerService logger) { _mapper = mapper; _repositoryWrapper = repositoryWrapper; _logger = logger; - _stringLocalizerCannotFind = stringLocalizerCannotFind; } // If you use Rider instead of Visual Studio, for example, "SuppressMessage" attribute suppresses PossibleMultipleEnumeration warning [SuppressMessage("ReSharper", "PossibleMultipleEnumeration", Justification = "Here is no sense to do materialization of query because of nested ToListAsync method in GetAllAsync method")] - public async Task?>> Handle(GetRelatedFigureByStreetcodeIdQuery request, CancellationToken cancellationToken) + public async Task>> Handle(GetRelatedFigureByStreetcodeIdQuery request, CancellationToken cancellationToken) { var relatedFigureIds = GetRelatedFigureIdsByStreetcodeId(request.StreetcodeId); if (!relatedFigureIds.Any()) { - string message = "Returning empty enumerable of related figures"; + const string message = "Returning empty enumerable of related figures"; _logger.LogInformation(message); return Result.Ok(Enumerable.Empty()); } var relatedFigures = await _repositoryWrapper.StreetcodeRepository.GetAllAsync( - predicate: sc => relatedFigureIds.Any(id => id == sc.Id) && sc.Status == DAL.Enums.StreetcodeStatus.Published, - include: scl => scl.Include(sc => sc.Images).ThenInclude(img => img.ImageDetails) - .Include(sc => sc.Tags)); + predicate: sc => relatedFigureIds.Any(id => id == sc.Id) && sc.Status == StreetcodeStatus.Published, + include: scl => scl + .Include(sc => sc.Images) + .ThenInclude(img => img.ImageDetails) + .Include(sc => sc.Tags)); - if (!relatedFigures.Any()) + if (!relatedFigureIds.Any()) { - string errorMsg = _stringLocalizerCannotFind["CannotFindAnyRelatedFiguresByStreetcodeId", request.StreetcodeId].Value; - _logger.LogError(request, errorMsg); - - return Result.Fail(new Error(errorMsg)); + const string message = "Returning empty enumerable of related figures"; + _logger.LogInformation(message); + return Result.Ok(Enumerable.Empty()); } - foreach(StreetcodeContent streetcode in relatedFigures) + foreach(var streetcode in relatedFigures) { - if(streetcode.Images != null) - { - streetcode.Images = streetcode.Images.OrderBy(img => img.ImageDetails?.Alt).ToList(); - } + streetcode.Images = streetcode.Images.OrderBy(img => img.ImageDetails?.Alt).ToList(); } - return Result.Ok?>(_mapper.Map>(relatedFigures)); + var relatedFigureDto = _mapper.Map>(relatedFigures); + + return Result.Ok(relatedFigureDto); } private IQueryable GetRelatedFigureIdsByStreetcodeId(int streetcodeId) @@ -69,7 +68,7 @@ private IQueryable GetRelatedFigureIdsByStreetcodeId(int streetcodeId) try { var observerIds = _repositoryWrapper.RelatedFigureRepository - .FindAll(f => f.TargetId == streetcodeId).Select(o => o.ObserverId); + .FindAll(f => f.TargetId == streetcodeId).Select(o => o.ObserverId); var targetIds = _repositoryWrapper.RelatedFigureRepository .FindAll(f => f.ObserverId == streetcodeId).Select(t => t.TargetId); diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByStreetcodeId/GetRelatedFiguresByStreetcodeIdQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByStreetcodeId/GetRelatedFiguresByStreetcodeIdQuery.cs index 5cb595066..bd4fd3b21 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByStreetcodeId/GetRelatedFiguresByStreetcodeIdQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByStreetcodeId/GetRelatedFiguresByStreetcodeIdQuery.cs @@ -5,4 +5,4 @@ namespace Streetcode.BLL.MediatR.Streetcode.RelatedFigure.GetByStreetcodeId; public record GetRelatedFigureByStreetcodeIdQuery(int StreetcodeId) - : IRequest?>>; + : IRequest>>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByTagId/GetRelatedFiguresByTagIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByTagId/GetRelatedFiguresByTagIdHandler.cs index 1cecf410e..a82fb5206 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByTagId/GetRelatedFiguresByTagIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByTagId/GetRelatedFiguresByTagIdHandler.cs @@ -3,57 +3,61 @@ using FluentResults; using MediatR; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Localization; using Streetcode.BLL.DTO.Streetcode.RelatedFigure; using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; using Streetcode.DAL.Enums; -namespace Streetcode.BLL.MediatR.Streetcode.RelatedFigure.GetByTagId +namespace Streetcode.BLL.MediatR.Streetcode.RelatedFigure.GetByTagId; + +public class GetRelatedFiguresByTagIdHandler : IRequestHandler>> { - internal class GetRelatedFiguresByTagIdHandler : IRequestHandler?>> - { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repositoryWrapper; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerCannotFind; + private readonly IMapper _mapper; + private readonly IRepositoryWrapper _repositoryWrapper; + private readonly ILoggerService _logger; - public GetRelatedFiguresByTagIdHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) - { - _repositoryWrapper = repositoryWrapper; - _mapper = mapper; - _logger = logger; - _stringLocalizerCannotFind = stringLocalizerCannotFind; - } + public GetRelatedFiguresByTagIdHandler( + IRepositoryWrapper repositoryWrapper, + IMapper mapper, + ILoggerService logger) + { + _repositoryWrapper = repositoryWrapper; + _mapper = mapper; + _logger = logger; + } - // If you use Rider instead of Visual Studio, for example, "SuppressMessage" attribute suppresses PossibleMultipleEnumeration warning - [SuppressMessage("ReSharper", "PossibleMultipleEnumeration", Justification = "Here is no sense to do materialization of query because of nested ToListAsync method in GetAllAsync method")] - public async Task?>> Handle(GetRelatedFiguresByTagIdQuery request, CancellationToken cancellationToken) - { - var streetcodes = await _repositoryWrapper.StreetcodeRepository - .GetAllAsync( - predicate: sc => sc.Status == DAL.Enums.StreetcodeStatus.Published && - sc.Tags.Select(t => t.Id).Any(tag => tag == request.TagId), + // If you use Rider instead of Visual Studio, for example, "SuppressMessage" attribute suppresses PossibleMultipleEnumeration warning + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration", Justification = "Here is no sense to do materialization of query because of nested ToListAsync method in GetAllAsync method")] + public async Task>> Handle(GetRelatedFiguresByTagIdQuery request, CancellationToken cancellationToken) + { + var streetcodes = await _repositoryWrapper.StreetcodeRepository + .GetAllAsync( + predicate: sc => sc.Status == StreetcodeStatus.Published && + sc.Tags + .Select(t => t.Id) + .Any(tag => tag == request.TagId), include: scl => scl - .Include(sc => sc.Images).ThenInclude(x => x.ImageDetails) + .Include(sc => sc.Images) + .ThenInclude(x => x.ImageDetails) .Include(sc => sc.Tags)); - const int blackAndWhiteImageAssignmentKey = (int)ImageAssigment.Blackandwhite; - foreach (var streetcode in streetcodes) - { - streetcode.Images = streetcode.Images.Where(x => x.ImageDetails != null && x.ImageDetails.Alt!.Equals(blackAndWhiteImageAssignmentKey.ToString())).ToList(); - } + if (!streetcodes.Any()) + { + const string message = "Returning empty enumerable of related figures"; + _logger.LogInformation(message); + return Result.Ok(Enumerable.Empty()); + } - if (!streetcodes.Any()) - { - string errorMsg = _stringLocalizerCannotFind["CannotFindAnyFactWithCorrespondingId", request.TagId].Value; - _logger.LogError(request, errorMsg); + const int blackAndWhiteImageAssignmentKey = (int)ImageAssigment.Blackandwhite; + foreach (var streetcode in streetcodes) + { + streetcode.Images = streetcode.Images + .Where(x => x.ImageDetails != null && x.ImageDetails.Alt!.Equals(blackAndWhiteImageAssignmentKey.ToString())) + .ToList(); + } - return Result.Ok?>(null); - } + var relatedFigureDtos = _mapper.Map>(streetcodes); - return Result.Ok?>(_mapper.Map>(streetcodes)); - } + return Result.Ok(relatedFigureDtos); } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByTagId/GetRelatedFiguresByTagIdQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByTagId/GetRelatedFiguresByTagIdQuery.cs index 02dfc35e1..46642c4ab 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByTagId/GetRelatedFiguresByTagIdQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedFigure/GetByTagId/GetRelatedFiguresByTagIdQuery.cs @@ -5,5 +5,5 @@ namespace Streetcode.BLL.MediatR.Streetcode.RelatedFigure.GetByTagId { public record GetRelatedFiguresByTagIdQuery(int TagId) - : IRequest?>>; + : IRequest>>; } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Create/CreateRelatedTermCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Create/CreateRelatedTermCommand.cs index 877294e4f..3c9c1d1b4 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Create/CreateRelatedTermCommand.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Create/CreateRelatedTermCommand.cs @@ -2,8 +2,7 @@ using MediatR; using Streetcode.BLL.DTO.Streetcode.TextContent; -namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Create -{ - public record CreateRelatedTermCommand(RelatedTermCreateDTO RelatedTerm) - : IRequest>; -} +namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Create; + +public record CreateRelatedTermCommand(RelatedTermCreateDTO RelatedTerm) + : IRequest>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Create/CreateRelatedTermHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Create/CreateRelatedTermHandler.cs index 25e4bc7bb..e24cbf014 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Create/CreateRelatedTermHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Create/CreateRelatedTermHandler.cs @@ -6,84 +6,78 @@ using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; +using RelatedTermEntity = Streetcode.DAL.Entities.Streetcode.TextContent.RelatedTerm; -using Entity = Streetcode.DAL.Entities.Streetcode.TextContent.RelatedTerm; +namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Create; -namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Create +public class CreateRelatedTermHandler : IRequestHandler> { - public class CreateRelatedTermHandler : IRequestHandler> + private readonly IRepositoryWrapper _repository; + private readonly IMapper _mapper; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerCannotCreate; + private readonly IStringLocalizer _stringLocalizerCannotSave; + private readonly IStringLocalizer _stringLocalizerCannotMap; + private readonly IStringLocalizer _stringLocalizer; + + public CreateRelatedTermHandler( + IRepositoryWrapper repository, + IMapper mapper, + ILoggerService logger, + IStringLocalizer stringLocalizerCannotSave, + IStringLocalizer stringLocalizerCannotMap, + IStringLocalizer stringLocalizer, + IStringLocalizer stringLocalizerCannotCreate) { - private readonly IRepositoryWrapper _repository; - private readonly IMapper _mapper; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerCannotCreate; - private readonly IStringLocalizer _stringLocalizerCannotSave; - private readonly IStringLocalizer _stringLocalizerCannotMap; - private readonly IStringLocalizer _stringLocalizer; + _repository = repository; + _mapper = mapper; + _logger = logger; + _stringLocalizerCannotSave = stringLocalizerCannotSave; + _stringLocalizerCannotMap = stringLocalizerCannotMap; + _stringLocalizer = stringLocalizer; + _stringLocalizerCannotCreate = stringLocalizerCannotCreate; + } - public CreateRelatedTermHandler( - IRepositoryWrapper repository, - IMapper mapper, - ILoggerService logger, - IStringLocalizer stringLocalizerCannotSave, - IStringLocalizer stringLocalizerCannotMap, - IStringLocalizer stringLocalizer, - IStringLocalizer stringLocalizerCannotCreate) - { - _repository = repository; - _mapper = mapper; - _logger = logger; - _stringLocalizerCannotSave = stringLocalizerCannotSave; - _stringLocalizerCannotMap = stringLocalizerCannotMap; - _stringLocalizer = stringLocalizer; - _stringLocalizerCannotCreate = stringLocalizerCannotCreate; - } + public async Task> Handle(CreateRelatedTermCommand request, CancellationToken cancellationToken) + { + var relatedTerm = _mapper.Map(request.RelatedTerm); - public async Task> Handle(CreateRelatedTermCommand request, CancellationToken cancellationToken) + if (relatedTerm is null) { - var relatedTerm = _mapper.Map(request.RelatedTerm); - - if (relatedTerm is null) - { - string errorMsg = _stringLocalizerCannotCreate["CannotCreateNewRelatedWordForTerm"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } - - var existingTerms = await _repository.RelatedTermRepository - .GetAllAsync( - predicate: rt => rt.TermId == request.RelatedTerm.TermId && rt.Word == request.RelatedTerm.Word); + var errorMessage = _stringLocalizerCannotCreate["CannotCreateNewRelatedWordForTerm"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); + } - if (existingTerms is null || existingTerms.Any()) - { - string errorMsg = _stringLocalizer["WordWithThisDefinitionAlreadyExists"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + var existingTerms = await _repository.RelatedTermRepository + .GetAllAsync(x => x.TermId == request.RelatedTerm.TermId && x.Word == request.RelatedTerm.Word); - var createdRelatedTerm = _repository.RelatedTermRepository.Create(relatedTerm); + if (existingTerms.Any()) + { + var errorMessage = _stringLocalizer["WordWithThisDefinitionAlreadyExists"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); + } - var isSuccessResult = await _repository.SaveChangesAsync() > 0; + var createdRelatedTerm = await _repository.RelatedTermRepository.CreateAsync(relatedTerm); + var isSuccessResult = await _repository.SaveChangesAsync() > 0; - if(!isSuccessResult) - { - string errorMsg = _stringLocalizerCannotSave["CannotSaveChangesInTheDatabaseAfterRelatedWordCreation"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + if (!isSuccessResult) + { + var errorMessage = _stringLocalizerCannotSave["CannotSaveChangesInTheDatabaseAfterRelatedWordCreation"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); + } - var createdRelatedTermDTO = _mapper.Map(createdRelatedTerm); + var createdRelatedTermDTO = _mapper.Map(createdRelatedTerm); - if(createdRelatedTermDTO != null) - { - return Result.Ok(createdRelatedTermDTO); - } - else - { - string errorMsg = _stringLocalizerCannotMap["CannotMapEntity"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + if (createdRelatedTermDTO is null) + { + var errorMessage = _stringLocalizerCannotMap["CannotMapEntity"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } + + return Result.Ok(createdRelatedTermDTO); } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Delete/DeleteRelatedTermCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Delete/DeleteRelatedTermCommand.cs index 23e4a82c0..055424624 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Delete/DeleteRelatedTermCommand.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Delete/DeleteRelatedTermCommand.cs @@ -2,8 +2,7 @@ using MediatR; using Streetcode.BLL.DTO.Streetcode.TextContent; -namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Delete -{ - public record DeleteRelatedTermCommand(string word) - : IRequest>; -} +namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Delete; + +public record DeleteRelatedTermCommand(string Word) + : IRequest>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Delete/DeleteRelatedTermHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Delete/DeleteRelatedTermHandler.cs index e81da18b1..75e263364 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Delete/DeleteRelatedTermHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Delete/DeleteRelatedTermHandler.cs @@ -7,55 +7,52 @@ using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Delete +namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Delete; + +public class DeleteRelatedTermHandler : IRequestHandler> { - public class DeleteRelatedTermHandler : IRequestHandler> + private readonly IRepositoryWrapper _repository; + private readonly IMapper _mapper; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerCannotFind; + private readonly IStringLocalizer _stringLocalizerFailedToDelete; + + public DeleteRelatedTermHandler( + IRepositoryWrapper repository, + IMapper mapper, + ILoggerService logger, + IStringLocalizer stringLocalizerFailedToDelete, + IStringLocalizer stringLocalizerCannotFind) + { + _repository = repository; + _mapper = mapper; + _logger = logger; + _stringLocalizerFailedToDelete = stringLocalizerFailedToDelete; + _stringLocalizerCannotFind = stringLocalizerCannotFind; + } + + public async Task> Handle(DeleteRelatedTermCommand request, CancellationToken cancellationToken) { - private readonly IRepositoryWrapper _repository; - private readonly IMapper _mapper; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerCannotFind; - private readonly IStringLocalizer _stringLocalizerFailedToDelete; - - public DeleteRelatedTermHandler( - IRepositoryWrapper repository, - IMapper mapper, - ILoggerService logger, - IStringLocalizer stringLocalizerFailedToDelete, - IStringLocalizer stringLocalizerCannotFind) + var relatedTerm = await _repository.RelatedTermRepository.GetFirstOrDefaultAsync(x => x.Word!.ToLower().Equals(request.Word.ToLower())); + + if (relatedTerm is null) { - _repository = repository; - _mapper = mapper; - _logger = logger; - _stringLocalizerFailedToDelete = stringLocalizerFailedToDelete; - _stringLocalizerCannotFind = stringLocalizerCannotFind; + var errorMessage = _stringLocalizerCannotFind["CannotFindRelatedTermWithCorrespondingId", request.Word].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } - public async Task> Handle(DeleteRelatedTermCommand request, CancellationToken cancellationToken) + _repository.RelatedTermRepository.Delete(relatedTerm); + var resultIsSuccess = await _repository.SaveChangesAsync() > 0; + var relatedTermDto = _mapper.Map(relatedTerm); + + if (!resultIsSuccess || relatedTermDto is null) { - var relatedTerm = await _repository.RelatedTermRepository.GetFirstOrDefaultAsync(rt => rt.Word!.ToLower().Equals(request.word.ToLower())); - - if (relatedTerm is null) - { - string errorMsg = _stringLocalizerCannotFind["CannotFindRelatedTermWithCorrespondingId", request.word].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } - - _repository.RelatedTermRepository.Delete(relatedTerm); - - var resultIsSuccess = await _repository.SaveChangesAsync() > 0; - var relatedTermDto = _mapper.Map(relatedTerm); - if(resultIsSuccess && relatedTermDto != null) - { - return Result.Ok(relatedTermDto); - } - else - { - string errorMsg = _stringLocalizerFailedToDelete["FailedToDeleteRelatedTerm"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + var errorMessage = _stringLocalizerFailedToDelete["FailedToDeleteRelatedTerm"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } + + return Result.Ok(relatedTermDto); } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/GetAll/GetAllRelatedTermsQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/GetAll/GetAllRelatedTermsQuery.cs deleted file mode 100644 index 6f01cccf0..000000000 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/GetAll/GetAllRelatedTermsQuery.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.GetAll -{ - internal class GetAllRelatedTermsQuery - { - } -} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/GetAllByTermId/GetAllRelatedTermsByTermIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/GetAllByTermId/GetAllRelatedTermsByTermIdHandler.cs index 1c9f3ebf9..75b9cf0aa 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/GetAllByTermId/GetAllRelatedTermsByTermIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/GetAllByTermId/GetAllRelatedTermsByTermIdHandler.cs @@ -8,54 +8,42 @@ using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.GetAllByTermId -{ - public record GetAllRelatedTermsByTermIdHandler : IRequestHandler>> - { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repository; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerCannotGet; - private readonly IStringLocalizer _stringLocalizerCannotCreate; - - public GetAllRelatedTermsByTermIdHandler( - IMapper mapper, - IRepositoryWrapper repositoryWrapper, - ILoggerService logger, - IStringLocalizer stringLocalizerCannotGet, - IStringLocalizer stringLocalizerCannotCreate) - { - _mapper = mapper; - _repository = repositoryWrapper; - _logger = logger; - _stringLocalizerCannotCreate = stringLocalizerCannotCreate; - _stringLocalizerCannotGet = stringLocalizerCannotGet; - } +namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.GetAllByTermId; - public async Task>> Handle(GetAllRelatedTermsByTermIdQuery request, CancellationToken cancellationToken) - { - var relatedTerms = await _repository.RelatedTermRepository - .GetAllAsync( - predicate: rt => rt.TermId == request.id, - include: rt => rt.Include(rt => rt.Term!)); +public record GetAllRelatedTermsByTermIdHandler : IRequestHandler>> +{ + private readonly IMapper _mapper; + private readonly IRepositoryWrapper _repository; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerCannotCreate; - if (relatedTerms is null) - { - string errorMsg = _stringLocalizerCannotGet["CannotGetWordsByTermId"].Value; - _logger.LogError(request, errorMsg); - return new Error(errorMsg); - } + public GetAllRelatedTermsByTermIdHandler( + IMapper mapper, + IRepositoryWrapper repositoryWrapper, + ILoggerService logger, + IStringLocalizer stringLocalizerCannotCreate) + { + _mapper = mapper; + _repository = repositoryWrapper; + _logger = logger; + _stringLocalizerCannotCreate = stringLocalizerCannotCreate; + } - var relatedTermsDTO = _mapper.Map>(relatedTerms); + public async Task>> Handle(GetAllRelatedTermsByTermIdQuery request, CancellationToken cancellationToken) + { + var relatedTerms = await _repository.RelatedTermRepository.GetAllAsync( + x => x.TermId == request.Id, + x => x.Include(rt => rt.Term!)); - if (relatedTermsDTO is null) - { - string errorMsg = _stringLocalizerCannotCreate["CannotCreateDTOsForRelatedWords"].Value; - _logger.LogError(request, errorMsg); - return new Error(errorMsg); - } + var relatedTermsDto = _mapper.Map>(relatedTerms); - return Result.Ok(relatedTermsDTO); + if (relatedTermsDto is null) + { + var errorMessage = _stringLocalizerCannotCreate["CannotCreateDTOsForRelatedWords"].Value; + _logger.LogError(request, errorMessage); + return new Error(errorMessage); } + + return Result.Ok(relatedTermsDto); } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/GetAllByTermId/GetAllRelatedTermsByTermIdQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/GetAllByTermId/GetAllRelatedTermsByTermIdQuery.cs index 31f461eae..3ac051785 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/GetAllByTermId/GetAllRelatedTermsByTermIdQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/GetAllByTermId/GetAllRelatedTermsByTermIdQuery.cs @@ -2,8 +2,7 @@ using MediatR; using Streetcode.BLL.DTO.Streetcode.TextContent; -namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.GetAllByTermId -{ - public record GetAllRelatedTermsByTermIdQuery(int id) - : IRequest>>; -} +namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.GetAllByTermId; + +public record GetAllRelatedTermsByTermIdQuery(int Id) + : IRequest>>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/GetById/GetRelatedTermByIdQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/GetById/GetRelatedTermByIdQuery.cs deleted file mode 100644 index 30be2500f..000000000 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/GetById/GetRelatedTermByIdQuery.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.GetById -{ - internal class GetRelatedTermByIdQuery - { - } -} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Update/UpdateRelatedTermCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Update/UpdateRelatedTermCommand.cs index e3d85ee98..71b8876fd 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Update/UpdateRelatedTermCommand.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Update/UpdateRelatedTermCommand.cs @@ -2,8 +2,7 @@ using MediatR; using Streetcode.BLL.DTO.Streetcode.TextContent; -namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Update -{ - public record UpdateRelatedTermCommand(int id, RelatedTermDTO RelatedTerm) - : IRequest>; -} +namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Update; + +public record UpdateRelatedTermCommand(int Id, RelatedTermDTO RelatedTermDto) + : IRequest>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Update/UpdateRelatedTermHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Update/UpdateRelatedTermHandler.cs index 540c633f3..fbcc2bb6a 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Update/UpdateRelatedTermHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/RelatedTerm/Update/UpdateRelatedTermHandler.cs @@ -1,24 +1,12 @@ -using AutoMapper; -using FluentResults; +using FluentResults; using MediatR; -using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Update +namespace Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Update; + +public class UpdateRelatedTermHandler : IRequestHandler> { - public class UpdateRelatedTermHandler : IRequestHandler> + public Task> Handle(UpdateRelatedTermCommand request, CancellationToken cancellationToken) { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repository; - - public UpdateRelatedTermHandler(IMapper mapper, IRepositoryWrapper repository) - { - _mapper = mapper; - _repository = repository; - } - - public Task> Handle(UpdateRelatedTermCommand request, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } + throw new NotImplementedException(); } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Create/CreateStreetcodeCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Create/CreateStreetcodeCommand.cs index 4fec869c2..4304e3a30 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Create/CreateStreetcodeCommand.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Create/CreateStreetcodeCommand.cs @@ -3,5 +3,6 @@ using Streetcode.BLL.DTO.Streetcode.Create; namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.Create; -public record class CreateStreetcodeCommand(StreetcodeCreateDTO Streetcode) + +public record CreateStreetcodeCommand(StreetcodeCreateDTO Streetcode) : IRequest>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Create/CreateStreetcodeHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Create/CreateStreetcodeHandler.cs index d7987e2bd..1b1d305f6 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Create/CreateStreetcodeHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Create/CreateStreetcodeHandler.cs @@ -9,7 +9,6 @@ using Streetcode.BLL.DTO.Media.Art; using Streetcode.BLL.DTO.Media.Create; using Streetcode.BLL.DTO.Media.Images; -using Streetcode.BLL.DTO.Partners; using Streetcode.BLL.DTO.Streetcode.RelatedFigure; using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; using Streetcode.BLL.DTO.Timeline.Update; @@ -25,13 +24,12 @@ using Streetcode.DAL.Entities.Streetcode; using Streetcode.DAL.Entities.Timeline; using Streetcode.DAL.Repositories.Interfaces.Base; +using TransactionLinkEntity = Streetcode.DAL.Entities.Transactions.TransactionLink; namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.Create; public class CreateStreetcodeHandler : IRequestHandler> { - public const int StreetcodeIndexMaxValue = 9999; - public const int StreetcodeIndexMinValue = 1; private readonly IMapper _mapper; private readonly IRepositoryWrapper _repositoryWrapper; private readonly ILoggerService _logger; @@ -39,7 +37,7 @@ public class CreateStreetcodeHandler : IRequestHandler _stringLocalizerAnErrorOccurred; private readonly IStringLocalizer _stringLocalizerFailedToValidate; private readonly IStringLocalizer _stringLocalizerFieldNames; - private IHttpContextAccessor _httpContextAccessor; + private readonly IHttpContextAccessor _httpContextAccessor; public CreateStreetcodeHandler( IMapper mapper, @@ -70,19 +68,19 @@ public async Task> Handle(CreateStreetcodeCommand request, Cancellat var streetcode = StreetcodeFactory.CreateStreetcode(request.Streetcode.StreetcodeType); _mapper.Map(request.Streetcode, streetcode); streetcode.CreatedAt = streetcode.UpdatedAt = DateTime.UtcNow; - streetcode.UserId = HttpContextHelper.GetCurrentUserId(_httpContextAccessor); - _repositoryWrapper.StreetcodeRepository.Create(streetcode); + streetcode.UserId = HttpContextHelper.GetCurrentUserId(_httpContextAccessor) !; + await _repositoryWrapper.StreetcodeRepository.CreateAsync(streetcode); var isResultSuccess = await _repositoryWrapper.SaveChangesAsync() > 0; await AddTimelineItems(streetcode, request.Streetcode.TimelineItems); await AddImagesAsync(streetcode, request.Streetcode.ImagesIds); AddAudio(streetcode, request.Streetcode.AudioId); - await AddArtGallery(streetcode, request.Streetcode.StreetcodeArtSlides.ToList(), request.Streetcode.Arts); - await AddTags(streetcode, request.Streetcode.Tags.ToList()); + await AddArtGallery(streetcode, request.Streetcode.StreetcodeArtSlides, request.Streetcode.Arts); + await AddTags(streetcode, request.Streetcode.Tags); await AddRelatedFigures(streetcode, request.Streetcode.RelatedFigures); await AddPartners(streetcode, request.Streetcode.Partners); await AddToponyms(streetcode, request.Streetcode.Toponyms); AddStatisticRecords(streetcode, request.Streetcode.StatisticRecords); - AddTransactionLink(streetcode, request.Streetcode.ARBlockURL); + AddTransactionLink(streetcode, request.Streetcode.ArBlockUrl); await _repositoryWrapper.SaveChangesAsync(); await AddFactImageDescription(request.Streetcode.Facts); @@ -94,12 +92,10 @@ public async Task> Handle(CreateStreetcodeCommand request, Cancellat transactionScope.Complete(); return Result.Ok(streetcode.Id); } - else - { - string errorMsg = _stringLocalizerFailedToCreate["FailedToCreateStreetcode"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + + var errorMsg = _stringLocalizerFailedToCreate["FailedToCreateStreetcode"].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(new Error(errorMsg)); } catch (Exception ex) { @@ -110,78 +106,68 @@ public async Task> Handle(CreateStreetcodeCommand request, Cancellat } } - public static List CreateStreetcodeArtsForUnusedArts(int streetcodeId, List arts, List streetcodeArts) + private async Task AddImagesDetails(IEnumerable imagesDetailsDtos) { - foreach (var art in arts) + if (imagesDetailsDtos.IsNullOrEmpty()) { - var newStreetcodeArt = new StreetcodeArt() - { - Index = 0, - StreetcodeId = streetcodeId, - ArtId = art.Id, - StreetcodeArtSlideId = null, - }; - - if (streetcodeArts.Count == 0) - { - streetcodeArts.Add(newStreetcodeArt); - } - else - { - for (int streetcodeArtsIndex = 0; streetcodeArtsIndex < streetcodeArts.Count; streetcodeArtsIndex++) - { - if (art.Id == streetcodeArts[streetcodeArtsIndex].ArtId) - { - break; - } - - if (streetcodeArtsIndex == streetcodeArts.Count - 1) - { - streetcodeArts.Add(newStreetcodeArt); - } - } - } + throw new ArgumentNullException(nameof(imagesDetailsDtos), _stringLocalizerFailedToValidate["CannotBeEmpty", _stringLocalizerFieldNames["ImagesDetails"]]); } - return streetcodeArts; + var imageDetails = _mapper.Map>(imagesDetailsDtos); + await _repositoryWrapper.ImageDetailsRepository.CreateRangeAsync(imageDetails); } - public async Task AddImagesDetails(IEnumerable imageDetails) + private async Task AddImagesAsync(StreetcodeContent streetcode, IEnumerable imagesIds) { - await _repositoryWrapper.ImageDetailsRepository.CreateRangeAsync(_mapper.Map>(imageDetails)); - } + if (imagesIds == null) + { + throw new ArgumentNullException(nameof(imagesIds), _stringLocalizerFailedToValidate["CannotBeEmpty", _stringLocalizerFieldNames["Images"]]); + } - public async Task AddImagesAsync(StreetcodeContent streetcode, IEnumerable imagesIds) - { - await _repositoryWrapper.StreetcodeImageRepository.CreateRangeAsync(imagesIds.Select(imageId => new StreetcodeImage() + var imagesList = imagesIds.ToList(); + + if (imagesList.Count == 0) { - ImageId = imageId, - StreetcodeId = streetcode.Id, - })); + throw new ArgumentException(_stringLocalizerFailedToValidate["CannotBeEmpty", _stringLocalizerFieldNames["Images"]], nameof(imagesIds)); + } + + var streetcodeImages = imagesList + .Select(imageId => new StreetcodeImage() + { + ImageId = imageId, + StreetcodeId = streetcode.Id, + }) + .ToList(); + + await _repositoryWrapper.StreetcodeImageRepository.CreateRangeAsync(streetcodeImages); } - private Task AddFactImageDescription(IEnumerable facts) + private Task AddFactImageDescription(IEnumerable? facts) { - foreach (FactUpdateCreateDto fact in facts) + var factsList = facts?.ToList(); + + if (factsList is null or { Count: 0 }) + { + return Task.CompletedTask; + } + + foreach (var fact in factsList.Where(fact => !string.IsNullOrEmpty(fact.ImageDescription))) { - if (fact.ImageDescription != null) + _repositoryWrapper.ImageDetailsRepository.Create(new ImageDetails() { - _repositoryWrapper.ImageDetailsRepository.Create(new ImageDetails() - { - Alt = fact.ImageDescription, - ImageId = fact.ImageId - }); - } + Alt = fact.ImageDescription, + ImageId = fact.ImageId + }); } return Task.CompletedTask; } - private void AddTransactionLink(StreetcodeContent streetcode, string? url) + private static void AddTransactionLink(StreetcodeContent streetcode, string? url) { if (url != null) { - streetcode.TransactionLink = new DAL.Entities.Transactions.TransactionLink() + streetcode.TransactionLink = new TransactionLinkEntity() { Url = url, UrlTitle = url, @@ -189,11 +175,18 @@ private void AddTransactionLink(StreetcodeContent streetcode, string? url) } } - private void AddStatisticRecords(StreetcodeContent streetcode, IEnumerable statisticRecords) + private void AddStatisticRecords(StreetcodeContent streetcode, IEnumerable? statisticRecords) { + var statisticRecordsList = statisticRecords?.ToList(); + + if (statisticRecordsList is null or { Count: 0 }) + { + return; + } + var statisticRecordsToCreate = new List(); - foreach (var statisticRecord in statisticRecords) + foreach (var statisticRecord in statisticRecordsList) { var newStatistic = _mapper.Map(statisticRecord); var streetcodeCoordinate = streetcode.Coordinates.FirstOrDefault(x => @@ -207,34 +200,41 @@ private void AddStatisticRecords(StreetcodeContent streetcode, IEnumerable tags) + private async Task AddTags(StreetcodeContent streetcode, IEnumerable? tags) { + var tagsList = tags?.ToList(); + + if (tagsList is null or { Count: 0 }) + { + return; + } + var indexedTags = new List(); - for (int i = 0; i < tags.Count; i++) + for (int i = 0; i < tagsList.Count; i++) { var newTagIndex = new StreetcodeTagIndex { StreetcodeId = streetcode.Id, - TagId = tags[i].Id, - IsVisible = tags[i].IsVisible, + TagId = tagsList[i].Id, + IsVisible = tagsList[i].IsVisible, Index = i, }; - if (tags[i].Id <= 0) + if (tagsList[i].Id <= 0) { - var exists = await _repositoryWrapper.TagRepository.GetFirstOrDefaultAsync(t => tags[i].Title == t.Title); + var exists = await _repositoryWrapper.TagRepository.GetFirstOrDefaultAsync(t => tagsList[i].Title == t.Title); if (exists is not null) { throw new HttpRequestException(_stringLocalizerFailedToValidate["MustBeUnique", _stringLocalizerFieldNames["Tag"]], null, System.Net.HttpStatusCode.BadRequest); } - var newTag = _mapper.Map(tags[i]); + var newTag = _mapper.Map(tagsList[i]); newTag.Id = 0; newTagIndex.Tag = newTag; } @@ -245,9 +245,16 @@ private async Task AddTags(StreetcodeContent streetcode, List await _repositoryWrapper.StreetcodeTagIndexRepository.CreateRangeAsync(indexedTags); } - private async Task AddRelatedFigures(StreetcodeContent streetcode, IEnumerable relatedFigures) + private async Task AddRelatedFigures(StreetcodeContent streetcode, IEnumerable? relatedFigures) { - var relatedFiguresToCreate = relatedFigures + var relatedFiguresList = relatedFigures?.ToList(); + + if (relatedFiguresList is null or { Count: 0 }) + { + return; + } + + var relatedFiguresToCreate = relatedFiguresList .Select(relatedFigure => new DAL.Entities.Streetcode.RelatedFigure { ObserverId = streetcode.Id, @@ -258,13 +265,25 @@ private async Task AddRelatedFigures(StreetcodeContent streetcode, IEnumerable artSlides, IEnumerable arts) + private async Task AddArtGallery(StreetcodeContent streetcode, IEnumerable? artSlides, IEnumerable? arts) { - var usedArtIds = new HashSet(artSlides.SelectMany(slide => slide.StreetcodeArts).Select(streetcodeArt => streetcodeArt.ArtId)); + var artSlidesList = artSlides?.ToList() ?? new List(); + var artsList = arts?.ToList() ?? new List(); + + if (artSlidesList.Count == 0 && artsList.Count == 0) + { + return; + } + + var usedArtIds = new HashSet(artSlidesList + .SelectMany(slide => slide.StreetcodeArts) + .Select(streetcodeArt => streetcodeArt.ArtId)); - var filteredArts = arts.Where(art => usedArtIds.Contains(art.Id)).ToList(); + var filteredArts = artsList + .Where(art => usedArtIds.Contains(art.Id)) + .ToList(); - var newArtSlides = _mapper.Map>(artSlides); + var newArtSlides = _mapper.Map>(artSlidesList); newArtSlides.ForEach(artSlide => artSlide.StreetcodeId = streetcode.Id); await _repositoryWrapper.StreetcodeArtSlideRepository.CreateRangeAsync(newArtSlides); @@ -276,25 +295,22 @@ private async Task AddArtGallery(StreetcodeContent streetcode, List new { PlaceholderId = placeholderArt.Id, RealId = newArt.Id }) - .ToDictionary(x => x.PlaceholderId, x => x.RealId); + var artIdMap = filteredArts + .Zip(newArts, (placeholderArt, newArt) => new { PlaceholderId = placeholderArt.Id, RealId = newArt.Id }) + .ToDictionary(x => x.PlaceholderId, x => x.RealId); var newStreetcodeArts = new List(); - foreach (var artSlide in artSlides) + + foreach (var artSlide in artSlidesList) { - var slideId = newArtSlides[artSlides.IndexOf(artSlide)].Id; + var slideId = newArtSlides[artSlidesList.IndexOf(artSlide)].Id; foreach (var streetcodeArt in artSlide.StreetcodeArts) { var newStreetcodeArt = _mapper.Map(streetcodeArt); newStreetcodeArt.StreetcodeId = streetcode.Id; - if (artIdMap.TryGetValue(streetcodeArt.ArtId, out var newArtId)) - { - newStreetcodeArt.ArtId = newArtId; - } - else - { - throw new KeyNotFoundException($"Art ID '{streetcodeArt.ArtId}' not found in the mapped arts."); - } + newStreetcodeArt.ArtId = artIdMap.TryGetValue(streetcodeArt.ArtId, out var newArtId) + ? newArtId + : throw new KeyNotFoundException($"Art ID '{streetcodeArt.ArtId}' not found in the mapped arts."); newStreetcodeArt.StreetcodeArtSlideId = slideId; newStreetcodeArts.Add(newStreetcodeArt); @@ -305,15 +321,22 @@ private async Task AddArtGallery(StreetcodeContent streetcode, List timelineItems) + private async Task AddTimelineItems(StreetcodeContent streetcode, IEnumerable? timelineItems) { - var newContexts = timelineItems.SelectMany(x => x.HistoricalContexts).Where(c => c.Id == 0).DistinctBy(x => x.Title); - var newContextsDb = _mapper.Map>(newContexts); + var timelineItemCreateUpdateDtos = timelineItems?.ToList(); + + if (timelineItemCreateUpdateDtos is null or { Count: 0 }) + { + return; + } + + var newContexts = timelineItemCreateUpdateDtos.SelectMany(x => x.HistoricalContexts).Where(c => c.Id == 0).DistinctBy(x => x.Title).ToList(); + var newContextsDb = _mapper.Map>(newContexts); await _repositoryWrapper.HistoricalContextRepository.CreateRangeAsync(newContextsDb); await _repositoryWrapper.SaveChangesAsync(); List newTimelines = new List(); - foreach (var timelineItem in timelineItems) + foreach (var timelineItem in timelineItemCreateUpdateDtos) { var newTimeline = _mapper.Map(timelineItem); newTimeline.HistoricalContextTimelines = timelineItem.HistoricalContexts @@ -331,9 +354,16 @@ private async Task AddTimelineItems(StreetcodeContent streetcode, IEnumerable partners) + private async Task AddPartners(StreetcodeContent streetcode, IEnumerable? partners) { - var partnersToCreate = partners.Select(partnerId => new StreetcodePartner + var partnersList = partners?.ToList(); + + if (partnersList is null or { Count: 0 }) + { + return; + } + + var partnersToCreate = partnersList.Select(partnerId => new StreetcodePartner { StreetcodeId = streetcode.Id, PartnerId = partnerId @@ -342,9 +372,16 @@ private async Task AddPartners(StreetcodeContent streetcode, IEnumerable pa await _repositoryWrapper.PartnerStreetcodeRepository.CreateRangeAsync(partnersToCreate); } - private async Task AddToponyms(StreetcodeContent streetcode, IEnumerable toponyms) + private async Task AddToponyms(StreetcodeContent streetcode, IEnumerable? toponyms) { - var toponymsName = toponyms.Select(x => x.StreetName); + var toponymList = toponyms?.ToList(); + + if (toponymList is null or { Count: 0 }) + { + return; + } + + var toponymsName = toponymList.Select(x => x.StreetName); streetcode.Toponyms.AddRange(await _repositoryWrapper.ToponymRepository.GetAllAsync(x => toponymsName.Contains(x.StreetName))); } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/CreateFavourite/CreateFavouriteStreetcodeCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/CreateFavourite/CreateFavouriteStreetcodeCommand.cs new file mode 100644 index 000000000..04a05c018 --- /dev/null +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/CreateFavourite/CreateFavouriteStreetcodeCommand.cs @@ -0,0 +1,8 @@ +using FluentResults; +using MediatR; + +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.CreateFavourite +{ + public record CreateFavouriteStreetcodeCommand(int StreetcodeId) + : IRequest>; +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/CreateFavourite/CreateFavouriteStreetcodeHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/CreateFavourite/CreateFavouriteStreetcodeHandler.cs new file mode 100644 index 000000000..3d254ce53 --- /dev/null +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/CreateFavourite/CreateFavouriteStreetcodeHandler.cs @@ -0,0 +1,62 @@ +using FluentResults; +using MediatR; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Localization; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.SharedResource; +using Streetcode.BLL.Util.Helpers; +using Streetcode.DAL.Entities.Streetcode.Favourites; +using Streetcode.DAL.Repositories.Interfaces.Base; + +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.CreateFavourite +{ + public class CreateFavouriteStreetcodeHandler : IRequestHandler> + { + private readonly IRepositoryWrapper _repositoryWrapper; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerAlreadyExists; + private readonly IStringLocalizer _stringLocalizerCannotSave; + private readonly IHttpContextAccessor _httpContextAccessor; + + public CreateFavouriteStreetcodeHandler(IRepositoryWrapper repositoryWrapper, ILoggerService logger, IStringLocalizer stringLocalizerAlreadyExists, IStringLocalizer stringLocalizerCannotSave, IHttpContextAccessor httpContextAccessor) + { + _repositoryWrapper = repositoryWrapper; + _logger = logger; + _stringLocalizerAlreadyExists = stringLocalizerAlreadyExists; + _stringLocalizerCannotSave = stringLocalizerCannotSave; + _httpContextAccessor = httpContextAccessor; + } + + public async Task> Handle(CreateFavouriteStreetcodeCommand request, CancellationToken cancellationToken) + { + var userId = HttpContextHelper.GetCurrentUserId(_httpContextAccessor)!; + + if (await _repositoryWrapper.FavouritesRepository.GetFirstOrDefaultAsync( + f => f.UserId == userId && f.StreetcodeId == request.StreetcodeId) is not null) + { + string errorMsg = _stringLocalizerAlreadyExists["FavouriteAlreadyExists"].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(new Error(errorMsg)); + } + + var favourite = new Favourite + { + StreetcodeId = request.StreetcodeId, + UserId = userId, + }; + + await _repositoryWrapper.FavouritesRepository.CreateAsync(favourite); + + var resultIsSuccessChangeStatus = await _repositoryWrapper.SaveChangesAsync() > 0; + + if (resultIsSuccessChangeStatus) + { + return Result.Ok(Unit.Value); + } + + string errorMessage = _stringLocalizerCannotSave["CannotSaveTheData"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); + } + } +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Delete/DeleteStreetcodeHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Delete/DeleteStreetcodeHandler.cs index c571d7774..64f65dc8d 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Delete/DeleteStreetcodeHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Delete/DeleteStreetcodeHandler.cs @@ -34,7 +34,7 @@ public async Task> Handle(DeleteStreetcodeCommand request, Cancella if (streetcode is null) { - string errorMsg = _stringLocalizerCannotFind["CannotFindStreetcodeWithCorrespondingCategoryId", request.Id].Value; + var errorMsg = _stringLocalizerCannotFind["CannotFindAnyStreetcodeWithCorrespondingId", request.Id].Value; _logger.LogError(request, errorMsg); return Result.Fail(new Error(errorMsg)); } @@ -51,11 +51,9 @@ public async Task> Handle(DeleteStreetcodeCommand request, Cancella { return Result.Ok(Unit.Value); } - else - { - string errorMsg = _stringLocalizerFailedToDelete["FailedToDeleteStreetcode"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + + var finalErrorMsg = _stringLocalizerFailedToDelete["FailedToDeleteStreetcode"].Value; + _logger.LogError(request, finalErrorMsg); + return Result.Fail(new Error(finalErrorMsg)); } } \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/DeleteFromFavourites/DeleteStreetcodeFromFavouritesCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/DeleteFromFavourites/DeleteStreetcodeFromFavouritesCommand.cs new file mode 100644 index 000000000..9d880fc62 --- /dev/null +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/DeleteFromFavourites/DeleteStreetcodeFromFavouritesCommand.cs @@ -0,0 +1,8 @@ +using FluentResults; +using MediatR; + +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.DeleteFromFavourites +{ + public record DeleteStreetcodeFromFavouritesCommand(int StreetcodeId) + : IRequest>; +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/DeleteFromFavourites/DeleteStreetcodeFromFavouritesHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/DeleteFromFavourites/DeleteStreetcodeFromFavouritesHandler.cs new file mode 100644 index 000000000..3750b6447 --- /dev/null +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/DeleteFromFavourites/DeleteStreetcodeFromFavouritesHandler.cs @@ -0,0 +1,58 @@ +using FluentResults; +using MediatR; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Localization; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.SharedResource; +using Streetcode.BLL.Util.Helpers; +using Streetcode.DAL.Repositories.Interfaces.Base; + +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.DeleteFromFavourites +{ + public class DeleteStreetcodeFromFavouritesHandler : IRequestHandler> + { + private readonly IRepositoryWrapper _repositoryWrapper; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerCannotFind; + private readonly IStringLocalizer _stringLocalizerFailedToDelete; + private readonly IHttpContextAccessor _httpContextAccessor; + + public DeleteStreetcodeFromFavouritesHandler(IRepositoryWrapper repositoryWrapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind, IStringLocalizer stringLocalizerFailedToDelete, IHttpContextAccessor httpContextAccessor) + { + _repositoryWrapper = repositoryWrapper; + _logger = logger; + _stringLocalizerCannotFind = stringLocalizerCannotFind; + _stringLocalizerFailedToDelete = stringLocalizerFailedToDelete; + _httpContextAccessor = httpContextAccessor; + } + + public async Task> Handle(DeleteStreetcodeFromFavouritesCommand request, CancellationToken cancellationToken) + { + var userId = HttpContextHelper.GetCurrentUserId(_httpContextAccessor)!; + + var favourite = await _repositoryWrapper.FavouritesRepository.GetFirstOrDefaultAsync( + f => f.UserId == userId && f.StreetcodeId == request.StreetcodeId); + + if (favourite is null) + { + string errorMsg = _stringLocalizerCannotFind["CannotFindStreetcodeInFavourites"].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(new Error(errorMsg)); + } + + _repositoryWrapper.FavouritesRepository.Delete(favourite); + var resultIsSuccess = await _repositoryWrapper.SaveChangesAsync() > 0; + + if (resultIsSuccess) + { + return Result.Ok(Unit.Value); + } + else + { + string errorMsg = _stringLocalizerFailedToDelete["FailedToDeleteStreetcode"].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(new Error(errorMsg)); + } + } + } +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/DeleteSoft/DeleteSoftStreetcodeHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/DeleteSoft/DeleteSoftStreetcodeHandler.cs index efd7f33d5..8f08966d5 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/DeleteSoft/DeleteSoftStreetcodeHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/DeleteSoft/DeleteSoftStreetcodeHandler.cs @@ -14,7 +14,11 @@ public class DeleteSoftStreetcodeHandler : IRequestHandler _stringLocalizerCannotFind; private readonly IStringLocalizer _stringLocalizerFailedToUpdate; - public DeleteSoftStreetcodeHandler(IRepositoryWrapper repositoryWrapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind, IStringLocalizer stringLocalizerFailedToUpdate) + public DeleteSoftStreetcodeHandler( + IRepositoryWrapper repositoryWrapper, + ILoggerService logger, + IStringLocalizer stringLocalizerCannotFind, + IStringLocalizer stringLocalizerFailedToUpdate) { _repositoryWrapper = repositoryWrapper; _logger = logger; @@ -29,9 +33,9 @@ public async Task> Handle(DeleteSoftStreetcodeCommand request, Canc if (streetcode is null) { - string errorMsg = _stringLocalizerCannotFind["CannotFindStreetcodeWithCorrespondingCategoryId", request.Id].Value; + var errorMsg = _stringLocalizerCannotFind["CannotFindAnyStreetcodeWithCorrespondingId", request.Id].Value; _logger.LogError(request, errorMsg); - throw new ArgumentNullException(errorMsg); + return Result.Fail(new Error(errorMsg)); } streetcode.Status = DAL.Enums.StreetcodeStatus.Deleted; @@ -39,17 +43,15 @@ public async Task> Handle(DeleteSoftStreetcodeCommand request, Canc _repositoryWrapper.StreetcodeRepository.Update(streetcode); - var resultIsDeleteSucces = await _repositoryWrapper.SaveChangesAsync() > 0; + var resultIsDeleteSuccess = await _repositoryWrapper.SaveChangesAsync() > 0; - if(resultIsDeleteSucces) + if(resultIsDeleteSuccess) { return Result.Ok(Unit.Value); } - else - { - string errorMsg = _stringLocalizerFailedToUpdate["FailedToChangeStatusOfStreetcodeToDeleted"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + + var finalErrorMsg = _stringLocalizerFailedToUpdate["FailedToChangeStatusOfStreetcodeToDeleted"].Value; + _logger.LogError(request, finalErrorMsg); + return Result.Fail(new Error(finalErrorMsg)); } } \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAll/GetAllStreetcodesHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAll/GetAllStreetcodesHandler.cs index e365d3b74..9281d2098 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAll/GetAllStreetcodesHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAll/GetAllStreetcodesHandler.cs @@ -2,8 +2,11 @@ using AutoMapper; using FluentResults; using MediatR; +using Microsoft.EntityFrameworkCore; using Streetcode.BLL.DTO.Streetcode; +using Microsoft.Extensions.Localization; using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Streetcode; using Streetcode.DAL.Repositories.Interfaces.Base; @@ -13,19 +16,32 @@ public class GetAllStreetcodesHandler : IRequestHandler _stringLocalizerCannotFind; + private readonly IStringLocalizer _stringLocalizerFailedToValidate; + + public GetAllStreetcodesHandler( + IRepositoryWrapper repositoryWrapper, + IMapper mapper, + ILoggerService logger, + IStringLocalizer stringLocalizerCannotFind, + IStringLocalizer stringLocalizerFailedToValidate) { _repositoryWrapper = repositoryWrapper; _mapper = mapper; + _logger = logger; + _stringLocalizerCannotFind = stringLocalizerCannotFind; + _stringLocalizerFailedToValidate = stringLocalizerFailedToValidate; } public Task> Handle(GetAllStreetcodesQuery query, CancellationToken cancellationToken) { - var filterRequest = query.request; + var filterRequest = query.Request; var streetcodes = _repositoryWrapper.StreetcodeRepository - .FindAll(); + .FindAll() + .Include(s => s.Tags) + .AsQueryable(); if (filterRequest.Title is not null) { @@ -34,18 +50,37 @@ public Task> Handle(GetAllStreetcodesQuery if (filterRequest.Sort is not null) { - FindSortedStreetcodes(ref streetcodes, filterRequest.Sort); + var sortedResult = FindSortedStreetcodes(ref streetcodes, filterRequest.Sort); + if (sortedResult.IsFailed) + { + var errorMsg = _stringLocalizerCannotFind[sortedResult.Errors[0].Message].Value; + _logger.LogError(query, errorMsg); + return Task.FromResult>(Result.Fail(new Error(errorMsg))); + } } if (filterRequest.Filter is not null) { - FindFilteredStreetcodes(ref streetcodes, filterRequest.Filter); + var filterResult = FindFilteredStreetcodes(ref streetcodes, filterRequest.Filter); + if (filterResult.IsFailed) + { + var errorMsg = _stringLocalizerCannotFind[filterResult.Errors[0].Message].Value; + _logger.LogError(query, errorMsg); + return Task.FromResult>(Result.Fail(new Error(errorMsg))); + } } var totalAmount = streetcodes.Count(); if (filterRequest.Amount is not null && filterRequest.Page is not null) { + if (filterRequest.Page <= 0 || filterRequest.Amount <= 0) + { + var errorMsg = _stringLocalizerFailedToValidate["InvalidPaginationParameters"].Value; + _logger.LogError(query, errorMsg); + return Task.FromResult>(Result.Fail(new Error(errorMsg))); + } + ApplyPagination(ref streetcodes, filterRequest.Amount!.Value, filterRequest.Page!.Value); } @@ -60,7 +95,7 @@ public Task> Handle(GetAllStreetcodesQuery return Task.FromResult(Result.Ok(response)); } - private void FindStreetcodesWithMatchTitle( + private static void FindStreetcodesWithMatchTitle( ref IQueryable streetcodes, string title) { @@ -71,7 +106,7 @@ private void FindStreetcodesWithMatchTitle( .ToString() == title); } - private void FindFilteredStreetcodes( + private static Result FindFilteredStreetcodes( ref IQueryable streetcodes, string filter) { @@ -79,13 +114,23 @@ private void FindFilteredStreetcodes( var filterColumn = filterParams[0]; var filterValue = filterParams[1]; + var type = typeof(StreetcodeContent); + var property = type.GetProperty(filterColumn); + + if (property is null) + { + return Result.Fail(new Error("CannotFindAnyPropertyWithThisName")); + } + streetcodes = streetcodes .AsEnumerable() - .Where(s => filterValue.Contains(s.Status.ToString())) + .Where(s => property.GetValue(s)?.ToString()?.Contains(filterValue, StringComparison.OrdinalIgnoreCase) ?? false) .AsQueryable(); + + return Result.Ok(); } - private void FindSortedStreetcodes( + private static Result FindSortedStreetcodes( ref IQueryable streetcodes, string sort) { @@ -94,16 +139,22 @@ private void FindSortedStreetcodes( var sortColumn = sort.Trim(); var sortDirection = "asc"; - if (sortColumn.StartsWith("-")) + if (sortColumn.StartsWith('-')) { sortDirection = "desc"; sortColumn = sortColumn.Substring(1); } var type = typeof(StreetcodeContent); + var property = type.GetProperty(sortColumn); + if (property is null) + { + return Result.Fail(new Error("CannotFindAnyPropertyWithThisName")); + } + var parameter = Expression.Parameter(type, "p"); - var property = Expression.Property(parameter, sortColumn); - var lambda = Expression.Lambda(property, parameter); + var memberExpression = Expression.Property(parameter, sortColumn); + var lambda = Expression.Lambda(memberExpression, parameter); streetcodes = sortDirection switch { @@ -111,9 +162,11 @@ private void FindSortedStreetcodes( "desc" => Queryable.OrderByDescending(sortedRecords, (dynamic)lambda), _ => sortedRecords, }; + + return Result.Ok(); } - private void ApplyPagination( + private static void ApplyPagination( ref IQueryable streetcodes, int amount, int page) diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAll/GetAllStreetcodesQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAll/GetAllStreetcodesQuery.cs index 8797c41a0..551451c91 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAll/GetAllStreetcodesQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAll/GetAllStreetcodesQuery.cs @@ -4,5 +4,5 @@ namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAll; -public record GetAllStreetcodesQuery(GetAllStreetcodesRequestDTO request) +public record GetAllStreetcodesQuery(GetAllStreetcodesRequestDTO Request) : IRequest>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllCatalog/GetAllStreetcodesCatalogHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllCatalog/GetAllStreetcodesCatalogHandler.cs index 02b6a1a12..e41005c76 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllCatalog/GetAllStreetcodesCatalogHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllCatalog/GetAllStreetcodesCatalogHandler.cs @@ -9,45 +9,50 @@ using Streetcode.DAL.Enums; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllCatalog +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllCatalog; + +public class GetAllStreetcodesCatalogHandler : IRequestHandler>> { - public class GetAllStreetcodesCatalogHandler : IRequestHandler>> + private readonly IMapper _mapper; + private readonly IRepositoryWrapper _repositoryWrapper; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerNo; + + public GetAllStreetcodesCatalogHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerNo) { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repositoryWrapper; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerNo; + _repositoryWrapper = repositoryWrapper; + _mapper = mapper; + _logger = logger; + _stringLocalizerNo = stringLocalizerNo; + } - public GetAllStreetcodesCatalogHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerNo) - { - _repositoryWrapper = repositoryWrapper; - _mapper = mapper; - _logger = logger; - _stringLocalizerNo = stringLocalizerNo; - } + public async Task>> Handle(GetAllStreetcodesCatalogQuery request, CancellationToken cancellationToken) + { + var streetcodes = await _repositoryWrapper.StreetcodeRepository.GetAllAsync( + predicate: sc => sc.Status == StreetcodeStatus.Published, + include: src => src + .Include(item => item.Images) + .ThenInclude(x => x.ImageDetails!)); - public async Task>> Handle(GetAllStreetcodesCatalogQuery request, CancellationToken cancellationToken) + var streetcodesList = streetcodes.ToList(); + if (streetcodesList.Any()) { - var streetcodes = await _repositoryWrapper.StreetcodeRepository.GetAllAsync( - predicate: sc => sc.Status == DAL.Enums.StreetcodeStatus.Published, - include: src => src.Include(item => item.Images).ThenInclude(x => x.ImageDetails!)); - - if (streetcodes.Any()) + const int keyNumOfImageToDisplay = (int)ImageAssigment.Blackandwhite; + foreach (var streetcode in streetcodesList) { - const int keyNumOfImageToDisplay = (int)ImageAssigment.Blackandwhite; - foreach (var streetcode in streetcodes) - { - streetcode.Images = streetcode.Images.Where(x => x.ImageDetails != null && x.ImageDetails.Alt!.Equals(keyNumOfImageToDisplay.ToString())).ToList(); - } - - var skipped = streetcodes.Skip((request.page - 1) * request.count).Take(request.count); - return Result.Ok(_mapper.Map>(skipped)); + streetcode.Images = streetcode.Images + .Where(x => x.ImageDetails != null && x.ImageDetails.Alt!.Equals(keyNumOfImageToDisplay.ToString())) + .ToList(); } - string errorMsg = _stringLocalizerNo["NoStreetcodesExistNow"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(errorMsg); + var skipped = streetcodesList.Skip((request.Page - 1) * request.Count).Take(request.Count); + + return Result.Ok(_mapper.Map>(skipped)); } + + var errorMsg = _stringLocalizerNo["NoStreetcodesExistNow"].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(errorMsg); } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllCatalog/GetAllStreetcodesCatalogQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllCatalog/GetAllStreetcodesCatalogQuery.cs index 1a21659f5..33667be9c 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllCatalog/GetAllStreetcodesCatalogQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllCatalog/GetAllStreetcodesCatalogQuery.cs @@ -2,8 +2,7 @@ using MediatR; using Streetcode.BLL.DTO.Streetcode.CatalogItem; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllCatalog -{ - public record GetAllStreetcodesCatalogQuery(int page, int count) - : IRequest>>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllCatalog; + +public record GetAllStreetcodesCatalogQuery(int Page, int Count) + : IRequest>>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllFavourites/GetAllStreetcodeFavouritesHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllFavourites/GetAllStreetcodeFavouritesHandler.cs new file mode 100644 index 000000000..70187a7e3 --- /dev/null +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllFavourites/GetAllStreetcodeFavouritesHandler.cs @@ -0,0 +1,57 @@ +using AutoMapper; +using FluentResults; +using MediatR; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Localization; +using Streetcode.BLL.DTO.Streetcode; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.SharedResource; +using Streetcode.BLL.Util.Helpers; +using Streetcode.DAL.Enums; +using Streetcode.DAL.Repositories.Interfaces.Base; + +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllFavourites +{ + public class GetAllStreetcodeFavouritesHandler : IRequestHandler>> + { + private readonly IMapper _mapper; + private readonly IRepositoryWrapper _repositoryWrapper; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerNo; + private readonly IHttpContextAccessor _httpContextAccessor; + + public GetAllStreetcodeFavouritesHandler(IMapper mapper, IRepositoryWrapper repositoryWrapper, ILoggerService logger, IStringLocalizer stringLocalizerNo, IHttpContextAccessor httpContextAccessor) + { + _mapper = mapper; + _repositoryWrapper = repositoryWrapper; + _logger = logger; + _stringLocalizerNo = stringLocalizerNo; + _httpContextAccessor = httpContextAccessor; + } + + public async Task>> Handle(GetAllStreetcodeFavouritesQuery request, CancellationToken cancellationToken) + { + var userId = HttpContextHelper.GetCurrentUserId(_httpContextAccessor)!; + + var favourites = await _repositoryWrapper.StreetcodeRepository.GetAllAsync( + predicate: fv => fv.UserFavourites.Any(u => u.Id == userId), + include: fv => fv.Include(item => item.Images).ThenInclude(x => x.ImageDetails!)); + if (favourites.Any()) + { + const int keyNumOfImageToDisplay = (int)ImageAssigment.Blackandwhite; + foreach (var streetcode in favourites) + { + streetcode.Images = streetcode.Images.Where(x => x.ImageDetails != null && x.ImageDetails.Alt!.Equals(keyNumOfImageToDisplay.ToString())).ToList(); + } + + return Result.Ok(_mapper.Map>(favourites).Where(s => request.Type == null || s.Type == request.Type)); + } + + string errorMsg = _stringLocalizerNo["NoFavouritesFound"].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(errorMsg); + } + } +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllFavourites/GetAllStreetcodeFavouritesQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllFavourites/GetAllStreetcodeFavouritesQuery.cs new file mode 100644 index 000000000..3e880866b --- /dev/null +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllFavourites/GetAllStreetcodeFavouritesQuery.cs @@ -0,0 +1,10 @@ +using FluentResults; +using MediatR; +using Streetcode.BLL.DTO.Streetcode; +using Streetcode.DAL.Enums; + +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllFavourites +{ + public record GetAllStreetcodeFavouritesQuery(StreetcodeType? Type = null) + : IRequest>>; +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllMainPage/GetAllStreetcodesMainPageHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllMainPage/GetAllStreetcodesMainPageHandler.cs index 2ba238b90..cab75cd9b 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllMainPage/GetAllStreetcodesMainPageHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllMainPage/GetAllStreetcodesMainPageHandler.cs @@ -5,52 +5,60 @@ using Microsoft.Extensions.Localization; using Streetcode.BLL.DTO.Streetcode; using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllStreetcodesMainPage; using Streetcode.BLL.SharedResource; using Streetcode.DAL.Enums; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllMainPage +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllMainPage; + +public class GetAllStreetcodesMainPageHandler : IRequestHandler>> { - public class GetAllStreetcodesMainPageHandler : IRequestHandler>> + private readonly IMapper _mapper; + private readonly IRepositoryWrapper _repositoryWrapper; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerNo; + + public GetAllStreetcodesMainPageHandler( + IRepositoryWrapper repositoryWrapper, + IMapper mapper, + ILoggerService logger, + IStringLocalizer stringLocalizerNo) { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repositoryWrapper; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerNo; + _repositoryWrapper = repositoryWrapper; + _mapper = mapper; + _logger = logger; + _stringLocalizerNo = stringLocalizerNo; + } - public GetAllStreetcodesMainPageHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerNo) - { - _repositoryWrapper = repositoryWrapper; - _mapper = mapper; - _logger = logger; - _stringLocalizerNo = stringLocalizerNo; - } + public async Task>> Handle(GetAllStreetcodesMainPageQuery request, CancellationToken cancellationToken) + { + var streetcodes = await _repositoryWrapper.StreetcodeRepository.GetAllAsync( + predicate: sc => sc.Status == StreetcodeStatus.Published, + include: src => src + .Include(item => item.Text) + .Include(item => item.Images) + .ThenInclude(x => x.ImageDetails!)); - public async Task>> Handle(GetAllStreetcodesMainPageQuery request, CancellationToken cancellationToken) + var streetcodesList = streetcodes.ToList(); + if (streetcodesList.Any()) { - var streetcodes = await _repositoryWrapper.StreetcodeRepository.GetAllAsync( - predicate: sc => sc.Status == DAL.Enums.StreetcodeStatus.Published, - include: src => src.Include(item => item.Text).Include(item => item.Images).ThenInclude(x => x.ImageDetails!)); - - if (streetcodes.Any()) + const int keyNumOfImageToDisplay = (int)ImageAssigment.Blackandwhite; + foreach (var streetcode in streetcodesList) { - const int keyNumOfImageToDisplay = (int)ImageAssigment.Blackandwhite; - foreach (var streetcode in streetcodes) - { - streetcode.Images = streetcode.Images.Where(x => x.ImageDetails != null && x.ImageDetails.Alt!.Equals(keyNumOfImageToDisplay.ToString())).ToList(); - } - - var random = new Random(); - var shuffledStreetcodes = streetcodes.OrderBy(sc => random.Next()); - - return Result.Ok(_mapper.Map>(shuffledStreetcodes)); + streetcode.Images = streetcode.Images + .Where(x => x.ImageDetails != null && x.ImageDetails.Alt!.Equals(keyNumOfImageToDisplay.ToString())) + .ToList(); } - string errorMsg = _stringLocalizerNo["NoStreetcodesExistNow"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(errorMsg); + var random = new Random(); + var shuffledStreetcodes = streetcodesList.OrderBy(_ => random.Next()); + + return Result.Ok(_mapper.Map>(shuffledStreetcodes)); } + + var errorMsg = _stringLocalizerNo["NoStreetcodesExistNow"].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(errorMsg); } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllMainPage/GetAllStreetcodesMainPageQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllMainPage/GetAllStreetcodesMainPageQuery.cs index 23f91b964..45d7d914f 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllMainPage/GetAllStreetcodesMainPageQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllMainPage/GetAllStreetcodesMainPageQuery.cs @@ -2,7 +2,6 @@ using MediatR; using Streetcode.BLL.DTO.Streetcode; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllStreetcodesMainPage -{ - public record GetAllStreetcodesMainPageQuery : IRequest>>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllMainPage; + +public record GetAllStreetcodesMainPageQuery : IRequest>>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllPublished/GetAllPublishedHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllPublished/GetAllPublishedHandler.cs index 68bd8c22e..24c24d821 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllPublished/GetAllPublishedHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllPublished/GetAllPublishedHandler.cs @@ -1,36 +1,47 @@ using AutoMapper; using FluentResults; using MediatR; +using Microsoft.Extensions.Localization; +using Microsoft.IdentityModel.Tokens; using Streetcode.BLL.DTO.Streetcode; -using Streetcode.BLL.MediatR.Streetcode.RelatedFigure.GetAllPublished; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllCatalog +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllPublished; + +public class GetAllPublishedHandler : IRequestHandler>> { - public class GetAllPublishedHandler : IRequestHandler>> + private readonly IMapper _mapper; + private readonly IRepositoryWrapper _repositoryWrapper; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerNo; + + public GetAllPublishedHandler( + IRepositoryWrapper repositoryWrapper, + IMapper mapper, + ILoggerService logger, + IStringLocalizer stringLocalizerNo) { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repositoryWrapper; + _repositoryWrapper = repositoryWrapper; + _mapper = mapper; + _logger = logger; + _stringLocalizerNo = stringLocalizerNo; + } - public GetAllPublishedHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper) - { - _repositoryWrapper = repositoryWrapper; - _mapper = mapper; - } + public async Task>> Handle(GetAllPublishedQuery request, CancellationToken cancellationToken) + { + var streetcodes = await _repositoryWrapper.StreetcodeRepository.GetAllAsync( + predicate: sc => sc.Status == DAL.Enums.StreetcodeStatus.Published); - public async Task>> Handle(GetAllPublishedQuery request, CancellationToken cancellationToken) + if (streetcodes.IsNullOrEmpty()) { - var streetcodes = await _repositoryWrapper.StreetcodeRepository.GetAllAsync( - predicate: sc => sc.Status == DAL.Enums.StreetcodeStatus.Published); - - if (streetcodes is null) - { - // Logger - return Result.Fail("No streetcodes exist now"); - } - - return Result.Ok(_mapper.Map>(streetcodes)); + var errorMsg = _stringLocalizerNo["NoStreetcodesExistNow"].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(errorMsg); } - } -} + + return Result.Ok(_mapper.Map>(streetcodes)); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllPublished/GetAllPublishedQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllPublished/GetAllPublishedQuery.cs index 10bed94ad..cd55703d0 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllPublished/GetAllPublishedQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllPublished/GetAllPublishedQuery.cs @@ -2,7 +2,7 @@ using MediatR; using Streetcode.BLL.DTO.Streetcode; -namespace Streetcode.BLL.MediatR.Streetcode.RelatedFigure.GetAllPublished; +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllPublished; public record GetAllPublishedQuery() : IRequest>>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllShort/GetAllStreetcodesShortHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllShort/GetAllStreetcodesShortHandler.cs index 0d41f08ad..64d0da743 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllShort/GetAllStreetcodesShortHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllShort/GetAllStreetcodesShortHandler.cs @@ -7,36 +7,39 @@ using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllShort +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllShort; + +public class GetAllStreetcodesShortHandler : IRequestHandler>> { - public class GetAllStreetcodesShortHandler : IRequestHandler>> + private readonly IMapper _mapper; + private readonly IRepositoryWrapper _repositoryWrapper; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerNo; + + public GetAllStreetcodesShortHandler( + IRepositoryWrapper repositoryWrapper, + IMapper mapper, + ILoggerService logger, + IStringLocalizer stringLocalizerNo) { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repositoryWrapper; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerNo; + _repositoryWrapper = repositoryWrapper; + _mapper = mapper; + _logger = logger; + _stringLocalizerNo = stringLocalizerNo; + } - public GetAllStreetcodesShortHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerNo) - { - _repositoryWrapper = repositoryWrapper; - _mapper = mapper; - _logger = logger; - _stringLocalizerNo = stringLocalizerNo; - } + public async Task>> Handle(GetAllStreetcodesShortQuery request, CancellationToken cancellationToken) + { + var streetcodes = await _repositoryWrapper.StreetcodeRepository.GetAllAsync(); - public async Task>> Handle(GetAllStreetcodesShortQuery request, CancellationToken cancellationToken) + if (streetcodes.Any()) { - var streetcodes = await _repositoryWrapper.StreetcodeRepository.GetAllAsync(); - - if (streetcodes.Any()) - { - return Result.Ok(_mapper.Map>(streetcodes)); - } - - string errorMsg = _stringLocalizerNo["NoStreetcodesExistNow"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(errorMsg); + return Result.Ok(_mapper.Map>(streetcodes)); } + + var errorMsg = _stringLocalizerNo["NoStreetcodesExistNow"].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(errorMsg); } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllShort/GetAllStreetcodesShortQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllShort/GetAllStreetcodesShortQuery.cs index 5281fbe83..92d8029c8 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllShort/GetAllStreetcodesShortQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetAllShort/GetAllStreetcodesShortQuery.cs @@ -2,7 +2,6 @@ using MediatR; using Streetcode.BLL.DTO.Streetcode; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllShort -{ - public record GetAllStreetcodesShortQuery : IRequest>>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllShort; + +public record GetAllStreetcodesShortQuery : IRequest>>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByFilter/GetStreetcodeByFilterHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByFilter/GetStreetcodeByFilterHandler.cs index 2d8ccae4a..a438d40d1 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByFilter/GetStreetcodeByFilterHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByFilter/GetStreetcodeByFilterHandler.cs @@ -5,103 +5,102 @@ using Streetcode.DAL.Entities.Streetcode; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetByFilter +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetByFilter; + +public class GetStreetcodeByFilterHandler : IRequestHandler>> { - public class GetStreetcodeByFilterHandler : IRequestHandler>> - { - private readonly IRepositoryWrapper _repositoryWrapper; + private readonly IRepositoryWrapper _repositoryWrapper; - public GetStreetcodeByFilterHandler(IRepositoryWrapper repositoryWrapper) - { - _repositoryWrapper = repositoryWrapper; - } + public GetStreetcodeByFilterHandler(IRepositoryWrapper repositoryWrapper) + { + _repositoryWrapper = repositoryWrapper; + } - public async Task>> Handle(GetStreetcodeByFilterQuery request, CancellationToken cancellationToken) - { - var searchQuery = request.Filter.SearchQuery.Trim(); - var results = new List(); + public async Task>> Handle(GetStreetcodeByFilterQuery request, CancellationToken cancellationToken) + { + var searchQuery = request.Filter.SearchQuery.Trim(); + var results = new List(); - results.AddRange(await GetStreetcodeResultsAsync(searchQuery)); - results.AddRange(await GetTextResultsAsync(searchQuery)); - results.AddRange(await GetFactResultsAsync(searchQuery)); - results.AddRange(await GetTimelineResultsAsync(searchQuery)); - results.AddRange(await GetArtGalleryResultsAsync(searchQuery)); + results.AddRange(await GetStreetcodeResultsAsync(searchQuery)); + results.AddRange(await GetTextResultsAsync(searchQuery)); + results.AddRange(await GetFactResultsAsync(searchQuery)); + results.AddRange(await GetTimelineResultsAsync(searchQuery)); + results.AddRange(await GetArtGalleryResultsAsync(searchQuery)); - return results; - } + return results; + } - private async Task> GetStreetcodeResultsAsync(string searchQuery) - { - var streetcodes = await _repositoryWrapper.StreetcodeRepository.GetAllAsync( - x => x.Status == DAL.Enums.StreetcodeStatus.Published && - (x.Title!.Contains(searchQuery) || (x.Alias != null && x.Alias.Contains(searchQuery)) || x.Teaser!.Contains(searchQuery))); - - return streetcodes.Select(streetcode => CreateFilterResult( - streetcode, - streetcode.Title!.Contains(searchQuery, StringComparison.OrdinalIgnoreCase) ? streetcode.Title : - streetcode.Alias?.Contains(searchQuery, StringComparison.OrdinalIgnoreCase) == true ? streetcode.Alias : - streetcode.Teaser!.Contains(searchQuery, StringComparison.OrdinalIgnoreCase) ? streetcode.Teaser : - streetcode.TransliterationUrl!)); - } - - private async Task> GetTextResultsAsync(string searchQuery) - { - var texts = await _repositoryWrapper.TextRepository.GetAllAsync( - x => x.Streetcode!.Status == DAL.Enums.StreetcodeStatus.Published, - i => i.Include(x => x.Streetcode!)); + private async Task> GetStreetcodeResultsAsync(string searchQuery) + { + var streetcodes = await _repositoryWrapper.StreetcodeRepository.GetAllAsync( + x => x.Status == DAL.Enums.StreetcodeStatus.Published && + (x.Title!.Contains(searchQuery) || (x.Alias != null && x.Alias.Contains(searchQuery)) || x.Teaser!.Contains(searchQuery))); + + return streetcodes.Select(streetcode => CreateFilterResult( + streetcode, + streetcode.Title!.Contains(searchQuery, StringComparison.OrdinalIgnoreCase) ? streetcode.Title : + streetcode.Alias?.Contains(searchQuery, StringComparison.OrdinalIgnoreCase) == true ? streetcode.Alias : + streetcode.Teaser!.Contains(searchQuery, StringComparison.OrdinalIgnoreCase) ? streetcode.Teaser : + streetcode.TransliterationUrl!)); + } - return texts.Where(text => text.Title!.Contains(searchQuery, StringComparison.OrdinalIgnoreCase) || - (!string.IsNullOrEmpty(text.TextContent) && text.TextContent.Contains(searchQuery, StringComparison.OrdinalIgnoreCase))) - .Select(text => CreateFilterResult(text.Streetcode!, text.Title!.Contains(searchQuery) ? text.Title! : text.TextContent!, "Текст", "text")); - } + private async Task> GetTextResultsAsync(string searchQuery) + { + var texts = await _repositoryWrapper.TextRepository.GetAllAsync( + x => x.Streetcode!.Status == DAL.Enums.StreetcodeStatus.Published, + i => i.Include(x => x.Streetcode!)); - private async Task> GetFactResultsAsync(string searchQuery) - { - var facts = await _repositoryWrapper.FactRepository.GetAllAsync( - x => x.Streetcode!.Status == DAL.Enums.StreetcodeStatus.Published, - i => i.Include(x => x.Streetcode!)); + return texts.Where(text => text.Title!.Contains(searchQuery, StringComparison.OrdinalIgnoreCase) || + (!string.IsNullOrEmpty(text.TextContent) && text.TextContent.Contains(searchQuery, StringComparison.OrdinalIgnoreCase))) + .Select(text => CreateFilterResult(text.Streetcode!, text.Title!.Contains(searchQuery) ? text.Title! : text.TextContent!, "Текст", "text")); + } - return facts.Where(fact => fact.Title!.Contains(searchQuery, StringComparison.OrdinalIgnoreCase) || - fact.FactContent!.Contains(searchQuery, StringComparison.OrdinalIgnoreCase)) - .Select(fact => CreateFilterResult(fact.Streetcode!, fact.Title!, "Wow-факти", "wow-facts", factId: fact.Id)); - } + private async Task> GetFactResultsAsync(string searchQuery) + { + var facts = await _repositoryWrapper.FactRepository.GetAllAsync( + x => x.Streetcode!.Status == DAL.Enums.StreetcodeStatus.Published, + i => i.Include(x => x.Streetcode!)); - private async Task> GetTimelineResultsAsync(string searchQuery) - { - var timelineItems = await _repositoryWrapper.TimelineRepository.GetAllAsync( - x => x.Streetcode!.Status == DAL.Enums.StreetcodeStatus.Published, - i => i.Include(x => x.Streetcode!)); + return facts.Where(fact => fact.Title!.Contains(searchQuery, StringComparison.OrdinalIgnoreCase) || + fact.FactContent!.Contains(searchQuery, StringComparison.OrdinalIgnoreCase)) + .Select(fact => CreateFilterResult(fact.Streetcode!, fact.Title!, "Wow-факти", "wow-facts", factId: fact.Id)); + } - return timelineItems.Where(timelineItem => timelineItem.Title!.Contains(searchQuery, StringComparison.OrdinalIgnoreCase) || - (!string.IsNullOrEmpty(timelineItem.Description) && timelineItem.Description.Contains(searchQuery, StringComparison.OrdinalIgnoreCase))) - .Select(timelineItem => CreateFilterResult(timelineItem.Streetcode!, timelineItem.Title!, "Хронологія", "timeline", timelineItemId: timelineItem.Id)); - } + private async Task> GetTimelineResultsAsync(string searchQuery) + { + var timelineItems = await _repositoryWrapper.TimelineRepository.GetAllAsync( + x => x.Streetcode!.Status == DAL.Enums.StreetcodeStatus.Published, + i => i.Include(x => x.Streetcode!)); - private async Task> GetArtGalleryResultsAsync(string searchQuery) - { - var streetcodeArts = await _repositoryWrapper.StreetcodeArtRepository.GetAllAsync( - x => x.StreetcodeArtSlide!.Streetcode != null && x.StreetcodeArtSlide.Streetcode.Status == DAL.Enums.StreetcodeStatus.Published, - i => i.Include(sArt => sArt.Art).Include(sArt => sArt.StreetcodeArtSlide).ThenInclude(slide => slide!.Streetcode!)); + return timelineItems.Where(timelineItem => timelineItem.Title!.Contains(searchQuery, StringComparison.OrdinalIgnoreCase) || + (!string.IsNullOrEmpty(timelineItem.Description) && timelineItem.Description.Contains(searchQuery, StringComparison.OrdinalIgnoreCase))) + .Select(timelineItem => CreateFilterResult(timelineItem.Streetcode!, timelineItem.Title!, "Хронологія", "timeline", timelineItemId: timelineItem.Id)); + } - return streetcodeArts.Where(streetcodeArt => !string.IsNullOrEmpty(streetcodeArt.Art!.Description) && - streetcodeArt.Art.Description.Contains(searchQuery, StringComparison.OrdinalIgnoreCase)) - .SelectMany(streetcodeArt => streetcodeArt.StreetcodeArtSlide!.StreetcodeArts!.Select(art => - CreateFilterResult(art.StreetcodeArtSlide!.Streetcode!, streetcodeArt.Art!.Description!, "Арт-галерея", "art-gallery"))); - } + private async Task> GetArtGalleryResultsAsync(string searchQuery) + { + var streetcodeArts = await _repositoryWrapper.StreetcodeArtRepository.GetAllAsync( + x => x.StreetcodeArtSlide!.Streetcode != null && x.StreetcodeArtSlide.Streetcode.Status == DAL.Enums.StreetcodeStatus.Published, + i => i.Include(sArt => sArt.Art).Include(sArt => sArt.StreetcodeArtSlide).ThenInclude(slide => slide!.Streetcode!)); + + return streetcodeArts.Where(streetcodeArt => !string.IsNullOrEmpty(streetcodeArt.Art!.Description) && + streetcodeArt.Art.Description.Contains(searchQuery, StringComparison.OrdinalIgnoreCase)) + .SelectMany(streetcodeArt => streetcodeArt.StreetcodeArtSlide!.StreetcodeArts!.Select(art => + CreateFilterResult(art.StreetcodeArtSlide!.Streetcode!, streetcodeArt.Art!.Description!, "Арт-галерея", "art-gallery"))); + } - private StreetcodeFilterResultDTO CreateFilterResult(StreetcodeContent streetcode, string content, string? sourceName = null, string? blockName = null, int factId = 0, int timelineItemId = 0) + private static StreetcodeFilterResultDTO CreateFilterResult(StreetcodeContent streetcode, string content, string? sourceName = null, string? blockName = null, int factId = 0, int timelineItemId = 0) + { + return new StreetcodeFilterResultDTO { - return new StreetcodeFilterResultDTO - { - StreetcodeId = streetcode.Id, - StreetcodeTransliterationUrl = streetcode.TransliterationUrl!, - StreetcodeIndex = streetcode.Index, - BlockName = blockName!, - Content = content, - SourceName = sourceName!, - FactId = factId, - TimelineItemId = timelineItemId - }; - } + StreetcodeId = streetcode.Id, + StreetcodeTransliterationUrl = streetcode.TransliterationUrl!, + StreetcodeIndex = streetcode.Index, + BlockName = blockName!, + Content = content, + SourceName = sourceName!, + FactId = factId, + TimelineItemId = timelineItemId + }; } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByFilter/GetStreetcodeByFilterQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByFilter/GetStreetcodeByFilterQuery.cs index 3522bd003..5c10585fb 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByFilter/GetStreetcodeByFilterQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByFilter/GetStreetcodeByFilterQuery.cs @@ -3,8 +3,7 @@ using Streetcode.BLL.DTO.AdditionalContent.Filter; using Streetcode.BLL.DTO.Streetcode; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetByFilter -{ - public record class GetStreetcodeByFilterQuery(StreetcodeFilterRequestDTO Filter) - : IRequest>>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetByFilter; + +public record GetStreetcodeByFilterQuery(StreetcodeFilterRequestDTO Filter) + : IRequest>>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetById/GetStreetcodeByIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetById/GetStreetcodeByIdHandler.cs index 214511024..6b38b7349 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetById/GetStreetcodeByIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetById/GetStreetcodeByIdHandler.cs @@ -2,11 +2,8 @@ using FluentResults; using MediatR; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Localization; using Streetcode.BLL.DTO.AdditionalContent.Tag; using Streetcode.BLL.DTO.Streetcode; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetById; @@ -15,33 +12,26 @@ public class GetStreetcodeByIdHandler : IRequestHandler _stringLocalizerCannotFind; - public GetStreetcodeByIdHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) + public GetStreetcodeByIdHandler( + IRepositoryWrapper repositoryWrapper, + IMapper mapper) { _repositoryWrapper = repositoryWrapper; _mapper = mapper; - _logger = logger; - _stringLocalizerCannotFind = stringLocalizerCannotFind; } public async Task> Handle(GetStreetcodeByIdQuery request, CancellationToken cancellationToken) { - var streetcode = await _repositoryWrapper.StreetcodeRepository.GetFirstOrDefaultAsync( - predicate: st => st.Id == request.Id); - - if (streetcode is null) - { - string errorMsg = _stringLocalizerCannotFind["CannotFindAnyStreetcodeWithCorrespondingId", request.Id].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + var streetcode = await _repositoryWrapper.StreetcodeRepository + .GetFirstOrDefaultAsync( + predicate: st => st.Id == request.Id); var tagIndexed = await _repositoryWrapper.StreetcodeTagIndexRepository - .GetAllAsync( - t => t.StreetcodeId == request.Id, - include: q => q.Include(ti => ti.Tag!)); + .GetAllAsync( + predicate: t => t.StreetcodeId == request.Id, + include: q => q.Include(ti => ti.Tag!)); + var streetcodeDto = _mapper.Map(streetcode); streetcodeDto.Tags = _mapper.Map>(tagIndexed); diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByIndex/GetStreetcodeByIndexHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByIndex/GetStreetcodeByIndexHandler.cs index 538679797..916f4ca53 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByIndex/GetStreetcodeByIndexHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByIndex/GetStreetcodeByIndexHandler.cs @@ -17,7 +17,11 @@ public class GetStreetcodeByIndexHandler : IRequestHandler _stringLocalizerCannotFind; - public GetStreetcodeByIndexHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) + public GetStreetcodeByIndexHandler( + IRepositoryWrapper repositoryWrapper, + IMapper mapper, + ILoggerService logger, + IStringLocalizer stringLocalizerCannotFind) { _repositoryWrapper = repositoryWrapper; _mapper = mapper; @@ -33,7 +37,7 @@ public async Task> Handle(GetStreetcodeByIndexQuery reques if (streetcode is null) { - string errorMsg = _stringLocalizerCannotFind["CannotFindAnyStreetcodeWithCorrespondingIndex", request.Index].Value; + var errorMsg = _stringLocalizerCannotFind["CannotFindAnyStreetcodeWithCorrespondingIndex", request.Index].Value; _logger.LogError(request, errorMsg); return Result.Fail(new Error(errorMsg)); } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByTransliterationUrl/GetStreetcodeByTransliterationUrlHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByTransliterationUrl/GetStreetcodeByTransliterationUrlHandler.cs index 7b2fdfbda..87e3ce0c3 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByTransliterationUrl/GetStreetcodeByTransliterationUrlHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByTransliterationUrl/GetStreetcodeByTransliterationUrlHandler.cs @@ -9,50 +9,53 @@ using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetByTransliterationUrl +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetByTransliterationUrl; + +public class GetStreetcodeByTransliterationUrlHandler : IRequestHandler> { - public class GetStreetcodeByTransliterationUrlHandler : IRequestHandler> + private readonly IRepositoryWrapper _repository; + private readonly IMapper _mapper; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerCannotFind; + + public GetStreetcodeByTransliterationUrlHandler( + IRepositoryWrapper repository, + IMapper mapper, + ILoggerService logger, + IStringLocalizer stringLocalizerCannotFind) + { + _repository = repository; + _mapper = mapper; + _logger = logger; + _stringLocalizerCannotFind = stringLocalizerCannotFind; + } + + public async Task> Handle(GetStreetcodeByTransliterationUrlQuery request, CancellationToken cancellationToken) { - private readonly IRepositoryWrapper _repository; - private readonly IMapper _mapper; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerCannotFind; + var streetcode = await _repository.StreetcodeRepository + .GetFirstOrDefaultAsync( + predicate: st => st.TransliterationUrl == request.Url); - public GetStreetcodeByTransliterationUrlHandler(IRepositoryWrapper repository, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) + if (streetcode == null) { - _repository = repository; - _mapper = mapper; - _logger = logger; - _stringLocalizerCannotFind = stringLocalizerCannotFind; + var errorMsg = _stringLocalizerCannotFind["CannotFindStreetcodeByTransliterationUrl", request.Url].Value; + _logger.LogError(request, errorMsg); + return new Error(errorMsg); } - public async Task> Handle(GetStreetcodeByTransliterationUrlQuery request, CancellationToken cancellationToken) + var tagIndexed = await _repository.StreetcodeTagIndexRepository + .GetAllAsync( + t => t.StreetcodeId == streetcode.Id, + include: q => q.Include(ti => ti.Tag!)); + + var streetcodeDto = _mapper.Map(streetcode); + streetcodeDto.Tags = _mapper.Map>(tagIndexed); + + if(streetcodeDto.Tags is not null) { - var streetcode = await _repository.StreetcodeRepository - .GetFirstOrDefaultAsync( - predicate: st => st.TransliterationUrl == request.url); - - if (streetcode == null) - { - string errorMsg = _stringLocalizerCannotFind["CannotFindStreetcodeByTransliterationUrl", request.url].Value; - _logger.LogError(request, errorMsg); - return new Error(errorMsg); - } - - var tagIndexed = await _repository.StreetcodeTagIndexRepository - .GetAllAsync( - t => t.StreetcodeId == streetcode.Id, - include: q => q.Include(ti => ti.Tag!)); - - var streetcodeDTO = _mapper.Map(streetcode); - streetcodeDTO.Tags = _mapper.Map>(tagIndexed); - - if(streetcodeDTO.Tags is not null) - { - streetcodeDTO.Tags = streetcodeDTO.Tags.OrderBy(tag => tag.Index); - } - - return Result.Ok(streetcodeDTO); + streetcodeDto.Tags = streetcodeDto.Tags.OrderBy(tag => tag.Index); } + + return Result.Ok(streetcodeDto); } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByTransliterationUrl/GetStreetcodeByTransliterationUrlQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByTransliterationUrl/GetStreetcodeByTransliterationUrlQuery.cs index 28c9b0616..20814a979 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByTransliterationUrl/GetStreetcodeByTransliterationUrlQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetByTransliterationUrl/GetStreetcodeByTransliterationUrlQuery.cs @@ -2,8 +2,7 @@ using MediatR; using Streetcode.BLL.DTO.Streetcode; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetByTransliterationUrl -{ - public record GetStreetcodeByTransliterationUrlQuery(string url) - : IRequest>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetByTransliterationUrl; + +public record GetStreetcodeByTransliterationUrlQuery(string Url) + : IRequest>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetCount/GetStreetcodesCountHander.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetCount/GetStreetcodesCountHander.cs deleted file mode 100644 index 854b48a80..000000000 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetCount/GetStreetcodesCountHander.cs +++ /dev/null @@ -1,51 +0,0 @@ -using AutoMapper; -using FluentResults; -using MediatR; -using Microsoft.Extensions.Localization; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Entities.Streetcode; -using Streetcode.DAL.Enums; -using Streetcode.DAL.Repositories.Interfaces.Base; - -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetCount -{ - public class GetStreetcodesCountHander : IRequestHandler> - { - private readonly IRepositoryWrapper _repositoryWrapper; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerNo; - - public GetStreetcodesCountHander(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerNo) - { - _repositoryWrapper = repositoryWrapper; - _logger = logger; - _stringLocalizerNo = stringLocalizerNo; - } - - public async Task> Handle(GetStreetcodesCountQuery request, CancellationToken cancellationToken) - { - IEnumerable streetcodes; - - if (request.onlyPublished) - { - streetcodes = await _repositoryWrapper.StreetcodeRepository - .GetAllAsync(s => s.Status == StreetcodeStatus.Published); - } - else - { - streetcodes = await _repositoryWrapper.StreetcodeRepository.GetAllAsync(); - } - - if (streetcodes.Any()) - { - return Result.Ok(streetcodes.Count()); - } - - string errorMsg = _stringLocalizerNo["NoStreetcodesExistNow"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(errorMsg); - } - } -} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetCount/GetStreetcodesCountHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetCount/GetStreetcodesCountHandler.cs new file mode 100644 index 000000000..590f0b288 --- /dev/null +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetCount/GetStreetcodesCountHandler.cs @@ -0,0 +1,53 @@ +using FluentResults; +using MediatR; +using Microsoft.Extensions.Localization; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Enums; +using Streetcode.DAL.Repositories.Interfaces.Base; + +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetCount; + +public class GetStreetcodesCountHandler : IRequestHandler> +{ + private readonly IRepositoryWrapper _repositoryWrapper; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerNo; + + public GetStreetcodesCountHandler( + IRepositoryWrapper repositoryWrapper, + ILoggerService logger, + IStringLocalizer stringLocalizerNo) + { + _repositoryWrapper = repositoryWrapper; + _logger = logger; + _stringLocalizerNo = stringLocalizerNo; + } + + public async Task> Handle(GetStreetcodesCountQuery request, CancellationToken cancellationToken) + { + IEnumerable streetcodes; + + if (request.OnlyPublished) + { + streetcodes = await _repositoryWrapper.StreetcodeRepository + .GetAllAsync(s => s.Status == StreetcodeStatus.Published); + } + else + { + streetcodes = await _repositoryWrapper.StreetcodeRepository.GetAllAsync(); + } + + var streetcodeContents = streetcodes.ToList(); + if (streetcodeContents.Any()) + { + return Result.Ok(streetcodeContents.Count); + } + + var errorMsg = _stringLocalizerNo["NoStreetcodesExistNow"].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(errorMsg); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetCount/GetStreetcodesCountQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetCount/GetStreetcodesCountQuery.cs index 4c37120c9..5e110f471 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetCount/GetStreetcodesCountQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetCount/GetStreetcodesCountQuery.cs @@ -1,8 +1,7 @@ using FluentResults; using MediatR; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetCount -{ - public record GetStreetcodesCountQuery(bool onlyPublished) - : IRequest>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetCount; + +public record GetStreetcodesCountQuery(bool OnlyPublished) + : IRequest>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetFavouriteById/GetFavouriteByIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetFavouriteById/GetFavouriteByIdHandler.cs new file mode 100644 index 000000000..4fd57d644 --- /dev/null +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetFavouriteById/GetFavouriteByIdHandler.cs @@ -0,0 +1,54 @@ +using AutoMapper; +using FluentResults; +using MediatR; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Localization; +using Streetcode.BLL.DTO.Streetcode; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.SharedResource; +using Streetcode.BLL.Util.Helpers; +using Streetcode.DAL.Enums; +using Streetcode.DAL.Repositories.Interfaces.Base; + +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetFavouriteById +{ + public class GetFavouriteByIdHandler : IRequestHandler> + { + private readonly IMapper _mapper; + private readonly IRepositoryWrapper _repositoryWrapper; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerNo; + private readonly IHttpContextAccessor _httpContextAccessor; + + public GetFavouriteByIdHandler(IMapper mapper, IRepositoryWrapper repositoryWrapper, ILoggerService logger, IStringLocalizer stringLocalizerNo, IHttpContextAccessor httpContextAccessor) + { + _mapper = mapper; + _repositoryWrapper = repositoryWrapper; + _logger = logger; + _stringLocalizerNo = stringLocalizerNo; + _httpContextAccessor = httpContextAccessor; + } + + public async Task> Handle(GetFavouriteByIdQuery request, CancellationToken cancellationToken) + { + var userId = HttpContextHelper.GetCurrentUserId(_httpContextAccessor)!; + + var favourite = await _repositoryWrapper.StreetcodeRepository.GetFirstOrDefaultAsync( + predicate: fv => fv.UserFavourites.Any(u => u.Id == userId) && fv.Id == request.StreetcodeId, + include: fv => fv.Include(item => item.Images).ThenInclude(x => x.ImageDetails!)); + + if (favourite is not null) + { + const int keyNumOfImageToDisplay = (int)ImageAssigment.Blackandwhite; + favourite.Images = favourite.Images.Where(x => x.ImageDetails != null && x.ImageDetails.Alt!.Equals(keyNumOfImageToDisplay.ToString())).ToList(); + return Result.Ok(_mapper.Map(favourite)); + } + + string errorMsg = _stringLocalizerNo["NoFavouritesWithId", request.StreetcodeId].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(errorMsg); + } + } +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetFavouriteById/GetFavouriteByIdQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetFavouriteById/GetFavouriteByIdQuery.cs new file mode 100644 index 000000000..87a65b197 --- /dev/null +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetFavouriteById/GetFavouriteByIdQuery.cs @@ -0,0 +1,9 @@ +using FluentResults; +using MediatR; +using Streetcode.BLL.DTO.Streetcode; + +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetFavouriteById +{ + public record GetFavouriteByIdQuery(int StreetcodeId) + : IRequest>; +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetFavouriteStatus/GetFavouriteStatusHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetFavouriteStatus/GetFavouriteStatusHandler.cs new file mode 100644 index 000000000..30b2f45c1 --- /dev/null +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetFavouriteStatus/GetFavouriteStatusHandler.cs @@ -0,0 +1,30 @@ +using FluentResults; +using MediatR; +using Microsoft.AspNetCore.Http; +using Streetcode.BLL.Util.Helpers; +using Streetcode.DAL.Repositories.Interfaces.Base; + +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetFavouriteStatus +{ + public class GetFavouriteStatusHandler : IRequestHandler> + { + private readonly IRepositoryWrapper _repositoryWrapper; + private readonly IHttpContextAccessor _httpContextAccessor; + + public GetFavouriteStatusHandler(IRepositoryWrapper repositoryWrapper, IHttpContextAccessor httpContextAccessor) + { + _repositoryWrapper = repositoryWrapper; + _httpContextAccessor = httpContextAccessor; + } + + public async Task> Handle(GetFavouriteStatusQuery request, CancellationToken cancellationToken) + { + var userId = HttpContextHelper.GetCurrentUserId(_httpContextAccessor)!; + + var favourite = await _repositoryWrapper.StreetcodeRepository.GetFirstOrDefaultAsync( + fv => fv.UserFavourites.Any(u => u.Id == userId) && fv.Id == request.StreetcodeId); + return Result.Ok(favourite != null); + } + } +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetFavouriteStatus/GetFavouriteStatusQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetFavouriteStatus/GetFavouriteStatusQuery.cs new file mode 100644 index 000000000..c8a7b844d --- /dev/null +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetFavouriteStatus/GetFavouriteStatusQuery.cs @@ -0,0 +1,8 @@ +using FluentResults; +using MediatR; + +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetFavouriteStatus +{ + public record GetFavouriteStatusQuery(int StreetcodeId) + : IRequest>; +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetPageMainPage/GetPageOfStreetcodesMainPageHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetPageMainPage/GetPageOfStreetcodesMainPageHandler.cs index e75e31c61..696d79800 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetPageMainPage/GetPageOfStreetcodesMainPageHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetPageMainPage/GetPageOfStreetcodesMainPageHandler.cs @@ -11,61 +11,67 @@ using Streetcode.DAL.Enums; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetPageMainPage +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetPageMainPage; + +public class GetPageOfStreetcodesMainPageHandler : IRequestHandler>> { - public class GetPageOfStreetcodesMainPageHandler : IRequestHandler>> - { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repositoryWrapper; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerNo; + private readonly IMapper _mapper; + private readonly IRepositoryWrapper _repositoryWrapper; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerNo; - public GetPageOfStreetcodesMainPageHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerNo) - { - _repositoryWrapper = repositoryWrapper; - _mapper = mapper; - _logger = logger; - _stringLocalizerNo = stringLocalizerNo; - } + public GetPageOfStreetcodesMainPageHandler( + IRepositoryWrapper repositoryWrapper, + IMapper mapper, + ILoggerService logger, + IStringLocalizer stringLocalizerNo) + { + _repositoryWrapper = repositoryWrapper; + _mapper = mapper; + _logger = logger; + _stringLocalizerNo = stringLocalizerNo; + } - public Task>> Handle(GetPageOfStreetcodesMainPageQuery request, CancellationToken cancellationToken) - { - var streetcodes = _repositoryWrapper.StreetcodeRepository.GetAllPaginated( - request.page, - request.pageSize, - predicate: sc => sc.Status == DAL.Enums.StreetcodeStatus.Published, - include: src => src.Include(item => item.Text).Include(item => item.Images).ThenInclude(x => x.ImageDetails!), + public Task>> Handle(GetPageOfStreetcodesMainPageQuery request, CancellationToken cancellationToken) + { + var streetcodes = _repositoryWrapper.StreetcodeRepository.GetAllPaginated( + request.Page, + request.PageSize, + predicate: sc => sc.Status == StreetcodeStatus.Published, + include: src => src + .Include(item => item.Text) + .Include(item => item.Images) + .ThenInclude(x => x.ImageDetails!), descendingSortKeySelector: sc => sc.CreatedAt) - .Entities.ToList(); + .Entities.ToList(); - if (streetcodes.Any()) + if (streetcodes.Any()) + { + const int keyNumOfImageToDisplay = (int)ImageAssigment.Blackandwhite; + foreach (var streetcode in streetcodes) { - const int keyNumOfImageToDisplay = (int)ImageAssigment.Blackandwhite; - foreach (var streetcode in streetcodes) - { - streetcode.Images = streetcode.Images.Where(x => x.ImageDetails != null && x.ImageDetails.Alt!.Equals(keyNumOfImageToDisplay.ToString())).ToList(); - } - - return Task.FromResult(Result.Ok(_mapper.Map>(ShuffleStreetcodes(streetcodes)))); + streetcode.Images = streetcode.Images + .Where(x => x.ImageDetails != null && x.ImageDetails.Alt!.Equals(keyNumOfImageToDisplay.ToString())) + .ToList(); } - string errorMsg = _stringLocalizerNo["NoStreetcodesExistNow"].Value; - _logger.LogError(request, errorMsg); - return Task.FromResult(Result.Fail>(errorMsg)); + return Task.FromResult(Result.Ok(_mapper.Map>(ShuffleStreetcodes(streetcodes)))); } - private static List ShuffleStreetcodes(IEnumerable streetcodes) + var errorMsg = _stringLocalizerNo["NoStreetcodesExistNow"].Value; + _logger.LogError(request, errorMsg); + return Task.FromResult(Result.Fail>(errorMsg)); + } + + private static List ShuffleStreetcodes(IEnumerable streetcodes) + { + using var rng = RandomNumberGenerator.Create(); + return streetcodes.OrderBy(sc => { - using (var rng = RandomNumberGenerator.Create()) - { - return streetcodes.OrderBy(sc => - { - byte[] random = new byte[4]; - rng.GetBytes(random); - return BitConverter.ToInt32(random, 0) & 0x7FFFFFFF; - }).ToList(); - } - } + var random = new byte[4]; + rng.GetBytes(random); + return BitConverter.ToInt32(random, 0) & 0x7FFFFFFF; + }).ToList(); } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetPageMainPage/GetPageOfStreetcodesMainPageQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetPageMainPage/GetPageOfStreetcodesMainPageQuery.cs index 8055dfcbb..15e79c2b1 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetPageMainPage/GetPageOfStreetcodesMainPageQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetPageMainPage/GetPageOfStreetcodesMainPageQuery.cs @@ -2,8 +2,7 @@ using MediatR; using Streetcode.BLL.DTO.Streetcode; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetPageMainPage -{ - public record GetPageOfStreetcodesMainPageQuery(ushort page, ushort pageSize) - : IRequest>>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetPageMainPage; + +public record GetPageOfStreetcodesMainPageQuery(ushort Page, ushort PageSize) + : IRequest>>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetShortById/GetStreetcodeShortByIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetShortById/GetStreetcodeShortByIdHandler.cs index 849105f2d..d6825a8c7 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetShortById/GetStreetcodeShortByIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetShortById/GetStreetcodeShortByIdHandler.cs @@ -7,51 +7,39 @@ using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetShortById +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetShortById; + +public class GetStreetcodeShortByIdHandler : IRequestHandler> { - public class GetStreetcodeShortByIdHandler : IRequestHandler> + private readonly IMapper _mapper; + private readonly IRepositoryWrapper _repository; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerCannotMap; + + public GetStreetcodeShortByIdHandler( + IMapper mapper, + IRepositoryWrapper repository, + ILoggerService logger, + IStringLocalizer stringLocalizerCannotMap) { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repository; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerCannotFind; - private readonly IStringLocalizer _stringLocalizerCannotMap; + _mapper = mapper; + _repository = repository; + _logger = logger; + _stringLocalizerCannotMap = stringLocalizerCannotMap; + } - public GetStreetcodeShortByIdHandler( - IMapper mapper, - IRepositoryWrapper repository, - ILoggerService logger, - IStringLocalizer stringLocalizerCannotMap, - IStringLocalizer stringLocalizerCannotFind) - { - _mapper = mapper; - _repository = repository; - _logger = logger; - _stringLocalizerCannotMap = stringLocalizerCannotMap; - _stringLocalizerCannotFind = stringLocalizerCannotFind; - } + public async Task> Handle(GetStreetcodeShortByIdQuery request, CancellationToken cancellationToken) + { + var streetcode = await _repository.StreetcodeRepository.GetFirstOrDefaultAsync(st => st.Id == request.Id); + var streetcodeShortDto = _mapper.Map(streetcode); - public async Task> Handle(GetStreetcodeShortByIdQuery request, CancellationToken cancellationToken) + if (streetcodeShortDto == null) { - var streetcode = await _repository.StreetcodeRepository.GetFirstOrDefaultAsync(st => st.Id == request.id); - - if (streetcode == null) - { - string errorMsg = _stringLocalizerCannotFind["CannotFindStreetcodeById"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } - - var streetcodeShortDTO = _mapper.Map(streetcode); - - if(streetcodeShortDTO == null) - { - string errorMsg = _stringLocalizerCannotMap["CannotMapStreetcodeToShortDTO"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } - - return Result.Ok(streetcodeShortDTO); + var errorMsg = _stringLocalizerCannotMap["CannotMapStreetcodeToShortDTO"].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(new Error(errorMsg)); } + + return Result.Ok(streetcodeShortDto); } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetShortById/GetStreetcodeShortByIdQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetShortById/GetStreetcodeShortByIdQuery.cs index 2b911c477..20824b732 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetShortById/GetStreetcodeShortByIdQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetShortById/GetStreetcodeShortByIdQuery.cs @@ -2,8 +2,7 @@ using MediatR; using Streetcode.BLL.DTO.Streetcode; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetShortById -{ - public record GetStreetcodeShortByIdQuery(int id) - : IRequest>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetShortById; + +public record GetStreetcodeShortByIdQuery(int Id) + : IRequest>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetUrlByQrId/GetStreetcodeUrlByQrIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetUrlByQrId/GetStreetcodeUrlByQrIdHandler.cs index 1617fe900..ad021b3db 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetUrlByQrId/GetStreetcodeUrlByQrIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetUrlByQrId/GetStreetcodeUrlByQrIdHandler.cs @@ -6,44 +6,43 @@ using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetUrlByQrId +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetUrlByQrId; + +public class GetStreetcodeUrlByQrIdHandler : IRequestHandler> { - public class GetStreetcodeUrlByQrIdHandler : IRequestHandler> + private readonly IRepositoryWrapper _repository; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerCannotFind; + public GetStreetcodeUrlByQrIdHandler(IRepositoryWrapper repository, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) { - private readonly IRepositoryWrapper _repository; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerCannotFind; - public GetStreetcodeUrlByQrIdHandler(IRepositoryWrapper repository, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) - { - _repository = repository; - _logger = logger; - _stringLocalizerCannotFind = stringLocalizerCannotFind; - } - - public async Task> Handle(GetStreetcodeUrlByQrIdQuery request, CancellationToken cancellationToken) - { - var statisticRecord = await _repository.StatisticRecordRepository - .GetFirstOrDefaultAsync( - predicate: (sr) => sr.QrId == request.qrId, - include: (sr) => sr.Include((sr) => sr.StreetcodeCoordinate)); + _repository = repository; + _logger = logger; + _stringLocalizerCannotFind = stringLocalizerCannotFind; + } - if (statisticRecord == null) - { - string errorMsg = _stringLocalizerCannotFind["CannotFindRecordWithQrId"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + public async Task> Handle(GetStreetcodeUrlByQrIdQuery request, CancellationToken cancellationToken) + { + var statisticRecord = await _repository.StatisticRecordRepository + .GetFirstOrDefaultAsync( + predicate: (sr) => sr.QrId == request.QrId, + include: (sr) => sr.Include((record) => record.StreetcodeCoordinate)); - var streetcode = await _repository.StreetcodeRepository.GetFirstOrDefaultAsync((s) => s.Id == statisticRecord.StreetcodeCoordinate.StreetcodeId); + if (statisticRecord == null) + { + var errorMsg = _stringLocalizerCannotFind["CannotFindRecordWithQrId"].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(new Error(errorMsg)); + } - if(streetcode == null) - { - string errorMsg = _stringLocalizerCannotFind["CannotFindStreetcodeById"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + var streetcode = await _repository.StreetcodeRepository.GetFirstOrDefaultAsync((s) => s.Id == statisticRecord.StreetcodeCoordinate.StreetcodeId); - return Result.Ok(streetcode.TransliterationUrl!); + if(streetcode == null) + { + var errorMsg = _stringLocalizerCannotFind["CannotFindStreetcodeById"].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(new Error(errorMsg)); } + + return Result.Ok(streetcode.TransliterationUrl!); } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetUrlByQrId/GetStreetcodeUrlByQrIdQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetUrlByQrId/GetStreetcodeUrlByQrIdQuery.cs index babb93f31..42fb5233b 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetUrlByQrId/GetStreetcodeUrlByQrIdQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/GetUrlByQrId/GetStreetcodeUrlByQrIdQuery.cs @@ -1,8 +1,7 @@ using FluentResults; using MediatR; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetUrlByQrId -{ - public record GetStreetcodeUrlByQrIdQuery(int qrId) - : IRequest>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.GetUrlByQrId; + +public record GetStreetcodeUrlByQrIdQuery(int QrId) + : IRequest>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Update/UpdateStreetcodeCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Update/UpdateStreetcodeCommand.cs index a8c487b5e..889596a69 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Update/UpdateStreetcodeCommand.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Update/UpdateStreetcodeCommand.cs @@ -2,8 +2,7 @@ using MediatR; using Streetcode.BLL.DTO.Streetcode.Update; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.Update -{ - public record class UpdateStreetcodeCommand(StreetcodeUpdateDTO Streetcode) - : IRequest>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.Update; + +public record UpdateStreetcodeCommand(StreetcodeUpdateDTO Streetcode) + : IRequest>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Update/UpdateStreetcodeHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Update/UpdateStreetcodeHandler.cs index 265708c98..02aa39724 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Update/UpdateStreetcodeHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/Update/UpdateStreetcodeHandler.cs @@ -1,7 +1,6 @@ using AutoMapper; using FluentResults; using MediatR; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Localization; using Streetcode.BLL.DTO.AdditionalContent.Tag; using Streetcode.BLL.DTO.Media.Art; @@ -21,158 +20,160 @@ using Streetcode.DAL.Entities.Streetcode; using Streetcode.DAL.Entities.Timeline; using Streetcode.DAL.Enums; -using Streetcode.BLL.Interfaces.Cache; -using Streetcode.BLL.MediatR.Streetcode.Streetcode.Create; using Streetcode.DAL.Entities.AdditionalContent; using Streetcode.DAL.Entities.Transactions; using Streetcode.DAL.Repositories.Interfaces.Base; using Microsoft.AspNetCore.Http; using Streetcode.BLL.Util.Helpers; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.Update +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.Update; + +public class UpdateStreetcodeHandler : IRequestHandler> { - public class UpdateStreetcodeHandler : IRequestHandler> + private readonly IMapper _mapper; + private readonly IRepositoryWrapper _repositoryWrapper; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerFailedToUpdate; + private readonly IStringLocalizer _stringLocalizerAnErrorOccurred; + private readonly IStringLocalizer _stringLocalizerFailedToValidate; + private readonly IStringLocalizer _stringLocalizerFieldNames; + private readonly ICacheService _cacheService; + private readonly IHttpContextAccessor _httpContextAccessor; + + public UpdateStreetcodeHandler( + IMapper mapper, + IRepositoryWrapper repositoryWrapper, + ILoggerService logger, + IStringLocalizer stringLocalizerAnErrorOccurred, + IStringLocalizer stringLocalizerFailedToUpdate, + IStringLocalizer stringLocalizerFailedToValidate, + IStringLocalizer stringLocalizerFieldNames, + ICacheService cacheService, + IHttpContextAccessor httpContextAccessor) { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repositoryWrapper; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerFailedToUpdate; - private readonly IStringLocalizer _stringLocalizerAnErrorOccurred; - private readonly IStringLocalizer _stringLocalizerFailedToValidate; - private readonly IStringLocalizer _stringLocalizerFieldNames; - private readonly ICacheService _cacheService; - private IHttpContextAccessor _httpContextAccessor; - - public UpdateStreetcodeHandler( - IMapper mapper, - IRepositoryWrapper repositoryWrapper, - ILoggerService logger, - IStringLocalizer stringLocalizerAnErrorOccurred, - IStringLocalizer stringLocalizerFailedToUpdate, - IStringLocalizer stringLocalizerFailedToValidate, - IStringLocalizer stringLocalizerFieldNames, - ICacheService cacheService, - IHttpContextAccessor httpContextAccessor) - { - _mapper = mapper; - _repositoryWrapper = repositoryWrapper; - _logger = logger; - _stringLocalizerFailedToUpdate = stringLocalizerFailedToUpdate; - _stringLocalizerAnErrorOccurred = stringLocalizerAnErrorOccurred; - _stringLocalizerFailedToValidate = stringLocalizerFailedToValidate; - _stringLocalizerFieldNames = stringLocalizerFieldNames; - _stringLocalizerFailedToUpdate = stringLocalizerFailedToUpdate; - _cacheService = cacheService; - _httpContextAccessor = httpContextAccessor; - } + _mapper = mapper; + _repositoryWrapper = repositoryWrapper; + _logger = logger; + _stringLocalizerFailedToUpdate = stringLocalizerFailedToUpdate; + _stringLocalizerAnErrorOccurred = stringLocalizerAnErrorOccurred; + _stringLocalizerFailedToValidate = stringLocalizerFailedToValidate; + _stringLocalizerFieldNames = stringLocalizerFieldNames; + _stringLocalizerFailedToUpdate = stringLocalizerFailedToUpdate; + _cacheService = cacheService; + _httpContextAccessor = httpContextAccessor; + } - public async Task> Handle(UpdateStreetcodeCommand request, CancellationToken cancellationToken) + public async Task> Handle(UpdateStreetcodeCommand request, CancellationToken cancellationToken) + { + using (var transactionScope = _repositoryWrapper.BeginTransaction()) { - using (var transactionScope = _repositoryWrapper.BeginTransaction()) + try { - try + var streetcodeToUpdate = StreetcodeFactory.CreateStreetcode(request.Streetcode.StreetcodeType); + _mapper.Map(request.Streetcode, streetcodeToUpdate); + + await UpdateEntitiesAsync(request.Streetcode.StatisticRecords, _repositoryWrapper.StreetcodeCoordinateRepository); + await UpdateEntitiesAsync(request.Streetcode.StreetcodeCategoryContents, _repositoryWrapper.StreetcodeCategoryContentRepository); + await UpdateEntitiesAsync(request.Streetcode.RelatedFigures, _repositoryWrapper.RelatedFigureRepository); + await UpdateEntitiesAsync(request.Streetcode.Partners, _repositoryWrapper.PartnerStreetcodeRepository); + await UpdateEntitiesAsync(request.Streetcode.Facts, _repositoryWrapper.FactRepository); + await UpdateTags(request.Streetcode.Tags); + await UpdateStreetcodeToponymAsync(streetcodeToUpdate, request.Streetcode.Toponyms); + await UpdateTimelineItemsAsync(streetcodeToUpdate, request.Streetcode.TimelineItems); + UpdateAudio(request.Streetcode.Audios, streetcodeToUpdate); + await UpdateArtGallery(streetcodeToUpdate, request.Streetcode.StreetcodeArtSlides, request.Streetcode.Arts); + await UpdateImagesAsync(request.Streetcode.Images); + UpdateTransactionLink(streetcodeToUpdate, request.Streetcode.ArBlockUrl); + + await UpdateFactsDescription(request.Streetcode.ImagesDetails); + var deleteTransactionLinks = _repositoryWrapper.TransactLinksRepository.FindAll(t => t.StreetcodeId == streetcodeToUpdate.Id); + _repositoryWrapper.TransactLinksRepository.DeleteRange(deleteTransactionLinks); + + if (request.Streetcode.Text != null) { - var streetcodeToUpdate = StreetcodeFactory.CreateStreetcode(request.Streetcode.StreetcodeType); - _mapper.Map(request.Streetcode, streetcodeToUpdate); - - await UpdateEntitiesAsync(request.Streetcode.StatisticRecords, _repositoryWrapper.StreetcodeCoordinateRepository); - await UpdateEntitiesAsync(request.Streetcode.StreetcodeCategoryContents, _repositoryWrapper.StreetcodeCategoryContentRepository); - await UpdateEntitiesAsync(request.Streetcode.RelatedFigures, _repositoryWrapper.RelatedFigureRepository); - await UpdateEntitiesAsync(request.Streetcode.Partners, _repositoryWrapper.PartnerStreetcodeRepository); - await UpdateEntitiesAsync(request.Streetcode.Facts, _repositoryWrapper.FactRepository); - - // await UpdateEntitiesAsync(request.Streetcode.Tags, _repositoryWrapper.StreetcodeTagIndexRepository); - await UpdateTags(request.Streetcode.Tags); - await UpdateStreetcodeToponymAsync(streetcodeToUpdate, request.Streetcode.Toponyms); - await UpdateTimelineItemsAsync(streetcodeToUpdate, request.Streetcode.TimelineItems); - UpdateAudio(request.Streetcode.Audios, streetcodeToUpdate); - await UpdateArtGallery(streetcodeToUpdate, request.Streetcode.StreetcodeArtSlides, request.Streetcode.Arts); - await UpdateImagesAsync(request.Streetcode.Images); - UpdateTransactionLink(streetcodeToUpdate, request.Streetcode.ARBlockUrl); - - await UpdateFactsDescription(request.Streetcode.ImagesDetails); - var deleteTransactionLinks = _repositoryWrapper.TransactLinksRepository.FindAll(t => t.StreetcodeId == streetcodeToUpdate.Id); - _repositoryWrapper.TransactLinksRepository.DeleteRange(deleteTransactionLinks); - - if (request.Streetcode.Text != null) - { - await UpdateEntitiesAsync(new List { request.Streetcode.Text }, _repositoryWrapper.TextRepository); - } - - streetcodeToUpdate.Arts = new List(); - streetcodeToUpdate.StreetcodeArtSlides = new List(); - _repositoryWrapper.StreetcodeRepository.Update(streetcodeToUpdate); - - _repositoryWrapper.StreetcodeRepository.Entry(streetcodeToUpdate).Property(x => x.CreatedAt).IsModified = false; - var discriminatorProperty = _repositoryWrapper.StreetcodeRepository.Entry(streetcodeToUpdate).Property(StreetcodeTypeDiscriminators.DiscriminatorName); - discriminatorProperty.CurrentValue = StreetcodeTypeDiscriminators.GetStreetcodeType(request.Streetcode.StreetcodeType); - discriminatorProperty.IsModified = true; - streetcodeToUpdate.UpdatedAt = DateTime.UtcNow; - streetcodeToUpdate.UserId = HttpContextHelper.GetCurrentUserId(_httpContextAccessor); - var isResultSuccess = await _repositoryWrapper.SaveChangesAsync() > 0; - - if (isResultSuccess) - { - transactionScope.Complete(); - _cacheService.RemoveStreetcodeCaches(streetcodeToUpdate.Id); - return Result.Ok(streetcodeToUpdate.Id); - } - else - { - string errorMsg = _stringLocalizerFailedToUpdate["FailedToUpdateStreetcode"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + await UpdateEntitiesAsync(new List { request.Streetcode.Text }, _repositoryWrapper.TextRepository); } - catch (Exception ex) - { - string errorMsg = _stringLocalizerAnErrorOccurred["AnErrorOccurredWhileUpdating", ex.Message].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); + streetcodeToUpdate.Arts = new List(); + streetcodeToUpdate.StreetcodeArtSlides = new List(); + _repositoryWrapper.StreetcodeRepository.Update(streetcodeToUpdate); + + _repositoryWrapper.StreetcodeRepository.Entry(streetcodeToUpdate).Property(x => x.CreatedAt).IsModified = false; + var discriminatorProperty = _repositoryWrapper.StreetcodeRepository.Entry(streetcodeToUpdate).Property(StreetcodeTypeDiscriminators.DiscriminatorName); + discriminatorProperty.CurrentValue = StreetcodeTypeDiscriminators.GetStreetcodeType(request.Streetcode.StreetcodeType); + discriminatorProperty.IsModified = true; + streetcodeToUpdate.UpdatedAt = DateTime.UtcNow; + streetcodeToUpdate.UserId = HttpContextHelper.GetCurrentUserId(_httpContextAccessor) !; + var isResultSuccess = await _repositoryWrapper.SaveChangesAsync() > 0; + + if (isResultSuccess) + { + transactionScope.Complete(); + _cacheService.RemoveStreetcodeCaches(streetcodeToUpdate.Id); + return Result.Ok(streetcodeToUpdate.Id); } + + var errorMsg = _stringLocalizerFailedToUpdate["FailedToUpdateStreetcode"].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(new Error(errorMsg)); + } + catch (Exception ex) + { + var errorMsg = _stringLocalizerAnErrorOccurred["AnErrorOccurredWhileUpdating", ex.Message].Value; + _logger.LogError(request, errorMsg); + return Result.Fail(new Error(errorMsg)); } } + } + + private async Task UpdateFactsDescription(IEnumerable? imageDetails) + { + var imageDetailsList = imageDetails?.ToList(); - private async Task UpdateFactsDescription(IEnumerable? imageDetails) + if (imageDetailsList is null or { Count: 0 }) { - if (imageDetails == null) - { - return; - } + return; + } - _repositoryWrapper.ImageDetailsRepository - .DeleteRange(_mapper.Map>(imageDetails.Where(f => f.Alt == "" && f.Id != 0))); + _repositoryWrapper.ImageDetailsRepository + .DeleteRange(_mapper.Map>(imageDetailsList.Where(f => f.Alt == "" && f.Id != 0))); - _repositoryWrapper.ImageDetailsRepository - .UpdateRange(_mapper.Map>(imageDetails.Where(f => f.Alt != ""))); + _repositoryWrapper.ImageDetailsRepository + .UpdateRange(_mapper.Map>(imageDetailsList.Where(f => f.Alt != ""))); - await _repositoryWrapper.SaveChangesAsync(); - } + await _repositoryWrapper.SaveChangesAsync(); + } - private async Task UpdateTimelineItemsAsync(StreetcodeContent streetcode, IEnumerable timelineItems) + private async Task UpdateTimelineItemsAsync(StreetcodeContent streetcode, IEnumerable? timelineItems) + { + var timelineItemsList = timelineItems?.ToList(); + + if (timelineItemsList is null or { Count: 0 }) { - var contextToCreate = timelineItems.SelectMany(x => x.HistoricalContexts).Where(c => c.Id == 0).DistinctBy(x => x.Title); - var createdContext = _mapper.Map>(contextToCreate); - await _repositoryWrapper.HistoricalContextRepository.CreateRangeAsync(createdContext); - await _repositoryWrapper.SaveChangesAsync(); + return; + } - var (toUpdate, toCreate, toDelete) = CategorizeItems(timelineItems); + var contextToCreate = timelineItemsList.SelectMany(x => x.HistoricalContexts).Where(c => c.Id == 0).DistinctBy(x => x.Title); + var createdContext = _mapper.Map>(contextToCreate).ToList(); + await _repositoryWrapper.HistoricalContextRepository.CreateRangeAsync(createdContext); + await _repositoryWrapper.SaveChangesAsync(); - var timelineItemsUpdated = new List(); - foreach (var timelineItem in toUpdate) - { - timelineItemsUpdated.Add(_mapper.Map(timelineItem)); - var (historicalContextToUpdate, historicalContextToCreate, historicalContextToDelete) = CategorizeItems(timelineItem.HistoricalContexts); + var (toUpdate, toCreate, toDelete) = CategorizeItems(timelineItemsList); - var deletedItems = historicalContextToDelete.Select(x => new HistoricalContextTimeline + var timelineItemsUpdated = new List(); + foreach (var timelineItem in toUpdate) + { + timelineItemsUpdated.Add(_mapper.Map(timelineItem)); + var (_, historicalContextToCreate, historicalContextToDelete) = CategorizeItems(timelineItem.HistoricalContexts); + + var deletedItems = historicalContextToDelete.Select(x => new HistoricalContextTimeline { TimelineId = timelineItem.Id, HistoricalContextId = x.Id, }) .ToList(); - var createdItems = historicalContextToCreate.Select(x => new HistoricalContextTimeline + var createdItems = historicalContextToCreate.Select(x => new HistoricalContextTimeline { TimelineId = timelineItem.Id, HistoricalContextId = x.Id == 0 @@ -181,285 +182,302 @@ private async Task UpdateTimelineItemsAsync(StreetcodeContent streetcode, IEnume }) .ToList(); - _repositoryWrapper.HistoricalContextTimelineRepository.DeleteRange(deletedItems); - await _repositoryWrapper.HistoricalContextTimelineRepository.CreateRangeAsync(createdItems); - } - - streetcode.TimelineItems.AddRange(timelineItemsUpdated); + _repositoryWrapper.HistoricalContextTimelineRepository.DeleteRange(deletedItems); + await _repositoryWrapper.HistoricalContextTimelineRepository.CreateRangeAsync(createdItems); + } - var timelineItemsCreated = new List(); - foreach (var timelineItem in toCreate) - { - var timelineItemCreate = _mapper.Map(timelineItem); - timelineItemCreate.HistoricalContextTimelines = timelineItem.HistoricalContexts - .Select(x => new HistoricalContextTimeline - { - HistoricalContextId = x.Id == 0 - ? createdContext.First(h => h.Title!.Equals(x.Title)).Id - : x.Id - }) - .ToList(); - - timelineItemsCreated.Add(timelineItemCreate); - } + streetcode.TimelineItems.AddRange(timelineItemsUpdated); - streetcode.TimelineItems.AddRange(timelineItemsCreated); + var timelineItemsCreated = new List(); + foreach (var timelineItem in toCreate) + { + var timelineItemCreate = _mapper.Map(timelineItem); + timelineItemCreate.HistoricalContextTimelines = timelineItem.HistoricalContexts + .Select(x => new HistoricalContextTimeline + { + HistoricalContextId = x.Id == 0 + ? createdContext.First(h => h.Title!.Equals(x.Title)).Id + : x.Id + }) + .ToList(); - _repositoryWrapper.TimelineRepository.DeleteRange(_mapper.Map>(toDelete)); + timelineItemsCreated.Add(timelineItemCreate); } - private async Task UpdateStreetcodeToponymAsync(StreetcodeContent streetcodeContent, IEnumerable toponyms) - { - var (_, toCreate, toDelete) = CategorizeItems(toponyms); - - if (toDelete.Any()) - { - var toponymsNameToDelete = toDelete.Select(x => x.StreetName); - await _repositoryWrapper.ToponymRepository.ExecuteSqlRaw(GetToponymDeleteQuery(streetcodeContent.Id, toponymsNameToDelete)); - } + streetcode.TimelineItems.AddRange(timelineItemsCreated); - var toponymsNameToCreate = toCreate.Select(x => x.StreetName); - var toponymsToAdd = await _repositoryWrapper.ToponymRepository - .GetAllAsync(predicate: t => toponymsNameToCreate.Contains(t.StreetName)); + _repositoryWrapper.TimelineRepository.DeleteRange(_mapper.Map>(toDelete)); + } - streetcodeContent.Toponyms.AddRange(toponymsToAdd); + private async Task UpdateStreetcodeToponymAsync(StreetcodeContent streetcodeContent, IEnumerable? toponyms) + { + if (toponyms is null) + { + return; } - private string GetToponymDeleteQuery(int streetcodeId, IEnumerable toponymsName) + var (_, toCreate, toDelete) = CategorizeItems(toponyms); + + var toDeleteList = toDelete.ToList(); + if (toDeleteList.Any()) { - string query = "DELETE st FROM streetcode.streetcode_toponym AS st " + - "LEFT JOIN toponyms.toponyms AS t ON st.ToponymId = t.Id " + - $"WHERE st.StreetcodeId = {streetcodeId} AND ("; + var toponymsNameToDelete = toDeleteList.Select(x => x.StreetName); + await _repositoryWrapper.ToponymRepository.ExecuteSqlRaw(GetToponymDeleteQuery(streetcodeContent.Id, toponymsNameToDelete)); + } - string condition = string.Join(" OR ", toponymsName.Select(name => $"t.StreetName LIKE '%{name}%'")); - query += condition + ")"; + var toponymsNameToCreate = toCreate.Select(x => x.StreetName); + var toponymsToAdd = await _repositoryWrapper.ToponymRepository + .GetAllAsync(predicate: t => toponymsNameToCreate.Contains(t.StreetName)); - return query; - } + streetcodeContent.Toponyms.AddRange(toponymsToAdd); + } - private async Task UpdateImagesAsync(IEnumerable images) - { - var (_, toCreate, toDelete) = CategorizeItems(images); + private static string GetToponymDeleteQuery(int streetcodeId, IEnumerable toponymsName) + { + string query = "DELETE st FROM streetcode.streetcode_toponym AS st " + + "LEFT JOIN toponyms.toponyms AS t ON st.ToponymId = t.Id " + + $"WHERE st.StreetcodeId = {streetcodeId} AND ("; - _repositoryWrapper.ImageRepository.DeleteRange(_mapper.Map>(toDelete)); - await _repositoryWrapper.StreetcodeImageRepository.CreateRangeAsync(_mapper.Map>(toCreate)); - } + string condition = string.Join(" OR ", toponymsName.Select(name => $"t.StreetName LIKE '%{name}%'")); + query += condition + ")"; - private void UpdateTransactionLink(StreetcodeContent streetcode, string? url) + return query; + } + + private async Task UpdateImagesAsync(IEnumerable images) + { + var (_, toCreate, toDelete) = CategorizeItems(images); + + _repositoryWrapper.ImageRepository.DeleteRange(_mapper.Map>(toDelete)); + await _repositoryWrapper.StreetcodeImageRepository.CreateRangeAsync(_mapper.Map>(toCreate)); + } + + private static void UpdateTransactionLink(StreetcodeContent streetcode, string? url) + { + if (url is null) { - if (url is null) + streetcode.TransactionLink = new TransactionLink() { - streetcode.TransactionLink = new DAL.Entities.Transactions.TransactionLink() - { - Url = "", - UrlTitle = "", - }; - } + Url = string.Empty, + UrlTitle = string.Empty, + }; } + } - private void UpdateAudio(IEnumerable audios, StreetcodeContent streetcode) + private static void UpdateAudio(IEnumerable? audios, StreetcodeContent streetcode) + { + if (audios is null) { - var (toUpdate, toCreate, _) = CategorizeItems(audios); + return; + } - if (toCreate?.Any() == true) - { - streetcode.AudioId = toCreate.First().Id; - } + var (toUpdate, toCreate, _) = CategorizeItems(audios); - if (toUpdate?.Any() == true) - { - streetcode.AudioId = toUpdate.First().Id; - } + var toCreateList = toCreate.ToList(); + var toUpdateList = toUpdate.ToList(); + + if (toCreateList is { Count: > 0 }) + { + streetcode.AudioId = toCreateList[0].Id; } - private async Task UpdateArtGallery(StreetcodeContent streetcode, IEnumerable artSlides, IEnumerable arts) + if (toUpdateList is { Count: > 0 }) { - _repositoryWrapper.StreetcodeArtRepository.DeleteRange(await _repositoryWrapper.StreetcodeArtRepository.GetAllAsync(a => a.StreetcodeId == streetcode.Id)); - await _repositoryWrapper.SaveChangesAsync(); + streetcode.AudioId = toUpdateList[0].Id; + } + } - var filteredCreatedArts = arts.Where(art => art.ModelState == ModelState.Created).ToList(); + private async Task UpdateArtGallery(StreetcodeContent streetcode, IEnumerable? artSlides, IEnumerable? arts) + { + _repositoryWrapper.StreetcodeArtRepository.DeleteRange(await _repositoryWrapper.StreetcodeArtRepository.GetAllAsync(a => a.StreetcodeId == streetcode.Id)); + await _repositoryWrapper.SaveChangesAsync(); + var artSlidesList = artSlides?.ToList() ?? new List(); + var artsList = arts?.ToList() ?? new List(); - var usedArtIds = new HashSet(artSlides.Where(slide => slide.ModelState != ModelState.Deleted).SelectMany(slide => slide.StreetcodeArts).Select(streetcodeArt => streetcodeArt.ArtId)); + var filteredCreatedArts = artsList.Where(art => art.ModelState == ModelState.Created).ToList(); - var filteredArts = filteredCreatedArts.Where(art => usedArtIds.Contains(art.Id)).ToList(); - var filteredUnusedExistingArtsToDelete = arts.Where(art => !usedArtIds.Contains(art.Id) && art.ModelState == ModelState.Updated).ToList(); + var usedArtIds = new HashSet(artSlidesList.Where(slide => slide.ModelState != ModelState.Deleted).SelectMany(slide => slide.StreetcodeArts).Select(streetcodeArt => streetcodeArt.ArtId)); - var unusedExistingArtsToDelete = filteredUnusedExistingArtsToDelete - .Select(art => - { - var mappedArt = _mapper.Map(art); - mappedArt.Id = art.Id; - return mappedArt; - }) - .ToList(); + var filteredArts = filteredCreatedArts.Where(art => usedArtIds.Contains(art.Id)).ToList(); + var filteredUnusedExistingArtsToDelete = artsList.Where(art => !usedArtIds.Contains(art.Id) && art.ModelState == ModelState.Updated).ToList(); - var newArts = _mapper.Map>(filteredArts); - newArts.ForEach(art => art.StreetcodeId = streetcode.Id); + var unusedExistingArtsToDelete = filteredUnusedExistingArtsToDelete + .Select(art => + { + var mappedArt = _mapper.Map(art); + mappedArt.Id = art.Id; + return mappedArt; + }) + .ToList(); + + var newArts = _mapper.Map>(filteredArts); + newArts.ForEach(art => art.StreetcodeId = streetcode.Id); - await _repositoryWrapper.ArtRepository.CreateRangeAsync(newArts); - await _repositoryWrapper.SaveChangesAsync(); + await _repositoryWrapper.ArtRepository.CreateRangeAsync(newArts); + await _repositoryWrapper.SaveChangesAsync(); - var artIdMap = filteredArts.Zip(newArts, (placeholderArt, newArt) => new { PlaceholderId = placeholderArt.Id, RealId = newArt.Id }) - .ToDictionary(x => x.PlaceholderId, x => x.RealId); + var artIdMap = filteredArts.Zip(newArts, (placeholderArt, newArt) => new { PlaceholderId = placeholderArt.Id, RealId = newArt.Id }) + .ToDictionary(x => x.PlaceholderId, x => x.RealId); - var toDeleteArts = new List(); - var toUpdateArts = new List(); - foreach (var art in arts) + var toDeleteArts = new List(); + var toUpdateArts = new List(); + foreach (var art in artsList) + { + var newArt = _mapper.Map(art); + newArt.StreetcodeId = streetcode.Id; + newArt.Id = art.Id; + if (art.ModelState == ModelState.Deleted) { - var newArt = _mapper.Map(art); - newArt.StreetcodeId = streetcode.Id; - newArt.Id = art.Id; - if (art.ModelState == ModelState.Deleted) - { - toDeleteArts.Add(newArt); - } - else if (art.ModelState == ModelState.Updated && usedArtIds.Contains(art.Id)) - { - toUpdateArts.Add(newArt); - } + toDeleteArts.Add(newArt); + } + else if (art.ModelState == ModelState.Updated && usedArtIds.Contains(art.Id)) + { + toUpdateArts.Add(newArt); } + } - _repositoryWrapper.ArtRepository.DeleteRange(toDeleteArts.Concat(unusedExistingArtsToDelete)); - _repositoryWrapper.ArtRepository.UpdateRange(toUpdateArts); - await _repositoryWrapper.SaveChangesAsync(); + _repositoryWrapper.ArtRepository.DeleteRange(toDeleteArts.Concat(unusedExistingArtsToDelete)); + _repositoryWrapper.ArtRepository.UpdateRange(toUpdateArts); + await _repositoryWrapper.SaveChangesAsync(); - StreetcodeArtSlide? toCreateSlide = null; - var toDeleteSlides = new List(); - var toUpdateSlides = new List(); + StreetcodeArtSlide? toCreateSlide = null; + var toDeleteSlides = new List(); + var toUpdateSlides = new List(); - var toCreateStreetcodeArts = new List(); - foreach (var artSlide in artSlides) - { - var newArtSlide = _mapper.Map(artSlide); - newArtSlide.StreetcodeId = streetcode.Id; - newArtSlide.StreetcodeArts = null; + var toCreateStreetcodeArts = new List(); + foreach (var artSlide in artSlidesList) + { + var newArtSlide = _mapper.Map(artSlide); + newArtSlide.StreetcodeId = streetcode.Id; + newArtSlide.StreetcodeArts = null; - var newStreetcodeArts = - GetStreetcodeArtsWithNewArtsId(streetcode.Id, artIdMap, artSlide); + var newStreetcodeArts = + GetStreetcodeArtsWithNewArtsId(streetcode.Id, artIdMap, artSlide); - DistributeArtSlide(artSlide, newArtSlide, newStreetcodeArts, ref toCreateSlide, ref toUpdateSlides, ref toDeleteSlides, ref toCreateStreetcodeArts); + DistributeArtSlide(artSlide, newArtSlide, newStreetcodeArts, ref toCreateSlide, ref toUpdateSlides, ref toDeleteSlides, ref toCreateStreetcodeArts); - if (toCreateSlide != null) + if (toCreateSlide != null) + { + await _repositoryWrapper.StreetcodeArtSlideRepository.CreateAsync(toCreateSlide); + await _repositoryWrapper.SaveChangesAsync(); + foreach (var streetcodeArt in newStreetcodeArts) { - await _repositoryWrapper.StreetcodeArtSlideRepository.CreateAsync(toCreateSlide); - await _repositoryWrapper.SaveChangesAsync(); - foreach (var streetcodeArt in newStreetcodeArts) - { - streetcodeArt.StreetcodeArtSlideId = toCreateSlide.Id; - toCreateStreetcodeArts.Add(streetcodeArt); - } - - toCreateSlide = null; + streetcodeArt.StreetcodeArtSlideId = toCreateSlide.Id; + toCreateStreetcodeArts.Add(streetcodeArt); } - } - _repositoryWrapper.StreetcodeArtSlideRepository.DeleteRange(toDeleteSlides); - _repositoryWrapper.StreetcodeArtSlideRepository.UpdateRange(toUpdateSlides); - await _repositoryWrapper.StreetcodeArtRepository.CreateRangeAsync(toCreateStreetcodeArts); - await _repositoryWrapper.SaveChangesAsync(); + toCreateSlide = null; + } } - private async Task UpdateEntitiesAsync(IEnumerable updates, IRepositoryBase repository) - where T : class - where U : IModelState - { - var (toUpdate, toCreate, toDelete) = CategorizeItems(updates); + _repositoryWrapper.StreetcodeArtSlideRepository.DeleteRange(toDeleteSlides); + _repositoryWrapper.StreetcodeArtSlideRepository.UpdateRange(toUpdateSlides); + await _repositoryWrapper.StreetcodeArtRepository.CreateRangeAsync(toCreateStreetcodeArts); + await _repositoryWrapper.SaveChangesAsync(); + } - await repository.CreateRangeAsync(_mapper.Map>(toCreate)); - repository.DeleteRange(_mapper.Map>(toDelete)); - repository.UpdateRange(_mapper.Map>(toUpdate)); + private async Task UpdateEntitiesAsync(IEnumerable? updates, IRepositoryBase repository) + where T : class + where TU : IModelState + { + if (updates == null) + { + return; } - private async Task UpdateTags(IEnumerable tags) - { - var (toUpdate, toCreate, toDelete) = CategorizeItems(tags); + var (toUpdate, toCreate, toDelete) = CategorizeItems(updates); - foreach (var newTag in toCreate) - { - var existingTag = await _repositoryWrapper.TagRepository.GetFirstOrDefaultAsync(t => t.Title == newTag.Title); - if (existingTag is not null && existingTag.Id != newTag.Id) - { - throw new HttpRequestException(_stringLocalizerFailedToValidate["MustBeUnique", _stringLocalizerFieldNames["Tag"]], null, System.Net.HttpStatusCode.BadRequest); - } - } + await repository.CreateRangeAsync(_mapper.Map>(toCreate)); + repository.DeleteRange(_mapper.Map>(toDelete)); + repository.UpdateRange(_mapper.Map>(toUpdate)); + } - await _repositoryWrapper.StreetcodeTagIndexRepository.CreateRangeAsync(_mapper.Map>(toCreate)); - _repositoryWrapper.StreetcodeTagIndexRepository.DeleteRange(_mapper.Map>(toDelete)); - _repositoryWrapper.StreetcodeTagIndexRepository.UpdateRange(_mapper.Map>(toUpdate)); + private async Task UpdateTags(IEnumerable? tags) + { + if (tags is null) + { + return; } - private (IEnumerable toUpdate, IEnumerable toCreate, IEnumerable toDelete) CategorizeItems(IEnumerable items) - where T : IModelState - { - var toUpdate = new List(); - var toCreate = new List(); - var toDelete = new List(); + var (toUpdate, toCreate, toDelete) = CategorizeItems(tags); - foreach (var item in items) + foreach (var newTag in toCreate) + { + var existingTag = await _repositoryWrapper.TagRepository.GetFirstOrDefaultAsync(t => t.Title == newTag.Title); + if (existingTag is not null && existingTag.Id != newTag.Id) { - switch (item.ModelState) - { - case Enums.ModelState.Updated: - toUpdate.Add(item); - break; - case Enums.ModelState.Created: - toCreate.Add(item); - break; - default: - toDelete.Add(item); - break; - } + throw new HttpRequestException(_stringLocalizerFailedToValidate["MustBeUnique", _stringLocalizerFieldNames["Tag"]], null, System.Net.HttpStatusCode.BadRequest); } - - return (toUpdate, toCreate, toDelete); } - private List GetStreetcodeArtsWithNewArtsId(int streetcodeId, Dictionary artIdMap, StreetcodeArtSlideCreateUpdateDTO streetcodeArtSlide) + await _repositoryWrapper.StreetcodeTagIndexRepository.CreateRangeAsync(_mapper.Map>(toCreate)); + _repositoryWrapper.StreetcodeTagIndexRepository.DeleteRange(_mapper.Map>(toDelete)); + _repositoryWrapper.StreetcodeTagIndexRepository.UpdateRange(_mapper.Map>(toUpdate)); + } + + private static (IEnumerable toUpdate, IEnumerable toCreate, IEnumerable toDelete) CategorizeItems(IEnumerable items) + where T : IModelState + { + var toUpdate = new List(); + var toCreate = new List(); + var toDelete = new List(); + + foreach (var item in items) { - var newStreetcodeArts = new List(); - foreach (var art in streetcodeArtSlide.StreetcodeArts) + switch (item.ModelState) { - var newArt = _mapper.Map(art); - newArt.StreetcodeId = streetcodeId; - if (artIdMap.TryGetValue(art.ArtId, out var newArtId)) - { - newArt.ArtId = newArtId; - } - else - { - newArt.ArtId = art.ArtId; - } - - newStreetcodeArts.Add(newArt); + case ModelState.Updated: + toUpdate.Add(item); + break; + case ModelState.Created: + toCreate.Add(item); + break; + default: + toDelete.Add(item); + break; } + } + + return (toUpdate, toCreate, toDelete); + } - return newStreetcodeArts; + private List GetStreetcodeArtsWithNewArtsId(int streetcodeId, Dictionary artIdMap, StreetcodeArtSlideCreateUpdateDTO streetcodeArtSlide) + { + var newStreetcodeArts = new List(); + foreach (var art in streetcodeArtSlide.StreetcodeArts) + { + var newArt = _mapper.Map(art); + newArt.StreetcodeId = streetcodeId; + newArt.ArtId = artIdMap.TryGetValue(art.ArtId, out var newArtId) ? newArtId : art.ArtId; + newStreetcodeArts.Add(newArt); } - private void DistributeArtSlide(StreetcodeArtSlideCreateUpdateDTO artSlideDto, StreetcodeArtSlide artSlide, List newStreetcodeArts, ref StreetcodeArtSlide? toCreateSlide, ref List toUpdateSlides, ref List toDeleteSlides, ref List toCreateStreetcodeArts) + return newStreetcodeArts; + } + + private static void DistributeArtSlide(StreetcodeArtSlideCreateUpdateDTO artSlideDto, StreetcodeArtSlide artSlide, List newStreetcodeArts, ref StreetcodeArtSlide? toCreateSlide, ref List toUpdateSlides, ref List toDeleteSlides, ref List toCreateStreetcodeArts) + { + switch (artSlideDto.ModelState) { - if (artSlideDto.ModelState == ModelState.Created) - { + case ModelState.Created: toCreateSlide = artSlide; - return; - } + break; - artSlide.Id = artSlideDto.SlideId; - if (artSlideDto.ModelState == ModelState.Deleted) - { + case ModelState.Deleted: + artSlide.Id = artSlideDto.SlideId; toDeleteSlides.Add(artSlide); - return; - } + break; - if (artSlideDto.ModelState == ModelState.Updated) - { + case ModelState.Updated: + artSlide.Id = artSlideDto.SlideId; toUpdateSlides.Add(artSlide); foreach (var streetcodeArt in newStreetcodeArts) { streetcodeArt.StreetcodeArtSlideId = artSlideDto.SlideId; toCreateStreetcodeArts.Add(streetcodeArt); } - } + + break; } } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/UpdateStatus/UpdateStatusStreetcodeByIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/UpdateStatus/UpdateStatusStreetcodeByIdHandler.cs index b570d7a71..9bcea6b93 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/UpdateStatus/UpdateStatusStreetcodeByIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/UpdateStatus/UpdateStatusStreetcodeByIdHandler.cs @@ -33,7 +33,7 @@ public async Task> Handle(UpdateStatusStreetcodeByIdCommand request if (streetcode is null) { - string errorMsg = _stringLocalizerCannotFind["CannotFindAnyStreetcodeWithCorrespondingId", request.Id].Value; + var errorMsg = _stringLocalizerCannotFind["CannotFindAnyStreetcodeWithCorrespondingId", request.Id].Value; _logger.LogError(request, errorMsg); return Result.Fail(new Error(errorMsg)); } @@ -49,11 +49,9 @@ public async Task> Handle(UpdateStatusStreetcodeByIdCommand request { return Result.Ok(Unit.Value); } - else - { - string errorMsg = _stringLocalizerFailedToUpdate["FailedToUpdateStatusOfStreetcode"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + + var finalErrorMsg = _stringLocalizerFailedToUpdate["FailedToUpdateStatusOfStreetcode"].Value; + _logger.LogError(request, finalErrorMsg); + return Result.Fail(new Error(finalErrorMsg)); } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithIndexExist/StreetcodeWithIndexExistHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithIndexExist/StreetcodeWithIndexExistHandler.cs index 8a728b526..4ce3fcf52 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithIndexExist/StreetcodeWithIndexExistHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithIndexExist/StreetcodeWithIndexExistHandler.cs @@ -1,33 +1,21 @@ -using AutoMapper; -using FluentResults; +using FluentResults; using MediatR; -using Streetcode.BLL.Interfaces.Logging; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.WithIndexExist -{ - public class StreetcodeWithIndexExistHandler : IRequestHandler> - { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repositoryWrapper; - private readonly ILoggerService _logger; +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.WithIndexExist; - public StreetcodeWithIndexExistHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger) - { - _repositoryWrapper = repositoryWrapper; - _mapper = mapper; - _logger = logger; - } +public class StreetcodeWithIndexExistHandler : IRequestHandler> +{ + private readonly IRepositoryWrapper _repositoryWrapper; - public async Task> Handle(StreetcodeWithIndexExistQuery request, CancellationToken cancellationToken) - { - var streetcode = await _repositoryWrapper.StreetcodeRepository.GetFirstOrDefaultAsync(s => s.Index == request.index); - if (streetcode == null) - { - return Result.Ok(false); - } + public StreetcodeWithIndexExistHandler(IRepositoryWrapper repositoryWrapper) + { + _repositoryWrapper = repositoryWrapper; + } - return Result.Ok(true); - } + public async Task> Handle(StreetcodeWithIndexExistQuery request, CancellationToken cancellationToken) + { + var streetcode = await _repositoryWrapper.StreetcodeRepository.GetFirstOrDefaultAsync(s => s.Index == request.Index); + return Result.Ok(streetcode != null); } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithIndexExist/StreetcodeWithIndexExistQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithIndexExist/StreetcodeWithIndexExistQuery.cs index 40eaae8d0..a1662de8d 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithIndexExist/StreetcodeWithIndexExistQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithIndexExist/StreetcodeWithIndexExistQuery.cs @@ -3,6 +3,6 @@ namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.WithIndexExist { - public record StreetcodeWithIndexExistQuery(int index) + public record StreetcodeWithIndexExistQuery(int Index) : IRequest>; } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithUrlExist/StreetcodeWithUrlExistHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithUrlExist/StreetcodeWithUrlExistHandler.cs index b5e093579..f2283e256 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithUrlExist/StreetcodeWithUrlExistHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithUrlExist/StreetcodeWithUrlExistHandler.cs @@ -1,25 +1,21 @@ using FluentResults; using MediatR; -using Streetcode.BLL.Interfaces.Logging; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.WithUrlExist +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.WithUrlExist; + +public class StreetcodeWithUrlExistHandler : IRequestHandler> { - public class StreetcodeWithUrlExistHandler : IRequestHandler> - { - private readonly IRepositoryWrapper _repository; - private readonly ILoggerService _logger; + private readonly IRepositoryWrapper _repository; - public StreetcodeWithUrlExistHandler(IRepositoryWrapper repository, ILoggerService logger) - { - _repository = repository; - _logger = logger; - } + public StreetcodeWithUrlExistHandler(IRepositoryWrapper repository) + { + _repository = repository; + } - public async Task> Handle(StreetcodeWithUrlExistQuery request, CancellationToken cancellationToken) - { - var streetcodes = await _repository.StreetcodeRepository.GetFirstOrDefaultAsync(predicate: st => st.TransliterationUrl == request.url); - return Result.Ok(streetcodes != null); - } + public async Task> Handle(StreetcodeWithUrlExistQuery request, CancellationToken cancellationToken) + { + var streetcodes = await _repository.StreetcodeRepository.GetFirstOrDefaultAsync(predicate: st => st.TransliterationUrl == request.Url); + return Result.Ok(streetcodes != null); } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithUrlExist/StreetcodeWithUrlExistQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithUrlExist/StreetcodeWithUrlExistQuery.cs index e02e5a9ad..6ecc8038b 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithUrlExist/StreetcodeWithUrlExistQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Streetcode/WithUrlExist/StreetcodeWithUrlExistQuery.cs @@ -1,8 +1,7 @@ using FluentResults; using MediatR; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.WithUrlExist -{ - public record StreetcodeWithUrlExistQuery(string url) - : IRequest>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.WithUrlExist; + +public record StreetcodeWithUrlExistQuery(string Url) + : IRequest>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Create/CreateTermCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Create/CreateTermCommand.cs index 2b9e5bd05..2b7c54bc3 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Create/CreateTermCommand.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Create/CreateTermCommand.cs @@ -2,8 +2,7 @@ using MediatR; using Streetcode.BLL.DTO.Streetcode.TextContent; -namespace Streetcode.BLL.MediatR.Streetcode.Term.Create -{ - public record CreateTermCommand(TermCreateDTO Term) - : IRequest>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Term.Create; + +public record CreateTermCommand(TermCreateDTO Term) + : IRequest>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Create/CreateTermHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Create/CreateTermHandler.cs index 64f04f3e2..8a21c8c78 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Create/CreateTermHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Create/CreateTermHandler.cs @@ -6,75 +6,62 @@ using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; +using TermEntity = Streetcode.DAL.Entities.Streetcode.TextContent.Term; -namespace Streetcode.BLL.MediatR.Streetcode.Term.Create +namespace Streetcode.BLL.MediatR.Streetcode.Term.Create; + +public class CreateTermHandler : IRequestHandler> { - public class CreateTermHandler : IRequestHandler> + private readonly IMapper _mapper; + private readonly IRepositoryWrapper _repository; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerCannotConvert; + private readonly IStringLocalizer _stringLocalizerFailedToCreate; + + public CreateTermHandler( + IMapper mapper, + IRepositoryWrapper repository, + ILoggerService logger, + IStringLocalizer stringLocalizerFailedToCreate, + IStringLocalizer stringLocalizerCannotConvert) { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repository; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerCannotConvert; - private readonly IStringLocalizer _stringLocalizerCannotCreate; - private readonly IStringLocalizer _stringLocalizerFailedToCreate; + _mapper = mapper; + _repository = repository; + _logger = logger; + _stringLocalizerFailedToCreate = stringLocalizerFailedToCreate; + _stringLocalizerCannotConvert = stringLocalizerCannotConvert; + } - public CreateTermHandler( - IMapper mapper, - IRepositoryWrapper repository, - ILoggerService logger, - IStringLocalizer stringLocalizerCannotCreate, - IStringLocalizer stringLocalizerFailedToCreate, - IStringLocalizer stringLocalizerCannotConvert) - { - _mapper = mapper; - _repository = repository; - _logger = logger; - _stringLocalizerCannotCreate = stringLocalizerCannotCreate; - _stringLocalizerFailedToCreate = stringLocalizerFailedToCreate; - _stringLocalizerCannotConvert = stringLocalizerCannotConvert; - } + public async Task> Handle(CreateTermCommand request, CancellationToken cancellationToken) + { + var term = _mapper.Map(request.Term); - public async Task> Handle(CreateTermCommand request, CancellationToken cancellationToken) + if (term is null) { - var term = _mapper.Map(request.Term); - - if (term is null) - { - string errorMsg = _stringLocalizerCannotConvert["CannotConvertNullToTerm"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } - - var createdTerm = _repository.TermRepository.Create(term); - - if (createdTerm is null) - { - string errorMsg = _stringLocalizerCannotCreate["CannotCreateTerm"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + var errorMessage = _stringLocalizerCannotConvert["CannotConvertNullToTerm"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); + } - var resultIsSuccess = await _repository.SaveChangesAsync() > 0; + var createdTerm = await _repository.TermRepository.CreateAsync(term); + var resultIsSuccess = await _repository.SaveChangesAsync() > 0; - if(!resultIsSuccess) - { - string errorMsg = _stringLocalizerFailedToCreate["FailedToCreateTerm"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + if (!resultIsSuccess) + { + var errorMessage = _stringLocalizerFailedToCreate["FailedToCreateTerm"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); + } - var createdTermDTO = _mapper.Map(createdTerm); + var createdTermDto = _mapper.Map(createdTerm); - if(createdTermDTO != null) - { - return Result.Ok(createdTermDTO); - } - else - { - string errorMsg = _stringLocalizerFailedToCreate["FailedToMapCreatedTerm"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + if (createdTermDto is null) + { + var errorMessage = _stringLocalizerFailedToCreate["FailedToMapCreatedTerm"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } + + return Result.Ok(createdTermDto); } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Delete/DeleteTermCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Delete/DeleteTermCommand.cs index de63e0f9e..eb48e6b09 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Delete/DeleteTermCommand.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Delete/DeleteTermCommand.cs @@ -1,8 +1,7 @@ using FluentResults; using MediatR; -namespace Streetcode.BLL.MediatR.Streetcode.Term.Delete -{ - public record DeleteTermCommand(int id) - : IRequest>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Term.Delete; + +public record DeleteTermCommand(int id) + : IRequest>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Delete/DeleteTermHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Delete/DeleteTermHandler.cs index 98aa2c304..2f9648152 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Delete/DeleteTermHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Delete/DeleteTermHandler.cs @@ -5,47 +5,48 @@ using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.Term.Delete +namespace Streetcode.BLL.MediatR.Streetcode.Term.Delete; + +public class DeleteTermHandler : IRequestHandler> { - public class DeleteTermHandler : IRequestHandler> + private readonly IRepositoryWrapper _repository; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerCannotConvert; + private readonly IStringLocalizer _stringLocalizerFailedToDelete; + + public DeleteTermHandler( + IRepositoryWrapper repository, + ILoggerService logger, + IStringLocalizer stringLocalizerFailedToDelete, + IStringLocalizer stringLocalizerCannotConvert) { - private readonly IRepositoryWrapper _repository; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerCannotConvert; - private readonly IStringLocalizer _stringLocalizerFailedToDelete; + _repository = repository; + _logger = logger; + _stringLocalizerFailedToDelete = stringLocalizerFailedToDelete; + _stringLocalizerCannotConvert = stringLocalizerCannotConvert; + } - public DeleteTermHandler(IRepositoryWrapper repository, ILoggerService logger, IStringLocalizer stringLocalizerFailedToDelete, IStringLocalizer stringLocalizerCannotConvert) + public async Task> Handle(DeleteTermCommand request, CancellationToken cancellationToken) + { + var term = await _repository.TermRepository.GetFirstOrDefaultAsync(x => x.Id == request.id); + + if (term is null) { - _repository = repository; - _logger = logger; - _stringLocalizerFailedToDelete = stringLocalizerFailedToDelete; - _stringLocalizerCannotConvert = stringLocalizerCannotConvert; + var errorMessage = _stringLocalizerCannotConvert["CannotConvertNullToTerm"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } - public async Task> Handle(DeleteTermCommand request, CancellationToken cancellationToken) + _repository.TermRepository.Delete(term); + var resultIsSuccess = await _repository.SaveChangesAsync() > 0; + + if (!resultIsSuccess) { - var term = await _repository.TermRepository.GetFirstOrDefaultAsync((term) => term.Id == request.id); - - if (term is null) - { - string errorMsg = _stringLocalizerCannotConvert["CannotConvertNullToTerm"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } - - _repository.TermRepository.Delete(term); - - var resultIsSuccess = await _repository.SaveChangesAsync() > 0; - if(resultIsSuccess) - { - return Result.Ok(Unit.Value); - } - else - { - string errorMsg = _stringLocalizerFailedToDelete["FailedToDeleteTerm"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + var errorMessage = _stringLocalizerFailedToDelete["FailedToDeleteTerm"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } + + return Result.Ok(Unit.Value); } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/GetAll/GetAllTermsHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/GetAll/GetAllTermsHandler.cs index cb1f33fc6..d94522da2 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/GetAll/GetAllTermsHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/GetAll/GetAllTermsHandler.cs @@ -1,41 +1,26 @@ using AutoMapper; using FluentResults; using MediatR; -using Microsoft.Extensions.Localization; using Streetcode.BLL.DTO.Streetcode.TextContent; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Streetcode.Term.GetAll -{ - public class GetAllTermsHandler : IRequestHandler>> - { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repositoryWrapper; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerCannotFind; +namespace Streetcode.BLL.MediatR.Streetcode.Term.GetAll; - public GetAllTermsHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) - { - _repositoryWrapper = repositoryWrapper; - _mapper = mapper; - _logger = logger; - _stringLocalizerCannotFind = stringLocalizerCannotFind; - } +public class GetAllTermsHandler : IRequestHandler>> +{ + private readonly IMapper _mapper; + private readonly IRepositoryWrapper _repositoryWrapper; - public async Task>> Handle(GetAllTermsQuery request, CancellationToken cancellationToken) - { - var terms = await _repositoryWrapper.TermRepository.GetAllAsync(); + public GetAllTermsHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper) + { + _repositoryWrapper = repositoryWrapper; + _mapper = mapper; + } - if (terms is null) - { - string errorMsg = _stringLocalizerCannotFind["CannotFindAnyTerm"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + public async Task>> Handle(GetAllTermsQuery request, CancellationToken cancellationToken) + { + var terms = await _repositoryWrapper.TermRepository.GetAllAsync(); - return Result.Ok(_mapper.Map>(terms)); - } + return Result.Ok(_mapper.Map>(terms)); } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/GetAll/GetAllTermsQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/GetAll/GetAllTermsQuery.cs index b0136929b..006ba2d0b 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/GetAll/GetAllTermsQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/GetAll/GetAllTermsQuery.cs @@ -2,7 +2,7 @@ using MediatR; using Streetcode.BLL.DTO.Streetcode.TextContent; -namespace Streetcode.BLL.MediatR.Streetcode.Term.GetAll -{ - public record GetAllTermsQuery : IRequest>>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Term.GetAll; + +public record GetAllTermsQuery + : IRequest>>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/GetById/GetTermByIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/GetById/GetTermByIdHandler.cs index e65178f24..538b51d34 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/GetById/GetTermByIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/GetById/GetTermByIdHandler.cs @@ -16,7 +16,11 @@ public class GetTermByIdHandler : IRequestHandler _stringLocalizerCannotFind; - public GetTermByIdHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) + public GetTermByIdHandler( + IRepositoryWrapper repositoryWrapper, + IMapper mapper, + ILoggerService logger, + IStringLocalizer stringLocalizerCannotFind) { _repositoryWrapper = repositoryWrapper; _mapper = mapper; @@ -26,15 +30,15 @@ public GetTermByIdHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, public async Task> Handle(GetTermByIdQuery request, CancellationToken cancellationToken) { - var term = await _repositoryWrapper.TermRepository.GetFirstOrDefaultAsync(f => f.Id == request.Id); + var term = await _repositoryWrapper.TermRepository.GetFirstOrDefaultAsync(x => x.Id == request.Id); if (term is null) { - string errorMsg = _stringLocalizerCannotFind["CannotFindAnyTermWithCorrespondingId", request.Id].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); + var errorMessage = _stringLocalizerCannotFind["CannotFindAnyTermWithCorrespondingId", request.Id].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } return Result.Ok(_mapper.Map(term)); } -} \ No newline at end of file +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Update/UpdateTermCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Update/UpdateTermCommand.cs index 79f25013c..b10810fda 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Update/UpdateTermCommand.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Update/UpdateTermCommand.cs @@ -2,8 +2,7 @@ using MediatR; using Streetcode.BLL.DTO.Streetcode.TextContent; -namespace Streetcode.BLL.MediatR.Streetcode.Term.Update -{ - public record UpdateTermCommand(TermDTO Term) - : IRequest>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Term.Update; + +public record UpdateTermCommand(TermDTO Term) + : IRequest>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Update/UpdateTermHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Update/UpdateTermHandler.cs index c2ca828fe..56ea7aa6f 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Update/UpdateTermHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Term/Update/UpdateTermHandler.cs @@ -5,49 +5,53 @@ using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; +using TermEntity = Streetcode.DAL.Entities.Streetcode.TextContent.Term; -namespace Streetcode.BLL.MediatR.Streetcode.Term.Update +namespace Streetcode.BLL.MediatR.Streetcode.Term.Update; + +public class UpdateTermHandler : IRequestHandler> { - public class UpdateTermHandler : IRequestHandler> + private readonly IMapper _mapper; + private readonly IRepositoryWrapper _repository; + private readonly ILoggerService _logger; + private readonly IStringLocalizer _stringLocalizerCannotConvertNull; + private readonly IStringLocalizer _stringLocalizerFailedToUpdate; + + public UpdateTermHandler( + IMapper mapper, + IRepositoryWrapper repository, + ILoggerService logger, + IStringLocalizer stringLocalizerFailedToUpdate, + IStringLocalizer stringLocalizerCannotConvertNull) { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repository; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerCannotConvertNull; - private readonly IStringLocalizer _stringLocalizerFailedToUpdate; + _mapper = mapper; + _repository = repository; + _logger = logger; + _stringLocalizerFailedToUpdate = stringLocalizerFailedToUpdate; + _stringLocalizerCannotConvertNull = stringLocalizerCannotConvertNull; + } - public UpdateTermHandler(IMapper mapper, IRepositoryWrapper repository, ILoggerService logger, IStringLocalizer stringLocalizerFailedToUpdate, IStringLocalizer stringLocalizerCannotConvertNull) + public async Task> Handle(UpdateTermCommand request, CancellationToken cancellationToken) + { + var term = _mapper.Map(request.Term); + + if (term is null) { - _mapper = mapper; - _repository = repository; - _logger = logger; - _stringLocalizerFailedToUpdate = stringLocalizerFailedToUpdate; - _stringLocalizerCannotConvertNull = stringLocalizerCannotConvertNull; + var errorMessage = _stringLocalizerCannotConvertNull["CannotConvertNullToTerm"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } - public async Task> Handle(UpdateTermCommand request, CancellationToken cancellationToken) + _repository.TermRepository.Update(term); + var resultIsSuccess = await _repository.SaveChangesAsync() > 0; + + if (!resultIsSuccess) { - var term = _mapper.Map(request.Term); - if (term is null) - { - string errorMsg = _stringLocalizerCannotConvertNull["CannotConvertNullToTerm"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } - - _repository.TermRepository.Update(term); - - var resultIsSuccess = await _repository.SaveChangesAsync() > 0; - if (resultIsSuccess) - { - return Result.Ok(Unit.Value); - } - else - { - string errorMsg = _stringLocalizerFailedToUpdate["FailedToUpdateTerm"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + var errorMessage = _stringLocalizerFailedToUpdate["FailedToUpdateTerm"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } + + return Result.Ok(Unit.Value); } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Create/CreateTextCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Create/CreateTextCommand.cs deleted file mode 100644 index f81112106..000000000 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Create/CreateTextCommand.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Streetcode.BLL.MediatR.Streetcode.Text.Create -{ - internal class CreateTextCommand - { - } -} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Create/CreateTextHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Create/CreateTextHandler.cs deleted file mode 100644 index 5a53c0ff7..000000000 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Create/CreateTextHandler.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Streetcode.BLL.MediatR.Streetcode.Text.Create -{ - internal class CreateTextHandler - { - } -} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Delete/DeleteTextCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Delete/DeleteTextCommand.cs index 548c3e4f7..55aeccba3 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Delete/DeleteTextCommand.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Delete/DeleteTextCommand.cs @@ -4,4 +4,4 @@ namespace Streetcode.BLL.MediatR.Streetcode.Text.Delete; public record DeleteTextCommand(int Id) - : IRequest>; \ No newline at end of file + : IRequest>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Delete/DeleteTextHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Delete/DeleteTextHandler.cs index 82c273d7a..04eb5b4a8 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Delete/DeleteTextHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Delete/DeleteTextHandler.cs @@ -28,27 +28,25 @@ public DeleteTextHandler( public async Task> Handle(DeleteTextCommand request, CancellationToken cancellationToken) { - var text = await _repositoryWrapper.TextRepository.GetFirstOrDefaultAsync(f => f.Id == request.Id); + var text = await _repositoryWrapper.TextRepository.GetFirstOrDefaultAsync(x => x.Id == request.Id); if (text is null) { - string errorMsg = _stringLocalizerCannotFind["CannotFindTextWithCorrespondingCategoryId", request.Id].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); + var errorMessage = _stringLocalizerCannotFind["CannotFindTextWithCorrespondingCategoryId", request.Id].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } _repositoryWrapper.TextRepository.Delete(text); - var resultIsSuccess = await _repositoryWrapper.SaveChangesAsync() > 0; - if(resultIsSuccess) - { - return Result.Ok(Unit.Value); - } - else + + if (!resultIsSuccess) { - string errorMsg = _stringLocalizerFailedToDelete["FailedToDeleteText"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); + var errorMessage = _stringLocalizerFailedToDelete["FailedToDeleteText"].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } + + return Result.Ok(Unit.Value); } -} \ No newline at end of file +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetAll/GetAllTextsHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetAll/GetAllTextsHandler.cs index b3d9295b6..f6b3097aa 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetAll/GetAllTextsHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetAll/GetAllTextsHandler.cs @@ -1,10 +1,7 @@ using AutoMapper; using FluentResults; using MediatR; -using Microsoft.Extensions.Localization; using Streetcode.BLL.DTO.Streetcode.TextContent.Text; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; namespace Streetcode.BLL.MediatR.Streetcode.Text.GetAll; @@ -13,28 +10,17 @@ public class GetAllTextsHandler : IRequestHandler _stringLocalizerCannotFind; - public GetAllTextsHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) + public GetAllTextsHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper) { _repositoryWrapper = repositoryWrapper; _mapper = mapper; - _logger = logger; - _stringLocalizerCannotFind = stringLocalizerCannotFind; } public async Task>> Handle(GetAllTextsQuery request, CancellationToken cancellationToken) { var texts = await _repositoryWrapper.TextRepository.GetAllAsync(); - if (texts is null) - { - string errorMsg = _stringLocalizerCannotFind["CannotFindAnyText"].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } - return Result.Ok(_mapper.Map>(texts)); } -} \ No newline at end of file +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetAll/GetAllTextsQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetAll/GetAllTextsQuery.cs index 7306d1a7b..a4598fcda 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetAll/GetAllTextsQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetAll/GetAllTextsQuery.cs @@ -4,4 +4,5 @@ namespace Streetcode.BLL.MediatR.Streetcode.Text.GetAll; -public record GetAllTextsQuery : IRequest>>; \ No newline at end of file +public record GetAllTextsQuery + : IRequest>>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetById/GetTextByIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetById/GetTextByIdHandler.cs index 45905607e..d378433f4 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetById/GetTextByIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetById/GetTextByIdHandler.cs @@ -16,7 +16,11 @@ public class GetTextByIdHandler : IRequestHandler _stringLocalizerCannotFind; - public GetTextByIdHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) + public GetTextByIdHandler( + IRepositoryWrapper repositoryWrapper, + IMapper mapper, + ILoggerService logger, + IStringLocalizer stringLocalizerCannotFind) { _repositoryWrapper = repositoryWrapper; _mapper = mapper; @@ -26,15 +30,15 @@ public GetTextByIdHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, public async Task> Handle(GetTextByIdQuery request, CancellationToken cancellationToken) { - var text = await _repositoryWrapper.TextRepository.GetFirstOrDefaultAsync(f => f.Id == request.Id); + var text = await _repositoryWrapper.TextRepository.GetFirstOrDefaultAsync(x => x.Id == request.Id); if (text is null) { - string errorMsg = _stringLocalizerCannotFind["CannotFindAnyTextWithCorrespondingId", request.Id].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); + var errorMessage = _stringLocalizerCannotFind["CannotFindAnyTextWithCorrespondingId", request.Id].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } return Result.Ok(_mapper.Map(text)); } -} \ No newline at end of file +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetByStreetcodeId/GetTextByStreetcodeIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetByStreetcodeId/GetTextByStreetcodeIdHandler.cs index ab0c19754..fe9b41587 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetByStreetcodeId/GetTextByStreetcodeIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetByStreetcodeId/GetTextByStreetcodeIdHandler.cs @@ -5,7 +5,6 @@ using Streetcode.BLL.DTO.Streetcode.TextContent.Text; using Streetcode.BLL.Interfaces.Cache; using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.Interfaces.Text; using Streetcode.BLL.MediatR.ResultVariations; using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; @@ -16,16 +15,19 @@ public class GetTextByStreetcodeIdHandler : IRequestHandler _stringLocalizerCannotFind; private readonly ICacheService _cacheService; - public GetTextByStreetcodeIdHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ITextService textService, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind, ICacheService cacheService) + public GetTextByStreetcodeIdHandler( + IRepositoryWrapper repositoryWrapper, + IMapper mapper, + ILoggerService logger, + IStringLocalizer stringLocalizerCannotFind, + ICacheService cacheService) { _repositoryWrapper = repositoryWrapper; _mapper = mapper; - _textService = textService; _logger = logger; _stringLocalizerCannotFind = stringLocalizerCannotFind; _cacheService = cacheService; @@ -40,21 +42,19 @@ public async Task> Handle(GetTextByStreetcodeIdQuery request, Ca async () => { var text = await _repositoryWrapper.TextRepository - .GetFirstOrDefaultAsync(text => text.StreetcodeId == request.StreetcodeId); + .GetFirstOrDefaultAsync(x => x.StreetcodeId == request.StreetcodeId); - if (text is null) + if (text is null && await _repositoryWrapper.StreetcodeRepository + .GetFirstOrDefaultAsync(x => x.Id == request.StreetcodeId) is null) { - if (await _repositoryWrapper.StreetcodeRepository - .GetFirstOrDefaultAsync(s => s.Id == request.StreetcodeId) == null) - { - string errorMsg = _stringLocalizerCannotFind["CannotFindTransactionLinkByStreetcodeIdBecause", request.StreetcodeId].Value; - _logger.LogError(request, errorMsg); - return Result.Fail(new Error(errorMsg)); - } + var errorMessage = _stringLocalizerCannotFind["CannotFindTransactionLinkByStreetcodeIdBecause", request.StreetcodeId].Value; + _logger.LogError(request, errorMessage); + return Result.Fail(new Error(errorMessage)); } - NullResult result = new NullResult(); - if (text != null) + var result = new NullResult(); + + if (text is not null) { result.WithValue(_mapper.Map(text)); } @@ -63,4 +63,4 @@ public async Task> Handle(GetTextByStreetcodeIdQuery request, Ca }, TimeSpan.FromMinutes(10)); } -} \ No newline at end of file +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetByStreetcodeId/GetTextByStreetcodeIdQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetByStreetcodeId/GetTextByStreetcodeIdQuery.cs index adbafdbd5..6cf79a2e7 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetByStreetcodeId/GetTextByStreetcodeIdQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/GetByStreetcodeId/GetTextByStreetcodeIdQuery.cs @@ -5,4 +5,4 @@ namespace Streetcode.BLL.MediatR.Streetcode.Text.GetByStreetcodeId; public record GetTextByStreetcodeIdQuery(int StreetcodeId) - : IRequest>; \ No newline at end of file + : IRequest>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Update/UpdateTextCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Update/UpdateTextCommand.cs deleted file mode 100644 index db3dc8b32..000000000 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Update/UpdateTextCommand.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Streetcode.BLL.MediatR.Streetcode.Text.Update -{ - internal class UpdateTextCommand - { - } -} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Update/UpdateTextHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Update/UpdateTextHandler.cs deleted file mode 100644 index e2e7a8ceb..000000000 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/Update/UpdateTextHandler.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Streetcode.BLL.MediatR.Streetcode.Text.Update -{ - internal class UpdateTextHandler - { - } -} diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/UpdateParsed/UpdateParsedTextAdminPreviewHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/UpdateParsed/UpdateParsedTextAdminPreviewHandler.cs index d8d6f3040..2eed3c57a 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/UpdateParsed/UpdateParsedTextAdminPreviewHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/UpdateParsed/UpdateParsedTextAdminPreviewHandler.cs @@ -2,21 +2,21 @@ using MediatR; using Streetcode.BLL.Interfaces.Text; -namespace Streetcode.BLL.MediatR.Streetcode.Text.GetParsed +namespace Streetcode.BLL.MediatR.Streetcode.Text.UpdateParsed; + +public class UpdateParsedTextAdminPreviewHandler : IRequestHandler> { - public class UpdateParsedTextAdminPreviewHandler : IRequestHandler> + private readonly ITextService _textService; + + public UpdateParsedTextAdminPreviewHandler(ITextService textService) { - private readonly ITextService _textService; + _textService = textService; + } - public UpdateParsedTextAdminPreviewHandler(ITextService textService) - { - _textService = textService; - } + public async Task> Handle(UpdateParsedTextForAdminPreviewCommand request, CancellationToken cancellationToken) + { + var parsedText = await _textService.AddTermsTag(request.TextToParse); - public async Task> Handle(UpdateParsedTextForAdminPreviewCommand request, CancellationToken cancellationToken) - { - string parsedText = await _textService.AddTermsTag(request.TextToParse); - return parsedText == null ? Result.Fail(new Error("text was not parsed successfully")) : Result.Ok(parsedText); - } + return Result.Ok(parsedText); } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/UpdateParsed/UpdateParsedTextForAdminPreviewCommand.cs b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/UpdateParsed/UpdateParsedTextForAdminPreviewCommand.cs index fa345e1d8..464da2d51 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/UpdateParsed/UpdateParsedTextForAdminPreviewCommand.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Streetcode/Text/UpdateParsed/UpdateParsedTextForAdminPreviewCommand.cs @@ -1,8 +1,7 @@ using FluentResults; using MediatR; -namespace Streetcode.BLL.MediatR.Streetcode.Text.GetParsed -{ - public record UpdateParsedTextForAdminPreviewCommand(string TextToParse) - : IRequest>; -} +namespace Streetcode.BLL.MediatR.Streetcode.Text.UpdateParsed; + +public record UpdateParsedTextForAdminPreviewCommand(string TextToParse) + : IRequest>; diff --git a/Streetcode/Streetcode.BLL/MediatR/Team/Create/CreateTeamHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Team/Create/CreateTeamHandler.cs index d4ea5b786..83f263732 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Team/Create/CreateTeamHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Team/Create/CreateTeamHandler.cs @@ -2,12 +2,10 @@ using FluentResults; using MediatR; using Microsoft.Extensions.Localization; -using Streetcode.BLL.DTO.Partners; using Streetcode.BLL.DTO.Team; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Team; -using Streetcode.DAL.Enums; using Streetcode.DAL.Repositories.Interfaces.Base; namespace Streetcode.BLL.MediatR.Team.Create @@ -17,18 +15,18 @@ public class CreateTeamHandler : IRequestHandler _stringLocalizerCannot; + private readonly IStringLocalizer _stringLocalizerFailed; public CreateTeamHandler( IMapper mapper, IRepositoryWrapper repository, ILoggerService logger, - IStringLocalizer stringLocalizerCannot) + IStringLocalizer stringLocalizerFailed) { _mapper = mapper; _repository = repository; _logger = logger; - _stringLocalizerCannot = stringLocalizerCannot; + _stringLocalizerFailed = stringLocalizerFailed; } public async Task> Handle(CreateTeamQuery request, CancellationToken cancellationToken) @@ -38,40 +36,38 @@ public async Task> Handle(CreateTeamQuery request, Cancell { teamMember.Positions!.Clear(); - var newLogoTypes = request.teamMember.TeamMemberLinks.Select(links => links.LogoType).ToList(); - teamMember = await _repository.TeamRepository.CreateAsync(teamMember); - _repository.SaveChanges(); + await _repository.SaveChangesAsync(); - var newPositions = request.teamMember.Positions.ToList(); + var newPositions = request.teamMember.Positions!.ToList(); foreach (var newPosition in newPositions) { if (newPosition.Id < 0) { - Positions position = new Positions() { Id = 0, Position = newPosition.Position, TeamMembers = null }; - var tpm = _repository.PositionRepository.Create(position); + Positions position = new () { Id = 0, Position = newPosition.Position, TeamMembers = null }; + var tpm = await _repository.PositionRepository.CreateAsync(position); - _repository.SaveChanges(); + await _repository.SaveChangesAsync(); - _repository.TeamPositionRepository.Create( + await _repository.TeamPositionRepository.CreateAsync( new TeamMemberPositions { TeamMemberId = teamMember.Id, PositionsId = tpm.Id }); } else { - _repository.TeamPositionRepository.Create( + await _repository.TeamPositionRepository.CreateAsync( new TeamMemberPositions { TeamMemberId = teamMember.Id, PositionsId = newPosition.Id }); } } - _repository.SaveChanges(); - var resulted = _mapper.Map(teamMember); + await _repository.SaveChangesAsync(); return Result.Ok(_mapper.Map(teamMember)); } catch (Exception ex) { + string errorMessage = _stringLocalizerFailed["FailedToCreateTeam"].Value; _logger.LogError(request, ex.Message); - return Result.Fail(ex.Message); + return Result.Fail(errorMessage); } } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Team/Delete/DeleteTeamHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Team/Delete/DeleteTeamHandler.cs index b5d10707b..3b246c188 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Team/Delete/DeleteTeamHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Team/Delete/DeleteTeamHandler.cs @@ -38,7 +38,7 @@ public async Task> Handle(DeleteTeamQuery request, Cancell _repositoryWrapper.TeamRepository.Delete(team); try { - _repositoryWrapper.SaveChanges(); + await _repositoryWrapper.SaveChangesAsync(); return Result.Ok(_mapper.Map(team)); } catch (Exception ex) diff --git a/Streetcode/Streetcode.BLL/MediatR/Team/GetAll/GetAllTeamHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Team/GetAll/GetAllTeamHandler.cs index 4c7bab812..e0b5865a0 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Team/GetAll/GetAllTeamHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Team/GetAll/GetAllTeamHandler.cs @@ -2,56 +2,63 @@ using FluentResults; using MediatR; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Localization; using Streetcode.BLL.DTO.Team; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Entities.News; -using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.BLL.Interfaces.BlobStorage; using Streetcode.DAL.Entities.Team; -using Streetcode.DAL.Helpers; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Team.GetAll +namespace Streetcode.BLL.MediatR.Team.GetAll; + +public class GetAllTeamHandler : IRequestHandler> { - public class GetAllTeamHandler : IRequestHandler> + private readonly IMapper _mapper; + private readonly IRepositoryWrapper _repositoryWrapper; + private readonly IBlobService _blobService; + + public GetAllTeamHandler( + IRepositoryWrapper repositoryWrapper, + IMapper mapper, + IBlobService blobService) { - private readonly IMapper _mapper; - private readonly IRepositoryWrapper _repositoryWrapper; - private readonly ILoggerService _logger; - private readonly IStringLocalizer _stringLocalizerCannotFind; + _repositoryWrapper = repositoryWrapper; + _mapper = mapper; + _blobService = blobService; + } - public GetAllTeamHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) + public Task> Handle(GetAllTeamQuery request, CancellationToken cancellationToken) + { + var paginationResponse = _repositoryWrapper + .TeamRepository + .GetAllPaginated( + request.page, + request.pageSize, + include: x => x + .Include(x => x.Positions) + .Include(x => x.TeamMemberLinks!) + .Include(x => x.Image!)); + + var teamMemberDtos = MapToTeamMemberDtos(paginationResponse.Entities); + var getAllTeamDto = new GetAllTeamDTO() { - _repositoryWrapper = repositoryWrapper; - _mapper = mapper; - _logger = logger; - _stringLocalizerCannotFind = stringLocalizerCannotFind; - } + TotalAmount = paginationResponse.TotalItems, + TeamMembers = teamMemberDtos, + }; + + return Task.FromResult(Result.Ok(getAllTeamDto)); + } + + private IEnumerable MapToTeamMemberDtos(IEnumerable teamMemberEntities) + { + var teamMemberDtosList = _mapper.Map>(teamMemberEntities).ToList(); - public Task> Handle(GetAllTeamQuery request, CancellationToken cancellationToken) + foreach (var teamMemberDto in teamMemberDtosList) { - PaginationResponse paginationResponse = _repositoryWrapper - .TeamRepository - .GetAllPaginated( - request.page, - request.pageSize, - include: x => x.Include(x => x.Positions).Include(x => x.TeamMemberLinks!)); - - if (paginationResponse is null) + if (teamMemberDto.Image is not null) { - string errorMsg = _stringLocalizerCannotFind["CannotFindAnyTeam"].Value; - _logger.LogError(request, errorMsg); - return Task.FromResult(Result.Fail(new Error(errorMsg))); + teamMemberDto.Image.Base64 = _blobService.FindFileInStorageAsBase64(teamMemberDto.Image.BlobName); } - - GetAllTeamDTO getAllTeamDTO = new GetAllTeamDTO() - { - TotalAmount = paginationResponse.TotalItems, - TeamMembers = _mapper.Map>(paginationResponse.Entities), - }; - - return Task.FromResult(Result.Ok(getAllTeamDTO)); } + + return teamMemberDtosList; } -} \ No newline at end of file +} diff --git a/Streetcode/Streetcode.BLL/MediatR/Team/GetByRoleId/GetTeamByRoleIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Team/GetByRoleId/GetTeamByRoleIdHandler.cs index 871149d73..e4a5592b6 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Team/GetByRoleId/GetTeamByRoleIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Team/GetByRoleId/GetTeamByRoleIdHandler.cs @@ -29,22 +29,28 @@ public async Task>> Handle(GetTeamByRoleIdQuer try { var teamDtoByRoleId = await _repositoryWrapper.TeamRepository.GetAllAsync( - predicate: t => t.Positions!.Where(p => p.Id == request.roleId).Count() > 0, + predicate: t => t.Positions!.Any(p => p.Id == request.roleId), include: t => t.Include(tm => tm.TeamMemberLinks).Include(tm => tm.Image!)); + teamDtoByRoleId = teamDtoByRoleId + .Select(team => + { + if (team.Image != null) + { + team.Image.Base64 = _blob.FindFileInStorageAsBase64(team.Image.BlobName!); + } - foreach (var team in teamDtoByRoleId) - { - team.Image!.Base64 = _blob.FindFileInStorageAsBase64(team.Image.BlobName!); - } - + return team; + }) + .ToList(); var teamByRoleId = _mapper.Map>(teamDtoByRoleId); return Result.Ok(teamByRoleId); } catch (Exception ex) { - return Result.Fail(ex.Message); + _logger.LogError(request, ex.Message); + return Result.Fail(ex.Message); } } } diff --git a/Streetcode/Streetcode.BLL/MediatR/Team/GetNamePosition/GetTickerStringHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Team/GetNamePosition/GetTickerStringHandler.cs index ae517a42c..e16cf1651 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Team/GetNamePosition/GetTickerStringHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Team/GetNamePosition/GetTickerStringHandler.cs @@ -3,56 +3,57 @@ using MediatR; using Microsoft.EntityFrameworkCore; using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.MediatR.Team.GetNamePosition; using Streetcode.DAL.Repositories.Interfaces.Base; -public class GetTickerStringHandler : IRequestHandler> +namespace Streetcode.BLL.MediatR.Team.GetNamePosition { - private readonly IRepositoryWrapper _repository; - private readonly ILoggerService _loggerService; - - public GetTickerStringHandler(IRepositoryWrapper repository, ILoggerService loggerService) + public class GetTickerStringHandler : IRequestHandler> { - _repository = repository; - _loggerService = loggerService; - } + private readonly IRepositoryWrapper _repository; + private readonly ILoggerService _loggerService; - public async Task> Handle(GetTickerStringQuery request, CancellationToken cancellationToken) - { - var positions = await _repository.PositionRepository.GetAllAsync(include: p => p.Include(src => src.TeamMembers!)); - string a = string.Empty; - StringBuilder memberString = new StringBuilder(); + public GetTickerStringHandler(IRepositoryWrapper repository, ILoggerService loggerService) + { + _repository = repository; + _loggerService = loggerService; + } - foreach (var position in positions) + public async Task> Handle(GetTickerStringQuery request, CancellationToken cancellationToken) { - if (position.TeamMembers is not null && position.TeamMembers.Count > 0) - { - memberString.Append(position.Position); - memberString.Append(": "); + var positions = await _repository.PositionRepository.GetAllAsync(include: p => p.Include(src => src.TeamMembers!)); + StringBuilder memberString = new(); - int memberCount = position.TeamMembers.Count; - for (int i = 0; i < memberCount; i++) + foreach (var position in positions) + { + if (position.TeamMembers is not null && position.TeamMembers.Count > 0) { - memberString.Append(position.TeamMembers[i].Name); + memberString.Append(position.Position); + memberString.Append(": "); - if (i < memberCount - 1) + int memberCount = position.TeamMembers.Count; + for (int i = 0; i < memberCount; i++) { - memberString.Append(", "); + memberString.Append(position.TeamMembers[i].Name); + + if (i < memberCount - 1) + { + memberString.Append(", "); + } } - } - memberString.Append(" "); + memberString.Append(' '); + } } - } - try - { - return Result.Ok(memberString.ToString()); - } - catch (Exception ex) - { - _loggerService.LogError(request, ex.Message); - return Result.Fail(ex.Message); + try + { + return Result.Ok(memberString.ToString()); + } + catch (Exception ex) + { + _loggerService.LogError(request, ex.Message); + return Result.Fail(ex.Message); + } } } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Team/TeamMembersLinks/Create/CreateTeamLinkHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Team/TeamMembersLinks/Create/CreateTeamLinkHandler.cs index 4beb9037a..030193252 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Team/TeamMembersLinks/Create/CreateTeamLinkHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Team/TeamMembersLinks/Create/CreateTeamLinkHandler.cs @@ -45,7 +45,7 @@ public async Task> Handle(CreateTeamLinkQuery request, return Result.Fail(new Error(errorMsg)); } - var createdTeamLink = _repository.TeamLinkRepository.Create(teamMemberLink); + var createdTeamLink = await _repository.TeamLinkRepository.CreateAsync(teamMemberLink); if (createdTeamLink is null) { diff --git a/Streetcode/Streetcode.BLL/MediatR/Team/Update/UpdateTeamHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Team/Update/UpdateTeamHandler.cs index 334b4c769..522017a43 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Team/Update/UpdateTeamHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Team/Update/UpdateTeamHandler.cs @@ -42,9 +42,9 @@ public async Task> Handle(UpdateTeamQuery request, C team.Positions?.Clear(); _repositoryWrapper.TeamRepository.Update(team); - _repositoryWrapper.SaveChanges(); + await _repositoryWrapper.SaveChangesAsync(); - var newPositions = request.TeamMember.Positions.ToList(); + var newPositions = request.TeamMember.Positions!.ToList(); var newPositionsIds = newPositions.Select(s => s.Id).ToList(); var oldPositions = await _repositoryWrapper.TeamPositionRepository @@ -62,22 +62,22 @@ public async Task> Handle(UpdateTeamQuery request, C { if (newPosition.Id < 0) { - Positions position = new Positions() { Id = 0, Position = newPosition.Position, TeamMembers = null }; - var tpm = _repositoryWrapper.PositionRepository.Create(position); + Positions position = new() { Id = 0, Position = newPosition.Position, TeamMembers = null }; + var tpm = await _repositoryWrapper.PositionRepository.CreateAsync(position); - _repositoryWrapper.SaveChanges(); + await _repositoryWrapper.SaveChangesAsync(); - _repositoryWrapper.TeamPositionRepository.Create( + await _repositoryWrapper.TeamPositionRepository.CreateAsync( new TeamMemberPositions { TeamMemberId = team.Id, PositionsId = tpm.Id }); } else if (oldPositions.FirstOrDefault(x => x.PositionsId == newPosition.Id) == null) { - _repositoryWrapper.TeamPositionRepository.Create( + await _repositoryWrapper.TeamPositionRepository.CreateAsync( new TeamMemberPositions { TeamMemberId = team.Id, PositionsId = newPosition.Id }); } } - _repositoryWrapper.SaveChanges(); + await _repositoryWrapper.SaveChangesAsync(); var dbo = _mapper.Map(team); dbo.Positions = newPositions; return Result.Ok(dbo); diff --git a/Streetcode/Streetcode.BLL/MediatR/Timeline/HistoricalContext/GetAll/GetAllHistoricalContextHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Timeline/HistoricalContext/GetAll/GetAllHistoricalContextHandler.cs index 37d039e7f..7b5c2f5f9 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Timeline/HistoricalContext/GetAll/GetAllHistoricalContextHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Timeline/HistoricalContext/GetAll/GetAllHistoricalContextHandler.cs @@ -1,13 +1,10 @@ using AutoMapper; using FluentResults; using MediatR; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Localization; using Streetcode.BLL.DTO.Timeline; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Entities.News; -using Streetcode.DAL.Entities.Timeline; using Streetcode.DAL.Helpers; using Streetcode.DAL.Repositories.Interfaces.Base; @@ -44,7 +41,7 @@ public Task> Handle(GetAllHistoricalContextQu return Task.FromResult(Result.Fail(new Error(errorMsg))); } - GetAllHistoricalContextDTO getAllHistoricalContextDTO = new GetAllHistoricalContextDTO + GetAllHistoricalContextDTO getAllHistoricalContextDTO = new () { TotalAmount = paginationResponse.TotalItems, HistoricalContexts = _mapper.Map>(paginationResponse.Entities) diff --git a/Streetcode/Streetcode.BLL/MediatR/Timeline/HistoricalContext/GetAll/GetAllHistoricalContextQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Timeline/HistoricalContext/GetAll/GetAllHistoricalContextQuery.cs index 032f38262..3343ed0f2 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Timeline/HistoricalContext/GetAll/GetAllHistoricalContextQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Timeline/HistoricalContext/GetAll/GetAllHistoricalContextQuery.cs @@ -1,6 +1,5 @@ using FluentResults; using MediatR; -using Microsoft.AspNetCore.Mvc; using Streetcode.BLL.DTO.Timeline; namespace Streetcode.BLL.MediatR.Timeline.HistoricalContext.GetAll diff --git a/Streetcode/Streetcode.BLL/MediatR/Timeline/HistoricalContext/Update/UpdateHistoricalContextHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Timeline/HistoricalContext/Update/UpdateHistoricalContextHandler.cs index da6437975..0fb1588b3 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Timeline/HistoricalContext/Update/UpdateHistoricalContextHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Timeline/HistoricalContext/Update/UpdateHistoricalContextHandler.cs @@ -6,6 +6,7 @@ using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; +using HistoricalContextClass = Streetcode.DAL.Entities.Timeline.HistoricalContext; namespace Streetcode.BLL.MediatR.Timeline.HistoricalContext.Update { @@ -62,9 +63,7 @@ await _repositoryWrapper.HistoricalContextRepository.GetFirstOrDefaultAsync(x => try { - /* have some shitty code right here, if you delete the DAL.Entities.Timeline. part it will show error - even if you have using Streetcode.DAL.Entities.Timeline; so sad :( */ - var contextToUpdate = _mapper.Map(request.HistoricalContext); + var contextToUpdate = _mapper.Map(request.HistoricalContext); _repositoryWrapper.HistoricalContextRepository.Update(contextToUpdate); await _repositoryWrapper.SaveChangesAsync(); return Result.Ok(_mapper.Map(contextToUpdate)); diff --git a/Streetcode/Streetcode.BLL/MediatR/Timeline/TimelineItem/GetByStreetcodeId/GetTimelineItemsByStreetcodeIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Timeline/TimelineItem/GetByStreetcodeId/GetTimelineItemsByStreetcodeIdHandler.cs index ab4747cb4..560aac95f 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Timeline/TimelineItem/GetByStreetcodeId/GetTimelineItemsByStreetcodeIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Timeline/TimelineItem/GetByStreetcodeId/GetTimelineItemsByStreetcodeIdHandler.cs @@ -2,10 +2,8 @@ using FluentResults; using MediatR; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Localization; using Streetcode.BLL.DTO.Timeline; using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Repositories.Interfaces.Base; namespace Streetcode.BLL.MediatR.Timeline.TimelineItem.GetByStreetcodeId; @@ -15,14 +13,12 @@ public class GetTimelineItemsByStreetcodeIdHandler : IRequestHandler _stringLocalizerCannotFind; - public GetTimelineItemsByStreetcodeIdHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) + public GetTimelineItemsByStreetcodeIdHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger) { _repositoryWrapper = repositoryWrapper; _mapper = mapper; _logger = logger; - _stringLocalizerCannotFind = stringLocalizerCannotFind; } public async Task>> Handle(GetTimelineItemsByStreetcodeIdQuery request, CancellationToken cancellationToken) diff --git a/Streetcode/Streetcode.BLL/MediatR/Toponyms/GetAll/GetAllToponymsHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Toponyms/GetAll/GetAllToponymsHandler.cs index 2bc944ea7..81a8d8764 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Toponyms/GetAll/GetAllToponymsHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Toponyms/GetAll/GetAllToponymsHandler.cs @@ -2,7 +2,6 @@ using FluentResults; using MediatR; using Streetcode.BLL.DTO.Toponyms; -using Streetcode.BLL.Interfaces.Logging; using Streetcode.DAL.Entities.Toponyms; using Streetcode.DAL.Repositories.Interfaces.Base; @@ -13,13 +12,11 @@ public class GetAllToponymsHandler : IRequestHandler> Handle(GetAllToponymsQuery query, CancellationToken cancellationToken) @@ -34,8 +31,6 @@ public Task> Handle(GetAllToponymsQuery query, FindStreetcodesWithMatchTitle(ref toponyms, filterRequest.Title); } - // int pagesAmount = ApplyPagination(ref toponyms, filterRequest.Amount, filterRequest.Page); - var toponymDtos = _mapper.Map>(toponyms.AsEnumerable()); var response = new GetAllToponymsResponseDTO @@ -47,7 +42,7 @@ public Task> Handle(GetAllToponymsQuery query, return Task.FromResult(Result.Ok(response)); } - private void FindStreetcodesWithMatchTitle( + private static void FindStreetcodesWithMatchTitle( ref IQueryable toponyms, string title) { @@ -58,18 +53,4 @@ private void FindStreetcodesWithMatchTitle( .GroupBy(s => s.StreetName) .Select(g => g.First()); } - - // private int ApplyPagination( - // ref IQueryable toponyms, - // int amount, - // int page) - // { - // var totalPages = (int)Math.Ceiling(toponyms.Count() / (double)amount); - - // toponyms = toponyms - // .Skip((page - 1) * amount) - // .Take(amount); - - // return totalPages; - // } } \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Toponyms/GetByStreetcodeId/GetToponymsByStreetcodeIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Toponyms/GetByStreetcodeId/GetToponymsByStreetcodeIdHandler.cs index 0b7420948..a95137bc1 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Toponyms/GetByStreetcodeId/GetToponymsByStreetcodeIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Toponyms/GetByStreetcodeId/GetToponymsByStreetcodeIdHandler.cs @@ -15,14 +15,14 @@ public class GetToponymsByStreetcodeIdHandler : IRequestHandler _stringLocalizerCannotFind; + private readonly IStringLocalizer _stringLocalizerNo; - public GetToponymsByStreetcodeIdHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind) + public GetToponymsByStreetcodeIdHandler(IRepositoryWrapper repositoryWrapper, IMapper mapper, ILoggerService logger, IStringLocalizer stringLocalizerNo) { _repositoryWrapper = repositoryWrapper; _mapper = mapper; _logger = logger; - _stringLocalizerCannotFind = stringLocalizerCannotFind; + _stringLocalizerNo = stringLocalizerNo; } public async Task>> Handle(GetToponymsByStreetcodeIdQuery request, CancellationToken cancellationToken) @@ -33,12 +33,12 @@ public async Task>> Handle(GetToponymsByStreetcod predicate: sc => sc.Streetcodes.Any(s => s.Id == request.StreetcodeId), include: scl => scl .Include(sc => sc.Coordinate!)); - toponyms.DistinctBy(x => x.StreetName); + toponyms = toponyms.DistinctBy(x => x.StreetName).ToList(); if (!toponyms.Any()) { - string message = "Returning empty enumerable of toponyms"; - _logger.LogInformation(message); + string errorMsg = _stringLocalizerNo["NoToponymWithSuchId", request.StreetcodeId].Value; + _logger.LogInformation(errorMsg); return Result.Ok(Enumerable.Empty()); } diff --git a/Streetcode/Streetcode.BLL/MediatR/Users/GetAllUserName/ExistWithUserNameHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Users/ExistWithUserName/ExistWithUserNameHandler.cs similarity index 92% rename from Streetcode/Streetcode.BLL/MediatR/Users/GetAllUserName/ExistWithUserNameHandler.cs rename to Streetcode/Streetcode.BLL/MediatR/Users/ExistWithUserName/ExistWithUserNameHandler.cs index f99653847..ada841982 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Users/GetAllUserName/ExistWithUserNameHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Users/ExistWithUserName/ExistWithUserNameHandler.cs @@ -2,7 +2,7 @@ using MediatR; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Users.GetAllUserName; +namespace Streetcode.BLL.MediatR.Users.ExistWithUserName; public class ExistWithUserNameHandler : IRequestHandler> { diff --git a/Streetcode/Streetcode.BLL/MediatR/Users/GetAllUserName/ExistWithUserNameQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Users/ExistWithUserName/ExistWithUserNameQuery.cs similarity index 67% rename from Streetcode/Streetcode.BLL/MediatR/Users/GetAllUserName/ExistWithUserNameQuery.cs rename to Streetcode/Streetcode.BLL/MediatR/Users/ExistWithUserName/ExistWithUserNameQuery.cs index c6b974f22..b3a0e660d 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Users/GetAllUserName/ExistWithUserNameQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Users/ExistWithUserName/ExistWithUserNameQuery.cs @@ -1,6 +1,6 @@ using FluentResults; using MediatR; -namespace Streetcode.BLL.MediatR.Users.GetAllUserName; +namespace Streetcode.BLL.MediatR.Users.ExistWithUserName; public record ExistWithUserNameQuery(string UserName) : IRequest>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Users/ForgotPassword/ForgotPasswordHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Users/ForgotPassword/ForgotPasswordHandler.cs index 1db8242f5..119e27b2b 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Users/ForgotPassword/ForgotPasswordHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Users/ForgotPassword/ForgotPasswordHandler.cs @@ -1,5 +1,4 @@ -using AutoMapper; -using FluentResults; +using FluentResults; using MediatR; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; @@ -11,7 +10,6 @@ using Streetcode.BLL.SharedResource; using Streetcode.BLL.Util.Helpers; using Streetcode.DAL.Entities.Users; -using Streetcode.DAL.Repositories.Interfaces.Base; namespace Streetcode.BLL.MediatR.Users.ForgotPassword; @@ -25,7 +23,14 @@ public class ForgotPasswordHandler : IRequestHandler stringLocalizerCannotFind, UserManager userManager, IEmailService forgotPasswordEmailService, IStringLocalizer localizer, IHttpContextAccessor httpContextAccessor, IMessageDataAbstractFactory messageDataAbstractFactory, IStringLocalizer stringLocalizerEmailHandler) + public ForgotPasswordHandler( + ILoggerService logger, + UserManager userManager, + IEmailService forgotPasswordEmailService, + IStringLocalizer localizer, + IHttpContextAccessor httpContextAccessor, + IMessageDataAbstractFactory messageDataAbstractFactory, + IStringLocalizer stringLocalizerEmailHandler) { _logger = logger; _userManager = userManager; @@ -57,8 +62,8 @@ public async Task> Handle(ForgotPasswordCommand request, Cancellati var message = _messageDataAbstractFactory.CreateForgotPasswordMessageData( new string[] { request.ForgotPasswordDto.Email }, endcodedToken, - user.UserName, - currentDomain); + encodedUserName, + currentDomain!); var isSuccess = await _emailService.SendEmailAsync(message); diff --git a/Streetcode/Streetcode.BLL/MediatR/Users/GetByName/GetByUserNameHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Users/GetByEmail/GetByEmailHandler.cs similarity index 73% rename from Streetcode/Streetcode.BLL/MediatR/Users/GetByName/GetByUserNameHandler.cs rename to Streetcode/Streetcode.BLL/MediatR/Users/GetByEmail/GetByEmailHandler.cs index b7184f6b4..84debb4cf 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Users/GetByName/GetByUserNameHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Users/GetByEmail/GetByEmailHandler.cs @@ -12,9 +12,9 @@ using Streetcode.DAL.Entities.Users; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Users.GetByName; +namespace Streetcode.BLL.MediatR.Users.GetByEmail; -public class GetByUserNameHandler : IRequestHandler> +public class GetByEmailHandler : IRequestHandler> { private readonly IMapper _mapper; private readonly IRepositoryWrapper _repositoryWrapper; @@ -23,7 +23,13 @@ public class GetByUserNameHandler : IRequestHandler _userManager; private readonly IHttpContextAccessor _httpContextAccessor; - public GetByUserNameHandler(IMapper mapper, IRepositoryWrapper repositoryWrapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind, UserManager userManager, IHttpContextAccessor httpContextAccessor, IStringLocalizer localizer) + public GetByEmailHandler( + IMapper mapper, + IRepositoryWrapper repositoryWrapper, + ILoggerService logger, + UserManager userManager, + IHttpContextAccessor httpContextAccessor, + IStringLocalizer localizer) { _mapper = mapper; _repositoryWrapper = repositoryWrapper; @@ -33,7 +39,7 @@ public GetByUserNameHandler(IMapper mapper, IRepositoryWrapper repositoryWrapper _localizer = localizer; } - public async Task> Handle(GetByUserNameQuery request, CancellationToken cancellationToken) + public async Task> Handle(GetByEmailQuery request, CancellationToken cancellationToken) { var user = await _repositoryWrapper.UserRepository.GetFirstOrDefaultAsync(u => u.Email == HttpContextHelper.GetCurrentUserEmail(_httpContextAccessor), include: qu => qu.Include(x => x.Expertises)); @@ -45,7 +51,7 @@ public async Task> Handle(GetByUserNameQuery request, Cancellati } var userDto = _mapper.Map(user); - userDto.Role = (await _userManager.GetRolesAsync(user)).FirstOrDefault(); + userDto.Role = (await _userManager.GetRolesAsync(user)).FirstOrDefault() !; return Result.Ok(userDto); } diff --git a/Streetcode/Streetcode.BLL/MediatR/Users/GetByEmail/GetByEmailQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Users/GetByEmail/GetByEmailQuery.cs new file mode 100644 index 000000000..657bd920a --- /dev/null +++ b/Streetcode/Streetcode.BLL/MediatR/Users/GetByEmail/GetByEmailQuery.cs @@ -0,0 +1,7 @@ +using FluentResults; +using MediatR; +using Streetcode.BLL.DTO.Users; + +namespace Streetcode.BLL.MediatR.Users.GetByEmail; + +public record GetByEmailQuery : IRequest>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Users/GetByName/GetByUserNameQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Users/GetByName/GetByUserNameQuery.cs deleted file mode 100644 index 459f9c19e..000000000 --- a/Streetcode/Streetcode.BLL/MediatR/Users/GetByName/GetByUserNameQuery.cs +++ /dev/null @@ -1,7 +0,0 @@ -using FluentResults; -using MediatR; -using Streetcode.BLL.DTO.Users; - -namespace Streetcode.BLL.MediatR.Users.GetByName; - -public record GetByUserNameQuery() : IRequest>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Users/GetByUserName/GetOtherUserByUserNameHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Users/GetOtherUserByUserName/GetOtherUserByUserNameHandler.cs similarity index 74% rename from Streetcode/Streetcode.BLL/MediatR/Users/GetByUserName/GetOtherUserByUserNameHandler.cs rename to Streetcode/Streetcode.BLL/MediatR/Users/GetOtherUserByUserName/GetOtherUserByUserNameHandler.cs index ba2ef6cb0..856b3dffb 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Users/GetByUserName/GetOtherUserByUserNameHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Users/GetOtherUserByUserName/GetOtherUserByUserNameHandler.cs @@ -1,18 +1,16 @@ using AutoMapper; using FluentResults; using MediatR; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Localization; using Streetcode.BLL.DTO.Users; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.SharedResource; -using Streetcode.BLL.Util.Helpers; using Streetcode.DAL.Entities.Users; using Streetcode.DAL.Repositories.Interfaces.Base; -namespace Streetcode.BLL.MediatR.Users.GetByUserName; +namespace Streetcode.BLL.MediatR.Users.GetOtherUserByUserName; public class GetOtherUserByUserNameHandler : IRequestHandler> { @@ -20,16 +18,19 @@ public class GetOtherUserByUserNameHandler : IRequestHandler _userManager; - private readonly IHttpContextAccessor _httpContextAccessor; private readonly IStringLocalizer _localizer; - public GetOtherUserByUserNameHandler(IMapper mapper, IRepositoryWrapper repositoryWrapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind, UserManager userManager, IHttpContextAccessor httpContextAccessor, IStringLocalizer localizer) + public GetOtherUserByUserNameHandler( + IMapper mapper, + IRepositoryWrapper repositoryWrapper, + ILoggerService logger, + UserManager userManager, + IStringLocalizer localizer) { _mapper = mapper; _repositoryWrapper = repositoryWrapper; _logger = logger; _userManager = userManager; - _httpContextAccessor = httpContextAccessor; _localizer = localizer; } @@ -45,7 +46,7 @@ public async Task> Handle(GetOtherUserByUserNameQuery req } var userDto = _mapper.Map(user); - userDto.Role = (await _userManager.GetRolesAsync(user)).FirstOrDefault(); + userDto.Role = (await _userManager.GetRolesAsync(user)).FirstOrDefault() !; return Result.Ok(userDto); } diff --git a/Streetcode/Streetcode.BLL/MediatR/Users/GetByUserName/GetOtherUserByUserNameQuery.cs b/Streetcode/Streetcode.BLL/MediatR/Users/GetOtherUserByUserName/GetOtherUserByUserNameQuery.cs similarity index 72% rename from Streetcode/Streetcode.BLL/MediatR/Users/GetByUserName/GetOtherUserByUserNameQuery.cs rename to Streetcode/Streetcode.BLL/MediatR/Users/GetOtherUserByUserName/GetOtherUserByUserNameQuery.cs index 402bdb187..fd345eb37 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Users/GetByUserName/GetOtherUserByUserNameQuery.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Users/GetOtherUserByUserName/GetOtherUserByUserNameQuery.cs @@ -2,6 +2,6 @@ using MediatR; using Streetcode.BLL.DTO.Users; -namespace Streetcode.BLL.MediatR.Users.GetByUserName; +namespace Streetcode.BLL.MediatR.Users.GetOtherUserByUserName; public record GetOtherUserByUserNameQuery(string UserName) : IRequest>; \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/MediatR/Users/Update/UpdateUserHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Users/Update/UpdateUserHandler.cs index 431f67c6f..aeef56b2c 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Users/Update/UpdateUserHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Users/Update/UpdateUserHandler.cs @@ -24,7 +24,13 @@ public class UpdateUserHandler : IRequestHandler _localizer; - public UpdateUserHandler(IMapper mapper, IRepositoryWrapper repositoryWrapper, ILoggerService logger, UserManager userManager, IHttpContextAccessor httpContextAccessor, IStringLocalizer localizer) + public UpdateUserHandler( + IMapper mapper, + IRepositoryWrapper repositoryWrapper, + ILoggerService logger, + UserManager userManager, + IHttpContextAccessor httpContextAccessor, + IStringLocalizer localizer) { _mapper = mapper; _repositoryWrapper = repositoryWrapper; @@ -41,7 +47,7 @@ public async Task> Handle(UpdateUserCommand request, Cancellatio var currentUserEmail = HttpContextHelper.GetCurrentUserEmail(_httpContextAccessor); var user = await _userManager.Users .Include(u => u.Expertises) - .SingleOrDefaultAsync(u => u.Email == currentUserEmail); + .SingleOrDefaultAsync(u => u.Email == currentUserEmail, cancellationToken); if (user is null) { @@ -72,7 +78,8 @@ public async Task> Handle(UpdateUserCommand request, Cancellatio await _repositoryWrapper.SaveChangesAsync(); var userDto = _mapper.Map(user); - userDto.Role = (await _userManager.GetRolesAsync(user)).FirstOrDefault(); + var roles = await _userManager.GetRolesAsync(user); + userDto.Role = roles.FirstOrDefault() ?? throw new InvalidOperationException("User must have at least one role assigned"); return Result.Ok(userDto); } diff --git a/Streetcode/Streetcode.BLL/MediatR/Users/UpdateForgotPassword/UpdateForgotPasswordHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Users/UpdateForgotPassword/UpdateForgotPasswordHandler.cs index 16d4006b9..ad065b823 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Users/UpdateForgotPassword/UpdateForgotPasswordHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Users/UpdateForgotPassword/UpdateForgotPasswordHandler.cs @@ -1,14 +1,10 @@ -using AutoMapper; -using FluentResults; +using FluentResults; using MediatR; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Localization; -using Streetcode.BLL.DTO.Users; using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.MediatR.Users.ForgotPassword; using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Users; -using Streetcode.DAL.Repositories.Interfaces.Base; namespace Streetcode.BLL.MediatR.Users.UpdateForgotPassword; @@ -18,7 +14,10 @@ public class UpdateForgotPasswordHandler : IRequestHandler _userManager; private readonly IStringLocalizer _localizer; - public UpdateForgotPasswordHandler(IRepositoryWrapper repositoryWrapper, ILoggerService logger, IStringLocalizer stringLocalizerCannotFind, UserManager userManager, IStringLocalizer localizer) + public UpdateForgotPasswordHandler( + ILoggerService logger, + UserManager userManager, + IStringLocalizer localizer) { _logger = logger; _userManager = userManager; diff --git a/Streetcode/Streetcode.BLL/Resources/SharedResource.AlreadyExistSharedResource.en-US.resx b/Streetcode/Streetcode.BLL/Resources/SharedResource.AlreadyExistSharedResource.en-US.resx index 9482bbaa2..16cbbed34 100644 --- a/Streetcode/Streetcode.BLL/Resources/SharedResource.AlreadyExistSharedResource.en-US.resx +++ b/Streetcode/Streetcode.BLL/Resources/SharedResource.AlreadyExistSharedResource.en-US.resx @@ -21,4 +21,7 @@ Partner with field '{0}' and its value '{1}' already exists + + Streetcode is already in favourites + \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/Resources/SharedResource.AlreadyExistSharedResource.uk-UA.resx b/Streetcode/Streetcode.BLL/Resources/SharedResource.AlreadyExistSharedResource.uk-UA.resx index ae8f353f7..a1702d9bc 100644 --- a/Streetcode/Streetcode.BLL/Resources/SharedResource.AlreadyExistSharedResource.uk-UA.resx +++ b/Streetcode/Streetcode.BLL/Resources/SharedResource.AlreadyExistSharedResource.uk-UA.resx @@ -21,4 +21,7 @@ Партнер з полем '{0}' та його значенням '{1}' вже існує + + Стріткод уже додано в улюблені + \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.en-US.Designer.cs b/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.en-US.Designer.cs index 5c305c0dd..7c6dc644d 100644 --- a/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.en-US.Designer.cs +++ b/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.en-US.Designer.cs @@ -212,6 +212,15 @@ internal static string CannotFindAnyPositions { } } + /// + /// Looks up a localized string similar to Cannot find any field with this name. + /// + internal static string CannotFindAnyPropertyWithThisName { + get { + return ResourceManager.GetString("CannotFindAnyPropertyWithThisName", resourceCulture); + } + } + /// /// Looks up a localized string similar to Cannot find any related figures by a streetcode id: {0}. /// diff --git a/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.en-US.resx b/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.en-US.resx index a2f52d8ec..0aa6b7a1c 100644 --- a/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.en-US.resx +++ b/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.en-US.resx @@ -279,6 +279,9 @@ Cannot find streetcode by id + + Cannot find streetcode in favourites + Cannot find streetcode by transliteration url: {0} @@ -324,4 +327,7 @@ Cannot find historical context with title '{0}' + + Cannot find any field with this name + \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.uk-UA.Designer.cs b/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.uk-UA.Designer.cs index 1f0de3a0d..95487a637 100644 --- a/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.uk-UA.Designer.cs +++ b/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.uk-UA.Designer.cs @@ -212,6 +212,15 @@ internal static string CannotFindAnyPositions { } } + /// + /// Looks up a localized string similar to Не вдалося знайти жодного поля з такою назвою. + /// + internal static string CannotFindAnyPropertyWithThisName { + get { + return ResourceManager.GetString("CannotFindAnyPropertyWithThisName", resourceCulture); + } + } + /// /// Looks up a localized string similar to Не вдалося знайти будь-які пов'язані цифри за ідентифікатором стріткоду: {0}. /// diff --git a/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.uk-UA.resx b/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.uk-UA.resx index f79a0bc7a..a3eeaa999 100644 --- a/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.uk-UA.resx +++ b/Streetcode/Streetcode.BLL/Resources/SharedResource.CannotFindSharedResource.uk-UA.resx @@ -189,6 +189,9 @@ Не вдалося знайти жодний стріткод з відповідним TagId: {0} + + Не вдалося знайти стріткод в улюблених + Не вдалося знайти жодного субтитра за ідентифікатором стріткоду: {0} @@ -321,4 +324,7 @@ Не вдалося знайти історичний контекст з назвою '{0}' + + Не вдалося знайти жодного поля з такою назвою + \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.en-US.Designer.cs b/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.en-US.Designer.cs index 080b2fa42..9877f544d 100644 --- a/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.en-US.Designer.cs +++ b/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.en-US.Designer.cs @@ -149,6 +149,15 @@ internal static string InvalidNewsUrl { } } + /// + /// Looks up a localized string similar to Pagination parameters must be valid. + /// + internal static string InvalidPaginationParameters { + get { + return ResourceManager.GetString("InvalidPaginationParameters", resourceCulture); + } + } + /// /// Looks up a localized string similar to Field '{0}' has invalid precision. /// @@ -194,6 +203,15 @@ internal static string MaxLength { } } + /// + /// Looks up a localized string similar to Максимальна length of field '{0}' is {1}. + /// + internal static string MinLength { + get { + return ResourceManager.GetString("MinLength", resourceCulture); + } + } + /// /// Looks up a localized string similar to Field '{0}' must be between {1} and {2}. /// @@ -239,6 +257,15 @@ internal static string MustContainAtMostOneAlt2 { } } + /// + /// Looks up a localized string similar to Field '{0}' may contain at most three expertises. + /// + internal static string MustContainAtMostThreeExpertises { + get { + return ResourceManager.GetString("MustContainAtMostThreeExpertises", resourceCulture); + } + } + /// /// Looks up a localized string similar to Field '{0}' must contain exactly one black and white image.. /// @@ -248,6 +275,33 @@ internal static string MustContainExactlyOneAlt1 { } } + /// + /// Looks up a localized string similar to {0} must not be in the past.. + /// + internal static string MustNotBeInPast { + get { + return ResourceManager.GetString("MustNotBeInPast", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Name must consist of Cyrillic or Latin characters (both uppercase and lowercase) and can only include hyphens (-) and apostrophes (').. + /// + internal static string NameFormat { + get { + return ResourceManager.GetString("NameFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Surname must consist of Cyrillic or Latin characters (both uppercase and lowercase) and can only include hyphens (-) and apostrophes (').. + /// + internal static string SurnameFormat { + get { + return ResourceManager.GetString("SurnameFormat", resourceCulture); + } + } + /// /// Looks up a localized string similar to Transliteration url must consists of small latin characters, numbers and hyphen. /// @@ -257,6 +311,15 @@ internal static string TransliterationUrlFormat { } } + /// + /// Looks up a localized string similar to Surname must consist of Latin characters (lowercase) and can only include hyphens (-), apostrophes (') and underscores(_).. + /// + internal static string UserNameFormat { + get { + return ResourceManager.GetString("UserNameFormat", resourceCulture); + } + } + /// /// Looks up a localized string similar to Field '{0}' must be valid url. /// diff --git a/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.en-US.resx b/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.en-US.resx index 8afa9784e..30be546e1 100644 --- a/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.en-US.resx +++ b/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.en-US.resx @@ -204,4 +204,10 @@ The image size can't exceed {0} MB + + Pagination parameters must be valid + + + {0} must not be in the past. + \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.uk-UA.Designer.cs b/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.uk-UA.Designer.cs index 05ebdc478..a86341ef5 100644 --- a/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.uk-UA.Designer.cs +++ b/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.uk-UA.Designer.cs @@ -149,6 +149,15 @@ internal static string InvalidNewsUrl { } } + /// + /// Looks up a localized string similar to Параметри пагінації повинні бути коректними. + /// + internal static string InvalidPaginationParameters { + get { + return ResourceManager.GetString("InvalidPaginationParameters", resourceCulture); + } + } + /// /// Looks up a localized string similar to Поле '{0}' має неправильну точність. /// @@ -194,6 +203,15 @@ internal static string MaxLength { } } + /// + /// Looks up a localized string similar to Мінімальна довжина поля '{0}' - {1}. + /// + internal static string MinLength { + get { + return ResourceManager.GetString("MinLength", resourceCulture); + } + } + /// /// Looks up a localized string similar to Поле '{0}' має бути між {1} і {2}. /// @@ -239,6 +257,15 @@ internal static string MustContainAtMostOneAlt2 { } } + /// + /// Looks up a localized string similar to Поле '{0}' може містити щонайбільше три досвіди.. + /// + internal static string MustContainAtMostThreeExpertises { + get { + return ResourceManager.GetString("MustContainAtMostThreeExpertises", resourceCulture); + } + } + /// /// Looks up a localized string similar to Поле '{0}' має містити рівно одне чорно-біле зображення.. /// @@ -248,6 +275,33 @@ internal static string MustContainExactlyOneAlt1 { } } + /// + /// Looks up a localized string similar to {0} не повинна бути у минулому.. + /// + internal static string MustNotBeInPast { + get { + return ResourceManager.GetString("MustNotBeInPast", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ім'я повинно складатися лише з літер латиниці або кирилиці (великих і малих) та може містити лише символи дефіс (-) і апостроф (').. + /// + internal static string NameFormat { + get { + return ResourceManager.GetString("NameFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Прізвище повинно складатися лише з літер латиниці або кирилиці (великих і малих) та може містити лише символи дефіс (-) і апостроф (').. + /// + internal static string SurnameFormat { + get { + return ResourceManager.GetString("SurnameFormat", resourceCulture); + } + } + /// /// Looks up a localized string similar to Транслітероване посилання має містити тільки маленькі латинські літери, цифри та дефіс. /// @@ -257,6 +311,15 @@ internal static string TransliterationUrlFormat { } } + /// + /// Looks up a localized string similar to Нікнейм повинен складатися лише з літер латиниці (малих) та може містити лише символи дефіс (-), апостроф (') та підкреслення(_).. + /// + internal static string UserNameFormat { + get { + return ResourceManager.GetString("UserNameFormat", resourceCulture); + } + } + /// /// Looks up a localized string similar to Поле '{0}' повинно бути дійсною URL адресою . /// diff --git a/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.uk-UA.resx b/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.uk-UA.resx index 0651f2839..26c26a41e 100644 --- a/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.uk-UA.resx +++ b/Streetcode/Streetcode.BLL/Resources/SharedResource.FailedToValidateSharedResource.uk-UA.resx @@ -204,4 +204,10 @@ Розмір картинки не може перевищувати {0} MB + + Параметри пагінації повинні бути коректними + + + {0} не повинна бути у минулому. + \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/Resources/SharedResource.FieldNamesSharedResource.uk-UA.resx b/Streetcode/Streetcode.BLL/Resources/SharedResource.FieldNamesSharedResource.uk-UA.resx index 08b9786f3..cc47a79f0 100644 --- a/Streetcode/Streetcode.BLL/Resources/SharedResource.FieldNamesSharedResource.uk-UA.resx +++ b/Streetcode/Streetcode.BLL/Resources/SharedResource.FieldNamesSharedResource.uk-UA.resx @@ -142,7 +142,7 @@ Ім'я - Вакансія + Позиція Ідентифікатор картинки @@ -252,12 +252,12 @@ Прізвище - - Псевдонім - Тизер + + Псевдонім + Транслітероване посилання diff --git a/Streetcode/Streetcode.BLL/Resources/SharedResource.NoSharedResource.en-US.resx b/Streetcode/Streetcode.BLL/Resources/SharedResource.NoSharedResource.en-US.resx index 5e08be28e..9a9b03191 100644 --- a/Streetcode/Streetcode.BLL/Resources/SharedResource.NoSharedResource.en-US.resx +++ b/Streetcode/Streetcode.BLL/Resources/SharedResource.NoSharedResource.en-US.resx @@ -159,4 +159,13 @@ No team with such id + + No streetcode has been added to favourites + + + No favourite streetcode with corresponding id: {0} + + + No toponym with such streetcode id: {0} + \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/Resources/SharedResource.NoSharedResource.uk-UA.resx b/Streetcode/Streetcode.BLL/Resources/SharedResource.NoSharedResource.uk-UA.resx index 196898071..2747db0d4 100644 --- a/Streetcode/Streetcode.BLL/Resources/SharedResource.NoSharedResource.uk-UA.resx +++ b/Streetcode/Streetcode.BLL/Resources/SharedResource.NoSharedResource.uk-UA.resx @@ -159,4 +159,13 @@ Жодної команди з таким ідентифікатором + + Жодний стріткод не додано до улюблених + + + Жодного улюбленого стріткоду з ідентифікатором: {0} + + + Жодного топоніма з таким ідентифікатором стріткоду: {0} + \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/Services/Authentication/GoogleService.cs b/Streetcode/Streetcode.BLL/Services/Authentication/GoogleService.cs new file mode 100644 index 000000000..7990b976b --- /dev/null +++ b/Streetcode/Streetcode.BLL/Services/Authentication/GoogleService.cs @@ -0,0 +1,30 @@ +using Google.Apis.Auth; +using Microsoft.Extensions.Configuration; +using Streetcode.BLL.Interfaces.Authentication; + +namespace Streetcode.BLL.Services.Authentication +{ + public class GoogleService : IGoogleService + { + private readonly IConfiguration _configuration; + public GoogleService(IConfiguration configuration) + { + _configuration = configuration; + } + + public async Task ValidateGoogleToken(string id) + { + if (string.IsNullOrEmpty(_configuration["Authentication:Google:ClientId"])) + { + throw new InvalidOperationException("Google ClientId configuration is missing"); + } + + var payload = await GoogleJsonWebSignature.ValidateAsync(id, new GoogleJsonWebSignature.ValidationSettings + { + Audience = new[] { _configuration["Authentication:Google:ClientId"] } + }); + + return payload; + } + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/Services/Authentication/TokenService.cs b/Streetcode/Streetcode.BLL/Services/Authentication/TokenService.cs index 57594f4b1..4d8c99df1 100644 --- a/Streetcode/Streetcode.BLL/Services/Authentication/TokenService.cs +++ b/Streetcode/Streetcode.BLL/Services/Authentication/TokenService.cs @@ -1,5 +1,4 @@ -using System.Data; -using System.IdentityModel.Tokens.Jwt; +using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using System.Security.Cryptography; @@ -58,15 +57,8 @@ public JwtSecurityToken RefreshToken(string accessToken, string refreshToken) throw new Exception(InvalidRefreshTokenErrorMessage); } - var tokenDescriptor = new SecurityTokenDescriptor() - { - Subject = new ClaimsIdentity(principles?.Claims), - Expires = DateTime.UtcNow.AddMinutes(_jwtOptions.AccessTokenLifetimeInMinutes), - SigningCredentials = _signingCredentials, - Issuer = _jwtOptions.Issuer, - Audience = _jwtOptions.Audience - }; - var newToken = _jwtSecurityTokenHandler.CreateJwtSecurityToken(tokenDescriptor); + var tokenDescriptor = GetTokenDescriptorAsync(user); + var newToken = _jwtSecurityTokenHandler.CreateJwtSecurityToken(tokenDescriptor.Result); return newToken; } @@ -113,9 +105,9 @@ private ClaimsPrincipal GetPrinciplesFromExpiredToken(string token) { claimsPrincipal = _jwtSecurityTokenHandler.ValidateToken(token, tokenValidationParameters, out _); } - catch (SecurityTokenValidationException ex) + catch (SecurityTokenException ex) { - throw new SecurityTokenValidationException(ex.Message, ex); + throw new SecurityTokenException(ex.Message, ex); } return claimsPrincipal; @@ -139,7 +131,7 @@ private Task GetTokenDescriptorAsync(User user) Subject = new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.NameIdentifier, user.Id), - new Claim(ClaimTypes.Name, user.UserName ?? string.Empty), + new Claim(ClaimTypes.Name, user.UserName), new Claim(ClaimTypes.GivenName, user.Name), new Claim(ClaimTypes.Surname, user.Surname), new Claim(ClaimTypes.Email, user.Email ?? string.Empty), diff --git a/Streetcode/Streetcode.BLL/Services/BlobStorageService/BlobService.cs b/Streetcode/Streetcode.BLL/Services/BlobStorageService/BlobService.cs index 05cc5ba26..49ede1bab 100644 --- a/Streetcode/Streetcode.BLL/Services/BlobStorageService/BlobService.cs +++ b/Streetcode/Streetcode.BLL/Services/BlobStorageService/BlobService.cs @@ -1,4 +1,5 @@ -using System.Security.Cryptography; +using System.Buffers; +using System.Security.Cryptography; using System.Text; using Microsoft.Extensions.Options; using Streetcode.BLL.Interfaces.BlobStorage; @@ -33,18 +34,13 @@ public MemoryStream FindFileInStorageAsMemoryStream(string? name) public string FindFileInStorageAsBase64(string name) { - string[] splitedName = name.Split('.'); - - byte[] decodedBytes = DecryptFile(splitedName[0], splitedName[1]); - - string base64 = Convert.ToBase64String(decodedBytes); - - return base64; + using var stream = FindFileInStorageAsMemoryStream(name); + return Convert.ToBase64String(stream.ToArray()); } public string SaveFileInStorage(string base64, string name, string extension) { - byte[] imageBytes = Convert.FromBase64String(base64); + byte[] imageBytes = ConvertBase64ToBytes(base64); string createdFileName = $"{DateTime.Now}{name}" .Replace(" ", "_") .Replace(".", "_") @@ -60,7 +56,7 @@ public string SaveFileInStorage(string base64, string name, string extension) public void SaveFileInStorageBase64(string base64, string name, string extension) { - byte[] imageBytes = Convert.FromBase64String(base64.Trim()); + byte[] imageBytes = ConvertBase64ToBytes(base64.Trim()); Directory.CreateDirectory(_blobPath); EncryptFile(imageBytes, extension, name); } @@ -90,67 +86,102 @@ public string UpdateFileInStorage( return hashBlobStorageName; } - private IEnumerable GetAllBlobNames() + private byte[] ConvertBase64ToBytes(string base64) { - var paths = Directory.EnumerateFiles(_blobPath); + int byteCount = (base64.Length * 3) / 4; + byte[] buffer = ArrayPool.Shared.Rent(byteCount); + try + { + if (!Convert.TryFromBase64String(base64, buffer, out int bytesWritten)) + { + throw new FormatException("Invalid Base64 string."); + } - return paths.Select(p => Path.GetFileName(p)); + return buffer[..bytesWritten]; + } + finally + { + ArrayPool.Shared.Return(buffer); + } } private string HashFunction(string createdFileName) { - using (var hash = SHA256.Create()) - { - Encoding enc = Encoding.UTF8; - byte[] result = hash.ComputeHash(enc.GetBytes(createdFileName)); - return Convert.ToBase64String(result).Replace('/', '_'); - } + using var hash = SHA256.Create(); + byte[] result = hash.ComputeHash(Encoding.UTF8.GetBytes(createdFileName)); + return BitConverter.ToString(result).Replace("-", "").ToLower(); } private void EncryptFile(byte[] imageBytes, string type, string name) { + string filePath = Path.Combine(_blobPath, $"{name}.{type}"); byte[] keyBytes = Encoding.UTF8.GetBytes(_keyCrypt); - byte[] iv = new byte[16]; - using (var rng = RandomNumberGenerator.Create()) + using var aes = Aes.Create(); + aes.KeySize = 256; + aes.Key = keyBytes; + aes.GenerateIV(); + + using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write); + fileStream.Write(aes.IV, 0, aes.IV.Length); + + using var cryptoStream = new CryptoStream(fileStream, aes.CreateEncryptor(), CryptoStreamMode.Write); + + int bufferSize = 4096; + byte[] buffer = ArrayPool.Shared.Rent(bufferSize); + + try { - rng.GetBytes(iv); + using var memoryStream = new MemoryStream(imageBytes); + int bytesRead; + while ((bytesRead = memoryStream.Read(buffer, 0, buffer.Length)) > 0) + { + cryptoStream.Write(buffer, 0, bytesRead); + } } - - byte[] encryptedBytes; - using (Aes aes = Aes.Create()) + finally { - aes.KeySize = 256; - aes.Key = keyBytes; - aes.IV = iv; - ICryptoTransform encryptor = aes.CreateEncryptor(); - encryptedBytes = encryptor.TransformFinalBlock(imageBytes, 0, imageBytes.Length); + ArrayPool.Shared.Return(buffer); } - - byte[] encryptedData = new byte[encryptedBytes.Length + iv.Length]; - Buffer.BlockCopy(iv, 0, encryptedData, 0, iv.Length); - Buffer.BlockCopy(encryptedBytes, 0, encryptedData, iv.Length, encryptedBytes.Length); - File.WriteAllBytes($"{_blobPath}{name}.{type}", encryptedData); } private byte[] DecryptFile(string fileName, string type) { - byte[] encryptedData = File.ReadAllBytes($"{_blobPath}{fileName}.{type}"); + string filePath = Path.Combine(_blobPath, $"{fileName}.{type}"); + + using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read); byte[] keyBytes = Encoding.UTF8.GetBytes(_keyCrypt); byte[] iv = new byte[16]; - Buffer.BlockCopy(encryptedData, 0, iv, 0, iv.Length); - - byte[] decryptedBytes; - using (Aes aes = Aes.Create()) + if (fileStream.Read(iv, 0, iv.Length) != iv.Length) { - aes.KeySize = 256; - aes.Key = keyBytes; - aes.IV = iv; - ICryptoTransform decryptor = aes.CreateDecryptor(); - decryptedBytes = decryptor.TransformFinalBlock(encryptedData, iv.Length, encryptedData.Length - iv.Length); + throw new IOException("Invalid IV length"); } - return decryptedBytes; + using var aes = Aes.Create(); + aes.KeySize = 256; + aes.Key = keyBytes; + aes.IV = iv; + + using var cryptoStream = new CryptoStream(fileStream, aes.CreateDecryptor(), CryptoStreamMode.Read); + using var memoryStream = new MemoryStream(); + + int bufferSize = 4096; + byte[] buffer = ArrayPool.Shared.Rent(bufferSize); + + try + { + int bytesRead; + while ((bytesRead = cryptoStream.Read(buffer, 0, buffer.Length)) > 0) + { + memoryStream.Write(buffer, 0, bytesRead); + } + + return memoryStream.ToArray(); + } + finally + { + ArrayPool.Shared.Return(buffer); + } } } \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/Services/Instagram/InstagramService.cs b/Streetcode/Streetcode.BLL/Services/Instagram/InstagramService.cs index c3d919d0e..f43a39b2c 100644 --- a/Streetcode/Streetcode.BLL/Services/Instagram/InstagramService.cs +++ b/Streetcode/Streetcode.BLL/Services/Instagram/InstagramService.cs @@ -8,15 +8,15 @@ namespace Streetcode.BLL.Services.Instagram { public class InstagramService : IInstagramService { - private readonly HttpClient _httpClient; + private readonly IHttpClientFactory _httpClientFactory; private readonly InstagramEnvirovmentVariables _envirovment; private readonly string _userId; private readonly string _accessToken; private static int postLimit = 10; - public InstagramService(IOptions instagramEnvirovment) + public InstagramService(IOptions instagramEnvirovment, IHttpClientFactory httpClientFactory) { - _httpClient = new HttpClient(); + _httpClientFactory = httpClientFactory; _envirovment = instagramEnvirovment.Value; _userId = _envirovment.InstagramID; _accessToken = _envirovment.InstagramToken; @@ -24,12 +24,13 @@ public InstagramService(IOptions instagramEnvirov public async Task> GetPostsAsync() { - string apiUrl = $"https://graph.instagram.com/{_userId}/media?fields=id,caption,media_type,media_url,permalink,thumbnail_url&limit={2 * postLimit}&access_token={_accessToken}"; + var apiUrl = $"https://graph.instagram.com/{_userId}/media?fields=id,caption,media_type,media_url,permalink,thumbnail_url&limit={2 * postLimit}&access_token={_accessToken}"; - HttpResponseMessage response = await _httpClient.GetAsync(apiUrl); + var httpClient = _httpClientFactory.CreateClient(); + var response = await httpClient.GetAsync(apiUrl); response.EnsureSuccessStatusCode(); - string jsonResponse = await response.Content.ReadAsStringAsync(); + var jsonResponse = await response.Content.ReadAsStringAsync(); var jsonOptions = new JsonSerializerOptions { @@ -39,7 +40,7 @@ public async Task> GetPostsAsync() var postResponse = JsonSerializer.Deserialize(jsonResponse, jsonOptions); - IEnumerable posts = RemoveVideoMediaType(postResponse!.Data); + var posts = RemoveVideoMediaType(postResponse!.Data); return posts; } diff --git a/Streetcode/Streetcode.BLL/Streetcode.BLL.csproj b/Streetcode/Streetcode.BLL/Streetcode.BLL.csproj index b31973b0f..dcfc37cb7 100644 --- a/Streetcode/Streetcode.BLL/Streetcode.BLL.csproj +++ b/Streetcode/Streetcode.BLL/Streetcode.BLL.csproj @@ -8,6 +8,12 @@ + + + + + + @@ -42,13 +48,13 @@ + - diff --git a/Streetcode/Streetcode.BLL/Util/Helpers/HttpContextHelper.cs b/Streetcode/Streetcode.BLL/Util/Helpers/HttpContextHelper.cs index 83b42718c..870b3818c 100644 --- a/Streetcode/Streetcode.BLL/Util/Helpers/HttpContextHelper.cs +++ b/Streetcode/Streetcode.BLL/Util/Helpers/HttpContextHelper.cs @@ -5,19 +5,39 @@ namespace Streetcode.BLL.Util.Helpers; public static class HttpContextHelper { - public static string? GetCurrentUserName(IHttpContextAccessor httpContextAccessor) + public static string GetCurrentUserName(IHttpContextAccessor httpContextAccessor) { - return httpContextAccessor.HttpContext?.User?.Identity?.Name; + var userName = httpContextAccessor.HttpContext?.User.Identity?.Name; + if (string.IsNullOrEmpty(userName)) + { + throw new UnauthorizedAccessException("User is not authenticated or username is not available."); + } + + return userName; } - public static string? GetCurrentUserId(IHttpContextAccessor httpContextAccessor) + public static string GetCurrentUserId(IHttpContextAccessor httpContextAccessor) { - return httpContextAccessor.HttpContext?.User?.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value; + var userId = httpContextAccessor.HttpContext?.User.Claims + .FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value; + if (string.IsNullOrEmpty(userId)) + { + throw new UnauthorizedAccessException("User ID claim is not available."); + } + + return userId; } - public static string? GetCurrentUserEmail(IHttpContextAccessor httpContextAccessor) + public static string GetCurrentUserEmail(IHttpContextAccessor httpContextAccessor) { - return httpContextAccessor.HttpContext?.User?.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value; + var email = httpContextAccessor.HttpContext?.User.Claims + .FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value; + if (string.IsNullOrEmpty(email)) + { + throw new UnauthorizedAccessException("Email claim is not available."); + } + + return email; } public static string? GetCurrentDomain(IHttpContextAccessor httpContextAccessor) diff --git a/Streetcode/Streetcode.BLL/Util/Helpers/UserHelper.cs b/Streetcode/Streetcode.BLL/Util/Helpers/UserHelper.cs index bebe85491..5468dbdc1 100644 --- a/Streetcode/Streetcode.BLL/Util/Helpers/UserHelper.cs +++ b/Streetcode/Streetcode.BLL/Util/Helpers/UserHelper.cs @@ -1,5 +1,4 @@ -using System.Text; -using Streetcode.DAL.Entities.Users; +using Streetcode.DAL.Entities.Users; namespace Streetcode.BLL.Util.Helpers; @@ -7,7 +6,7 @@ public static class UserHelper { public static string EmailToUserNameConverter(User user) { - var cleanEmail = RemoveNonAlphaNumericFromEmail(user.Email); + var cleanEmail = RemoveNonAlphaNumericFromEmail(user.Email!); var randomSuffix = Guid.NewGuid().ToString("N").Substring(0, 8); @@ -17,15 +16,9 @@ public static string EmailToUserNameConverter(User user) private static string RemoveNonAlphaNumericFromEmail(string email) { var beforeAtSymbol = email.Split("@")[0]; - var sb = new StringBuilder(); - foreach (var character in beforeAtSymbol) - { - if (char.IsLetterOrDigit(character)) - { - sb.Append(character); - } - } + var onlyLettersOrDigits = beforeAtSymbol.Where(char.IsLetterOrDigit); + var cleanEmail = string.Concat(onlyLettersOrDigits); - return sb.ToString(); + return cleanEmail; } } \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/Validators/Analytics/StatisticRecordValidator.cs b/Streetcode/Streetcode.BLL/Validators/Analytics/StatisticRecordValidator.cs deleted file mode 100644 index 9be099e99..000000000 --- a/Streetcode/Streetcode.BLL/Validators/Analytics/StatisticRecordValidator.cs +++ /dev/null @@ -1,26 +0,0 @@ -using FluentValidation; -using Microsoft.Extensions.Localization; -using Streetcode.BLL.DTO.Analytics; -using Streetcode.BLL.MediatR.Analytics.StatisticRecord.Create; -using Streetcode.BLL.SharedResource; - -namespace Streetcode.BLL.Validators.Analytics; - -public class StatisticRecordValidator : AbstractValidator -{ - private const int AddressMaxLength = 150; - public StatisticRecordValidator(IStringLocalizer localizer, IStringLocalizer fieldLocalizer) - { - RuleFor(st => st.StatisticRecordDTO.Address) - .NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["Address"]]) - .MaximumLength(AddressMaxLength).WithMessage(localizer["MaxLength", fieldLocalizer["Address"], AddressMaxLength]); - - RuleFor(st => st.StatisticRecordDTO.StreetcodeCoordinate.Latitude) - .NotNull().WithMessage(localizer["IsRequired", fieldLocalizer["Latitude"]]) - .PrecisionScale(18, 4, true).WithMessage(localizer["InvalidPrecision", fieldLocalizer["Latitude"]]); - - RuleFor(st => st.StatisticRecordDTO.StreetcodeCoordinate.Longtitude) - .NotNull().WithMessage(localizer["IsRequired", fieldLocalizer["Longtitude"]]) - .PrecisionScale(18, 4, true).WithMessage(localizer["InvalidPrecision", fieldLocalizer["Longtitude"]]); - } -} \ No newline at end of file diff --git a/Streetcode/Streetcode.BLL/Validators/News/BaseNewsValidator.cs b/Streetcode/Streetcode.BLL/Validators/News/BaseNewsValidator.cs index 314e00d26..012eeffdc 100644 --- a/Streetcode/Streetcode.BLL/Validators/News/BaseNewsValidator.cs +++ b/Streetcode/Streetcode.BLL/Validators/News/BaseNewsValidator.cs @@ -35,7 +35,10 @@ public BaseNewsValidator( .MustAsync((imageId, token) => ValidationExtentions.HasExistingImage(_repositoryWrapper, imageId, token)).WithMessage(x => localizer["ImageDoesntExist", x.ImageId]); RuleFor(x => x.CreationDate) - .NotEmpty().WithMessage(x => localizer["IsRequired", fieldLocalizer["CreationDate"]]); + .Cascade(CascadeMode.Stop) + .NotEmpty().WithMessage(x => localizer["IsRequired", fieldLocalizer["CreationDate"]]) + .Must(date => date.Date >= DateTime.UtcNow.Date) + .WithMessage(x => localizer["MustNotBeInPast", fieldLocalizer["CreationDate"]]); RuleFor(x => x.URL) .NotEmpty().WithMessage(x => localizer["CannotBeEmpty", fieldLocalizer["TargetUrl"]]) diff --git a/Streetcode/Streetcode.BLL/Validators/Streetcode/CreateStreetcodeValidator.cs b/Streetcode/Streetcode.BLL/Validators/Streetcode/CreateStreetcodeValidator.cs index 31408bf39..880e2d435 100644 --- a/Streetcode/Streetcode.BLL/Validators/Streetcode/CreateStreetcodeValidator.cs +++ b/Streetcode/Streetcode.BLL/Validators/Streetcode/CreateStreetcodeValidator.cs @@ -1,6 +1,5 @@ using FluentValidation; using Microsoft.Extensions.Localization; -using Streetcode.BLL.DTO.Streetcode.Create; using Streetcode.BLL.MediatR.Streetcode.Streetcode.Create; using Streetcode.BLL.SharedResource; using Streetcode.BLL.Validators.AdditionalContent.Tag; @@ -33,8 +32,8 @@ public CreateStreetcodeValidator( RuleFor(c => c.Streetcode).SetValidator(baseStreetcodeValidator); RuleFor(c => c.Streetcode.Index) .MustAsync(BeUniqueIndex).WithMessage(x => localizer["MustBeUnique", fieldLocalizer["Index"]]); - RuleFor(c => c.Streetcode.ARBlockURL) - .MustBeValidUrl().When(c => c.Streetcode.ARBlockURL is not null) + RuleFor(c => c.Streetcode.ArBlockUrl) + .MustBeValidUrl().When(c => c.Streetcode.ArBlockUrl is not null) .WithMessage(localizer["ValidUrl", fieldLocalizer["ARBlockURL"]]); RuleFor(c => c.Streetcode.Text!.Title) diff --git a/Streetcode/Streetcode.BLL/Validators/Streetcode/Timeline/TimelineItemValidator.cs b/Streetcode/Streetcode.BLL/Validators/Streetcode/Timeline/TimelineItemValidator.cs index 604a7d5b0..cda6acc81 100644 --- a/Streetcode/Streetcode.BLL/Validators/Streetcode/Timeline/TimelineItemValidator.cs +++ b/Streetcode/Streetcode.BLL/Validators/Streetcode/Timeline/TimelineItemValidator.cs @@ -2,7 +2,6 @@ using Microsoft.Extensions.Localization; using Streetcode.BLL.DTO.Timeline.Update; using Streetcode.BLL.SharedResource; -using Streetcode.BLL.Validators.Common; namespace Streetcode.BLL.Validators.Streetcode.TimelineItem; diff --git a/Streetcode/Streetcode.BLL/Validators/Streetcode/Toponyms/StreetcodeToponymValidator.cs b/Streetcode/Streetcode.BLL/Validators/Streetcode/Toponyms/StreetcodeToponymValidator.cs index 5126eebf1..cdb15fb66 100644 --- a/Streetcode/Streetcode.BLL/Validators/Streetcode/Toponyms/StreetcodeToponymValidator.cs +++ b/Streetcode/Streetcode.BLL/Validators/Streetcode/Toponyms/StreetcodeToponymValidator.cs @@ -1,5 +1,4 @@ using FluentValidation; -using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.Extensions.Localization; using Streetcode.BLL.DTO.Toponyms; using Streetcode.BLL.SharedResource; diff --git a/Streetcode/Streetcode.BLL/Validators/Streetcode/UpdateStreetcodeValidator.cs b/Streetcode/Streetcode.BLL/Validators/Streetcode/UpdateStreetcodeValidator.cs index 52ef5ce3f..9f0a5cbe0 100644 --- a/Streetcode/Streetcode.BLL/Validators/Streetcode/UpdateStreetcodeValidator.cs +++ b/Streetcode/Streetcode.BLL/Validators/Streetcode/UpdateStreetcodeValidator.cs @@ -35,9 +35,9 @@ public UpdateStreetcodeValidator( RuleFor(c => c.Streetcode).SetValidator(baseStreetcodeValidator); RuleFor(c => c.Streetcode) .MustAsync(BeUniqueIndex).WithMessage(x => localizer["MustBeUnique", fieldLocalizer["Index"]]); - RuleFor(c => c.Streetcode!.ARBlockUrl) + RuleFor(c => c.Streetcode!.ArBlockUrl) .MustBeValidUrl() - .When(c => !string.IsNullOrEmpty(c.Streetcode.ARBlockUrl)) + .When(c => !string.IsNullOrEmpty(c.Streetcode.ArBlockUrl)) .WithMessage(localizer["ValidUrl", fieldLocalizer["ARBlockURL"]]); RuleFor(c => c.Streetcode.Text!.Title) diff --git a/Streetcode/Streetcode.BLL/Validators/Users/BaseUserValidator.cs b/Streetcode/Streetcode.BLL/Validators/Users/BaseUserValidator.cs index 8096d9679..370ce9867 100644 --- a/Streetcode/Streetcode.BLL/Validators/Users/BaseUserValidator.cs +++ b/Streetcode/Streetcode.BLL/Validators/Users/BaseUserValidator.cs @@ -32,19 +32,19 @@ public BaseUserValidator( .MaximumLength(MaxLengthAboutYourself).WithMessage(localizer["MaxLength", fieldLocalizer["AboutYourself"], MaxLengthAboutYourself]); RuleFor(dto => dto.UserName) - .Matches(@"^[a-z0-9'-_]+$").WithMessage(localizer["NameFormat", fieldLocalizer["UserName"], MinLengthSurname]) + .Matches(@"^[a-zA-Z0-9'\-_]+$").WithMessage(localizer["UserNameFormat"]) .NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["UserName"]]) .MinimumLength(MinLengthName).WithMessage(localizer["MinLength", fieldLocalizer["UserName"], MinLengthUserName]) .MaximumLength(MaxLengthName).WithMessage(localizer["MaxLength", fieldLocalizer["UserName"], MaxLengthUserName]); RuleFor(dto => dto.Name) - .Matches(@"^[a-zA-Zа-яА-ЯґҐєЄіІїЇ'-]+$").WithMessage(localizer["NameFormat", fieldLocalizer["Name"], MinLengthSurname]) + .Matches(@"^[a-zA-Zа-яА-ЯґҐєЄіІїЇ'-]+$").WithMessage(localizer["NameFormat"]) .NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["Name"]]) .MinimumLength(MinLengthName).WithMessage(localizer["MinLength", fieldLocalizer["Name"], MinLengthName]) .MaximumLength(MaxLengthName).WithMessage(localizer["MaxLength", fieldLocalizer["Name"], MaxLengthName]); RuleFor(dto => dto.Surname) - .Matches(@"^[a-zA-Zа-яА-ЯґҐєЄіІїЇ'-]+$").WithMessage(localizer["SurnameFormat", fieldLocalizer["Surname"], MinLengthSurname]) + .Matches(@"^[a-zA-Zа-яА-ЯґҐєЄіІїЇ'-]+$").WithMessage(localizer["SurnameFormat"]) .NotEmpty().WithMessage(localizer["CannotBeEmpty", fieldLocalizer["Surname"]]) .MinimumLength(MinLengthSurname).WithMessage(localizer["MinLength", fieldLocalizer["Surname"], MinLengthSurname]) .MaximumLength(MaxLengthSurname).WithMessage(localizer["MaxLength", fieldLocalizer["Surname"], MaxLengthSurname]); diff --git a/Streetcode/Streetcode.DAL/Configurations/StreetcodeContentMap.cs b/Streetcode/Streetcode.DAL/Configurations/StreetcodeContentMap.cs index cd105e6c4..5cf64ecd0 100644 --- a/Streetcode/Streetcode.DAL/Configurations/StreetcodeContentMap.cs +++ b/Streetcode/Streetcode.DAL/Configurations/StreetcodeContentMap.cs @@ -5,6 +5,7 @@ using Streetcode.DAL.Entities.Partners; using Streetcode.DAL.Entities.Sources; using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Streetcode.Favourites; using Streetcode.DAL.Entities.Streetcode.TextContent; using Streetcode.DAL.Entities.Streetcode.Types; using Streetcode.DAL.Entities.Toponyms; @@ -53,11 +54,11 @@ public void Configure(EntityTypeBuilder builder) .WithMany(i => i.Streetcodes) .UsingEntity( si => si.HasOne(i => i.Image) - .WithMany() - .HasForeignKey(i => i.ImageId), + .WithMany() + .HasForeignKey(i => i.ImageId), si => si.HasOne(i => i.Streetcode) - .WithMany() - .HasForeignKey(i => i.StreetcodeId)) + .WithMany() + .HasForeignKey(i => i.StreetcodeId)) .ToTable("streetcode_image", "streetcode"); builder @@ -70,35 +71,35 @@ public void Configure(EntityTypeBuilder builder) .WithMany(t => t.Streetcodes) .UsingEntity( st => st.HasOne(s => s.Toponym) - .WithMany() - .HasForeignKey(x => x.ToponymId), + .WithMany() + .HasForeignKey(x => x.ToponymId), st => st.HasOne(s => s.Streetcode) - .WithMany() - .HasForeignKey(x => x.StreetcodeId)) + .WithMany() + .HasForeignKey(x => x.StreetcodeId)) .ToTable("streetcode_toponym", "streetcode"); builder .HasMany(d => d.SourceLinkCategories) .WithMany(c => c.Streetcodes) .UsingEntity( - scat => scat.HasOne(i => i.SourceLinkCategory) - .WithMany(s => s.StreetcodeCategoryContents) - .HasForeignKey(i => i.SourceLinkCategoryId), - scat => scat.HasOne(i => i.Streetcode) - .WithMany(s => s.StreetcodeCategoryContents) - .HasForeignKey(i => i.StreetcodeId)) + scat => scat.HasOne(i => i.SourceLinkCategory) + .WithMany(s => s.StreetcodeCategoryContents) + .HasForeignKey(i => i.SourceLinkCategoryId), + scat => scat.HasOne(i => i.Streetcode) + .WithMany(s => s.StreetcodeCategoryContents) + .HasForeignKey(i => i.StreetcodeId)) .ToTable("streetcode_source_link_categories", "sources"); builder .HasMany(d => d.Partners) .WithMany(p => p.Streetcodes) .UsingEntity( - sp => sp.HasOne(i => i.Partner) - .WithMany() - .HasForeignKey(x => x.PartnerId), - sp => sp.HasOne(i => i.Streetcode) - .WithMany() - .HasForeignKey(x => x.StreetcodeId)) + sp => sp.HasOne(i => i.Partner) + .WithMany() + .HasForeignKey(x => x.PartnerId), + sp => sp.HasOne(i => i.Streetcode) + .WithMany() + .HasForeignKey(x => x.StreetcodeId)) .ToTable("streetcode_partners", "streetcode"); builder @@ -136,5 +137,17 @@ public void Configure(EntityTypeBuilder builder) .WithMany(u => u.StreetcodeContent) .HasForeignKey(s => s.UserId) .OnDelete(DeleteBehavior.NoAction); + + builder + .HasMany(u => u.UserFavourites) + .WithMany(s => s.StreetcodeFavourites) + .UsingEntity( + f => f.HasOne(i => i.User) + .WithMany() + .HasForeignKey(x => x.UserId), + f => f.HasOne(i => i.Streetcode) + .WithMany() + .HasForeignKey(x => x.StreetcodeId)) + .ToTable("favourites", "streetcode"); } } \ No newline at end of file diff --git a/Streetcode/Streetcode.DAL/Entities/Streetcode/Favourites/Favourite.cs b/Streetcode/Streetcode.DAL/Entities/Streetcode/Favourites/Favourite.cs new file mode 100644 index 000000000..111814c4c --- /dev/null +++ b/Streetcode/Streetcode.DAL/Entities/Streetcode/Favourites/Favourite.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Streetcode.DAL.Entities.Users; + +namespace Streetcode.DAL.Entities.Streetcode.Favourites +{ + [Table("favourites", Schema = "streetcode")] + public class Favourite + { + [Required] + public int StreetcodeId { get; set; } + [Required] + public string UserId { get; set; } = string.Empty; + public StreetcodeContent Streetcode { get; set; } = null!; + public User User { get; set; } = null!; + } +} diff --git a/Streetcode/Streetcode.DAL/Entities/Streetcode/StreetcodeContent.cs b/Streetcode/Streetcode.DAL/Entities/Streetcode/StreetcodeContent.cs index a4bc33827..b2d3adc01 100644 --- a/Streetcode/Streetcode.DAL/Entities/Streetcode/StreetcodeContent.cs +++ b/Streetcode/Streetcode.DAL/Entities/Streetcode/StreetcodeContent.cs @@ -8,6 +8,7 @@ using Streetcode.DAL.Entities.Media.Images; using Streetcode.DAL.Entities.Partners; using Streetcode.DAL.Entities.Sources; +using Streetcode.DAL.Entities.Streetcode.Favourites; using Streetcode.DAL.Entities.Streetcode.TextContent; using Streetcode.DAL.Entities.Timeline; using Streetcode.DAL.Entities.Toponyms; @@ -106,4 +107,6 @@ public class StreetcodeContent public List StreetcodeCategoryContents { get; set; } = new(); public List? Arts { get; set; } = new(); + + public List? UserFavourites { get; set; } = new(); } diff --git a/Streetcode/Streetcode.DAL/Entities/Users/User.cs b/Streetcode/Streetcode.DAL/Entities/Users/User.cs index 5daaf0129..bac91859b 100644 --- a/Streetcode/Streetcode.DAL/Entities/Users/User.cs +++ b/Streetcode/Streetcode.DAL/Entities/Users/User.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Identity; using Streetcode.DAL.Entities.Media.Images; using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Streetcode.Favourites; namespace Streetcode.DAL.Entities.Users { @@ -9,7 +10,7 @@ public class User : IdentityUser { [Required] [MinLength(2)] - [MaxLength(128)] + [MaxLength(50)] public new string UserName { get => base.UserName ?? string.Empty; @@ -18,11 +19,11 @@ public class User : IdentityUser [Required] [MinLength(2)] - [MaxLength(128)] + [MaxLength(50)] public string Name { get; set; } = null!; [Required] [MinLength(2)] - [MaxLength(128)] + [MaxLength(50)] public string Surname { get; set; } = null!; public string? RefreshToken { get; set; } [MaxLength(500)] @@ -30,7 +31,8 @@ public class User : IdentityUser public DateTime? RefreshTokenExpiry { get; set; } public int? AvatarId { get; set; } public Image? Avatar { get; set; } - public List Expertises { get; set; } = new (); + public List Expertises { get; set; } = new(); public List? StreetcodeContent { get; set; } = new(); + public List? StreetcodeFavourites { get; set; } = new(); } } diff --git a/Streetcode/Streetcode.DAL/Persistence/Migrations/20250204150151_AddFavourites.Designer.cs b/Streetcode/Streetcode.DAL/Persistence/Migrations/20250204150151_AddFavourites.Designer.cs new file mode 100644 index 000000000..6eb427f68 --- /dev/null +++ b/Streetcode/Streetcode.DAL/Persistence/Migrations/20250204150151_AddFavourites.Designer.cs @@ -0,0 +1,2032 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Streetcode.DAL.Persistence; + +#nullable disable + +namespace Streetcode.DAL.Persistence.Migrations +{ + [DbContext(typeof(StreetcodeDbContext))] + [Migration("20250204150151_AddFavourites")] + partial class AddFavourites + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .UseCollation("SQL_Ukrainian_CP1251_CI_AS") + .HasAnnotation("ProductVersion", "7.0.13") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Coordinate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CoordinateType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Latitude") + .HasColumnType("decimal(18,4)"); + + b.Property("Longtitude") + .HasColumnType("decimal(18,4)"); + + b.HasKey("Id"); + + b.ToTable("coordinates", "add_content"); + + b.HasDiscriminator("CoordinateType").HasValue("coordinate_base"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.StreetcodeTagIndex", b => + { + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("TagId") + .HasColumnType("int"); + + b.Property("Index") + .HasColumnType("int"); + + b.Property("IsVisible") + .HasColumnType("bit"); + + b.HasKey("StreetcodeId", "TagId"); + + b.HasIndex("TagId"); + + b.ToTable("streetcode_tag_index", "add_content"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Subtitle", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("SubtitleText") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("subtitles", "add_content"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Title") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("tags", "add_content"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Analytics.StatisticRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("Count") + .HasColumnType("int"); + + b.Property("QrId") + .HasColumnType("int"); + + b.Property("StreetcodeCoordinateId") + .HasColumnType("int"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeCoordinateId") + .IsUnique(); + + b.HasIndex("StreetcodeId"); + + b.ToTable("qr_coordinates", "coordinates"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Feedback.Response", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("responses", "feedback"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Jobs.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .IsRequired() + .HasMaxLength(3000) + .HasColumnType("nvarchar(3000)"); + + b.Property("Salary") + .IsRequired() + .HasMaxLength(15) + .HasColumnType("nvarchar(15)"); + + b.Property("Status") + .HasColumnType("bit"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(65) + .HasColumnType("nvarchar(65)"); + + b.HasKey("Id"); + + b.ToTable("job", "jobs"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Audio", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BlobName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property("Title") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("audios", "media"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.Art", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("Title") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.HasIndex("ImageId") + .IsUnique(); + + b.HasIndex("StreetcodeId"); + + b.ToTable("arts", "media"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.Image", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BlobName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("images", "media"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.ImageDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Alt") + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Title") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("ImageId") + .IsUnique(); + + b.ToTable("image_details", "media"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.StreetcodeImage", b => + { + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.HasKey("ImageId", "StreetcodeId"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("streetcode_image", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Video", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("Title") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Url") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("videos", "media"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.News.News", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(25000) + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("URL") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("ImageId") + .IsUnique(); + + b.HasIndex("URL") + .IsUnique(); + + b.ToTable("news", "news"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Partners.Partner", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .HasMaxLength(600) + .HasColumnType("nvarchar(600)"); + + b.Property("IsKeyPartner") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("IsVisibleEverywhere") + .HasColumnType("bit"); + + b.Property("LogoId") + .HasColumnType("int"); + + b.Property("TargetUrl") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("UrlTitle") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("LogoId") + .IsUnique(); + + b.ToTable("partners", "partners"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Partners.PartnerSourceLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("LogoType") + .HasColumnType("tinyint"); + + b.Property("PartnerId") + .HasColumnType("int"); + + b.Property("TargetUrl") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("PartnerId"); + + b.ToTable("partner_source_links", "partners"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Partners.StreetcodePartner", b => + { + b.Property("PartnerId") + .HasColumnType("int"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.HasKey("PartnerId", "StreetcodeId"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("streetcode_partners", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Sources.SourceLinkCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("source_link_categories", "sources"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Sources.StreetcodeCategoryContent", b => + { + b.Property("SourceLinkCategoryId") + .HasColumnType("int"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(15000) + .HasColumnType("nvarchar(max)"); + + b.HasKey("SourceLinkCategoryId", "StreetcodeId"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("streetcode_source_link_categories", "sources"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.Favourites.Favourite", b => + { + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("StreetcodeId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("favourites", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.RelatedFigure", b => + { + b.Property("ObserverId") + .HasColumnType("int"); + + b.Property("TargetId") + .HasColumnType("int"); + + b.HasKey("ObserverId", "TargetId"); + + b.HasIndex("TargetId"); + + b.ToTable("related_figures", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeArt", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ArtId") + .HasColumnType("int"); + + b.Property("Index") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(1); + + b.Property("StreetcodeArtSlideId") + .HasColumnType("int"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeArtSlideId"); + + b.HasIndex("StreetcodeId"); + + b.HasIndex("ArtId", "StreetcodeArtSlideId"); + + b.ToTable("streetcode_art", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeArtSlide", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Index") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(1); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("Template") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("streetcode_art_slide", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Alias") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AudioId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasDefaultValueSql("GETDATE()"); + + b.Property("DateString") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("EventEndOrPersonDeathDate") + .HasColumnType("datetime2"); + + b.Property("EventStartOrPersonBirthDate") + .HasColumnType("datetime2"); + + b.Property("Index") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("StreetcodeType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Teaser") + .IsRequired() + .HasMaxLength(650) + .HasColumnType("nvarchar(650)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("TransliterationUrl") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("UpdatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasDefaultValueSql("GETDATE()"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ViewCount") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.HasKey("Id"); + + b.HasIndex("AudioId") + .IsUnique() + .HasFilter("[AudioId] IS NOT NULL"); + + b.HasIndex("Index") + .IsUnique(); + + b.HasIndex("TransliterationUrl") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("streetcodes", "streetcode"); + + b.HasDiscriminator("StreetcodeType").HasValue("streetcode-base"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.Fact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("FactContent") + .IsRequired() + .HasMaxLength(600) + .HasColumnType("nvarchar(600)"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Index") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("facts", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.RelatedTerm", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("TermId") + .HasColumnType("int"); + + b.Property("Word") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("TermId"); + + b.ToTable("related_terms", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.Term", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("terms", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.Text", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AdditionalText") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("TextContent") + .IsRequired() + .HasMaxLength(15000) + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeId") + .IsUnique(); + + b.ToTable("texts", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.Positions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Position") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("positions", "team"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.TeamMember", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("IsMain") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ImageId") + .IsUnique(); + + b.ToTable("team_members", "team"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.TeamMemberLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("LogoType") + .HasColumnType("tinyint"); + + b.Property("TargetUrl") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("TeamMemberId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TeamMemberId"); + + b.ToTable("team_member_links", "team"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.TeamMemberPositions", b => + { + b.Property("TeamMemberId") + .HasColumnType("int"); + + b.Property("PositionsId") + .HasColumnType("int"); + + b.HasKey("TeamMemberId", "PositionsId"); + + b.HasIndex("PositionsId"); + + b.ToTable("team_member_positions", "team"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Timeline.HistoricalContext", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Title") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("historical_contexts", "timeline"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Timeline.HistoricalContextTimeline", b => + { + b.Property("TimelineId") + .HasColumnType("int"); + + b.Property("HistoricalContextId") + .HasColumnType("int"); + + b.HasKey("TimelineId", "HistoricalContextId"); + + b.HasIndex("HistoricalContextId"); + + b.ToTable("HistoricalContextsTimelines"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Timeline.TimelineItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DateViewPattern") + .HasColumnType("int"); + + b.Property("Description") + .HasMaxLength(600) + .HasColumnType("nvarchar(600)"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("timeline_items", "timeline"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Toponyms.StreetcodeToponym", b => + { + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("ToponymId") + .HasColumnType("int"); + + b.HasKey("StreetcodeId", "ToponymId"); + + b.HasIndex("ToponymId"); + + b.ToTable("streetcode_toponym", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Toponyms.Toponym", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AdminRegionNew") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("AdminRegionOld") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("Community") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("Gromada") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("Oblast") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("StreetName") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("StreetType") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("toponyms", "toponyms"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Transactions.TransactionLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("UrlTitle") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeId") + .IsUnique(); + + b.ToTable("transaction_links", "transactions"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Users.Expertise.Expertise", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Title") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("expertise", "users"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Users.Expertise.UserExpertise", b => + { + b.Property("ExpertiseId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("ExpertiseId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("user_expertise", "users"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Users.User", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AboutYourself") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("AvatarId") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("RefreshToken") + .HasColumnType("nvarchar(max)"); + + b.Property("RefreshTokenExpiry") + .HasColumnType("datetime2"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("Surname") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("AvatarId") + .IsUnique() + .HasFilter("[AvatarId] IS NOT NULL"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types.StreetcodeCoordinate", b => + { + b.HasBaseType("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Coordinate"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("coordinates", "add_content"); + + b.HasDiscriminator().HasValue("coordinate_streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types.ToponymCoordinate", b => + { + b.HasBaseType("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Coordinate"); + + b.Property("ToponymId") + .HasColumnType("int"); + + b.HasIndex("ToponymId") + .IsUnique() + .HasFilter("[ToponymId] IS NOT NULL"); + + b.ToTable("coordinates", "add_content"); + + b.HasDiscriminator().HasValue("coordinate_toponym"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.Types.EventStreetcode", b => + { + b.HasBaseType("Streetcode.DAL.Entities.Streetcode.StreetcodeContent"); + + b.ToTable("streetcodes", "streetcode"); + + b.HasDiscriminator().HasValue("streetcode-event"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.Types.PersonStreetcode", b => + { + b.HasBaseType("Streetcode.DAL.Entities.Streetcode.StreetcodeContent"); + + b.Property("FirstName") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("LastName") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Rank") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.ToTable("streetcodes", "streetcode"); + + b.HasDiscriminator().HasValue("streetcode-person"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Streetcode.DAL.Entities.Users.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Streetcode.DAL.Entities.Users.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Users.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Streetcode.DAL.Entities.Users.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.StreetcodeTagIndex", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("StreetcodeTagIndices") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.AdditionalContent.Tag", "Tag") + .WithMany("StreetcodeTagIndices") + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Subtitle", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("Subtitles") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Analytics.StatisticRecord", b => + { + b.HasOne("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types.StreetcodeCoordinate", "StreetcodeCoordinate") + .WithOne("StatisticRecord") + .HasForeignKey("Streetcode.DAL.Entities.Analytics.StatisticRecord", "StreetcodeCoordinateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("StatisticRecords") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Streetcode"); + + b.Navigation("StreetcodeCoordinate"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.Art", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Image") + .WithOne("Art") + .HasForeignKey("Streetcode.DAL.Entities.Media.Images.Art", "ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("Arts") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Image"); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.ImageDetails", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Image") + .WithOne("ImageDetails") + .HasForeignKey("Streetcode.DAL.Entities.Media.Images.ImageDetails", "ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.StreetcodeImage", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Image") + .WithMany() + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany() + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Image"); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Video", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("Videos") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.News.News", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Image") + .WithOne("News") + .HasForeignKey("Streetcode.DAL.Entities.News.News", "ImageId") + .OnDelete(DeleteBehavior.ClientCascade) + .IsRequired(); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Partners.Partner", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Logo") + .WithOne("Partner") + .HasForeignKey("Streetcode.DAL.Entities.Partners.Partner", "LogoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Logo"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Partners.PartnerSourceLink", b => + { + b.HasOne("Streetcode.DAL.Entities.Partners.Partner", "Partner") + .WithMany("PartnerSourceLinks") + .HasForeignKey("PartnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Partner"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Partners.StreetcodePartner", b => + { + b.HasOne("Streetcode.DAL.Entities.Partners.Partner", "Partner") + .WithMany() + .HasForeignKey("PartnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany() + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Partner"); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Sources.SourceLinkCategory", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Image") + .WithMany("SourceLinkCategories") + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Sources.StreetcodeCategoryContent", b => + { + b.HasOne("Streetcode.DAL.Entities.Sources.SourceLinkCategory", "SourceLinkCategory") + .WithMany("StreetcodeCategoryContents") + .HasForeignKey("SourceLinkCategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("StreetcodeCategoryContents") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("SourceLinkCategory"); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.Favourites.Favourite", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany() + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Users.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.RelatedFigure", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Observer") + .WithMany("Observers") + .HasForeignKey("ObserverId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Target") + .WithMany("Targets") + .HasForeignKey("TargetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Observer"); + + b.Navigation("Target"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeArt", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Art", "Art") + .WithMany("StreetcodeArts") + .HasForeignKey("ArtId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeArtSlide", "StreetcodeArtSlide") + .WithMany("StreetcodeArts") + .HasForeignKey("StreetcodeArtSlideId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("StreetcodeArts") + .HasForeignKey("StreetcodeId"); + + b.Navigation("Art"); + + b.Navigation("Streetcode"); + + b.Navigation("StreetcodeArtSlide"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeArtSlide", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("StreetcodeArtSlides") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Audio", "Audio") + .WithOne("Streetcode") + .HasForeignKey("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "AudioId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Streetcode.DAL.Entities.Users.User", "User") + .WithMany("StreetcodeContent") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Audio"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.Fact", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Image") + .WithMany("Facts") + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("Facts") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Image"); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.RelatedTerm", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.TextContent.Term", "Term") + .WithMany("RelatedTerms") + .HasForeignKey("TermId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Term"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.Text", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithOne("Text") + .HasForeignKey("Streetcode.DAL.Entities.Streetcode.TextContent.Text", "StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.TeamMember", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Image") + .WithOne("TeamMember") + .HasForeignKey("Streetcode.DAL.Entities.Team.TeamMember", "ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.TeamMemberLink", b => + { + b.HasOne("Streetcode.DAL.Entities.Team.TeamMember", "TeamMember") + .WithMany("TeamMemberLinks") + .HasForeignKey("TeamMemberId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TeamMember"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.TeamMemberPositions", b => + { + b.HasOne("Streetcode.DAL.Entities.Team.Positions", "Positions") + .WithMany() + .HasForeignKey("PositionsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Team.TeamMember", "TeamMember") + .WithMany() + .HasForeignKey("TeamMemberId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Positions"); + + b.Navigation("TeamMember"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Timeline.HistoricalContextTimeline", b => + { + b.HasOne("Streetcode.DAL.Entities.Timeline.HistoricalContext", "HistoricalContext") + .WithMany("HistoricalContextTimelines") + .HasForeignKey("HistoricalContextId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Timeline.TimelineItem", "Timeline") + .WithMany("HistoricalContextTimelines") + .HasForeignKey("TimelineId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("HistoricalContext"); + + b.Navigation("Timeline"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Timeline.TimelineItem", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("TimelineItems") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Toponyms.StreetcodeToponym", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany() + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Toponyms.Toponym", "Toponym") + .WithMany() + .HasForeignKey("ToponymId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + + b.Navigation("Toponym"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Transactions.TransactionLink", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithOne("TransactionLink") + .HasForeignKey("Streetcode.DAL.Entities.Transactions.TransactionLink", "StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Users.Expertise.UserExpertise", b => + { + b.HasOne("Streetcode.DAL.Entities.Users.Expertise.Expertise", "Expertise") + .WithMany() + .HasForeignKey("ExpertiseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Users.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expertise"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Users.User", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Avatar") + .WithOne("User") + .HasForeignKey("Streetcode.DAL.Entities.Users.User", "AvatarId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Avatar"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types.StreetcodeCoordinate", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("Coordinates") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types.ToponymCoordinate", b => + { + b.HasOne("Streetcode.DAL.Entities.Toponyms.Toponym", "Toponym") + .WithOne("Coordinate") + .HasForeignKey("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types.ToponymCoordinate", "ToponymId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Toponym"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Tag", b => + { + b.Navigation("StreetcodeTagIndices"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Audio", b => + { + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.Art", b => + { + b.Navigation("StreetcodeArts"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.Image", b => + { + b.Navigation("Art"); + + b.Navigation("Facts"); + + b.Navigation("ImageDetails"); + + b.Navigation("News"); + + b.Navigation("Partner"); + + b.Navigation("SourceLinkCategories"); + + b.Navigation("TeamMember"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Partners.Partner", b => + { + b.Navigation("PartnerSourceLinks"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Sources.SourceLinkCategory", b => + { + b.Navigation("StreetcodeCategoryContents"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeArtSlide", b => + { + b.Navigation("StreetcodeArts"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", b => + { + b.Navigation("Arts"); + + b.Navigation("Coordinates"); + + b.Navigation("Facts"); + + b.Navigation("Observers"); + + b.Navigation("StatisticRecords"); + + b.Navigation("StreetcodeArtSlides"); + + b.Navigation("StreetcodeArts"); + + b.Navigation("StreetcodeCategoryContents"); + + b.Navigation("StreetcodeTagIndices"); + + b.Navigation("Subtitles"); + + b.Navigation("Targets"); + + b.Navigation("Text"); + + b.Navigation("TimelineItems"); + + b.Navigation("TransactionLink"); + + b.Navigation("Videos"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.Term", b => + { + b.Navigation("RelatedTerms"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.TeamMember", b => + { + b.Navigation("TeamMemberLinks"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Timeline.HistoricalContext", b => + { + b.Navigation("HistoricalContextTimelines"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Timeline.TimelineItem", b => + { + b.Navigation("HistoricalContextTimelines"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Toponyms.Toponym", b => + { + b.Navigation("Coordinate"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Users.User", b => + { + b.Navigation("StreetcodeContent"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types.StreetcodeCoordinate", b => + { + b.Navigation("StatisticRecord") + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Streetcode/Streetcode.DAL/Persistence/Migrations/20250204150151_AddFavourites.cs b/Streetcode/Streetcode.DAL/Persistence/Migrations/20250204150151_AddFavourites.cs new file mode 100644 index 000000000..e23e09375 --- /dev/null +++ b/Streetcode/Streetcode.DAL/Persistence/Migrations/20250204150151_AddFavourites.cs @@ -0,0 +1,55 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Streetcode.DAL.Persistence.Migrations +{ + /// + public partial class AddFavourites : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "favourites", + schema: "streetcode", + columns: table => new + { + StreetcodeId = table.Column(type: "int", nullable: false), + UserId = table.Column(type: "nvarchar(450)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_favourites", x => new { x.StreetcodeId, x.UserId }); + table.ForeignKey( + name: "FK_favourites_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_favourites_streetcodes_StreetcodeId", + column: x => x.StreetcodeId, + principalSchema: "streetcode", + principalTable: "streetcodes", + principalColumn: "Id", + onDelete: ReferentialAction.NoAction); + }); + + migrationBuilder.CreateIndex( + name: "IX_favourites_UserId", + schema: "streetcode", + table: "favourites", + column: "UserId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + migrationBuilder.DropTable( + name: "favourites", + schema: "streetcode"); + } + } +} diff --git a/Streetcode/Streetcode.DAL/Persistence/Migrations/20250217205949_UpdateUserNameFieldsLenght.Designer.cs b/Streetcode/Streetcode.DAL/Persistence/Migrations/20250217205949_UpdateUserNameFieldsLenght.Designer.cs new file mode 100644 index 000000000..e80349da3 --- /dev/null +++ b/Streetcode/Streetcode.DAL/Persistence/Migrations/20250217205949_UpdateUserNameFieldsLenght.Designer.cs @@ -0,0 +1,1998 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Streetcode.DAL.Persistence; + +#nullable disable + +namespace Streetcode.DAL.Persistence.Migrations +{ + [DbContext(typeof(StreetcodeDbContext))] + [Migration("20250217205949_UpdateUserNameFieldsLenght")] + partial class UpdateUserNameFieldsLenght + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .UseCollation("SQL_Ukrainian_CP1251_CI_AS") + .HasAnnotation("ProductVersion", "7.0.13") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Coordinate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CoordinateType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Latitude") + .HasColumnType("decimal(18,4)"); + + b.Property("Longtitude") + .HasColumnType("decimal(18,4)"); + + b.HasKey("Id"); + + b.ToTable("coordinates", "add_content"); + + b.HasDiscriminator("CoordinateType").HasValue("coordinate_base"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.StreetcodeTagIndex", b => + { + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("TagId") + .HasColumnType("int"); + + b.Property("Index") + .HasColumnType("int"); + + b.Property("IsVisible") + .HasColumnType("bit"); + + b.HasKey("StreetcodeId", "TagId"); + + b.HasIndex("TagId"); + + b.ToTable("streetcode_tag_index", "add_content"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Subtitle", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("SubtitleText") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("subtitles", "add_content"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Title") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("tags", "add_content"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Analytics.StatisticRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("Count") + .HasColumnType("int"); + + b.Property("QrId") + .HasColumnType("int"); + + b.Property("StreetcodeCoordinateId") + .HasColumnType("int"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeCoordinateId") + .IsUnique(); + + b.HasIndex("StreetcodeId"); + + b.ToTable("qr_coordinates", "coordinates"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Feedback.Response", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("responses", "feedback"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Jobs.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .IsRequired() + .HasMaxLength(3000) + .HasColumnType("nvarchar(3000)"); + + b.Property("Salary") + .IsRequired() + .HasMaxLength(15) + .HasColumnType("nvarchar(15)"); + + b.Property("Status") + .HasColumnType("bit"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(65) + .HasColumnType("nvarchar(65)"); + + b.HasKey("Id"); + + b.ToTable("job", "jobs"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Audio", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BlobName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property("Title") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("audios", "media"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.Art", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("Title") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.HasIndex("ImageId") + .IsUnique(); + + b.HasIndex("StreetcodeId"); + + b.ToTable("arts", "media"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.Image", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BlobName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("images", "media"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.ImageDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Alt") + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Title") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("ImageId") + .IsUnique(); + + b.ToTable("image_details", "media"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.StreetcodeImage", b => + { + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.HasKey("ImageId", "StreetcodeId"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("streetcode_image", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Video", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("Title") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Url") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("videos", "media"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.News.News", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(25000) + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("URL") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("ImageId") + .IsUnique(); + + b.HasIndex("URL") + .IsUnique(); + + b.ToTable("news", "news"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Partners.Partner", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .HasMaxLength(600) + .HasColumnType("nvarchar(600)"); + + b.Property("IsKeyPartner") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("IsVisibleEverywhere") + .HasColumnType("bit"); + + b.Property("LogoId") + .HasColumnType("int"); + + b.Property("TargetUrl") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("UrlTitle") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("LogoId") + .IsUnique(); + + b.ToTable("partners", "partners"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Partners.PartnerSourceLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("LogoType") + .HasColumnType("tinyint"); + + b.Property("PartnerId") + .HasColumnType("int"); + + b.Property("TargetUrl") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("PartnerId"); + + b.ToTable("partner_source_links", "partners"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Partners.StreetcodePartner", b => + { + b.Property("PartnerId") + .HasColumnType("int"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.HasKey("PartnerId", "StreetcodeId"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("streetcode_partners", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Sources.SourceLinkCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("source_link_categories", "sources"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Sources.StreetcodeCategoryContent", b => + { + b.Property("SourceLinkCategoryId") + .HasColumnType("int"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(15000) + .HasColumnType("nvarchar(max)"); + + b.HasKey("SourceLinkCategoryId", "StreetcodeId"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("streetcode_source_link_categories", "sources"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.RelatedFigure", b => + { + b.Property("ObserverId") + .HasColumnType("int"); + + b.Property("TargetId") + .HasColumnType("int"); + + b.HasKey("ObserverId", "TargetId"); + + b.HasIndex("TargetId"); + + b.ToTable("related_figures", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeArt", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ArtId") + .HasColumnType("int"); + + b.Property("Index") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(1); + + b.Property("StreetcodeArtSlideId") + .HasColumnType("int"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeArtSlideId"); + + b.HasIndex("StreetcodeId"); + + b.HasIndex("ArtId", "StreetcodeArtSlideId"); + + b.ToTable("streetcode_art", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeArtSlide", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Index") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(1); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("Template") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("streetcode_art_slide", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Alias") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("AudioId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasDefaultValueSql("GETDATE()"); + + b.Property("DateString") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("EventEndOrPersonDeathDate") + .HasColumnType("datetime2"); + + b.Property("EventStartOrPersonBirthDate") + .HasColumnType("datetime2"); + + b.Property("Index") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("StreetcodeType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Teaser") + .IsRequired() + .HasMaxLength(650) + .HasColumnType("nvarchar(650)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("TransliterationUrl") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("UpdatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasDefaultValueSql("GETDATE()"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ViewCount") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.HasKey("Id"); + + b.HasIndex("AudioId") + .IsUnique() + .HasFilter("[AudioId] IS NOT NULL"); + + b.HasIndex("Index") + .IsUnique(); + + b.HasIndex("TransliterationUrl") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("streetcodes", "streetcode"); + + b.HasDiscriminator("StreetcodeType").HasValue("streetcode-base"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.Fact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("FactContent") + .IsRequired() + .HasMaxLength(600) + .HasColumnType("nvarchar(600)"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("Index") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("facts", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.RelatedTerm", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("TermId") + .HasColumnType("int"); + + b.Property("Word") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("TermId"); + + b.ToTable("related_terms", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.Term", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("terms", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.Text", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AdditionalText") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("TextContent") + .IsRequired() + .HasMaxLength(15000) + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("nvarchar(300)"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeId") + .IsUnique(); + + b.ToTable("texts", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.Positions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Position") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("positions", "team"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.TeamMember", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("ImageId") + .HasColumnType("int"); + + b.Property("IsMain") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ImageId") + .IsUnique(); + + b.ToTable("team_members", "team"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.TeamMemberLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("LogoType") + .HasColumnType("tinyint"); + + b.Property("TargetUrl") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("TeamMemberId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TeamMemberId"); + + b.ToTable("team_member_links", "team"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.TeamMemberPositions", b => + { + b.Property("TeamMemberId") + .HasColumnType("int"); + + b.Property("PositionsId") + .HasColumnType("int"); + + b.HasKey("TeamMemberId", "PositionsId"); + + b.HasIndex("PositionsId"); + + b.ToTable("team_member_positions", "team"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Timeline.HistoricalContext", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Title") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("historical_contexts", "timeline"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Timeline.HistoricalContextTimeline", b => + { + b.Property("TimelineId") + .HasColumnType("int"); + + b.Property("HistoricalContextId") + .HasColumnType("int"); + + b.HasKey("TimelineId", "HistoricalContextId"); + + b.HasIndex("HistoricalContextId"); + + b.ToTable("HistoricalContextsTimelines"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Timeline.TimelineItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DateViewPattern") + .HasColumnType("int"); + + b.Property("Description") + .HasMaxLength(600) + .HasColumnType("nvarchar(600)"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("timeline_items", "timeline"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Toponyms.StreetcodeToponym", b => + { + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("ToponymId") + .HasColumnType("int"); + + b.HasKey("StreetcodeId", "ToponymId"); + + b.HasIndex("ToponymId"); + + b.ToTable("streetcode_toponym", "streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Toponyms.Toponym", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AdminRegionNew") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("AdminRegionOld") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("Community") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("Gromada") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("Oblast") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("StreetName") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("StreetType") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("toponyms", "toponyms"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Transactions.TransactionLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("UrlTitle") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("StreetcodeId") + .IsUnique(); + + b.ToTable("transaction_links", "transactions"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Users.Expertise.Expertise", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Title") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("expertise", "users"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Users.Expertise.UserExpertise", b => + { + b.Property("ExpertiseId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("ExpertiseId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("user_expertise", "users"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Users.User", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AboutYourself") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("AvatarId") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("RefreshToken") + .HasColumnType("nvarchar(max)"); + + b.Property("RefreshTokenExpiry") + .HasColumnType("datetime2"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("Surname") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("AvatarId") + .IsUnique() + .HasFilter("[AvatarId] IS NOT NULL"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types.StreetcodeCoordinate", b => + { + b.HasBaseType("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Coordinate"); + + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.HasIndex("StreetcodeId"); + + b.ToTable("coordinates", "add_content"); + + b.HasDiscriminator().HasValue("coordinate_streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types.ToponymCoordinate", b => + { + b.HasBaseType("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Coordinate"); + + b.Property("ToponymId") + .HasColumnType("int"); + + b.HasIndex("ToponymId") + .IsUnique() + .HasFilter("[ToponymId] IS NOT NULL"); + + b.ToTable("coordinates", "add_content"); + + b.HasDiscriminator().HasValue("coordinate_toponym"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.Types.EventStreetcode", b => + { + b.HasBaseType("Streetcode.DAL.Entities.Streetcode.StreetcodeContent"); + + b.ToTable("streetcodes", "streetcode"); + + b.HasDiscriminator().HasValue("streetcode-event"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.Types.PersonStreetcode", b => + { + b.HasBaseType("Streetcode.DAL.Entities.Streetcode.StreetcodeContent"); + + b.Property("FirstName") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("LastName") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Rank") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.ToTable("streetcodes", "streetcode"); + + b.HasDiscriminator().HasValue("streetcode-person"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Streetcode.DAL.Entities.Users.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Streetcode.DAL.Entities.Users.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Users.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Streetcode.DAL.Entities.Users.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.StreetcodeTagIndex", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("StreetcodeTagIndices") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.AdditionalContent.Tag", "Tag") + .WithMany("StreetcodeTagIndices") + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Subtitle", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("Subtitles") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Analytics.StatisticRecord", b => + { + b.HasOne("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types.StreetcodeCoordinate", "StreetcodeCoordinate") + .WithOne("StatisticRecord") + .HasForeignKey("Streetcode.DAL.Entities.Analytics.StatisticRecord", "StreetcodeCoordinateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("StatisticRecords") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Streetcode"); + + b.Navigation("StreetcodeCoordinate"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.Art", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Image") + .WithOne("Art") + .HasForeignKey("Streetcode.DAL.Entities.Media.Images.Art", "ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("Arts") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Image"); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.ImageDetails", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Image") + .WithOne("ImageDetails") + .HasForeignKey("Streetcode.DAL.Entities.Media.Images.ImageDetails", "ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.StreetcodeImage", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Image") + .WithMany() + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany() + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Image"); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Video", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("Videos") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.News.News", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Image") + .WithOne("News") + .HasForeignKey("Streetcode.DAL.Entities.News.News", "ImageId") + .OnDelete(DeleteBehavior.ClientCascade) + .IsRequired(); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Partners.Partner", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Logo") + .WithOne("Partner") + .HasForeignKey("Streetcode.DAL.Entities.Partners.Partner", "LogoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Logo"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Partners.PartnerSourceLink", b => + { + b.HasOne("Streetcode.DAL.Entities.Partners.Partner", "Partner") + .WithMany("PartnerSourceLinks") + .HasForeignKey("PartnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Partner"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Partners.StreetcodePartner", b => + { + b.HasOne("Streetcode.DAL.Entities.Partners.Partner", "Partner") + .WithMany() + .HasForeignKey("PartnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany() + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Partner"); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Sources.SourceLinkCategory", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Image") + .WithMany("SourceLinkCategories") + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Sources.StreetcodeCategoryContent", b => + { + b.HasOne("Streetcode.DAL.Entities.Sources.SourceLinkCategory", "SourceLinkCategory") + .WithMany("StreetcodeCategoryContents") + .HasForeignKey("SourceLinkCategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("StreetcodeCategoryContents") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("SourceLinkCategory"); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.RelatedFigure", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Observer") + .WithMany("Observers") + .HasForeignKey("ObserverId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Target") + .WithMany("Targets") + .HasForeignKey("TargetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Observer"); + + b.Navigation("Target"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeArt", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Art", "Art") + .WithMany("StreetcodeArts") + .HasForeignKey("ArtId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeArtSlide", "StreetcodeArtSlide") + .WithMany("StreetcodeArts") + .HasForeignKey("StreetcodeArtSlideId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("StreetcodeArts") + .HasForeignKey("StreetcodeId"); + + b.Navigation("Art"); + + b.Navigation("Streetcode"); + + b.Navigation("StreetcodeArtSlide"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeArtSlide", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("StreetcodeArtSlides") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Audio", "Audio") + .WithOne("Streetcode") + .HasForeignKey("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "AudioId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Streetcode.DAL.Entities.Users.User", "User") + .WithMany("StreetcodeContent") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Audio"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.Fact", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Image") + .WithMany("Facts") + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("Facts") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Image"); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.RelatedTerm", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.TextContent.Term", "Term") + .WithMany("RelatedTerms") + .HasForeignKey("TermId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Term"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.Text", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithOne("Text") + .HasForeignKey("Streetcode.DAL.Entities.Streetcode.TextContent.Text", "StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.TeamMember", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Image") + .WithOne("TeamMember") + .HasForeignKey("Streetcode.DAL.Entities.Team.TeamMember", "ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.TeamMemberLink", b => + { + b.HasOne("Streetcode.DAL.Entities.Team.TeamMember", "TeamMember") + .WithMany("TeamMemberLinks") + .HasForeignKey("TeamMemberId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TeamMember"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.TeamMemberPositions", b => + { + b.HasOne("Streetcode.DAL.Entities.Team.Positions", "Positions") + .WithMany() + .HasForeignKey("PositionsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Team.TeamMember", "TeamMember") + .WithMany() + .HasForeignKey("TeamMemberId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Positions"); + + b.Navigation("TeamMember"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Timeline.HistoricalContextTimeline", b => + { + b.HasOne("Streetcode.DAL.Entities.Timeline.HistoricalContext", "HistoricalContext") + .WithMany("HistoricalContextTimelines") + .HasForeignKey("HistoricalContextId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Timeline.TimelineItem", "Timeline") + .WithMany("HistoricalContextTimelines") + .HasForeignKey("TimelineId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("HistoricalContext"); + + b.Navigation("Timeline"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Timeline.TimelineItem", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("TimelineItems") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Toponyms.StreetcodeToponym", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany() + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Toponyms.Toponym", "Toponym") + .WithMany() + .HasForeignKey("ToponymId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + + b.Navigation("Toponym"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Transactions.TransactionLink", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithOne("TransactionLink") + .HasForeignKey("Streetcode.DAL.Entities.Transactions.TransactionLink", "StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Users.Expertise.UserExpertise", b => + { + b.HasOne("Streetcode.DAL.Entities.Users.Expertise.Expertise", "Expertise") + .WithMany() + .HasForeignKey("ExpertiseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Users.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Expertise"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Users.User", b => + { + b.HasOne("Streetcode.DAL.Entities.Media.Images.Image", "Avatar") + .WithOne("User") + .HasForeignKey("Streetcode.DAL.Entities.Users.User", "AvatarId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Avatar"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types.StreetcodeCoordinate", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany("Coordinates") + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types.ToponymCoordinate", b => + { + b.HasOne("Streetcode.DAL.Entities.Toponyms.Toponym", "Toponym") + .WithOne("Coordinate") + .HasForeignKey("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types.ToponymCoordinate", "ToponymId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Toponym"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Tag", b => + { + b.Navigation("StreetcodeTagIndices"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Audio", b => + { + b.Navigation("Streetcode"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.Art", b => + { + b.Navigation("StreetcodeArts"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Media.Images.Image", b => + { + b.Navigation("Art"); + + b.Navigation("Facts"); + + b.Navigation("ImageDetails"); + + b.Navigation("News"); + + b.Navigation("Partner"); + + b.Navigation("SourceLinkCategories"); + + b.Navigation("TeamMember"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Partners.Partner", b => + { + b.Navigation("PartnerSourceLinks"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Sources.SourceLinkCategory", b => + { + b.Navigation("StreetcodeCategoryContents"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeArtSlide", b => + { + b.Navigation("StreetcodeArts"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", b => + { + b.Navigation("Arts"); + + b.Navigation("Coordinates"); + + b.Navigation("Facts"); + + b.Navigation("Observers"); + + b.Navigation("StatisticRecords"); + + b.Navigation("StreetcodeArtSlides"); + + b.Navigation("StreetcodeArts"); + + b.Navigation("StreetcodeCategoryContents"); + + b.Navigation("StreetcodeTagIndices"); + + b.Navigation("Subtitles"); + + b.Navigation("Targets"); + + b.Navigation("Text"); + + b.Navigation("TimelineItems"); + + b.Navigation("TransactionLink"); + + b.Navigation("Videos"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.Term", b => + { + b.Navigation("RelatedTerms"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Team.TeamMember", b => + { + b.Navigation("TeamMemberLinks"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Timeline.HistoricalContext", b => + { + b.Navigation("HistoricalContextTimelines"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Timeline.TimelineItem", b => + { + b.Navigation("HistoricalContextTimelines"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Toponyms.Toponym", b => + { + b.Navigation("Coordinate"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.Users.User", b => + { + b.Navigation("StreetcodeContent"); + }); + + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types.StreetcodeCoordinate", b => + { + b.Navigation("StatisticRecord") + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Streetcode/Streetcode.DAL/Persistence/Migrations/20250217205949_UpdateUserNameFieldsLenght.cs b/Streetcode/Streetcode.DAL/Persistence/Migrations/20250217205949_UpdateUserNameFieldsLenght.cs new file mode 100644 index 000000000..039fa7d92 --- /dev/null +++ b/Streetcode/Streetcode.DAL/Persistence/Migrations/20250217205949_UpdateUserNameFieldsLenght.cs @@ -0,0 +1,58 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Streetcode.DAL.Persistence.Migrations +{ + /// + public partial class UpdateUserNameFieldsLenght : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Surname", + table: "AspNetUsers", + type: "nvarchar(50)", + maxLength: 50, + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(128)", + oldMaxLength: 128); + + migrationBuilder.AlterColumn( + name: "Name", + table: "AspNetUsers", + type: "nvarchar(50)", + maxLength: 50, + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(128)", + oldMaxLength: 128); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Surname", + table: "AspNetUsers", + type: "nvarchar(128)", + maxLength: 128, + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(50)", + oldMaxLength: 50); + + migrationBuilder.AlterColumn( + name: "Name", + table: "AspNetUsers", + type: "nvarchar(128)", + maxLength: 128, + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(50)", + oldMaxLength: 50); + } + } +} diff --git a/Streetcode/Streetcode.DAL/Persistence/Migrations/StreetcodeDbContextModelSnapshot.cs b/Streetcode/Streetcode.DAL/Persistence/Migrations/StreetcodeDbContextModelSnapshot.cs index 3c59e6084..ec8b6587b 100644 --- a/Streetcode/Streetcode.DAL/Persistence/Migrations/StreetcodeDbContextModelSnapshot.cs +++ b/Streetcode/Streetcode.DAL/Persistence/Migrations/StreetcodeDbContextModelSnapshot.cs @@ -656,6 +656,21 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("streetcode_source_link_categories", "sources"); }); + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.Favourites.Favourite", b => + { + b.Property("StreetcodeId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("StreetcodeId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("favourites", "streetcode"); + }); + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.RelatedFigure", b => { b.Property("ObserverId") @@ -791,6 +806,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("datetime2") .HasDefaultValueSql("GETDATE()"); + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + b.Property("ViewCount") .ValueGeneratedOnAdd() .HasColumnType("int") @@ -808,6 +827,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("TransliterationUrl") .IsUnique(); + b.HasIndex("UserId"); + b.ToTable("streetcodes", "streetcode"); b.HasDiscriminator("StreetcodeType").HasValue("streetcode-base"); @@ -1053,7 +1074,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("HistoricalContextId"); - b.ToTable("HistoricalContextsTimelines", (string)null); + b.ToTable("HistoricalContextsTimelines"); }); modelBuilder.Entity("Streetcode.DAL.Entities.Timeline.TimelineItem", b => @@ -1242,8 +1263,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Name") .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)"); + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); b.Property("NormalizedEmail") .HasMaxLength(256) @@ -1273,8 +1294,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Surname") .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)"); + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); b.Property("TwoFactorEnabled") .HasColumnType("bit"); @@ -1602,6 +1623,25 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Streetcode"); }); + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.Favourites.Favourite", b => + { + b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Streetcode") + .WithMany() + .HasForeignKey("StreetcodeId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("Streetcode.DAL.Entities.Users.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Streetcode"); + + b.Navigation("User"); + }); + modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.RelatedFigure", b => { b.HasOne("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "Observer") @@ -1663,7 +1703,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasForeignKey("Streetcode.DAL.Entities.Streetcode.StreetcodeContent", "AudioId") .OnDelete(DeleteBehavior.SetNull); + b.HasOne("Streetcode.DAL.Entities.Users.User", "User") + .WithMany("StreetcodeContent") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + b.Navigation("Audio"); + + b.Navigation("User"); }); modelBuilder.Entity("Streetcode.DAL.Entities.Streetcode.TextContent.Fact", b => @@ -1965,6 +2013,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Coordinate"); }); + modelBuilder.Entity("Streetcode.DAL.Entities.Users.User", b => + { + b.Navigation("StreetcodeContent"); + }); + modelBuilder.Entity("Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types.StreetcodeCoordinate", b => { b.Navigation("StatisticRecord") diff --git a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20230703154732_UpdatePartnerModel.sql b/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20230703154732_UpdatePartnerModel.sql deleted file mode 100644 index ac2edd334..000000000 --- a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20230703154732_UpdatePartnerModel.sql +++ /dev/null @@ -1,31 +0,0 @@ -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230703154732_UpdatePartnerModel') -BEGIN - DECLARE @var0 sysname; - SELECT @var0 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[partners].[partner_source_links]') AND [c].[name] = N'Title'); - IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [partners].[partner_source_links] DROP CONSTRAINT [' + @var0 + '];'); - ALTER TABLE [partners].[partner_source_links] DROP COLUMN [Title]; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230703154732_UpdatePartnerModel') -BEGIN - DECLARE @var1 sysname; - SELECT @var1 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[partners].[partners]') AND [c].[name] = N'TargetUrl'); - IF @var1 IS NOT NULL EXEC(N'ALTER TABLE [partners].[partners] DROP CONSTRAINT [' + @var1 + '];'); - ALTER TABLE [partners].[partners] ALTER COLUMN [TargetUrl] nvarchar(255) NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230703154732_UpdatePartnerModel') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20230703154732_UpdatePartnerModel', N'7.0.13'); -END; -GO - diff --git a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20230804120930_Change_StreetcodeCategoryContent_Text_to_10000_simb.sql b/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20230804120930_Change_StreetcodeCategoryContent_Text_to_10000_simb.sql deleted file mode 100644 index 87418bae8..000000000 --- a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20230804120930_Change_StreetcodeCategoryContent_Text_to_10000_simb.sql +++ /dev/null @@ -1,19 +0,0 @@ -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230804120930_Change_StreetcodeCategoryContent_Text_to_10000_simb') -BEGIN - DECLARE @var0 sysname; - SELECT @var0 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[sources].[streetcode_source_link_categories]') AND [c].[name] = N'Text'); - IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [sources].[streetcode_source_link_categories] DROP CONSTRAINT [' + @var0 + '];'); - ALTER TABLE [sources].[streetcode_source_link_categories] ALTER COLUMN [Text] nvarchar(max) NOT NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230804120930_Change_StreetcodeCategoryContent_Text_to_10000_simb') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20230804120930_Change_StreetcodeCategoryContent_Text_to_10000_simb', N'7.0.13'); -END; -GO - diff --git a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20230905201616_Jobs.sql b/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20230905201616_Jobs.sql deleted file mode 100644 index bef40b318..000000000 --- a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20230905201616_Jobs.sql +++ /dev/null @@ -1,44 +0,0 @@ -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230905201616_Jobs') -BEGIN - DECLARE @var0 sysname; - SELECT @var0 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[team].[team_members]') AND [c].[name] = N'LastName'); - IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [team].[team_members] DROP CONSTRAINT [' + @var0 + '];'); - ALTER TABLE [team].[team_members] DROP COLUMN [LastName]; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230905201616_Jobs') -BEGIN - IF SCHEMA_ID(N'jobs') IS NULL EXEC(N'CREATE SCHEMA [jobs];'); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230905201616_Jobs') -BEGIN - EXEC sp_rename N'[team].[team_members].[FirstName]', N'Name', N'COLUMN'; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230905201616_Jobs') -BEGIN - CREATE TABLE [jobs].[job] ( - [Id] int NOT NULL IDENTITY, - [Title] nvarchar(65) NOT NULL, - [Status] bit NOT NULL, - [Description] nvarchar(2000) NOT NULL, - [Salary] nvarchar(15) NOT NULL, - CONSTRAINT [PK_job] PRIMARY KEY ([Id]) - ); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230905201616_Jobs') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20230905201616_Jobs', N'7.0.13'); -END; -GO - diff --git a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20231130202258_DatestringLength.sql b/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20231130202258_DatestringLength.sql deleted file mode 100644 index 30af29191..000000000 --- a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20231130202258_DatestringLength.sql +++ /dev/null @@ -1,19 +0,0 @@ -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231130202258_DatestringLength') -BEGIN - DECLARE @var0 sysname; - SELECT @var0 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[streetcode].[streetcodes]') AND [c].[name] = N'DateString'); - IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [streetcode].[streetcodes] DROP CONSTRAINT [' + @var0 + '];'); - ALTER TABLE [streetcode].[streetcodes] ALTER COLUMN [DateString] nvarchar(100) NOT NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231130202258_DatestringLength') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20231130202258_DatestringLength', N'7.0.13'); -END; -GO - diff --git a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240104113247_JobsDescriptionLength.sql b/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240104113247_JobsDescriptionLength.sql deleted file mode 100644 index 03c6a1e7e..000000000 --- a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240104113247_JobsDescriptionLength.sql +++ /dev/null @@ -1,19 +0,0 @@ -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104113247_JobsDescriptionLength') -BEGIN - DECLARE @var0 sysname; - SELECT @var0 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[jobs].[job]') AND [c].[name] = N'Description'); - IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [jobs].[job] DROP CONSTRAINT [' + @var0 + '];'); - ALTER TABLE [jobs].[job] ALTER COLUMN [Description] nvarchar(3000) NOT NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104113247_JobsDescriptionLength') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20240104113247_JobsDescriptionLength', N'7.0.13'); -END; -GO - diff --git a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240104204923_AddIdentityTables.sql b/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240104204923_AddIdentityTables.sql deleted file mode 100644 index 66cef6260..000000000 --- a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240104204923_AddIdentityTables.sql +++ /dev/null @@ -1,277 +0,0 @@ -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - ALTER TABLE [Users].[Users] DROP CONSTRAINT [PK_Users]; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - DECLARE @var0 sysname; - SELECT @var0 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[Users].[Users]') AND [c].[name] = N'Login'); - IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [Users].[Users] DROP CONSTRAINT [' + @var0 + '];'); - ALTER TABLE [Users].[Users] DROP COLUMN [Login]; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - DECLARE @var1 sysname; - SELECT @var1 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[Users].[Users]') AND [c].[name] = N'Password'); - IF @var1 IS NOT NULL EXEC(N'ALTER TABLE [Users].[Users] DROP CONSTRAINT [' + @var1 + '];'); - ALTER TABLE [Users].[Users] DROP COLUMN [Password]; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - DECLARE @var2 sysname; - SELECT @var2 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[Users].[Users]') AND [c].[name] = N'Id'); - IF @var2 IS NOT NULL EXEC(N'ALTER TABLE [Users].[Users] DROP CONSTRAINT [' + @var2 + '];'); - ALTER TABLE [Users].[Users] DROP COLUMN [Id]; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - EXEC sp_rename N'[Users].[Users]', N'AspNetUsers'; - DECLARE @defaultSchema sysname = SCHEMA_NAME(); - EXEC(N'ALTER SCHEMA [' + @defaultSchema + N'] TRANSFER [Users].[AspNetUsers];'); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - EXEC sp_rename N'[AspNetUsers].[Role]', N'AccessFailedCount', N'COLUMN'; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - DECLARE @var3 sysname; - SELECT @var3 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[AspNetUsers]') AND [c].[name] = N'Email'); - IF @var3 IS NOT NULL EXEC(N'ALTER TABLE [AspNetUsers] DROP CONSTRAINT [' + @var3 + '];'); - ALTER TABLE [AspNetUsers] ALTER COLUMN [Email] nvarchar(256) NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - ALTER TABLE [AspNetUsers] ADD [Id] nvarchar(450) NOT NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - ALTER TABLE [AspNetUsers] ADD [ConcurrencyStamp] nvarchar(max) NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - ALTER TABLE [AspNetUsers] ADD [EmailConfirmed] bit NOT NULL DEFAULT CAST(0 AS bit); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - ALTER TABLE [AspNetUsers] ADD [LockoutEnabled] bit NOT NULL DEFAULT CAST(0 AS bit); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - ALTER TABLE [AspNetUsers] ADD [LockoutEnd] datetimeoffset NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - ALTER TABLE [AspNetUsers] ADD [NormalizedEmail] nvarchar(256) NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - ALTER TABLE [AspNetUsers] ADD [NormalizedUserName] nvarchar(256) NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - ALTER TABLE [AspNetUsers] ADD [PasswordHash] nvarchar(max) NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - ALTER TABLE [AspNetUsers] ADD [PhoneNumber] nvarchar(max) NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - ALTER TABLE [AspNetUsers] ADD [PhoneNumberConfirmed] bit NOT NULL DEFAULT CAST(0 AS bit); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - ALTER TABLE [AspNetUsers] ADD [SecurityStamp] nvarchar(max) NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - ALTER TABLE [AspNetUsers] ADD [TwoFactorEnabled] bit NOT NULL DEFAULT CAST(0 AS bit); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - ALTER TABLE [AspNetUsers] ADD [UserName] nvarchar(256) NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - ALTER TABLE [AspNetUsers] ADD CONSTRAINT [PK_AspNetUsers] PRIMARY KEY ([Id]); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - CREATE TABLE [AspNetRoles] ( - [Id] nvarchar(450) NOT NULL, - [Name] nvarchar(256) NULL, - [NormalizedName] nvarchar(256) NULL, - [ConcurrencyStamp] nvarchar(max) NULL, - CONSTRAINT [PK_AspNetRoles] PRIMARY KEY ([Id]) - ); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - CREATE TABLE [AspNetUserClaims] ( - [Id] int NOT NULL IDENTITY, - [UserId] nvarchar(450) NOT NULL, - [ClaimType] nvarchar(max) NULL, - [ClaimValue] nvarchar(max) NULL, - CONSTRAINT [PK_AspNetUserClaims] PRIMARY KEY ([Id]), - CONSTRAINT [FK_AspNetUserClaims_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE - ); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - CREATE TABLE [AspNetUserLogins] ( - [LoginProvider] nvarchar(450) NOT NULL, - [ProviderKey] nvarchar(450) NOT NULL, - [ProviderDisplayName] nvarchar(max) NULL, - [UserId] nvarchar(450) NOT NULL, - CONSTRAINT [PK_AspNetUserLogins] PRIMARY KEY ([LoginProvider], [ProviderKey]), - CONSTRAINT [FK_AspNetUserLogins_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE - ); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - CREATE TABLE [AspNetUserTokens] ( - [UserId] nvarchar(450) NOT NULL, - [LoginProvider] nvarchar(450) NOT NULL, - [Name] nvarchar(450) NOT NULL, - [Value] nvarchar(max) NULL, - CONSTRAINT [PK_AspNetUserTokens] PRIMARY KEY ([UserId], [LoginProvider], [Name]), - CONSTRAINT [FK_AspNetUserTokens_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE - ); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - CREATE TABLE [AspNetRoleClaims] ( - [Id] int NOT NULL IDENTITY, - [RoleId] nvarchar(450) NOT NULL, - [ClaimType] nvarchar(max) NULL, - [ClaimValue] nvarchar(max) NULL, - CONSTRAINT [PK_AspNetRoleClaims] PRIMARY KEY ([Id]), - CONSTRAINT [FK_AspNetRoleClaims_AspNetRoles_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [AspNetRoles] ([Id]) ON DELETE CASCADE - ); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - CREATE TABLE [AspNetUserRoles] ( - [UserId] nvarchar(450) NOT NULL, - [RoleId] nvarchar(450) NOT NULL, - CONSTRAINT [PK_AspNetUserRoles] PRIMARY KEY ([UserId], [RoleId]), - CONSTRAINT [FK_AspNetUserRoles_AspNetRoles_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [AspNetRoles] ([Id]) ON DELETE CASCADE, - CONSTRAINT [FK_AspNetUserRoles_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE - ); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - CREATE INDEX [EmailIndex] ON [AspNetUsers] ([NormalizedEmail]); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - EXEC(N'CREATE UNIQUE INDEX [UserNameIndex] ON [AspNetUsers] ([NormalizedUserName]) WHERE [NormalizedUserName] IS NOT NULL'); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - CREATE INDEX [IX_AspNetRoleClaims_RoleId] ON [AspNetRoleClaims] ([RoleId]); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - EXEC(N'CREATE UNIQUE INDEX [RoleNameIndex] ON [AspNetRoles] ([NormalizedName]) WHERE [NormalizedName] IS NOT NULL'); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - CREATE INDEX [IX_AspNetUserClaims_UserId] ON [AspNetUserClaims] ([UserId]); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - CREATE INDEX [IX_AspNetUserLogins_UserId] ON [AspNetUserLogins] ([UserId]); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - CREATE INDEX [IX_AspNetUserRoles_RoleId] ON [AspNetUserRoles] ([RoleId]); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20240104204923_AddIdentityTables', N'7.0.13'); -END; -GO - diff --git a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240122161255_ForFansLength.sql b/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240122161255_ForFansLength.sql deleted file mode 100644 index 782bd1faf..000000000 --- a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240122161255_ForFansLength.sql +++ /dev/null @@ -1,7 +0,0 @@ -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240122161255_ForFansLength') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20240122161255_ForFansLength', N'7.0.13'); -END; -GO - diff --git a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240407205620_AddRefreshTokenToUser.sql b/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240407205620_AddRefreshTokenToUser.sql deleted file mode 100644 index 95d6852b9..000000000 --- a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240407205620_AddRefreshTokenToUser.sql +++ /dev/null @@ -1,31 +0,0 @@ -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240407205620_AddRefreshTokenToUser') -BEGIN - DECLARE @var0 sysname; - SELECT @var0 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[jobs].[job]') AND [c].[name] = N'Description'); - IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [jobs].[job] DROP CONSTRAINT [' + @var0 + '];'); - ALTER TABLE [jobs].[job] ALTER COLUMN [Description] nvarchar(3000) NOT NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240407205620_AddRefreshTokenToUser') -BEGIN - ALTER TABLE [AspNetUsers] ADD [RefreshToken] nvarchar(max) NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240407205620_AddRefreshTokenToUser') -BEGIN - ALTER TABLE [AspNetUsers] ADD [RefreshTokenExpiry] datetime2 NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240407205620_AddRefreshTokenToUser') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20240407205620_AddRefreshTokenToUser', N'7.0.13'); -END; -GO - diff --git a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240417150303_AudioConstraintChange.sql b/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240417150303_AudioConstraintChange.sql deleted file mode 100644 index 0ea6cdf40..000000000 --- a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240417150303_AudioConstraintChange.sql +++ /dev/null @@ -1,19 +0,0 @@ -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240417150303_AudioConstraintChange') -BEGIN - ALTER TABLE [streetcode].[streetcodes] DROP CONSTRAINT [FK_streetcodes_audios_AudioId]; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240417150303_AudioConstraintChange') -BEGIN - ALTER TABLE [streetcode].[streetcodes] ADD CONSTRAINT [FK_streetcodes_audios_AudioId] FOREIGN KEY ([AudioId]) REFERENCES [media].[audios] ([Id]) ON DELETE SET NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240417150303_AudioConstraintChange') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20240417150303_AudioConstraintChange', N'7.0.13'); -END; -GO - diff --git a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240428073027_FactIndexAdd.sql b/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240428073027_FactIndexAdd.sql deleted file mode 100644 index 066cb9569..000000000 --- a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20240428073027_FactIndexAdd.sql +++ /dev/null @@ -1,13 +0,0 @@ -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240428073027_FactIndexAdd') -BEGIN - ALTER TABLE [streetcode].[facts] ADD [Index] int NOT NULL DEFAULT 0; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240428073027_FactIndexAdd') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20240428073027_FactIndexAdd', N'7.0.13'); -END; -GO - diff --git a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20250118172930_ChangeConstraints.sql b/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20250118172930_ChangeConstraints.sql deleted file mode 100644 index a78a63cbe..000000000 --- a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20250118172930_ChangeConstraints.sql +++ /dev/null @@ -1,111 +0,0 @@ -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') -BEGIN - ALTER TABLE [news].[news] DROP CONSTRAINT [FK_news_images_ImageId]; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') -BEGIN - DROP INDEX [IX_news_ImageId] ON [news].[news]; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') -BEGIN - DECLARE @var0 sysname; - SELECT @var0 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[sources].[source_link_categories]') AND [c].[name] = N'Title'); - IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [sources].[source_link_categories] DROP CONSTRAINT [' + @var0 + '];'); - ALTER TABLE [sources].[source_link_categories] ALTER COLUMN [Title] nvarchar(max) NOT NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') -BEGIN - DECLARE @var1 sysname; - SELECT @var1 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[news].[news]') AND [c].[name] = N'ImageId'); - IF @var1 IS NOT NULL EXEC(N'ALTER TABLE [news].[news] DROP CONSTRAINT [' + @var1 + '];'); - EXEC(N'UPDATE [news].[news] SET [ImageId] = 0 WHERE [ImageId] IS NULL'); - ALTER TABLE [news].[news] ALTER COLUMN [ImageId] int NOT NULL; - ALTER TABLE [news].[news] ADD DEFAULT 0 FOR [ImageId]; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') -BEGIN - DECLARE @var2 sysname; - SELECT @var2 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[jobs].[job]') AND [c].[name] = N'Description'); - IF @var2 IS NOT NULL EXEC(N'ALTER TABLE [jobs].[job] DROP CONSTRAINT [' + @var2 + '];'); - ALTER TABLE [jobs].[job] ALTER COLUMN [Description] nvarchar(3000) NOT NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') -BEGIN - CREATE UNIQUE INDEX [IX_news_ImageId] ON [news].[news] ([ImageId]); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') -BEGIN - ALTER TABLE [news].[news] ADD CONSTRAINT [FK_news_images_ImageId] FOREIGN KEY ([ImageId]) REFERENCES [media].[images] ([Id]) ON DELETE NO ACTION; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20240806144219_ImageConstaintChange', N'7.0.13'); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240905125058_MakeTeaserRequired') -BEGIN - DECLARE @var3 sysname; - SELECT @var3 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[streetcode].[streetcodes]') AND [c].[name] = N'Teaser'); - IF @var3 IS NOT NULL EXEC(N'ALTER TABLE [streetcode].[streetcodes] DROP CONSTRAINT [' + @var3 + '];'); - EXEC(N'UPDATE [streetcode].[streetcodes] SET [Teaser] = N'''' WHERE [Teaser] IS NULL'); - ALTER TABLE [streetcode].[streetcodes] ALTER COLUMN [Teaser] nvarchar(650) NOT NULL; - ALTER TABLE [streetcode].[streetcodes] ADD DEFAULT N'' FOR [Teaser]; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240905125058_MakeTeaserRequired') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20240905125058_MakeTeaserRequired', N'7.0.13'); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240906091812_AddConstraintsToNews') -BEGIN - DROP INDEX [IX_news_URL] ON [news].[news]; - DECLARE @var4 sysname; - SELECT @var4 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[news].[news]') AND [c].[name] = N'URL'); - IF @var4 IS NOT NULL EXEC(N'ALTER TABLE [news].[news] DROP CONSTRAINT [' + @var4 + '];'); - ALTER TABLE [news].[news] ALTER COLUMN [URL] nvarchar(200) NOT NULL; - CREATE UNIQUE INDEX [IX_news_URL] ON [news].[news] ([URL]); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240906091812_AddConstraintsToNews') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20240906091812_AddConstraintsToNews', N'7.0.13'); -END; -GO - diff --git a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20250124043754_UserUpdate.sql b/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20250124043754_UserUpdate.sql deleted file mode 100644 index f02fc46bb..000000000 --- a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/Script_20250124043754_UserUpdate.sql +++ /dev/null @@ -1,115 +0,0 @@ -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') -BEGIN - ALTER TABLE [news].[news] DROP CONSTRAINT [FK_news_images_ImageId]; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') -BEGIN - IF SCHEMA_ID(N'users') IS NULL EXEC(N'CREATE SCHEMA [users];'); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') -BEGIN - DECLARE @var0 sysname; - SELECT @var0 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[AspNetUsers]') AND [c].[name] = N'UserName'); - IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [AspNetUsers] DROP CONSTRAINT [' + @var0 + '];'); - EXEC(N'UPDATE [AspNetUsers] SET [UserName] = N'''' WHERE [UserName] IS NULL'); - ALTER TABLE [AspNetUsers] ALTER COLUMN [UserName] nvarchar(256) NOT NULL; - ALTER TABLE [AspNetUsers] ADD DEFAULT N'' FOR [UserName]; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') -BEGIN - DECLARE @var1 sysname; - SELECT @var1 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[AspNetUsers]') AND [c].[name] = N'Surname'); - IF @var1 IS NOT NULL EXEC(N'ALTER TABLE [AspNetUsers] DROP CONSTRAINT [' + @var1 + '];'); - ALTER TABLE [AspNetUsers] ALTER COLUMN [Surname] nvarchar(128) NOT NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') -BEGIN - DECLARE @var2 sysname; - SELECT @var2 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[AspNetUsers]') AND [c].[name] = N'Name'); - IF @var2 IS NOT NULL EXEC(N'ALTER TABLE [AspNetUsers] DROP CONSTRAINT [' + @var2 + '];'); - ALTER TABLE [AspNetUsers] ALTER COLUMN [Name] nvarchar(128) NOT NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') -BEGIN - ALTER TABLE [AspNetUsers] ADD [AboutYourself] nvarchar(500) NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') -BEGIN - ALTER TABLE [AspNetUsers] ADD [AvatarId] int NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') -BEGIN - CREATE TABLE [users].[expertise] ( - [Id] int NOT NULL IDENTITY, - [Title] nvarchar(50) NOT NULL, - CONSTRAINT [PK_expertise] PRIMARY KEY ([Id]) - ); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') -BEGIN - CREATE TABLE [users].[user_expertise] ( - [ExpertiseId] int NOT NULL, - [UserId] nvarchar(450) NOT NULL, - CONSTRAINT [PK_user_expertise] PRIMARY KEY ([ExpertiseId], [UserId]), - CONSTRAINT [FK_user_expertise_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE, - CONSTRAINT [FK_user_expertise_expertise_ExpertiseId] FOREIGN KEY ([ExpertiseId]) REFERENCES [users].[expertise] ([Id]) ON DELETE CASCADE - ); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') -BEGIN - EXEC(N'CREATE UNIQUE INDEX [IX_AspNetUsers_AvatarId] ON [AspNetUsers] ([AvatarId]) WHERE [AvatarId] IS NOT NULL'); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') -BEGIN - CREATE INDEX [IX_user_expertise_UserId] ON [users].[user_expertise] ([UserId]); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') -BEGIN - ALTER TABLE [AspNetUsers] ADD CONSTRAINT [FK_AspNetUsers_images_AvatarId] FOREIGN KEY ([AvatarId]) REFERENCES [media].[images] ([Id]) ON DELETE SET NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') -BEGIN - ALTER TABLE [news].[news] ADD CONSTRAINT [FK_news_images_ImageId] FOREIGN KEY ([ImageId]) REFERENCES [media].[images] ([Id]); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20250124043754_UserUpdate', N'7.0.13'); -END; -GO - diff --git a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/StreetcodeAuthor.sql b/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/StreetcodeAuthor.sql deleted file mode 100644 index 117e97b38..000000000 --- a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/StreetcodeAuthor.sql +++ /dev/null @@ -1,85 +0,0 @@ -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181308_StreetcodeUserRelationship') -BEGIN - ALTER TABLE [news].[news] DROP CONSTRAINT [FK_news_images_ImageId]; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181308_StreetcodeUserRelationship') -BEGIN - ALTER TABLE [streetcode].[streetcodes] ADD [UserId] nvarchar(450) NULL; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181308_StreetcodeUserRelationship') -BEGIN - CREATE INDEX [IX_streetcodes_UserId] ON [streetcode].[streetcodes] ([UserId]); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181308_StreetcodeUserRelationship') -BEGIN - ALTER TABLE [news].[news] ADD CONSTRAINT [FK_news_images_ImageId] FOREIGN KEY ([ImageId]) REFERENCES [media].[images] ([Id]); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181308_StreetcodeUserRelationship') -BEGIN - ALTER TABLE [streetcode].[streetcodes] ADD CONSTRAINT [FK_streetcodes_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181308_StreetcodeUserRelationship') -BEGIN - - DECLARE @FirstUserId NVARCHAR(450); - SELECT TOP 1 @FirstUserId = Id FROM [dbo].[AspNetUsers]; - - UPDATE [streetcode].[streetcodes] - SET [UserId] = @FirstUserId - WHERE [UserId] IS NULL; - -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181308_StreetcodeUserRelationship') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20250119181308_StreetcodeUserRelationship', N'7.0.13'); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181832_RemoveNullability') -BEGIN - ALTER TABLE [streetcode].[streetcodes] DROP CONSTRAINT [FK_streetcodes_AspNetUsers_UserId]; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181832_RemoveNullability') -BEGIN - DROP INDEX [IX_streetcodes_UserId] ON [streetcode].[streetcodes]; - DECLARE @var0 sysname; - SELECT @var0 = [d].[name] - FROM [sys].[default_constraints] [d] - INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] - WHERE ([d].[parent_object_id] = OBJECT_ID(N'[streetcode].[streetcodes]') AND [c].[name] = N'UserId'); - IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [streetcode].[streetcodes] DROP CONSTRAINT [' + @var0 + '];'); - EXEC(N'UPDATE [streetcode].[streetcodes] SET [UserId] = N'''' WHERE [UserId] IS NULL'); - ALTER TABLE [streetcode].[streetcodes] ALTER COLUMN [UserId] nvarchar(450) NOT NULL; - ALTER TABLE [streetcode].[streetcodes] ADD DEFAULT N'' FOR [UserId]; - CREATE INDEX [IX_streetcodes_UserId] ON [streetcode].[streetcodes] ([UserId]); -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181832_RemoveNullability') -BEGIN - ALTER TABLE [streetcode].[streetcodes] ADD CONSTRAINT [FK_streetcodes_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE; -END; -GO - -IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181832_RemoveNullability') -BEGIN - INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) - VALUES (N'20250119181832_RemoveNullability', N'7.0.13'); -END; -GO - diff --git a/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/UpdateUserNameFieldsLenght.sql b/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/UpdateUserNameFieldsLenght.sql new file mode 100644 index 000000000..53a984ec1 --- /dev/null +++ b/Streetcode/Streetcode.DAL/Persistence/ScriptsMigration/UpdateUserNameFieldsLenght.sql @@ -0,0 +1,974 @@ +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230703154732_UpdatePartnerModel') +BEGIN + DECLARE @var0 sysname; + SELECT @var0 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[partners].[partner_source_links]') AND [c].[name] = N'Title'); + IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [partners].[partner_source_links] DROP CONSTRAINT [' + @var0 + '];'); + ALTER TABLE [partners].[partner_source_links] DROP COLUMN [Title]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230703154732_UpdatePartnerModel') +BEGIN + DECLARE @var1 sysname; + SELECT @var1 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[partners].[partners]') AND [c].[name] = N'TargetUrl'); + IF @var1 IS NOT NULL EXEC(N'ALTER TABLE [partners].[partners] DROP CONSTRAINT [' + @var1 + '];'); + ALTER TABLE [partners].[partners] ALTER COLUMN [TargetUrl] nvarchar(255) NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230703154732_UpdatePartnerModel') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20230703154732_UpdatePartnerModel', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230804120930_Change_StreetcodeCategoryContent_Text_to_10000_simb') +BEGIN + DECLARE @var2 sysname; + SELECT @var2 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[sources].[streetcode_source_link_categories]') AND [c].[name] = N'Text'); + IF @var2 IS NOT NULL EXEC(N'ALTER TABLE [sources].[streetcode_source_link_categories] DROP CONSTRAINT [' + @var2 + '];'); + ALTER TABLE [sources].[streetcode_source_link_categories] ALTER COLUMN [Text] nvarchar(max) NOT NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230804120930_Change_StreetcodeCategoryContent_Text_to_10000_simb') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20230804120930_Change_StreetcodeCategoryContent_Text_to_10000_simb', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230905201616_Jobs') +BEGIN + DECLARE @var3 sysname; + SELECT @var3 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[team].[team_members]') AND [c].[name] = N'LastName'); + IF @var3 IS NOT NULL EXEC(N'ALTER TABLE [team].[team_members] DROP CONSTRAINT [' + @var3 + '];'); + ALTER TABLE [team].[team_members] DROP COLUMN [LastName]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230905201616_Jobs') +BEGIN + IF SCHEMA_ID(N'jobs') IS NULL EXEC(N'CREATE SCHEMA [jobs];'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230905201616_Jobs') +BEGIN + EXEC sp_rename N'[team].[team_members].[FirstName]', N'Name', N'COLUMN'; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230905201616_Jobs') +BEGIN + CREATE TABLE [jobs].[job] ( + [Id] int NOT NULL IDENTITY, + [Title] nvarchar(65) NOT NULL, + [Status] bit NOT NULL, + [Description] nvarchar(2000) NOT NULL, + [Salary] nvarchar(15) NOT NULL, + CONSTRAINT [PK_job] PRIMARY KEY ([Id]) + ); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20230905201616_Jobs') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20230905201616_Jobs', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + ALTER TABLE [streetcode].[streetcode_art] DROP CONSTRAINT [FK_streetcode_art_arts_ArtId]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + ALTER TABLE [streetcode].[streetcode_art] DROP CONSTRAINT [FK_streetcode_art_streetcodes_StreetcodeId]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + ALTER TABLE [streetcode].[streetcode_art] DROP CONSTRAINT [PK_streetcode_art]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + DROP INDEX [IX_streetcode_art_ArtId_StreetcodeId] ON [streetcode].[streetcode_art]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + DECLARE @var4 sysname; + SELECT @var4 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[streetcode].[streetcode_art]') AND [c].[name] = N'StreetcodeId'); + IF @var4 IS NOT NULL EXEC(N'ALTER TABLE [streetcode].[streetcode_art] DROP CONSTRAINT [' + @var4 + '];'); + ALTER TABLE [streetcode].[streetcode_art] ALTER COLUMN [StreetcodeId] int NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + ALTER TABLE [streetcode].[streetcode_art] ADD [Id] int NOT NULL IDENTITY; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + ALTER TABLE [streetcode].[streetcode_art] ADD [StreetcodeArtSlideId] int NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + ALTER TABLE [media].[arts] ADD [StreetcodeId] int NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + ALTER TABLE [streetcode].[streetcode_art] ADD CONSTRAINT [PK_streetcode_art] PRIMARY KEY ([Id]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + CREATE TABLE [streetcode].[streetcode_art_slide] ( + [Id] int NOT NULL IDENTITY, + [StreetcodeId] int NOT NULL, + [Template] int NOT NULL, + [Index] int NOT NULL DEFAULT 1, + CONSTRAINT [PK_streetcode_art_slide] PRIMARY KEY ([Id]), + CONSTRAINT [FK_streetcode_art_slide_streetcodes_StreetcodeId] FOREIGN KEY ([StreetcodeId]) REFERENCES [streetcode].[streetcodes] ([Id]) ON DELETE CASCADE + ); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + CREATE INDEX [IX_streetcode_art_ArtId_StreetcodeArtSlideId] ON [streetcode].[streetcode_art] ([ArtId], [StreetcodeArtSlideId]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + CREATE INDEX [IX_streetcode_art_StreetcodeArtSlideId] ON [streetcode].[streetcode_art] ([StreetcodeArtSlideId]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + CREATE INDEX [IX_arts_StreetcodeId] ON [media].[arts] ([StreetcodeId]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + CREATE INDEX [IX_streetcode_art_slide_StreetcodeId] ON [streetcode].[streetcode_art_slide] ([StreetcodeId]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + ALTER TABLE [media].[arts] ADD CONSTRAINT [FK_arts_streetcodes_StreetcodeId] FOREIGN KEY ([StreetcodeId]) REFERENCES [streetcode].[streetcodes] ([Id]) ON DELETE CASCADE; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + ALTER TABLE [streetcode].[streetcode_art] ADD CONSTRAINT [FK_streetcode_art_arts_ArtId] FOREIGN KEY ([ArtId]) REFERENCES [media].[arts] ([Id]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + ALTER TABLE [streetcode].[streetcode_art] ADD CONSTRAINT [FK_streetcode_art_streetcode_art_slide_StreetcodeArtSlideId] FOREIGN KEY ([StreetcodeArtSlideId]) REFERENCES [streetcode].[streetcode_art_slide] ([Id]) ON DELETE CASCADE; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + ALTER TABLE [streetcode].[streetcode_art] ADD CONSTRAINT [FK_streetcode_art_streetcodes_StreetcodeId] FOREIGN KEY ([StreetcodeId]) REFERENCES [streetcode].[streetcodes] ([Id]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231108151054_RefactorStreetcodeArts') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20231108151054_RefactorStreetcodeArts', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231130202258_DatestringLength') +BEGIN + DECLARE @var5 sysname; + SELECT @var5 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[streetcode].[streetcodes]') AND [c].[name] = N'DateString'); + IF @var5 IS NOT NULL EXEC(N'ALTER TABLE [streetcode].[streetcodes] DROP CONSTRAINT [' + @var5 + '];'); + ALTER TABLE [streetcode].[streetcodes] ALTER COLUMN [DateString] nvarchar(100) NOT NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20231130202258_DatestringLength') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20231130202258_DatestringLength', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104113247_JobsDescriptionLength') +BEGIN + DECLARE @var6 sysname; + SELECT @var6 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[jobs].[job]') AND [c].[name] = N'Description'); + IF @var6 IS NOT NULL EXEC(N'ALTER TABLE [jobs].[job] DROP CONSTRAINT [' + @var6 + '];'); + ALTER TABLE [jobs].[job] ALTER COLUMN [Description] nvarchar(3000) NOT NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104113247_JobsDescriptionLength') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20240104113247_JobsDescriptionLength', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + ALTER TABLE [Users].[Users] DROP CONSTRAINT [PK_Users]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + DECLARE @var7 sysname; + SELECT @var7 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[Users].[Users]') AND [c].[name] = N'Login'); + IF @var7 IS NOT NULL EXEC(N'ALTER TABLE [Users].[Users] DROP CONSTRAINT [' + @var7 + '];'); + ALTER TABLE [Users].[Users] DROP COLUMN [Login]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + DECLARE @var8 sysname; + SELECT @var8 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[Users].[Users]') AND [c].[name] = N'Password'); + IF @var8 IS NOT NULL EXEC(N'ALTER TABLE [Users].[Users] DROP CONSTRAINT [' + @var8 + '];'); + ALTER TABLE [Users].[Users] DROP COLUMN [Password]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + DECLARE @var9 sysname; + SELECT @var9 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[Users].[Users]') AND [c].[name] = N'Id'); + IF @var9 IS NOT NULL EXEC(N'ALTER TABLE [Users].[Users] DROP CONSTRAINT [' + @var9 + '];'); + ALTER TABLE [Users].[Users] DROP COLUMN [Id]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + EXEC sp_rename N'[Users].[Users]', N'AspNetUsers'; + DECLARE @defaultSchema sysname = SCHEMA_NAME(); + EXEC(N'ALTER SCHEMA [' + @defaultSchema + N'] TRANSFER [Users].[AspNetUsers];'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + EXEC sp_rename N'[AspNetUsers].[Role]', N'AccessFailedCount', N'COLUMN'; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + DECLARE @var10 sysname; + SELECT @var10 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[AspNetUsers]') AND [c].[name] = N'Email'); + IF @var10 IS NOT NULL EXEC(N'ALTER TABLE [AspNetUsers] DROP CONSTRAINT [' + @var10 + '];'); + ALTER TABLE [AspNetUsers] ALTER COLUMN [Email] nvarchar(256) NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + ALTER TABLE [AspNetUsers] ADD [Id] nvarchar(450) NOT NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + ALTER TABLE [AspNetUsers] ADD [ConcurrencyStamp] nvarchar(max) NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + ALTER TABLE [AspNetUsers] ADD [EmailConfirmed] bit NOT NULL DEFAULT CAST(0 AS bit); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + ALTER TABLE [AspNetUsers] ADD [LockoutEnabled] bit NOT NULL DEFAULT CAST(0 AS bit); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + ALTER TABLE [AspNetUsers] ADD [LockoutEnd] datetimeoffset NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + ALTER TABLE [AspNetUsers] ADD [NormalizedEmail] nvarchar(256) NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + ALTER TABLE [AspNetUsers] ADD [NormalizedUserName] nvarchar(256) NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + ALTER TABLE [AspNetUsers] ADD [PasswordHash] nvarchar(max) NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + ALTER TABLE [AspNetUsers] ADD [PhoneNumber] nvarchar(max) NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + ALTER TABLE [AspNetUsers] ADD [PhoneNumberConfirmed] bit NOT NULL DEFAULT CAST(0 AS bit); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + ALTER TABLE [AspNetUsers] ADD [SecurityStamp] nvarchar(max) NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + ALTER TABLE [AspNetUsers] ADD [TwoFactorEnabled] bit NOT NULL DEFAULT CAST(0 AS bit); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + ALTER TABLE [AspNetUsers] ADD [UserName] nvarchar(256) NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + ALTER TABLE [AspNetUsers] ADD CONSTRAINT [PK_AspNetUsers] PRIMARY KEY ([Id]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + CREATE TABLE [AspNetRoles] ( + [Id] nvarchar(450) NOT NULL, + [Name] nvarchar(256) NULL, + [NormalizedName] nvarchar(256) NULL, + [ConcurrencyStamp] nvarchar(max) NULL, + CONSTRAINT [PK_AspNetRoles] PRIMARY KEY ([Id]) + ); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + CREATE TABLE [AspNetUserClaims] ( + [Id] int NOT NULL IDENTITY, + [UserId] nvarchar(450) NOT NULL, + [ClaimType] nvarchar(max) NULL, + [ClaimValue] nvarchar(max) NULL, + CONSTRAINT [PK_AspNetUserClaims] PRIMARY KEY ([Id]), + CONSTRAINT [FK_AspNetUserClaims_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE + ); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + CREATE TABLE [AspNetUserLogins] ( + [LoginProvider] nvarchar(450) NOT NULL, + [ProviderKey] nvarchar(450) NOT NULL, + [ProviderDisplayName] nvarchar(max) NULL, + [UserId] nvarchar(450) NOT NULL, + CONSTRAINT [PK_AspNetUserLogins] PRIMARY KEY ([LoginProvider], [ProviderKey]), + CONSTRAINT [FK_AspNetUserLogins_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE + ); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + CREATE TABLE [AspNetUserTokens] ( + [UserId] nvarchar(450) NOT NULL, + [LoginProvider] nvarchar(450) NOT NULL, + [Name] nvarchar(450) NOT NULL, + [Value] nvarchar(max) NULL, + CONSTRAINT [PK_AspNetUserTokens] PRIMARY KEY ([UserId], [LoginProvider], [Name]), + CONSTRAINT [FK_AspNetUserTokens_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE + ); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + CREATE TABLE [AspNetRoleClaims] ( + [Id] int NOT NULL IDENTITY, + [RoleId] nvarchar(450) NOT NULL, + [ClaimType] nvarchar(max) NULL, + [ClaimValue] nvarchar(max) NULL, + CONSTRAINT [PK_AspNetRoleClaims] PRIMARY KEY ([Id]), + CONSTRAINT [FK_AspNetRoleClaims_AspNetRoles_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [AspNetRoles] ([Id]) ON DELETE CASCADE + ); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + CREATE TABLE [AspNetUserRoles] ( + [UserId] nvarchar(450) NOT NULL, + [RoleId] nvarchar(450) NOT NULL, + CONSTRAINT [PK_AspNetUserRoles] PRIMARY KEY ([UserId], [RoleId]), + CONSTRAINT [FK_AspNetUserRoles_AspNetRoles_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [AspNetRoles] ([Id]) ON DELETE CASCADE, + CONSTRAINT [FK_AspNetUserRoles_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE + ); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + CREATE INDEX [EmailIndex] ON [AspNetUsers] ([NormalizedEmail]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + EXEC(N'CREATE UNIQUE INDEX [UserNameIndex] ON [AspNetUsers] ([NormalizedUserName]) WHERE [NormalizedUserName] IS NOT NULL'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + CREATE INDEX [IX_AspNetRoleClaims_RoleId] ON [AspNetRoleClaims] ([RoleId]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + EXEC(N'CREATE UNIQUE INDEX [RoleNameIndex] ON [AspNetRoles] ([NormalizedName]) WHERE [NormalizedName] IS NOT NULL'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + CREATE INDEX [IX_AspNetUserClaims_UserId] ON [AspNetUserClaims] ([UserId]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + CREATE INDEX [IX_AspNetUserLogins_UserId] ON [AspNetUserLogins] ([UserId]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + CREATE INDEX [IX_AspNetUserRoles_RoleId] ON [AspNetUserRoles] ([RoleId]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240104204923_AddIdentityTables') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20240104204923_AddIdentityTables', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240122161255_ForFansLength') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20240122161255_ForFansLength', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240407205620_AddRefreshTokenToUser') +BEGIN + DECLARE @var11 sysname; + SELECT @var11 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[jobs].[job]') AND [c].[name] = N'Description'); + IF @var11 IS NOT NULL EXEC(N'ALTER TABLE [jobs].[job] DROP CONSTRAINT [' + @var11 + '];'); + ALTER TABLE [jobs].[job] ALTER COLUMN [Description] nvarchar(3000) NOT NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240407205620_AddRefreshTokenToUser') +BEGIN + ALTER TABLE [AspNetUsers] ADD [RefreshToken] nvarchar(max) NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240407205620_AddRefreshTokenToUser') +BEGIN + ALTER TABLE [AspNetUsers] ADD [RefreshTokenExpiry] datetime2 NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240407205620_AddRefreshTokenToUser') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20240407205620_AddRefreshTokenToUser', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240417150303_AudioConstraintChange') +BEGIN + ALTER TABLE [streetcode].[streetcodes] DROP CONSTRAINT [FK_streetcodes_audios_AudioId]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240417150303_AudioConstraintChange') +BEGIN + ALTER TABLE [streetcode].[streetcodes] ADD CONSTRAINT [FK_streetcodes_audios_AudioId] FOREIGN KEY ([AudioId]) REFERENCES [media].[audios] ([Id]) ON DELETE SET NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240417150303_AudioConstraintChange') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20240417150303_AudioConstraintChange', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240428073027_FactIndexAdd') +BEGIN + ALTER TABLE [streetcode].[facts] ADD [Index] int NOT NULL DEFAULT 0; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240428073027_FactIndexAdd') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20240428073027_FactIndexAdd', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') +BEGIN + ALTER TABLE [news].[news] DROP CONSTRAINT [FK_news_images_ImageId]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') +BEGIN + DROP INDEX [IX_news_ImageId] ON [news].[news]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') +BEGIN + DECLARE @var12 sysname; + SELECT @var12 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[sources].[source_link_categories]') AND [c].[name] = N'Title'); + IF @var12 IS NOT NULL EXEC(N'ALTER TABLE [sources].[source_link_categories] DROP CONSTRAINT [' + @var12 + '];'); + ALTER TABLE [sources].[source_link_categories] ALTER COLUMN [Title] nvarchar(max) NOT NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') +BEGIN + DECLARE @var13 sysname; + SELECT @var13 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[news].[news]') AND [c].[name] = N'ImageId'); + IF @var13 IS NOT NULL EXEC(N'ALTER TABLE [news].[news] DROP CONSTRAINT [' + @var13 + '];'); + EXEC(N'UPDATE [news].[news] SET [ImageId] = 0 WHERE [ImageId] IS NULL'); + ALTER TABLE [news].[news] ALTER COLUMN [ImageId] int NOT NULL; + ALTER TABLE [news].[news] ADD DEFAULT 0 FOR [ImageId]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') +BEGIN + DECLARE @var14 sysname; + SELECT @var14 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[jobs].[job]') AND [c].[name] = N'Description'); + IF @var14 IS NOT NULL EXEC(N'ALTER TABLE [jobs].[job] DROP CONSTRAINT [' + @var14 + '];'); + ALTER TABLE [jobs].[job] ALTER COLUMN [Description] nvarchar(3000) NOT NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') +BEGIN + CREATE UNIQUE INDEX [IX_news_ImageId] ON [news].[news] ([ImageId]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') +BEGIN + ALTER TABLE [news].[news] ADD CONSTRAINT [FK_news_images_ImageId] FOREIGN KEY ([ImageId]) REFERENCES [media].[images] ([Id]) ON DELETE NO ACTION; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240806144219_ImageConstaintChange') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20240806144219_ImageConstaintChange', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240905125058_MakeTeaserRequired') +BEGIN + DECLARE @var15 sysname; + SELECT @var15 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[streetcode].[streetcodes]') AND [c].[name] = N'Teaser'); + IF @var15 IS NOT NULL EXEC(N'ALTER TABLE [streetcode].[streetcodes] DROP CONSTRAINT [' + @var15 + '];'); + EXEC(N'UPDATE [streetcode].[streetcodes] SET [Teaser] = N'''' WHERE [Teaser] IS NULL'); + ALTER TABLE [streetcode].[streetcodes] ALTER COLUMN [Teaser] nvarchar(650) NOT NULL; + ALTER TABLE [streetcode].[streetcodes] ADD DEFAULT N'' FOR [Teaser]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240905125058_MakeTeaserRequired') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20240905125058_MakeTeaserRequired', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240906091812_AddConstraintsToNews') +BEGIN + DROP INDEX [IX_news_URL] ON [news].[news]; + DECLARE @var16 sysname; + SELECT @var16 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[news].[news]') AND [c].[name] = N'URL'); + IF @var16 IS NOT NULL EXEC(N'ALTER TABLE [news].[news] DROP CONSTRAINT [' + @var16 + '];'); + ALTER TABLE [news].[news] ALTER COLUMN [URL] nvarchar(200) NOT NULL; + CREATE UNIQUE INDEX [IX_news_URL] ON [news].[news] ([URL]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20240906091812_AddConstraintsToNews') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20240906091812_AddConstraintsToNews', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181308_StreetcodeUserRelationship') +BEGIN + ALTER TABLE [news].[news] DROP CONSTRAINT [FK_news_images_ImageId]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181308_StreetcodeUserRelationship') +BEGIN + ALTER TABLE [streetcode].[streetcodes] ADD [UserId] nvarchar(450) NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181308_StreetcodeUserRelationship') +BEGIN + CREATE INDEX [IX_streetcodes_UserId] ON [streetcode].[streetcodes] ([UserId]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181308_StreetcodeUserRelationship') +BEGIN + ALTER TABLE [news].[news] ADD CONSTRAINT [FK_news_images_ImageId] FOREIGN KEY ([ImageId]) REFERENCES [media].[images] ([Id]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181308_StreetcodeUserRelationship') +BEGIN + ALTER TABLE [streetcode].[streetcodes] ADD CONSTRAINT [FK_streetcodes_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181308_StreetcodeUserRelationship') +BEGIN + + DECLARE @FirstUserId NVARCHAR(450); + SELECT TOP 1 @FirstUserId = Id FROM [dbo].[AspNetUsers]; + + UPDATE [streetcode].[streetcodes] + SET [UserId] = @FirstUserId + WHERE [UserId] IS NULL; + +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181308_StreetcodeUserRelationship') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20250119181308_StreetcodeUserRelationship', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181832_RemoveNullability') +BEGIN + ALTER TABLE [streetcode].[streetcodes] DROP CONSTRAINT [FK_streetcodes_AspNetUsers_UserId]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181832_RemoveNullability') +BEGIN + DROP INDEX [IX_streetcodes_UserId] ON [streetcode].[streetcodes]; + DECLARE @var17 sysname; + SELECT @var17 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[streetcode].[streetcodes]') AND [c].[name] = N'UserId'); + IF @var17 IS NOT NULL EXEC(N'ALTER TABLE [streetcode].[streetcodes] DROP CONSTRAINT [' + @var17 + '];'); + EXEC(N'UPDATE [streetcode].[streetcodes] SET [UserId] = N'''' WHERE [UserId] IS NULL'); + ALTER TABLE [streetcode].[streetcodes] ALTER COLUMN [UserId] nvarchar(450) NOT NULL; + ALTER TABLE [streetcode].[streetcodes] ADD DEFAULT N'' FOR [UserId]; + CREATE INDEX [IX_streetcodes_UserId] ON [streetcode].[streetcodes] ([UserId]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181832_RemoveNullability') +BEGIN + ALTER TABLE [streetcode].[streetcodes] ADD CONSTRAINT [FK_streetcodes_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250119181832_RemoveNullability') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20250119181832_RemoveNullability', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') +BEGIN + ALTER TABLE [news].[news] DROP CONSTRAINT [FK_news_images_ImageId]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') +BEGIN + IF SCHEMA_ID(N'users') IS NULL EXEC(N'CREATE SCHEMA [users];'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') +BEGIN + DECLARE @var18 sysname; + SELECT @var18 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[AspNetUsers]') AND [c].[name] = N'UserName'); + IF @var18 IS NOT NULL EXEC(N'ALTER TABLE [AspNetUsers] DROP CONSTRAINT [' + @var18 + '];'); + EXEC(N'UPDATE [AspNetUsers] SET [UserName] = N'''' WHERE [UserName] IS NULL'); + ALTER TABLE [AspNetUsers] ALTER COLUMN [UserName] nvarchar(256) NOT NULL; + ALTER TABLE [AspNetUsers] ADD DEFAULT N'' FOR [UserName]; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') +BEGIN + DECLARE @var19 sysname; + SELECT @var19 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[AspNetUsers]') AND [c].[name] = N'Surname'); + IF @var19 IS NOT NULL EXEC(N'ALTER TABLE [AspNetUsers] DROP CONSTRAINT [' + @var19 + '];'); + ALTER TABLE [AspNetUsers] ALTER COLUMN [Surname] nvarchar(128) NOT NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') +BEGIN + DECLARE @var20 sysname; + SELECT @var20 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[AspNetUsers]') AND [c].[name] = N'Name'); + IF @var20 IS NOT NULL EXEC(N'ALTER TABLE [AspNetUsers] DROP CONSTRAINT [' + @var20 + '];'); + ALTER TABLE [AspNetUsers] ALTER COLUMN [Name] nvarchar(128) NOT NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') +BEGIN + ALTER TABLE [AspNetUsers] ADD [AboutYourself] nvarchar(500) NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') +BEGIN + ALTER TABLE [AspNetUsers] ADD [AvatarId] int NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') +BEGIN + CREATE TABLE [users].[expertise] ( + [Id] int NOT NULL IDENTITY, + [Title] nvarchar(50) NOT NULL, + CONSTRAINT [PK_expertise] PRIMARY KEY ([Id]) + ); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') +BEGIN + CREATE TABLE [users].[user_expertise] ( + [ExpertiseId] int NOT NULL, + [UserId] nvarchar(450) NOT NULL, + CONSTRAINT [PK_user_expertise] PRIMARY KEY ([ExpertiseId], [UserId]), + CONSTRAINT [FK_user_expertise_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE, + CONSTRAINT [FK_user_expertise_expertise_ExpertiseId] FOREIGN KEY ([ExpertiseId]) REFERENCES [users].[expertise] ([Id]) ON DELETE CASCADE + ); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') +BEGIN + EXEC(N'CREATE UNIQUE INDEX [IX_AspNetUsers_AvatarId] ON [AspNetUsers] ([AvatarId]) WHERE [AvatarId] IS NOT NULL'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') +BEGIN + CREATE INDEX [IX_user_expertise_UserId] ON [users].[user_expertise] ([UserId]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') +BEGIN + ALTER TABLE [AspNetUsers] ADD CONSTRAINT [FK_AspNetUsers_images_AvatarId] FOREIGN KEY ([AvatarId]) REFERENCES [media].[images] ([Id]) ON DELETE SET NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') +BEGIN + ALTER TABLE [news].[news] ADD CONSTRAINT [FK_news_images_ImageId] FOREIGN KEY ([ImageId]) REFERENCES [media].[images] ([Id]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250124043754_UserUpdate') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20250124043754_UserUpdate', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250204150151_AddFavourites') +BEGIN + CREATE TABLE [streetcode].[favourites] ( + [StreetcodeId] int NOT NULL, + [UserId] nvarchar(450) NOT NULL, + CONSTRAINT [PK_favourites] PRIMARY KEY ([StreetcodeId], [UserId]), + CONSTRAINT [FK_favourites_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [AspNetUsers] ([Id]) ON DELETE CASCADE, + CONSTRAINT [FK_favourites_streetcodes_StreetcodeId] FOREIGN KEY ([StreetcodeId]) REFERENCES [streetcode].[streetcodes] ([Id]) + ); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250204150151_AddFavourites') +BEGIN + CREATE INDEX [IX_favourites_UserId] ON [streetcode].[favourites] ([UserId]); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250204150151_AddFavourites') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20250204150151_AddFavourites', N'7.0.13'); +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250217205949_UpdateUserNameFieldsLenght') +BEGIN + DECLARE @var21 sysname; + SELECT @var21 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[AspNetUsers]') AND [c].[name] = N'Surname'); + IF @var21 IS NOT NULL EXEC(N'ALTER TABLE [AspNetUsers] DROP CONSTRAINT [' + @var21 + '];'); + ALTER TABLE [AspNetUsers] ALTER COLUMN [Surname] nvarchar(50) NOT NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250217205949_UpdateUserNameFieldsLenght') +BEGIN + DECLARE @var22 sysname; + SELECT @var22 = [d].[name] + FROM [sys].[default_constraints] [d] + INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] + WHERE ([d].[parent_object_id] = OBJECT_ID(N'[AspNetUsers]') AND [c].[name] = N'Name'); + IF @var22 IS NOT NULL EXEC(N'ALTER TABLE [AspNetUsers] DROP CONSTRAINT [' + @var22 + '];'); + ALTER TABLE [AspNetUsers] ALTER COLUMN [Name] nvarchar(50) NOT NULL; +END; +GO + +IF NOT EXISTS(SELECT * FROM [entity_framework].[__EFMigrationsHistory] WHERE [MigrationId] = N'20250217205949_UpdateUserNameFieldsLenght') +BEGIN + INSERT INTO [entity_framework].[__EFMigrationsHistory] ([MigrationId], [ProductVersion]) + VALUES (N'20250217205949_UpdateUserNameFieldsLenght', N'7.0.13'); +END; +GO + diff --git a/Streetcode/Streetcode.DAL/Repositories/Interfaces/Base/IRepositoryWrapper.cs b/Streetcode/Streetcode.DAL/Repositories/Interfaces/Base/IRepositoryWrapper.cs index a68eb2cf5..5646defbc 100644 --- a/Streetcode/Streetcode.DAL/Repositories/Interfaces/Base/IRepositoryWrapper.cs +++ b/Streetcode/Streetcode.DAL/Repositories/Interfaces/Base/IRepositoryWrapper.cs @@ -8,6 +8,7 @@ using Streetcode.DAL.Repositories.Interfaces.Partners; using Streetcode.DAL.Repositories.Interfaces.Source; using Streetcode.DAL.Repositories.Interfaces.Streetcode; +using Streetcode.DAL.Repositories.Interfaces.Streetcode.Favourites; using Streetcode.DAL.Repositories.Interfaces.Streetcode.TextContent; using Streetcode.DAL.Repositories.Interfaces.Team; using Streetcode.DAL.Repositories.Interfaces.Timeline; @@ -15,7 +16,6 @@ using Streetcode.DAL.Repositories.Interfaces.Transactions; using Streetcode.DAL.Repositories.Interfaces.Users; using Streetcode.DAL.Repositories.Interfaces.Users.Expertise; - namespace Streetcode.DAL.Repositories.Interfaces.Base; public interface IRepositoryWrapper @@ -50,13 +50,14 @@ public interface IRepositoryWrapper IPartnerSourceLinkRepository PartnerSourceLinkRepository { get; } IUserRepository UserRepository { get; } IStreetcodeTagIndexRepository StreetcodeTagIndexRepository { get; } - IPartnerStreetcodeRepository PartnerStreetcodeRepository { get; } + IPartnerStreetcodeRepository PartnerStreetcodeRepository { get; } INewsRepository NewsRepository { get; } IPositionRepository PositionRepository { get; } IHistoricalContextTimelineRepository HistoricalContextTimelineRepository { get; } IStreetcodeToponymRepository StreetcodeToponymRepository { get; } IStreetcodeImageRepository StreetcodeImageRepository { get; } IJobRepository JobRepository { get; } + IFavouritesRepository FavouritesRepository { get; } IExpertiseRepository ExpertiseRepository { get; } IUserExpertiseRepository UserExpertiseRepository { get; } public int SaveChanges(); diff --git a/Streetcode/Streetcode.DAL/Repositories/Interfaces/Streetcode/Favourites/IFavouritesRepository.cs b/Streetcode/Streetcode.DAL/Repositories/Interfaces/Streetcode/Favourites/IFavouritesRepository.cs new file mode 100644 index 000000000..6f066e908 --- /dev/null +++ b/Streetcode/Streetcode.DAL/Repositories/Interfaces/Streetcode/Favourites/IFavouritesRepository.cs @@ -0,0 +1,9 @@ +using Streetcode.DAL.Repositories.Interfaces.Base; +using FavouriteStreetcodes = Streetcode.DAL.Entities.Streetcode.Favourites.Favourite; + +namespace Streetcode.DAL.Repositories.Interfaces.Streetcode.Favourites +{ + public interface IFavouritesRepository : IRepositoryBase + { + } +} diff --git a/Streetcode/Streetcode.DAL/Repositories/Realizations/Base/RepositoryWrapper.cs b/Streetcode/Streetcode.DAL/Repositories/Realizations/Base/RepositoryWrapper.cs index 3cb815a11..c79db00ac 100644 --- a/Streetcode/Streetcode.DAL/Repositories/Realizations/Base/RepositoryWrapper.cs +++ b/Streetcode/Streetcode.DAL/Repositories/Realizations/Base/RepositoryWrapper.cs @@ -10,6 +10,7 @@ using Streetcode.DAL.Repositories.Interfaces.Partners; using Streetcode.DAL.Repositories.Interfaces.Source; using Streetcode.DAL.Repositories.Interfaces.Streetcode; +using Streetcode.DAL.Repositories.Interfaces.Streetcode.Favourites; using Streetcode.DAL.Repositories.Interfaces.Streetcode.TextContent; using Streetcode.DAL.Repositories.Interfaces.Team; using Streetcode.DAL.Repositories.Interfaces.Timeline; @@ -114,7 +115,10 @@ public class RepositoryWrapper : IRepositoryWrapper private IJobRepository? _jobRepository; + private IFavouritesRepository? _favouritesRepository; + private IExpertiseRepository? _expertiseRepository; + private IUserExpertiseRepository? _userExpertiseRepository; public RepositoryWrapper(StreetcodeDbContext streetcodeDbContext) @@ -122,6 +126,19 @@ public RepositoryWrapper(StreetcodeDbContext streetcodeDbContext) _streetcodeDbContext = streetcodeDbContext; } + public IFavouritesRepository FavouritesRepository + { + get + { + if (_favouritesRepository == null) + { + _favouritesRepository = new FavouritesRepository(_streetcodeDbContext); + } + + return _favouritesRepository; + } + } + public INewsRepository NewsRepository { get @@ -464,7 +481,7 @@ public IRelatedTermRepository RelatedTermRepository { get { - if(_relatedTermRepository is null) + if (_relatedTermRepository is null) { _relatedTermRepository = new RelatedTermRepository(_streetcodeDbContext); } @@ -503,7 +520,7 @@ public IPartnerStreetcodeRepository PartnerStreetcodeRepository { get { - if(_partnerStreetcodeRepository is null) + if (_partnerStreetcodeRepository is null) { _partnerStreetcodeRepository = new PartnerStreetodeRepository(_streetcodeDbContext); } @@ -538,7 +555,7 @@ public ITeamLinkRepository TeamLinkRepository } } - public IImageDetailsRepository ImageDetailsRepository => _imageDetailsRepository??=new ImageDetailsRepository(_streetcodeDbContext); + public IImageDetailsRepository ImageDetailsRepository => _imageDetailsRepository ??= new ImageDetailsRepository(_streetcodeDbContext); public IHistoricalContextTimelineRepository HistoricalContextTimelineRepository { diff --git a/Streetcode/Streetcode.DAL/Repositories/Realizations/Streetcode/FavouritesRepository.cs b/Streetcode/Streetcode.DAL/Repositories/Realizations/Streetcode/FavouritesRepository.cs new file mode 100644 index 000000000..85bb12627 --- /dev/null +++ b/Streetcode/Streetcode.DAL/Repositories/Realizations/Streetcode/FavouritesRepository.cs @@ -0,0 +1,15 @@ +using Streetcode.DAL.Persistence; +using Streetcode.DAL.Repositories.Interfaces.Streetcode.Favourites; +using Streetcode.DAL.Repositories.Realizations.Base; +using FavouriteStreetcodes = Streetcode.DAL.Entities.Streetcode.Favourites.Favourite; + +namespace Streetcode.DAL.Repositories.Realizations.Streetcode +{ + public class FavouritesRepository : RepositoryBase, IFavouritesRepository + { + public FavouritesRepository(StreetcodeDbContext dbContext) + : base(dbContext) + { + } + } +} diff --git a/Streetcode/Streetcode.DAL/Streetcode.DAL.csproj b/Streetcode/Streetcode.DAL/Streetcode.DAL.csproj index 2c0a194b7..7e70a32ea 100644 --- a/Streetcode/Streetcode.DAL/Streetcode.DAL.csproj +++ b/Streetcode/Streetcode.DAL/Streetcode.DAL.csproj @@ -43,6 +43,7 @@ + diff --git a/Streetcode/Streetcode.WebApi/Controllers/Analytics/StatisticRecordController.cs b/Streetcode/Streetcode.WebApi/Controllers/Analytics/StatisticRecordController.cs index a7790f8ef..a6a2c9c9b 100644 --- a/Streetcode/Streetcode.WebApi/Controllers/Analytics/StatisticRecordController.cs +++ b/Streetcode/Streetcode.WebApi/Controllers/Analytics/StatisticRecordController.cs @@ -1,7 +1,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Streetcode.BLL.DTO.Analytics; -using Streetcode.BLL.MediatR.Analytics.StatisticRecord.Create; using Streetcode.BLL.MediatR.Analytics.StatisticRecord.Delete; using Streetcode.BLL.MediatR.Analytics.StatisticRecord.ExistByQrId; using Streetcode.BLL.MediatR.Analytics.StatisticRecord.GetAll; @@ -44,16 +43,6 @@ public async Task GetAllByStreetcodeId(int streetcodeId) return HandleResult(await Mediator.Send(new GetAllStatisticRecordsByStreetcodeIdQuery(streetcodeId))); } - [HttpPost] - [Authorize(Roles = nameof(UserRole.Admin))] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(StatisticRecordResponseDTO))] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(StatusCodes.Status403Forbidden)] - public async Task Create(StatisticRecordDTO statisticRecordDto) - { - return HandleResult(await Mediator.Send(new CreateStatisticRecordCommand(statisticRecordDto))); - } - [HttpPut("{id:int}")] [Authorize(Roles = nameof(UserRole.Admin))] [ProducesResponseType(StatusCodes.Status200OK)] diff --git a/Streetcode/Streetcode.WebApi/Controllers/Authentication/AuthController.cs b/Streetcode/Streetcode.WebApi/Controllers/Authentication/AuthController.cs index 1ce70b27a..1d4f93903 100644 --- a/Streetcode/Streetcode.WebApi/Controllers/Authentication/AuthController.cs +++ b/Streetcode/Streetcode.WebApi/Controllers/Authentication/AuthController.cs @@ -1,6 +1,6 @@ -using System.Security.Claims; -using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Streetcode.BLL.DTO.Authentication.GoogleLogin; using Streetcode.BLL.DTO.Authentication.Login; using Streetcode.BLL.DTO.Authentication.RefreshToken; using Streetcode.BLL.DTO.Authentication.Register; @@ -41,14 +41,7 @@ public async Task RefreshToken([FromBody] RefreshTokenRequestDTO [ProducesResponseType(StatusCodes.Status200OK)] public async Task Logout() { - var userId = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value; - - if (string.IsNullOrEmpty(userId)) - { - return Unauthorized("User is not authenticated."); - } - - var result = await Mediator.Send(new LogoutCommand(userId)); + var result = await Mediator.Send(new LogoutCommand()); if (result.IsFailed) { @@ -60,9 +53,9 @@ public async Task Logout() [HttpPost] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(LoginResponseDTO))] - public async Task GoogleLogin([FromBody] string idToken) + public async Task GoogleLogin(GoogleLoginRequest googleLoginRequest) { - var result = await Mediator.Send(new LoginGoogleQuery(idToken)); + var result = await Mediator.Send(new LoginGoogleQuery(googleLoginRequest.IdToken)); if (result.IsSuccess) { diff --git a/Streetcode/Streetcode.WebApi/Controllers/Instagram/InstagramController.cs b/Streetcode/Streetcode.WebApi/Controllers/Instagram/InstagramController.cs deleted file mode 100644 index 8e6b84779..000000000 --- a/Streetcode/Streetcode.WebApi/Controllers/Instagram/InstagramController.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Streetcode.BLL.MediatR.Instagram.GetAll; -using Streetcode.DAL.Entities.Instagram; - -namespace Streetcode.WebApi.Controllers.Instagram; - public class InstagramController : BaseApiController - { - [HttpGet] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] - public async Task GetAll() - { - return HandleResult(await Mediator.Send(new GetAllPostsQuery())); - } - } \ No newline at end of file diff --git a/Streetcode/Streetcode.WebApi/Controllers/Media/Images/ImageController.cs b/Streetcode/Streetcode.WebApi/Controllers/Media/Images/ImageController.cs index 0bb4e76df..ae96b777f 100644 --- a/Streetcode/Streetcode.WebApi/Controllers/Media/Images/ImageController.cs +++ b/Streetcode/Streetcode.WebApi/Controllers/Media/Images/ImageController.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Mvc; using Streetcode.BLL.DTO.Media.Images; -using Streetcode.BLL.MediatR.Media.Image.GetAll; using Streetcode.BLL.MediatR.Media.Image.GetBaseImage; using Streetcode.BLL.MediatR.Media.Image.GetById; using Streetcode.BLL.MediatR.Media.Image.GetByStreetcodeId; @@ -15,13 +14,6 @@ namespace Streetcode.WebApi.Controllers.Media.Images; public class ImageController : BaseApiController { - [HttpGet] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] - public async Task GetAll() - { - return HandleResult(await Mediator.Send(new GetAllImagesQuery())); - } - [HttpGet("{streetcodeId:int}")] [ValidateStreetcodeExistence] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] diff --git a/Streetcode/Streetcode.WebApi/Controllers/Streetcode/RelatedFigureController.cs b/Streetcode/Streetcode.WebApi/Controllers/Streetcode/RelatedFigureController.cs index e61fad068..9c2b0459b 100644 --- a/Streetcode/Streetcode.WebApi/Controllers/Streetcode/RelatedFigureController.cs +++ b/Streetcode/Streetcode.WebApi/Controllers/Streetcode/RelatedFigureController.cs @@ -1,10 +1,10 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Streetcode.BLL.DTO.Streetcode.RelatedFigure; -using Streetcode.BLL.MediatR.Streetcode.RelatedFigure.Create; using Streetcode.BLL.MediatR.Streetcode.RelatedFigure.Delete; using Streetcode.BLL.MediatR.Streetcode.RelatedFigure.GetByStreetcodeId; using Streetcode.BLL.MediatR.Streetcode.RelatedFigure.GetByTagId; +using Streetcode.BLL.MediatR.Streetcode.RelatedFigure.Create; using Streetcode.DAL.Enums; using Streetcode.WebApi.Attributes; diff --git a/Streetcode/Streetcode.WebApi/Controllers/Streetcode/StreetcodeController.cs b/Streetcode/Streetcode.WebApi/Controllers/Streetcode/StreetcodeController.cs index 825ff74a6..f2cef6edf 100644 --- a/Streetcode/Streetcode.WebApi/Controllers/Streetcode/StreetcodeController.cs +++ b/Streetcode/Streetcode.WebApi/Controllers/Streetcode/StreetcodeController.cs @@ -1,31 +1,37 @@ +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Streetcode.BLL.DTO.AdditionalContent.Filter; using Streetcode.BLL.DTO.Streetcode; +using Streetcode.BLL.DTO.Streetcode.CatalogItem; +using Streetcode.BLL.DTO.Streetcode.Create; +using Streetcode.BLL.DTO.Streetcode.Update; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.Create; using Streetcode.BLL.MediatR.Streetcode.Streetcode.Delete; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.DeleteFromFavourites; using Streetcode.BLL.MediatR.Streetcode.Streetcode.DeleteSoft; using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAll; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllCatalog; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllFavourites; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllShort; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetByFilter; using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetById; using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetByIndex; -using Streetcode.BLL.MediatR.Streetcode.Streetcode.UpdateStatus; -using Streetcode.BLL.MediatR.Streetcode.Streetcode.WithIndexExist; -using Streetcode.DAL.Enums; using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetByTransliterationUrl; -using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllShort; -using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllCatalog; using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetCount; -using Streetcode.BLL.MediatR.Streetcode.Streetcode.Create; -using Streetcode.BLL.DTO.Streetcode.Create; -using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetByFilter; -using Streetcode.BLL.DTO.AdditionalContent.Filter; -using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetUrlByQrId; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetFavouriteById; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetPageMainPage; using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetShortById; -using Streetcode.BLL.MediatR.Streetcode.Streetcode.WithUrlExist; -using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllStreetcodesMainPage; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetUrlByQrId; using Streetcode.BLL.MediatR.Streetcode.Streetcode.Update; -using Streetcode.BLL.DTO.Streetcode.Update; -using Streetcode.BLL.MediatR.Streetcode.RelatedFigure.GetAllPublished; -using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetPageMainPage; -using Microsoft.AspNetCore.Authorization; -using Streetcode.BLL.DTO.Streetcode.CatalogItem; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.UpdateStatus; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.CreateFavourite; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.WithIndexExist; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.WithUrlExist; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetFavouriteStatus; +using Streetcode.DAL.Enums; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllMainPage; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllPublished; +using Streetcode.WebApi.Attributes; namespace Streetcode.WebApi.Controllers.Streetcode; @@ -66,11 +72,12 @@ public async Task GetPageMainPage(ushort page, ushort pageSize) return HandleResult(await Mediator.Send(new GetPageOfStreetcodesMainPageQuery(page, pageSize))); } - [HttpGet("{id:int}")] + [HttpGet("{streetcodeId:int}")] + [ValidateStreetcodeExistence] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(StreetcodeShortDTO))] - public async Task GetShortById(int id) + public async Task GetShortById(int streetcodeId) { - return HandleResult(await Mediator.Send(new GetStreetcodeShortByIdQuery(id))); + return HandleResult(await Mediator.Send(new GetStreetcodeShortByIdQuery(streetcodeId))); } [HttpGet] @@ -94,6 +101,16 @@ public async Task ExistWithUrl([FromRoute] string url) return HandleResult(await Mediator.Send(new StreetcodeWithUrlExistQuery(url))); } + [HttpGet("{streetcodeId:int}")] + [Authorize(Roles = nameof(UserRole.User))] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(bool))] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + public async Task GetFavouriteStatus([FromRoute] int streetcodeId) + { + return HandleResult(await Mediator.Send(new GetFavouriteStatusQuery(streetcodeId))); + } + [HttpGet] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable))] public async Task GetAllCatalog([FromQuery] int page, [FromQuery] int count) @@ -101,6 +118,27 @@ public async Task GetAllCatalog([FromQuery] int page, [FromQuery] return HandleResult(await Mediator.Send(new GetAllStreetcodesCatalogQuery(page, count))); } + [HttpGet] + [Authorize(Roles = nameof(UserRole.User))] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List))] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + public async Task GetAllFavourites([FromQuery] StreetcodeType? type) + { + return HandleResult(await Mediator.Send(new GetAllStreetcodeFavouritesQuery(type))); + } + + [HttpGet("{streetcodeId:int}")] + [Authorize(Roles = nameof(UserRole.User))] + [ValidateStreetcodeExistence] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(StreetcodeFavouriteDto))] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + public async Task GetFavouriteById([FromRoute] int streetcodeId) + { + return HandleResult(await Mediator.Send(new GetFavouriteByIdQuery(streetcodeId))); + } + [HttpGet] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(int))] public async Task GetCount([FromQuery] bool? onlyPublished) @@ -115,11 +153,12 @@ public async Task GetByTransliterationUrl([FromRoute] string url) return HandleResult(await Mediator.Send(new GetStreetcodeByTransliterationUrlQuery(url))); } - [HttpGet("{id:int}")] + [HttpGet("{streetcodeId:int}")] + [ValidateStreetcodeExistence] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(StreetcodeDTO))] - public async Task GetById([FromRoute] int id) + public async Task GetById([FromRoute] int streetcodeId) { - return HandleResult(await Mediator.Send(new GetStreetcodeByIdQuery(id))); + return HandleResult(await Mediator.Send(new GetStreetcodeByIdQuery(streetcodeId))); } [HttpGet("{qrid:int}")] @@ -158,6 +197,18 @@ public async Task PatchStage( return HandleResult(await Mediator.Send(new UpdateStatusStreetcodeByIdCommand(id, status))); } + [HttpPost("{streetcodeId:int}")] + [Authorize(Roles = nameof(UserRole.User))] + [ValidateStreetcodeExistence] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + public async Task CreateFavourite( + [FromRoute] int streetcodeId) + { + return HandleResult(await Mediator.Send(new CreateFavouriteStreetcodeCommand(streetcodeId))); + } + [HttpDelete("{id:int}")] [Authorize(Roles = nameof(UserRole.Admin))] [ProducesResponseType(StatusCodes.Status200OK)] @@ -178,13 +229,24 @@ public async Task Delete([FromRoute] int id) return HandleResult(await Mediator.Send(new DeleteStreetcodeCommand(id))); } + [HttpDelete("{streetcodeId:int}")] + [Authorize(Roles = nameof(UserRole.User))] + [ValidateStreetcodeExistence] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + public async Task DeleteFromFavourites([FromRoute] int streetcodeId) + { + return HandleResult(await Mediator.Send(new DeleteStreetcodeFromFavouritesCommand(streetcodeId))); + } + [HttpPut] [Authorize(Roles = nameof(UserRole.Admin))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(int))] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] - public async Task Update([FromBody]StreetcodeUpdateDTO streetcode) + public async Task Update([FromBody] StreetcodeUpdateDTO streetcode) { return HandleResult(await Mediator.Send(new UpdateStreetcodeCommand(streetcode))); - } + } } diff --git a/Streetcode/Streetcode.WebApi/Controllers/Streetcode/TextContent/FactController.cs b/Streetcode/Streetcode.WebApi/Controllers/Streetcode/TextContent/FactController.cs index 267e6f189..3a7703a7e 100644 --- a/Streetcode/Streetcode.WebApi/Controllers/Streetcode/TextContent/FactController.cs +++ b/Streetcode/Streetcode.WebApi/Controllers/Streetcode/TextContent/FactController.cs @@ -52,7 +52,7 @@ public async Task Create([FromBody] StreetcodeFactCreateDTO fact) [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] - public async Task Update([FromRoute] int id, [FromBody] FactDto fact) + public async Task Update([FromRoute] int id, [FromBody] StreetcodeFactUpdateDTO fact) { fact.Id = id; return HandleResult(await Mediator.Send(new UpdateFactCommand(fact))); diff --git a/Streetcode/Streetcode.WebApi/Controllers/Streetcode/TextContent/TextController.cs b/Streetcode/Streetcode.WebApi/Controllers/Streetcode/TextContent/TextController.cs index 8e3266c51..850762a9d 100644 --- a/Streetcode/Streetcode.WebApi/Controllers/Streetcode/TextContent/TextController.cs +++ b/Streetcode/Streetcode.WebApi/Controllers/Streetcode/TextContent/TextController.cs @@ -4,7 +4,7 @@ using Streetcode.BLL.MediatR.Streetcode.Text.GetAll; using Streetcode.BLL.MediatR.Streetcode.Text.GetById; using Streetcode.BLL.MediatR.Streetcode.Text.GetByStreetcodeId; -using Streetcode.BLL.MediatR.Streetcode.Text.GetParsed; +using Streetcode.BLL.MediatR.Streetcode.Text.UpdateParsed; using Streetcode.DAL.Enums; using Streetcode.WebApi.Attributes; diff --git a/Streetcode/Streetcode.WebApi/Controllers/Users/UsersController.cs b/Streetcode/Streetcode.WebApi/Controllers/Users/UsersController.cs index 97f518747..922ef366e 100644 --- a/Streetcode/Streetcode.WebApi/Controllers/Users/UsersController.cs +++ b/Streetcode/Streetcode.WebApi/Controllers/Users/UsersController.cs @@ -1,14 +1,13 @@ -using System.Security.Claims; -using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Streetcode.BLL.DTO.Users; using Streetcode.BLL.DTO.Users.Password; using Streetcode.BLL.MediatR.Users.Delete; +using Streetcode.BLL.MediatR.Users.ExistWithUserName; using Streetcode.BLL.MediatR.Users.ForgotPassword; -using Streetcode.BLL.MediatR.Users.GetAllUserName; -using Streetcode.BLL.MediatR.Users.GetByName; +using Streetcode.BLL.MediatR.Users.GetByEmail; +using Streetcode.BLL.MediatR.Users.GetOtherUserByUserName; using Streetcode.BLL.MediatR.Users.Update; -using Streetcode.BLL.MediatR.Users.GetByUserName; using Streetcode.BLL.MediatR.Users.UpdateForgotPassword; namespace Streetcode.WebApi.Controllers.Users @@ -18,9 +17,9 @@ public class UsersController : BaseApiController [HttpGet] [Authorize] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task GetByUserName() + public async Task GetByEmail() { - return HandleResult(await Mediator.Send(new GetByUserNameQuery())); + return HandleResult(await Mediator.Send(new GetByEmailQuery())); } [HttpGet("{userName}")] diff --git a/Streetcode/Streetcode.WebApi/Extensions/ServiceCollectionExtensions.cs b/Streetcode/Streetcode.WebApi/Extensions/ServiceCollectionExtensions.cs index 2d2fca512..0c20befeb 100644 --- a/Streetcode/Streetcode.WebApi/Extensions/ServiceCollectionExtensions.cs +++ b/Streetcode/Streetcode.WebApi/Extensions/ServiceCollectionExtensions.cs @@ -68,6 +68,7 @@ public static void AddCustomServices(this IServiceCollection services) services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/Streetcode/Streetcode.WebApi/Middleware/ApiRequestResponseMiddleware/ApiRequestResponseMiddleware.cs b/Streetcode/Streetcode.WebApi/Middleware/ApiRequestResponseMiddleware/ApiRequestResponseMiddleware.cs index 23d74d8ae..716b5fc3c 100644 --- a/Streetcode/Streetcode.WebApi/Middleware/ApiRequestResponseMiddleware/ApiRequestResponseMiddleware.cs +++ b/Streetcode/Streetcode.WebApi/Middleware/ApiRequestResponseMiddleware/ApiRequestResponseMiddleware.cs @@ -70,8 +70,9 @@ private async Task GetResponseAsTextAsync(HttpResponse response) response.Body.Seek(0, SeekOrigin.Begin); var encoding = Encoding.UTF8; + using var streamReader = new StreamReader(response.Body, encoding, leaveOpen: true); - var text = await new StreamReader(response.Body, encoding).ReadToEndAsync(); + var text = await streamReader.ReadToEndAsync(); response.Body.Seek(0, SeekOrigin.Begin); @@ -120,29 +121,49 @@ private string GetFilteredBody(string body) private void TruncateProperties(JToken token) { - foreach (var property in token.Children().ToList()) + switch (token) { - if (_options.PropertiesToIgnore.Contains(property.Name.ToLower())) + case JObject obj: { - property.Remove(); - continue; - } + foreach (var property in obj.Properties()) + { + if (property.Value is JValue) + { + TruncateValue(property); + } + else + { + TruncateProperties(property.Value); + } + } - var valueType = property.Value.Type; + break; + } - if (valueType == JTokenType.Object || valueType == JTokenType.Array) + case JArray array: { - TruncateProperties(property.Value); - continue; + foreach (var item in array) + { + TruncateProperties(item); + } + + break; } + } + } - var valueAsString = property.Value.ToString(); - var valueLength = valueAsString.Length; + private void TruncateValue(JProperty property) + { + if (_options.PropertiesToIgnore.Contains(property.Name.ToLower())) + { + property.Remove(); + } - if (valueLength > _options.MaxResponseLength) - { - property.Value = new JValue(valueAsString.Substring(0, _options.MaxResponseLength) + "..."); - } + var valueAsString = property.Value.ToString(); + if (valueAsString.Length > _options.MaxResponseLength) + { + var shortenedLog = new JValue(valueAsString.Substring(0, _options.MaxResponseLength)); + property.Value = $"{shortenedLog}..."; } } } diff --git a/Streetcode/Streetcode.WebApi/Program.cs b/Streetcode/Streetcode.WebApi/Program.cs index eb6a99910..90a86f957 100644 --- a/Streetcode/Streetcode.WebApi/Program.cs +++ b/Streetcode/Streetcode.WebApi/Program.cs @@ -77,7 +77,10 @@ app.UseHsts(); } -await app.ApplyMigrations(); +if (!builder.Environment.EnvironmentName.Equals("IntegrationTests")) +{ + await app.SeedDataAsync(); +} app.AddCleanAudiosJob(); app.AddCleanImagesJob(); @@ -95,12 +98,12 @@ app.UseIpRateLimiting(); app.UseRateLimiter(); -BackgroundJob.Schedule( - wp => wp.ParseZipFileFromWebAsync(), TimeSpan.FromMinutes(1)); -RecurringJob.AddOrUpdate( - "ParseZipFileFromWebAsync", - wp => wp.ParseZipFileFromWebAsync(), - Cron.Monthly); +// BackgroundJob.Schedule( +// wp => wp.ParseZipFileFromWebAsync(), TimeSpan.FromMinutes(1)); +// RecurringJob.AddOrUpdate( +// "ParseZipFileFromWebAsync", +// wp => wp.ParseZipFileFromWebAsync(), +// Cron.Monthly); app.MapControllers(); app.UseMiddleware(); diff --git a/Streetcode/Streetcode.WebApi/Utils/WebParsingUtils.cs b/Streetcode/Streetcode.WebApi/Utils/WebParsingUtils.cs index 332418035..68b0e4712 100644 --- a/Streetcode/Streetcode.WebApi/Utils/WebParsingUtils.cs +++ b/Streetcode/Streetcode.WebApi/Utils/WebParsingUtils.cs @@ -1,469 +1,465 @@ -using System.Globalization; -using System.IO.Compression; -using System.Net; -using System.Text; -using Newtonsoft.Json; -using Polly; -using Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types; -using Streetcode.DAL.Entities.Toponyms; -using Streetcode.DAL.Persistence; -using Streetcode.DAL.Repositories.Interfaces.Base; -using Streetcode.DAL.Repositories.Realizations.Base; - -namespace Streetcode.WebApi.Utils; - -public class WebParsingUtils -{ - private const byte RegionColumn = 0; - private const byte AdministrativeRegionOldColumn = 1; - private const byte AdministrativeRegionNewColumn = 2; - private const byte CommonalityColumn = 3; - private const byte CommunityColumn = 4; - private const byte AddressColumn = 6; - private const byte LatitudeColumn = 7; - private const byte LongitudeColumn = 8; - - private static readonly string FileToParseUrl = "https://www.ukrposhta.ua/files/shares/out/houses.zip?_ga=2.213909844.272819342.1674050613-1387315609.1673613938&_gl=1*1obnqll*_ga*MTM4NzMxNTYwOS4xNjczNjEzOTM4*_ga_6400KY4HRY*MTY3NDA1MDYxMy4xMC4xLjE2NzQwNTE3ODUuNjAuMC4w"; - - private readonly IRepositoryWrapper _repository; - private readonly StreetcodeDbContext _streetcodeContext; - - public WebParsingUtils(StreetcodeDbContext streetcodeContext) - { - _repository = new RepositoryWrapper(streetcodeContext); - _streetcodeContext = streetcodeContext; - } - - public async Task ParseZipFileFromWebAsync() - { - _ = Directory.GetParent(Environment.CurrentDirectory)?.FullName!; - var zipPath = $"houses.zip"; - var extractTo = $"/root/build/StreetCode/Streetcode/Streetcode.DAL"; - - var cancellationToken = new CancellationTokenSource().Token; - - try - { - await DownloadAndExtractAsync(FileToParseUrl, zipPath, extractTo, cancellationToken); - Console.WriteLine("Download and extraction completed successfully."); - - if (File.Exists(zipPath)) - { - File.Delete(zipPath); - } - - await ProcessCsvFileAsync(extractTo); - } - catch (Exception ex) - { - Console.WriteLine($"An error occurred: {ex.Message}"); - } - } - - private static async Task DownloadAndExtractAsync( - string fileUrl, - string zipPath, - string extractTo, - CancellationToken cancellationToken) - { - if (string.IsNullOrEmpty(fileUrl) || !Uri.IsWellFormedUriString(fileUrl, UriKind.Absolute)) - { - throw new ArgumentException("FileUrl cannot be null, empty or invalid", nameof(fileUrl)); - } - - if (string.IsNullOrEmpty(zipPath)) - { - throw new ArgumentException("zipPath cannot be null or empty", nameof(zipPath)); - } - - if (string.IsNullOrEmpty(extractTo)) - { - throw new ArgumentException("extractTo cannot be null or empty", nameof(extractTo)); - } - - var clientHandler = new HttpClientHandler(); - clientHandler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; - clientHandler.ServerCertificateCustomValidationCallback = (_, _, _, _) => true; - - var retryPolicy = Policy.Handle().WaitAndRetryAsync( - 3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); - - var circuitBreakerPolicy = Policy.Handle().CircuitBreakerAsync(5, TimeSpan.FromMinutes(1)); - - using var client = new HttpClient(clientHandler, false); - client.Timeout = TimeSpan.FromSeconds(60); - - try - { - using var response = await retryPolicy.WrapAsync(circuitBreakerPolicy).ExecuteAsync(async () => await client - .GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead, cancellationToken)); - - response.EnsureSuccessStatusCode(); - response.Content.Headers.ContentType!.CharSet = Encoding.GetEncoding(1251).WebName; - - await using (var streamToReadFrom = await response.Content.ReadAsStreamAsync(cancellationToken)) - { - await using var streamToWriteTo = File.Open(zipPath, FileMode.Create); - await streamToReadFrom.CopyToAsync(streamToWriteTo, 81920, cancellationToken); - } - - using var archive = ZipFile.OpenRead(zipPath); - archive.ExtractToDirectory(extractTo, overwriteFiles: true); - Console.WriteLine($"Archive received and extracted to {extractTo}"); - } - catch (OperationCanceledException) - { - Console.WriteLine("The operation was cancelled."); - throw; - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - throw; - } - } - - /* - ProcessCsvFileAsync is an async method that reads data from a CSV file and processes it. - - It takes in two parameters: - - extractTo (string): the path to the directory where the CSV file is located - deleteFile (bool): a flag that indicates whether or not to delete the original CSV file after processing (default is false) - The method first sets the encoding for the CSV file to be read properly. It then reads the contents of the file at the specified path and stores it in a list. - - It groups the rows from the initial CSV in order to eliminate duplicate streets. It also checks for any rows that have already been processed and removes them from the list of rows to be processed. - - The method then uses the remaining rows to parse the coordinates of the streets and writes them to the CSV file. - - If the deleteFile flag is set to true, the original CSV file will be deleted. The method also saves the toponyms to a database. - */ - private async Task ProcessCsvFileAsync(string extractTo, bool deleteFile = false) - { - // Following line is required for proper csv encoding - Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - - string csvPath = $"{extractTo}/data.csv"; - - var allLinesFromDataCsv = new List(); - - if (File.Exists(csvPath)) - { - allLinesFromDataCsv = new List(await File.ReadAllLinesAsync(csvPath, Encoding.GetEncoding(1251))); - Console.OutputEncoding = Encoding.GetEncoding(1251); - } - - string excelPath = Directory.GetFiles(extractTo).First(fName => fName.EndsWith("houses.csv")); - - var rows = new List(await File.ReadAllLinesAsync(excelPath, Encoding.GetEncoding(1251))); - - // Grouping all rows from initial csv in order to get rid of duplicated streets - - var forParsingRows = GetDistinctRows(rows); - - var alreadyParsedRows = GetDistinctRows(allLinesFromDataCsv); - - var alreadyParsedRowsToWrite = allLinesFromDataCsv.Distinct().ToList(); - - var remainsToParse = forParsingRows.Except(alreadyParsedRows) - .Select(x => x.Split(';').ToList()).ToList(); - /*.Take(20) // TODO take it of if you want to start global parse - .ToList();*/ - - var toBeDeleted = alreadyParsedRows.Except(forParsingRows).ToList(); - - Console.WriteLine("Remains to parse: " + remainsToParse.Count); - Console.WriteLine("To be deleted: " + toBeDeleted.Count); - - // deletes out of date data in data.csv - foreach (var row in toBeDeleted) - { - alreadyParsedRowsToWrite = alreadyParsedRowsToWrite.Where(x => !x.Contains(row)).ToList(); - } - - await File.WriteAllLinesAsync(csvPath, alreadyParsedRowsToWrite, Encoding.GetEncoding(1251)); - - // parses coordinates and writes into data.csv - foreach (var row in remainsToParse) - { - var communityCol = row[CommunityColumn]; - string cityStringSearchOptimized = communityCol.Substring(communityCol.IndexOf(" ", StringComparison.Ordinal) + 1); - - var (streetName, streetType) = OptimizeStreetname(row[AddressColumn]); - string addressRow = $"{cityStringSearchOptimized} {streetName} {streetType}"; - - var (latitude, longitude) = await FetchCoordsByAddressAsync(addressRow); - - if (latitude is null || longitude is null) - { - addressRow = cityStringSearchOptimized; - (latitude, longitude) = await FetchCoordsByAddressAsync(addressRow); - } - - Console.WriteLine("\n" + addressRow); - Console.WriteLine($"Coordinates[{latitude}-{longitude}]"); - - var newRow = string.Empty; - for (int i = 0; i <= AddressColumn; i++) - { - newRow += $"{row[i]};"; - } - - newRow += $"{latitude};{longitude}"; - Console.WriteLine(newRow); - - await File.AppendAllTextAsync(csvPath, newRow + "\n", Encoding.GetEncoding(1251)); - } - - if (deleteFile) - { - File.Delete(excelPath); - } - - await SaveToponymsToDbAsync(csvPath); - } - - private async Task SaveToponymsToDbAsync(string csvPath) - { - var rows = new List( - await File.ReadAllLinesAsync(csvPath, Encoding.GetEncoding(1251))) - .Skip(1) - .Select(x => x.Split(';')); - - // this part of code truncates Toponyms table - _streetcodeContext.Set().RemoveRange(_streetcodeContext.Set()); - await _streetcodeContext.SaveChangesAsync(); - - foreach (var row in rows) - { - try - { - var (streetName, streetType) = OptimizeStreetname(row[AddressColumn]); - - await _repository.ToponymRepository.CreateAsync(new Toponym - { - Oblast = row[RegionColumn], - AdminRegionOld = row[AdministrativeRegionOldColumn], - AdminRegionNew = row[AdministrativeRegionNewColumn], - Gromada = row[CommonalityColumn], - Community = row[CommunityColumn], - StreetName = streetName, - StreetType = streetType, - Coordinate = new ToponymCoordinate - { - Latitude = decimal.Parse(row[LatitudeColumn], CultureInfo.InvariantCulture), - Longtitude = decimal.Parse(row[LongitudeColumn], CultureInfo.InvariantCulture) - } - }); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - } - - var isChangeSuccessful = await _repository.SaveChangesAsync() > 0; - Console.WriteLine($"Success: {isChangeSuccessful}"); - } - - /// - /// Fetches the coordinates of an address using the OpenStreetMap Nominatim API. - /// - /// The address to fetch coordinates for. - /// A tuple containing the latitude and longitude of the address. - private static async Task<(string?, string?)> FetchCoordsByAddressAsync(string address) - { - var retryPolicy = Policy.Handle().WaitAndRetryAsync( - 3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); - - var circuitBreakerPolicy = Policy.Handle().CircuitBreakerAsync(5, TimeSpan.FromMinutes(1)); - - try - { - using var client = new HttpClient(); - - // Add user-agent and referer headers to request - client.DefaultRequestHeaders.Add("User-Agent", "HistoryCode"); - - // Send GET request to Nominatim API and retrieve JSON data - var encodedAddress = Uri.EscapeDataString(address); - var jsonData = await retryPolicy.WrapAsync(circuitBreakerPolicy).ExecuteAsync(async () => - await client.GetByteArrayAsync($"https://nominatim.openstreetmap.org/search?q={encodedAddress}, Україна&format=json&limit=1&addressdetails=1")); - - return ParseJsonToCoordinateTuple(Encoding.UTF8.GetString(jsonData)); - } - catch (Exception ex) - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(ex.Message); - Console.ForegroundColor = ConsoleColor.White; - } - - return (null, null); - } - - /// - /// Returns a list of distinct rows based on the first N columns of the input list. - /// - /// The list of rows to filter. - /// How many columns will be taken. - /// A list of distinct rows based on the first seven columns of the input list. - private static List GetDistinctRows(IEnumerable rows, byte beforeColumn = 7) => - rows.Select(x => string.Join(";", x.Split(';').Take(beforeColumn))) - .Distinct() - .ToList(); - - // Following method returns name of the street optimized in such kind of way that will allow OSM Nominatim find its coordinates - private static (string, string) OptimizeStreetname(string streetname) - { - if (streetname.IndexOf("пров. ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "провулок"); - } - - if (streetname.IndexOf("проїзд ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "проїзд"); - } - - if (streetname.IndexOf("вул. ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "вулиця"); - } - - if (streetname.IndexOf("просп. ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "проспект"); - } - - if (streetname.IndexOf("тупик ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "тупик"); - } - - if (streetname.IndexOf("пл. ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "площа"); - } - - if (streetname.IndexOf("майдан ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "майдан"); - } - - if (streetname.IndexOf("узвіз ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "узвіз"); - } - - if (streetname.IndexOf("дорога ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "дорога"); - } - - if (streetname.IndexOf("парк ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "парк"); - } - - if (streetname.IndexOf("жилий масив ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", streetname.IndexOf(" ", StringComparison.Ordinal) + 1, StringComparison.Ordinal) + 1), "парк"); - } - - if (streetname.IndexOf("м-р ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "мікрорайон"); - } - - if (streetname.IndexOf("алея ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "алея"); - } - - if (streetname.IndexOf("хутір ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "хутір"); - } - - if (streetname.IndexOf("кв-л ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "квартал"); - } - - if (streetname.IndexOf("урочище ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "урочище"); - } - - if (streetname.IndexOf("набережна ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "набережна"); - } - - if (streetname.IndexOf("селище ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "селище"); - } - - if (streetname.IndexOf("лінія ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "лінія"); - } - - if (streetname.IndexOf("шлях ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "шлях"); - } - - if (streetname.IndexOf("спуск ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "спуск"); - } - - if (streetname.IndexOf("завулок ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "завулок"); - } - - if (streetname.IndexOf("острів ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "острів"); - } - - if (streetname.IndexOf("бульв. ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "бульвар"); - } - - if (streetname.IndexOf("шосе ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "шосе"); - } - - if (streetname.IndexOf("містечко ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "містечко"); - } - - if (streetname.IndexOf("в’їзд ", StringComparison.Ordinal) != -1) - { - return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "в’їзд"); - } - - return (string.Empty, string.Empty); - } - - // Following method parses JSON from OSM Nominatim API and returns lat/lon tuple - private static (string?, string?) ParseJsonToCoordinateTuple(string json) - { - var data = JsonConvert.DeserializeObject>>(json); - - if (data is null || data.Count == 0) - { - return default; - } - - return (data[0]["lat"].ToString(), data[0]["lon"].ToString()); - } -} \ No newline at end of file +// using System.Globalization; +// using System.IO.Compression; +// using System.Net; +// using System.Text; +// using Newtonsoft.Json; +// using Polly; +// using Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types; +// using Streetcode.DAL.Entities.Toponyms; +// using Streetcode.DAL.Persistence; +// using Streetcode.DAL.Repositories.Interfaces.Base; +// using Streetcode.DAL.Repositories.Realizations.Base; +// +// namespace Streetcode.WebApi.Utils; +// +// public class WebParsingUtils +// { +// private const byte RegionColumn = 0; +// private const byte AdministrativeRegionOldColumn = 1; +// private const byte AdministrativeRegionNewColumn = 2; +// private const byte CommonalityColumn = 3; +// private const byte CommunityColumn = 4; +// private const byte AddressColumn = 6; +// private const byte LatitudeColumn = 7; +// private const byte LongitudeColumn = 8; +// +// private static readonly string FileToParseUrl = "https://www.ukrposhta.ua/files/shares/out/houses.zip?_ga=2.213909844.272819342.1674050613-1387315609.1673613938&_gl=1*1obnqll*_ga*MTM4NzMxNTYwOS4xNjczNjEzOTM4*_ga_6400KY4HRY*MTY3NDA1MDYxMy4xMC4xLjE2NzQwNTE3ODUuNjAuMC4w"; +// +// private readonly IRepositoryWrapper _repository; +// private readonly StreetcodeDbContext _streetcodeContext; +// +// public WebParsingUtils(StreetcodeDbContext streetcodeContext) +// { +// _repository = new RepositoryWrapper(streetcodeContext); +// _streetcodeContext = streetcodeContext; +// } +// +// public async Task ParseZipFileFromWebAsync() +// { +// _ = Directory.GetParent(Environment.CurrentDirectory)?.FullName!; +// var zipPath = $"houses.zip"; +// var extractTo = $"/root/build/StreetCode/Streetcode/Streetcode.DAL"; +// +// var cancellationToken = new CancellationTokenSource().Token; +// +// try +// { +// await DownloadAndExtractAsync(FileToParseUrl, zipPath, extractTo, cancellationToken); +// Console.WriteLine("Download and extraction completed successfully."); +// +// if (File.Exists(zipPath)) +// { +// File.Delete(zipPath); +// } +// +// await ProcessCsvFileAsync(extractTo); +// } +// catch (Exception ex) +// { +// Console.WriteLine($"An error occurred: {ex.Message}"); +// } +// } +// +// private static async Task DownloadAndExtractAsync( +// string fileUrl, +// string zipPath, +// string extractTo, +// CancellationToken cancellationToken) +// { +// if (string.IsNullOrEmpty(fileUrl) || !Uri.IsWellFormedUriString(fileUrl, UriKind.Absolute)) +// { +// throw new ArgumentException("FileUrl cannot be null, empty or invalid", nameof(fileUrl)); +// } +// +// if (string.IsNullOrEmpty(zipPath)) +// { +// throw new ArgumentException("zipPath cannot be null or empty", nameof(zipPath)); +// } +// +// if (string.IsNullOrEmpty(extractTo)) +// { +// throw new ArgumentException("extractTo cannot be null or empty", nameof(extractTo)); +// } +// +// var clientHandler = new HttpClientHandler(); +// clientHandler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; +// clientHandler.ServerCertificateCustomValidationCallback = (_, _, _, _) => true; +// +// var retryPolicy = Policy.Handle().WaitAndRetryAsync( +// 3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); +// +// var circuitBreakerPolicy = Policy.Handle().CircuitBreakerAsync(5, TimeSpan.FromMinutes(1)); +// +// using var client = new HttpClient(clientHandler, false); +// client.Timeout = TimeSpan.FromSeconds(60); +// +// try +// { +// using var response = await retryPolicy.WrapAsync(circuitBreakerPolicy).ExecuteAsync(async () => await client +// .GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead, cancellationToken)); +// +// response.EnsureSuccessStatusCode(); +// response.Content.Headers.ContentType!.CharSet = Encoding.GetEncoding(1251).WebName; +// +// await using (var streamToReadFrom = await response.Content.ReadAsStreamAsync(cancellationToken)) +// { +// await using var streamToWriteTo = File.Open(zipPath, FileMode.Create); +// await streamToReadFrom.CopyToAsync(streamToWriteTo, 81920, cancellationToken); +// } +// +// using var archive = ZipFile.OpenRead(zipPath); +// archive.ExtractToDirectory(extractTo, overwriteFiles: true); +// Console.WriteLine($"Archive received and extracted to {extractTo}"); +// } +// catch (OperationCanceledException) +// { +// Console.WriteLine("The operation was cancelled."); +// throw; +// } +// catch (Exception ex) +// { +// Console.WriteLine(ex.Message); +// throw; +// } +// } +// +// /* +// ProcessCsvFileAsync is an async method that reads data from a CSV file and processes it. +// +// It takes in two parameters: +// +// extractTo (string): the path to the directory where the CSV file is located +// deleteFile (bool): a flag that indicates whether or not to delete the original CSV file after processing (default is false) +// The method first sets the encoding for the CSV file to be read properly. It then reads the contents of the file at the specified path and stores it in a list. +// +// It groups the rows from the initial CSV in order to eliminate duplicate streets. It also checks for any rows that have already been processed and removes them from the list of rows to be processed. +// +// The method then uses the remaining rows to parse the coordinates of the streets and writes them to the CSV file. +// +// If the deleteFile flag is set to true, the original CSV file will be deleted. The method also saves the toponyms to a database. +// */ +// private async Task ProcessCsvFileAsync(string extractTo, bool deleteFile = false) +// { +// // Following line is required for proper csv encoding +// Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); +// +// string csvPath = $"{extractTo}/data.csv"; +// +// var allLinesFromDataCsv = new List(); +// +// if (File.Exists(csvPath)) +// { +// allLinesFromDataCsv = new List(await File.ReadAllLinesAsync(csvPath, Encoding.GetEncoding(1251))); +// Console.OutputEncoding = Encoding.GetEncoding(1251); +// } +// +// string excelPath = Directory.GetFiles(extractTo).First(fName => fName.EndsWith("houses.csv")); +// +// var rows = new List(await File.ReadAllLinesAsync(excelPath, Encoding.GetEncoding(1251))); +// +// // Grouping all rows from initial csv in order to get rid of duplicated streets +// +// var forParsingRows = GetDistinctRows(rows); +// +// var alreadyParsedRows = GetDistinctRows(allLinesFromDataCsv); +// +// var alreadyParsedRowsToWrite = allLinesFromDataCsv.Distinct().ToList(); +// +// var remainsToParse = forParsingRows.Except(alreadyParsedRows) +// .Select(x => x.Split(';').ToList()).ToList(); +// /*.Take(20) // TODO take it of if you want to start global parse +// .ToList();*/ +// +// var toBeDeleted = alreadyParsedRows.Except(forParsingRows).ToList(); +// +// Console.WriteLine("Remains to parse: " + remainsToParse.Count); +// Console.WriteLine("To be deleted: " + toBeDeleted.Count); +// +// // deletes out of date data in data.csv +// foreach (var row in toBeDeleted) +// { +// alreadyParsedRowsToWrite = alreadyParsedRowsToWrite.Where(x => !x.Contains(row)).ToList(); +// } +// +// await File.WriteAllLinesAsync(csvPath, alreadyParsedRowsToWrite, Encoding.GetEncoding(1251)); +// +// // parses coordinates and writes into data.csv +// foreach (var row in remainsToParse) +// { +// var communityCol = row[CommunityColumn]; +// string cityStringSearchOptimized = communityCol.Substring(communityCol.IndexOf(" ", StringComparison.Ordinal) + 1); +// +// var (streetName, streetType) = OptimizeStreetname(row[AddressColumn]); +// string addressRow = $"{cityStringSearchOptimized} {streetName} {streetType}"; +// +// var (latitude, longitude) = await FetchCoordsByAddressAsync(addressRow); +// +// if (latitude is null || longitude is null) +// { +// addressRow = cityStringSearchOptimized; +// (latitude, longitude) = await FetchCoordsByAddressAsync(addressRow); +// } +// +// var newRow = string.Empty; +// for (int i = 0; i <= AddressColumn; i++) +// { +// newRow += $"{row[i]};"; +// } +// +// newRow += $"{latitude};{longitude}"; +// +// await File.AppendAllTextAsync(csvPath, newRow + "\n", Encoding.GetEncoding(1251)); +// } +// +// if (deleteFile) +// { +// File.Delete(excelPath); +// } +// +// await SaveToponymsToDbAsync(csvPath); +// } +// +// private async Task SaveToponymsToDbAsync(string csvPath) +// { +// var rows = new List( +// await File.ReadAllLinesAsync(csvPath, Encoding.GetEncoding(1251))) +// .Skip(1) +// .Select(x => x.Split(';')); +// +// // this part of code truncates Toponyms table +// _streetcodeContext.Set().RemoveRange(_streetcodeContext.Set()); +// await _streetcodeContext.SaveChangesAsync(); +// +// foreach (var row in rows) +// { +// try +// { +// var (streetName, streetType) = OptimizeStreetname(row[AddressColumn]); +// +// await _repository.ToponymRepository.CreateAsync(new Toponym +// { +// Oblast = row[RegionColumn], +// AdminRegionOld = row[AdministrativeRegionOldColumn], +// AdminRegionNew = row[AdministrativeRegionNewColumn], +// Gromada = row[CommonalityColumn], +// Community = row[CommunityColumn], +// StreetName = streetName, +// StreetType = streetType, +// Coordinate = new ToponymCoordinate +// { +// Latitude = decimal.Parse(row[LatitudeColumn], CultureInfo.InvariantCulture), +// Longtitude = decimal.Parse(row[LongitudeColumn], CultureInfo.InvariantCulture) +// } +// }); +// } +// catch (Exception ex) +// { +// Console.WriteLine(ex.Message); +// } +// } +// +// var isChangeSuccessful = await _repository.SaveChangesAsync() > 0; +// Console.WriteLine($"Success: {isChangeSuccessful}"); +// } +// +// /// +// /// Fetches the coordinates of an address using the OpenStreetMap Nominatim API. +// /// +// /// The address to fetch coordinates for. +// /// A tuple containing the latitude and longitude of the address. +// private static async Task<(string?, string?)> FetchCoordsByAddressAsync(string address) +// { +// var retryPolicy = Policy.Handle().WaitAndRetryAsync( +// 3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); +// +// var circuitBreakerPolicy = Policy.Handle().CircuitBreakerAsync(5, TimeSpan.FromMinutes(1)); +// +// try +// { +// using var client = new HttpClient(); +// +// // Add user-agent and referer headers to request +// client.DefaultRequestHeaders.Add("User-Agent", "HistoryCode"); +// +// // Send GET request to Nominatim API and retrieve JSON data +// var encodedAddress = Uri.EscapeDataString(address); +// var jsonData = await retryPolicy.WrapAsync(circuitBreakerPolicy).ExecuteAsync(async () => +// await client.GetByteArrayAsync($"https://nominatim.openstreetmap.org/search?q={encodedAddress}, Україна&format=json&limit=1&addressdetails=1")); +// +// return ParseJsonToCoordinateTuple(Encoding.UTF8.GetString(jsonData)); +// } +// catch (Exception ex) +// { +// Console.ForegroundColor = ConsoleColor.Red; +// Console.WriteLine(ex.Message); +// Console.ForegroundColor = ConsoleColor.White; +// } +// +// return (null, null); +// } +// +// /// +// /// Returns a list of distinct rows based on the first N columns of the input list. +// /// +// /// The list of rows to filter. +// /// How many columns will be taken. +// /// A list of distinct rows based on the first seven columns of the input list. +// private static List GetDistinctRows(IEnumerable rows, byte beforeColumn = 7) => +// rows.Select(x => string.Join(";", x.Split(';').Take(beforeColumn))) +// .Distinct() +// .ToList(); +// +// // Following method returns name of the street optimized in such kind of way that will allow OSM Nominatim find its coordinates +// private static (string, string) OptimizeStreetname(string streetname) +// { +// if (streetname.IndexOf("пров. ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "провулок"); +// } +// +// if (streetname.IndexOf("проїзд ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "проїзд"); +// } +// +// if (streetname.IndexOf("вул. ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "вулиця"); +// } +// +// if (streetname.IndexOf("просп. ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "проспект"); +// } +// +// if (streetname.IndexOf("тупик ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "тупик"); +// } +// +// if (streetname.IndexOf("пл. ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "площа"); +// } +// +// if (streetname.IndexOf("майдан ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "майдан"); +// } +// +// if (streetname.IndexOf("узвіз ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "узвіз"); +// } +// +// if (streetname.IndexOf("дорога ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "дорога"); +// } +// +// if (streetname.IndexOf("парк ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "парк"); +// } +// +// if (streetname.IndexOf("жилий масив ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", streetname.IndexOf(" ", StringComparison.Ordinal) + 1, StringComparison.Ordinal) + 1), "парк"); +// } +// +// if (streetname.IndexOf("м-р ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "мікрорайон"); +// } +// +// if (streetname.IndexOf("алея ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "алея"); +// } +// +// if (streetname.IndexOf("хутір ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "хутір"); +// } +// +// if (streetname.IndexOf("кв-л ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "квартал"); +// } +// +// if (streetname.IndexOf("урочище ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "урочище"); +// } +// +// if (streetname.IndexOf("набережна ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "набережна"); +// } +// +// if (streetname.IndexOf("селище ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "селище"); +// } +// +// if (streetname.IndexOf("лінія ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "лінія"); +// } +// +// if (streetname.IndexOf("шлях ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "шлях"); +// } +// +// if (streetname.IndexOf("спуск ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "спуск"); +// } +// +// if (streetname.IndexOf("завулок ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "завулок"); +// } +// +// if (streetname.IndexOf("острів ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "острів"); +// } +// +// if (streetname.IndexOf("бульв. ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "бульвар"); +// } +// +// if (streetname.IndexOf("шосе ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "шосе"); +// } +// +// if (streetname.IndexOf("містечко ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "містечко"); +// } +// +// if (streetname.IndexOf("в’їзд ", StringComparison.Ordinal) != -1) +// { +// return (streetname.Substring(streetname.IndexOf(" ", StringComparison.Ordinal) + 1), "в’їзд"); +// } +// +// return (string.Empty, string.Empty); +// } +// +// // Following method parses JSON from OSM Nominatim API and returns lat/lon tuple +// private static (string?, string?) ParseJsonToCoordinateTuple(string json) +// { +// var data = JsonConvert.DeserializeObject>>(json); +// +// if (data is null || data.Count == 0) +// { +// return default; +// } +// +// return (data[0]["lat"].ToString(), data[0]["lon"].ToString()); +// } +// } \ No newline at end of file diff --git a/Streetcode/Streetcode.WebApi/appsettings.IntegrationTests.json b/Streetcode/Streetcode.WebApi/appsettings.IntegrationTests.json index 600620bd4..de2a6595b 100644 --- a/Streetcode/Streetcode.WebApi/appsettings.IntegrationTests.json +++ b/Streetcode/Streetcode.WebApi/appsettings.IntegrationTests.json @@ -15,5 +15,13 @@ "ReCaptcha": { "SecretKey": "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe", "Url": "https://www.google.com/recaptcha/api/siteverify" + }, + "EmailConfiguration": { + "From": "streetcodefordev@gmail.com", + "To": "stritkod@gmail.com", + "SmtpServer": "smtp.gmail.com", + "Port": 465, + "Username": "streetcodefordev@gmail.com", + "Password": "" } } diff --git a/Streetcode/Streetcode.XIntegrationTest/Constants/ControllerTests/AuthConstants.cs b/Streetcode/Streetcode.XIntegrationTest/Constants/ControllerTests/AuthConstants.cs index 958661e8c..172cc391e 100644 --- a/Streetcode/Streetcode.XIntegrationTest/Constants/ControllerTests/AuthConstants.cs +++ b/Streetcode/Streetcode.XIntegrationTest/Constants/ControllerTests/AuthConstants.cs @@ -33,7 +33,9 @@ internal static class AuthConstants Name = "User_Admin", Surname = "User_Admin", Email = "user@admin.com", + NormalizedEmail = "USER@ADMIN.COM", UserName = "User_Admin_T", + NormalizedUserName = "USER_ADMIN_T", RefreshToken = "User_Admin_Refresh_Token", RefreshTokenExpiry = DateTime.Now.AddDays(1), }; @@ -44,7 +46,9 @@ internal static class AuthConstants Name = "User_User", Surname = "User_User", Email = "user@user.com", + NormalizedEmail = "USER@USER.COM", UserName = "User_User_T", + NormalizedUserName = "User_User_T", RefreshToken = "User_User_Refresh_Token", RefreshTokenExpiry = DateTime.Now.AddDays(1), }; diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/AdditionalContent/TagControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/AdditionalContent/TagControllerTests.cs index 070a959c1..6f1d962fe 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/AdditionalContent/TagControllerTests.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/AdditionalContent/TagControllerTests.cs @@ -9,16 +9,15 @@ using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.AdditionalContent.Tag.Create; using Streetcode.BLL.MediatR.AdditionalContent.Tag.Delete; -using Streetcode.BLL.MediatR.AdditionalContent.Tag.GetAll; using Streetcode.BLL.MediatR.AdditionalContent.Tag.Update; using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Streetcode; -using Streetcode.DAL.Entities.Streetcode.TextContent; using Streetcode.DAL.Repositories.Interfaces.AdditionalContent; using Streetcode.DAL.Repositories.Interfaces.Base; using Streetcode.XIntegrationTest.Base; using Streetcode.XIntegrationTest.ControllerTests.BaseController; using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; using Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.AdditionalContent.Tag; using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Tag; using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.AdditionalContent; diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/AdditionalContent/TeamPositionsControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/AdditionalContent/TeamPositionsControllerTests.cs index aea01d751..0e58cec33 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/AdditionalContent/TeamPositionsControllerTests.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/AdditionalContent/TeamPositionsControllerTests.cs @@ -18,6 +18,7 @@ using Streetcode.XIntegrationTest.ControllerTests.BaseController; using Streetcode.XIntegrationTest.ControllerTests.Utils; using Streetcode.XIntegrationTest.ControllerTests.Utils.AdditionalContent.Positions; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Additional; using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.AdditionalContent; using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.MediaExtracter.Image; @@ -42,8 +43,8 @@ public TeamPositionsControllerTests(CustomWebApplicationFactory factory int uniqueId = UniqueNumberGenerator.GenerateInt(); this.testCreatePosition = TeamPositionsExtracter.Extract(uniqueId); this.testUpdatePosition = TeamPositionsExtracter.Extract(uniqueId); - this.testTeamMemberImage = ImageExtracter.Extract(1); - this.testTeamMember = TeamMemberExtracter.Extract(uniqueId); + this.testTeamMemberImage = ImageExtracter.Extract(uniqueId); + this.testTeamMember = TeamMemberExtracter.Extract(uniqueId, this.testTeamMemberImage.Id); this.testStreetcodeContent = StreetcodeContentExtracter .Extract( uniqueId, diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Analytics/StatisticRecordControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Analytics/StatisticRecordControllerTests.cs new file mode 100644 index 000000000..62f550e3d --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Analytics/StatisticRecordControllerTests.cs @@ -0,0 +1,192 @@ +using System.Net; +using Streetcode.BLL.DTO.Analytics; +using Streetcode.DAL.Entities.Analytics; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Analytics; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Analytics; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Analytics; + +[Collection("Authorization")] +public class StatisticRecordControllerTests : BaseAuthorizationControllerTests +{ + private readonly StatisticRecord _statisticRecord; + + public StatisticRecordControllerTests(CustomWebApplicationFactory factory, TokenStorage tokenStorage) + : base(factory, "/api/StatisticRecord", tokenStorage) + { + var uniqueStreetcodeId = UniqueNumberGenerator.GenerateInt(); + var uniqueStatisticRecordId = UniqueNumberGenerator.GenerateInt(); + StreetcodeContentExtracter + .Extract( + uniqueStreetcodeId, + uniqueStreetcodeId, + Guid.NewGuid().ToString()); + _statisticRecord = StatisticRecordExtracter.Extract(uniqueStatisticRecordId, uniqueStreetcodeId); + } + + [Fact] + public async Task Update_ValidId_ReturnsSuccessStatusCode() + { + // Arrange + var validId = _statisticRecord.QrId; + + // Act + var response = await Client.Update(validId, TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + public async Task Update_InvalidId_ReturnsBadRequest() + { + // Arrange + var invalidId = -9999; + + // Act + var response = await Client.Update(invalidId, TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + public async Task GetAll_ValidRequest_ReturnsSuccessStatusCode() + { + // Act + var response = await Client.GetAll(); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + } + + [Fact] + public async Task GetByQrId_ValidQrId_ReturnsSuccessStatusCode() + { + // Arrange + var validQrId = _statisticRecord.QrId; + + // Act + var response = await Client.GetByQrId(validQrId); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + } + + [Fact] + public async Task GetByQrId_InvalidQrId_ReturnsBadRequest() + { + // Arrange + var validQrId = -9999; + + // Act + var response = await Client.GetByQrId(validQrId); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + Assert.Null(returnedValue); + } + + [Fact] + public async Task ExistByQrId_ValidQrId_ReturnsSuccessStatusCode() + { + // Arrange + var validQrId = _statisticRecord.QrId; + + // Act + var response = await Client.ExistByQrId(validQrId); + bool.TryParse(response.Content, out bool result); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.True(result); + } + + [Fact] + public async Task ExistByQrId_InvalidQrId_ReturnsFalse() + { + // Arrange + var validQrId = -9999; + + // Act + var response = await Client.ExistByQrId(validQrId); + bool.TryParse(response.Content, out bool result); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.False(result); + } + + [Fact] + public async Task GetAllByStreetcodeId_ValidStreetcodeId_ReturnsSuccessStatusCode() + { + // Arrange + var streetcodeId = _statisticRecord.StreetcodeId; + + // Act + var response = await Client.GetAllByStreetcodeId(streetcodeId); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + public async Task GetAllByStreetcodeId_InvalidStreetcodeId_ReturnsBadRequest() + { + // Arrange + var streetcodeId = -9999; + + // Act + var response = await Client.GetAllByStreetcodeId(streetcodeId); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + public async Task Delete_ValidId_ReturnsSuccessStatusCode() + { + // Arrange + var id = _statisticRecord.QrId; + + // Act + var response = await Client.Delete(id, TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + public async Task Delete_InvalidId_ReturnsBadRequest() + { + // Arrange + var id = -9999; + + // Act + var response = await Client.Delete(id, TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + StatisticRecordExtracter.Remove(_statisticRecord); + } + + base.Dispose(disposing); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Authentication/AuthControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Authentication/AuthControllerTests.cs index a76754e6d..08db6b34d 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Authentication/AuthControllerTests.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Authentication/AuthControllerTests.cs @@ -1,44 +1,52 @@ -using Streetcode.BLL.DTO.Authentication.Login; +using System.Net; +using Moq; +using Streetcode.BLL.DTO.Authentication.GoogleLogin; +using Streetcode.BLL.DTO.Authentication.Login; using Streetcode.BLL.DTO.Authentication.RefreshToken; using Streetcode.DAL.Entities.Users; using Streetcode.DAL.Enums; using Streetcode.XIntegrationTest.ControllerTests.BaseController; using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; using Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Authentication; using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Authentication; using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Authentication; +using Xunit; namespace Streetcode.XIntegrationTest.ControllerTests.Authentication { - using System.Net; - using Xunit; - [Collection("Authorization")] - public class AuthControllerTests : BaseAuthorizationControllerTests, IClassFixture> + public class AuthControllerTests : BaseAuthorizationControllerTests { - private readonly User testUser; - private readonly string testPassword; + private readonly User _testUser; + private readonly string _testPassword; + private readonly CustomWebApplicationFactory _factory; public AuthControllerTests(CustomWebApplicationFactory factory, TokenStorage tokenStorage) : base(factory, "/api/Auth", tokenStorage) { - (this.testUser, this.testPassword) = UserExtracter.Extract( + _factory = factory; + _factory.GoogleServiceMock.Reset(); + _factory.EmailServiceMock.Reset(); + + TokenStorage = new TokenStorage(); + (_testUser, _testPassword) = UserExtracter.Extract( userId: Guid.NewGuid().ToString(), userName: Guid.NewGuid().ToString(), - password: this.GenerateTestPassword(), + password: GenerateTestPassword(), nameof(UserRole.User), nameof(UserRole.Admin)); } [Fact] [ExtractRegisterRequest] - public async Task Register_ReturnsSuccessStatusCode() + public async Task Register_ValidInput_ReturnsSuccessStatusCode() { // Arrange. var registerRequest = ExtractRegisterRequestAttribute.RegisterRequest; // Act. - var response = await this.Client.Register(registerRequest); + var response = await Client.Register(registerRequest); // Assert. Assert.Equal(HttpStatusCode.OK, response.StatusCode); @@ -46,14 +54,14 @@ public async Task Register_ReturnsSuccessStatusCode() [Fact] [ExtractRegisterRequest] - public async Task Register_InvalidInputData_Returns404BadRequest() + public async Task Register_InvalidInputData_ReturnsBadRequest() { // Arrange. var registerRequest = ExtractRegisterRequestAttribute.RegisterRequest; registerRequest.Email = string.Empty; // Act. - var response = await this.Client.Register(registerRequest); + var response = await Client.Register(registerRequest); // Assert. Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); @@ -61,58 +69,58 @@ public async Task Register_InvalidInputData_Returns404BadRequest() [Fact] [ExtractRegisterRequest] - public async Task Register_WithGivenEmailAlreadyInDatabase_Returns404BadRequest() + public async Task Register_EmailAlreadyExists_ReturnsBadRequest() { // Arrange. var registerRequest = ExtractRegisterRequestAttribute.RegisterRequest; - registerRequest.Email = this.testUser.Email!; + registerRequest.Email = _testUser.Email!; // Act. - var response = await this.Client.Register(registerRequest); + var response = await Client.Register(registerRequest); // Assert. Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } [Fact] - public async Task Login_ReturnsSuccessStatusCode() + public async Task Login_ValidInput_ReturnsSuccessStatusCode() { // Arrange. - LoginRequestDTO loginRequest = this.GetLoginRequestDTO(); + LoginRequestDTO loginRequest = GetLoginRequestDTO(); // Act. - var response = await this.Client.Login(loginRequest); + var response = await Client.Login(loginRequest); // Assert. Assert.Equal(HttpStatusCode.OK, response.StatusCode); } [Fact] - public async Task Login_InvalidInputData_Returns404BadRequest() + public async Task Login_InvalidInputData_ReturnsBadRequest() { // Arrange. - LoginRequestDTO loginRequest = this.GetLoginRequestDTO(); + LoginRequestDTO loginRequest = GetLoginRequestDTO(); loginRequest.Login = string.Empty; // Act. - var response = await this.Client.Login(loginRequest); + var response = await Client.Login(loginRequest); // Assert. Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } [Fact] - public async Task RefreshToken_ReturnsSuccess() + public async Task RefreshToken_ValidTokens_ReturnsSuccess() { // Arrange. RefreshTokenRequestDTO refreshTokenRequestDTO = new RefreshTokenRequestDTO() { - AccessToken = this.TokenStorage.UserAccessToken, - RefreshToken = this.TokenStorage.UserRefreshToken, + AccessToken = TokenStorage.UserAccessToken, + RefreshToken = TokenStorage.UserRefreshToken, }; // Act. - var response = await this.Client.RefreshToken(refreshTokenRequestDTO); + var response = await Client.RefreshToken(refreshTokenRequestDTO); // Assert. Assert.Equal(HttpStatusCode.OK, response.StatusCode); @@ -128,7 +136,7 @@ public async Task RefreshToken_InvalidAccessToken_ReturnsBadRequest() }; // Act. - var response = await this.Client.RefreshToken(refreshTokenRequestDTO); + var response = await Client.RefreshToken(refreshTokenRequestDTO); // Assert. Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); @@ -140,22 +148,128 @@ public async Task RefreshToken_InvalidRefreshToken_ReturnsUnauthorized() // Arrange. RefreshTokenRequestDTO refreshTokenRequestDTO = new RefreshTokenRequestDTO() { - AccessToken = this.TokenStorage.UserAccessToken, + AccessToken = TokenStorage.UserAccessToken, RefreshToken = "invalid_token", }; // Act. - var response = await this.Client.RefreshToken(refreshTokenRequestDTO); + var response = await Client.RefreshToken(refreshTokenRequestDTO); // Assert. Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); } + [Fact] + public async Task Logout_InvalidToken_ReturnsUnauthorized() + { + // Act. + var response = await Client.Logout(); + + // Assert. + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + public async Task Logout_ValidToken_ReturnsSuccessStatusCode() + { + // Arrange. + await TokenStorage.GenerateNewTokens(_testUser); + var validToken = TokenStorage.UserAccessToken; + + // Act. + var response = await Client.Logout(validToken); + + // Assert. + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + public async Task Logout_InvalidUserId_ReturnsBadRequest() + { + // Arrange. + _testUser.UserName = "invalid_username"; + _testUser.NormalizedUserName = "INVALID_USERNAME"; + await TokenStorage.GenerateNewTokens(_testUser); + var invalidToken = TokenStorage.UserAccessToken; + + // Act. + var response = await Client.Logout(invalidToken); + + // Assert. + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + public async Task LoginGoogle_ValidToken_ReturnsSuccessAndUserData() + { + // Arrange + var validToken = "valid_google_id_token"; + var request = new GoogleLoginRequest + { + IdToken = validToken, + }; + _factory.SetupMockGoogleLogin(_testUser, validToken); + + // Act + var response = await Client.GoogleLogin(request); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + _factory.GoogleServiceMock.Verify(es => es.ValidateGoogleToken(It.IsAny()), Times.Once); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + Assert.NotNull(returnedValue.User); + Assert.False(string.IsNullOrEmpty(returnedValue.AccessToken)); + } + + [Fact] + public async Task LoginGoogle_InvalidToken_ReturnsBadRequest() + { + // Arrange + var invalidToken = "invalid_google_id_token"; + var request = new GoogleLoginRequest + { + IdToken = invalidToken, + }; + _factory.SetupMockGoogleLogin(_testUser); + + // Act + var response = await Client.GoogleLogin(request); + + // Assert + _factory.GoogleServiceMock.Verify(es => es.ValidateGoogleToken(It.IsAny()), Times.Once); + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + public async Task LoginGoogle_NewUser_CreatesAccountAndReturnsToken() + { + // Arrange + var newUserToken = "new_google_id_token"; + var request = new GoogleLoginRequest + { + IdToken = newUserToken, + }; + _testUser.Email = "newemail@test.com"; + _factory.SetupMockGoogleLogin(_testUser, newUserToken); + + // Act + var response = await Client.GoogleLogin(request); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + _factory.GoogleServiceMock.Verify(es => es.ValidateGoogleToken(It.IsAny()), Times.Once); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + Assert.NotNull(returnedValue.User); + Assert.False(string.IsNullOrEmpty(returnedValue.AccessToken)); + } + protected override void Dispose(bool disposing) { if (disposing) { - UserExtracter.Remove(this.testUser); + UserExtracter.Remove(_testUser); } base.Dispose(disposing); @@ -165,8 +279,8 @@ private LoginRequestDTO GetLoginRequestDTO() { return new LoginRequestDTO() { - Login = this.testUser.Email!, - Password = this.testPassword, + Login = _testUser.Email!, + Password = _testPassword, CaptchaToken = "test_captcha_token", }; } diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/BaseController/BaseAuthorizationControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/BaseController/BaseAuthorizationControllerTests.cs index b5c31f808..e23c08834 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/BaseController/BaseAuthorizationControllerTests.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/BaseController/BaseAuthorizationControllerTests.cs @@ -1,4 +1,5 @@ using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; namespace Streetcode.XIntegrationTest.ControllerTests.BaseController { @@ -10,16 +11,6 @@ public BaseAuthorizationControllerTests(CustomWebApplicationFactory fac this.TokenStorage = tokenStorage; } - protected TokenStorage TokenStorage { get; } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - this.TokenStorage.Dispose(); - } - - base.Dispose(disposing); - } + protected TokenStorage TokenStorage { get; init; } } } diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Email/EmailControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Email/EmailControllerTests.cs new file mode 100644 index 000000000..de58f0687 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Email/EmailControllerTests.cs @@ -0,0 +1,47 @@ +using System.Net; +using Moq; +using Streetcode.BLL.DTO.Email; +using Streetcode.BLL.Models.Email.Messages.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Email; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Email; + +public class EmailControllerTests : BaseControllerTests +{ + private readonly CustomWebApplicationFactory _factory; + + public EmailControllerTests(CustomWebApplicationFactory factory) + : base(factory, "/api/Email") + { + _factory = factory; + } + + [Fact] + public async Task Send_ValidData_ReturnsSuccessStatusCode() + { + // Arrange + var emailDto = GetEmailDTO(); + _factory.SetupMockEmailService(); + + // Act + var response = await Client.Send(emailDto); + + // Assert + _factory.EmailServiceMock.Verify(es => es.SendEmailAsync(It.IsAny()), Times.Once); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + private EmailDTO GetEmailDTO() + { + return new EmailDTO + { + From = "test@test.com", + Source = "test_source", + Content = "test_content", + Token = "test_token", + }; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Jobs/Create/JobCreateControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Jobs/Create/JobCreateControllerTests.cs index 90d24a912..8feba6d7f 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Jobs/Create/JobCreateControllerTests.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Jobs/Create/JobCreateControllerTests.cs @@ -4,9 +4,9 @@ using Streetcode.XIntegrationTest.Base; using Streetcode.XIntegrationTest.ControllerTests.BaseController; using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; using Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Job; using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Job; -using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Authentication; using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Job; using Xunit; diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Media/Images/ImageControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Media/Images/ImageControllerTests.cs index 846508ae8..7412de74a 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Media/Images/ImageControllerTests.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Media/Images/ImageControllerTests.cs @@ -29,17 +29,6 @@ public ImageControllerTests(CustomWebApplicationFactory factory) Guid.NewGuid().ToString()); } - [Fact] - public async Task GetAllReturn_SuccessStatusCode() - { - var response = await this.Client.GetAllAsync(); - var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); - - Assert.Multiple( - () => Assert.True(response.IsSuccessStatusCode), - () => Assert.NotNull(returnedValue)); - } - [Fact] public async Task GetById_ReturnSuccessStatusCode() { diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/News/NewsGetAllControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/News/NewsGetAllControllerTests.cs index 609b14a93..4c923d82a 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/News/NewsGetAllControllerTests.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/News/NewsGetAllControllerTests.cs @@ -3,14 +3,13 @@ using Streetcode.XIntegrationTest.ControllerTests.BaseController; using Streetcode.XIntegrationTest.ControllerTests.Utils; using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.News; -using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.AdditionalContent; using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.News; using Xunit; namespace Streetcode.XIntegrationTest.ControllerTests.News { [Collection("News")] - public class NewsGetAllControllerTests : BaseControllerTests, IClassFixture> + public class NewsGetAllControllerTests : BaseControllerTests { private DAL.Entities.News.News testNews; diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Partners/PartnersControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Partners/PartnersControllerTests.cs index c4d5ea696..f09bf026e 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Partners/PartnersControllerTests.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Partners/PartnersControllerTests.cs @@ -7,6 +7,7 @@ using Streetcode.XIntegrationTest.Base; using Streetcode.XIntegrationTest.ControllerTests.BaseController; using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Partners; using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter; using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.AdditionalContent; diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/RelatedFigureControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/RelatedFigureControllerTests.cs new file mode 100644 index 000000000..da8b61be1 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/RelatedFigureControllerTests.cs @@ -0,0 +1,193 @@ +using System.Net; +using Streetcode.BLL.DTO.Streetcode.RelatedFigure; +using Streetcode.DAL.Entities.AdditionalContent; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; +using Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.RelatedFigure; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.StreetCode; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.AdditionalContent; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.RelatedFigure; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Streetcode; + +[Collection("Authorization")] +public class RelatedFigureControllerTests : BaseAuthorizationControllerTests +{ + private readonly StreetcodeContent _testStreetcodeContent1; + private readonly StreetcodeContent _testStreetcodeContent2; + private readonly RelatedFigure _testRelatedFigure; + private readonly Tag _testTag; + + public RelatedFigureControllerTests( + CustomWebApplicationFactory factory, + TokenStorage tokenStorage) + : base(factory, "/api/RelatedFigure", tokenStorage) + { + (_testStreetcodeContent1, _testStreetcodeContent2, _testRelatedFigure, _testTag) = RelatedFigureExtracter.ExtractTestData(); + } + + [Fact] + public async Task GetByStreetcodeId_ReturnSuccessStatusCode() + { + // Act + var response = await Client.GetByStreetcodeId(_testStreetcodeContent1.Id); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.Multiple(() => + { + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(returnedValue); + }); + } + + [Fact] + public async Task GetByStreetcodeId_Incorrect_ReturnsBadRequest() + { + // Arrange + const int incorrectId = -100; + + // Act + var response = await Client.GetByStreetcodeId(incorrectId); + + // Assert + Assert.Multiple(() => + { + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + Assert.False(response.IsSuccessStatusCode); + }); + } + + [Fact] + public async Task GetByTagId_ReturnSuccessStatusCode() + { + // Arrange + TagExtracter.AddStreetcodeTagIndex(_testStreetcodeContent1.Id, _testTag.Id); + + // Act + var response = await Client.GetByTagId(_testTag.Id); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.Multiple(() => + { + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(returnedValue); + }); + } + + [Fact] + public async Task GetByTagId_Incorrect_ReturnEmptyList() + { + // Arrange + const int incorrectId = -100; + + // Act + var response = await Client.GetByTagId(incorrectId); + + // Assert + Assert.Multiple(() => + { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.True(response.IsSuccessStatusCode); + Assert.Equal("[]", response.Content); + }); + } + + [Fact] + [ExtractCreateTestRelatedFigure] + public async Task CreateRelatedFigure_ReturnsSuccessStatusCode() + { + // Arrange + var observerId = ExtractCreateTestRelatedFigureAttribute.StreetcodeContent1.Id; + var targetId = ExtractCreateTestRelatedFigureAttribute.StreetcodeContent2.Id; + + // Act + var response = await Client.Create(observerId, targetId, TokenStorage.AdminAccessToken); + + // Assert + Assert.Multiple(() => + { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.True(response.IsSuccessStatusCode); + Assert.Equal("{}", response.Content); + }); + } + + [Fact] + public async Task Create_TokenNotPassed_ReturnsUnauthorized() + { + // Act + var response = await Client.Create(_testStreetcodeContent1.Id, _testStreetcodeContent2.Id); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + public async Task Create_NotAdminTokenPassed_ReturnsForbidden() + { + // Act + var response = await Client.Create(_testStreetcodeContent1.Id, _testStreetcodeContent2.Id, TokenStorage.UserAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + + [Fact] + [ExtractDeleteTestRelatedFigure] + public async Task DeleteRelatedFigure_ReturnsSuccessStatusCode() + { + // Arrange + var observerId = ExtractDeleteTestRelatedFigureAttribute.StreetcodeContent1.Id; + var targetId = ExtractDeleteTestRelatedFigureAttribute.StreetcodeContent2.Id; + + // Act + var response = await Client.Delete(observerId, targetId, TokenStorage.AdminAccessToken); + + // Assert + Assert.Multiple(() => + { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.True(response.IsSuccessStatusCode); + Assert.Equal("{}", response.Content); + }); + } + + [Fact] + public async Task Delete_TokenNotPassed_ReturnsUnauthorized() + { + // Act + var response = await Client.Delete(_testStreetcodeContent1.Id, _testStreetcodeContent2.Id); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + public async Task Delete_NotAdminTokenPassed_ReturnsForbidden() + { + // Act + var response = await Client.Delete(_testStreetcodeContent1.Id, _testStreetcodeContent2.Id, TokenStorage.UserAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + TagExtracter.Remove(_testTag); + RelatedFigureExtracter.Remove(_testRelatedFigure); + StreetcodeContentExtracter.Remove(_testStreetcodeContent1); + StreetcodeContentExtracter.Remove(_testStreetcodeContent2); + } + + base.Dispose(disposing); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/StreetcodeCreateControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/StreetcodeCreateControllerTests.cs index 788c588f3..edcc589ac 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/StreetcodeCreateControllerTests.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/StreetcodeCreateControllerTests.cs @@ -3,71 +3,39 @@ using Streetcode.XIntegrationTest.Base; using Streetcode.XIntegrationTest.ControllerTests.BaseController; using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; using Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode; using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.StreetCode; -using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Job; using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter; using Xunit; namespace Streetcode.XIntegrationTest.ControllerTests.Streetcode { [Collection("Authorization")] - public class StreetcodeCreateControllerTests : BaseAuthorizationControllerTests, IClassFixture> + public class StreetcodeCreateControllerTests : BaseAuthorizationControllerTests { - private readonly StreetcodeContent testStreetcodeContent; + private readonly StreetcodeContent _testStreetcodeContent; public StreetcodeCreateControllerTests(CustomWebApplicationFactory factory, TokenStorage tokenStorage) : base(factory, "/api/Streetcode", tokenStorage) { - int uniqueId = UniqueNumberGenerator.GenerateInt(); - this.testStreetcodeContent = StreetcodeContentExtracter + var uniqueId = UniqueNumberGenerator.GenerateInt(); + _testStreetcodeContent = StreetcodeContentExtracter .Extract( uniqueId, uniqueId, Guid.NewGuid().ToString()); } - [Fact(Skip = "There are no images in the streetcode, so the test will fail without them.")] - [ExtractCreateTestStreetcode] - public async Task Create_ReturnsSuccessStatusCode() - { - // Arrange - var streetcodeCreateDTO = ExtractCreateTestStreetcodeAttribute.StreetcodeForTest; - - // Act - var response = await this.Client.CreateAsync(streetcodeCreateDTO, this.TokenStorage.AdminAccessToken); - - // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - } - - [Fact(Skip = "This test will fail if the previous test fails.")] - [ExtractCreateTestStreetcode] - public async Task Create_CreatesNewStreetcode() - { - // Arrange - var streetcodeCreateDTO = ExtractCreateTestStreetcodeAttribute.StreetcodeForTest; - - // Act - await this.Client.CreateAsync(streetcodeCreateDTO, this.TokenStorage.AdminAccessToken); - var streetcodeId = StreetcodeIndexFetch.GetStreetcodeByIndex(streetcodeCreateDTO.Index); - var getResponse = await this.Client.GetByIdAsync(streetcodeId); - var fetchedStreetcode = CaseIsensitiveJsonDeserializer.Deserialize(getResponse.Content); - - // Assert - Assert.Equal(streetcodeCreateDTO.Title, fetchedStreetcode?.Title); - Assert.Equal(streetcodeCreateDTO.TransliterationUrl, fetchedStreetcode?.TransliterationUrl); - } - [Fact] [ExtractCreateTestStreetcode] public async Task Create_TokenNotPassed_ReturnsUnauthorized() { // Arrange - var streetcodeCreateDTO = ExtractCreateTestStreetcodeAttribute.StreetcodeForTest; + var streetcodeCreateDto = ExtractCreateTestStreetcodeAttribute.StreetcodeForTest; // Act - var response = await this.Client.CreateAsync(streetcodeCreateDTO); + var response = await Client.CreateAsync(streetcodeCreateDto); // Assert Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); @@ -78,10 +46,10 @@ public async Task Create_TokenNotPassed_ReturnsUnauthorized() public async Task Create_NotAdminTokenPassed_ReturnsForbidden() { // Arrange - var streetcodeCreateDTO = ExtractCreateTestStreetcodeAttribute.StreetcodeForTest; + var streetcodeCreateDto = ExtractCreateTestStreetcodeAttribute.StreetcodeForTest; // Act - var response = await this.Client.CreateAsync(streetcodeCreateDTO, this.TokenStorage.UserAccessToken); + var response = await Client.CreateAsync(streetcodeCreateDto, TokenStorage.UserAccessToken); // Assert Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); @@ -92,11 +60,11 @@ public async Task Create_NotAdminTokenPassed_ReturnsForbidden() public async Task Create_WithInvalidData_ReturnsBadRequest() { // Arrange - var streetcodeCreateDTO = ExtractCreateTestStreetcodeAttribute.StreetcodeForTest; - streetcodeCreateDTO.Title = null!; // Invalid data + var streetcodeCreateDto = ExtractCreateTestStreetcodeAttribute.StreetcodeForTest; + streetcodeCreateDto.Title = null!; // Invalid data // Act - var response = await this.Client.CreateAsync(streetcodeCreateDTO, this.TokenStorage.AdminAccessToken); + var response = await Client.CreateAsync(streetcodeCreateDto, TokenStorage.AdminAccessToken); // Assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); @@ -107,11 +75,11 @@ public async Task Create_WithInvalidData_ReturnsBadRequest() public async Task Create_WithExistingStreetcode_ReturnsConflict() { // Arrange - var streetcodeCreateDTO = ExtractCreateTestStreetcodeAttribute.StreetcodeForTest; - streetcodeCreateDTO.Index = this.testStreetcodeContent.Index; + var streetcodeCreateDto = ExtractCreateTestStreetcodeAttribute.StreetcodeForTest; + streetcodeCreateDto.Index = _testStreetcodeContent.Index; // Act - var response = await this.Client.CreateAsync(streetcodeCreateDTO, this.TokenStorage.AdminAccessToken); + var response = await Client.CreateAsync(streetcodeCreateDto, TokenStorage.AdminAccessToken); // Assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); @@ -122,12 +90,12 @@ public async Task Create_WithExistingStreetcode_ReturnsConflict() public async Task Create_WithLongTransliterationUrl_ReturnsBadRequest() { // Arrange - var transliterationUrlMaxLength = 150; - var streetcodeCreateDTO = ExtractCreateTestStreetcodeAttribute.StreetcodeForTest; - streetcodeCreateDTO.TransliterationUrl = new string('a', transliterationUrlMaxLength + 1); + const int transliterationUrlMaxLength = 150; + var streetcodeCreateDto = ExtractCreateTestStreetcodeAttribute.StreetcodeForTest; + streetcodeCreateDto.TransliterationUrl = new string('a', transliterationUrlMaxLength + 1); // Act - var response = await this.Client.CreateAsync(streetcodeCreateDTO, this.TokenStorage.AdminAccessToken); + var response = await Client.CreateAsync(streetcodeCreateDto, TokenStorage.AdminAccessToken); // Assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); @@ -137,7 +105,7 @@ protected override void Dispose(bool disposing) { if (disposing) { - StreetcodeContentExtracter.Remove(this.testStreetcodeContent); + StreetcodeContentExtracter.Remove(_testStreetcodeContent); } base.Dispose(disposing); diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/StreetcodeDeleteControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/StreetcodeDeleteControllerTests.cs new file mode 100644 index 000000000..3b0bcded7 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/StreetcodeDeleteControllerTests.cs @@ -0,0 +1,119 @@ +using System.Net; +using Streetcode.BLL.DTO.Streetcode; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.Delete; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.DeleteSoft; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Enums; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.StreetCode; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Streetcode; + +[Collection("Authorization")] +public class StreetcodeDeleteControllerTests : BaseAuthorizationControllerTests +{ + private readonly StreetcodeContent _testSoftDeleteStreetcodeContent; + private readonly StreetcodeContent _testDeleteStreetcodeContent; + + public StreetcodeDeleteControllerTests( + CustomWebApplicationFactory factory, + TokenStorage tokenStorage) + : base(factory, "/api/Streetcode", tokenStorage) + { + var uniqueId = UniqueNumberGenerator.GenerateInt(); + var uniqueId2 = UniqueNumberGenerator.GenerateInt(); + _testSoftDeleteStreetcodeContent = StreetcodeContentExtracter + .Extract( + uniqueId, + uniqueId, + Guid.NewGuid().ToString()); + _testDeleteStreetcodeContent = StreetcodeContentExtracter + .Extract( + uniqueId2, + uniqueId2, + Guid.NewGuid().ToString()); + } + + [Fact] + public async Task SoftDelete_WithValidId_ShouldReturnSuccess() + { + // Arrange + DeleteSoftStreetcodeCommand command = new (_testSoftDeleteStreetcodeContent.Id); + + // Act + var deleteResponse = await Client.SoftDeleteAsync(command, TokenStorage.AdminAccessToken); + + // Assert + Assert.NotNull(deleteResponse); + Assert.True(deleteResponse.IsSuccessStatusCode); + + var response = await Client.GetByIdAsync(command.Id); + var streetcodeDto = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + Assert.NotNull(streetcodeDto); + Assert.Equal(StreetcodeStatus.Deleted, streetcodeDto.Status); + } + + [Fact] + public async Task SoftDelete_WithNonExistingId_ShouldReturnNotFound() + { + // Arrange + DeleteSoftStreetcodeCommand command = new (5555555); + + // Act + var response = await Client.SoftDeleteAsync(command, TokenStorage.AdminAccessToken); + + // Assert + Assert.NotNull(response); + Assert.False(response.IsSuccessStatusCode); + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + public async Task Delete_WithValidId_ShouldReturnSuccess() + { + // Arrange + DeleteStreetcodeCommand command = new (_testDeleteStreetcodeContent.Id); + + // Act + var deleteResponse = await Client.DeleteAsync(command, TokenStorage.AdminAccessToken); + + // Assert + Assert.NotNull(deleteResponse); + Assert.True(deleteResponse.IsSuccessStatusCode); + + var response = await Client.GetByIdAsync(command.Id); + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + public async Task Delete_WithNonExistingId_ShouldReturnNotFound() + { + // Arrange + DeleteStreetcodeCommand command = new (5555555); + + // Act + var response = await Client.DeleteAsync(command, TokenStorage.AdminAccessToken); + + // Assert + Assert.NotNull(response); + Assert.False(response.IsSuccessStatusCode); + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + StreetcodeContentExtracter.Remove(_testSoftDeleteStreetcodeContent); + StreetcodeContentExtracter.Remove(_testDeleteStreetcodeContent); + } + + base.Dispose(disposing); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/StreetcodeQueriesControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/StreetcodeQueriesControllerTests.cs new file mode 100644 index 000000000..dec67e22f --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/StreetcodeQueriesControllerTests.cs @@ -0,0 +1,591 @@ +using System.Net; +using Newtonsoft.Json; +using Streetcode.BLL.DTO.AdditionalContent.Filter; +using Streetcode.BLL.DTO.Streetcode; +using Streetcode.BLL.DTO.Streetcode.CatalogItem; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Enums; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; +using Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.StreetCode; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Streetcode; + +[Collection("Authorization")] +public class StreetcodeQueriesControllerTests : BaseAuthorizationControllerTests +{ + private readonly StreetcodeContent _testStreetcodeContent; + private readonly StreetcodeContent _testStreetcodeContent2; + private readonly StreetcodeContent _testStreetcodeContent3; + + public StreetcodeQueriesControllerTests(CustomWebApplicationFactory factory, TokenStorage tokenStorage) + : base(factory, "/api/Streetcode", tokenStorage) + { + var uniqueId = UniqueNumberGenerator.GenerateInt(); + var uniqueId2 = UniqueNumberGenerator.GenerateInt(); + var uniqueId3 = UniqueNumberGenerator.GenerateInt(); + _testStreetcodeContent = StreetcodeContentExtracter + .Extract( + uniqueId, + uniqueId, + Guid.NewGuid().ToString()); + _testStreetcodeContent2 = StreetcodeContentExtracter + .Extract( + uniqueId2, + uniqueId2, + Guid.NewGuid().ToString()); + _testStreetcodeContent2.Title = "Another_Title"; + _testStreetcodeContent2.Status = StreetcodeStatus.Draft; + _testStreetcodeContent3 = StreetcodeContentExtracter + .Extract( + uniqueId3, + uniqueId3, + Guid.NewGuid().ToString()); + } + + [Fact] + public async Task GetAllStreetcodes_ReturnsSuccess() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO(); + + // Act + var response = await Client.GetAllAsync(request); + var responseDto = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(response.Content); + Assert.NotEmpty(responseDto!.Streetcodes); + } + + [Fact] + public async Task GetAllStreetcodes_WithPagination_ReturnsCorrectAmount() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO { Page = 1, Amount = 2 }; + + // Act + var response = await Client.GetAllAsync(request); + var responseDto = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(response.Content); + Assert.InRange(responseDto!.Streetcodes.Count(), 1, 2); + } + + [Fact] + public async Task GetAllStreetcodes_WithIncorrectPagination_ReturnsBadRequest() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO { Page = -2, Amount = 2 }; + + // Act + var response = await Client.GetAllAsync(request); + + // Assert + Assert.Multiple( + () => Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode), + () => Assert.False(response.IsSuccessStatusCode)); + } + + [Fact] + public async Task GetAllStreetcodes_WithTitleFilter_ReturnsMatchingResults() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO { Title = "Test_Title" }; + + // Act + var response = await Client.GetAllAsync(request); + var responseDto = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(response.Content); + Assert.All(responseDto!.Streetcodes, s => Assert.Contains("Test_Title", s.Title, StringComparison.OrdinalIgnoreCase)); + } + + [Fact] + public async Task GetAllStreetcodes_WithNonExistingTitleFilter_ReturnsEmptyList() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO { Title = "NonExisting_Title" }; + + // Act + var response = await Client.GetAllAsync(request); + var responseDto = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(response.Content); + Assert.Empty(responseDto!.Streetcodes); + } + + [Fact] + public async Task GetAllStreetcodes_WithSorting_ReturnsSortedResults() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO { Sort = "Title" }; + + // Act + var response = await Client.GetAllAsync(request); + var responseDto = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(response.Content); + var sorted = responseDto!.Streetcodes.OrderBy(s => s.Title).ToList(); + Assert.Equal(sorted, responseDto.Streetcodes.ToList()); + } + + [Fact] + public async Task GetAllStreetcodes_WithIncorrectSortingProp_ReturnsBadRequest() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO { Sort = "IncorrectTitle" }; + + // Act + var response = await Client.GetAllAsync(request); + + // Assert + Assert.Multiple( + () => Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode), + () => Assert.False(response.IsSuccessStatusCode)); + } + + [Fact] + public async Task GetAllStreetcodes_WithFilter_ReturnsFilteredResults() + { + // Arrange + const string testTitle = "Test_Title"; + var request = new GetAllStreetcodesRequestDTO { Filter = $"Title:{testTitle}" }; + + // Act + var response = await Client.GetAllAsync(request); + var responseDto = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(response.Content); + Assert.All(responseDto!.Streetcodes, s => Assert.Equal(testTitle, s.Title)); + } + + [Fact] + public async Task GetAllStreetcodes_WithIncorrectFilter_ReturnsBadRequest() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO { Filter = "IncorrectStatus:Published" }; + + // Act + var response = await Client.GetAllAsync(request); + + // Assert + Assert.Multiple( + () => Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode), + () => Assert.False(response.IsSuccessStatusCode)); + } + + [Fact] + public async Task GetAllPublished_ReturnSuccess() + { + // Act + var response = await Client.GetAllPublishedAsync(); + + // Assert + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + var streetcodes = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + Assert.NotNull(streetcodes); + Assert.NotEmpty(streetcodes); + } + + [Fact] + public async Task GetAllShort_ReturnSuccess() + { + // Act + var response = await Client.GetAllShortAsync(); + + // Assert + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + var streetcodes = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + Assert.NotNull(streetcodes); + Assert.NotEmpty(streetcodes); + } + + [Fact] + public async Task GetAllMainPage_ReturnSuccess() + { + // Act + var response = await Client.GetAllMainPageAsync(); + + // Assert + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + var streetcodes = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + Assert.NotNull(streetcodes); + Assert.NotEmpty(streetcodes); + } + + [Fact] + public async Task GetPageMainPage_ReturnsPaginatedPublishedStreetcodes() + { + // Arrange + const ushort page = 1; + const ushort pageSize = 5; + + // Act + var response = await Client.GetPageMainPageAsync(page, pageSize); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + + var streetcodes = (CaseIsensitiveJsonDeserializer.Deserialize>(response.Content) ?? Array.Empty()).ToList(); + + Assert.NotNull(streetcodes); + Assert.NotEmpty(streetcodes); + Assert.True(streetcodes.Count <= pageSize); + } + + [Fact] + public async Task GetShortById_ReturnSuccess() + { + // Arrange + int id = _testStreetcodeContent.Id; + + // Act + var response = await Client.GetShortByIdAsync(id); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response); + Assert.Equal(id, returnedValue!.Id); + } + + [Fact] + public async Task GetShortById_Incorrect_ReturnBadRequest() + { + // Arrange + int id = -100; + + // Act + var response = await Client.GetShortByIdAsync(id); + + // Assert + Assert.Multiple( + () => Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode), + () => Assert.False(response.IsSuccessStatusCode)); + } + + [Fact] + public async Task GetByFilter_WithExistingSearchQuery_ReturnsFilteredStreetcodes() + { + // Arrange + var request = new StreetcodeFilterRequestDTO + { + SearchQuery = "Test_Title", + }; + + // Act + var response = await Client.GetByFilterAsync(request); + var responseDto = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(responseDto); + } + + [Fact] + public async Task GetByFilter_WithNonExistingSearchQuery_ReturnsEmptyList() + { + // Arrange + var request = new StreetcodeFilterRequestDTO + { + SearchQuery = "NonExisting_Title", + }; + + // Act + var response = await Client.GetByFilterAsync(request); + var responseDto = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(responseDto); + Assert.Empty(responseDto); + } + + [Fact] + public async Task ExistWithIndex_WithExistingIndex_ReturnsTrue() + { + // Arrange + int existingIndex = _testStreetcodeContent.Index; + + // Act + var response = await Client.ExistWithIndexAsync(existingIndex); + var exists = JsonConvert.DeserializeObject(response.Content!); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.True(exists); + } + + [Fact] + public async Task ExistWithIndex_WithNonExistingIndex_ReturnsFalse() + { + // Arrange + const int nonExistingIndex = -99999; + + // Act + var response = await Client.ExistWithIndexAsync(nonExistingIndex); + var exists = JsonConvert.DeserializeObject(response.Content!); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.False(exists); + } + + [Fact] + public async Task ExistWithUrl_WithExistingUrl_ReturnsTrue() + { + // Arrange + string existingUrl = _testStreetcodeContent.TransliterationUrl ?? string.Empty; + + // Act + var response = await Client.ExistWithUrlAsync(existingUrl); + var exists = JsonConvert.DeserializeObject(response.Content!); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.True(exists); + } + + [Fact] + public async Task ExistWithUrl_WithNonExistingUrl_ReturnsFalse() + { + // Arrange + string nonExistingUrl = "non-existing-url"; + + // Act + var response = await Client.ExistWithUrlAsync(nonExistingUrl); + var exists = JsonConvert.DeserializeObject(response.Content!); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.False(exists); + } + + [Fact] + public async Task GetAllCatalog_ReturnsSuccessAndNonEmptyList() + { + // Arrange + const int page = 1; + const int count = 10; + + // Act + var response = await Client.GetAllCatalogAsync(page, count); + var catalogItems = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(catalogItems); + Assert.NotEmpty(catalogItems); + Assert.InRange(catalogItems.Count, 1, 10); + } + + [Fact] + public async Task GetAllCatalog_WithInvalidCount_ReturnsEmptyList() + { + // Arrange + const int page = 1; + const int count = -10; + + // Act + var response = await Client.GetAllCatalogAsync(page, count); + var catalogItems = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(catalogItems); + Assert.Empty(catalogItems); + } + + [Fact] + public async Task GetCount_ReturnsValidCount() + { + // Arrange + bool? onlyPublished = false; + + // Act + var response = await Client.GetCountAsync(onlyPublished); + var count = JsonConvert.DeserializeObject(response.Content!); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + } + + [Fact] + public async Task GetCount_WithOnlyPublished_ReturnsOnlyPublishedCount() + { + // Arrange + bool? onlyPublished = true; + + // Act + var response = await Client.GetCountAsync(onlyPublished); + var count = JsonConvert.DeserializeObject(response.Content!); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + } + + [Fact] + public async Task GetByTransliterationUrl_ReturnsStreetcode_WhenExists() + { + // Arrange + string existingUrl = _testStreetcodeContent.TransliterationUrl ?? string.Empty; + + // Act + var response = await Client.GetByTransliterationUrl(existingUrl); + var streetcode = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(streetcode); + Assert.Equal(existingUrl, streetcode.TransliterationUrl); + } + + [Fact] + public async Task GetByTransliterationUrl_ReturnsBadRequest_WhenNotExists() + { + // Arrange + string nonExistingUrl = "non-exiting-url"; + + // Act + var response = await Client.GetByTransliterationUrl(nonExistingUrl); + + // Assert + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + public async Task GetById_ReturnsStreetcode_WhenExists() + { + // Arrange + int existingId = _testStreetcodeContent.Id; + + // Act + var response = await Client.GetByIdAsync(existingId); + var streetcode = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(streetcode); + Assert.Equal(existingId, streetcode.Id); + } + + [Fact] + public async Task GetById_ReturnsBadRequest_WhenNotExists() + { + // Arrange + const int nonExistingId = -1000; + + // Act + var response = await Client.GetByIdAsync(nonExistingId); + + // Assert + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + [ExtractStatisticRecord] + public async Task GetByQrId_ReturnsCorrectUrl() + { + // Arrange + int qrId = ExtractStatisticRecordAttribute.QrId; + + // Act + var response = await Client.GetByQrIdAsync(qrId); + var responseValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(responseValue); + Assert.Equal(ExtractStatisticRecordAttribute.TestStreetcode.TransliterationUrl, responseValue); + } + + [Fact] + [ExtractStatisticRecord] + public async Task GetByQrId_ReturnsBadRequest_WhenNotExists() + { + // Arrange + const int nonExistingId = -1000; + + // Act + var response = await Client.GetByQrIdAsync(nonExistingId); + + // Assert + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + public async Task GetByIndex_ReturnsStreetcode_WhenExists() + { + // Arrange + int existingId = _testStreetcodeContent.Id; + + // Act + var response = await Client.GetByIndexAsync(existingId); + var streetcode = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(streetcode); + Assert.Equal(existingId, streetcode.Id); + } + + [Fact] + public async Task GetByIndex_ReturnsBadRequest_WhenNotExists() + { + // Arrange + const int nonExistingId = -1000; + + // Act + var response = await Client.GetByIndexAsync(nonExistingId); + + // Assert + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/StreetcodeUpdateControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/StreetcodeUpdateControllerTests.cs index 7cf381a3c..138d6b66b 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/StreetcodeUpdateControllerTests.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/StreetcodeUpdateControllerTests.cs @@ -1,13 +1,16 @@ using System.Net; using Streetcode.BLL.DTO.AdditionalContent.Tag; +using Streetcode.BLL.DTO.Streetcode; using Streetcode.BLL.DTO.Streetcode.Update; using Streetcode.BLL.Enums; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.UpdateStatus; using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Enums; using Streetcode.XIntegrationTest.Base; using Streetcode.XIntegrationTest.ControllerTests.BaseController; using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.StreetCode; -using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Job; using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter; using Xunit; @@ -15,16 +18,16 @@ namespace Streetcode.XIntegrationTest.ControllerTests.Streetcode { [Collection("Authorization")] public class StreetcodeUpdateControllerTests : - BaseAuthorizationControllerTests, IClassFixture> + BaseAuthorizationControllerTests { - private readonly StreetcodeUpdateDTO testStreetcodeUpdateDTO; + private readonly StreetcodeUpdateDTO _testStreetcodeUpdateDto; public StreetcodeUpdateControllerTests(CustomWebApplicationFactory factory, TokenStorage tokenStorage) : base(factory, "/api/Streetcode", tokenStorage) { int uniqueId = UniqueNumberGenerator.GenerateInt(); int uniqueIndex = UniqueNumberGenerator.GenerateIntFromGuidInRange(); - this.testStreetcodeUpdateDTO = StreetcodeUpdateDTOExtracter.Extract( + _testStreetcodeUpdateDto = StreetcodeUpdateDTOExtracter.Extract( uniqueId, uniqueIndex, Guid.NewGuid().ToString()); @@ -33,9 +36,9 @@ public StreetcodeUpdateControllerTests(CustomWebApplicationFactory fact [Fact] public async Task Update_ReturnSuccessStatusCode() { - StreetcodeUpdateDTO updateStreetCodeDTO = this.testStreetcodeUpdateDTO; + StreetcodeUpdateDTO updateStreetCodeDto = _testStreetcodeUpdateDto; - var response = await this.Client.UpdateAsync(updateStreetCodeDTO, this.TokenStorage.AdminAccessToken); + var response = await Client.UpdateAsync(updateStreetCodeDto, TokenStorage.AdminAccessToken); Assert.True(response.IsSuccessStatusCode); } @@ -43,25 +46,30 @@ public async Task Update_ReturnSuccessStatusCode() [Fact] public async Task Update_ChangesTitleAndTransliterationUrl() { - StreetcodeUpdateDTO updateStreetCodeDTO = this.testStreetcodeUpdateDTO; - await this.Client.UpdateAsync(updateStreetCodeDTO, this.TokenStorage.AdminAccessToken); + StreetcodeUpdateDTO updateStreetCodeDto = _testStreetcodeUpdateDto; + await Client.UpdateAsync(updateStreetCodeDto, TokenStorage.AdminAccessToken); - var responseGetByIdUpdated = await this.Client.GetByIdAsync(updateStreetCodeDTO.Id); + var responseGetByIdUpdated = await Client.GetByIdAsync(updateStreetCodeDto.Id); var streetCodeContent = CaseIsensitiveJsonDeserializer.Deserialize(responseGetByIdUpdated.Content); Assert.Multiple(() => { - Assert.Equal(updateStreetCodeDTO.Title, streetCodeContent?.Title); - Assert.Equal(updateStreetCodeDTO.DateString, streetCodeContent?.DateString); + Assert.Equal(updateStreetCodeDto.Title, streetCodeContent?.Title); + Assert.Equal(updateStreetCodeDto.DateString, streetCodeContent?.DateString); }); } [Fact] public async Task Update_WithInvalidId_ReturnsBadRequest() { - StreetcodeUpdateDTO updateStreetCodeDTO = this.testStreetcodeUpdateDTO; - updateStreetCodeDTO.Id++; + StreetcodeUpdateDTO updateStreetCodeDto = new () + { + Id = _testStreetcodeUpdateDto.Id + 1, + Teaser = _testStreetcodeUpdateDto.Teaser, + Title = _testStreetcodeUpdateDto.Title, + DateString = _testStreetcodeUpdateDto.DateString, + }; - var response = await this.Client.UpdateAsync(updateStreetCodeDTO, this.TokenStorage.AdminAccessToken); + var response = await Client.UpdateAsync(updateStreetCodeDto, TokenStorage.AdminAccessToken); Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } @@ -69,44 +77,93 @@ public async Task Update_WithInvalidId_ReturnsBadRequest() [Fact] public async Task Update_WithInvalidData_ReturnsBadRequest() { - StreetcodeUpdateDTO updateStreetCodeDTO = this.testStreetcodeUpdateDTO; - updateStreetCodeDTO.Title = null!; // Invalid data + StreetcodeUpdateDTO updateStreetCodeDto = _testStreetcodeUpdateDto; + updateStreetCodeDto.Title = null!; // Invalid data - var response = await this.Client.UpdateAsync(updateStreetCodeDTO, this.TokenStorage.AdminAccessToken); + var response = await Client.UpdateAsync(updateStreetCodeDto, TokenStorage.AdminAccessToken); Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } [Fact] public async Task Update_WithInvalidTags_ReturnsBadRequest() { - StreetcodeUpdateDTO updateStreetCodeDTO = this.testStreetcodeUpdateDTO; - // Invalid tag data - updateStreetCodeDTO.Tags = new List + _testStreetcodeUpdateDto.Tags = new List { - new StreetcodeTagUpdateDTO + new StreetcodeTagUpdateDTO() { Id = 9999, // Non-existent tag ID Title = "Invalid Tag", IsVisible = true, Index = 0, - StreetcodeId = updateStreetCodeDTO.Id, + StreetcodeId = _testStreetcodeUpdateDto.Id, ModelState = ModelState.Updated, }, }; - var response = await this.Client.UpdateAsync(updateStreetCodeDTO, this.TokenStorage.AdminAccessToken); + var response = await Client.UpdateAsync(_testStreetcodeUpdateDto, TokenStorage.AdminAccessToken); Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } - protected override void Dispose(bool disposing) + [Fact] + public async Task PatchStage_UpdatesStatusSuccessfully() { - if (disposing) - { - StreetcodeUpdateDTOExtracter.Remove(this.testStreetcodeUpdateDTO); - } + // Arrange + UpdateStatusStreetcodeByIdCommand request = new (_testStreetcodeUpdateDto.Id, StreetcodeStatus.Draft); + + // Act + var response = await Client.PatchStageAsync(request, TokenStorage.AdminAccessToken); + + // Assert + Assert.NotNull(response); + Assert.True(response.IsSuccessStatusCode); + + var updatedResponse = await Client.GetByIdAsync(request.Id); + var updatedStreetcode = CaseIsensitiveJsonDeserializer.Deserialize(updatedResponse.Content); + Assert.NotNull(updatedStreetcode); + Assert.Equal(request.Status, updatedStreetcode.Status); + } + + [Fact] + public async Task PatchStage_ReturnsUnauthorized_WhenNoAuthToken() + { + // Arrange + UpdateStatusStreetcodeByIdCommand request = new (_testStreetcodeUpdateDto.Id, StreetcodeStatus.Published); + + // Act + var response = await Client.PatchStageAsync(request); + + // Assert + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + public async Task PatchStage_ReturnsBadRequest_WhenStreetcodeNotExists() + { + // Arrange + UpdateStatusStreetcodeByIdCommand request = new (-1999, StreetcodeStatus.Published); + + // Act + var response = await Client.PatchStageAsync(request, TokenStorage.AdminAccessToken); + + // Assert + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + public async Task PatchStage_ReturnsForbidden_WhenUserAccessToken() + { + // Arrange + UpdateStatusStreetcodeByIdCommand request = new (_testStreetcodeUpdateDto.Id, StreetcodeStatus.Published); + + // Act + var response = await Client.PatchStageAsync(request, TokenStorage.UserAccessToken); - base.Dispose(disposing); + // Assert + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); } } } \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/TextContent/FactControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/TextContent/FactControllerTests.cs new file mode 100644 index 000000000..0a1ac08ba --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/TextContent/FactControllerTests.cs @@ -0,0 +1,308 @@ +using System.Net; +using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; +using Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.TextContent.Facts; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.StreetCode.TextContent; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.TextContent; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Streetcode.TextContent; + +[Collection("Authorization")] +public class FactControllerTests : BaseAuthorizationControllerTests +{ + private readonly Fact _testFact; + + public FactControllerTests(CustomWebApplicationFactory factory, TokenStorage tokenStorage) + : base(factory, "/api/Fact", tokenStorage) + { + var factId = UniqueNumberGenerator.GenerateInt(); + _testFact = FactExtracter.Extract(factId); + } + + [Fact] + public async Task GetAll_ShouldReturnSuccessStatusCode_WhenFactsReceived() + { + // Act + var response = await this.Client.GetAllAsync(); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + } + + [Fact] + public async Task GetById_ShouldReturnSuccessStatusCode_WhenIdIsValid() + { + // Arrange + var factId = _testFact.Id; + + // Act + var response = await this.Client.GetByIdAsync(factId); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + Assert.Multiple( + () => Assert.Equal(_testFact.Id, returnedValue.Id), + () => Assert.Equal(_testFact.Title, returnedValue.Title), + () => Assert.Equal(_testFact.ImageId, returnedValue.ImageId), + () => Assert.Equal(_testFact.FactContent, returnedValue.FactContent), + () => Assert.Equal(_testFact.Index, returnedValue.Index)); + } + + [Fact] + public async Task GetById_ShouldReturnBadRequest_WhenIdIsNotValid() + { + // Arrange + const int factId = int.MinValue; + + // Act + var response = await this.Client.GetByIdAsync(factId); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + Assert.Null(returnedValue); + } + + [Fact] + public async Task GetByStreetcodeId_ShouldReturnSuccessStatusCode_WhenIdIsValid() + { + // Arrange + var factStreetcodeId = _testFact.StreetcodeId; + + // Act + var response = await this.Client.GetByStreetcodeId(factStreetcodeId); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + var returnedValueList = returnedValue!.ToList(); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + Assert.Multiple( + () => Assert.Equal(_testFact.Id, returnedValueList[0].Id), + () => Assert.Equal(_testFact.Title, returnedValueList[0].Title), + () => Assert.Equal(_testFact.ImageId, returnedValueList[0].ImageId), + () => Assert.Equal(_testFact.FactContent, returnedValueList[0].FactContent), + () => Assert.Equal(_testFact.Index, returnedValueList[0].Index)); + } + + [Fact] + public async Task GetByStreetcodeId_ShouldReturnBadRequest_WhenIdIsNotValid() + { + // Arrange + const int factStreetcodeId = int.MinValue; + + // Act + var response = await this.Client.GetByStreetcodeId(factStreetcodeId); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + [ExtractCreateTestFact] + public async Task Create_ShouldReturnSuccessStatusCode_WhenFactAdded() + { + // Arrange + var factCreateDto = ExtractCreateTestFactAttribute.FactCreateDtoForTest; + + // Act + var response = await this.Client.Create(factCreateDto, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("{}", response.Content); + } + + [Fact] + [ExtractCreateTestFact] + public async Task Create_ShouldReturnFail_WhenFactIsInvalid() + { + // Arrange + var factCreateDto = ExtractCreateTestFactAttribute.FactCreateDtoForTest; + factCreateDto.Title = null!; + + // Act + var response = await this.Client.Create(factCreateDto, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(0, (int)response.StatusCode); + } + + [Fact] + [ExtractCreateTestFact] + public async Task Create_ShouldReturnUnauthorized_WhenTokenIsAbsent() + { + // Arrange + var factCreateDto = ExtractCreateTestFactAttribute.FactCreateDtoForTest; + + // Act + var response = await this.Client.Create(factCreateDto); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + [ExtractCreateTestFact] + public async Task Create_ShouldReturnForbidden_WhenUserIsNotAdmin() + { + // Arrange + var factCreateDto = ExtractCreateTestFactAttribute.FactCreateDtoForTest; + + // Act + var response = await this.Client.Create(factCreateDto, this.TokenStorage.UserAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + + [Fact] + [ExtractUpdateTestFact] + public async Task Update_ShouldReturnSuccessStatusCode_WhenFactUpdated() + { + // Arrange + var factUpdateDto = ExtractUpdateTestFactAttribute.FactUpdateDtoForTest; + factUpdateDto.Id = _testFact.Id; + + // Act + var response = await this.Client.Update(_testFact.Id, factUpdateDto, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(0, (int)response.StatusCode); + } + + [Fact] + [ExtractUpdateTestFact] + public async Task Update_ShouldReturnFail_WhenIdNotExists() + { + // Arrange + var factUpdateDto = ExtractUpdateTestFactAttribute.FactUpdateDtoForTest; + factUpdateDto.Id = int.MinValue; + + // Act + var response = await this.Client.Update(int.MinValue, factUpdateDto, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(0, (int)response.StatusCode); + } + + [Fact] + [ExtractUpdateTestFact] + public async Task Update_ShouldReturnFail_WhenFactIsInvalid() + { + // Arrange + var factUpdateDto = ExtractUpdateTestFactAttribute.FactUpdateDtoForTest; + factUpdateDto.Id = _testFact.Id; + factUpdateDto.Title = null!; + + // Act + var response = await this.Client.Update(_testFact.Id, factUpdateDto, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(0, (int)response.StatusCode); + } + + [Fact] + [ExtractUpdateTestFact] + public async Task Update_ShouldReturnUnauthorized_WhenTokenIsAbsent() + { + // Arrange + var factUpdateDto = ExtractUpdateTestFactAttribute.FactUpdateDtoForTest; + factUpdateDto.Id = _testFact.Id; + + // Act + var response = await this.Client.Update(_testFact.Id, factUpdateDto); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + [ExtractUpdateTestFact] + public async Task Update_ShouldReturnForbidden_WhenUserIsNotAdmin() + { + // Arrange + var factUpdateDto = ExtractUpdateTestFactAttribute.FactUpdateDtoForTest; + + // Act + var response = await this.Client.Update(_testFact.Id, factUpdateDto, this.TokenStorage.UserAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + + [Fact] + [ExtractDeleteTestFact] + public async Task Delete_ShouldReturnSuccessStatusCode_WhenFactExists() + { + // Arrange + var factId = ExtractDeleteTestFactAttribute.FactForTest.Id; + + // Act + var response = await this.Client.Delete(factId, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("{}", response.Content); + } + + [Fact] + public async Task Delete_ShouldReturnBadRequest_WhenIdNotExists() + { + // Arrange + const int factId = int.MinValue; + + // Act + var response = await this.Client.Delete(factId, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + [ExtractDeleteTestFact] + public async Task Delete_ShouldReturnUnauthorized_WhenTokenIsAbsent() + { + // Arrange + var factId = ExtractDeleteTestFactAttribute.FactForTest.Id; + + // Act + var response = await this.Client.Delete(factId); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + [ExtractDeleteTestFact] + public async Task Delete_ShouldReturnForbidden_WhenUserIsNotAdmin() + { + // Arrange + var factId = ExtractDeleteTestFactAttribute.FactForTest.Id; + + // Act + var response = await this.Client.Delete(factId, this.TokenStorage.UserAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + FactExtracter.Remove(_testFact); + } + + base.Dispose(disposing); + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/TextContent/RelatedTermControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/TextContent/RelatedTermControllerTests.cs new file mode 100644 index 000000000..a0d82281f --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/TextContent/RelatedTermControllerTests.cs @@ -0,0 +1,255 @@ +using System.Net; +using Streetcode.BLL.DTO.Streetcode.TextContent; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; +using Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.TextContent.RelatedTerms; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.StreetCode.TextContent; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.TextContent; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Streetcode.TextContent; + +[Collection("Authorization")] +public class RelatedTermControllerTests : BaseAuthorizationControllerTests +{ + private readonly RelatedTerm _testRelatedTerm; + + public RelatedTermControllerTests(CustomWebApplicationFactory factory, TokenStorage tokenStorage) + : base(factory, "/api/RelatedTerm", tokenStorage) + { + var relatedTermId = UniqueNumberGenerator.GenerateInt(); + _testRelatedTerm = RelatedTermExtracter.Extract(relatedTermId); + } + + [Fact] + public async Task GetByTermId_ShouldReturnSuccessStatusCode_WhenRelatedTermsReceived() + { + // Arrange + var relatedTermTermId = _testRelatedTerm.TermId; + + // Act + var response = await this.Client.GetByTermId(relatedTermTermId); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + var returnedValueList = returnedValue!.ToList(); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + Assert.Multiple( + () => Assert.Equal(_testRelatedTerm.Id, returnedValueList[0].Id), + () => Assert.Equal(_testRelatedTerm.Word, returnedValueList[0].Word), + () => Assert.Equal(_testRelatedTerm.TermId, returnedValueList[0].TermId)); + } + + [Fact] + public async Task GetByTermId_ShouldReturnSuccessStatusCode_WhenIdIsNotValid() + { + // Arrange + const int relatedTermTermId = int.MinValue; + + // Act + var response = await this.Client.GetByTermId(relatedTermTermId); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + Assert.Empty(returnedValue); + } + + [Fact] + [ExtractCreateTestRelatedTerm] + public async Task Create_ShouldReturnSuccessStatusCode_WhenRelatedTermAdded() + { + // Arrange + var relatedTermCreateDto = ExtractCreateTestRelatedTermAttribute.RelatedTermCreateDtoForTest; + + // Act + var response = await this.Client.Create(relatedTermCreateDto, this.TokenStorage.AdminAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + Assert.Multiple( + () => Assert.Equal(relatedTermCreateDto.Word, returnedValue.Word), + () => Assert.Equal(relatedTermCreateDto.TermId, returnedValue.TermId)); + } + + [Fact] + [ExtractCreateTestRelatedTerm] + public async Task Create_ShouldReturnFail_WhenRelatedTermIsInvalid() + { + // Arrange + var relatedTermCreateDto = ExtractCreateTestRelatedTermAttribute.RelatedTermCreateDtoForTest; + relatedTermCreateDto.Word = null!; + + // Act + var response = await this.Client.Create(relatedTermCreateDto, this.TokenStorage.AdminAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(0, (int)response.StatusCode); + Assert.Null(returnedValue); + } + + [Fact] + [ExtractCreateTestRelatedTerm] + public async Task Create_ShouldReturnBadRequest_WhenRelatedTermWithWordAlreadyExists() + { + // Arrange + var relatedTermCreateDto = ExtractCreateTestRelatedTermAttribute.RelatedTermCreateDtoForTest; + relatedTermCreateDto.Word = _testRelatedTerm.Word!; + relatedTermCreateDto.TermId = _testRelatedTerm.TermId; + + // Act + var response = await this.Client.Create(relatedTermCreateDto, this.TokenStorage.AdminAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + Assert.Null(returnedValue); + } + + [Fact] + [ExtractCreateTestRelatedTerm] + public async Task Create_ShouldReturnUnauthorized_WhenTokenIsAbsent() + { + // Arrange + var relatedTermCreateDto = ExtractCreateTestRelatedTermAttribute.RelatedTermCreateDtoForTest; + + // Act + var response = await this.Client.Create(relatedTermCreateDto); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Null(returnedValue); + } + + [Fact] + [ExtractCreateTestRelatedTerm] + public async Task Create_ShouldReturnForbidden_WhenUserIsNotAdmin() + { + // Arrange + var relatedTermCreateDto = ExtractCreateTestRelatedTermAttribute.RelatedTermCreateDtoForTest; + + // Act + var response = await this.Client.Create(relatedTermCreateDto, this.TokenStorage.UserAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + Assert.Null(returnedValue); + } + + [Fact] + [ExtractUpdateTestRelatedTerm] + public async Task Update_ShouldReturnUnauthorized_WhenTokenIsAbsent() + { + // Arrange + var relatedTermUpdateDto = ExtractUpdateTestRelatedTermAttribute.RelatedTermUpdateDtoForTest; + relatedTermUpdateDto.Id = _testRelatedTerm.Id; + + // Act + var response = await this.Client.Update(relatedTermUpdateDto.Id, relatedTermUpdateDto); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + [ExtractUpdateTestRelatedTerm] + public async Task Update_ShouldReturnForbidden_WhenUserIsNotAdmin() + { + // Arrange + var relatedTermUpdateDto = ExtractUpdateTestRelatedTermAttribute.RelatedTermUpdateDtoForTest; + relatedTermUpdateDto.Id = _testRelatedTerm.Id; + + // Act + var response = await this.Client.Update(relatedTermUpdateDto.Id, relatedTermUpdateDto, this.TokenStorage.UserAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + + [Fact] + [ExtractDeleteTestRelatedTerm] + public async Task Delete_ShouldReturnSuccessStatusCode_WhenRelatedTermExists() + { + // Arrange + var relatedTerm = ExtractDeleteTestRelatedTermAttribute.RelatedTermForTest; + + // Act + var response = await this.Client.Delete(relatedTerm.Word!, this.TokenStorage.AdminAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + Assert.Multiple( + () => Assert.Equal(relatedTerm.Id, returnedValue.Id), + () => Assert.Equal(relatedTerm.Word, returnedValue.Word), + () => Assert.Equal(relatedTerm.TermId, returnedValue.TermId)); + } + + [Fact] + public async Task Delete_ShouldReturnBadRequest_WhenWordNotExists() + { + // Arrange + const string relatedTermWord = "qwerty"; + + // Act + var response = await this.Client.Delete(relatedTermWord, this.TokenStorage.AdminAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + Assert.Null(returnedValue); + } + + [Fact] + [ExtractDeleteTestRelatedTerm] + public async Task Delete_ShouldReturnUnauthorized_WhenTokenIsAbsent() + { + // Arrange + var relatedTermWord = ExtractDeleteTestRelatedTermAttribute.RelatedTermForTest.Word; + + // Act + var response = await this.Client.Delete(relatedTermWord!); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Null(returnedValue); + } + + [Fact] + [ExtractDeleteTestRelatedTerm] + public async Task Delete_ShouldReturnForbidden_WhenUserIsNotAdmin() + { + // Arrange + var relatedTermWord = ExtractDeleteTestRelatedTermAttribute.RelatedTermForTest.Word; + + // Act + var response = await this.Client.Delete(relatedTermWord!, this.TokenStorage.UserAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + Assert.Null(returnedValue); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + RelatedTermExtracter.Remove(_testRelatedTerm); + } + + base.Dispose(disposing); + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/TextContent/TermControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/TextContent/TermControllerTests.cs new file mode 100644 index 000000000..e6ac9a4d9 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/TextContent/TermControllerTests.cs @@ -0,0 +1,284 @@ +using System.Net; +using Streetcode.BLL.DTO.Streetcode.TextContent; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; +using Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.TextContent.Terms; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.StreetCode.TextContent; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.TextContent; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Streetcode.TextContent; + +[Collection("Authorization")] +public class TermControllerTests : BaseAuthorizationControllerTests +{ + private readonly Term _testTerm; + + public TermControllerTests(CustomWebApplicationFactory factory, TokenStorage tokenStorage) + : base(factory, "/api/Term", tokenStorage) + { + var termId = UniqueNumberGenerator.GenerateInt(); + _testTerm = TermExtracter.Extract(termId); + } + + [Fact] + public async Task GetAll_ShouldReturnSuccessStatusCode_WhenTermsReceived() + { + // Act + var response = await this.Client.GetAllAsync(); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + } + + [Fact] + public async Task GetById_ShouldReturnSuccessStatusCode_WhenIdIsValid() + { + // Arrange + var termId = _testTerm.Id; + + // Act + var response = await this.Client.GetByIdAsync(termId); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + Assert.Multiple( + () => Assert.Equal(_testTerm.Id, returnedValue.Id), + () => Assert.Equal(_testTerm.Title, returnedValue.Title), + () => Assert.Equal(_testTerm.Description, returnedValue.Description)); + } + + [Fact] + public async Task GetById_ShouldReturnBadRequest_WhenIdIsNotValid() + { + // Arrange + const int termId = int.MinValue; + + // Act + var response = await this.Client.GetByIdAsync(termId); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + Assert.Null(returnedValue); + } + + [Fact] + [ExtractCreateTestTerm] + public async Task Create_ShouldReturnSuccessStatusCode_WhenTermAdded() + { + // Arrange + var termCreateDto = ExtractCreateTestTermAttribute.TermCreateDtoForTest; + + // Act + var response = await this.Client.Create(termCreateDto, this.TokenStorage.AdminAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + Assert.Multiple( + () => Assert.Equal(termCreateDto.Title, returnedValue.Title), + () => Assert.Equal(termCreateDto.Description, returnedValue.Description)); + } + + [Fact] + [ExtractCreateTestTerm] + public async Task Create_ShouldReturnFail_WhenTermIsInvalid() + { + // Arrange + var termCreateDto = ExtractCreateTestTermAttribute.TermCreateDtoForTest; + termCreateDto.Title = null!; + + // Act + var response = await this.Client.Create(termCreateDto, this.TokenStorage.AdminAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(0, (int)response.StatusCode); + Assert.Null(returnedValue); + } + + [Fact] + [ExtractCreateTestTerm] + public async Task Create_ShouldReturnUnauthorized_WhenTokenIsAbsent() + { + // Arrange + var termCreateDto = ExtractCreateTestTermAttribute.TermCreateDtoForTest; + + // Act + var response = await this.Client.Create(termCreateDto); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Null(returnedValue); + } + + [Fact] + [ExtractCreateTestTerm] + public async Task Create_ShouldReturnForbidden_WhenUserIsNotAdmin() + { + // Arrange + var termCreateDto = ExtractCreateTestTermAttribute.TermCreateDtoForTest; + + // Act + var response = await this.Client.Create(termCreateDto, this.TokenStorage.UserAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + Assert.Null(returnedValue); + } + + [Fact] + [ExtractUpdateTestTerm] + public async Task Update_ShouldReturnSuccessStatusCode_WhenFactUpdated() + { + // Arrange + var factUpdateDto = ExtractUpdateTestTermAttribute.TermUpdateDtoForTest; + factUpdateDto.Id = _testTerm.Id; + + // Act + var response = await this.Client.Update(factUpdateDto, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("{}", response.Content); + } + + [Fact] + [ExtractUpdateTestTerm] + public async Task Update_ShouldReturnFail_WhenIdNotExists() + { + // Arrange + var factUpdateDto = ExtractUpdateTestTermAttribute.TermUpdateDtoForTest; + factUpdateDto.Id = int.MinValue; + + // Act + var response = await this.Client.Update(factUpdateDto, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(0, (int)response.StatusCode); + } + + [Fact] + [ExtractUpdateTestTerm] + public async Task Update_ShouldReturnFail_WhenFactIsInvalid() + { + // Arrange + var factUpdateDto = ExtractUpdateTestTermAttribute.TermUpdateDtoForTest; + factUpdateDto.Id = _testTerm.Id; + factUpdateDto.Title = null!; + + // Act + var response = await this.Client.Update(factUpdateDto, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(0, (int)response.StatusCode); + } + + [Fact] + [ExtractUpdateTestTerm] + public async Task Update_ShouldReturnUnauthorized_WhenTokenIsAbsent() + { + // Arrange + var factUpdateDto = ExtractUpdateTestTermAttribute.TermUpdateDtoForTest; + factUpdateDto.Id = _testTerm.Id; + + // Act + var response = await this.Client.Update(factUpdateDto); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + [ExtractUpdateTestTerm] + public async Task Update_ShouldReturnForbidden_WhenUserIsNotAdmin() + { + // Arrange + var factUpdateDto = ExtractUpdateTestTermAttribute.TermUpdateDtoForTest; + factUpdateDto.Id = _testTerm.Id; + + // Act + var response = await this.Client.Update(factUpdateDto, this.TokenStorage.UserAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + + [Fact] + [ExtractDeleteTestTerm] + public async Task Delete_ShouldReturnSuccessStatusCode_WhenTermExists() + { + // Arrange + var termId = ExtractDeleteTestTermAttribute.TermForTest.Id; + + // Act + var response = await this.Client.Delete(termId, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("{}", response.Content); + } + + [Fact] + [ExtractDeleteTestTerm] + public async Task Delete_ShouldReturnBadRequest_WhenIdNotExists() + { + // Arrange + const int termId = int.MinValue; + + // Act + var response = await this.Client.Delete(termId, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + [ExtractDeleteTestTerm] + public async Task Delete_ShouldReturnUnauthorized_WhenTokenIsAbsent() + { + // Arrange + var termId = ExtractDeleteTestTermAttribute.TermForTest.Id; + + // Act + var response = await this.Client.Delete(termId); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + [ExtractDeleteTestTerm] + public async Task Delete_ShouldReturnForbidden_WhenUserIsNotAdmin() + { + // Arrange + var termId = ExtractDeleteTestTermAttribute.TermForTest.Id; + + // Act + var response = await this.Client.Delete(termId, this.TokenStorage.UserAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + TermExtracter.Remove(_testTerm); + } + + base.Dispose(disposing); + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/TextContent/TextControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/TextContent/TextControllerTests.cs new file mode 100644 index 000000000..4a1b05bc7 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Streetcode/TextContent/TextControllerTests.cs @@ -0,0 +1,166 @@ +using System.Net; +using Streetcode.BLL.DTO.Streetcode.TextContent.Text; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; +using Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.TextContent.Texts; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.StreetCode.TextContent; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.TextContent; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Streetcode.TextContent; + +[Collection("Authorization")] +public class TextControllerTests : BaseAuthorizationControllerTests +{ + private readonly Text _testText; + + public TextControllerTests(CustomWebApplicationFactory factory, TokenStorage tokenStorage) + : base(factory, "/api/Text", tokenStorage) + { + var textId = UniqueNumberGenerator.GenerateInt(); + _testText = TextExtracter.Extract(textId); + } + + [Fact] + public async Task GetAll_ShouldReturnSuccessStatusCode_WhenTextsReceived() + { + // Act + var response = await this.Client.GetAllAsync(); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + } + + [Fact] + public async Task GetById_ShouldReturnSuccessStatusCode_WhenIdIsValid() + { + // Arrange + var textId = _testText.Id; + + // Act + var response = await this.Client.GetByIdAsync(textId); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + Assert.Multiple( + () => Assert.Equal(_testText.Id, returnedValue.Id), + () => Assert.Equal(_testText.Title, returnedValue.Title), + () => Assert.Equal(_testText.TextContent, returnedValue.TextContent), + () => Assert.Equal(_testText.AdditionalText, returnedValue.AdditionalText), + () => Assert.Equal(_testText.StreetcodeId, returnedValue.StreetcodeId)); + } + + [Fact] + public async Task GetById_ShouldReturnBadRequest_WhenIdIsNotValid() + { + // Arrange + const int textId = int.MinValue; + + // Act + var response = await this.Client.GetByIdAsync(textId); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + Assert.Null(returnedValue); + } + + [Fact] + public async Task GetByStreetcodeId_ShouldReturnSuccessStatusCode_WhenIdIsValid() + { + // Arrange + var textStreetcodeId = _testText.StreetcodeId; + + // Act + var response = await this.Client.GetByStreetcodeId(textStreetcodeId); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + Assert.Multiple( + () => Assert.Equal(_testText.Id, returnedValue.Id), + () => Assert.Equal(_testText.Title, returnedValue.Title), + () => Assert.Equal(_testText.TextContent, returnedValue.TextContent), + () => Assert.Equal(_testText.AdditionalText, returnedValue.AdditionalText), + () => Assert.Equal(_testText.StreetcodeId, returnedValue.StreetcodeId)); + } + + [Fact] + public async Task GetByStreetcodeId_ShouldReturnBadRequest_WhenIdIsNotValid() + { + // Arrange + const int textStreetcodeId = int.MinValue; + + // Act + var response = await this.Client.GetByStreetcodeId(textStreetcodeId); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + [ExtractUpdateParsedTextTestText] + public async Task UpdateParsedText_ShouldReturnSuccessStatusCode_WhenTextsParsed() + { + // Arrange + var textPreview = ExtractUpdateParsedTextTestTextAttribute.TextPreviewUpdateDtoForTest; + + // Act + var response = await this.Client.UpdateParsedText(textPreview, this.TokenStorage.AdminAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(returnedValue); + } + + [Fact] + [ExtractUpdateParsedTextTestText] + public async Task UpdateParsedText_ShouldReturnUnauthorized_WhenTokenIsAbsent() + { + // Arrange + var textPreview = ExtractUpdateParsedTextTestTextAttribute.TextPreviewUpdateDtoForTest; + + // Act + var response = await this.Client.UpdateParsedText(textPreview); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Null(returnedValue); + } + + [Fact] + [ExtractUpdateParsedTextTestText] + public async Task UpdateParsedText_ShouldReturnForbidden_WhenUserIsNotAdmin() + { + // Arrange + var textPreview = ExtractUpdateParsedTextTestTextAttribute.TextPreviewUpdateDtoForTest; + + // Act + var response = await this.Client.UpdateParsedText(textPreview, this.TokenStorage.UserAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + Assert.Null(returnedValue); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + TextExtracter.Remove(_testText); + } + + base.Dispose(disposing); + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Team/TeamControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Team/TeamControllerTests.cs new file mode 100644 index 000000000..d8f23c186 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Team/TeamControllerTests.cs @@ -0,0 +1,307 @@ +using System.Net; +using Streetcode.BLL.DTO.Team; +using Streetcode.DAL.Entities.Team; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; +using Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Team; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Team; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.AdditionalContent; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Team +{ + [Collection("Authorization")] + public class TeamControllerTests : BaseAuthorizationControllerTests, + IClassFixture> + { + private readonly TeamMember _testTeamMember; + private readonly Positions _testPosition; + + public TeamControllerTests(CustomWebApplicationFactory factory, TokenStorage tokenStorage) + : base(factory, "api/Team", tokenStorage) + { + int uniqueId = UniqueNumberGenerator.GenerateInt(); + + _testTeamMember = TeamMemberExtracter.Extract(uniqueId, uniqueId); + + _testPosition = TeamPositionsExtracter.Extract(uniqueId); + + TeamPositionsExtracter.AddTeamMemberPositions(_testTeamMember.Id, _testPosition.Id); + } + + [Fact] + public async Task GetAll_ReturnSuccessStatusCode() + { + // Act + var response = await this.Client.GetAllAsync(1, 10, this.TokenStorage.AdminAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Multiple( + () => Assert.True(response.IsSuccessStatusCode), + () => Assert.NotNull(returnedValue)); + } + + [Fact] + public async Task GetAllMain_ReturnSuccessStatusCode() + { + // Act + var response = await this.Client.GetAllMainAsync(); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.Multiple( + () => Assert.True(response.IsSuccessStatusCode), + () => Assert.NotNull(returnedValue)); + } + + [Fact] + public async Task GetById_ReturnSuccessStatusCode() + { + // Arrange + TeamMember expectedTeamMember = _testTeamMember; + + // Act + var response = await this.Client.GetByIdAsync(expectedTeamMember.Id); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Multiple( + () => Assert.True(response.IsSuccessStatusCode), + () => Assert.NotNull(returnedValue), + () => Assert.Equal(expectedTeamMember.Id, returnedValue?.Id), + () => Assert.Equal(expectedTeamMember.Name, returnedValue?.Name)); + } + + [Fact] + public async Task GetById_Incorrect_ReturnBadRequest() + { + // Act + const int incorrectId = -1; + var response = await this.Client.GetByIdAsync(incorrectId); + + // Assert + Assert.Multiple( + () => Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode), + () => Assert.False(response.IsSuccessStatusCode)); + } + + [Fact] + public async Task GetByRoleId_ReturnSuccessStatusCode() + { + // Arrange + TeamMember expectedTeamMember = _testTeamMember; + + // Act + var response = await this.Client.GetByRoleIdAsync(_testPosition.Id); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.Multiple( + () => Assert.True(response.IsSuccessStatusCode), + () => Assert.NotNull(returnedValue), + () => Assert.Equal(expectedTeamMember.Id, returnedValue!.Single().Id), + () => Assert.Equal(expectedTeamMember.Name, returnedValue!.Single().Name)); + } + + [Fact] + [ExtractCreateTeamMember] + public async Task Create_ReturnSuccessStatusCode() + { + // Arrange + var teamMemberCreateDto = ExtractCreateTeamMemberAttribute.TeamMemberForTest; + + // Act + var response = await this.Client.CreateAsync(teamMemberCreateDto, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + [ExtractCreateTeamMember] + public async Task Create_TokenNotPassed_ReturnsUnauthorized() + { + // Arrange + var teamMemberCreateDto = ExtractCreateTeamMemberAttribute.TeamMemberForTest; + + // Act + var response = await this.Client.CreateAsync(teamMemberCreateDto); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + [ExtractCreateTeamMember] + public async Task Create_NotAdminTokenPassed_ReturnsForbidden() + { + // Arrange + var teamMemberCreateDto = ExtractCreateTeamMemberAttribute.TeamMemberForTest; + + // Act + var response = await this.Client.CreateAsync(teamMemberCreateDto, this.TokenStorage.UserAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + + [Fact] + [ExtractCreateTeamMember] + public async Task Create_CreatesNewTeamMember() + { + // Arrange + var teamMemberCreateDto = ExtractCreateTeamMemberAttribute.TeamMemberForTest; + + // Act + var response = await this.Client.CreateAsync(teamMemberCreateDto, this.TokenStorage.AdminAccessToken); + var fetchedTeamMember = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Equal(teamMemberCreateDto.Name, fetchedTeamMember?.Name); + } + + [Fact] + [ExtractCreateTeamMember] + public async Task Create_WithInvalidData_ReturnsBadRequest() + { + // Arrange + var teamMemberCreateDto = ExtractCreateTeamMemberAttribute.TeamMemberForTest; + teamMemberCreateDto.Name = null!; + + // Act + var response = await this.Client.CreateAsync(teamMemberCreateDto, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + [ExtractCreateTeamMember] + public async Task Create_WithExistingImage_ReturnsBadRequest() + { + // Arrange + var teamMemberCreateDto = ExtractCreateTeamMemberAttribute.TeamMemberForTest; + teamMemberCreateDto.ImageId = _testTeamMember.ImageId; + + // Act + var response = await this.Client.CreateAsync(teamMemberCreateDto, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + [ExtractUpdateTeamMember] + public async Task Update_ReturnsSuccessStatusCode() + { + // Arrange + var teamMemberUpdateDto = ExtractUpdateTeamMemberAttribute.TeamMemberForTest; + + // Act + var response = await this.Client.UpdateAsync(teamMemberUpdateDto, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + [ExtractUpdateTeamMember] + public async Task Update_WithInvalidData_ReturnsBadRequest() + { + // Arrange + const int id = -1; + var teamMemberUpdateDto = ExtractUpdateTeamMemberAttribute.TeamMemberForTest; + teamMemberUpdateDto.Id = id; + + // Act + var response = await this.Client.UpdateAsync(teamMemberUpdateDto, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Multiple( + () => Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode), + () => Assert.False(response.IsSuccessStatusCode)); + } + + [Fact] + [ExtractUpdateTeamMember] + public async Task Update_TokenNotPassed_ReturnsUnauthorized() + { + // Arrange + var teamMemberUpdateDto = ExtractUpdateTeamMemberAttribute.TeamMemberForTest; + + // Act + var response = await this.Client.UpdateAsync(teamMemberUpdateDto); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + [ExtractUpdateTeamMember] + public async Task Update_NotAdminTokenPassed_ReturnsForbidden() + { + // Arrange + var teamMemberUpdateDto = ExtractUpdateTeamMemberAttribute.TeamMemberForTest; + + // Act + var response = await this.Client.UpdateAsync(teamMemberUpdateDto, this.TokenStorage.UserAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + + [Fact] + [ExtractDeleteTeamMember] + public async Task Delete_ReturnsSuccessStatusCode() + { + // Arrange + int id = ExtractDeleteTeamMemberAttribute.TeamMemberForTest.Id; + + // Act + var response = await this.Client.DeleteAsync(id, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + public async Task Delete_TokenNotPassed_ReturnsUnauthorized() + { + // Arrange + int id = _testTeamMember.Id; + + // Act + var response = await this.Client.DeleteAsync(id); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + public async Task Delete_NotAdminTokenPassed_ReturnsForbidden() + { + // Arrange + int id = _testTeamMember.Id; + + // Act + var response = await this.Client.DeleteAsync(id, this.TokenStorage.UserAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + + [Fact] + public async Task Delete_WithInvalidData_ReturnsBadRequest() + { + // Act + const int id = -1; + var response = await this.Client.DeleteAsync(id, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Team/TeamLinkControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Team/TeamLinkControllerTests.cs new file mode 100644 index 000000000..28fb847cb --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Team/TeamLinkControllerTests.cs @@ -0,0 +1,126 @@ +using System.Net; +using Streetcode.BLL.DTO.Team; +using Streetcode.DAL.Entities.Media.Images; +using Streetcode.DAL.Entities.Team; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; +using Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Team; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Team; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.AdditionalContent; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.MediaExtracter.Image; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Team; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Team +{ + [Collection("Authorization")] + public class TeamLinkControllerTests : BaseAuthorizationControllerTests, + IClassFixture> + { + private readonly Image _testImage; + private readonly TeamMember _testTeamMember; + private readonly TeamMemberLink _testLink; + + public TeamLinkControllerTests(CustomWebApplicationFactory factory, TokenStorage tokenStorage) + : base(factory, "api/TeamLink", tokenStorage) + { + int uniqueId = UniqueNumberGenerator.GenerateInt(); + _testImage = ImageExtracter.Extract(uniqueId); + _testTeamMember = TeamMemberExtracter.Extract(uniqueId, _testImage.Id); + _testTeamMember.ImageId = _testImage.Id; + _testLink = TeamLinkExtracter.Extract(uniqueId, _testTeamMember.Id); + } + + [Fact] + public async Task GetAll_ReturnsSuccessStatusCode() + { + // Act + var response = await this.Client.GetAllAsync(); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.Multiple( + () => Assert.True(response.IsSuccessStatusCode), + () => Assert.NotNull(returnedValue)); + } + + [Fact] + [ExtractCreateTeamLink] + public async Task Create_ReturnSuccessStatusCode() + { + // Act + var teamLinkCreateDto = ExtractCreateTeamLinkAttribute.TeamLinkForTest; + teamLinkCreateDto.TeamMemberId = _testTeamMember.Id; + + // Act + var response = await this.Client.CreateAsync(teamLinkCreateDto, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + [ExtractCreateTeamLink] + public async Task Create_TokenNotPassed_ReturnsUnauthorized() + { + // Act + var teamLinkCreateDto = ExtractCreateTeamLinkAttribute.TeamLinkForTest; + + // Act + var response = await this.Client.CreateAsync(teamLinkCreateDto); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + + [Fact] + [ExtractCreateTeamLink] + public async Task Create_NotAdminTokenPassed_ReturnsForbidden() + { + // Act + var teamLinkCreateDto = ExtractCreateTeamLinkAttribute.TeamLinkForTest; + teamLinkCreateDto.TeamMemberId = _testTeamMember.Id; + + // Act + var response = await this.Client.CreateAsync(teamLinkCreateDto, this.TokenStorage.UserAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + } + + [Fact] + [ExtractCreateTeamLink] + public async Task Create_CreatesNewTeamMemberLink() + { + // Act + var teamLinkCreateDto = ExtractCreateTeamLinkAttribute.TeamLinkForTest; + teamLinkCreateDto.TeamMemberId = _testTeamMember.Id; + + // Act + var response = await this.Client.CreateAsync(teamLinkCreateDto, this.TokenStorage.AdminAccessToken); + var fetchedLink = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Multiple( + () => Assert.Equal(teamLinkCreateDto.LogoType, fetchedLink?.LogoType), + () => Assert.Equal(teamLinkCreateDto.TargetUrl, fetchedLink?.TargetUrl)); + } + + [Fact] + [ExtractCreateTeamLink] + public async Task Create_WithInvalidData_ReturnsBadRequest() + { + // Arrange + var teamLinkCreateDto = ExtractCreateTeamLinkAttribute.TeamLinkForTest; + teamLinkCreateDto.TargetUrl = null!; + + // Act + var response = await this.Client.CreateAsync(teamLinkCreateDto, this.TokenStorage.AdminAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Team/TickerStringControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Team/TickerStringControllerTests.cs new file mode 100644 index 000000000..ea8afb46a --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Team/TickerStringControllerTests.cs @@ -0,0 +1,56 @@ +using Streetcode.DAL.Entities.Media.Images; +using Streetcode.DAL.Entities.Team; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Team; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.AdditionalContent; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.MediaExtracter.Image; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Team +{ + [Collection("TickerString")] + public class TickerStringControllerTests : BaseControllerTests, IClassFixture> + { + private readonly Image _testTeamMemberImage; + private readonly TeamMember _testTeamMember; + private readonly Positions _testPosition; + + public TickerStringControllerTests(CustomWebApplicationFactory factory) + : base(factory, "api/TickerString") + { + int uniqueId = UniqueNumberGenerator.GenerateInt(); + _testTeamMemberImage = ImageExtracter.Extract(uniqueId); + _testTeamMember = TeamMemberExtracter.Extract(uniqueId, _testTeamMemberImage.Id); + _testPosition = TeamPositionsExtracter.Extract(uniqueId); + } + + [Fact] + public async Task GetNameTickerString_ReturnsSuccessStatusCode() + { + // Arrange + TeamPositionsExtracter.AddTeamMemberPositions(_testTeamMember.Id, _testPosition.Id); + + // Act + var response = await this.Client.GetNameTickerString(); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(returnedValue); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + TeamPositionsExtracter.Remove(_testPosition); + ImageExtracter.Remove(_testTeamMemberImage); + TeamMemberExtracter.Remove(_testTeamMember); + } + + base.Dispose(disposing); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Timeline/HistoricalContextControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Timeline/HistoricalContextControllerTests.cs index 92909c6a0..8413add80 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Timeline/HistoricalContextControllerTests.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Timeline/HistoricalContextControllerTests.cs @@ -1,13 +1,10 @@ using System.Linq.Expressions; using System.Net; -using AutoMapper; -using Microsoft.EntityFrameworkCore.Query; using Microsoft.Extensions.Localization; using Moq; using Streetcode.BLL.DTO.Timeline; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Timeline.HistoricalContext.Delete; -using Streetcode.BLL.MediatR.Timeline.HistoricalContext.Update; using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Streetcode; using Streetcode.DAL.Entities.Timeline; @@ -17,8 +14,8 @@ using Streetcode.XIntegrationTest.ControllerTests.BaseController; using Streetcode.XIntegrationTest.ControllerTests.Utils; using Streetcode.XIntegrationTest.ControllerTests.Utils.AdditionalContent.Timeline; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Timeline; -using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Job; using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter; using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Timeline; using Xunit; @@ -29,17 +26,17 @@ namespace Streetcode.XIntegrationTest.ControllerTests.Timeline; public class HistoricalContextControllerTests : BaseAuthorizationControllerTests, IClassFixture> { - private readonly HistoricalContext testCreateContext; - private readonly HistoricalContext testUpdateContext; - private readonly StreetcodeContent testStreetcodeContent; + private readonly HistoricalContext _testCreateContext; + private readonly HistoricalContext _testUpdateContext; + private readonly StreetcodeContent _testStreetcodeContent; public HistoricalContextControllerTests(CustomWebApplicationFactory factory, TokenStorage tokenStorage) : base(factory, "/api/HistoricalContext", tokenStorage) { int uniqueId = UniqueNumberGenerator.GenerateInt(); - this.testCreateContext = HistoricalContextExtracter.Extract(uniqueId); - this.testUpdateContext = HistoricalContextExtracter.Extract(uniqueId); - this.testStreetcodeContent = StreetcodeContentExtracter + _testCreateContext = HistoricalContextExtracter.Extract(uniqueId); + _testUpdateContext = HistoricalContextExtracter.Extract(uniqueId); + _testStreetcodeContent = StreetcodeContentExtracter .Extract( uniqueId, uniqueId, @@ -49,25 +46,32 @@ public HistoricalContextControllerTests(CustomWebApplicationFactory fac [Fact] public async Task GetAll_ReturnSuccessStatusCode() { + // Act var response = await this.Client.GetAllAsync(); var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); - Assert.True(response.IsSuccessStatusCode); - Assert.NotNull(returnedValue); + // Assert + Assert.Multiple( + () => Assert.True(response.IsSuccessStatusCode), + () => Assert.NotNull(returnedValue)); } [Fact] public async Task GetById_ReturnSuccessStatusCode() { - HistoricalContext expectedContext = this.testCreateContext; + // Arrange + HistoricalContext expectedContext = _testCreateContext; + + // Act var response = await this.Client.GetByIdAsync(expectedContext.Id); var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); - Assert.True(response.IsSuccessStatusCode); - Assert.NotNull(returnedValue); + // Assert Assert.Multiple( + () => Assert.True(response.IsSuccessStatusCode), + () => Assert.NotNull(returnedValue), () => Assert.Equal(expectedContext.Id, returnedValue?.Id), () => Assert.Equal(expectedContext.Title, returnedValue?.Title)); } @@ -75,11 +79,15 @@ public async Task GetById_ReturnSuccessStatusCode() [Fact] public async Task GetByIdIncorrect_ReturnBadRequest() { - int incorrectId = -100; + // Arrange + const int incorrectId = -100; + + // Act var response = await this.Client.GetByIdAsync(incorrectId); + // Assert Assert.Multiple( - () => Assert.Equal(System.Net.HttpStatusCode.BadRequest, response.StatusCode), + () => Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode), () => Assert.False(response.IsSuccessStatusCode)); } @@ -162,7 +170,7 @@ public async Task Create_WithExistingTag_ReturnsConflict() { // Arrange var historicalContextCreateDto = ExtractCreateTestHistoricalContextAttribute.HistoricalContextForTest; - historicalContextCreateDto.Title = this.testCreateContext.Title!; + historicalContextCreateDto.Title = _testCreateContext.Title!; // Act var response = await this.Client.CreateAsync(historicalContextCreateDto, this.TokenStorage.AdminAccessToken); @@ -172,12 +180,12 @@ public async Task Create_WithExistingTag_ReturnsConflict() } [Fact] - [ExtractUpdateTestHistoricalContextAttribute] + [ExtractUpdateTestHistoricalContext] public async Task Update_ReturnSuccessStatusCode() { // Arrange var historicalContextCreateDto = ExtractUpdateTestHistoricalContextAttribute.HistoricalContextForTest; - historicalContextCreateDto.Id = this.testCreateContext.Id; + historicalContextCreateDto.Id = _testCreateContext.Id; // Act var response = await this.Client.UpdateAsync(historicalContextCreateDto, this.TokenStorage.AdminAccessToken); @@ -187,12 +195,12 @@ public async Task Update_ReturnSuccessStatusCode() } [Fact] - [ExtractUpdateTestHistoricalContextAttribute] + [ExtractUpdateTestHistoricalContext] public async Task Update_Incorect_ReturnBadRequest() { // Arrange var historicalContextCreateDto = ExtractUpdateTestHistoricalContextAttribute.HistoricalContextForTest; - var invalidHistoricalContextId = -10; + const int invalidHistoricalContextId = -10; historicalContextCreateDto.Id = invalidHistoricalContextId; // Act @@ -205,7 +213,7 @@ public async Task Update_Incorect_ReturnBadRequest() } [Fact] - [ExtractUpdateTestHistoricalContextAttribute] + [ExtractUpdateTestHistoricalContext] public async Task Update_TokenNotPassed_ReturnsUnauthorized() { // Arrange @@ -219,7 +227,7 @@ public async Task Update_TokenNotPassed_ReturnsUnauthorized() } [Fact] - [ExtractUpdateTestHistoricalContextAttribute] + [ExtractUpdateTestHistoricalContext] public async Task Update_NotAdminTokenPassed_ReturnsForbidden() { // Arrange @@ -233,7 +241,7 @@ public async Task Update_NotAdminTokenPassed_ReturnsForbidden() } [Fact] - [ExtractUpdateTestHistoricalContextAttribute] + [ExtractUpdateTestHistoricalContext] public async Task Update_WithInvalidData_ReturnsBadRequest() { // Arrange @@ -248,13 +256,13 @@ public async Task Update_WithInvalidData_ReturnsBadRequest() } [Fact] - [ExtractUpdateTestHistoricalContextAttribute] + [ExtractUpdateTestHistoricalContext] public async Task Update_WithExistingTitle_ReturnsBadRequest() { // Arrange var historicalContextCreateDto = ExtractUpdateTestHistoricalContextAttribute.HistoricalContextForTest; - historicalContextCreateDto.Id = this.testCreateContext.Id; - historicalContextCreateDto.Title = this.testUpdateContext.Title!; + historicalContextCreateDto.Id = _testCreateContext.Id; + historicalContextCreateDto.Title = _testUpdateContext.Title!; // Act var response = await this.Client.UpdateAsync(historicalContextCreateDto, this.TokenStorage.AdminAccessToken); @@ -263,51 +271,11 @@ public async Task Update_WithExistingTitle_ReturnsBadRequest() Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } - [Fact] - [ExtractUpdateTestHistoricalContextAttribute] - public async Task Update_ChangesNotSaved_ReturnsBadRequest() - { - // Arrange - var historicalContextCreateDto = ExtractUpdateTestHistoricalContextAttribute.HistoricalContextForTest; - historicalContextCreateDto.Id = this.testUpdateContext.Id; - - var repositoryMock = new Mock(); - var repositoryWrapperMock = new Mock(); - var mockLocalizerValidation = new Mock>(); - var mockLocalizerFieldNames = new Mock>(); - var mockLocalizerCannotFind = new Mock>(); - repositoryMock.Setup(r => r.GetFirstOrDefaultAsync(It.IsAny>>(), default)) - .ReturnsAsync((Expression> expr, IIncludableQueryable include) => - { - var compiledExpr = expr.Compile(); - return compiledExpr(this.testUpdateContext) ? this.testUpdateContext : null; - }); - - repositoryWrapperMock.SetupGet(wrapper => wrapper.HistoricalContextRepository).Returns(repositoryMock.Object); - repositoryWrapperMock.Setup(wrapper => wrapper.SaveChangesAsync()).ReturnsAsync(null); - repositoryWrapperMock.Setup(wrapper => wrapper.SaveChangesAsync()).Throws(default(Exception)); - - var mapperMock = new Mock(); - mapperMock.Setup(m => m.Map(default)).Returns(this.testUpdateContext); - var loggerMock = new Mock(); - - var handler = new UpdateHistoricalContextHandler(repositoryWrapperMock.Object, mapperMock.Object, loggerMock.Object, mockLocalizerCannotFind.Object, mockLocalizerValidation.Object, mockLocalizerFieldNames.Object); - - var query = new UpdateHistoricalContextCommand(historicalContextCreateDto); - var cancellationToken = CancellationToken.None; - - // Act - var result = await handler.Handle(query, cancellationToken); - - // Assert - Assert.False(result.IsSuccess); - } - [Fact] public async Task Delete_ReturnsSuccessStatusCode() { // Arrange - int id = this.testCreateContext.Id; + int id = _testCreateContext.Id; // Act var response = await this.Client.Delete(id, this.TokenStorage.AdminAccessToken); @@ -320,7 +288,7 @@ public async Task Delete_ReturnsSuccessStatusCode() public async Task Delete_TokenNotPassed_ReturnsUnathorized() { // Arrange - int id = this.testCreateContext.Id; + int id = _testCreateContext.Id; // Act var response = await this.Client.Delete(id); @@ -333,7 +301,7 @@ public async Task Delete_TokenNotPassed_ReturnsUnathorized() public async Task Delete_NotAdminTokenPassed_ReturnsForbidden() { // Arrange - int id = this.testCreateContext.Id; + int id = _testCreateContext.Id; // Act var response = await this.Client.Delete(id, this.TokenStorage.UserAccessToken); @@ -346,7 +314,7 @@ public async Task Delete_NotAdminTokenPassed_ReturnsForbidden() public async Task Delete_WithInvalidData_ReturnsBadRequest() { // Arrange - int id = -100; + const int id = -100; // Act var response = await this.Client.Delete(id, this.TokenStorage.AdminAccessToken); @@ -358,13 +326,13 @@ public async Task Delete_WithInvalidData_ReturnsBadRequest() [Fact] public async Task Delete_ChangesNotSaved_ReturnsBadRequest() { - int id = this.testUpdateContext.Id; + int id = _testUpdateContext.Id; var repositoryMock = new Mock(); var repositoryWrapperMock = new Mock(); var mockLocalizerCannotFind = new Mock>(); repositoryMock.Setup(r => r.GetFirstOrDefaultAsync(It.IsAny>>(), default)) - .ReturnsAsync(this.testUpdateContext); + .ReturnsAsync(_testUpdateContext); repositoryMock.Setup(r => r.Delete(default!)); repositoryWrapperMock.SetupGet(wrapper => wrapper.HistoricalContextRepository).Returns(repositoryMock.Object); @@ -384,15 +352,4 @@ public async Task Delete_ChangesNotSaved_ReturnsBadRequest() // Assert Assert.False(result.IsSuccess); } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - StreetcodeContentExtracter.Remove(this.testStreetcodeContent); - HistoricalContextExtracter.Remove(this.testCreateContext); - } - - base.Dispose(disposing); - } } \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Timeline/TimelineItemControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Timeline/TimelineItemControllerTests.cs new file mode 100644 index 000000000..fbe6bffb7 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Timeline/TimelineItemControllerTests.cs @@ -0,0 +1,117 @@ +using System.Net; +using Streetcode.BLL.DTO.Timeline; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Timeline; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Timeline; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Timeline; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Timeline +{ + [Collection("TimelineItem")] + public class TimelineItemControllerTests : BaseControllerTests, IClassFixture> + { + private readonly TimelineItem _timelineItem; + private readonly StreetcodeContent _testStreetcodeContent; + + public TimelineItemControllerTests(CustomWebApplicationFactory factory) + : base(factory, "api/TimelineItem") + { + int uniqueId = UniqueNumberGenerator.GenerateInt(); + _timelineItem = TimelineItemExtracter.Extract(uniqueId); + _testStreetcodeContent = StreetcodeContentExtracter + .Extract( + uniqueId, + uniqueId, + Guid.NewGuid().ToString()); + } + + [Fact] + public async Task GetAll_ReturnsSuccessStatusCode() + { + // Act + var response = await this.Client.GetAllAsync(); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(returnedValue); + } + + [Fact] + public async Task GetById_ReturnsSuccessStatusCode() + { + // Arrange + TimelineItem expectedTimeline = _timelineItem; + + // Act + var response = await this.Client.GetByIdAsync(expectedTimeline.Id); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(returnedValue); + Assert.Multiple( + () => Assert.Equal(expectedTimeline.Id, returnedValue.Id), + () => Assert.Equal(expectedTimeline.Title, returnedValue.Title)); + } + + [Fact] + public async Task GetByIdIncorrect_ReturnsBadRequest() + { + // Arrange + int incorrectId = -1; + + // Act + var response = await this.Client.GetByIdAsync(incorrectId); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + Assert.False(response.IsSuccessStatusCode); + } + + [Fact] + public async Task GetByStreetcodeId_ReturnsSuccessStatusCode() + { + // Arrange + int streetcodeId = _testStreetcodeContent.Id; + + // Act + var response = await this.Client.GetByStreetcodeId(streetcodeId); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.True(response.IsSuccessful); + Assert.NotNull(returnedValue); + } + + [Fact(Skip = "will fail until pr 2098 is merged")] + public async Task GetByStreetcodeIdIncorrect_ReturnsBadRequest() + { + // Assert + int incorrectStreetcodeId = -1; + + // Act + var response = await this.Client.GetByStreetcodeId(incorrectStreetcodeId); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + Assert.False(response.IsSuccessStatusCode); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + TimelineItemExtracter.Remove(_timelineItem); + StreetcodeContentExtracter.Remove(_testStreetcodeContent); + } + + base.Dispose(disposing); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Toponyms/ToponymControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Toponyms/ToponymControllerTests.cs new file mode 100644 index 000000000..16baa973d --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Toponyms/ToponymControllerTests.cs @@ -0,0 +1,120 @@ +using System.Net; +using Streetcode.BLL.DTO.Toponyms; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Toponyms; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Toponym; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Toponyms; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Toponyms +{ + [Collection("Toponym")] + public class ToponymControllerTests : BaseControllerTests, IClassFixture> + { + private readonly Toponym _toponym; + private readonly StreetcodeContent _testStreetcodeContent; + + public ToponymControllerTests(CustomWebApplicationFactory factory) + : base(factory, "api/Toponym") + { + int uniqueId = UniqueNumberGenerator.GenerateInt(); + _toponym = ToponymExtracter.Extract(uniqueId); + _testStreetcodeContent = StreetcodeContentExtracter + .Extract( + uniqueId, + uniqueId, + Guid.NewGuid().ToString()); + } + + [Fact] + public async Task GetAll_ReturnsSuccessStatusCode() + { + // Act + var response = await this.Client.GetAllAsync(); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(returnedValue); + } + + [Fact] + public async Task GetById_ReturnsSuccessStatusCode() + { + // Arrange + Toponym expectedToponym = _toponym; + + // Act + var response = await this.Client.GetByIdAsync(expectedToponym.Id); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Multiple( + () => Assert.True(response.IsSuccessStatusCode), + () => Assert.NotNull(returnedValue), + () => Assert.Equal(expectedToponym.Id, returnedValue?.Id), + () => Assert.Equal(expectedToponym.Oblast, returnedValue?.Oblast)); + } + + [Fact] + public async Task GetByIdIncorrect_ReturnsBadRequest() + { + // Arrange + const int incorrectId = -1; + + // Act + var response = await this.Client.GetByIdAsync(incorrectId); + + // Assert + Assert.Multiple( + () => Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode), + () => Assert.False(response.IsSuccessStatusCode)); + } + + [Fact] + public async Task GetByStreetcodeId_ReturnsSuccessStatusCode() + { + // Arrange + int streetcodeId = _testStreetcodeContent.Id; + + // Act + var response = await this.Client.GetByStreetcodeId(streetcodeId); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.Multiple( + () => Assert.True(response.IsSuccessStatusCode), + () => Assert.NotNull(returnedValue)); + } + + [Fact] + public async Task GetByStreetcodeIdIncorrect_ReturnsBadRequest() + { + // Assert + const int incorrectStreetcodeId = -1; + + // Act + var response = await this.Client.GetByStreetcodeId(incorrectStreetcodeId); + + // Assert + Assert.Multiple( + () => Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode), + () => Assert.False(response.IsSuccessStatusCode)); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + StreetcodeContentExtracter.Remove(_testStreetcodeContent); + ToponymExtracter.Remove(_toponym); + } + + base.Dispose(disposing); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Transaction/TransactLinksControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Transaction/TransactLinksControllerTests.cs new file mode 100644 index 000000000..a6e6ff9d4 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Transaction/TransactLinksControllerTests.cs @@ -0,0 +1,108 @@ +using System.Net; +using Streetcode.BLL.DTO.Transactions; +using Streetcode.DAL.Entities.Transactions; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Transaction; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Transaction; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Transaction +{ + [Collection("Transaction")] + public class TransactLinksControllerTests : BaseControllerTests, IClassFixture> + { + private readonly TransactionLink transactionLink; + + public TransactLinksControllerTests(CustomWebApplicationFactory factory) + : base(factory, "api/TransactLinks") + { + int uniqueId = UniqueNumberGenerator.GenerateInt(); + this.transactionLink = TransactLinkExtracter.Extract(uniqueId); + } + + [Fact] + public async Task GetAll_ReturnsSuccessStatusCode() + { + // Act + var response = await this.Client.GetAllAsync(); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(returnedValue); + } + + [Fact] + public async Task GetByStreetcodeId_ReturnsSuccessStatusCode() + { + // Arrange + int streetcodeId = this.transactionLink.StreetcodeId; + + // Act + var response = await this.Client.GetByStreetcodeId(streetcodeId); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.True(response.IsSuccessful); + Assert.NotNull(returnedValue); + Assert.Equal(streetcodeId, returnedValue.StreetcodeId); + } + + [Fact] + public async Task GetByStreetcodeIdIncorrect_ReturnsBadRequest() + { + // Arrange + int incorrectStreetcodeId = -1; + + // Act + var response = await this.Client.GetByStreetcodeId(incorrectStreetcodeId); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + Assert.False(response.IsSuccessStatusCode); + } + + [Fact] + public async Task GetById_ReturnsSuccessStatusCode() + { + // Arrange + TransactionLink expectedTransactLink = this.transactionLink; + + // Act + var response = await this.Client.GetByIdAsync(expectedTransactLink.Id); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(returnedValue); + Assert.Equal(expectedTransactLink.Id, returnedValue.Id); + Assert.Equal(expectedTransactLink.Url, returnedValue.Url); + } + + [Fact] + public async Task GetByIdIncorrect_ReturnsBadRequest() + { + // Arrange + int incorrectId = -1; + + // Act + var response = await this.Client.GetByIdAsync(incorrectId); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + Assert.False(response.IsSuccessStatusCode); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + TransactLinkExtracter.Remove(this.transactionLink); + } + + base.Dispose(disposing); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Users/Expertises/ExpertiseControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Users/Expertises/ExpertiseControllerTests.cs new file mode 100644 index 000000000..dcac51e16 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Users/Expertises/ExpertiseControllerTests.cs @@ -0,0 +1,28 @@ +using Streetcode.BLL.DTO.Users.Expertise; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Users.Expertises; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Users.Expertises; + +public class ExpertiseControllerTests : BaseControllerTests +{ + public ExpertiseControllerTests(CustomWebApplicationFactory factory) + : base(factory, "/api/Expertises") + { + } + + [Fact] + public async Task GetAll_Expertises_ReturnsSuccessStatusCode() + { + // Act + var response = await Client.GetAll(); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize>(response.Content); + + // Assert + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(returnedValue); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Users/UserControllerTests.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Users/UserControllerTests.cs new file mode 100644 index 000000000..ad0f0285d --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Users/UserControllerTests.cs @@ -0,0 +1,288 @@ +using System.Net; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Streetcode.BLL.DTO.Users; +using Streetcode.BLL.DTO.Users.Expertise; +using Streetcode.BLL.DTO.Users.Password; +using Streetcode.BLL.Models.Email.Messages.Base; +using Streetcode.DAL.Entities.Users; +using Streetcode.DAL.Entities.Users.Expertise; +using Streetcode.DAL.Enums; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; +using Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Users; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Users; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Authentication; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Expertises; +using Xunit; + +namespace Streetcode.XIntegrationTest.ControllerTests.Users; + +[Collection("Authorization")] +public class UserControllerTests : BaseAuthorizationControllerTests, IClassFixture> +{ + private readonly User _testUser; + private readonly Expertise _testExpertise; + private readonly UserManager _userManager; + private readonly CustomWebApplicationFactory _factory; + + public UserControllerTests(CustomWebApplicationFactory factory, TokenStorage tokenStorage) + : base(factory, "/api/Users", tokenStorage) + { + _factory = factory; + var serviceProvider = _factory.Services.CreateScope().ServiceProvider; + + _userManager = serviceProvider.GetRequiredService>(); + + TokenStorage = new TokenStorage(); + + var uniqueExpertiseId = UniqueNumberGenerator.GenerateInt(); + + _testExpertise = ExpertiseExtracter.Extract(uniqueExpertiseId); + + (_testUser, _) = UserExtracter.Extract( + userId: Guid.NewGuid().ToString(), + userName: Guid.NewGuid().ToString(), + password: GenerateTestPassword(), + nameof(UserRole.User), + nameof(UserRole.Admin)); + } + + [Fact] + public async Task GetByEmail_ValidToken_ReturnsSuccessStatusCode() + { + // Act + var response = await Client.GetByEmail(TokenStorage.UserAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.True(response.IsSuccessStatusCode); + Assert.NotNull(returnedValue); + } + + [Fact] + public async Task ExistWithUserName_ValidUserName_ReturnsSuccessStatusCode() + { + // Arrange + var validUserName = _testUser.UserName; + + // Act + var response = await Client.ExistWithUserName(validUserName, TokenStorage.UserAccessToken); + bool.TryParse(response.Content, out bool result); + + // Assert + Assert.True(response.IsSuccessStatusCode); + Assert.True(result); + } + + [Fact] + public async Task ExistWithUserName_InvalidToken_ReturnsUnauthorized() + { + // Arrange + var validUserName = _testUser.UserName; + + // Act + var response = await Client.ExistWithUserName(validUserName); + bool.TryParse(response.Content, out bool result); + + // Assert + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.False(result); + } + + [Fact] + public async Task ExistWithUserName_InvalidUserName_ReturnFalse() + { + // Arrange + var invalidUserName = "NonExistentUser_" + Guid.NewGuid(); + + // Act + var response = await Client.ExistWithUserName(invalidUserName, TokenStorage.UserAccessToken); + bool.TryParse(response.Content, out bool result); + + // Assert + Assert.False(result); + } + + [Fact] + public async Task GetOtherUserByUserName_ValidUserName_ReturnsSuccessStatusCode() + { + // Arrange + var validUserName = _testUser.UserName; + + // Act + var response = await Client.GetOtherUserByUserName(validUserName); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.NotNull(returnedValue); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + public async Task GetOtherUserByUserName_InvalidUserName_ReturnsBadRequest() + { + // Arrange + var validUserName = _testUser.UserName; + + // Act + var response = await Client.GetOtherUserByUserName(validUserName.Substring(0, 4)); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Null(returnedValue); + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + [ExtractUpdateTestUser] + public async Task UpdateUser_ValidData_ReturnsSuccessStatusCode() + { + // Arrange + var userToUpdate = ExtractUpdateTestUserAttribute.UserForTest; + userToUpdate.UserName = Guid.NewGuid().ToString(); + userToUpdate.Expertises.Add(new ExpertiseDTO + { + Id = _testExpertise.Id, + Title = _testExpertise.Title, + }); + + // Act + var response = await Client.Update(userToUpdate, TokenStorage.UserAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.NotNull(returnedValue); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + [ExtractUpdateTestUser] + public async Task UpdateUser_SameUserName_ReturnsBadRequest() + { + // Arrange + var userToUpdate = ExtractUpdateTestUserAttribute.UserForTest; + userToUpdate.UserName = _testUser.UserName; + + // Act + var response = await Client.Update(userToUpdate, TokenStorage.UserAccessToken); + var returnedValue = CaseIsensitiveJsonDeserializer.Deserialize(response.Content); + + // Assert + Assert.Null(returnedValue); + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + public async Task DeleteUser_ValidEmail_ReturnsSuccessStatusCode() + { + // Arrange + await TokenStorage.GenerateNewTokens(_testUser); + + // Act + var response = await Client.Delete(_testUser.Email!, TokenStorage.UserAccessToken); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + [ExtractUpdateTestUser] + public async Task DeleteUser_InvalidEmail_ReturnsBadRequest() + { + // Arrange + var userToUpdate = ExtractUpdateTestUserAttribute.UserForTest; + userToUpdate.Email = "invalid_email"; + + // Act + var response = await Client.Delete(_testUser.Email!, TokenStorage.UserAccessToken); + bool.TryParse(response.Content, out bool result); + + // Assert + Assert.False(result); + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + public async Task ForgotPassword_ValidEmail_ReturnsSuccessStatusCode() + { + // Arrange + var forgotPassword = new ForgotPasswordDTO + { + Email = _testUser.Email!, + }; + _factory.SetupMockEmailService(); + + // Act + var response = await Client.ForgotPassword(forgotPassword); + + // Assert + _factory.EmailServiceMock.Verify(es => es.SendEmailAsync(It.IsAny()), Times.Once); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + public async Task ForgotPassword_InvalidEmail_ReturnsBadRequest() + { + // Arrange + var forgotPassword = new ForgotPasswordDTO + { + Email = "invalid_email", + }; + + // Act + var response = await Client.ForgotPassword(forgotPassword); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + [Fact] + public async Task UpdateForgotPassword_ValidData_ReturnsSuccessStatusCode() + { + // Arrange + var forgotPassword = new UpdateForgotPasswordDTO + { + Username = Uri.EscapeDataString(_testUser.UserName), + Password = "Newpassword1!", + ConfirmPassword = "Newpassword1!", + }; + var token = await _userManager.GeneratePasswordResetTokenAsync(_testUser); + forgotPassword.Token = Uri.EscapeDataString(token); + + // Act + var response = await Client.UpdateForgotPassword(forgotPassword); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + public async Task UpdateForgotPassword_InvalidData_ReturnsBadRequest() + { + // Arrange + var forgotPassword = new UpdateForgotPasswordDTO + { + Username = _testUser.UserName, + Password = "newpassword1!", + ConfirmPassword = "newpassword1!", + }; + var token = await _userManager.GeneratePasswordResetTokenAsync(_testUser); + forgotPassword.Token = token; + + // Act + var response = await Client.UpdateForgotPassword(forgotPassword); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + + private static string GenerateTestPassword() + { + string guid = Guid.NewGuid().ToString(); + return $"TestPass123_{guid.Substring(0, 10)}"; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/AuthorizationFixture/AuthorizationCollection.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/AuthorizationFixture/AuthorizationCollection.cs index aa031a1b4..57d3786ec 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/AuthorizationFixture/AuthorizationCollection.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/AuthorizationFixture/AuthorizationCollection.cs @@ -1,4 +1,5 @@ -using Xunit; +using Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture; +using Xunit; namespace Streetcode.XIntegrationTest.ControllerTests.Utils { diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/AuthorizationFixture/TokenStorage.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/AuthorizationFixture/TokenStorage.cs index 7c4e33520..6e1aa0cf4 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/AuthorizationFixture/TokenStorage.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/AuthorizationFixture/TokenStorage.cs @@ -7,31 +7,31 @@ using Streetcode.WebApi.Extensions; using static Streetcode.XIntegrationTest.Constants.ControllerTests.AuthConstants; -namespace Streetcode.XIntegrationTest.ControllerTests.Utils +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.AuthorizationFixture { public class TokenStorage : IDisposable { - private readonly StreetcodeDbContext streetcodeDbContext; - private readonly IConfiguration configuration; - private readonly ITokenService tokenService; - private readonly Dictionary users; + private readonly StreetcodeDbContext _streetcodeDbContext; + private readonly IConfiguration _configuration; + private readonly ITokenService _tokenService; + private readonly Dictionary _users; - private bool disposed = false; + private bool disposed; public TokenStorage() { - this.users = new Dictionary + _users = new Dictionary { ["Admin"] = TEST_USER_ADMIN, ["User"] = TEST_USER_USER, }; - this.streetcodeDbContext = this.GetDbContext(); - this.configuration = GetConfiguration(); + _streetcodeDbContext = GetDbContext(); + _configuration = GetConfiguration(); - this.tokenService = new TokenService(this.configuration, this.streetcodeDbContext); + _tokenService = new TokenService(_configuration, _streetcodeDbContext); - this.ObtainTokensAsync().GetAwaiter().GetResult(); + ObtainTokensAsync().GetAwaiter().GetResult(); } public string AdminAccessToken { get; private set; } = null!; @@ -42,25 +42,29 @@ public TokenStorage() public string UserRefreshToken { get; private set; } = null!; + public async Task GenerateNewTokens(User user) + { + UserAccessToken = (await _tokenService.GenerateAccessTokenAsync(user)).RawData; + UserRefreshToken = _tokenService.SetNewRefreshTokenForUser(user); + } + public void Dispose() { - this.Dispose(true); + Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { - if (this.disposed) + if (!disposed) { - return; - } + if (disposing) + { + _streetcodeDbContext.Dispose(); + } - if (disposing) - { - this.streetcodeDbContext.Dispose(); + disposed = true; } - - this.disposed = true; } private static IConfiguration GetConfiguration() @@ -87,10 +91,10 @@ private StreetcodeDbContext GetDbContext() private async Task ObtainTokensAsync() { - this.AdminAccessToken = (await this.tokenService.GenerateAccessTokenAsync(this.users["Admin"])).RawData; - this.UserAccessToken = (await this.tokenService.GenerateAccessTokenAsync(this.users["User"])).RawData; - this.AdminRefreshToken = this.tokenService.SetNewRefreshTokenForUser(this.users["Admin"]); - this.UserRefreshToken = this.tokenService.SetNewRefreshTokenForUser(this.users["User"]); + AdminAccessToken = (await _tokenService.GenerateAccessTokenAsync(_users["Admin"])).RawData; + UserAccessToken = (await _tokenService.GenerateAccessTokenAsync(_users["User"])).RawData; + AdminRefreshToken = _tokenService.SetNewRefreshTokenForUser(_users["Admin"]); + UserRefreshToken = _tokenService.SetNewRefreshTokenForUser(_users["User"]); } } } diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/ExtractCreateTestStreetcodeAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/ExtractCreateTestStreetcodeAttribute.cs index 7050c5d7d..94071ab8e 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/ExtractCreateTestStreetcodeAttribute.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/ExtractCreateTestStreetcodeAttribute.cs @@ -7,7 +7,6 @@ using Streetcode.BLL.DTO.Media.Create; using Streetcode.BLL.DTO.Media.Images; using Streetcode.BLL.DTO.Media.Video; -using Streetcode.BLL.DTO.Partners; using Streetcode.BLL.DTO.Sources; using Streetcode.BLL.DTO.Streetcode.Create; using Streetcode.BLL.DTO.Streetcode.RelatedFigure; @@ -21,64 +20,63 @@ using Xunit.Sdk; using static Streetcode.XIntegrationTest.Constants.ControllerTests.StreetcodeConstants; -namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public class ExtractCreateTestStreetcodeAttribute : BeforeAfterTestAttribute { - [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] - public class ExtractCreateTestStreetcodeAttribute : BeforeAfterTestAttribute - { - public static StreetcodeCreateDTO StreetcodeForTest { get; set; } = null!; + public static StreetcodeCreateDTO StreetcodeForTest { get; set; } = null!; - public override void Before(MethodInfo methodUnderTest) + public override void Before(MethodInfo methodUnderTest) + { + StreetcodeForTest = new StreetcodeCreateDTO { - StreetcodeForTest = new StreetcodeCreateDTO + Index = STREETCODE_CREATE_INDEX, + FirstName = "TestFirstName", + LastName = "TestLastName", + Title = "TestTitle", + DateString = "20 травня 2023", + Alias = "TestAlias", + TransliterationUrl = Guid.NewGuid().ToString(), + ArBlockUrl = "test-arblock-url", + StreetcodeType = StreetcodeType.Event, + Status = StreetcodeStatus.Published, + EventStartOrPersonBirthDate = DateTime.Now, + EventEndOrPersonDeathDate = DateTime.Now.AddDays(1), + ViewCount = 1, + Teaser = "Test Teaser", + Text = new TextCreateDTO { - Index = STREETCODE_CREATE_INDEX, - FirstName = "TestFirstName", - LastName = "TestLastName", - Title = "TestTitle", - DateString = "20 травня 2023", - Alias = "TestAlias", - TransliterationUrl = Guid.NewGuid().ToString(), - ARBlockURL = "test-arblock-url", - StreetcodeType = StreetcodeType.Event, - Status = StreetcodeStatus.Published, - EventStartOrPersonBirthDate = DateTime.Now, - EventEndOrPersonDeathDate = DateTime.Now.AddDays(1), - ViewCount = 1, - Teaser = "Test Teaser", - Text = new TextCreateDTO - { - Title = "TestTextTitle", - TextContent = "TestTextContent", - AdditionalText = "TestAdditionalText", - }, - Toponyms = new List(), - ImagesIds = new List(), - Tags = new List(), - Subtitles = new List(), - Facts = new List(), - Videos = new List(), - Partners = new List(), - Arts = new List(), - StreetcodeArtSlides = new List(), - StatisticRecords = new List(), - StreetcodeCategoryContents = new List(), - Coordinates = new List(), - ImagesDetails = new List(), - TimelineItems = new List(), - RelatedFigures = new List(), - }; - } + Title = "TestTextTitle", + TextContent = "TestTextContent", + AdditionalText = "TestAdditionalText", + }, + Toponyms = new List(), + ImagesIds = new List(), + Tags = new List(), + Subtitles = new List(), + Facts = new List(), + Videos = new List(), + Partners = new List(), + Arts = new List(), + StreetcodeArtSlides = new List(), + StatisticRecords = new List(), + StreetcodeCategoryContents = new List(), + Coordinates = new List(), + ImagesDetails = new List(), + TimelineItems = new List(), + RelatedFigures = new List(), + }; + } - public override void After(MethodInfo methodUnderTest) + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var streetcodeContent = sqlDbHelper.GetExistItem(p => p.Index == StreetcodeForTest.Index); + if (streetcodeContent != null) { - var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); - var streetcodeContent = sqlDbHelper.GetExistItem(p => p.Index == StreetcodeForTest.Index); - if (streetcodeContent != null) - { - sqlDbHelper.DeleteItem(streetcodeContent); - sqlDbHelper.SaveChanges(); - } + sqlDbHelper.DeleteItem(streetcodeContent); + sqlDbHelper.SaveChanges(); } } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/ExtractStatisticRecordAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/ExtractStatisticRecordAttribute.cs new file mode 100644 index 000000000..ae0dedb09 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/ExtractStatisticRecordAttribute.cs @@ -0,0 +1,59 @@ +using System.Reflection; +using Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types; +using Streetcode.DAL.Entities.Analytics; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.AdditionalContent; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public class ExtractStatisticRecordAttribute : BeforeAfterTestAttribute +{ + public static int QrId { get; private set; } + + public static StreetcodeContent TestStreetcode { get; private set; } = null!; + + private static StreetcodeCoordinate TestCoordinate { get; set; } = null!; + + private static StatisticRecord TestStatisticRecord { get; set; } = null!; + + public override void Before( + MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + QrId = UniqueNumberGenerator.GenerateInt(); + var streetcodeId = UniqueNumberGenerator.GenerateInt(); + + TestStreetcode = StreetcodeContentExtracter + .Extract( + streetcodeId, + streetcodeId, + Guid.NewGuid().ToString()); + + TestCoordinate = CoordinateExtracter.Extract(streetcodeId, streetcodeId); + TestStatisticRecord = new StatisticRecord + { + QrId = QrId, + Count = 10, + Address = "Test Address", + StreetcodeId = TestStreetcode.Id, + StreetcodeCoordinateId = TestCoordinate.Id, + }; + + sqlDbHelper.AddNewItem(TestStatisticRecord); + sqlDbHelper.SaveChanges(); + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + sqlDbHelper.DeleteItem(TestStatisticRecord); + sqlDbHelper.DeleteItem(TestCoordinate); + sqlDbHelper.DeleteItem(TestStreetcode); + sqlDbHelper.SaveChanges(); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/RelatedFigure/ExtractCreateTestRelatedFigureAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/RelatedFigure/ExtractCreateTestRelatedFigureAttribute.cs new file mode 100644 index 000000000..90a61b73a --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/RelatedFigure/ExtractCreateTestRelatedFigureAttribute.cs @@ -0,0 +1,47 @@ +using System.Reflection; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.RelatedFigure; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.RelatedFigure; + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] +public class ExtractCreateTestRelatedFigureAttribute : BeforeAfterTestAttribute +{ + public static StreetcodeContent StreetcodeContent1 { get; private set; } = null!; + + public static StreetcodeContent StreetcodeContent2 { get; private set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + int observerId = UniqueNumberGenerator.GenerateInt(); + int targetId = UniqueNumberGenerator.GenerateInt(); + StreetcodeContent1 = StreetcodeContentExtracter + .Extract( + observerId, + observerId, + Guid.NewGuid().ToString()); + StreetcodeContent2 = StreetcodeContentExtracter + .Extract( + targetId, + targetId, + Guid.NewGuid().ToString()); + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var relatedFigures = sqlDbHelper.GetAll( + rf => rf.ObserverId == StreetcodeContent1.Id || rf.TargetId == StreetcodeContent2.Id); + foreach (var relatedFigure in relatedFigures) + { + RelatedFigureExtracter.Remove(relatedFigure); + } + + StreetcodeContentExtracter.Remove(StreetcodeContent1); + StreetcodeContentExtracter.Remove(StreetcodeContent2); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/RelatedFigure/ExtractDeleteTestRelatedFigureAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/RelatedFigure/ExtractDeleteTestRelatedFigureAttribute.cs new file mode 100644 index 000000000..ac6cd2539 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/RelatedFigure/ExtractDeleteTestRelatedFigureAttribute.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.RelatedFigure; +using Xunit.Sdk; +using RelateFigureEntity = Streetcode.DAL.Entities.Streetcode.RelatedFigure; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.RelatedFigure; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public class ExtractDeleteTestRelatedFigureAttribute : BeforeAfterTestAttribute +{ + public static StreetcodeContent StreetcodeContent1 { get; private set; } = new (); + + public static StreetcodeContent StreetcodeContent2 { get; private set; } = new (); + + public static RelateFigureEntity RelatedFigureForTest { get; private set; } = new (); + + public override void Before(MethodInfo methodUnderTest) + { + var observerId = UniqueNumberGenerator.GenerateInt(); + var targetId = UniqueNumberGenerator.GenerateInt(); + StreetcodeContent1 = StreetcodeContentExtracter + .Extract( + observerId, + observerId, + Guid.NewGuid().ToString()); + StreetcodeContent2 = StreetcodeContentExtracter + .Extract( + targetId, + targetId, + Guid.NewGuid().ToString()); + RelatedFigureForTest = RelatedFigureExtracter.Extract(StreetcodeContent1.Id, StreetcodeContent2.Id); + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var existingStreetcode1 = sqlDbHelper.GetExistItem(sc => sc.Id == StreetcodeContent1.Id); + var existingStreetcode2 = sqlDbHelper.GetExistItem(sc => sc.Id == StreetcodeContent2.Id); + if (existingStreetcode2 != null) + { + sqlDbHelper.DeleteItem(existingStreetcode2); + sqlDbHelper.SaveChanges(); + } + + if (existingStreetcode1 != null) + { + sqlDbHelper.DeleteItem(existingStreetcode1); + sqlDbHelper.SaveChanges(); + } + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Facts/ExtractCreateTestFactAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Facts/ExtractCreateTestFactAttribute.cs new file mode 100644 index 000000000..3633cbec0 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Facts/ExtractCreateTestFactAttribute.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; +using Streetcode.DAL.Entities.Media.Images; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.MediaExtracter.Image; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.TextContent.Facts; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public class ExtractCreateTestFactAttribute : BeforeAfterTestAttribute +{ + public static StreetcodeFactCreateDTO FactCreateDtoForTest { get; private set; } = null!; + + private static Image ImageForTest { get; set; } = null!; + + private static StreetcodeContent StreetcodeForTest { get; set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + var factIndex = UniqueNumberGenerator.GenerateInt(); + var imageId = UniqueNumberGenerator.GenerateInt(); + var streetcodeContentId = UniqueNumberGenerator.GenerateInt(); + + ImageForTest = ImageExtracter.Extract(imageId); + StreetcodeForTest = StreetcodeContentExtracter.Extract( + streetcodeContentId, + streetcodeContentId, + Guid.NewGuid().ToString()); + FactCreateDtoForTest = new StreetcodeFactCreateDTO() + { + Title = "StreetcodeFactCreateDto for create test", + ImageId = ImageForTest.Id, + FactContent = "Lorem ipsum dolor sit amet, consectetur adipiscing elit", + StreetcodeId = StreetcodeForTest.Id, + Index = factIndex, + ImageDescription = "Lorem ipsum dolor sit amet, consectetur adipiscing elit", + }; + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var fact = sqlDbHelper.GetExistItem(fact => fact.Title == FactCreateDtoForTest.Title); + + if (fact is not null) + { + sqlDbHelper.DeleteItem(fact); + } + + ImageExtracter.Remove(ImageForTest); + StreetcodeContentExtracter.Remove(StreetcodeForTest); + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Facts/ExtractDeleteTestFactAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Facts/ExtractDeleteTestFactAttribute.cs new file mode 100644 index 000000000..a61906f4e --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Facts/ExtractDeleteTestFactAttribute.cs @@ -0,0 +1,43 @@ +using System.Reflection; +using Streetcode.DAL.Entities.Media.Images; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.TextContent; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.TextContent.Facts; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public class ExtractDeleteTestFactAttribute : BeforeAfterTestAttribute +{ + public static Fact FactForTest { get; private set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + const string factTitle = "Fact for delete test"; + var factId = UniqueNumberGenerator.GenerateInt(); + + FactForTest = FactExtracter.Extract(factId, factTitle); + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var streetcodeContent = sqlDbHelper.GetExistItemId(FactForTest.StreetcodeId); + var image = sqlDbHelper.GetExistItemId((int)FactForTest.ImageId!); + + if (streetcodeContent is not null) + { + sqlDbHelper.DeleteItem(streetcodeContent); + sqlDbHelper.SaveChanges(); + } + + if (image is not null) + { + sqlDbHelper.DeleteItem(image); + sqlDbHelper.SaveChanges(); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Facts/ExtractUpdateTestFactAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Facts/ExtractUpdateTestFactAttribute.cs new file mode 100644 index 000000000..9f8a493f1 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Facts/ExtractUpdateTestFactAttribute.cs @@ -0,0 +1,38 @@ +using System.Reflection; +using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.TextContent.Facts; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public class ExtractUpdateTestFactAttribute : BeforeAfterTestAttribute +{ + public static StreetcodeFactUpdateDTO FactUpdateDtoForTest { get; private set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + var factIndex = UniqueNumberGenerator.GenerateInt(); + + FactUpdateDtoForTest = new StreetcodeFactUpdateDTO() + { + Id = 1, + Title = "FactDto for update test", + FactContent = "Lorem ipsum dolor sit amet, consectetur adipiscing elit", + Index = factIndex, + }; + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var fact = sqlDbHelper.GetExistItem(fact => fact.Title == FactUpdateDtoForTest.Title); + + if (fact is not null) + { + sqlDbHelper.DeleteItem(fact); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/RelatedTerms/ExtractCreateTestRelatedTermAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/RelatedTerms/ExtractCreateTestRelatedTermAttribute.cs new file mode 100644 index 000000000..ebb062cb3 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/RelatedTerms/ExtractCreateTestRelatedTermAttribute.cs @@ -0,0 +1,42 @@ +using System.Reflection; +using Streetcode.BLL.DTO.Streetcode.TextContent; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.TextContent; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.TextContent.RelatedTerms; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public class ExtractCreateTestRelatedTermAttribute : BeforeAfterTestAttribute +{ + public static RelatedTermCreateDTO RelatedTermCreateDtoForTest { get; private set; } = null!; + + private static Term TermForTest { get; set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + var termId = UniqueNumberGenerator.GenerateInt(); + + TermForTest = TermExtracter.Extract(termId); + RelatedTermCreateDtoForTest = new RelatedTermCreateDTO() + { + Word = "RelatedTermCreateDto for create test", + TermId = TermForTest.Id, + }; + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var relatedTerm = sqlDbHelper.GetExistItem(relatedTerm => relatedTerm.Word == RelatedTermCreateDtoForTest.Word); + + if (relatedTerm is not null) + { + sqlDbHelper.DeleteItem(relatedTerm); + } + + TermExtracter.Remove(TermForTest); + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/RelatedTerms/ExtractDeleteTestRelatedTermAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/RelatedTerms/ExtractDeleteTestRelatedTermAttribute.cs new file mode 100644 index 000000000..2fdd0c830 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/RelatedTerms/ExtractDeleteTestRelatedTermAttribute.cs @@ -0,0 +1,34 @@ +using System.Reflection; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.TextContent; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.TextContent.RelatedTerms; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public class ExtractDeleteTestRelatedTermAttribute : BeforeAfterTestAttribute +{ + public static RelatedTerm RelatedTermForTest { get; private set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + const string relatedTermWord = "RelatedTerm for delete test"; + var relatedTermId = UniqueNumberGenerator.GenerateInt(); + + RelatedTermForTest = RelatedTermExtracter.Extract(relatedTermId, relatedTermWord); + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var term = sqlDbHelper.GetExistItemId(RelatedTermForTest.TermId); + + if (term is not null) + { + sqlDbHelper.DeleteItem(term); + sqlDbHelper.SaveChanges(); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/RelatedTerms/ExtractUpdateTestRelatedTermAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/RelatedTerms/ExtractUpdateTestRelatedTermAttribute.cs new file mode 100644 index 000000000..0a03d8142 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/RelatedTerms/ExtractUpdateTestRelatedTermAttribute.cs @@ -0,0 +1,34 @@ +using System.Reflection; +using Streetcode.BLL.DTO.Streetcode.TextContent; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.TextContent.RelatedTerms; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public class ExtractUpdateTestRelatedTermAttribute : BeforeAfterTestAttribute +{ + public static RelatedTermDTO RelatedTermUpdateDtoForTest { get; private set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + RelatedTermUpdateDtoForTest = new RelatedTermDTO() + { + Id = 1, + Word = "RelatedTermDto for update test", + TermId = 1, + }; + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var relatedTerm = sqlDbHelper.GetExistItem(relatedTerm => relatedTerm.Word == RelatedTermUpdateDtoForTest.Word); + + if (relatedTerm is not null) + { + sqlDbHelper.DeleteItem(relatedTerm); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Terms/ExtractCreateTestTermAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Terms/ExtractCreateTestTermAttribute.cs new file mode 100644 index 000000000..12977a2d9 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Terms/ExtractCreateTestTermAttribute.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using Streetcode.BLL.DTO.Streetcode.TextContent; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.TextContent.Terms; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public class ExtractCreateTestTermAttribute : BeforeAfterTestAttribute +{ + public static TermCreateDTO TermCreateDtoForTest { get; private set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + TermCreateDtoForTest = new TermCreateDTO() + { + Title = "TermCreateDto for create test", + Description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit", + }; + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var term = sqlDbHelper.GetExistItem(term => term.Title == TermCreateDtoForTest.Title); + + if (term is not null) + { + sqlDbHelper.DeleteItem(term); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Terms/ExtractDeleteTestTermAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Terms/ExtractDeleteTestTermAttribute.cs new file mode 100644 index 000000000..6c49325b2 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Terms/ExtractDeleteTestTermAttribute.cs @@ -0,0 +1,21 @@ +using System.Reflection; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.TextContent; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.TextContent.Terms; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public class ExtractDeleteTestTermAttribute : BeforeAfterTestAttribute +{ + public static Term TermForTest { get; private set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + const string termTitle = "Term for delete test"; + var termId = UniqueNumberGenerator.GenerateInt(); + + TermForTest = TermExtracter.Extract(termId, termTitle); + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Terms/ExtractUpdateTestTermAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Terms/ExtractUpdateTestTermAttribute.cs new file mode 100644 index 000000000..6a51bb464 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Terms/ExtractUpdateTestTermAttribute.cs @@ -0,0 +1,34 @@ +using System.Reflection; +using Streetcode.BLL.DTO.Streetcode.TextContent; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.TextContent.Terms; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public class ExtractUpdateTestTermAttribute : BeforeAfterTestAttribute +{ + public static TermDTO TermUpdateDtoForTest { get; private set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + TermUpdateDtoForTest = new TermDTO() + { + Id = 1, + Title = "TermDto for update test", + Description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit", + }; + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var term = sqlDbHelper.GetExistItem(relatedTerm => relatedTerm.Title == TermUpdateDtoForTest.Title); + + if (term is not null) + { + sqlDbHelper.DeleteItem(term); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Texts/ExtractUpdateParsedTextTestTextAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Texts/ExtractUpdateParsedTextTestTextAttribute.cs new file mode 100644 index 000000000..ef3d0b32f --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Streetcode/TextContent/Texts/ExtractUpdateParsedTextTestTextAttribute.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using Streetcode.BLL.DTO.Streetcode.TextContent.Text; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Streetcode.TextContent.Texts; + +[AttributeUsage(AttributeTargets.Method, Inherited = false)] +public class ExtractUpdateParsedTextTestTextAttribute : BeforeAfterTestAttribute +{ + public static TextPreviewDTO TextPreviewUpdateDtoForTest { get; set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + TextPreviewUpdateDtoForTest = new TextPreviewDTO() + { + TextContent = "Lorem ipsum dolor sit amet, consectetur adipiscing elit", + }; + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Team/ExtractCreateTeamLinkAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Team/ExtractCreateTeamLinkAttribute.cs new file mode 100644 index 000000000..8c4bc8406 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Team/ExtractCreateTeamLinkAttribute.cs @@ -0,0 +1,34 @@ +using System.Reflection; +using Streetcode.BLL.DTO.Team; +using Streetcode.DAL.Entities.Team; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Team +{ + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + public class ExtractCreateTeamLinkAttribute : BeforeAfterTestAttribute + { + public static TeamMemberLinkCreateDTO TeamLinkForTest { get; set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + TeamLinkForTest = new TeamMemberLinkCreateDTO + { + LogoType = DAL.Enums.LogoType.Instagram, + TargetUrl = "https://instagram.com/testCreate", + }; + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var context = sqlDbHelper.GetExistItem(t => t.TargetUrl == TeamLinkForTest.TargetUrl); + if (context != null) + { + sqlDbHelper.DeleteItem(context); + sqlDbHelper.SaveChanges(); + } + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Team/ExtractCreateTeamMemberAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Team/ExtractCreateTeamMemberAttribute.cs new file mode 100644 index 000000000..4abbfbb21 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Team/ExtractCreateTeamMemberAttribute.cs @@ -0,0 +1,49 @@ +using System.Reflection; +using Streetcode.BLL.DTO.Team; +using Streetcode.DAL.Entities.Media.Images; +using Streetcode.DAL.Entities.Team; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.MediaExtracter.Image; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Team +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] + public class ExtractCreateTeamMemberAttribute : BeforeAfterTestAttribute + { + public static TeamMemberCreateDTO TeamMemberForTest { get; set; } = null!; + + private Image _image { get; set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + _image = ImageExtracter.Extract(UniqueNumberGenerator.GenerateInt()); + TeamMemberForTest = new TeamMemberCreateDTO + { + Name = "test create", + Description = "test create description", + IsMain = false, + ImageId = _image.Id, + }; + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var context = sqlDbHelper.GetExistItem(t => t.Name == TeamMemberForTest.Name); + if (context != null) + { + sqlDbHelper.DeleteItem(context); + sqlDbHelper.SaveChanges(); + } + + var image = sqlDbHelper.GetExistItem(t => t.Id == _image.Id); + if (image != null) + { + sqlDbHelper.DeleteItem(image); + sqlDbHelper.SaveChanges(); + } + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Team/ExtractDeleteTeamMemberAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Team/ExtractDeleteTeamMemberAttribute.cs new file mode 100644 index 000000000..2714f1e43 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Team/ExtractDeleteTeamMemberAttribute.cs @@ -0,0 +1,63 @@ +using System.Reflection; +using Streetcode.BLL.DTO.Team; +using Streetcode.DAL.Entities.Media.Images; +using Streetcode.DAL.Entities.Team; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.AdditionalContent; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.MediaExtracter.Image; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Team +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] + public class ExtractDeleteTeamMemberAttribute : BeforeAfterTestAttribute + { + public static UpdateTeamMemberDTO TeamMemberForTest { get; set; } = null!; + + private TeamMember _teamMember { get; set; } = null!; + + private Image _image { get; set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + int uniqueId = UniqueNumberGenerator.GenerateInt(); + _image = ImageExtracter.Extract(uniqueId); + _teamMember = TeamMemberExtracter.Extract(uniqueId, _image.Id); + + TeamMemberForTest = new UpdateTeamMemberDTO + { + Id = _teamMember.Id, + Name = "test", + Description = "test description", + IsMain = false, + ImageId = _image.Id, + }; + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var context = sqlDbHelper.GetExistItem(t => t.Id == TeamMemberForTest.Id); + if (context != null) + { + sqlDbHelper.DeleteItem(context); + sqlDbHelper.SaveChanges(); + } + + var image = sqlDbHelper.GetExistItem(t => t.Id == _image.Id); + if (image != null) + { + sqlDbHelper.DeleteItem(image); + sqlDbHelper.SaveChanges(); + } + + var teamMember = sqlDbHelper.GetExistItem(t => t.Id == _teamMember.Id); + if (teamMember != null) + { + sqlDbHelper.DeleteItem(teamMember); + sqlDbHelper.SaveChanges(); + } + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Team/ExtractUpdateTeamMemberAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Team/ExtractUpdateTeamMemberAttribute.cs new file mode 100644 index 000000000..2cb45671b --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Team/ExtractUpdateTeamMemberAttribute.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using Streetcode.BLL.DTO.Team; +using Streetcode.DAL.Entities.Media.Images; +using Streetcode.DAL.Entities.Team; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.AdditionalContent; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.MediaExtracter.Image; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Team +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] + public class ExtractUpdateTeamMemberAttribute : BeforeAfterTestAttribute + { + private TeamMember _teamMember = null!; + private Image _image = null!; + + public static UpdateTeamMemberDTO TeamMemberForTest { get; set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + int uniqueId = UniqueNumberGenerator.GenerateInt(); + _image = ImageExtracter.Extract(uniqueId); + _teamMember = TeamMemberExtracter.Extract(uniqueId, _image.Id); + + TeamMemberForTest = new UpdateTeamMemberDTO + { + Id = _teamMember.Id, + Name = "test", + Description = "test description", + IsMain = false, + ImageId = _image.Id, + }; + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var teamMember = sqlDbHelper.GetExistItem(t => t.Id == TeamMemberForTest.Id); + if (teamMember != null) + { + sqlDbHelper.DeleteItem(teamMember); + sqlDbHelper.SaveChanges(); + } + + var image = sqlDbHelper.GetExistItem(t => t.Id == _image.Id); + if (image != null) + { + sqlDbHelper.DeleteItem(image); + sqlDbHelper.SaveChanges(); + } + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Users/ExtractUpdateTestUserAttribute.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Users/ExtractUpdateTestUserAttribute.cs new file mode 100644 index 000000000..ec67ea735 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/BeforeAndAfterTestAtribute/Users/ExtractUpdateTestUserAttribute.cs @@ -0,0 +1,65 @@ +using System.Reflection; +using Streetcode.BLL.DTO.Users; +using Streetcode.DAL.Entities.Users; +using Streetcode.XIntegrationTest.ControllerTests.BaseController; +using Xunit.Sdk; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.BeforeAndAfterTestAtribute.Users; + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] +public class ExtractUpdateTestUserAttribute : BeforeAfterTestAttribute +{ + private static User? _testUserEntity; + + public static UpdateUserDTO UserForTest { get; private set; } = null!; + + public override void Before(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + + var uniqueId = Guid.NewGuid().ToString(); + string testUserName = $"testuser_{uniqueId.Substring(0, 8)}".ToLower(); + string testEmail = $"test_{uniqueId.Substring(0, 8)}@example.com"; + + _testUserEntity = new User + { + Name = "testname", + Surname = "testsurname", + Id = uniqueId, + UserName = testUserName, + NormalizedUserName = testUserName.ToUpper(), + Email = testEmail, + PasswordHash = GenerateTestPassword(), + }; + + sqlDbHelper.AddNewItem(_testUserEntity); + sqlDbHelper.SaveChanges(); + + UserForTest = new UpdateUserDTO + { + Name = "UpdatedName", + Surname = "UpdatedSurname", + UserName = $"Updated_{testUserName}", + AboutYourself = "Updated description", + PhoneNumber = "+380735004490", + Email = testEmail, + }; + } + + public override void After(MethodInfo methodUnderTest) + { + var sqlDbHelper = BaseControllerTests.GetSqlDbHelper(); + var user = sqlDbHelper.GetExistItem(u => u.Email == UserForTest.Email); + if (user != null) + { + sqlDbHelper.DeleteItem(user); + sqlDbHelper.SaveChanges(); + } + } + + private string GenerateTestPassword() + { + string guid = Guid.NewGuid().ToString(); + return $"TestPass123_{guid.Substring(0, 10)}"; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Analytics/AnalyticsClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Analytics/AnalyticsClient.cs new file mode 100644 index 000000000..c0cc93883 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Analytics/AnalyticsClient.cs @@ -0,0 +1,43 @@ +using RestSharp; +using Streetcode.BLL.DTO.Analytics; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Analytics; + +public class AnalyticsClient : BaseClient +{ + public AnalyticsClient(HttpClient client, string secondPartUrl = "") + : base(client, secondPartUrl) + { + } + + public async Task Update(int id, string authToken = "") + { + return await SendCommand($"/Update/{id}", Method.Put, authToken); + } + + public async Task GetAll(string authToken = "") + { + return await SendQuery($"/GetAll", authToken); + } + + public async Task GetByQrId(int qrId, string authToken = "") + { + return await SendQuery($"/GetByQrId/{qrId}", authToken); + } + + public async Task ExistByQrId(int qrId, string authToken = "") + { + return await SendQuery($"/ExistByQrId/{qrId}", authToken); + } + + public async Task GetAllByStreetcodeId(int streetcodeId, string authToken = "") + { + return await SendQuery($"/GetAllByStreetcodeId/{streetcodeId}", authToken); + } + + public async Task Delete(int id, string authToken = "") + { + return await SendCommand($"/Delete/{id}", Method.Delete, authToken); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Authentication/AuthenticationClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Authentication/AuthenticationClient.cs index 808eb1f5f..1bdd3b4a8 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Authentication/AuthenticationClient.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Authentication/AuthenticationClient.cs @@ -1,4 +1,5 @@ using RestSharp; +using Streetcode.BLL.DTO.Authentication.GoogleLogin; using Streetcode.BLL.DTO.Authentication.Login; using Streetcode.BLL.DTO.Authentication.RefreshToken; using Streetcode.BLL.DTO.Authentication.Register; @@ -15,17 +16,27 @@ public AuthenticationClient(HttpClient client, string secondPartUrl = "") public async Task Login(LoginRequestDTO loginRequestDTO) { - return await this.SendCommand("/Login", Method.Post, loginRequestDTO); + return await SendCommand("/Login", Method.Post, loginRequestDTO); } public async Task Register(RegisterRequestDTO registerRequestDTO) { - return await this.SendCommand("/Register", Method.Post, registerRequestDTO); + return await SendCommand("/Register", Method.Post, registerRequestDTO); } public async Task RefreshToken(RefreshTokenRequestDTO refreshTokenRequestDTO) { - return await this.SendCommand("/RefreshToken", Method.Post, refreshTokenRequestDTO); + return await SendCommand("/RefreshToken", Method.Post, refreshTokenRequestDTO); + } + + public async Task Logout(string authToken = "") + { + return await SendCommand("/Logout", Method.Post, authToken: authToken); + } + + public async Task GoogleLogin(GoogleLoginRequest googleLoginRequest, string authToken = "") + { + return await SendCommand("/GoogleLogin", Method.Post, googleLoginRequest, authToken: authToken); } } } diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Base/BaseClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Base/BaseClient.cs index f30d39607..48b29191d 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Base/BaseClient.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Base/BaseClient.cs @@ -1,5 +1,4 @@ using RestSharp; -using RestSharp.Serializers; namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base { @@ -10,18 +9,18 @@ public class BaseClient public BaseClient(HttpClient client, string secondPartUrl = "") { this.client = new RestClient(client) { AcceptedContentTypes = ContentType.JsonAccept }; - this.SecondPartUrl = secondPartUrl; + SecondPartUrl = secondPartUrl; } protected string SecondPartUrl { get; } protected async Task SendQuery(string requestString, string authToken = "") { - var request = new RestRequest($"{this.SecondPartUrl}{requestString}"); + var request = new RestRequest($"{SecondPartUrl}{requestString}"); RestResponse response; try { - response = await this.SendRequest(request, authToken); + response = await SendRequest(request, authToken); } catch (Exception ex) { @@ -32,15 +31,19 @@ protected async Task SendQuery(string requestString, string authTo return response; } - protected async Task SendCommand(string requestString, Method method, T requestDto, string authToken = "") - where T : class + protected async Task SendCommand(string requestString, Method method, T? requestDto = default, string authToken = "") + where T : class? { - var request = new RestRequest($"{this.SecondPartUrl}{requestString}", method); - request.AddJsonBody(requestDto); + var request = new RestRequest($"{SecondPartUrl}{requestString}", method); + if (requestDto is not null) + { + request.AddJsonBody(requestDto); + } + RestResponse response; try { - response = await this.SendRequest(request, authToken); + response = await SendRequest(request, authToken); } catch (Exception ex) { @@ -50,13 +53,18 @@ protected async Task SendCommand(string requestString, Method m return response; } + protected async Task SendCommand(string requestString, Method method, string authToken = "") + { + return await SendCommand(requestString, method, null, authToken); + } + private async Task SendRequest(RestRequest request, string authToken) { request.OnBeforeDeserialization = resp => { resp.ContentType = "application/json"; }; request.AddHeader("Authorization", $"Bearer {authToken}"); request.AddHeader("Content-Type", "application/json"); - var response = await this.client.ExecuteAsync(request); + var response = await client.ExecuteAsync(request); return response; } } diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Email/EmailClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Email/EmailClient.cs new file mode 100644 index 000000000..6f9b8cb43 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Email/EmailClient.cs @@ -0,0 +1,18 @@ +using RestSharp; +using Streetcode.BLL.DTO.Email; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Email; + +public class EmailClient : BaseClient +{ + public EmailClient(HttpClient client, string secondPartUrl = "") + : base(client, secondPartUrl) + { + } + + public async Task Send(EmailDTO emailDto, string authToken = "") + { + return await SendCommand("/Send", Method.Post, emailDto, authToken); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/RelatedFigureClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/RelatedFigureClient.cs new file mode 100644 index 000000000..6e3b6c16f --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/RelatedFigureClient.cs @@ -0,0 +1,30 @@ +using RestSharp; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.StreetCode; + +public class RelatedFigureClient : StreetcodeRelatedBaseClient +{ + public RelatedFigureClient( + HttpClient client, string secondPartUrl = "") + : base(client, secondPartUrl) + { + } + + public async Task GetByTagId(int id, string authToken = "") + { + return await SendQuery($"/GetByTagId/{id}", authToken); + } + + public async Task Create(int observerId, int targetId, string authToken = "") + { + var requestBody = new { observerId, targetId }; + return await SendCommand($"/Create/{observerId}&{targetId}", Method.Post, requestBody, authToken); + } + + public async Task Delete(int observerId, int targetId, string authToken = "") + { + var requestBody = new { observerId, targetId }; + return await SendCommand($"/Delete/{observerId}&{targetId}", Method.Delete, requestBody, authToken); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/StreetcodeClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/StreetcodeClient.cs index 1dbad6c74..458345970 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/StreetcodeClient.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/StreetcodeClient.cs @@ -1,6 +1,11 @@ using RestSharp; +using Streetcode.BLL.DTO.AdditionalContent.Filter; +using Streetcode.BLL.DTO.Streetcode; using Streetcode.BLL.DTO.Streetcode.Create; using Streetcode.BLL.DTO.Streetcode.Update; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.Delete; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.DeleteSoft; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.UpdateStatus; using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.StreetCode @@ -12,19 +17,102 @@ public StreetcodeClient(HttpClient client, string secondPartUrl = "") { } - public async Task GetArtsByStreetcodeId(int id, string authToken = "") + public async Task UpdateAsync(StreetcodeUpdateDTO updateStreetcodeDto, string authToken = "") { - return await this.SendQuery($"/getArtsByStreetcodeId/{id}", authToken); + return await SendCommand("/Update", Method.Put, updateStreetcodeDto, authToken); } - public async Task UpdateAsync(StreetcodeUpdateDTO updateStreetcodeDTO, string authToken = "") + public async Task CreateAsync(StreetcodeCreateDTO createStreetcodeDto, string authToken = "") { - return await this.SendCommand("/Update", Method.Put, updateStreetcodeDTO, authToken); + return await SendCommand("/Create", Method.Post, createStreetcodeDto, authToken); } - public async Task CreateAsync(StreetcodeCreateDTO createStreetcodeDTO, string authToken = "") + public async Task GetAllAsync(GetAllStreetcodesRequestDTO request) { - return await this.SendCommand("/Create", Method.Post, createStreetcodeDTO, authToken); + string queryString = QueryStringHelper.ToQueryString(request); + return await SendQuery($"/GetAll{queryString}"); + } + + public async Task GetAllPublishedAsync() + { + return await SendQuery("/GetAllPublished"); + } + + public async Task GetAllShortAsync() + { + return await SendQuery("/GetAllShort"); + } + + public async Task GetAllMainPageAsync() + { + return await SendQuery("/GetAllMainPage"); + } + + public async Task GetPageMainPageAsync(ushort page, ushort pageSize) + { + return await SendQuery($"/GetPageMainPage?page={page}&pageSize={pageSize}"); + } + + public async Task GetShortByIdAsync(int id) + { + return await SendQuery($"/GetShortById/{id}"); + } + + public async Task GetByFilterAsync(StreetcodeFilterRequestDTO request) + { + string queryString = QueryStringHelper.ToQueryString(request); + return await SendQuery($"/GetByFilter{queryString}"); + } + + public async Task ExistWithIndexAsync(int index) + { + return await SendQuery($"/ExistWithIndex/{index}"); + } + + public async Task ExistWithUrlAsync(string url) + { + return await SendQuery($"/ExistWithUrl/{url}"); + } + + public async Task GetAllCatalogAsync(int page, int count) + { + return await SendQuery($"/GetAllCatalog?page={page}&count={count}"); + } + + public async Task GetCountAsync(bool? onlyPublished) + { + var query = onlyPublished.HasValue ? $"?onlyPublished={onlyPublished.Value}" : string.Empty; + return await SendQuery($"/GetCount{query}"); + } + + public async Task GetByTransliterationUrl(string url) + { + return await SendQuery($"/GetByTransliterationUrl/{url}"); + } + + public async Task GetByQrIdAsync(int qrid) + { + return await SendQuery($"/GetByQrId/{qrid}"); + } + + public async Task GetByIndexAsync(int index) + { + return await SendQuery($"/GetByIndex/{index}"); + } + + public async Task PatchStageAsync(UpdateStatusStreetcodeByIdCommand request, string authToken = "") + { + return await SendCommand($"/PatchStage/{request.Id}/{request.Status}", Method.Put, request, authToken); + } + + public async Task SoftDeleteAsync(DeleteSoftStreetcodeCommand request, string authToken = "") + { + return await SendCommand($"/SoftDelete/{request.Id}", Method.Delete, request, authToken); + } + + public async Task DeleteAsync(DeleteStreetcodeCommand request, string authToken = "") + { + return await SendCommand($"/Delete/{request.Id}", Method.Delete, request, authToken); } } } diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/TextContent/FactClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/TextContent/FactClient.cs new file mode 100644 index 000000000..f96d6dcf3 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/TextContent/FactClient.cs @@ -0,0 +1,28 @@ +using RestSharp; +using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.StreetCode.TextContent; + +public class FactClient : StreetcodeRelatedBaseClient +{ + public FactClient(HttpClient client, string secondPathUrl = "") + : base(client, secondPathUrl) + { + } + + public async Task Create(StreetcodeFactCreateDTO streetcodeFactCreateDto, string authToken = "") + { + return await SendCommand("/Create", Method.Post, streetcodeFactCreateDto, authToken); + } + + public async Task Update(int id, StreetcodeFactUpdateDTO factUpdateDto, string authToken = "") + { + return await SendCommand($"/Update/{id}", Method.Put, factUpdateDto, authToken); + } + + public async Task Delete(int id, string authToken = "") + { + return await SendCommand($"/Delete/{id}", Method.Delete, new FactDto(), authToken); + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/TextContent/RelatedTermClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/TextContent/RelatedTermClient.cs new file mode 100644 index 000000000..b4efb1b29 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/TextContent/RelatedTermClient.cs @@ -0,0 +1,33 @@ +using RestSharp; +using Streetcode.BLL.DTO.Streetcode.TextContent; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.StreetCode.TextContent; + +public class RelatedTermClient : StreetcodeRelatedBaseClient +{ + public RelatedTermClient(HttpClient client, string secondPathUrl = "") + : base(client, secondPathUrl) + { + } + + public async Task GetByTermId(int id, string authToken = "") + { + return await SendQuery($"/GetByTermId/{id}", authToken); + } + + public async Task Create(RelatedTermCreateDTO relatedTermCreateDto, string authToken = "") + { + return await SendCommand("/Create", Method.Post, relatedTermCreateDto, authToken); + } + + public async Task Update(int id, RelatedTermDTO relatedTermUpdateDto, string authToken = "") + { + return await SendCommand($"/Update/{id}", Method.Put, relatedTermUpdateDto, authToken); + } + + public async Task Delete(string word, string authToken = "") + { + return await SendCommand($"/Delete/{word}", Method.Delete, new RelatedTermDTO(), authToken); + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/TextContent/TermClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/TextContent/TermClient.cs new file mode 100644 index 000000000..ee99889b8 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/TextContent/TermClient.cs @@ -0,0 +1,28 @@ +using RestSharp; +using Streetcode.BLL.DTO.Streetcode.TextContent; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.StreetCode.TextContent; + +public class TermClient : StreetcodeRelatedBaseClient +{ + public TermClient(HttpClient client, string secondPathUrl = "") + : base(client, secondPathUrl) + { + } + + public async Task Create(TermCreateDTO streetcodeFactCreateDto, string authToken = "") + { + return await SendCommand("/Create", Method.Post, streetcodeFactCreateDto, authToken); + } + + public async Task Update(TermDTO termUpdateDto, string authToken = "") + { + return await SendCommand($"/Update", Method.Put, termUpdateDto, authToken); + } + + public async Task Delete(int id, string authToken = "") + { + return await SendCommand($"/Delete/{id}", Method.Delete, new TermDTO(), authToken); + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/TextContent/TextClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/TextContent/TextClient.cs new file mode 100644 index 000000000..5427b5eff --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/StreetCode/TextContent/TextClient.cs @@ -0,0 +1,18 @@ +using RestSharp; +using Streetcode.BLL.DTO.Streetcode.TextContent.Text; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.StreetCode.TextContent; + +public class TextClient : StreetcodeRelatedBaseClient +{ + public TextClient(HttpClient client, string secondPathUrl = "") + : base(client, secondPathUrl) + { + } + + public async Task UpdateParsedText(TextPreviewDTO textPreviewDto, string authToken = "") + { + return await SendCommand("/UpdateParsedText", Method.Post, textPreviewDto, authToken); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Team/TeamClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Team/TeamClient.cs new file mode 100644 index 000000000..9716d495b --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Team/TeamClient.cs @@ -0,0 +1,49 @@ +using RestSharp; +using Streetcode.BLL.DTO.Team; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Team +{ + public class TeamClient : BaseClient + { + public TeamClient(HttpClient client, string secondPartUrl = "") + : base(client, secondPartUrl) + { + } + + public async Task GetAllAsync(ushort page, ushort pageSize, string authToken = "") + { + return await this.SendQuery($"/GetAll?page={page}&pageSize={pageSize}", authToken); + } + + public async Task GetAllMainAsync(string authToken = "") + { + return await this.SendQuery($"/GetAllMain", authToken); + } + + public async Task GetByIdAsync(int id, string authToken = "") + { + return await this.SendQuery($"/GetById/{id}", authToken); + } + + public async Task GetByRoleIdAsync(int id, string authToken = "") + { + return await this.SendQuery($"/GetByRoleId/{id}", authToken); + } + + public async Task CreateAsync(TeamMemberCreateDTO createTeamMemberDTO, string authToken = "") + { + return await this.SendCommand("/Create", Method.Post, createTeamMemberDTO, authToken); + } + + public async Task UpdateAsync(UpdateTeamMemberDTO createTeamMemberDTO, string authToken = "") + { + return await this.SendCommand("/Update", Method.Put, createTeamMemberDTO, authToken); + } + + public async Task DeleteAsync(int id, string authToken = "") + { + return await this.SendCommand($"/Delete/{id}", Method.Delete, new TeamMemberDTO(), authToken); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Team/TeamLinkClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Team/TeamLinkClient.cs new file mode 100644 index 000000000..34586686f --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Team/TeamLinkClient.cs @@ -0,0 +1,24 @@ +using RestSharp; +using Streetcode.BLL.DTO.Team; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Team +{ + public class TeamLinkClient : BaseClient + { + public TeamLinkClient(HttpClient client, string secondPartUrl = "") + : base(client, secondPartUrl) + { + } + + public async Task GetAllAsync(string authToken = "") + { + return await this.SendQuery("/GetAll", authToken); + } + + public async Task CreateAsync(TeamMemberLinkCreateDTO teamMemberLink, string authToken = "") + { + return await this.SendCommand("/Create", Method.Post, teamMemberLink, authToken); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Team/TickerStringClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Team/TickerStringClient.cs new file mode 100644 index 000000000..f49c145bf --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Team/TickerStringClient.cs @@ -0,0 +1,18 @@ +using RestSharp; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Team +{ + public class TickerStringClient : BaseClient + { + public TickerStringClient(HttpClient client, string secondPartUrl = "") + : base(client, secondPartUrl) + { + } + + public async Task GetNameTickerString(string authToken = "") + { + return await this.SendQuery("/GetNameTickerString/", authToken); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Timeline/TimelineClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Timeline/TimelineClient.cs new file mode 100644 index 000000000..00e48cd10 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Timeline/TimelineClient.cs @@ -0,0 +1,12 @@ +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Timeline +{ + public class TimelineClient : StreetcodeRelatedBaseClient + { + public TimelineClient(HttpClient client, string secondPartUrl = "") + : base(client, secondPartUrl) + { + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Toponym/ToponymsClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Toponym/ToponymsClient.cs new file mode 100644 index 000000000..1ae5d19ea --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Toponym/ToponymsClient.cs @@ -0,0 +1,12 @@ +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Toponym +{ + public class ToponymsClient : StreetcodeRelatedBaseClient + { + public ToponymsClient(HttpClient client, string secondPartUrl = "") + : base(client, secondPartUrl) + { + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Transaction/TransactLinksClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Transaction/TransactLinksClient.cs new file mode 100644 index 000000000..861002cc7 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Transaction/TransactLinksClient.cs @@ -0,0 +1,12 @@ +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Transaction +{ + public class TransactLinksClient : StreetcodeRelatedBaseClient + { + public TransactLinksClient(HttpClient client, string secondPartUrl = "") + : base(client, secondPartUrl) + { + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Users/Expertises/ExpertiseClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Users/Expertises/ExpertiseClient.cs new file mode 100644 index 000000000..e54e3a9d3 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Users/Expertises/ExpertiseClient.cs @@ -0,0 +1,17 @@ +using RestSharp; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Users.Expertises; + +public class ExpertiseClient : BaseClient +{ + public ExpertiseClient(HttpClient client, string secondPartUrl = "") + : base(client, secondPartUrl) + { + } + + public async Task GetAll(string authToken = "") + { + return await SendQuery("/GetAll", authToken); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Users/UserClient.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Users/UserClient.cs new file mode 100644 index 000000000..c2f00db1d --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Client/Users/UserClient.cs @@ -0,0 +1,49 @@ +using RestSharp; +using Streetcode.BLL.DTO.Users; +using Streetcode.BLL.DTO.Users.Password; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Client.Users; + +public class UserClient : BaseClient +{ + public UserClient(HttpClient client, string secondPartUrl = "") + : base(client, secondPartUrl) + { + } + + public async Task GetByEmail(string authToken = "") + { + return await SendQuery("/GetByEmail", authToken); + } + + public async Task ExistWithUserName(string userName, string authToken = "") + { + return await SendQuery($"/ExistWithUserName/{userName}", authToken); + } + + public async Task GetOtherUserByUserName(string otherUserName, string authToken = "") + { + return await SendQuery($"/GetOtherUserByUserName/{otherUserName}", authToken); + } + + public async Task Update(UpdateUserDTO updateUserDto, string authToken = "") + { + return await SendCommand("/Update", Method.Put, updateUserDto, authToken); + } + + public async Task Delete(string email, string authToken = "") + { + return await SendCommand($"/Delete/{email}", Method.Delete, authToken); + } + + public async Task ForgotPassword(ForgotPasswordDTO updateForgotPasswordDto, string authToken = "") + { + return await SendCommand("/ForgotPassword", Method.Post, updateForgotPasswordDto, authToken); + } + + public async Task UpdateForgotPassword(UpdateForgotPasswordDTO updateForgotPasswordDto, string authToken = "") + { + return await SendCommand("/UpdateForgotPassword", Method.Put, updateForgotPasswordDto, authToken); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/CustomWebApplicationFactory.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/CustomWebApplicationFactory.cs index 8e27ecf3f..58056dde3 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/CustomWebApplicationFactory.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/CustomWebApplicationFactory.cs @@ -1,15 +1,71 @@ -namespace Streetcode.XIntegrationTest.ControllerTests.Utils -{ - using System; - using Microsoft.AspNetCore.Hosting; - using Microsoft.AspNetCore.Mvc.Testing; +using Google.Apis.Auth; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Streetcode.BLL.Interfaces.Authentication; +using Streetcode.BLL.Interfaces.Email; +using Streetcode.BLL.Models.Email.Messages.Base; +using Streetcode.DAL.Entities.Users; +namespace Streetcode.XIntegrationTest.ControllerTests.Utils +{ public class CustomWebApplicationFactory : WebApplicationFactory where TProgram : class { + public Mock EmailServiceMock { get; private set; } = new Mock(); + + public Mock GoogleServiceMock { get; private set; } = new Mock(); + + public void SetupMockGoogleLogin(User user, string? token = null) + { + if (token is null) + { + GoogleServiceMock + .Setup(gs => gs.ValidateGoogleToken("invalid_google_id_token")) + .ThrowsAsync(new InvalidJwtException("Invalid Google Token")); + } + else + { + GoogleServiceMock + .Setup(gs => gs.ValidateGoogleToken(It.IsAny())) + .ReturnsAsync(new GoogleJsonWebSignature.Payload + { + Email = user.Email, + GivenName = user.Name, + FamilyName = user.Surname, + Subject = "google-subject-id", + }); + } + } + + public void SetupMockEmailService(bool success = true) + { + EmailServiceMock.Setup(es => es.SendEmailAsync(It.IsAny())) + .ReturnsAsync(success); + } + protected override void ConfigureWebHost(IWebHostBuilder builder) { Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "IntegrationTests"); + + builder.ConfigureServices(services => + { + var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(IEmailService)); + if (descriptor != null) + { + services.Remove(descriptor); + } + + var googleDescriptor = services.SingleOrDefault(d => d.ServiceType == typeof(IGoogleService)); + if (googleDescriptor != null) + { + services.Remove(googleDescriptor); + } + + services.AddSingleton(EmailServiceMock.Object); + services.AddSingleton(GoogleServiceMock.Object); + }); } } } diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/AdditionalContent/TeamMemberExtracter.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/AdditionalContent/TeamMemberExtracter.cs index dca38a9f4..f7d7842eb 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/AdditionalContent/TeamMemberExtracter.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/AdditionalContent/TeamMemberExtracter.cs @@ -1,21 +1,26 @@ -using Streetcode.DAL.Entities.Team; +using Streetcode.DAL.Entities.Media.Images; +using Streetcode.DAL.Entities.Team; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.MediaExtracter.Image; namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.AdditionalContent { public static class TeamMemberExtracter { - public static TeamMember Extract(int teamMemberId) + public static TeamMember Extract(int teamMemberId, int imageId) { TeamMember testTeamMember = TestDataProvider.GetTestData(); testTeamMember.Id = teamMemberId; + testTeamMember.ImageId = imageId; - return BaseExtracter.Extract(testTeamMember, teamMember => teamMember.Id == teamMemberId); + ImageExtracter.Extract(imageId); + return BaseExtracter.Extract(testTeamMember, teamMember => teamMember.Id == teamMemberId); } public static void Remove(TeamMember entity) { BaseExtracter.RemoveByPredicate(teamMember => teamMember.Id == entity.Id); + BaseExtracter.RemoveByPredicate(image => image.Id == entity.ImageId); } } } diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Analytics/StatisticRecordExtracter.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Analytics/StatisticRecordExtracter.cs new file mode 100644 index 000000000..71869f3a1 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Analytics/StatisticRecordExtracter.cs @@ -0,0 +1,28 @@ +using Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types; +using Streetcode.DAL.Entities.Analytics; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Analytics; + +public static class StatisticRecordExtracter +{ + public static StatisticRecord Extract(int id, int streetcodeId) + { + StatisticRecord testStatisticRecord = TestDataProvider.GetTestData(); + StreetcodeCoordinate testStreetcodeCoordinate = new StreetcodeCoordinate + { + StreetcodeId = streetcodeId, + Latitude = 50, + Longtitude = 50, + }; + testStatisticRecord.StreetcodeCoordinate = testStreetcodeCoordinate; + testStatisticRecord.StreetcodeId = streetcodeId; + testStatisticRecord.Id = id; + + return BaseExtracter.Extract(testStatisticRecord, strCont => strCont.Id == id); + } + + public static void Remove(StatisticRecord entity) + { + BaseExtracter.RemoveById(entity.Id); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Authentication/UserExtracter.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Authentication/UserExtracter.cs index 1157f7e09..5c2b7bd4d 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Authentication/UserExtracter.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Authentication/UserExtracter.cs @@ -11,7 +11,10 @@ public static (User user, string password) Extract(string userId, string userNam User testUser = TestDataProvider.GetTestData(); testUser.Id = userId; testUser.UserName = userName; + testUser.NormalizedUserName = userName.ToUpper(); testUser.PasswordHash = HashPassword(password, testUser); + testUser.Email += RemoveIncorrectSymbolsFromEmail(userId); + testUser.NormalizedEmail += RemoveIncorrectSymbolsFromEmail(userId); BaseExtracter.Extract(testUser, user => user.Id == userId, false); if (roleNames.Length == 0) { @@ -20,7 +23,7 @@ public static (User user, string password) Extract(string userId, string userNam return (testUser, password); } - foreach (var roleName in roleNames) + for (var i = 0; i < roleNames.Length; i++) { IdentityRole role = RoleExtracter.Extract(nameof(UserRole.User)); RoleExtracter.AddUserRole(testUser.Id, role.Id); @@ -34,10 +37,16 @@ public static void Remove(User entity) BaseExtracter.RemoveByPredicate(user => user.Id == entity.Id); } + private static string RemoveIncorrectSymbolsFromEmail(string email) + { + return string.Concat(email.Where(char.IsLetter))!; + } + private static string HashPassword(string password, User user) { var hasher = new PasswordHasher(); var hashedPassword = hasher.HashPassword(user, password); + return hashedPassword; } } diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Expertises/ExpertiseExtracter.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Expertises/ExpertiseExtracter.cs new file mode 100644 index 000000000..be80bee4e --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Expertises/ExpertiseExtracter.cs @@ -0,0 +1,16 @@ +using Streetcode.DAL.Entities.Users.Expertise; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Expertises; + +public static class ExpertiseExtracter +{ + public static Expertise Extract(int expertiseId) + { + var testExpertise = TestDataProvider.GetTestData(); + + testExpertise.Id = expertiseId; + var extracter = BaseExtracter.Extract(testExpertise, e => e.Id == expertiseId); + + return extracter; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/RelatedFigure/RelatedFigureExtracter.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/RelatedFigure/RelatedFigureExtracter.cs new file mode 100644 index 000000000..e86ae587d --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/RelatedFigure/RelatedFigureExtracter.cs @@ -0,0 +1,51 @@ +using Streetcode.DAL.Entities.AdditionalContent; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.AdditionalContent; +using RelatedFigureEntity = Streetcode.DAL.Entities.Streetcode.RelatedFigure; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.RelatedFigure; + +public static class RelatedFigureExtracter +{ + public static (StreetcodeContent, StreetcodeContent, RelatedFigureEntity, Tag) ExtractTestData() + { + var observerId = UniqueNumberGenerator.GenerateInt(); + var targetId = UniqueNumberGenerator.GenerateInt(); + + var testStreetcodeContent1 = StreetcodeContentExtracter.Extract( + observerId, + observerId, + Guid.NewGuid().ToString()); + + var testStreetcodeContent2 = StreetcodeContentExtracter.Extract( + targetId, + targetId, + Guid.NewGuid().ToString()); + + var testRelatedFigure = Extract(testStreetcodeContent1.Id, testStreetcodeContent2.Id); + + var testTag = TagExtracter.Extract(targetId, Guid.NewGuid().ToString()); + + return (testStreetcodeContent1, testStreetcodeContent2, testRelatedFigure, testTag); + } + + public static RelatedFigureEntity Extract(int observerId, int targetId) + { + var testRelatedFigure = new RelatedFigureEntity + { + ObserverId = observerId, + TargetId = targetId, + }; + + var extractor = BaseExtracter.Extract(testRelatedFigure, figure => + figure.ObserverId == observerId && figure.TargetId == targetId); + return extractor; + } + + public static void Remove(RelatedFigureEntity entity) + { + BaseExtracter.RemoveByPredicate( + figure => figure.ObserverId == entity.ObserverId && figure.TargetId == entity.TargetId); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/StreetcodeUpdateDTOExtracter.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/StreetcodeUpdateDTOExtracter.cs index 86025112c..8c0d702a6 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/StreetcodeUpdateDTOExtracter.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/StreetcodeUpdateDTOExtracter.cs @@ -44,8 +44,6 @@ public static StreetcodeUpdateDTO Extract(int id, int index, string transliterat public static void Remove(StreetcodeUpdateDTO entity) { - BaseExtracter.RemoveByPredicate(strCont => strCont.Id == entity.Id); - foreach (var image in entity.Images) { var imageBlob = dbHelper.GetExistItemId(image.Id); @@ -56,6 +54,8 @@ public static void Remove(StreetcodeUpdateDTO entity) { BaseExtracter.RemoveById(imageDetails.Id); } + + BaseExtracter.RemoveByPredicate(strCont => strCont.Id == entity.Id); } private static StreetcodeUpdateDTO GetTestStreetcodeUpdateDTO(int id, int index, string transliterationUrl, Image testImage) @@ -100,7 +100,7 @@ private static StreetcodeUpdateDTO GetTestStreetcodeUpdateDTO(int id, int index, StreetcodeArtSlides = new List(), StatisticRecords = new List(), StreetcodeCategoryContents = new List(), - ARBlockUrl = "https://streetcode/1" + ArBlockUrl = "https://streetcode/1", }; } } diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/TextContent/FactExtracter.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/TextContent/FactExtracter.cs new file mode 100644 index 000000000..d03300958 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/TextContent/FactExtracter.cs @@ -0,0 +1,44 @@ +using Streetcode.DAL.Entities.Media.Images; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.Base; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.MediaExtracter.Image; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.TextContent; + +public static class FactExtracter +{ + public static Fact Extract(int factId, string? title = null) + { + var streetcodeContentId = UniqueNumberGenerator.GenerateInt(); + var imageId = UniqueNumberGenerator.GenerateInt(); + + var testFact = TestDataProvider.GetTestData(); + var testStreetcodeContent = StreetcodeContentExtracter.Extract( + streetcodeContentId, + streetcodeContentId, + Guid.NewGuid().ToString()); + var testImage = ImageExtracter.Extract(imageId); + + testFact.Id = factId; + testFact.ImageId = testImage.Id; + testFact.Image = testImage; + testFact.StreetcodeId = testStreetcodeContent.Id; + testFact.Streetcode = testStreetcodeContent; + testFact.Index = factId; + + if (title is not null) + { + testFact.Title = title; + } + + return BaseExtracter.Extract(testFact, fact => fact.Id == factId); + } + + public static void Remove(Fact factEntity) + { + BaseExtracter.RemoveById(factEntity.Id); + BaseExtracter.RemoveById(factEntity.StreetcodeId); + BaseExtracter.RemoveById(factEntity.ImageId!.Value); + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/TextContent/RelatedTermExtracter.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/TextContent/RelatedTermExtracter.cs new file mode 100644 index 000000000..4333d0458 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/TextContent/RelatedTermExtracter.cs @@ -0,0 +1,32 @@ +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.TextContent; + +public static class RelatedTermExtracter +{ + public static RelatedTerm Extract(int relatedTermId, string? word = null) + { + var termId = UniqueNumberGenerator.GenerateInt(); + + var testRelatedTerm = TestDataProvider.GetTestData(); + var testTerm = TermExtracter.Extract(termId); + + testRelatedTerm.Id = relatedTermId; + testRelatedTerm.TermId = testTerm.Id; + testRelatedTerm.Term = testTerm; + + if (word is not null) + { + testRelatedTerm.Word = word; + } + + return BaseExtracter.Extract(testRelatedTerm, relatedTerm => relatedTerm.Id == relatedTermId); + } + + public static void Remove(RelatedTerm relatedTermEntity) + { + BaseExtracter.RemoveById(relatedTermEntity.Id); + BaseExtracter.RemoveById(relatedTermEntity.TermId); + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/TextContent/TermExtracter.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/TextContent/TermExtracter.cs new file mode 100644 index 000000000..7c162cda0 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/TextContent/TermExtracter.cs @@ -0,0 +1,25 @@ +using Streetcode.DAL.Entities.Streetcode.TextContent; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.TextContent; + +public static class TermExtracter +{ + public static Term Extract(int termId, string? title = null) + { + var testTerm = TestDataProvider.GetTestData(); + + testTerm.Id = termId; + + if (title is not null) + { + testTerm.Title = title; + } + + return BaseExtracter.Extract(testTerm, term => term.Id == termId); + } + + public static void Remove(Term termEntity) + { + BaseExtracter.RemoveById(termEntity.Id); + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/TextContent/TextExtracter.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/TextContent/TextExtracter.cs new file mode 100644 index 000000000..4d118c3cc --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/StreetcodeExtracter/TextContent/TextExtracter.cs @@ -0,0 +1,31 @@ +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.XIntegrationTest.Base; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter.TextContent; + +public static class TextExtracter +{ + public static Text Extract(int textId) + { + var streetcodeContentId = UniqueNumberGenerator.GenerateInt(); + + var testText = TestDataProvider.GetTestData(); + var testStreetcodeContent = StreetcodeContentExtracter.Extract( + streetcodeContentId, + streetcodeContentId, + Guid.NewGuid().ToString()); + + testText.Id = textId; + testText.StreetcodeId = testStreetcodeContent.Id; + testText.Streetcode = testStreetcodeContent; + + return BaseExtracter.Extract(testText, text => text.Id == textId); + } + + public static void Remove(Text textEntity) + { + BaseExtracter.RemoveById(textEntity.Id); + BaseExtracter.RemoveById(textEntity.StreetcodeId); + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Team/TeamLinkExtracter.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Team/TeamLinkExtracter.cs new file mode 100644 index 000000000..d6dc55726 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Team/TeamLinkExtracter.cs @@ -0,0 +1,22 @@ +using Streetcode.DAL.Entities.Team; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Team +{ + public static class TeamLinkExtracter + { + public static TeamMemberLink Extract(int linkId, int teamMemberId) + { + TeamMemberLink testTeamLink = TestDataProvider.GetTestData(); + + testTeamLink.Id = linkId; + testTeamLink.TeamMemberId = teamMemberId; + + return BaseExtracter.Extract(testTeamLink, teamLink => teamLink.Id == linkId); + } + + public static void Remove(TeamMemberLink entity) + { + BaseExtracter.RemoveByPredicate(teamLink => teamLink.Id == entity.Id); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Timeline/TimelineItemExtracter.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Timeline/TimelineItemExtracter.cs new file mode 100644 index 000000000..d278df526 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Timeline/TimelineItemExtracter.cs @@ -0,0 +1,27 @@ +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Timeline; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Timeline +{ + public static class TimelineItemExtracter + { + public static TimelineItem Extract(int timelineId) + { + TimelineItem item = TestDataProvider.GetTestData(); + StreetcodeContent testStreetcodeContent = StreetcodeContentExtracter.Extract( + timelineId, + timelineId, + Guid.NewGuid().ToString()); + item.StreetcodeId = testStreetcodeContent.Id; + item.Id = timelineId; + + return BaseExtracter.Extract(item, t => t.Id == timelineId); + } + + public static void Remove(TimelineItem item) + { + BaseExtracter.RemoveByPredicate(t => t.Id == item.Id); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Toponyms/ToponymExtracter.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Toponyms/ToponymExtracter.cs new file mode 100644 index 000000000..8074021e9 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Toponyms/ToponymExtracter.cs @@ -0,0 +1,20 @@ +using Streetcode.DAL.Entities.Toponyms; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Toponyms +{ + public static class ToponymExtracter + { + public static Toponym Extract(int toponymId) + { + var toponym = TestDataProvider.GetTestData(); + toponym.Id = toponymId; + + return BaseExtracter.Extract(toponym, t => t.Id == toponymId); + } + + public static void Remove(Toponym toponym) + { + BaseExtracter.RemoveByPredicate(t => t.Id == toponym.Id); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Transaction/TransactLinkExtracter.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Transaction/TransactLinkExtracter.cs new file mode 100644 index 000000000..adc1382d6 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/Extracter/Transaction/TransactLinkExtracter.cs @@ -0,0 +1,29 @@ +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Transactions; +using Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.StreetcodeExtracter; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils.Extracter.Transaction +{ + public static class TransactLinkExtracter + { + public static TransactionLink Extract(int transactId) + { + TransactionLink transactionLink = TestDataProvider.GetTestData(); + + StreetcodeContent testStreetcodeContent = StreetcodeContentExtracter.Extract( + transactId, + transactId, + Guid.NewGuid().ToString()); + + transactionLink.StreetcodeId = testStreetcodeContent.Id; + transactionLink.Id = transactId; + + return BaseExtracter.Extract(transactionLink, transact => transact.Id == transactId); + } + + public static void Remove(TransactionLink transact) + { + BaseExtracter.RemoveByPredicate(t => t.Id == transact.Id); + } + } +} diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/QueryStringHelper.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/QueryStringHelper.cs new file mode 100644 index 000000000..128380584 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/QueryStringHelper.cs @@ -0,0 +1,25 @@ +using System.Web; + +namespace Streetcode.XIntegrationTest.ControllerTests.Utils; + +public static class QueryStringHelper +{ + public static string ToQueryString(T obj) + { + if (obj is null) + { + return string.Empty; + } + + var properties = typeof(T).GetProperties() + .Where(p => p.GetValue(obj) != null) + .Select(p => $"{HttpUtility.UrlEncode(p.Name)}={HttpUtility.UrlEncode(p.GetValue(obj)?.ToString() ?? string.Empty)}") + .ToList(); + + var queryString = string.Join("&", properties); + + return queryString.Any() + ? queryString.Insert(0, "?") + : string.Empty; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/SqlDbHelper.cs b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/SqlDbHelper.cs index a46413266..d35ebcf22 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/SqlDbHelper.cs +++ b/Streetcode/Streetcode.XIntegrationTest/ControllerTests/Utils/SqlDbHelper.cs @@ -1,37 +1,32 @@ -using Microsoft.EntityFrameworkCore; +using System.Collections.Concurrent; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata; using Streetcode.DAL.Persistence; -using System.Collections.Concurrent; namespace Streetcode.XIntegrationTest.ControllerTests.Utils { public class SqlDbHelper { - private readonly StreetcodeDbContext dbContext; + private readonly StreetcodeDbContext _dbContext; private readonly object _lock = new object(); private static readonly ConcurrentDictionary _entityLocks = new ConcurrentDictionary(); public SqlDbHelper(DbContextOptions options) { - this.dbContext = new StreetcodeDbContext(options); - } - - public string GetEntityTableName() - { - var entityType = this.dbContext.Model.FindEntityType(typeof(T)); - return $"{entityType?.GetSchema()}.{entityType?.GetTableName()}"; + _dbContext = new StreetcodeDbContext(options); } public string GetIdentityInsertString(bool enable) { var value = enable ? "ON" : "OFF"; - return $"SET IDENTITY_INSERT {this.GetEntityTableName()} {value};"; + return $"SET IDENTITY_INSERT {GetEntityTableName()} {value};"; } public bool ItemWithIdExist(int id) where T : class, new() { var idProp = typeof(T).GetProperty("Id"); - if (this.dbContext.Set() + if (_dbContext.Set() .AsEnumerable() .FirstOrDefault(predicate: s => (int)idProp?.GetValue(s) ! == id) == null) { @@ -45,7 +40,7 @@ public bool ItemWithIdExist(int id) where T : class, new() { var idProp = typeof(T).GetProperty("Id"); - return this.dbContext.Set() + return _dbContext.Set() .AsEnumerable() .FirstOrDefault(s => ((int)idProp?.GetValue(s) !) == id); } @@ -65,7 +60,7 @@ public T AddNewItem(T newItem) lock (_entityLocks.GetOrAdd(typeof(T), new object())) { - return this.dbContext.Set().Add(newItem).Entity; + return _dbContext.Set().Add(newItem).Entity; } } @@ -78,29 +73,36 @@ public void AddItemWithCustomId(T newItem) { try { - this.dbContext.Database.OpenConnection(); + _dbContext.Database.OpenConnection(); - string tableSchema = this.dbContext.Model.FindEntityType(typeof(T))?.GetSchema()!; - string tableName = this.dbContext.Model.FindEntityType(typeof(T))?.GetTableName()!; + string tableSchema = _dbContext.Model.FindEntityType(typeof(T))?.GetSchema() !; + string tableName = _dbContext.Model.FindEntityType(typeof(T))?.GetTableName() !; string identityOnCommand = $"SET IDENTITY_INSERT {tableSchema}.{tableName} ON"; string identityOffCommand = $"SET IDENTITY_INSERT {tableSchema}.{tableName} OFF"; - this.dbContext.Database.ExecuteSqlRaw(identityOnCommand); - - var trackedEntity = this.dbContext.ChangeTracker.Entries().FirstOrDefault(e => e.Entity == newItem); + if (TableHasIdentityColumn(typeof(T))) + { + _dbContext.Database.ExecuteSqlRaw(identityOnCommand); + } + + var trackedEntity = _dbContext.ChangeTracker.Entries().FirstOrDefault(e => e.Entity == newItem); if (trackedEntity != null) { trackedEntity.State = EntityState.Detached; } - this.dbContext.Add(newItem); - this.dbContext.SaveChanges(); - this.dbContext.Database.ExecuteSqlRaw(identityOffCommand); + _dbContext.Add(newItem); + _dbContext.SaveChanges(); + + if (TableHasIdentityColumn(typeof(T))) + { + _dbContext.Database.ExecuteSqlRaw(identityOnCommand); + } } finally { - this.dbContext.Database.CloseConnection(); + _dbContext.Database.CloseConnection(); } } } @@ -110,10 +112,10 @@ public void AddItemWithCustomId(T newItem) { if (predicate != null) { - return this.dbContext.Set().AsEnumerable().FirstOrDefault(predicate); + return _dbContext.Set().AsEnumerable().FirstOrDefault(predicate); } - return this.dbContext.Set().FirstOrDefault(); + return _dbContext.Set().FirstOrDefault(); } public bool Any(Func? predicate = default) @@ -121,10 +123,10 @@ public bool Any(Func? predicate = default) { if (predicate != null) { - return this.dbContext.Set().AsNoTracking().Any(predicate); + return _dbContext.Set().AsNoTracking().Any(predicate); } - return this.dbContext.Set().AsNoTracking().Any(); + return _dbContext.Set().AsNoTracking().Any(); } public IEnumerable GetAll(Func? predicate = default) @@ -132,10 +134,10 @@ public IEnumerable GetAll(Func? predicate = default) { if (predicate != null) { - return this.dbContext.Set().AsNoTracking().AsEnumerable().Where(predicate); + return _dbContext.Set().AsNoTracking().AsEnumerable().Where(predicate); } - return this.dbContext.Set().AsNoTracking(); + return _dbContext.Set().AsNoTracking(); } public T DeleteItem(T item) @@ -143,7 +145,7 @@ public T DeleteItem(T item) { lock (_entityLocks.GetOrAdd(typeof(T), new object())) { - return this.dbContext.Set().Remove(item).Entity; + return _dbContext.Set().Remove(item).Entity; } } @@ -151,8 +153,25 @@ public void SaveChanges() { lock (_lock) { - this.dbContext.SaveChanges(); + _dbContext.SaveChanges(); } } + + private bool TableHasIdentityColumn(Type entityType) + { + var entityTypeMeta = _dbContext.Model.FindEntityType(entityType); + if (entityTypeMeta == null) + { + return false; + } + + return entityTypeMeta.GetProperties().Any(p => p.ValueGenerated == ValueGenerated.OnAdd); + } + + private string GetEntityTableName() + { + var entityType = _dbContext.Model.FindEntityType(typeof(T)); + return $"{entityType?.GetSchema()}.{entityType?.GetTableName()}"; + } } } diff --git a/Streetcode/Streetcode.XIntegrationTest/ServiceTests/BlobServiceTests/Utils/testData.json b/Streetcode/Streetcode.XIntegrationTest/ServiceTests/BlobServiceTests/Utils/testData.json index c887c2261..f24ced2e9 100644 --- a/Streetcode/Streetcode.XIntegrationTest/ServiceTests/BlobServiceTests/Utils/testData.json +++ b/Streetcode/Streetcode.XIntegrationTest/ServiceTests/BlobServiceTests/Utils/testData.json @@ -1,4 +1,4 @@ { "mimeType": "image/png", - "base64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAABN2lDQ1BBZG9iZSBSR0IgKDE5OTgpAAAokZWPv0rDUBSHvxtFxaFWCOLgcCdRUGzVwYxJW4ogWKtDkq1JQ5ViEm6uf/oQjm4dXNx9AidHwUHxCXwDxamDQ4QMBYvf9J3fORzOAaNi152GUYbzWKt205Gu58vZF2aYAoBOmKV2q3UAECdxxBjf7wiA10277jTG+38yH6ZKAyNguxtlIYgK0L/SqQYxBMygn2oQD4CpTto1EE9AqZf7G1AKcv8ASsr1fBBfgNlzPR+MOcAMcl8BTB1da4Bakg7UWe9Uy6plWdLuJkEkjweZjs4zuR+HiUoT1dFRF8jvA2AxH2w3HblWtay99X/+PRHX82Vun0cIQCw9F1lBeKEuf1UYO5PrYsdwGQ7vYXpUZLs3cLcBC7dFtlqF8hY8Dn8AwMZP/fNTP8gAAAAJcEhZcwAAACcAAAAnASoJkU8AAAiFaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA2LjAtYzAwMiA3OS4xNjQzNjAsIDIwMjAvMDIvMTMtMDE6MDc6MjIgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMSAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIzLTA2LTIwVDEyOjQxOjEyKzAzOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDIzLTA2LTIwVDEyOjQ2OjI4KzAzOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMy0wNi0yMFQxMjo0NjoyOCswMzowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6Nzc2NDVhZmYtZDc1OC0zYTQzLTk1NGMtN2JhYjFjY2VmMDNhIiB4bXBNTTpEb2N1bWVudElEPSJhZG9iZTpkb2NpZDpwaG90b3Nob3A6OGViNjE3NzItZGZkMy01MDQ3LTkzNmEtNDg5YWI4NDM5M2VmIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6ZDZiMmE0NzUtZDcwZi0xYTQwLWIzM2UtMjc2NzdjNjY0Njk0IiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0iQWRvYmUgUkdCICgxOTk4KSI+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6ZDZiMmE0NzUtZDcwZi0xYTQwLWIzM2UtMjc2NzdjNjY0Njk0IiBzdEV2dDp3aGVuPSIyMDIzLTA2LTIwVDEyOjQxOjEyKzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgMjEuMSAoV2luZG93cykiLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmYxOTQ0Y2I1LTkzMGYtYTE0OC05NTExLTFhMGI2MGUwYmU0OSIgc3RFdnQ6d2hlbj0iMjAyMy0wNi0yMFQxMjo0NjoyOCswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIxLjEgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjb252ZXJ0ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImZyb20gaW1hZ2UvanBlZyB0byBpbWFnZS9wbmciLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImRlcml2ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImNvbnZlcnRlZCBmcm9tIGltYWdlL2pwZWcgdG8gaW1hZ2UvcG5nIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NzY0NWFmZi1kNzU4LTNhNDMtOTU0Yy03YmFiMWNjZWYwM2EiIHN0RXZ0OndoZW49IjIwMjMtMDYtMjBUMTI6NDY6MjgrMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4xIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6ZjE5NDRjYjUtOTMwZi1hMTQ4LTk1MTEtMWEwYjYwZTBiZTQ5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOmQ2YjJhNDc1LWQ3MGYtMWE0MC1iMzNlLTI3Njc3YzY2NDY5NCIgc3RSZWY6b3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOmQ2YjJhNDc1LWQ3MGYtMWE0MC1iMzNlLTI3Njc3YzY2NDY5NCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PumMVtQAAAANSURBVAiZY/j//z8DAAj8Av6Fzas0AAAAAElFTkSuQmCC" + "base64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAABN2lDQ1BBZG9iZSBSR0IgKDE5OTgpAAAokZWPv0rDUBSHvxtFxaFWCOLgcCdRUGzVwYxJW4ogWKtDkq1JQ5ViEm6uf/oQjm4dXNx9AidHwUHxCXwDxamDQ4QMBYvf9J3fORzOAaNi152GUYbzWKt205Gu58vZF2aYAoBOmKV2q3UAECdxxBjf7wiA10277jTG+38yH6ZKAyNguxtlIYgK0L/SqQYxBMygn2oQD4CpTto1EE9AqZf7G1AKcv8ASsr1fBBfgNlzPR+MOcAMcl8BTB1da4Bakg7UWe9Uy6plWdLuJkEkjweZjs4zuR+HiUoT1dFRF8jvA2AxH2w3HblWtay99X/+PRHX82Vun0cIQCw9F1lBeKEuf1UYO5PrYsdwGQ7vYXpUZLs3cLcBC7dFtlqF8hY8Dn8AwMZP/fNTP8gAAAAJcEhZcwAAACcAAAAnASoJkU8AAAiFaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA2LjAtYzAwMiA3OS4xNjQzNjAsIDIwMjAvMDIvMTMtMDE6MDc6MjIgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMSAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIzLTA2LTIwVDEyOjQxOjEyKzAzOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDIzLTA2LTIwVDEyOjQ2OjI4KzAzOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMy0wNi0yMFQxMjo0NjoyOCswMzowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6Nzc2NDVhZmYtZDc1OC0zYTQzLTk1NGMtN2JhYjFjY2VmMDNhIiB4bXBNTTpEb2N1bWVudElEPSJhZG9iZTpkb2NpZDpwaG90b3Nob3A6OGViNjE3NzItZGZkMy01MDQ3LTkzNmEtNDg5YWI4NDM5M2VmIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6ZDZiMmE0NzUtZDcwZi0xYTQwLWIzM2UtMjc2NzdjNjY0Njk0IiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0iQWRvYmUgUkdCICgxOTk4KSI+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6ZDZiMmE0NzUtZDcwZi0xYTQwLWIzM2UtMjc2NzdjNjY0Njk0IiBzdEV2dDp3aGVuPSIyMDIzLTA2LTIwVDEyOjQxOjEyKzAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgMjEuMSAoV2luZG93cykiLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmYxOTQ0Y2I1LTkzMGYtYTE0OC05NTExLTFhMGI2MGUwYmU0OSIgc3RFdnQ6d2hlbj0iMjAyMy0wNi0yMFQxMjo0NjoyOCswMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIxLjEgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjb252ZXJ0ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImZyb20gaW1hZ2UvanBlZyB0byBpbWFnZS9wbmciLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImRlcml2ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImNvbnZlcnRlZCBmcm9tIGltYWdlL2pwZWcgdG8gaW1hZ2UvcG5nIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NzY0NWFmZi1kNzU4LTNhNDMtOTU0Yy03YmFiMWNjZWYwM2EiIHN0RXZ0OndoZW49IjIwMjMtMDYtMjBUMTI6NDY6MjgrMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4xIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6ZjE5NDRjYjUtOTMwZi1hMTQ4LTk1MTEtMWEwYjYwZTBiZTQ5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOmQ2YjJhNDc1LWQ3MGYtMWE0MC1iMzNlLTI3Njc3YzY2NDY5NCIgc3RSZWY6b3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOmQ2YjJhNDc1LWQ3MGYtMWE0MC1iMzNlLTI3Njc3YzY2NDY5NCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PumMVtQAAAANSURBVAiZY/j//z8DAAj8Av6F" } \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/Streetcode.XIntegrationTest.csproj b/Streetcode/Streetcode.XIntegrationTest/Streetcode.XIntegrationTest.csproj index e73327c30..de6da1515 100644 --- a/Streetcode/Streetcode.XIntegrationTest/Streetcode.XIntegrationTest.csproj +++ b/Streetcode/Streetcode.XIntegrationTest/Streetcode.XIntegrationTest.csproj @@ -30,7 +30,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -57,4 +57,15 @@ PreserveNewest + + + + + + + + + + + diff --git a/Streetcode/Streetcode.XIntegrationTest/TestData/Expertise.json b/Streetcode/Streetcode.XIntegrationTest/TestData/Expertise.json new file mode 100644 index 000000000..cd92d2913 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/TestData/Expertise.json @@ -0,0 +1,3 @@ +{ + "Title": "Test_Title" +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/TestData/Fact.json b/Streetcode/Streetcode.XIntegrationTest/TestData/Fact.json new file mode 100644 index 000000000..f54179cd2 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/TestData/Fact.json @@ -0,0 +1,8 @@ +{ + "id": 1, + "title": "Lorem ipsum", + "factContent": "Lorem ipsum dolor sit amet, consectetur adipiscing elit", + "imageId": 1, + "streetcodeId": 1, + "index": 1 +} diff --git a/Streetcode/Streetcode.XIntegrationTest/TestData/RelatedFigure.json b/Streetcode/Streetcode.XIntegrationTest/TestData/RelatedFigure.json new file mode 100644 index 000000000..8f2480834 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/TestData/RelatedFigure.json @@ -0,0 +1,4 @@ +{ + "observerId": 0, + "targetId": 0 +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/TestData/RelatedTerm.json b/Streetcode/Streetcode.XIntegrationTest/TestData/RelatedTerm.json new file mode 100644 index 000000000..ee30346e6 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/TestData/RelatedTerm.json @@ -0,0 +1,5 @@ +{ + "id": 1, + "word": "Lorem ipsum", + "termId": 1 +} diff --git a/Streetcode/Streetcode.XIntegrationTest/TestData/StatisticRecord.json b/Streetcode/Streetcode.XIntegrationTest/TestData/StatisticRecord.json new file mode 100644 index 000000000..03e7955e7 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/TestData/StatisticRecord.json @@ -0,0 +1,7 @@ +{ + "qrId": 1, + "count": 0, + "address": "Test_Address", + "streetcodeId": 0, + "streetcodeCoordinateId": 0 +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/TestData/TeamMember.json b/Streetcode/Streetcode.XIntegrationTest/TestData/TeamMember.json index b6fbc49a7..9c877abf6 100644 --- a/Streetcode/Streetcode.XIntegrationTest/TestData/TeamMember.json +++ b/Streetcode/Streetcode.XIntegrationTest/TestData/TeamMember.json @@ -2,6 +2,5 @@ "name": "TestName", "description": "TestDescription", "isVisibleEverywhere": true, - "isMain": false, - "imageId": 1 + "isMain": true } \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/TestData/TeamMemberLink.json b/Streetcode/Streetcode.XIntegrationTest/TestData/TeamMemberLink.json new file mode 100644 index 000000000..d6ff90620 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/TestData/TeamMemberLink.json @@ -0,0 +1,4 @@ +{ + "LogoType": "Instagram", + "TargetUrl": "https://instagram.com/test" +} diff --git a/Streetcode/Streetcode.XIntegrationTest/TestData/Term.json b/Streetcode/Streetcode.XIntegrationTest/TestData/Term.json new file mode 100644 index 000000000..3ae3b9276 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/TestData/Term.json @@ -0,0 +1,5 @@ +{ + "id": 1, + "title": "Lorem ipsum", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit" +} diff --git a/Streetcode/Streetcode.XIntegrationTest/TestData/Text.json b/Streetcode/Streetcode.XIntegrationTest/TestData/Text.json new file mode 100644 index 000000000..03c5ed356 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/TestData/Text.json @@ -0,0 +1,7 @@ +{ + "id": 1, + "title": "Lorem ipsum", + "textContent": "Lorem ipsum dolor sit amet, consectetur adipiscing elit", + "additionalText": "Lorem ipsum dolor sit amet, consectetur adipiscing elit", + "streetcodeId": 1 +} diff --git a/Streetcode/Streetcode.XIntegrationTest/TestData/TimelineItem.json b/Streetcode/Streetcode.XIntegrationTest/TestData/TimelineItem.json new file mode 100644 index 000000000..88bc810ce --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/TestData/TimelineItem.json @@ -0,0 +1,6 @@ +{ + "title": "test", + "description": "test", + "date": "1997-07-05T00:00:00", + "dateViewPattern": 0 +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/TestData/Toponym.json b/Streetcode/Streetcode.XIntegrationTest/TestData/Toponym.json new file mode 100644 index 000000000..d9792a943 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/TestData/Toponym.json @@ -0,0 +1,10 @@ +{ + "oblast": "test", + "adminRegionOld": "test", + "adminRegionNew": "test", + "gromada": "test", + "community": "test", + "streetName": "test", + "streetType": "test", + "streetcodes": [] +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XIntegrationTest/TestData/TransactionLink.json b/Streetcode/Streetcode.XIntegrationTest/TestData/TransactionLink.json new file mode 100644 index 000000000..36e4696f8 --- /dev/null +++ b/Streetcode/Streetcode.XIntegrationTest/TestData/TransactionLink.json @@ -0,0 +1,4 @@ +{ + "UrlTitle": "test transaction", + "Url": "http://test.url" +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Attributes/Authentication/ValidEmailAttributeTest.cs b/Streetcode/Streetcode.XUnitTest/Attributes/Authentication/ValidEmailAttributeTest.cs index fc599e765..3686dbe6a 100644 --- a/Streetcode/Streetcode.XUnitTest/Attributes/Authentication/ValidEmailAttributeTest.cs +++ b/Streetcode/Streetcode.XUnitTest/Attributes/Authentication/ValidEmailAttributeTest.cs @@ -44,7 +44,6 @@ public void ShouldReturnCorrectFailMessage_InputParameterIsNotString() [Theory] [InlineData("test@@test.com")] [InlineData("@.com")] - [InlineData("test@test.ru")] [InlineData("asda @test.com")] [InlineData("test@.")] [InlineData("test@com")] @@ -65,7 +64,6 @@ public void ShouldReturnCorrectFailMessage_InvalidEmailFormat(string email) [InlineData("___test@test.com")] [InlineData("--___--@test.com")] [InlineData("QQQQQQQ@QQQQ.com")] - [InlineData("....@...com")] public void ShouldReturnSuccess_ValidEmail(string email) { // Arrange. diff --git a/Streetcode/Streetcode.XUnitTest/Factories/MessageDataFactory/MessageDataConcreteFactoryTests.cs b/Streetcode/Streetcode.XUnitTest/Factories/MessageDataFactory/MessageDataConcreteFactoryTests.cs new file mode 100644 index 000000000..f0783fe85 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/Factories/MessageDataFactory/MessageDataConcreteFactoryTests.cs @@ -0,0 +1,61 @@ +using Microsoft.Extensions.Options; +using Moq; +using Streetcode.BLL.Factories.MessageDataFactory.Concretes; +using Streetcode.BLL.Models.Email; +using Streetcode.BLL.Models.Email.Messages; +using Xunit; + +namespace Streetcode.XUnitTest.Factories.MessageDataFactory; + +public class MessageDataConcreteFactoryTests +{ + private readonly MessageDataConcreteFactory _factory; + private readonly EmailConfiguration _emailConfig; + + public MessageDataConcreteFactoryTests() + { + _emailConfig = new EmailConfiguration + { + To = "test@example.com", + From = "noreply@example.com", + }; + + var optionsMock = new Mock>(); + optionsMock.Setup(o => o.Value).Returns(_emailConfig); + + _factory = new MessageDataConcreteFactory(optionsMock.Object); + } + + [Fact] + public void CreateFeedbackMessageData_ShouldReturnValidMessage() + { + // Arrange + string from = "user@example.com"; + string source = "test_source"; + string content = "test_content"; + + // Act + var message = _factory.CreateFeedbackMessageData(from, source, content); + + // Assert + Assert.NotNull(message); + Assert.IsType(message); + } + + [Fact] + public void CreateForgotPasswordMessageData_ShouldReturnValidMessage() + { + // Arrange + string[] to = { "user@example.com" }; + string token = "reset-token"; + string username = "TestUser"; + string currentDomain = "https://example.com"; + + // Act + var message = _factory.CreateForgotPasswordMessageData(to, token, username, currentDomain); + + // Assert + Assert.NotNull(message); + Assert.IsType(message); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/DeleteStatisticRecordTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/DeleteStatisticRecordTests.cs new file mode 100644 index 000000000..a41698c95 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/DeleteStatisticRecordTests.cs @@ -0,0 +1,121 @@ +using System.Linq.Expressions; +using MediatR; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.Extensions.Localization; +using Moq; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Analytics.StatisticRecord.Delete; +using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Entities.Analytics; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Analytics; + +public class DeleteStatisticRecordTests +{ + private readonly Mock _repositoryWrapperMock; + private readonly Mock _loggerMock; + private readonly Mock> _localizerCannotFindMock; + private readonly Mock> _localizerFailedToDeleteMock; + private readonly DeleteStatisticRecordHandler _handler; + + public DeleteStatisticRecordTests() + { + _repositoryWrapperMock = new Mock(); + _loggerMock = new Mock(); + _localizerCannotFindMock = new Mock>(); + _localizerFailedToDeleteMock = new Mock>(); + + _handler = new DeleteStatisticRecordHandler( + _repositoryWrapperMock.Object, + _loggerMock.Object, + _localizerCannotFindMock.Object, + _localizerFailedToDeleteMock.Object); + } + + [Fact] + public async Task Handle_RecordIsDeletedSuccessfully_ShouldReturnSuccess() + { + // Arrange + var qrId = 1; + var statisticRecords = new List + { + new () { QrId = qrId }, + }; + + _repositoryWrapperMock.Setup(repo => repo.StatisticRecordRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(statisticRecords[0]); + + _repositoryWrapperMock.Setup(repo => repo.SaveChangesAsync()).ReturnsAsync(1); + + var request = new DeleteStatisticRecordCommand(qrId); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + Assert.Equal(Unit.Value, result.Value); + _repositoryWrapperMock.Verify(repo => repo.StatisticRecordRepository.Delete(It.IsAny()), Times.Once); + _repositoryWrapperMock.Verify(repo => repo.SaveChangesAsync(), Times.Once); + } + + [Fact] + public async Task Handle_RecordIsNotFound_ShouldReturnError() + { + // Arrange + var qrId = -1; + + _repositoryWrapperMock.Setup(repo => repo.StatisticRecordRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync((StatisticRecord)null!); + + _localizerCannotFindMock.Setup(loc => loc["CannotFindRecordWithQrId"]).Returns(new LocalizedString("CannotFindRecordWithQrId", "Record not found")); + + var request = new DeleteStatisticRecordCommand(qrId); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.False(result.IsSuccess); + Assert.Contains("Record not found", result.Errors[0].Message); + _repositoryWrapperMock.Verify(repo => repo.StatisticRecordRepository.Delete(It.IsAny()), Times.Never); + _repositoryWrapperMock.Verify(repo => repo.SaveChangesAsync(), Times.Never); + } + + [Fact] + public async Task Handle_DeleteFails_ShouldReturnError() + { + // Arrange + var qrId = 1; + var statisticRecords = new List + { + new () { QrId = qrId }, + }; + + _repositoryWrapperMock.Setup(repo => repo.StatisticRecordRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(statisticRecords[0]); + + _repositoryWrapperMock.Setup(repo => repo.SaveChangesAsync()).ReturnsAsync(0); + + _localizerFailedToDeleteMock.Setup(loc => loc["FailedToDeleteTheRecord"]).Returns(new LocalizedString("FailedToDeleteTheRecord", "Failed to delete record")); + + var request = new DeleteStatisticRecordCommand(qrId); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.False(result.IsSuccess); + Assert.Contains("Failed to delete record", result.Errors[0].Message); + _repositoryWrapperMock.Verify(repo => repo.StatisticRecordRepository.Delete(It.IsAny()), Times.Once); + _repositoryWrapperMock.Verify(repo => repo.SaveChangesAsync(), Times.Once); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/ExistStatisticRecordByQrIdTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/ExistStatisticRecordByQrIdTests.cs new file mode 100644 index 000000000..d07cfd60d --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/ExistStatisticRecordByQrIdTests.cs @@ -0,0 +1,76 @@ +using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.MediatR.Analytics.StatisticRecord.ExistByQrId; +using Streetcode.DAL.Entities.Analytics; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Analytics; +public class ExistStatisticRecordByQrIdTests +{ + private readonly Mock _repositoryWrapperMock; + private readonly ExistStatisticRecordByQrIdHandler _handler; + + public ExistStatisticRecordByQrIdTests() + { + _repositoryWrapperMock = new Mock(); + + _handler = new ExistStatisticRecordByQrIdHandler(_repositoryWrapperMock.Object); + } + + [Fact] + public async Task Handle_RecordExists_ShouldReturnTrue() + { + // Arrange + var qrId = 1; + var statisticRecords = new List + { + new () { QrId = qrId }, + }; + + _repositoryWrapperMock.Setup(repo => repo.StatisticRecordRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(statisticRecords[0]); + + var request = new ExistStatisticRecordByQrIdCommand(qrId); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + Assert.True(result.Value); + _repositoryWrapperMock.Verify( + repo => repo.StatisticRecordRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>()), Times.Once); + } + + [Fact] + public async Task Handle_RecordDoesNotExist_ShouldReturnFalse() + { + // Arrange + var qrId = -1; + + _repositoryWrapperMock.Setup( + repo => repo.StatisticRecordRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync((StatisticRecord)null!); + + var request = new ExistStatisticRecordByQrIdCommand(qrId); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + Assert.False(result.Value); + _repositoryWrapperMock.Verify( + repo => repo.StatisticRecordRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>()), Times.Once); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/GetAllStatisticRecordsByStreetcodeIdTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/GetAllStatisticRecordsByStreetcodeIdTests.cs new file mode 100644 index 000000000..5d631be6c --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/GetAllStatisticRecordsByStreetcodeIdTests.cs @@ -0,0 +1,126 @@ +using System.Linq.Expressions; +using AutoMapper; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.Extensions.Localization; +using MockQueryable; +using Moq; +using Streetcode.BLL.DTO.Analytics; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Analytics.StatisticRecord.GetAllByStreetcodeId; +using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types; +using Streetcode.DAL.Entities.Analytics; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Analytics; + +public class GetAllStatisticRecordsByStreetcodeIdTests +{ + private readonly Mock _repositoryMock; + private readonly Mock _mapperMock; + private readonly Mock _loggerMock; + private readonly Mock> _stringLocalizerCannotFindMock; + private readonly GetAllStatisticRecordsByStreetcodeIdHandler _handler; + + public GetAllStatisticRecordsByStreetcodeIdTests() + { + _repositoryMock = new Mock(); + _mapperMock = new Mock(); + _loggerMock = new Mock(); + _stringLocalizerCannotFindMock = new Mock>(); + + _handler = new GetAllStatisticRecordsByStreetcodeIdHandler( + _repositoryMock.Object, + _mapperMock.Object, + _loggerMock.Object, + _stringLocalizerCannotFindMock.Object); + } + + [Fact] + public async Task Handle_RecordsExist_ShouldReturnRecords() + { + // Arrange + int streetcodeId = 1; + var statisticRecords = GetStatisticRecords(streetcodeId); + var statisticRecordDtos = GetStatisticRecordDtos(); + + SetupMockRepository(statisticRecords); + + _mapperMock.Setup(mapper => mapper.Map>(It.IsAny>())) + .Returns(statisticRecordDtos); + + var request = new GetAllStatisticRecordsByStreetcodeIdQuery(streetcodeId); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + var records = result.Value.ToList(); + Assert.Equal(2, records.Count); + Assert.Equal(1, records[0].QrId); + Assert.Equal(2, records[1].QrId); + _repositoryMock.Verify( + repo => repo.StatisticRecordRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>()), Times.Once); + _mapperMock.Verify(mapper => mapper.Map>(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task Handle_RecordsNotFound_ShouldReturnFail() + { + // Arrange + int streetcodeId = 2; + + SetupMockRepository(Enumerable.Empty().AsQueryable().BuildMock()); + + _stringLocalizerCannotFindMock.Setup(localizer => localizer["CannotFindRecordWithStreetcodeId", streetcodeId]) + .Returns(new LocalizedString("CannotFindRecordWithStreetcodeId", $"Cannot find records with StreetcodeId {streetcodeId}")); + + var request = new GetAllStatisticRecordsByStreetcodeIdQuery(streetcodeId); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsFailed); + Assert.Equal($"Cannot find records with StreetcodeId {streetcodeId}", result.Errors[0].Message); + _loggerMock.Verify(logger => logger.LogError(request, $"Cannot find records with StreetcodeId {streetcodeId}"), Times.Once); + } + + private void SetupMockRepository(IEnumerable returns) + { + _repositoryMock.Setup(repo => repo.StatisticRecordRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(returns); + } + + private static List GetStatisticRecordDtos() + { + return new List + { + new () { QrId = 1, Count = 10 }, + new () { QrId = 2, Count = 15 }, + }; + } + + private List GetStatisticRecords(int streetcodeId) + { + return new List + { + new () + { + Id = 1, QrId = 1, Count = 10, + StreetcodeCoordinate = new StreetcodeCoordinate { StreetcodeId = streetcodeId }, + }, + new () + { + Id = 2, QrId = 2, Count = 15, + StreetcodeCoordinate = new StreetcodeCoordinate { StreetcodeId = streetcodeId }, + }, + }; + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/GetAllStatisticRecordsTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/GetAllStatisticRecordsTests.cs new file mode 100644 index 000000000..38f6675d8 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/GetAllStatisticRecordsTests.cs @@ -0,0 +1,144 @@ +using System.Linq.Expressions; +using AutoMapper; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.Extensions.Localization; +using Moq; +using Streetcode.BLL.DTO.Analytics; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Analytics.StatisticRecord.GetAll; +using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Entities.Analytics; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Analytics; + +public class GetAllStatisticRecordsTests +{ + private readonly Mock _repositoryWrapperMock; + private readonly Mock _mapperMock; + private readonly Mock _loggerMock; + private readonly Mock> _stringLocalizerCannotGetMock; + private readonly Mock> _stringLocalizerCannotMapMock; + private readonly GetAllStatisticRecordsHandler _handler; + + public GetAllStatisticRecordsTests() + { + _repositoryWrapperMock = new Mock(); + _mapperMock = new Mock(); + _loggerMock = new Mock(); + _stringLocalizerCannotGetMock = new Mock>(); + _stringLocalizerCannotMapMock = new Mock>(); + + _handler = new GetAllStatisticRecordsHandler( + _mapperMock.Object, + _repositoryWrapperMock.Object, + _loggerMock.Object, + _stringLocalizerCannotGetMock.Object, + _stringLocalizerCannotMapMock.Object); + } + + [Fact] + public async Task Handle_RecordsExist_ShouldReturnOrderedRecords() + { + // Arrange + var statisticRecords = GetStatisticRecords(); + var statisticRecordDTOs = GetStatisticRecordDTOs(); + + _repositoryWrapperMock.Setup(repo => repo.StatisticRecordRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(statisticRecords); + + _mapperMock.Setup(mapper => mapper.Map>(It.IsAny>())) + .Returns(statisticRecordDTOs); + + var request = new GetAllStatisticRecordsQuery(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + var orderedRecords = result.Value.ToList(); + Assert.Equal(20, orderedRecords[0].Count); + Assert.Equal(10, orderedRecords[^1].Count); + _repositoryWrapperMock.Verify( + repo => repo.StatisticRecordRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>()), Times.Once); + _mapperMock.Verify(mapper => mapper.Map>(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task Handle_RecordsAreNull_ShouldReturnFail() + { + // Arrange + _repositoryWrapperMock.Setup( + repo => repo.StatisticRecordRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync((IEnumerable)null!); + + _stringLocalizerCannotGetMock.Setup(localizer => localizer["CannotGetRecords"]) + .Returns(new LocalizedString("CannotGetRecords", "Cannot get statistic records")); + + var request = new GetAllStatisticRecordsQuery(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsFailed); + Assert.Equal("Cannot get statistic records", result.Errors[0].Message); + _loggerMock.Verify(logger => logger.LogError(request, "Cannot get statistic records"), Times.Once); + } + + [Fact] + public async Task Handle_MappingFails_ShouldReturnFail() + { + // Arrange + var statisticRecords = GetStatisticRecords(); + + _repositoryWrapperMock.Setup(repo => repo.StatisticRecordRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(statisticRecords); + + _mapperMock.Setup(mapper => mapper.Map>(It.IsAny>())) + .Returns((IEnumerable)null!); + + _stringLocalizerCannotMapMock.Setup(localizer => localizer["CannotMapRecords"]) + .Returns(new LocalizedString("CannotMapRecords", "Cannot map statistic records")); + + var request = new GetAllStatisticRecordsQuery(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsFailed); + Assert.Equal("Cannot map statistic records", result.Errors[0].Message); + _loggerMock.Verify(logger => logger.LogError(request, "Cannot map statistic records"), Times.Once); + } + + private List GetStatisticRecords() + { + return new List + { + new () { Id = 1, QrId = 1, Count = 10 }, + new () { Id = 2, QrId = 2, Count = 20 }, + new () { Id = 3, QrId = 3, Count = 15 }, + }; + } + + private List GetStatisticRecordDTOs() + { + return new List + { + new () { QrId = 1, Count = 10 }, + new () { QrId = 2, Count = 20 }, + new () { QrId = 3, Count = 15 }, + }; + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/GetStatisticRecordByQrIdTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/GetStatisticRecordByQrIdTests.cs new file mode 100644 index 000000000..c5806ff0a --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/GetStatisticRecordByQrIdTests.cs @@ -0,0 +1,147 @@ +using System.Linq.Expressions; +using AutoMapper; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.Extensions.Localization; +using Moq; +using Streetcode.BLL.DTO.Analytics; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Analytics.StatisticRecord.GetByQrId; +using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types; +using Streetcode.DAL.Entities.Analytics; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Analytics +{ + public class GetStatisticRecordByQrIdTests + { + private readonly Mock _repositoryMock; + private readonly Mock _mapperMock; + private readonly Mock _loggerMock; + private readonly Mock> _stringLocalizerCannotFindMock; + private readonly Mock> _stringLocalizerCannotMapMock; + private readonly GetStatisticRecordByQrIdHandler _handler; + + public GetStatisticRecordByQrIdTests() + { + _repositoryMock = new Mock(); + _mapperMock = new Mock(); + _loggerMock = new Mock(); + _stringLocalizerCannotFindMock = new Mock>(); + _stringLocalizerCannotMapMock = new Mock>(); + + _handler = new GetStatisticRecordByQrIdHandler( + _mapperMock.Object, + _repositoryMock.Object, + _loggerMock.Object, + _stringLocalizerCannotMapMock.Object, + _stringLocalizerCannotFindMock.Object); + } + + [Fact] + public async Task Handle_RecordExists_ShouldReturnRecord() + { + // Arrange + var qrId = 1; + var statisticRecord = GetStatisticRecord(qrId); + var statisticRecordDTO = GetStatisticRecordDTOs(qrId); + + _repositoryMock.Setup(repo => repo.StatisticRecordRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(statisticRecord); + + _mapperMock.Setup(mapper => mapper.Map(statisticRecord)) + .Returns(statisticRecordDTO); + + var request = new GetStatisticRecordByQrIdQuery(qrId); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + Assert.Equal(qrId, result.Value.QrId); + _repositoryMock.Verify( + repo => repo.StatisticRecordRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>()), Times.Once); + _mapperMock.Verify(mapper => mapper.Map(It.IsAny()), Times.Once); + } + + [Fact] + public async Task Handle_RecordNotFound_ShouldReturnFail() + { + // Arrange + var qrId = -1; + + _repositoryMock.Setup(repo => repo.StatisticRecordRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync((StatisticRecord)null!); + + _stringLocalizerCannotFindMock.Setup(localizer => localizer["CannotFindRecordWithQrId"]) + .Returns(new LocalizedString("CannotFindRecordWithQrId", "Cannot find record with this QR ID")); + + var request = new GetStatisticRecordByQrIdQuery(qrId); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsFailed); + Assert.Equal("Cannot find record with this QR ID", result.Errors[0].Message); + _loggerMock.Verify(logger => logger.LogError(request, "Cannot find record with this QR ID"), Times.Once); + } + + [Fact] + public async Task Handle_MappingFails_ShouldReturnFail() + { + // Arrange + var qrId = 1; + var statisticRecord = GetStatisticRecord(qrId); + + _repositoryMock.Setup(repo => repo.StatisticRecordRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(statisticRecord); + + _mapperMock.Setup(mapper => mapper.Map(It.IsAny())) + .Returns((StatisticRecordDTO)null!); + + _stringLocalizerCannotMapMock.Setup(localizer => localizer["CannotMapRecord"]) + .Returns(new LocalizedString("CannotMapRecord", "Cannot map the record")); + + var request = new GetStatisticRecordByQrIdQuery(qrId); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsFailed); + Assert.Equal("Cannot map the record", result.Errors[0].Message); + _loggerMock.Verify(logger => logger.LogError(request, "Cannot map the record"), Times.Once); + } + + private StatisticRecord GetStatisticRecord(int qrId) + { + return new StatisticRecord + { + Id = 1, + QrId = qrId, + Count = 10, + StreetcodeCoordinate = new StreetcodeCoordinate { StreetcodeId = 1 }, + }; + } + + private StatisticRecordDTO GetStatisticRecordDTOs(int qrId) + { + return new StatisticRecordDTO + { + QrId = qrId, + Count = 10, + }; + } + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/UpdateCountStatisticRecordTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/UpdateCountStatisticRecordTests.cs new file mode 100644 index 000000000..2a5d87597 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Analytics/UpdateCountStatisticRecordTests.cs @@ -0,0 +1,127 @@ +using Microsoft.Extensions.Localization; +using Moq; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Analytics.StatisticRecord.UpdateCount; +using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Entities.Analytics; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Analytics +{ + public class UpdateCountStatisticRecordTests + { + private readonly Mock _repositoryMock; + private readonly Mock _loggerMock; + private readonly Mock> _stringLocalizerCannotFindMock; + private readonly Mock> _stringLocalizerCannotSaveMock; + private readonly UpdateCountStatisticRecordHandler _handler; + + public UpdateCountStatisticRecordTests() + { + _repositoryMock = new Mock(); + _loggerMock = new Mock(); + _stringLocalizerCannotFindMock = new Mock>(); + _stringLocalizerCannotSaveMock = new Mock>(); + + _handler = new UpdateCountStatisticRecordHandler( + _repositoryMock.Object, + _loggerMock.Object, + _stringLocalizerCannotSaveMock.Object, + _stringLocalizerCannotFindMock.Object); + } + + [Fact] + public async Task Handle_RecordExists_ShouldIncrementCount() + { + // Arrange + var qrId = 1; + var statisticRecord = GetStatisticRecord(qrId); + + _repositoryMock.Setup(repo => repo.StatisticRecordRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + null)) + .ReturnsAsync(statisticRecord); + + _repositoryMock.Setup(repo => repo.StatisticRecordRepository.Update(It.IsAny())); + + _repositoryMock.Setup(repo => repo.SaveChangesAsync()).ReturnsAsync(1); + + var request = new UpdateCountStatisticRecordCommand(qrId); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + Assert.Equal(6, statisticRecord.Count); + _repositoryMock.Verify(repo => repo.StatisticRecordRepository.Update(statisticRecord), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Once); + } + + [Fact] + public async Task Handle_RecordNotFound_ShouldReturnFail() + { + // Arrange + var qrId = 1; + + _repositoryMock.Setup(repo => repo.StatisticRecordRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + null)) + .ReturnsAsync((StatisticRecord)null!); + + _stringLocalizerCannotFindMock.Setup(localizer => localizer["CannotFindRecordWithQrId"]) + .Returns(new LocalizedString("CannotFindRecordWithQrId", "Cannot find record with this QR ID")); + + var request = new UpdateCountStatisticRecordCommand(qrId); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsFailed); + Assert.Equal("Cannot find record with this QR ID", result.Errors[0].Message); + _loggerMock.Verify(logger => logger.LogError(request, "Cannot find record with this QR ID"), Times.Once); + } + + [Fact] + public async Task Handle_SaveFails_ShouldReturnFail() + { + // Arrange + var qrId = 1; + var statisticRecord = GetStatisticRecord(qrId); + + _repositoryMock.Setup(repo => repo.StatisticRecordRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + null)) + .ReturnsAsync(statisticRecord); + + _repositoryMock.Setup(repo => repo.StatisticRecordRepository.Update(It.IsAny())); + + _repositoryMock.Setup(repo => repo.SaveChanges()).Returns(0); + + _stringLocalizerCannotSaveMock.Setup(localizer => localizer["CannotSaveTheData"]) + .Returns(new LocalizedString("CannotSaveTheData", "Cannot save the data")); + + var request = new UpdateCountStatisticRecordCommand(qrId); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsFailed); + Assert.Equal("Cannot save the data", result.Errors[0].Message); + _loggerMock.Verify(logger => logger.LogError(request, "Cannot save the data"), Times.Once); + } + + private StatisticRecord GetStatisticRecord(int qrId) + { + return new StatisticRecord + { + Id = 1, + QrId = qrId, + Count = 5, + }; + } + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Authentication/Logout/LogoutHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Authentication/Logout/LogoutHandlerTests.cs new file mode 100644 index 000000000..cbda97dbe --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Authentication/Logout/LogoutHandlerTests.cs @@ -0,0 +1,110 @@ +using System.Linq.Expressions; +using System.Security.Claims; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.MediatR.Authentication.Logout; +using Streetcode.DAL.Entities.Users; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.DAL.Repositories.Interfaces.Users; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Authentication.Logout +{ + public class LogoutHandlerTests + { + private readonly Mock _repositoryWrapperMock; + private readonly Mock _httpContextAccessorMock; + private readonly Mock _userRepositoryMock; + private readonly LogoutHandler _handler; + + public LogoutHandlerTests() + { + _repositoryWrapperMock = new Mock(); + _httpContextAccessorMock = new Mock(); + _userRepositoryMock = new Mock(); + + _repositoryWrapperMock.Setup(r => r.UserRepository).Returns(_userRepositoryMock.Object); + var fakeEmail = "test@example.com"; + var fakeUserName = "test_username"; + var fakeUserId = Guid.NewGuid().ToString(); + var claims = new List + { + new (ClaimTypes.NameIdentifier, fakeUserId), + new (ClaimTypes.Name, fakeUserName), + new (ClaimTypes.Email, fakeEmail), + }; + + var identity = new ClaimsIdentity(claims, "TestAuthType"); + var claimsPrincipal = new ClaimsPrincipal(identity); + var context = new DefaultHttpContext { User = claimsPrincipal }; + + _httpContextAccessorMock.Setup(_ => _.HttpContext).Returns(context); + _handler = new LogoutHandler( + _repositoryWrapperMock.Object, + _httpContextAccessorMock.Object); + } + + [Fact] + public async Task Handle_ShouldReturnFail_WhenUserNotFound() + { + // Arrange + var request = new LogoutCommand(); + + _userRepositoryMock.Setup(repo => repo.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync((User)null!); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsFailed); + Assert.Contains("User not found.", result.Errors[0].Message); + } + + [Fact] + public async Task Handle_ShouldReturnOk_WhenLogoutIsSuccessful() + { + // Arrange + var request = new LogoutCommand(); + var user = new User { UserName = "testUser", RefreshToken = "oldToken", RefreshTokenExpiry = DateTime.UtcNow }; + + _userRepositoryMock.Setup(repo => repo.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(user); + + _repositoryWrapperMock.Setup(repo => repo.SaveChangesAsync()).ReturnsAsync(1); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + } + + [Fact] + public async Task Handle_ShouldReturnFail_WhenDatabaseSaveFails() + { + // Arrange + var request = new LogoutCommand(); + var user = new User { UserName = "testUser", RefreshToken = "oldToken", RefreshTokenExpiry = DateTime.UtcNow }; + + _userRepositoryMock.Setup(repo => repo.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(user); + + _repositoryWrapperMock.Setup(repo => repo.SaveChangesAsync()).ReturnsAsync(0); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsFailed); + Assert.Contains("Failed to logout", result.Errors[0].Message); + } + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Email/SendEmailHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Email/SendEmailHandlerTests.cs index a2609b460..44486511e 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Email/SendEmailHandlerTests.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Email/SendEmailHandlerTests.cs @@ -17,25 +17,25 @@ namespace Streetcode.XUnitTest.MediatRTests.Email { public class SendEmailHandlerTests { - private readonly Mock mockEmailService; - private readonly Mock mockLogger; - private readonly Mock> mockStringLocalizer; - private readonly Mock mockHttpMessageHandler; - private readonly Mock mockConfiguration; - private readonly Mock mockMessageDataAbstractFactory; - private readonly Mock mockHttpClientFactory; + private readonly Mock _mockEmailService; + private readonly Mock _mockLogger; + private readonly Mock> _mockStringLocalizer; + private readonly Mock _mockHttpMessageHandler; + private readonly Mock _mockConfiguration; + private readonly Mock _mockMessageDataAbstractFactory; + private readonly Mock _mockHttpClientFactory; public SendEmailHandlerTests() { - this.mockEmailService = new Mock(); - this.mockLogger = new Mock(); - this.mockStringLocalizer = new Mock>(); - this.mockHttpMessageHandler = new Mock(); - this.mockConfiguration = new Mock(); - this.mockMessageDataAbstractFactory = new Mock(); - this.mockStringLocalizer.Setup(x => x["RecaptchaRequestFailed"]).Returns(new LocalizedString("RecaptchaRequestFailed", "RecaptchaRequestFailed")); - this.mockStringLocalizer.Setup(x => x["InvalidCaptcha"]).Returns(new LocalizedString("InvalidCaptcha", "InvalidCaptcha")); - this.mockHttpClientFactory = new Mock(); + _mockEmailService = new Mock(); + _mockLogger = new Mock(); + _mockStringLocalizer = new Mock>(); + _mockHttpMessageHandler = new Mock(); + _mockConfiguration = new Mock(); + _mockMessageDataAbstractFactory = new Mock(); + _mockStringLocalizer.Setup(x => x["RecaptchaRequestFailed"]).Returns(new LocalizedString("RecaptchaRequestFailed", "RecaptchaRequestFailed")); + _mockStringLocalizer.Setup(x => x["InvalidCaptcha"]).Returns(new LocalizedString("InvalidCaptcha", "InvalidCaptcha")); + _mockHttpClientFactory = new Mock(); } [Fact] @@ -45,11 +45,11 @@ public async Task ShouldReturnSuccessfully_EmailIsCorrect() var reCaptchaResponseDto = GetReCaptchaResponseDTO(true); var emailDto = GetEmailDTO(); - this.SetupMockHttpMessageHandlerReturnsOK(reCaptchaResponseDto); - this.SetupMockEmailServiceReturnsOK(); - this.SetupMockIHttpClientFactory(); + SetupMockHttpMessageHandlerReturnsOK(reCaptchaResponseDto); + SetupMockEmailServiceReturnsOK(); + SetupMockIHttpClientFactory(); - var handler = new SendEmailHandler(this.mockEmailService.Object, this.mockLogger.Object, this.mockStringLocalizer.Object, this.mockHttpClientFactory.Object, this.mockConfiguration.Object, this.mockMessageDataAbstractFactory.Object); + var handler = new SendEmailHandler(_mockEmailService.Object, _mockLogger.Object, _mockStringLocalizer.Object, _mockHttpClientFactory.Object, _mockConfiguration.Object, _mockMessageDataAbstractFactory.Object); // act var result = await handler.Handle(new SendEmailCommand(emailDto), CancellationToken.None); @@ -65,11 +65,11 @@ public async Task ShouldReturnFail_WhenHttpClientRequestFailed() var emailDto = GetEmailDTO(); var expectedErrorMessage = "RecaptchaRequestFailed"; - this.SetupMockHttpMessageHandlerReturnsFail(); - this.SetupMockEmailServiceReturnsOK(); - this.SetupMockIHttpClientFactory(); + SetupMockHttpMessageHandlerReturnsFail(); + SetupMockEmailServiceReturnsOK(); + SetupMockIHttpClientFactory(); - var handler = new SendEmailHandler(this.mockEmailService.Object, this.mockLogger.Object, this.mockStringLocalizer.Object, this.mockHttpClientFactory.Object, this.mockConfiguration.Object, this.mockMessageDataAbstractFactory.Object); + var handler = new SendEmailHandler(_mockEmailService.Object, _mockLogger.Object, _mockStringLocalizer.Object, _mockHttpClientFactory.Object, _mockConfiguration.Object, _mockMessageDataAbstractFactory.Object); // act var result = await handler.Handle(new SendEmailCommand(emailDto), CancellationToken.None); @@ -87,11 +87,11 @@ public async Task ShouldReturnFail_WhenTokenIsIncorrect() var emailDto = GetEmailDTO(); var expectedErrorMessage = "InvalidCaptcha"; - this.SetupMockHttpMessageHandlerReturnsOK(reCaptchaResponseDto); - this.SetupMockEmailServiceReturnsOK(); - this.SetupMockIHttpClientFactory(); + SetupMockHttpMessageHandlerReturnsOK(reCaptchaResponseDto); + SetupMockEmailServiceReturnsOK(); + SetupMockIHttpClientFactory(); - var handler = new SendEmailHandler(this.mockEmailService.Object, this.mockLogger.Object, this.mockStringLocalizer.Object, this.mockHttpClientFactory.Object, this.mockConfiguration.Object, this.mockMessageDataAbstractFactory.Object); + var handler = new SendEmailHandler(_mockEmailService.Object, _mockLogger.Object, _mockStringLocalizer.Object, _mockHttpClientFactory.Object, _mockConfiguration.Object, _mockMessageDataAbstractFactory.Object); // act var result = await handler.Handle(new SendEmailCommand(emailDto), CancellationToken.None); @@ -109,12 +109,12 @@ public async Task ShouldReturnFail_WhenEmailWasNotSent() var emailDto = GetEmailDTO(); var expectedErrorMessage = "FailedToSendEmailMessage"; - this.SetupMockHttpMessageHandlerReturnsOK(reCaptchaResponseDto); - this.SetupMockEmailServiceReturnsFalse(); - this.SetupMockStringLocalizer(expectedErrorMessage); - this.SetupMockIHttpClientFactory(); + SetupMockHttpMessageHandlerReturnsOK(reCaptchaResponseDto); + SetupMockEmailServiceReturnsFalse(); + SetupMockStringLocalizer(expectedErrorMessage); + SetupMockIHttpClientFactory(); - var handler = new SendEmailHandler(this.mockEmailService.Object, this.mockLogger.Object, this.mockStringLocalizer.Object, this.mockHttpClientFactory.Object, this.mockConfiguration.Object, this.mockMessageDataAbstractFactory.Object); + var handler = new SendEmailHandler(_mockEmailService.Object, _mockLogger.Object, _mockStringLocalizer.Object, _mockHttpClientFactory.Object, _mockConfiguration.Object, _mockMessageDataAbstractFactory.Object); // act var result = await handler.Handle(new SendEmailCommand(emailDto), CancellationToken.None); @@ -144,28 +144,28 @@ private static EmailDTO GetEmailDTO() private void SetupMockHttpMessageHandlerReturnsOK(ReCaptchaResponseDto reCaptchaResponseDto) { - this.mockHttpMessageHandler.Protected() + _mockHttpMessageHandler.Protected() .Setup>("SendAsync", ItExpr.IsAny(), ItExpr.IsAny()) - .ReturnsAsync(new HttpResponseMessage { StatusCode = HttpStatusCode.OK, Content = JsonContent.Create(reCaptchaResponseDto) }); + .ReturnsAsync(new HttpResponseMessage { StatusCode = HttpStatusCode.OK, Content = JsonContent.Create(reCaptchaResponseDto) }); } private void SetupMockHttpMessageHandlerReturnsFail() { - this.mockHttpMessageHandler.Protected() + _mockHttpMessageHandler.Protected() .Setup>("SendAsync", ItExpr.IsAny(), ItExpr.IsAny()) .ReturnsAsync(new HttpResponseMessage { StatusCode = HttpStatusCode.BadRequest }); } private void SetupMockEmailServiceReturnsOK() { - this.mockEmailService + _mockEmailService .Setup>(service => service.SendEmailAsync(It.IsAny())) .Returns(Task.FromResult(true)); } private void SetupMockEmailServiceReturnsFalse() { - this.mockEmailService + _mockEmailService .Setup>(service => service.SendEmailAsync(It.IsAny())) .Returns(Task.FromResult(false)); } @@ -173,13 +173,13 @@ private void SetupMockEmailServiceReturnsFalse() private void SetupMockStringLocalizer(string key) { var localizedString = new LocalizedString(key, key); - this.mockStringLocalizer.Setup(_ => _[key]).Returns(localizedString); + _mockStringLocalizer.Setup(_ => _[key]).Returns(localizedString); } private void SetupMockIHttpClientFactory() { - var client = new HttpClient(this.mockHttpMessageHandler.Object); - this.mockHttpClientFactory.Setup(_ => _.CreateClient(It.IsAny())).Returns(client); + var client = new HttpClient(_mockHttpMessageHandler.Object); + _mockHttpClientFactory.Setup(_ => _.CreateClient(It.IsAny())).Returns(client); } } } diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Media/Image/GetAllImageTests/GetAllImagesTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Media/Image/GetAllImageTests/GetAllImagesTest.cs deleted file mode 100644 index 84a39f7bd..000000000 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Media/Image/GetAllImageTests/GetAllImagesTest.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System.Linq.Expressions; -using AutoMapper; -using FluentResults; -using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; -using Moq; -using Streetcode.BLL.DTO.Media.Images; -using Streetcode.BLL.Interfaces.BlobStorage; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.MediatR.Media.Image.GetAll; -using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Repositories.Interfaces.Base; - -using Xunit; - -namespace Streetcode.XUnitTest.MediatRTests.Media.Images -{ - using ImageEntity = DAL.Entities.Media.Images; - - public class GetAllImagesTest - { - private readonly Mock mockRepo; - private readonly Mock mockMapper; - private readonly Mock blobService; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizer; - - public GetAllImagesTest() - { - this.mockRepo = new Mock(); - this.mockMapper = new Mock(); - this.blobService = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizer = new Mock>(); - } - - [Fact] - public async Task Handle_ReturnsAllImages() - { - // Arrange - this.MockRepositoryAndMapper(this.GetImagesList(), this.GetImagesDTOList()); - var handler = new GetAllImagesHandler(this.mockRepo.Object, this.mockMapper.Object, this.blobService.Object, this.mockLogger.Object, this.mockLocalizer.Object); - - // Act - var result = await handler.Handle(new GetAllImagesQuery(), default); - - // Assert - Assert.Equal(this.GetImagesList().Count, result.Value.Count()); - } - - [Fact] - public async Task Handle_ReturnsError() - { - // Arrange - this.MockRepositoryAndMapper(null, new List() { }); - var expectedError = $"Cannot find any image"; - this.mockLocalizer.Setup(localizer => localizer["CannotFindAnyImage"]) - .Returns(new LocalizedString("CannotFindAnyImage", expectedError)); - var handler = new GetAllImagesHandler(this.mockRepo.Object, this.mockMapper.Object, this.blobService.Object, this.mockLogger.Object, this.mockLocalizer.Object); - - // Act - var result = await handler.Handle(new GetAllImagesQuery(), default); - - // Assert - Assert.Equal(expectedError, result.Errors.Single().Message); - } - - [Fact] - public async Task Handle_ReturnsType() - { - // Arrange - this.MockRepositoryAndMapper(this.GetImagesList(), this.GetImagesDTOList()); - var handler = new GetAllImagesHandler(this.mockRepo.Object, this.mockMapper.Object, this.blobService.Object, this.mockLogger.Object, this.mockLocalizer.Object); - - // Act - var result = await handler.Handle(new GetAllImagesQuery(), default); - - // Assert - Assert.IsType>>(result); - } - - private List GetImagesList() - { - return new List() - { - new ImageEntity.Image() - { - Id = 1, - BlobName = "https://", - MimeType = string.Empty, - }, - new ImageEntity.Image() - { - Id = 2, - BlobName = "https://", - MimeType = string.Empty, - }, - }; - } - - private List GetImagesDTOList() - { - return new List() - { - new ImageDTO - { - Id = 1, - }, - new ImageDTO - { - Id = 2, - }, - }; - } - - private void MockRepositoryAndMapper(List imageList, List imageListDTO) - { - this.mockRepo.Setup(r => r.ImageRepository.GetAllAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(imageList); - - this.mockMapper.Setup(x => x.Map>(It.IsAny>())) - .Returns(imageListDTO); - } - } -} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/CreateFactTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/CreateFactTest.cs index 8ba5f85a0..6938518be 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/CreateFactTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/CreateFactTest.cs @@ -1,136 +1,136 @@ using AutoMapper; +using FluentAssertions; using MediatR; -using Microsoft.Extensions.Localization; using Moq; using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Streetcode.Fact.Create; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Streetcode.TextContent; using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; using Xunit; namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Facts; public class CreateFactTest { - private readonly Mock mockRepository; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerFailedToCreate; - private readonly Mock> mockLocalizerConvertNull; + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly MockFailedToCreateLocalizer _mockFailedToCreateLocalizer; + private readonly MockCannotConvertNullLocalizer _mockCannotConvertNullLocalizer; + private readonly CreateFactHandler _handler; public CreateFactTest() { - this.mockRepository = new Mock(); - this.mockMapper = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerConvertNull = new Mock>(); - this.mockLocalizerFailedToCreate = new Mock>(); + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockFailedToCreateLocalizer = new MockFailedToCreateLocalizer(); + _mockCannotConvertNullLocalizer = new MockCannotConvertNullLocalizer(); + _handler = new CreateFactHandler( + _mockRepository.Object, + _mockMapper.Object, + _mockLogger.Object, + _mockFailedToCreateLocalizer, + _mockCannotConvertNullLocalizer); } [Fact] - public async Task ShouldReturnSuccessfully_TypeIsCorrect() + public async Task ShouldCreateSuccessfully_WhenFactAdded() { // Arrange - this.mockRepository.Setup(x => x.FactRepository.Create(GetFact())); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(1); + var (factDto, fact) = GetFactObjects(); + var request = GetRequest(factDto); - this.mockMapper.Setup(x => x.Map(It.IsAny())) - .Returns(GetFact()); - - var handler = new CreateFactHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerFailedToCreate.Object, this.mockLocalizerConvertNull.Object); + SetupMockCreateAndSaveChangesAsync(fact, 1); + MockHelpers.SetupMockMapper(_mockMapper, fact, request.Fact); // Act - var result = await handler.Handle(new CreateFactCommand(GetFactDTO()), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.IsType(result.Value); + result.IsSuccess.Should().BeTrue(); + _mockRepository.Verify(x => x.FactRepository.CreateAsync(fact), Times.Once); + _mockRepository.Verify(x => x.SaveChangesAsync(), Times.Once); } [Fact] - public async Task ShouldReturnSuccessfully_WhenFactAdded() + public async Task ShouldCreateSuccessfully_WithCorrectDataType() { // Arrange - this.mockRepository.Setup(x => x.FactRepository.Create(GetFact())); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(1); - - this.mockMapper.Setup(x => x.Map(It.IsAny())) - .Returns(GetFact()); + var (factDto, fact) = GetFactObjects(); + var request = GetRequest(factDto); - var handler = new CreateFactHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerFailedToCreate.Object, this.mockLocalizerConvertNull.Object); + SetupMockCreateAndSaveChangesAsync(fact, 1); + MockHelpers.SetupMockMapper(_mockMapper, fact, request.Fact); // Act - var result = await handler.Handle(new CreateFactCommand(GetFactDTO()), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.True(result.IsSuccess); + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType(); } [Fact] - public async Task ShouldThrowExeption_WhenTryToAddNull() + public async Task ShouldCreateFailingly_WhenMappingFailed() { // Arrange - this.mockRepository.Setup(x => x.FactRepository.Create(GetFact())); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(1); - - this.mockMapper - .Setup(x => x.Map(It.IsAny())) - .Returns(GetFactWithNotExistId()); - - var expectedError = "Cannot convert null to Fact"; - this.mockLocalizerConvertNull.Setup(x => x["CannotConvertNullToFact"]) - .Returns(new LocalizedString("CannotConvertNullToFact", expectedError)); + var (factDto, _) = GetFactObjects(); + var request = GetRequest(factDto); + var expectedErrorMessage = _mockCannotConvertNullLocalizer["CannotConvertNullToFact"].Value; - var handler = new CreateFactHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerFailedToCreate.Object, this.mockLocalizerConvertNull.Object); + MockHelpers.SetupMockMapper(_mockMapper, null, request.Fact); // Act - var result = await handler.Handle(new CreateFactCommand(GetFactDTOWithNotExistId() !), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.Equal(expectedError, result.Errors[0].Message); + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); } [Fact] - public async Task ShouldThrowExeption_SaveChangesAsyncIsNotSuccessful() + public async Task ShouldCreateFailingly_WhenSaveChangesAsyncFailed() { // Arrange - this.mockRepository.Setup(x => x.FactRepository.Create(GetFact())); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(-1); + var (factDto, fact) = GetFactObjects(); + var request = GetRequest(factDto); + var expectedErrorMessage = _mockFailedToCreateLocalizer["FailedToCreateFact"].Value; - this.mockMapper.Setup(x => x.Map(It.IsAny())) - .Returns(GetFact()); - - var expectedError = "Failed to create a fact"; - this.mockLocalizerFailedToCreate.Setup(x => x["FailedToCreateFact"]) - .Returns(new LocalizedString("FailedToCreateFact", expectedError)); - - var handler = new CreateFactHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerFailedToCreate.Object, this.mockLocalizerConvertNull.Object); + SetupMockCreateAndSaveChangesAsync(fact, -1); + MockHelpers.SetupMockMapper(_mockMapper, fact, request.Fact); // Act - var result = await handler.Handle(new CreateFactCommand(GetFactDTO()), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.Equal(expectedError, result.Errors[0].Message); + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); } - private static Fact GetFact() + private static (StreetcodeFactCreateDTO, Fact) GetFactObjects() { - return new Fact(); - } + var factCreateDto = new StreetcodeFactCreateDTO(); + var fact = new Fact(); - private static StreetcodeFactCreateDTO GetFactDTO() - { - return new StreetcodeFactCreateDTO(); + return (factCreateDto, fact); } - private static Fact? GetFactWithNotExistId() + private static CreateFactCommand GetRequest(StreetcodeFactCreateDTO factDto) { - return null; + return new CreateFactCommand(factDto); } - private static StreetcodeFactCreateDTO? GetFactDTOWithNotExistId() + private void SetupMockCreateAndSaveChangesAsync(Fact fact, int saveChangesResult) { - return null; + _mockRepository + .Setup(x => x.FactRepository.CreateAsync(fact)); + _mockRepository + .Setup(x => x.SaveChangesAsync()) + .ReturnsAsync(saveChangesResult); } } diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/DeleteFactTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/DeleteFactTest.cs index 27c5ec607..e873b7f1d 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/DeleteFactTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/DeleteFactTest.cs @@ -1,135 +1,134 @@ -using System.Linq.Expressions; -using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; +using FluentAssertions; +using MediatR; using Moq; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Streetcode.Fact.Delete; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Streetcode.TextContent; using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; using Xunit; namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Facts; public class DeleteFactTest { - private readonly Mock repository; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerFailedToDelete; - private readonly Mock> mockLocalizerCannotFind; + private readonly Mock _mockRepository; + private readonly Mock _mockLogger; + private readonly MockFailedToDeleteLocalizer _mockFailedToDeleteLocalizer; + private readonly MockCannotFindLocalizer _mockCannotFindLocalizer; + private readonly DeleteFactHandler _handler; public DeleteFactTest() { - this.repository = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerCannotFind = new Mock>(); - this.mockLocalizerFailedToDelete = new Mock>(); + _mockRepository = new Mock(); + _mockLogger = new Mock(); + _mockFailedToDeleteLocalizer = new MockFailedToDeleteLocalizer(); + _mockCannotFindLocalizer = new MockCannotFindLocalizer(); + _handler = new DeleteFactHandler( + _mockRepository.Object, + _mockLogger.Object, + _mockFailedToDeleteLocalizer, + _mockCannotFindLocalizer); } [Theory] - [InlineData(2)] - public async Task ShouldDeleteSuccessfully(int id) + [InlineData(1)] + public async Task ShouldDeleteSuccessfully_WhenFactExists(int factId) { // Arrange - this.repository - .Setup(x => x.FactRepository.GetFirstOrDefaultAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(GetFact(id)); + var fact = GetFact(factId); + var request = GetRequest(factId); - this.repository.Setup(x => x.FactRepository - .Delete(GetFact(id))); - - this.repository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(1); - - var handler = new DeleteFactHandler(this.repository.Object, this.mockLogger.Object, this.mockLocalizerFailedToDelete.Object, this.mockLocalizerCannotFind.Object); + MockHelpers.SetupMockFactRepositoryGetFirstOrDefaultAsync(_mockRepository, fact); + SetupMockDeleteAndSaveChangesAsync(fact, 1); // Act - var result = await handler.Handle(new DeleteFactCommand(id), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.Multiple( - () => Assert.NotNull(result), - () => Assert.True(result.IsSuccess)); + result.IsSuccess.Should().BeTrue(); + _mockRepository.Verify(x => x.FactRepository.Delete(fact), Times.Once); + _mockRepository.Verify(x => x.SaveChangesAsync(), Times.Once); } [Theory] - [InlineData(2)] - public async Task ShouldThrowExeption_IdNotExisting(int id) + [InlineData(1)] + public async Task ShouldDeleteSuccessfully_WithCorrectDataType(int factId) { // Arrange - this.repository - .Setup(x => x.FactRepository.GetFirstOrDefaultAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(GetFactWithNotExistingId()); - - this.repository - .Setup(x => x.FactRepository - .Delete(GetFactWithNotExistingId() !)); - - var expectedError = $"Cannot find a fact with corresponding categoryId: {id}"; - this.mockLocalizerCannotFind.Setup(x => x[It.IsAny(), It.IsAny()]).Returns((string key, object[] args) => - { - if (args != null && args.Length > 0 && args[0] is int id) - { - return new LocalizedString(key, $"Cannot find a fact with corresponding categoryId: {id}"); - } + var fact = GetFact(factId); + var request = GetRequest(factId); - return new LocalizedString(key, "Cannot find any fact with unknown categoryId"); - }); + MockHelpers.SetupMockFactRepositoryGetFirstOrDefaultAsync(_mockRepository, fact); + SetupMockDeleteAndSaveChangesAsync(fact, 1); // Act - var handler = new DeleteFactHandler(this.repository.Object, this.mockLogger.Object, this.mockLocalizerFailedToDelete.Object, this.mockLocalizerCannotFind.Object); - - var result = await handler.Handle(new DeleteFactCommand(id), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.Equal(expectedError, result.Errors[0].Message); + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType(); } [Theory] - [InlineData(2)] - public async Task ShouldThrowExeption_SaveChangesAsyncIsNotSuccessful(int id) + [InlineData(1)] + public async Task ShouldDeleteFailingly_WhenFactNotExist(int factId) { // Arrange - this.repository - .Setup(x => x.FactRepository.GetFirstOrDefaultAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(GetFact(id)); + var request = GetRequest(factId); + var expectedErrorMessage = _mockCannotFindLocalizer["CannotFindFactWithCorrespondingCategoryId", factId].Value; - this.repository.Setup(x => x.FactRepository - .Delete(GetFact(id))); + MockHelpers.SetupMockFactRepositoryGetFirstOrDefaultAsync(_mockRepository, null); - this.repository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(0); + // Act + var result = await _handler.Handle(request, CancellationToken.None); - var expectedError = "Failed to delete a fact"; - this.mockLocalizerFailedToDelete.Setup(x => x["FailedToDeleteFact"]) - .Returns(new LocalizedString("FailedToDeleteFact", expectedError)); + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } - // Act - var handler = new DeleteFactHandler(this.repository.Object, this.mockLogger.Object, this.mockLocalizerFailedToDelete.Object, this.mockLocalizerCannotFind.Object); + [Theory] + [InlineData(1)] + public async Task ShouldDeleteFailingly_WhenSaveChangesAsyncFailed(int factId) + { + // Arrange + var fact = GetFact(factId); + var request = GetRequest(factId); + var expectedErrorMessage = _mockFailedToDeleteLocalizer["FailedToDeleteFact"].Value; + + MockHelpers.SetupMockFactRepositoryGetFirstOrDefaultAsync(_mockRepository, fact); + SetupMockDeleteAndSaveChangesAsync(fact, -1); - var result = await handler.Handle(new DeleteFactCommand(id), CancellationToken.None); + // Act + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.Equal(expectedError, result.Errors[0].Message); + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); } - private static Fact GetFact(int id) + private static Fact GetFact(int factId) { - return new Fact + return new Fact() { - Id = id, + Id = factId, }; } - private static Fact? GetFactWithNotExistingId() + private static DeleteFactCommand GetRequest(int factId) + { + return new DeleteFactCommand(factId); + } + + private void SetupMockDeleteAndSaveChangesAsync(Fact fact, int saveChangesResult) { - return null; + _mockRepository + .Setup(x => x.FactRepository.Delete(fact)); + _mockRepository + .Setup(x => x.SaveChangesAsync()) + .ReturnsAsync(saveChangesResult); } } diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/GetAllFactsTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/GetAllFactsTest.cs index 71794d835..2a3ebd703 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/GetAllFactsTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/GetAllFactsTest.cs @@ -1,155 +1,135 @@ using System.Linq.Expressions; using AutoMapper; +using FluentAssertions; using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; using Moq; using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; -using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Streetcode.Fact.GetAll; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Streetcode.TextContent; using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; using Xunit; namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Facts; public class GetAllFactsTest { - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotFind; - private Mock mockRepository; - private Mock mockMapper; + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly GetAllFactsHandler _handler; public GetAllFactsTest() { - this.mockRepository = new Mock(); - this.mockMapper = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerCannotFind = new Mock>(); + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _handler = new GetAllFactsHandler(_mockRepository.Object, _mockMapper.Object); } [Fact] - public async Task ShouldReturnSuccessfully_CorrectType() + public async Task ShouldGetAllSuccessfully_WhenFactsExist() { // Arrange - (this.mockMapper, this.mockRepository) = GetMapperAndRepo(this.mockMapper, this.mockRepository); + var (factsList, factDtoList) = GetFactObjectsLists(); + var request = GetRequest(); - var handler = new GetAllFactsHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + MockHelpers.SetupMockFactRepositoryGetAllAsync(_mockRepository, factsList); + MockHelpers.SetupMockMapper, List>(_mockMapper, factDtoList, factsList); // Act - var result = await handler.Handle(new GetAllFactsQuery(), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.Multiple( - () => Assert.NotNull(result), - () => Assert.IsType>(result.ValueOrDefault)); + result.IsSuccess.Should().BeTrue(); + result.Value.Should().SatisfyRespectively( + first => first.Id.Should().Be(factsList[0].Id), + second => second.Id.Should().Be(factsList[1].Id)); + result.Value.Should().HaveCount(2); + VerifyGetAllAsyncAndMockingOperationsExecution(factsList); } [Fact] - public async Task ShouldReturnSuccessfully_CountMatch() + public async Task ShouldGetAllSuccessfully_WithCorrectDataType() { // Arrange - (this.mockMapper, this.mockRepository) = GetMapperAndRepo(this.mockMapper, this.mockRepository); + var (factsList, factDtoList) = GetFactObjectsLists(); + var request = GetRequest(); - var handler = new GetAllFactsHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + MockHelpers.SetupMockFactRepositoryGetAllAsync(_mockRepository, factsList); + MockHelpers.SetupMockMapper, List>(_mockMapper, factDtoList, factsList); // Act - var result = await handler.Handle(new GetAllFactsQuery(), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.Multiple( - () => Assert.NotNull(result), - () => Assert.Equal(GetListFacts().Count(), result.Value.Count())); + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType>(); } [Fact] - public async Task ShouldThrowExeption_IdNotExist() + public async Task ShouldGetAllSuccessfully_WhenFactsNotExist() { // Arrange - this.mockRepository - .Setup(x => x.FactRepository.GetAllAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(GetListFactsWithNotExistingId()); - - this.mockMapper - .Setup(x => x.Map>(It.IsAny>())) - .Returns(GetListFactsDTOWithNotExistingId()); + var (emptyFactsList, emptyFactDtoList) = GetEmptyFactsObjectsLists(); + var request = GetRequest(); - var expectedError = "Cannot find any fact"; - this.mockLocalizerCannotFind.Setup(x => x["CannotFindAnyFact"]) - .Returns(new LocalizedString("CannotFindAnyFact", expectedError)); - - var handler = new GetAllFactsHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + MockHelpers.SetupMockFactRepositoryGetAllAsync(_mockRepository, emptyFactsList); + MockHelpers.SetupMockMapper(_mockMapper, emptyFactDtoList, emptyFactsList); // Act - var result = await handler.Handle(new GetAllFactsQuery(), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.Equal(expectedError, result.Errors[0].Message); + result.IsSuccess.Should().BeTrue(); + result.Value.Should().BeEmpty(); + result.ValueOrDefault.Should().BeAssignableTo>(); + VerifyGetAllAsyncAndMockingOperationsExecution(emptyFactsList); } - private static (Mock, Mock) GetMapperAndRepo( - Mock mockMapper, - Mock mockRepository) + private static (List, List) GetFactObjectsLists() { - mockRepository - .Setup(x => x.FactRepository.GetAllAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(GetListFacts()); - - mockMapper - .Setup(x => x - .Map>(It.IsAny>())) - .Returns(GetListFactDTO()); - - return (mockMapper, mockRepository); - } - - private static IQueryable GetListFacts() - { - var facts = new List + var factsList = new List() { - new Fact + new Fact() { Id = 1, }, - new Fact + new Fact() { Id = 2, }, }; + var factDtoList = new List() + { + new FactDto() + { + Id = factsList[0].Id, + }, + new FactDto() + { + Id = factsList[1].Id, + }, + }; - return facts.AsQueryable(); + return (factsList, factDtoList); } - private static List GetListFactsWithNotExistingId() + private static (List, List) GetEmptyFactsObjectsLists() { - return null; + return (new List(), new List()); } - private static List GetListFactsDTOWithNotExistingId() + private static GetAllFactsQuery GetRequest() { - return null; + return new GetAllFactsQuery(); } - private static List GetListFactDTO() + private void VerifyGetAllAsyncAndMockingOperationsExecution(List factsList) { - var factsDTO = new List - { - new FactDto - { - Id = 1, - }, - new FactDto - { - Id = 2, - }, - }; - - return factsDTO; + _mockRepository.Verify( + x => x.FactRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>()), + Times.Once); + _mockMapper.Verify(x => x.Map>(factsList), Times.Once); } } diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/GetFactByIdTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/GetFactByIdTest.cs index 1c3ee7cb4..c5f9b81ca 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/GetFactByIdTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/GetFactByIdTest.cs @@ -1,155 +1,117 @@ -using System.Linq.Expressions; -using AutoMapper; +using AutoMapper; +using FluentAssertions; using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; using Moq; using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Streetcode.Fact.GetById; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Streetcode.TextContent; using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; using Xunit; namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Facts; public class GetFactByIdTest { - private readonly Mock mockRepository; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotFind; + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly MockCannotFindLocalizer _mockCannotFindLocalizer; + private readonly GetFactByIdHandler _handler; public GetFactByIdTest() { - this.mockMapper = new Mock(); - this.mockRepository = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerCannotFind = new Mock>(); + _mockMapper = new Mock(); + _mockRepository = new Mock(); + _mockLogger = new Mock(); + _mockCannotFindLocalizer = new MockCannotFindLocalizer(); + _handler = new GetFactByIdHandler( + _mockRepository.Object, + _mockMapper.Object, + _mockLogger.Object, + _mockCannotFindLocalizer); } [Theory] [InlineData(1)] - public async Task ShouldReturnSuccessfully_ExistingId(int id) + public async Task ShouldGetByIdSuccessfully_WhenIdExists(int factId) { // Arrange - this.mockRepository - .Setup(x => x.FactRepository - .GetFirstOrDefaultAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(GetFact(id)); + var (fact, factDto) = GetFactObjects(factId); + var request = GetRequest(factId); - this.mockMapper - .Setup(x => x - .Map(It.IsAny())) - .Returns(GetFactDTO(id)); - - var handler = new GetFactByIdHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + MockHelpers.SetupMockFactRepositoryGetFirstOrDefaultAsync(_mockRepository, fact); + MockHelpers.SetupMockMapper(_mockMapper, factDto, fact); // Act - var result = await handler.Handle(new GetFactByIdQuery(id), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.Multiple( - () => Assert.NotNull(result), - () => Assert.True(result.IsSuccess), - () => Assert.Equal(result.Value.Id, id)); + result.IsSuccess.Should().BeTrue(); + result.Value.Id.Should().Be(factId); + _mockRepository.Verify( + x => x.FactRepository.GetFirstOrDefaultAsync( + f => f.Id == request.Id, + It.IsAny, IIncludableQueryable>>()), + Times.Once); + _mockMapper.Verify(x => x.Map(fact), Times.Once); } [Theory] [InlineData(1)] - public async Task ShouldReturnSuccessfully_NotExistingId(int id) + public async Task ShouldGetByIdSuccessfully_WithCorrectDataType(int factId) { // Arrange - this.mockRepository - .Setup(x => x.FactRepository - .GetFirstOrDefaultAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(GetFactWithNotExistingId()); - - this.mockMapper - .Setup(x => x.Map(It.IsAny())) - .Returns(GetFactDTOWithNotExistingId()); - - var expectedError = $"Cannot find any fact with corresponding id: {id}"; - this.mockLocalizerCannotFind.Setup(x => x[It.IsAny(), It.IsAny()]).Returns((string key, object[] args) => - { - if (args != null && args.Length > 0 && args[0] is int id) - { - return new LocalizedString(key, $"Cannot find any fact with corresponding id: {id}"); - } - - return new LocalizedString(key, "Cannot find any fact with unknown categoryId"); - }); + var (fact, factDto) = GetFactObjects(factId); + var request = GetRequest(factId); - var handler = new GetFactByIdHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + MockHelpers.SetupMockFactRepositoryGetFirstOrDefaultAsync(_mockRepository, fact); + MockHelpers.SetupMockMapper(_mockMapper, factDto, fact); // Act - var result = await handler.Handle(new GetFactByIdQuery(id), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.Multiple( - () => Assert.NotNull(result), - () => Assert.True(result.IsFailed), - () => Assert.Equal(expectedError, result.Errors[0].Message)); + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType(); } [Theory] [InlineData(1)] - public async Task ShouldReturnSuccessfully_CorrectType(int id) + public async Task ShouldGetByIdFailingly_WhenFactNotFound(int factId) { // Arrange - this.mockRepository - .Setup(x => x.FactRepository - .GetFirstOrDefaultAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(GetFact(id)); + var request = GetRequest(factId); + var expectedErrorMessage = _mockCannotFindLocalizer["CannotFindFactWithCorrespondingCategoryId", factId].Value; - this.mockMapper - .Setup(x => x - .Map(It.IsAny())) - .Returns(GetFactDTO(id)); - - var handler = new GetFactByIdHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + MockHelpers.SetupMockFactRepositoryGetFirstOrDefaultAsync(_mockRepository, null); // Act - var result = await handler.Handle(new GetFactByIdQuery(id), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.Multiple( - () => Assert.NotNull(result.ValueOrDefault), - () => Assert.IsType(result.ValueOrDefault)); + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); } - private static Fact GetFact(int id) + private static (Fact, FactDto) GetFactObjects(int factId) { - return new Fact + var fact = new Fact() { - Id = id, + Id = factId, }; - } - - private static Fact? GetFactWithNotExistingId() - { - return null; - } - - private static FactDto GetFactDTO(int id) - { - return new FactDto + var factDto = new FactDto() { - Id = id, + Id = fact.Id, }; + + return (fact, factDto); } - private static FactDto? GetFactDTOWithNotExistingId() + private static GetFactByIdQuery GetRequest(int factId) { - return null; + return new GetFactByIdQuery(factId); } } diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/GetFactByStreetcodeIdTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/GetFactByStreetcodeIdTest.cs deleted file mode 100644 index 1e3b316e6..000000000 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/GetFactByStreetcodeIdTest.cs +++ /dev/null @@ -1,154 +0,0 @@ -using System.Linq.Expressions; -using AutoMapper; -using FluentResults; -using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; -using Moq; -using Streetcode.BLL.DTO.Partners; -using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.MediatR.Streetcode.Fact.GetByStreetcodeId; -using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Entities.Streetcode; -using Streetcode.DAL.Entities.Streetcode.TextContent; -using Streetcode.DAL.Repositories.Interfaces.Base; -using Xunit; - -namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Facts; - -public class GetFactByStreetcodeIdTest -{ - private readonly Mock mockRepository; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotFind; - - public GetFactByStreetcodeIdTest() - { - this.mockRepository = new Mock(); - this.mockMapper = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerCannotFind = new Mock>(); - } - - [Theory] - [InlineData(1)] - public async Task ShouldReturnSuccessfully_ExistingId(int streetCodeId) - { - // Arrange - this.mockRepository.Setup(x => x.FactRepository - .GetAllAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(GetListFacts()); - - this.mockMapper - .Setup(x => x - .Map>(It.IsAny>())) - .Returns(GetListFactDTO()); - - var handler = new GetFactByStreetcodeIdHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); - - // Act - var result = await handler.Handle(new GetFactByStreetcodeIdQuery(streetCodeId), CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.NotNull(result), - () => Assert.True(result.IsSuccess), - () => Assert.NotEmpty(result.Value)); - } - - [Theory] - [InlineData(2)] - public async Task ShouldReturnSuccessfully_CorrectType(int streetCodeId) - { - // Arrange - this.mockRepository.Setup(x => x.FactRepository - .GetAllAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(GetListFacts()); - - this.mockMapper - .Setup(x => x - .Map>(It.IsAny>())) - .Returns(GetListFactDTO()); - - var handler = new GetFactByStreetcodeIdHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); - - // Act - var result = await handler.Handle(new GetFactByStreetcodeIdQuery(streetCodeId), CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.NotNull(result), - () => Assert.True(result.IsSuccess), - () => Assert.IsType>(result.ValueOrDefault)); - } - - [Theory] - [InlineData(1)] - public async Task ShouldReturnSuccessfully_IdNotExist(int streetCodeId) - { - // Arrange - this.mockRepository.Setup(x => x.FactRepository - .GetAllAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(GetListFactsWithNotExistingStreetcodeId() !); - - var handler = new GetFactByStreetcodeIdHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); - - // Act - var result = await handler.Handle(new GetFactByStreetcodeIdQuery(streetCodeId), CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.IsType>>(result), - () => Assert.IsAssignableFrom>(result.Value), - () => Assert.Empty(result.Value)); - } - - private static IQueryable GetListFacts() - { - var facts = new List - { - new Fact - { - Id = 1, - Title = "Викуп з кріпацтва", - ImageId = null, - Streetcode = new StreetcodeContent - { - Id = 1, - }, - StreetcodeId = 1, - FactContent = "Навесні 1838-го Карл Брюллов...", - }, - }; - - return facts.AsQueryable(); - } - - private static List GetListFactsWithNotExistingStreetcodeId() - { - return new List(); - } - - private static List GetListFactDTO() - { - var facts = new List - { - new FactDto - { - Id = 1, - }, - }; - - return facts; - } -} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/GetFactsByStreetcodeIdTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/GetFactsByStreetcodeIdTest.cs new file mode 100644 index 000000000..8e917f968 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/GetFactsByStreetcodeIdTest.cs @@ -0,0 +1,147 @@ +using AutoMapper; +using FluentAssertions; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Fact.GetByStreetcodeId; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Facts; + +public class GetFactsByStreetcodeIdTest +{ + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly MockCannotFindLocalizer _mockCannotFindLocalizer; + private readonly GetFactByStreetcodeIdHandler _handler; + + public GetFactsByStreetcodeIdTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockCannotFindLocalizer = new MockCannotFindLocalizer(); + _handler = new GetFactByStreetcodeIdHandler( + _mockRepository.Object, + _mockMapper.Object, + _mockLogger.Object, + _mockCannotFindLocalizer); + } + + [Theory] + [InlineData(1)] + public async Task ShouldGetByStreetcodeIdSuccessfully_WhenIdExists(int streetcodeId) + { + // Arrange + var (factsList, factDtoList) = GetFactObjectsLists(streetcodeId); + var request = GetRequest(streetcodeId); + + MockHelpers.SetupMockFactRepositoryGetAllAsync(_mockRepository, factsList); + MockHelpers.SetupMockMapper, List>(_mockMapper, factDtoList, factsList); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Should().SatisfyRespectively( + first => first.Id.Should().Be(factsList[0].Id), + second => second.Id.Should().Be(factsList[1].Id)); + result.Value.Should().HaveCount(2); + _mockMapper.Verify(x => x.Map>(factsList), Times.Once); + VerifyGetAllAsyncOperationExecution(request); + } + + [Theory] + [InlineData(1)] + public async Task ShouldGetByStreetcodeIdSuccessfully_WithCorrectDataType(int streetcodeId) + { + // Arrange + var (factsList, factDtoList) = GetFactObjectsLists(streetcodeId); + var request = GetRequest(streetcodeId); + + MockHelpers.SetupMockFactRepositoryGetAllAsync(_mockRepository, factsList); + MockHelpers.SetupMockMapper, List>(_mockMapper, factDtoList, factsList); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType>(); + } + + [Theory] + [InlineData(1)] + public async Task ShouldGetByStreetcodeIdSuccessfully_WhenIdNotExists(int streetcodeId) + { + // Arrange + var emptyFactsList = GetEmptyFactsList(); + var request = GetRequest(streetcodeId); + + MockHelpers.SetupMockFactRepositoryGetAllAsync(_mockRepository, emptyFactsList); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Should().BeEmpty(); + result.ValueOrDefault.Should().BeAssignableTo>(); + VerifyGetAllAsyncOperationExecution(request); + } + + private static (List, List) GetFactObjectsLists(int streetcodeId) + { + var factsList = new List() + { + new Fact() + { + Id = 1, + StreetcodeId = streetcodeId, + }, + new Fact() + { + Id = 2, + StreetcodeId = streetcodeId, + }, + }; + var factDtoList = new List() + { + new FactDto() + { + Id = factsList[0].Id, + }, + new FactDto() + { + Id = factsList[1].Id, + }, + }; + + return (factsList, factDtoList); + } + + private static List GetEmptyFactsList() + { + return new List(); + } + + private static GetFactByStreetcodeIdQuery GetRequest(int streetcodeId) + { + return new GetFactByStreetcodeIdQuery(streetcodeId); + } + + private void VerifyGetAllAsyncOperationExecution(GetFactByStreetcodeIdQuery request) + { + _mockRepository.Verify( + x => x.FactRepository.GetAllAsync( + f => f.StreetcodeId == request.StreetcodeId, + It.IsAny, IIncludableQueryable>>()), + Times.Once); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/UpdateFactTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/UpdateFactTest.cs index 8d1ca3ae0..2264aee9c 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/UpdateFactTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Facts/UpdateFactTest.cs @@ -1,136 +1,136 @@ using AutoMapper; +using FluentAssertions; using MediatR; -using Microsoft.Extensions.Localization; using Moq; using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Streetcode.Fact.Update; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Streetcode.TextContent; using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; using Xunit; namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Facts; public class UpdateFactTest { - private readonly Mock mockRepository; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerFailedToUpdate; - private readonly Mock> mockLocalizerConvertNull; + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly MockFailedToUpdateLocalizer _mockFailedToUpdateLocalizer; + private readonly MockCannotConvertNullLocalizer _mockCannotConvertNullLocalizer; + private readonly UpdateFactHandler _handler; public UpdateFactTest() { - this.mockRepository = new Mock(); - this.mockMapper = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerConvertNull = new Mock>(); - this.mockLocalizerFailedToUpdate = new Mock>(); + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockFailedToUpdateLocalizer = new MockFailedToUpdateLocalizer(); + _mockCannotConvertNullLocalizer = new MockCannotConvertNullLocalizer(); + _handler = new UpdateFactHandler( + _mockRepository.Object, + _mockMapper.Object, + _mockLogger.Object, + _mockFailedToUpdateLocalizer, + _mockCannotConvertNullLocalizer); } [Fact] - public async Task ShouldReturnSuccessfully_WhenUpdated() + public async Task ShouldUpdateSuccessfully_WhenFactExists() { // Arrange - this.mockRepository.Setup(x => x.FactRepository.Update(GetFact())); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(1); + var (fact, factDto) = GetFactObjects(); + var request = GetRequest(factDto); - this.mockMapper.Setup(x => x.Map(It.IsAny())) - .Returns(GetFact()); - - var handler = new UpdateFactHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerFailedToUpdate.Object, this.mockLocalizerConvertNull.Object); + SetupMockUpdateAndSaveChangesAsync(fact, 1); + MockHelpers.SetupMockMapper(_mockMapper, fact, request.Fact); // Act - var result = await handler.Handle(new UpdateFactCommand(GetFactDTO()), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.True(result.IsSuccess); + result.IsSuccess.Should().BeTrue(); + _mockRepository.Verify(x => x.FactRepository.Update(fact), Times.Once); + _mockRepository.Verify(x => x.SaveChangesAsync(), Times.Once); } [Fact] - public async Task ShouldThrowExeption_TryMapNullRequest() + public async Task ShouldUpdateSuccessfully_WithCorrectDataType() { // Arrange - this.mockRepository.Setup(x => x.FactRepository.Update(GetFactWithNotExistId() !)); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(1); - - this.mockMapper - .Setup(x => x.Map(It.IsAny())) - .Returns(GetFactWithNotExistId()); + var (fact, factDto) = GetFactObjects(); + var request = GetRequest(factDto); - var expectedError = "Cannot convert null to Fact"; - this.mockLocalizerConvertNull.Setup(x => x["CannotConvertNullToFact"]) - .Returns(new LocalizedString("CannotConvertNullToFact", expectedError)); - - var handler = new UpdateFactHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerFailedToUpdate.Object, this.mockLocalizerConvertNull.Object); + SetupMockUpdateAndSaveChangesAsync(fact, 1); + MockHelpers.SetupMockMapper(_mockMapper, fact, request.Fact); // Act - var result = await handler.Handle(new UpdateFactCommand(GetFactDTOWithNotExistId() !), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.Equal(expectedError, result.Errors[0].Message); + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType(); } [Fact] - public async Task ShouldThrowExeption_SaveChangesAsyncIsNotSuccessful() + public async Task ShouldUpdateFailingly_WhenMappingFailed() { // Arrange - this.mockRepository.Setup(x => x.FactRepository.Update(GetFact())); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(-1); - - this.mockMapper.Setup(x => x.Map(It.IsAny())) - .Returns(GetFact()); + var (_, factDto) = GetFactObjects(); + var request = GetRequest(factDto); + var expectedErrorMessage = _mockCannotConvertNullLocalizer["CannotConvertNullToFact"].Value; - var expectedError = "Failed to update a fact"; - this.mockLocalizerFailedToUpdate.Setup(x => x["FailedToUpdateFact"]) - .Returns(new LocalizedString("FailedToUpdateFact", expectedError)); - - var handler = new UpdateFactHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerFailedToUpdate.Object, this.mockLocalizerConvertNull.Object); + MockHelpers.SetupMockMapper(_mockMapper, null, request.Fact); // Act - var result = await handler.Handle(new UpdateFactCommand(GetFactDTO()), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.Equal(expectedError, result.Errors[0].Message); + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); } [Fact] - public async Task ShouldReturnSuccessfully_TypeIsCorrect() + public async Task ShouldUpdateFailingly_WhenSaveChangesAsyncFailed() { // Arrange - this.mockRepository.Setup(x => x.FactRepository.Create(GetFact())); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(1); - - this.mockMapper.Setup(x => x.Map(It.IsAny())) - .Returns(GetFact()); + var (fact, factDto) = GetFactObjects(); + var request = GetRequest(factDto); + var expectedErrorMessage = _mockFailedToUpdateLocalizer["FailedToUpdateFact"].Value; - var handler = new UpdateFactHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerFailedToUpdate.Object, this.mockLocalizerConvertNull.Object); + SetupMockUpdateAndSaveChangesAsync(fact, -1); + MockHelpers.SetupMockMapper(_mockMapper, fact, request.Fact); // Act - var result = await handler.Handle(new UpdateFactCommand(GetFactDTO()), CancellationToken.None); + var result = await _handler.Handle(request, CancellationToken.None); // Assert - Assert.IsType(result.Value); + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); } - private static Fact GetFact() + private static (Fact, StreetcodeFactUpdateDTO) GetFactObjects() { - return new Fact(); - } + var fact = new Fact(); + var factDto = new StreetcodeFactUpdateDTO(); - private static FactDto GetFactDTO() - { - return new FactDto(); + return (fact, factDto); } - private static Fact? GetFactWithNotExistId() + private static UpdateFactCommand GetRequest(StreetcodeFactUpdateDTO factDto) { - return null; + return new UpdateFactCommand(factDto); } - private static FactDto? GetFactDTOWithNotExistId() + private void SetupMockUpdateAndSaveChangesAsync(Fact fact, int saveChangesResult) { - return null; + _mockRepository + .Setup(x => x.FactRepository.Update(fact)); + _mockRepository + .Setup(x => x.SaveChangesAsync()) + .ReturnsAsync(saveChangesResult); } } diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedFigure/CreateRelatedFigureHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedFigure/CreateRelatedFigureHandlerTests.cs new file mode 100644 index 000000000..e0e9d55c7 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedFigure/CreateRelatedFigureHandlerTests.cs @@ -0,0 +1,186 @@ +using System.Linq.Expressions; +using Moq; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.RelatedFigure.Create; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; +using RelatedFigureEntity = Streetcode.DAL.Entities.Streetcode.RelatedFigure; + +namespace Streetcode.XUnitTest.MediatRTests.Streetcode.RelatedFigure; + +public class CreateRelatedFigureHandlerTests +{ + private readonly Mock _repositoryMock; + private readonly Mock _loggerMock; + private readonly MockNoSharedResourceLocalizer _mockNoShared; + private readonly MockFailedToCreateLocalizer _mockFailedToCreateLocalizer; + private readonly CreateRelatedFigureHandler _handler; + + public CreateRelatedFigureHandlerTests() + { + _repositoryMock = new Mock(); + _loggerMock = new Mock(); + _mockNoShared = new MockNoSharedResourceLocalizer(); + _mockFailedToCreateLocalizer = new MockFailedToCreateLocalizer(); + + _handler = new CreateRelatedFigureHandler( + _repositoryMock.Object, + _loggerMock.Object, + _mockNoShared, + _mockFailedToCreateLocalizer); + } + + [Fact] + public async Task Handle_WhenRelationCreatedSuccessfully_ReturnsSuccess() + { + // Arrange + var request = new CreateRelatedFigureCommand(1, 2); + SetupMocksForExistingStreetcodes(request.ObserverId, request.TargetId); + SetupMocksForNonExistingRelation(); + _repositoryMock.Setup(repo => repo.SaveChangesAsync()).ReturnsAsync(1); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + _repositoryMock.Verify( + repo => repo.RelatedFigureRepository.CreateAsync( + It.IsAny()), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenObserverStreetcodeDoesNotExist_ReturnsError() + { + // Arrange + var request = new CreateRelatedFigureCommand(1, 2); + SetupMocksForNonExistingStreetcode(request.ObserverId); + var expectedError = _mockNoShared["NoExistingStreetcodeWithId", request.ObserverId]; + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedError, result.Errors.Single().Message); + _loggerMock.Verify(logger => logger.LogError(request, expectedError), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenTargetStreetcodeDoesNotExist_ReturnsError() + { + // Arrange + var request = new CreateRelatedFigureCommand(1, 2); + SetupMocksForExistingStreetcodes(request.ObserverId); + SetupMocksForNonExistingStreetcode(request.TargetId); + var expectedError = _mockNoShared["NoExistingStreetcodeWithId", request.TargetId]; + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedError, result.Errors.Single().Message); + _loggerMock.Verify(logger => logger.LogError(request, expectedError), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenRelationAlreadyExists_ReturnsError() + { + // Arrange + var request = new CreateRelatedFigureCommand(1, 2); + SetupMocksForExistingStreetcodes(request.ObserverId, request.TargetId); + SetupMocksForExistingRelation(request.ObserverId, request.TargetId); + var expectedError = _mockFailedToCreateLocalizer["TheStreetcodesAreAlreadyLinked"]; + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedError, result.Errors.Single().Message); + _loggerMock.Verify(logger => logger.LogError(request, expectedError), Times.Once); + _repositoryMock.Verify( + repo => repo.RelatedFigureRepository.Create( + It.IsAny()), Times.Never); + }); + } + + [Fact] + public async Task Handle_WhenSavingFails_ReturnsError() + { + // Arrange + var request = new CreateRelatedFigureCommand(1, 2); + SetupMocksForExistingStreetcodes(request.ObserverId, request.TargetId); + SetupMocksForNonExistingRelation(); + _repositoryMock.Setup(repo => repo.SaveChangesAsync()).ReturnsAsync(0); + var expectedError = _mockFailedToCreateLocalizer["FailedToCreateRelation"]; + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedError, result.Errors.Single().Message); + _loggerMock.Verify(logger => logger.LogError(request, expectedError), Times.Once); + }); + } + + private void SetupMocksForExistingStreetcodes(params int[] streetcodeIds) + { + foreach (var id in streetcodeIds) + { + _repositoryMock + .Setup(repo => repo.StreetcodeRepository + .GetFirstOrDefaultAsync( + It.Is>>(expr => expr + .Compile() + .Invoke(new StreetcodeContent { Id = id })), null)) + .ReturnsAsync(new StreetcodeContent { Id = id }); + } + } + + private void SetupMocksForNonExistingStreetcode(int streetcodeId) + { + _repositoryMock + .Setup(repo => repo.StreetcodeRepository + .GetFirstOrDefaultAsync( + It.Is>>(expr => expr + .Compile() + .Invoke(new StreetcodeContent { Id = streetcodeId })), null)) + .ReturnsAsync((StreetcodeContent)null!); + } + + private void SetupMocksForExistingRelation(int observerId, int targetId) + { + _repositoryMock + .Setup(repo => repo.RelatedFigureRepository. + GetFirstOrDefaultAsync(It.IsAny>>(), null)) + .ReturnsAsync(new RelatedFigureEntity { ObserverId = observerId, TargetId = targetId }); + } + + private void SetupMocksForNonExistingRelation() + { + _repositoryMock + .Setup(repo => repo.RelatedFigureRepository + .GetFirstOrDefaultAsync( + It.IsAny>>(), null)) + .ReturnsAsync((RelatedFigureEntity)null!); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedFigure/DeleteRelatedFigureHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedFigure/DeleteRelatedFigureHandlerTests.cs new file mode 100644 index 000000000..cffccc1df --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedFigure/DeleteRelatedFigureHandlerTests.cs @@ -0,0 +1,120 @@ +using System.Linq.Expressions; +using Moq; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.RelatedFigure.Delete; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; +using Entity = Streetcode.DAL.Entities.Streetcode.RelatedFigure; + +namespace Streetcode.XUnitTest.MediatRTests.Streetcode.RelatedFigure; + +public class DeleteRelatedFigureHandlerTests +{ + private readonly Mock _repositoryMock; + private readonly Mock _loggerMock; + private readonly MockCannotFindLocalizer _mockCannotFindLocalizer; + private readonly MockFailedToDeleteLocalizer _mockFailedToDeleteLocalizer; + private readonly DeleteRelatedFigureHandler _handler; + + public DeleteRelatedFigureHandlerTests() + { + _repositoryMock = new Mock(); + _loggerMock = new Mock(); + _mockCannotFindLocalizer = new MockCannotFindLocalizer(); + _mockFailedToDeleteLocalizer = new MockFailedToDeleteLocalizer(); + + _handler = new DeleteRelatedFigureHandler( + _repositoryMock.Object, + _loggerMock.Object, + _mockFailedToDeleteLocalizer, + _mockCannotFindLocalizer); + } + + [Fact] + public async Task Handle_WhenRelationExists_DeletesRelationAndReturnsSuccess() + { + // Arrange + const int observerId = 1; + const int targetId = 2; + var relation = new Entity { ObserverId = observerId, TargetId = targetId }; + + SetupMocksForHandler(relation, 1); + + var command = new DeleteRelatedFigureCommand(observerId, targetId); + + // Act + var result = await _handler.Handle(command, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + _repositoryMock.Verify(repo => repo.RelatedFigureRepository.Delete(relation), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenRelationDoesNotExist_ReturnsError() + { + // Arrange + const int observerId = 1; + const int targetId = 2; + string expectedErrorMessage = _mockCannotFindLocalizer["CannotFindRelationBetweenStreetcodesWithCorrespondingIds", observerId, targetId]; + + SetupMocksForHandler(null, 0); + + var command = new DeleteRelatedFigureCommand(observerId, targetId); + + // Act + var result = await _handler.Handle(command, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorMessage, result.Errors.Single().Message); + _loggerMock.Verify(logger => logger.LogError(command, expectedErrorMessage), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Never); + }); + } + + [Fact] + public async Task Handle_WhenSaveChangesFails_ReturnsError() + { + // Arrange + const int observerId = 1; + const int targetId = 2; + var relation = new Entity { ObserverId = observerId, TargetId = targetId }; + string expectedErrorMessage = _mockFailedToDeleteLocalizer["FailedToDeleteRelation"]; + + SetupMocksForHandler(relation, 0); + + var command = new DeleteRelatedFigureCommand(observerId, targetId); + + // Act + var result = await _handler.Handle(command, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorMessage, result.Errors.Single().Message); + _loggerMock.Verify(logger => logger.LogError(command, expectedErrorMessage), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Once); + }); + } + + private void SetupMocksForHandler(Entity? relation, int saveChangesResult) + { + _repositoryMock + .Setup(repo => repo.RelatedFigureRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), null)) + .ReturnsAsync(relation); + + _repositoryMock + .Setup(repo => repo.SaveChangesAsync()) + .ReturnsAsync(saveChangesResult); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedFigure/GetRelatedFiguresByStreetcodeIdHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedFigure/GetRelatedFiguresByStreetcodeIdHandlerTests.cs index e7d3dd3b3..0e3686c4f 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedFigure/GetRelatedFiguresByStreetcodeIdHandlerTests.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedFigure/GetRelatedFiguresByStreetcodeIdHandlerTests.cs @@ -1,210 +1,205 @@ using System.Linq.Expressions; using AutoMapper; -using FluentResults; using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; using Moq; using Streetcode.BLL.DTO.Streetcode.RelatedFigure; -using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Streetcode.RelatedFigure.GetByStreetcodeId; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Media.Images; using Streetcode.DAL.Entities.Streetcode; -using Streetcode.DAL.Entities.Streetcode.Types; +using Streetcode.DAL.Enums; using Streetcode.DAL.Repositories.Interfaces.Base; using Xunit; using Entities = Streetcode.DAL.Entities.Streetcode; -namespace Streetcode.XUnitTest.MediatRTests.Streetcode.RelatedFigure +namespace Streetcode.XUnitTest.MediatRTests.Streetcode.RelatedFigure; + +public class GetRelatedFiguresByStreetcodeIdHandlerTests { - public class GetRelatedFiguresByStreetcodeIdHandlerTests + private readonly Mock _mapperMock; + private readonly Mock _repositoryMock; + private readonly Mock _loggerMock; + private readonly GetRelatedFiguresByStreetcodeIdHandler _handler; + + public GetRelatedFiguresByStreetcodeIdHandlerTests() { - private readonly Mock repository; - private readonly Mock mapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotFind; + _mapperMock = new Mock(); + _repositoryMock = new Mock(); + _loggerMock = new Mock(); + + _handler = new GetRelatedFiguresByStreetcodeIdHandler( + _mapperMock.Object, + _repositoryMock.Object, + _loggerMock.Object); + } - public GetRelatedFiguresByStreetcodeIdHandlerTests() - { - this.repository = new Mock(); - this.mapper = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerCannotFind = new Mock>(); - } - - [Theory] - [InlineData(1)] - public async Task Handle_ExistingId_ReturnsSuccess(int id) + [Fact] + public async Task Handle_WhenRelatedFiguresExist_ReturnsMappedResults() + { + // Arrange + var relatedFigureIds = new List { 1, 2 }; + var streetcodes = new List { - // Arrange - var testRelatedList = new List() - { - new Entities.RelatedFigure(), - }; + new () { Id = 1, Status = StreetcodeStatus.Published }, + new () { Id = 2, Status = StreetcodeStatus.Published }, + }; - var testPersonStreetcodeList = new List() - { - new PersonStreetcode(), - }; + SetupMocksForRelatedFigures(relatedFigureIds, streetcodes); - var testRelatedDTOList = new List() - { - new RelatedFigureDTO(), - }; + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((IEnumerable src) => src.Select(s => new RelatedFigureDTO { Id = s.Id })); - this.RepositorySetup(testRelatedList.AsQueryable(), new List()); + var request = new GetRelatedFigureByStreetcodeIdQuery(1); - this.repository.Setup(x => x.StreetcodeRepository.GetAllAsync( - It.IsAny>?>(), - It.IsAny, IIncludableQueryable>?>())) - .ReturnsAsync(testPersonStreetcodeList); + // Act + var result = await _handler.Handle(request, CancellationToken.None); - this.mapper.Setup(x => x.Map>(It.IsAny>())) - .Returns(testRelatedDTOList); + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.NotNull(result.Value); + Assert.Equal(2, result.Value.Count()); + Assert.Contains(result.Value, dto => dto.Id == 1); + Assert.Contains(result.Value, dto => dto.Id == 2); + }); + } - var handler = new GetRelatedFiguresByStreetcodeIdHandler(this.mapper.Object, this.repository.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + [Fact] + public async Task Handle_WhenNoRelatedFiguresExist_ReturnsEmptyResult() + { + // Arrange + SetupMocksForRelatedFigures(new List(), new List()); + var request = new GetRelatedFigureByStreetcodeIdQuery(1); - // Act - var result = await handler.Handle(new GetRelatedFigureByStreetcodeIdQuery(id), CancellationToken.None); + // Act + var result = await _handler.Handle(request, CancellationToken.None); - // Assert - Assert.Multiple( - () => Assert.NotNull(result), - () => Assert.NotEmpty(result.Value)); - } + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.NotNull(result.Value); + Assert.Empty(result.Value); + _loggerMock.Verify(logger => logger.LogInformation("Returning empty enumerable of related figures"), Times.Once); + }); + } - [Theory] - [InlineData(1)] - public async Task Handle_ReturnsCorrectType(int id) + [Fact] + public async Task Handle_WhenAllRelatedStreetcodesAreNotPublished_ReturnsEmptyResult() + { + // Arrange + var relatedFigureIds = new List { 1, 2 }; + var streetcodes = new List { - // Arrange - var testStreetcodeContentList = new List() - { - new StreetcodeContent(), - }; + new () { Id = 1, Status = StreetcodeStatus.Draft }, + new () { Id = 2, Status = StreetcodeStatus.Deleted }, + }; - var testRelatedFigureList = new List() - { - new Entities.RelatedFigure(), - }; + SetupMocksForRelatedFigures(relatedFigureIds, streetcodes); + var request = new GetRelatedFigureByStreetcodeIdQuery(1); - var testRelatedDTO = new RelatedFigureDTO() { Id = id }; + // Act + var result = await _handler.Handle(request, CancellationToken.None); - this.repository.Setup(x => x.StreetcodeRepository - .GetAllAsync(It.IsAny>?>(), It.IsAny, IIncludableQueryable>?>())) - .ReturnsAsync(testStreetcodeContentList.AsQueryable()); + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.NotNull(result.Value); + Assert.Empty(result.Value); + }); + } - this.RepositorySetup(testRelatedFigureList.AsQueryable(), testStreetcodeContentList); - this.MapperSetup(testRelatedDTO); + [Fact] + public async Task Handle_WhenExceptionOccurs_ReturnsEmptyResult() + { + // Arrange + _repositoryMock + .Setup(repo => repo.RelatedFigureRepository.FindAll(It.IsAny>>(), null)) + .Throws(new ArgumentNullException()); - var handler = new GetRelatedFiguresByStreetcodeIdHandler(this.mapper.Object, this.repository.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + var request = new GetRelatedFigureByStreetcodeIdQuery(1); - // Act - var result = await handler.Handle(new GetRelatedFigureByStreetcodeIdQuery(id), CancellationToken.None); + // Act + var result = await _handler.Handle(request, CancellationToken.None); - // Assert - Assert.IsAssignableFrom>(result.Value); - } + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.Empty(result.Value!); + }); + } - [Theory] - [InlineData(2)] - public async Task Handle_NonExisting_ReturnsGetAllNull(int id) + [Fact] + public async Task Handle_WhenStreetcodesHaveImages_OrdersImagesByAlt() + { + // Arrange + var relatedFigureIds = new List { 1 }; + var streetcodes = new List { - // Arrange - var testRelatedFigureEmptyList = new List() - { - new Entities.RelatedFigure(), - }; - var testRelatedDTO = new RelatedFigureDTO() { Id = id }; - string expectedErrorMessage = $"Cannot find any related figures by a streetcode id: {id}"; - this.mockLocalizerCannotFind.Setup(x => x[It.IsAny(), It.IsAny()]).Returns((string key, object[] args) => + new () { - if (args != null && args.Length > 0 && args[0] is int id) + Id = 1, + Status = StreetcodeStatus.Published, + Images = new List { - return new LocalizedString(key, $"Cannot find any related figures by a streetcode id: {id}"); - } - - return new LocalizedString(key, "Cannot find any related figures with unknown id"); - }); - - this.RepositorySetup(testRelatedFigureEmptyList.AsQueryable(), new List()); - this.MapperSetup(testRelatedDTO); - - var handler = new GetRelatedFiguresByStreetcodeIdHandler(this.mapper.Object, this.repository.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); - - // Act - var result = await handler.Handle(new GetRelatedFigureByStreetcodeIdQuery(id), CancellationToken.None); - - // Assert - Assert.Equal(expectedErrorMessage, result.Errors.Single().Message); - } + new () { ImageDetails = new ImageDetails { Alt = "0" } }, + new () { ImageDetails = new ImageDetails { Alt = "1" } }, + }, + }, + }; - [Theory] - [InlineData(2)] - public async Task Handle_NonExisting_ReturnsFindAllEmptyArray(int id) - { - // Arrange - this.RepositorySetup(Enumerable.Empty().AsQueryable(), new List()); + SetupMocksForRelatedFigures(relatedFigureIds, streetcodes); - var handler = new GetRelatedFiguresByStreetcodeIdHandler(this.mapper.Object, this.repository.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns(( + IEnumerable src) => src.Select(s => new RelatedFigureDTO { Id = s.Id })); - // Act - var result = await handler.Handle(new GetRelatedFigureByStreetcodeIdQuery(id), CancellationToken.None); + var request = new GetRelatedFigureByStreetcodeIdQuery(1); - // Assert - Assert.Multiple( - () => Assert.IsType>>(result), - () => Assert.IsAssignableFrom>(result.Value), - () => Assert.Empty(result.Value)); - } + // Act + var result = await _handler.Handle(request, CancellationToken.None); - [Fact] - public void Handle_OrdersImagesByAlt() + // Assert + Assert.Multiple(() => { - // Arrange - var relatedFigures = new List - { - new StreetcodeContent - { - Images = new List - { - new Image { ImageDetails = new ImageDetails { Alt = "B" } }, - new Image { ImageDetails = new ImageDetails { Alt = "A" } }, - }, - }, - }; + Assert.True(result.IsSuccess); + Assert.NotNull(result.Value); + Assert.Equal(1, result.Value.First().Id); + Assert.Equal("0", streetcodes.First().Images[0].ImageDetails?.Alt); + Assert.Equal("1", streetcodes.First().Images[1].ImageDetails?.Alt); + }); + } - // Act - foreach (StreetcodeContent streetcode in relatedFigures) + private void SetupMocksForRelatedFigures( + IEnumerable relatedFigureIds, + IEnumerable streetcodes) + { + _repositoryMock + .Setup(repo => repo.RelatedFigureRepository.FindAll( + It.IsAny>>(), + It.IsAny, + IIncludableQueryable>>())) + .Returns(( + Expression> _, + Func, IIncludableQueryable> + include) => { - if (streetcode.Images != null) - { - streetcode.Images = streetcode.Images.OrderBy(img => img.ImageDetails?.Alt).ToList(); - } - } - - // Assert - Assert.Equal("A", relatedFigures[0].Images[0].ImageDetails?.Alt); - Assert.Equal("B", relatedFigures[0].Images[1].ImageDetails?.Alt); - } + var queryableData = relatedFigureIds + .Select(id => new Entities.RelatedFigure { ObserverId = id, TargetId = id }) + .AsQueryable(); - private void MapperSetup(RelatedFigureDTO relatedFigureDTO) - { - this.mapper.Setup(x => x.Map(It.IsAny())) - .Returns(relatedFigureDTO); - } + return include != null ? include(queryableData) : queryableData; + }); - private void RepositorySetup(IQueryable relatedFigures, List streetcodeContents) - { - this.repository.Setup(x => x.RelatedFigureRepository - .FindAll(It.IsAny>?>(), null)) - .Returns(relatedFigures); - - this.repository.Setup(x => x.StreetcodeRepository.GetAllAsync( - It.IsAny>?>(), - It.IsAny, IIncludableQueryable>?>())) - .ReturnsAsync(streetcodeContents); - } + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(streetcodes); } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedFigure/GetRelatedFiguresByTagIdHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedFigure/GetRelatedFiguresByTagIdHandlerTests.cs new file mode 100644 index 000000000..771d453da --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedFigure/GetRelatedFiguresByTagIdHandlerTests.cs @@ -0,0 +1,137 @@ +using System.Linq.Expressions; +using AutoMapper; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.DTO.Streetcode.RelatedFigure; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.RelatedFigure.GetByTagId; +using Streetcode.DAL.Entities.AdditionalContent; +using Streetcode.DAL.Entities.Media.Images; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Enums; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Streetcode.RelatedFigure; + +public class GetRelatedFiguresByTagIdHandlerTests +{ + private readonly Mock _repositoryMock; + private readonly Mock _mapperMock; + private readonly Mock _loggerMock; + private readonly GetRelatedFiguresByTagIdHandler _handler; + + public GetRelatedFiguresByTagIdHandlerTests() + { + _repositoryMock = new Mock(); + _mapperMock = new Mock(); + _loggerMock = new Mock(); + + _handler = new GetRelatedFiguresByTagIdHandler( + _repositoryMock.Object, + _mapperMock.Object, + _loggerMock.Object); + } + + [Fact] + public async Task Handle_WhenStreetcodesExist_ReturnsMappedResults() + { + // Arrange + var request = new GetRelatedFiguresByTagIdQuery(1); + var testStreetcodes = GetTestStreetcodes(3, request.TagId); + + SetupMocksForStreetcodes(testStreetcodes); + + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((IEnumerable src) => src.Select(sc => new RelatedFigureDTO { Id = sc.Id }).ToList()); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.NotEmpty(result.Value); + Assert.Equal(testStreetcodes.Count, result.Value.Count()); + }); + } + + [Fact] + public async Task Handle_WhenNoStreetcodesExist_ReturnsEmptyResult() + { + // Arrange + var request = new GetRelatedFiguresByTagIdQuery(99); + SetupMocksForStreetcodes(new List()); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.Empty(result.Value); + _loggerMock.Verify(logger => logger.LogInformation("Returning empty enumerable of related figures"), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenFilteringImages_OnlyBlackAndWhiteAreKept() + { + // Arrange + var request = new GetRelatedFiguresByTagIdQuery(1); + var testStreetcodes = GetTestStreetcodes(3, request.TagId); + + SetupMocksForStreetcodes(testStreetcodes); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + Assert.All(testStreetcodes, streetcode => + { + Assert.All(streetcode.Images, img => + { + Assert.Equal(((int)ImageAssigment.Blackandwhite).ToString(), img.ImageDetails?.Alt); + }); + }); + } + + private static List GetTestStreetcodes(int count, int tagId) + { + return Enumerable.Range(1, count).Select(i => new StreetcodeContent + { + Id = i, + Status = StreetcodeStatus.Published, + Tags = new List + { + new () + { + Id = tagId, + }, + }, + Images = new List + { + new () + { + ImageDetails = new ImageDetails + { + Alt = ((int)ImageAssigment.Blackandwhite).ToString(), + }, + }, + }, + }).ToList(); + } + + private void SetupMocksForStreetcodes(IEnumerable streetcodes) + { + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(streetcodes); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerm/Create/CreateRelatedTermHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerm/Create/CreateRelatedTermHandlerTests.cs deleted file mode 100644 index e20001458..000000000 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerm/Create/CreateRelatedTermHandlerTests.cs +++ /dev/null @@ -1,181 +0,0 @@ -using System.Linq.Expressions; -using AutoMapper; -using FluentAssertions; -using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; -using Moq; -using Streetcode.BLL.DTO.Streetcode.TextContent; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Create; -using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Entities.Streetcode.TextContent; -using Streetcode.DAL.Repositories.Interfaces.Base; -using Xunit; -using Entity = Streetcode.DAL.Entities.Streetcode.TextContent.RelatedTerm; - -namespace Streetcode.XUnitTest.MediatRTests.StreetCode.RelatedTerm.Create -{ - public class CreateRelatedTermHandlerTests - { - private readonly Mock repositoryWrapperMock; - private readonly Mock mapperMock; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotCreate; - private readonly Mock> mockLocalizerCannotMap; - private readonly Mock> mockLocalizer; - private readonly Mock> mockLocalizerCannotSave; - - public CreateRelatedTermHandlerTests() - { - this.repositoryWrapperMock = new Mock(); - this.mapperMock = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizer = new Mock>(); - this.mockLocalizerCannotCreate = new Mock>(); - this.mockLocalizerCannotMap = new Mock>(); - this.mockLocalizerCannotSave = new Mock>(); - } - - [Theory] - [InlineData(2, "example")] - public async Task ShouldReturnSuccessfully_WhenRelatedTermAdded(int termId, string word) - { - // Arrange - var (relatedTermDTO, entity) = this.CreateRelatedTermObjects(termId, word); - var createRelatedTermCommand = new CreateRelatedTermCommand(relatedTermDTO); - - this.repositoryWrapperMock.Setup(r => r.RelatedTermRepository.Create(entity)); - this.repositoryWrapperMock.Setup(r => r.SaveChangesAsync()).ReturnsAsync(1); - this.SetupMapperMockToMapEntity(entity); - this.SetupLocalizers(); - - var handler = new CreateRelatedTermHandler(this.repositoryWrapperMock.Object, this.mapperMock.Object, this.mockLogger.Object, this.mockLocalizerCannotSave.Object, this.mockLocalizerCannotMap.Object, this.mockLocalizer.Object, this.mockLocalizerCannotCreate.Object); - - // Act - var result = await handler.Handle(createRelatedTermCommand, CancellationToken.None); - - // Assert - result.IsSuccess.Should().BeFalse(); - this.repositoryWrapperMock.Verify(r => r.RelatedTermRepository.Create(entity), Times.Once); - this.repositoryWrapperMock.Verify(r => r.SaveChangesAsync(), Times.Once); - } - - [Fact] - public async Task Handle_Should_Return_Error_When_Related_Term_Is_Null() - { - // Arrange - this.SetupMapperMockToMapEntity(null); - var handler = new CreateRelatedTermHandler(this.repositoryWrapperMock.Object, this.mapperMock.Object, this.mockLogger.Object, this.mockLocalizerCannotSave.Object, this.mockLocalizerCannotMap.Object, this.mockLocalizer.Object, this.mockLocalizerCannotCreate.Object); - var command = new CreateRelatedTermCommand(new RelatedTermCreateDTO()); - this.SetupLocalizers(); - - // Act - var result = await handler.Handle(command, CancellationToken.None); - - // Assert - Assert.True(result.IsFailed); - Assert.False(result.IsSuccess); - } - - [Theory] - [InlineData(1, "test")] - public async Task Handle_Should_Return_Error_When_Related_Term_Already_Exists(int termId, string word) - { - // Arrange - var (relatedTermDTO, entity) = this.CreateRelatedTermObjects(termId, word); - var existingTerms = new List { entity }; - - this.SetupMapperMockToMapEntity(entity); - this.SetupGetAllAsyncWithExistingTerms(existingTerms); - this.SetupLocalizers(); - - var handler = new CreateRelatedTermHandler(this.repositoryWrapperMock.Object, this.mapperMock.Object, this.mockLogger.Object, this.mockLocalizerCannotSave.Object, this.mockLocalizerCannotMap.Object, this.mockLocalizer.Object, this.mockLocalizerCannotCreate.Object); - var command = new CreateRelatedTermCommand(relatedTermDTO); - - // Act - var result = await handler.Handle(command, CancellationToken.None); - - // Assert - Assert.True(result.IsFailed); - Assert.False(result.IsSuccess); - this.VerifyCreateAndSaveChangesNever(); - } - - [Theory] - [InlineData(1, "test")] - public async Task Handle_Should_Return_Error_When_SaveChangesAsync_Fails(int termId, string word) - { - // Arrange - var (relatedTermDTO, entity) = this.CreateRelatedTermObjects(termId, word); - var existingTerms = new List(); - var repositoryMock = new Mock(); - var mapperMock = new Mock(); - - mapperMock.Setup(m => m.Map(It.IsAny())).Returns(entity); - this.SetupGetAllAsyncWithExistingTerms(existingTerms); - - repositoryMock.Setup(r => r.RelatedTermRepository.Create(It.IsAny())); - repositoryMock.Setup(r => r.SaveChangesAsync()).ReturnsAsync(0); - this.SetupLocalizers(); - - var handler = new CreateRelatedTermHandler(repositoryMock.Object, mapperMock.Object, this.mockLogger.Object, this.mockLocalizerCannotSave.Object, this.mockLocalizerCannotMap.Object, this.mockLocalizer.Object, this.mockLocalizerCannotCreate.Object); - var command = new CreateRelatedTermCommand(relatedTermDTO); - - // Act - var result = await handler.Handle(command, CancellationToken.None); - - // Assert - Assert.True(result.IsFailed); - Assert.False(result.IsSuccess); - } - - private void SetupLocalizers() - { - // Setup for _mockLocalizer - this.mockLocalizer.Setup(x => x[It.IsAny()]) - .Returns((string key) => new LocalizedString(key, $"Word with this definition already exists")); - - // Setup for _mockLocalizerCannotCreate - this.mockLocalizerCannotCreate.Setup(x => x[It.IsAny()]) - .Returns((string key) => new LocalizedString(key, $"Cannot create new related word for a term")); - - // Setup for _mockLocalizerCannotMap - this.mockLocalizerCannotMap.Setup(x => x[It.IsAny()]) - .Returns((string key) => new LocalizedString(key, $"Cannot map entity")); - - // Setup for _mockLocalizerCannotSave - this.mockLocalizerCannotSave.Setup(x => x[It.IsAny()]) - .Returns((string key) => new LocalizedString(key, $"Cannot save changes in the database after related word creation")); - } - - private (RelatedTermCreateDTO relatedTermDTO, Entity entity) CreateRelatedTermObjects(int termId, string word) - { - var relatedTermDTO = new RelatedTermCreateDTO { TermId = termId, Word = word }; - var entity = new Entity { TermId = relatedTermDTO.TermId, Word = relatedTermDTO.Word }; - - return (relatedTermDTO, entity); - } - - private void SetupMapperMockToMapEntity(Entity? entity) - { - this.mapperMock.Setup(m => m.Map(It.IsAny())).Returns(entity); - } - - private void SetupGetAllAsyncWithExistingTerms(List existingTerms) - { - this.repositoryWrapperMock - .Setup(r => r.RelatedTermRepository - .GetAllAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(existingTerms); - } - - private void VerifyCreateAndSaveChangesNever() - { - this.repositoryWrapperMock.Verify(r => r.RelatedTermRepository.Create(It.IsAny()), Times.Never); - this.repositoryWrapperMock.Verify(r => r.SaveChangesAsync(), Times.Never); - } - } -} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerm/Delete/DeleteRelatedTermHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerm/Delete/DeleteRelatedTermHandlerTests.cs deleted file mode 100644 index fdd601bbf..000000000 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerm/Delete/DeleteRelatedTermHandlerTests.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System.Linq.Expressions; -using AutoMapper; -using FluentResults; -using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; -using Moq; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Delete; -using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Repositories.Interfaces.Base; -using Xunit; -using Entity = Streetcode.DAL.Entities.Streetcode.TextContent.RelatedTerm; -using EntityDTO = Streetcode.BLL.DTO.Streetcode.TextContent.RelatedTermDTO; - -namespace Streetcode.XUnitTest.MediatRTests.StreetCode.RelatedTerm.Delete -{ - public class DeleteRelatedTermHandlerTests - { - private readonly Mock repositoryWrapperMock; - private readonly Mock mapperMock; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotFind; - private readonly Mock> mockLocalizerFailedToDelete; - - public DeleteRelatedTermHandlerTests() - { - this.repositoryWrapperMock = new Mock(); - this.mapperMock = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerCannotFind = new Mock>(); - this.mockLocalizerFailedToDelete = new Mock>(); - } - - [Theory] - [InlineData(1, "test", 1)] - public async Task Handle_WhenRelatedTermExists_DeletesItAndReturnsSuccessResult(int id, string word, int termId) - { - // Arrange - var relatedTerm = CreateNewEntity(id, word, termId); - this.repositoryWrapperMock - .Setup(r => r.RelatedTermRepository - .GetFirstOrDefaultAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(relatedTerm); - this.repositoryWrapperMock.Setup(r => r.RelatedTermRepository.Delete(relatedTerm)); - this.repositoryWrapperMock.Setup(x => x.SaveChangesAsync()).ReturnsAsync(1); - var handler = new DeleteRelatedTermHandler(this.repositoryWrapperMock.Object, this.mapperMock.Object, this.mockLogger.Object, this.mockLocalizerFailedToDelete.Object, this.mockLocalizerCannotFind.Object); - var command = new DeleteRelatedTermCommand(word); - this.SetupLocalizers(); - - // Act - var result = await handler.Handle(command, default); - - // Assert - this.repositoryWrapperMock.Verify(r => r.RelatedTermRepository.Delete(relatedTerm), Times.Once); - this.repositoryWrapperMock.Verify(r => r.SaveChangesAsync(), Times.Once); - Assert.Multiple( - () => Assert.NotNull(result)); - } - - [Theory] - [InlineData("word")] - public async Task Handle_WhenRelatedTermDoesNotExist_ReturnsFailedResult(string word) - { - // Arrange - this.repositoryWrapperMock - .Setup(r => r.RelatedTermRepository - .GetFirstOrDefaultAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync((Entity?)null); - var sut = new DeleteRelatedTermHandler(this.repositoryWrapperMock.Object, this.mapperMock.Object, this.mockLogger.Object, this.mockLocalizerFailedToDelete.Object, this.mockLocalizerCannotFind.Object); - var command = new DeleteRelatedTermCommand(word); - var expectedError = $"Cannot find a related term: {word}"; - this.SetupLocalizers(); - - // Act - var result = await sut.Handle(command, CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.IsType>(result), - () => Assert.False(result.IsSuccess), - () => Assert.Equal(expectedError, result.Errors[0].Message)); - } - - [Theory] - [InlineData(1, "Test Word", 1)] - public async Task Handle_WhenDeletionFails_ReturnsFailedResult(int id, string word, int termId) - { - // Arrange - var relatedTerm = CreateNewEntity(id, word, termId); - this.repositoryWrapperMock - .Setup(r => r.RelatedTermRepository - .GetFirstOrDefaultAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(relatedTerm); - this.repositoryWrapperMock.Setup(rw => rw.RelatedTermRepository.Delete(It.IsAny())); - this.repositoryWrapperMock.Setup(rw => rw.SaveChangesAsync()) - .ReturnsAsync(0); - var sut = new DeleteRelatedTermHandler(this.repositoryWrapperMock.Object, this.mapperMock.Object, this.mockLogger.Object, this.mockLocalizerFailedToDelete.Object, this.mockLocalizerCannotFind.Object); - var command = new DeleteRelatedTermCommand(word); - var expectedError = "Failed to delete a related term"; - this.SetupLocalizers(); - - // Act - var result = await sut.Handle(command, CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.IsType>(result), - () => Assert.False(result.IsSuccess), - () => Assert.Equal(expectedError, result.Errors[0].Message)); - } - - private static Entity CreateNewEntity(int id, string word, int termId) - { - return new Entity { Id = id, Word = word, TermId = termId }; - } - - private void SetupLocalizers() - { - // Setup for _mockLocalizerCannotFind - this.mockLocalizerCannotFind.Setup(x => x[It.IsAny(), It.IsAny()]) - .Returns((string key, object[] args) => - { - if (args != null && args.Length > 0 && args[0] is string word) - { - return new LocalizedString(key, $"Cannot find a related term: {word}"); - } - - return new LocalizedString(key, "Cannot find any related term with unknown word"); - }); - - // Setup for _mockLocalizerFailedToDelete - this.mockLocalizerFailedToDelete - .Setup(x => x["FailedToDeleteRelatedTerm"]) - .Returns(new LocalizedString("FailedToDeleteRelatedTerm", "Failed to delete a related term")); - } - } -} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerm/GetAllByTermId/GetAllRelatedTermsByTermIdHandlerTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerm/GetAllByTermId/GetAllRelatedTermsByTermIdHandlerTest.cs deleted file mode 100644 index d94428799..000000000 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerm/GetAllByTermId/GetAllRelatedTermsByTermIdHandlerTest.cs +++ /dev/null @@ -1,173 +0,0 @@ -using System.Linq.Expressions; -using AutoMapper; -using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; -using Moq; -using Streetcode.BLL.DTO.Streetcode.TextContent; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.MediatR.Streetcode.RelatedTerm.GetAllByTermId; -using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Entities.Team; -using Streetcode.DAL.Repositories.Interfaces.Base; -using Xunit; -using Entity = Streetcode.DAL.Entities.Streetcode.TextContent.RelatedTerm; - -namespace Streetcode.XUnitTest.MediatRTests.StreetCode.RelatedTerm.GetAllByTermId -{ - public class GetAllRelatedTermsByTermIdHandlerTest - { - private readonly Mock mockRepository; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotGet; - private readonly Mock> mockLocalizerCannotCreate; - - public GetAllRelatedTermsByTermIdHandlerTest() - { - this.mockRepository = new Mock(); - this.mockMapper = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerCannotCreate = new Mock>(); - this.mockLocalizerCannotGet = new Mock>(); - } - - [Theory] - [InlineData(1)] - public async Task Handle_ReturnsError_WhenRepositoryReturnsNull(int id) - { - // Arrange - var query = new GetAllRelatedTermsByTermIdQuery(id); - - this.mockRepository - .Setup(x => x.RelatedTermRepository - .GetAllAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(GetEntityListWithNotExistingId()); - - var handler = new GetAllRelatedTermsByTermIdHandler(this.mockMapper.Object, this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerCannotGet.Object, this.mockLocalizerCannotCreate.Object); - var expectedError = "Cannot get words by term id"; - this.mockLocalizerCannotGet.Setup(x => x["CannotGetWordsByTermId"]) - .Returns(new LocalizedString("CannotGetWordsByTermId", expectedError)); - - // Act - var result = await handler.Handle(query, CancellationToken.None); - - // Assert - Assert.Equal(expectedError, result.Errors[0].Message); - } - - [Theory] - [InlineData(1)] - public async Task Handle_ReturnsError_WhenMapperReturnsNull(int id) - { - // Arrange - var query = new GetAllRelatedTermsByTermIdQuery(id); - var relatedTerms = new List { new Entity() }; - - this.mockRepository - .Setup(x => x.RelatedTermRepository. - GetAllAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(relatedTerms); - this.mockMapper - .Setup(x => x.Map>(relatedTerms)) - .Returns(GetRelatedTermDTOListWithNotExistingId()); - - var handler = new GetAllRelatedTermsByTermIdHandler(this.mockMapper.Object, this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerCannotGet.Object, this.mockLocalizerCannotCreate.Object); - var expectedError = "Cannot create DTOs for related words!"; - this.mockLocalizerCannotCreate.Setup(x => x["CannotCreateDTOsForRelatedWords"]) - .Returns(new LocalizedString("CannotCreateDTOsForRelatedWords", expectedError)); - - // Act - var result = await handler.Handle(query, CancellationToken.None); - - // Assert - Assert.Equal(expectedError, result.Errors[0].Message); - } - - [Theory] - [InlineData(1)] - public async Task Handle_ReturnsOkResult_WhenAllInputsAreValid(int id) - { - // Arrange - var query = new GetAllRelatedTermsByTermIdQuery(id); - - var relatedTerms = new List { new Entity() }; - - var relatedTermDTOs = new List { new RelatedTermDTO() }; - - this.mockRepository - .Setup(x => x.RelatedTermRepository - .GetAllAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(relatedTerms); - this.mockMapper.Setup(x => x.Map>(relatedTerms)).Returns(relatedTermDTOs); - - var handler = new GetAllRelatedTermsByTermIdHandler(this.mockMapper.Object, this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerCannotGet.Object, this.mockLocalizerCannotCreate.Object); - - // Act - var result = await handler.Handle(query, CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.True(result.IsSuccess), - () => Assert.Equal(relatedTermDTOs, result.Value)); - } - - [Theory] - [InlineData(1, 1, "RelatedTerm1")] - public async Task Handle_WhenRelatedTermsFound_ReturnsSuccessResult(int id, int termId, string testWord) - { - // Arrange - var relatedTerm = CreateNewEntity(id, testWord, termId); - var relatedTerms = new List { relatedTerm }; - var relatedTermDTOs = new List { new RelatedTermDTO() }; - - this.mockMapper.Setup(x => x.Map>(relatedTerms)).Returns(relatedTermDTOs); - - this.mockRepository - .Setup(x => x.RelatedTermRepository - .GetAllAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(relatedTerms); - - var query = new GetAllRelatedTermsByTermIdQuery(termId); - var handler = new GetAllRelatedTermsByTermIdHandler(this.mockMapper.Object, this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerCannotGet.Object, this.mockLocalizerCannotCreate.Object); - - // Act - var result = await handler.Handle(query, CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.True(result.IsSuccess), - () => Assert.IsAssignableFrom>(result.Value), - () => Assert.Equal(relatedTermDTOs.Count, result.Value.Count()), - () => Assert.Equal(relatedTermDTOs[0].Id, result.Value.First().Id), - () => Assert.Equal(relatedTermDTOs[0].TermId, result.Value.First().TermId), - () => Assert.Equal(relatedTermDTOs[0].Word, result.Value.First().Word)); - } - - private static List GetEntityListWithNotExistingId() - { - return null; - } - - private static List GetRelatedTermDTOListWithNotExistingId() - { - return null; - } - - private static Entity CreateNewEntity(int id, string word, int termId) - { - return new Entity { Id = id, Word = word, TermId = termId }; - } - } -} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerms/CreateRelatedTermTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerms/CreateRelatedTermTest.cs new file mode 100644 index 000000000..a1ccba237 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerms/CreateRelatedTermTest.cs @@ -0,0 +1,222 @@ +using AutoMapper; +using FluentAssertions; +using Moq; +using Streetcode.BLL.DTO.Streetcode.TextContent; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Create; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; +using RelatedTermEntity = Streetcode.DAL.Entities.Streetcode.TextContent.RelatedTerm; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.RelatedTerms; + +public class CreateRelatedTermTest +{ + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly MockCannotSaveLocalizer _mockCannotSaveLocalizer; + private readonly MockCannotMapLocalizer _mockCannotMapLocalizer; + private readonly MockCreateRelatedTermLocalizer _mockCreateRelatedTermLocalizer; + private readonly MockCannotCreateLocalizer _mockCannotCreateLocalizer; + private readonly CreateRelatedTermHandler _handler; + + public CreateRelatedTermTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockCannotSaveLocalizer = new MockCannotSaveLocalizer(); + _mockCannotMapLocalizer = new MockCannotMapLocalizer(); + _mockCreateRelatedTermLocalizer = new MockCreateRelatedTermLocalizer(); + _mockCannotCreateLocalizer = new MockCannotCreateLocalizer(); + _handler = new CreateRelatedTermHandler( + _mockRepository.Object, + _mockMapper.Object, + _mockLogger.Object, + _mockCannotSaveLocalizer, + _mockCannotMapLocalizer, + _mockCreateRelatedTermLocalizer, + _mockCannotCreateLocalizer); + } + + [Fact] + public async Task ShouldCreateSuccessfully_WhenRelatedTermAdded() + { + // Arrange + var (relatedTermCreateDto, relatedTerm, relatedTermDto) = GetRelatedTermObjects(); + var existingTermsList = GetEmptyRelatedTermList(); + var request = GetRequest(relatedTermCreateDto); + + MockHelpers.SetupMockRelatedTermRepositoryGetAllAsync(_mockRepository, existingTermsList); + SetupMockCreateAndSaveChangesAsync(relatedTerm, 1); + MockHelpers.SetupMockMapper(_mockMapper, relatedTerm, request.RelatedTerm); + MockHelpers.SetupMockMapper(_mockMapper, relatedTermDto, relatedTerm); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Word.Should().Be(relatedTerm.Word); + _mockRepository.Verify(r => r.RelatedTermRepository.CreateAsync(relatedTerm), Times.Once); + _mockRepository.Verify(r => r.SaveChangesAsync(), Times.Once); + _mockMapper.Verify(x => x.Map(relatedTerm), Times.Once); + } + + [Fact] + public async Task ShouldCreateSuccessfully_WithCorrectDataType() + { + // Arrange + var (relatedTermCreateDto, relatedTerm, relatedTermDto) = GetRelatedTermObjects(); + var existingTermsList = GetEmptyRelatedTermList(); + var request = GetRequest(relatedTermCreateDto); + + MockHelpers.SetupMockRelatedTermRepositoryGetAllAsync(_mockRepository, existingTermsList); + SetupMockCreateAndSaveChangesAsync(relatedTerm, 1); + MockHelpers.SetupMockMapper(_mockMapper, relatedTerm, request.RelatedTerm); + MockHelpers.SetupMockMapper(_mockMapper, relatedTermDto, relatedTerm); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType(); + } + + [Fact] + public async Task ShouldCreateFailingly_WhenFirstMappingFailed() + { + // Arrange + var (relatedTermCreateDto, _, _) = GetRelatedTermObjects(); + var request = GetRequest(relatedTermCreateDto); + var expectedErrorMessage = _mockCannotCreateLocalizer["CannotCreateNewRelatedWordForTerm"].Value; + + MockHelpers.SetupMockMapper(_mockMapper, null, request.RelatedTerm); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + [Fact] + public async Task ShouldCreateFailingly_WhenRelatedTermAlreadyExists() + { + // Arrange + var (relatedTermCreateDto, relatedTerm, _) = GetRelatedTermObjects(); + var existingTermsList = GetRelatedTermList(); + var request = GetRequest(relatedTermCreateDto); + var expectedErrorMessage = _mockCreateRelatedTermLocalizer["WordWithThisDefinitionAlreadyExists"].Value; + + MockHelpers.SetupMockRelatedTermRepositoryGetAllAsync(_mockRepository, existingTermsList); + MockHelpers.SetupMockMapper(_mockMapper, relatedTerm, request.RelatedTerm); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + [Fact] + public async Task ShouldCreateFailingly_WhenSaveChangesAsyncFailed() + { + // Arrange + var (relatedTermCreateDto, relatedTerm, _) = GetRelatedTermObjects(); + var existingTermsList = GetEmptyRelatedTermList(); + var request = GetRequest(relatedTermCreateDto); + var expectedErrorMessage = _mockCannotSaveLocalizer["CannotSaveChangesInTheDatabaseAfterRelatedWordCreation"].Value; + + MockHelpers.SetupMockRelatedTermRepositoryGetAllAsync(_mockRepository, existingTermsList); + SetupMockCreateAndSaveChangesAsync(relatedTerm, -1); + MockHelpers.SetupMockMapper(_mockMapper, relatedTerm, request.RelatedTerm); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + [Fact] + public async Task ShouldCreateFailingly_WhenSecondMappingFailed() + { + // Arrange + var (relatedTermCreateDto, relatedTerm, _) = GetRelatedTermObjects(); + var existingTermsList = GetEmptyRelatedTermList(); + var request = GetRequest(relatedTermCreateDto); + var expectedErrorMessage = _mockCannotMapLocalizer["CannotMapEntity"].Value; + + MockHelpers.SetupMockRelatedTermRepositoryGetAllAsync(_mockRepository, existingTermsList); + SetupMockCreateAndSaveChangesAsync(relatedTerm, 1); + MockHelpers.SetupMockMapper(_mockMapper, relatedTerm, request.RelatedTerm); + MockHelpers.SetupMockMapper(_mockMapper, null, relatedTerm); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + private static (RelatedTermCreateDTO, RelatedTermEntity, RelatedTermDTO) GetRelatedTermObjects() + { + const string word = "qwerty"; + + var relatedTermCreateDto = new RelatedTermCreateDTO() + { + Word = word, + }; + var relatedTerm = new RelatedTermEntity() + { + Word = word, + }; + var relatedTermDto = new RelatedTermDTO() + { + Word = word, + }; + + return (relatedTermCreateDto, relatedTerm, relatedTermDto); + } + + private static List GetRelatedTermList() + { + return new List() + { + new RelatedTermEntity(), + new RelatedTermEntity(), + }; + } + + private static List GetEmptyRelatedTermList() + { + return new List(); + } + + private static CreateRelatedTermCommand GetRequest(RelatedTermCreateDTO relatedTermDto) + { + return new CreateRelatedTermCommand(relatedTermDto); + } + + private void SetupMockCreateAndSaveChangesAsync(RelatedTermEntity relatedTerm, int saveChangesResult) + { + _mockRepository + .Setup(x => x.RelatedTermRepository.CreateAsync(relatedTerm)) + .ReturnsAsync(relatedTerm); + _mockRepository + .Setup(x => x.SaveChangesAsync()) + .ReturnsAsync(saveChangesResult); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerms/DeleteRelatedTermTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerms/DeleteRelatedTermTest.cs new file mode 100644 index 000000000..d38b13fe2 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerms/DeleteRelatedTermTest.cs @@ -0,0 +1,169 @@ +using AutoMapper; +using FluentAssertions; +using Moq; +using Streetcode.BLL.DTO.Streetcode.TextContent; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Delete; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; +using RelatedTermEntity = Streetcode.DAL.Entities.Streetcode.TextContent.RelatedTerm; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.RelatedTerms; + +public class DeleteRelatedTermTest +{ + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly MockFailedToDeleteLocalizer _mockFailedToDeleteLocalizer; + private readonly MockCannotFindLocalizer _mockCannotFindLocalizer; + private readonly DeleteRelatedTermHandler _handler; + + public DeleteRelatedTermTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockFailedToDeleteLocalizer = new MockFailedToDeleteLocalizer(); + _mockCannotFindLocalizer = new MockCannotFindLocalizer(); + _handler = new DeleteRelatedTermHandler( + _mockRepository.Object, + _mockMapper.Object, + _mockLogger.Object, + _mockFailedToDeleteLocalizer, + _mockCannotFindLocalizer); + } + + [Theory] + [InlineData("qwerty")] + public async Task ShouldDeleteSuccessfully_WhenRelatedTermExists(string word) + { + // Arrange + var (relatedTerm, relatedTermDto) = GetRelatedTermObjects(word); + var request = GetRequest(word); + + MockHelpers.SetupMockRelatedTermRepositoryGetFirstOrDefaultAsync(_mockRepository, relatedTerm); + SetupMockDeleteAndSaveChangesAsync(relatedTerm, 1); + MockHelpers.SetupMockMapper(_mockMapper, relatedTermDto, relatedTerm); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Word.Should().Be(word); + _mockRepository.Verify(x => x.RelatedTermRepository.Delete(relatedTerm), Times.Once); + _mockRepository.Verify(x => x.SaveChangesAsync(), Times.Once); + } + + [Theory] + [InlineData("qwerty")] + public async Task ShouldDeleteSuccessfully_WithCorrectDataType(string word) + { + // Arrange + var (relatedTerm, relatedTermDto) = GetRelatedTermObjects(word); + var request = GetRequest(word); + + MockHelpers.SetupMockRelatedTermRepositoryGetFirstOrDefaultAsync(_mockRepository, relatedTerm); + SetupMockDeleteAndSaveChangesAsync(relatedTerm, 1); + MockHelpers.SetupMockMapper(_mockMapper, relatedTermDto, relatedTerm); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType(); + } + + [Theory] + [InlineData("qwerty")] + public async Task ShouldDeleteFailingly_WhenRelatedTermNotExist(string word) + { + // Arrange + var request = GetRequest(word); + var expectedErrorMessage = _mockCannotFindLocalizer["CannotFindRelatedTermWithCorrespondingId", request.Word].Value; + + MockHelpers.SetupMockRelatedTermRepositoryGetFirstOrDefaultAsync(_mockRepository, null); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + [Theory] + [InlineData("qwerty")] + public async Task ShouldDeleteFailingly_WhenSaveChangesAsyncFailed(string word) + { + // Arrange + var (relatedTerm, _) = GetRelatedTermObjects(word); + var request = GetRequest(word); + var expectedErrorMessage = _mockFailedToDeleteLocalizer["FailedToDeleteRelatedTerm"].Value; + + MockHelpers.SetupMockRelatedTermRepositoryGetFirstOrDefaultAsync(_mockRepository, relatedTerm); + SetupMockDeleteAndSaveChangesAsync(relatedTerm, -1); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + [Theory] + [InlineData("qwerty")] + public async Task ShouldDeleteFailingly_WhenMappingFailed(string word) + { + // Arrange + var (relatedTerm, _) = GetRelatedTermObjects(word); + var request = GetRequest(word); + var expectedErrorMessage = _mockFailedToDeleteLocalizer["FailedToDeleteRelatedTerm"].Value; + + MockHelpers.SetupMockRelatedTermRepositoryGetFirstOrDefaultAsync(_mockRepository, relatedTerm); + SetupMockDeleteAndSaveChangesAsync(relatedTerm, 1); + MockHelpers.SetupMockMapper(_mockMapper, null, relatedTerm); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + private static (RelatedTermEntity, RelatedTermDTO) GetRelatedTermObjects(string word) + { + var relatedTerm = new RelatedTermEntity() + { + Word = word, + }; + var relatedTermDto = new RelatedTermDTO() + { + Word = word, + }; + + return (relatedTerm, relatedTermDto); + } + + private static DeleteRelatedTermCommand GetRequest(string word) + { + return new DeleteRelatedTermCommand(word); + } + + private void SetupMockDeleteAndSaveChangesAsync(RelatedTermEntity relatedTerm, int saveChangesResult) + { + _mockRepository + .Setup(x => x.RelatedTermRepository.Delete(relatedTerm)); + _mockRepository + .Setup(x => x.SaveChangesAsync()) + .ReturnsAsync(saveChangesResult); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerms/GetAllRelatedTermsByTermIdTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerms/GetAllRelatedTermsByTermIdTest.cs new file mode 100644 index 000000000..d705eb875 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/RelatedTerms/GetAllRelatedTermsByTermIdTest.cs @@ -0,0 +1,190 @@ +using AutoMapper; +using FluentAssertions; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.DTO.Streetcode.TextContent; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.RelatedTerm.GetAllByTermId; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; +using RelatedTermEntity = Streetcode.DAL.Entities.Streetcode.TextContent.RelatedTerm; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.RelatedTerms; + +public class GetAllRelatedTermsByTermIdTest +{ + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly MockCannotCreateLocalizer _mockCannotCreateLocalizer; + private readonly GetAllRelatedTermsByTermIdHandler _handler; + + public GetAllRelatedTermsByTermIdTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockCannotCreateLocalizer = new MockCannotCreateLocalizer(); + _handler = new GetAllRelatedTermsByTermIdHandler( + _mockMapper.Object, + _mockRepository.Object, + _mockLogger.Object, + _mockCannotCreateLocalizer); + } + + [Theory] + [InlineData(1)] + public async Task ShouldGetAllByTermIdSuccessfully_WhenRelatedTermsExist(int termId) + { + // Arrange + var (relatedTermsList, relatedTermDtoList) = GetRelatedTermsObjectsLists(termId); + var request = GetRequest(termId); + + MockHelpers.SetupMockRelatedTermRepositoryGetAllAsync(_mockRepository, relatedTermsList); + MockHelpers.SetupMockMapper, List>( + _mockMapper, + relatedTermDtoList, + relatedTermsList); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Should().SatisfyRespectively( + first => + { + first.Id.Should().Be(relatedTermsList[0].Id); + first.TermId.Should().Be(relatedTermsList[0].TermId); + }, + second => + { + second.Id.Should().Be(relatedTermsList[1].Id); + second.TermId.Should().Be(relatedTermsList[1].TermId); + }); + result.Value.Should().HaveCount(2); + VerifyGetAllAsyncAndMockingOperationsExecution(request, relatedTermsList); + } + + [Theory] + [InlineData(1)] + public async Task ShouldGetAllByTermIdSuccessfully_WithCorrectDataType(int termId) + { + // Arrange + var (relatedTermsList, relatedTermDtoList) = GetRelatedTermsObjectsLists(termId); + var request = GetRequest(termId); + + MockHelpers.SetupMockRelatedTermRepositoryGetAllAsync(_mockRepository, relatedTermsList); + MockHelpers.SetupMockMapper, List>( + _mockMapper, + relatedTermDtoList, + relatedTermsList); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType>(); + } + + [Theory] + [InlineData(1)] + public async Task ShouldGetAllByTermIdSuccessfully_WhenRelatedTermsNotExist(int termId) + { + // Arrange + var (emptyRelatedTermsList, emptyRelatedTermDtoList) = GetEmptyRelatedTermsObjectsLists(); + var request = GetRequest(termId); + + MockHelpers.SetupMockRelatedTermRepositoryGetAllAsync(_mockRepository, emptyRelatedTermsList); + MockHelpers.SetupMockMapper(_mockMapper, emptyRelatedTermDtoList, emptyRelatedTermsList); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Should().BeEmpty(); + result.ValueOrDefault.Should().BeAssignableTo>(); + VerifyGetAllAsyncAndMockingOperationsExecution(request, emptyRelatedTermsList); + } + + [Theory] + [InlineData(1)] + public async Task ShouldDeleteFailingly_WhenMappingFailed(int termId) + { + // Arrange + var (relatedTermsList, _) = GetRelatedTermsObjectsLists(termId); + var request = GetRequest(termId); + var expectedErrorMessage = _mockCannotCreateLocalizer["CannotCreateDTOsForRelatedWords"].Value; + + MockHelpers.SetupMockRelatedTermRepositoryGetAllAsync(_mockRepository, relatedTermsList); + MockHelpers.SetupMockMapper?, List>( + _mockMapper, + null, + relatedTermsList); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + private static (List, List) GetRelatedTermsObjectsLists(int termId) + { + var relatedTermsList = new List() + { + new RelatedTermEntity() + { + Id = 1, + TermId = termId, + }, + new RelatedTermEntity() + { + Id = 2, + TermId = termId, + }, + }; + var relatedTermDtoList = new List() + { + new RelatedTermDTO() + { + Id = relatedTermsList[0].Id, + TermId = termId, + }, + new RelatedTermDTO() + { + Id = relatedTermsList[1].Id, + TermId = termId, + }, + }; + + return (relatedTermsList, relatedTermDtoList); + } + + private static (List, List) GetEmptyRelatedTermsObjectsLists() + { + return (new List(), new List()); + } + + private static GetAllRelatedTermsByTermIdQuery GetRequest(int termId) + { + return new GetAllRelatedTermsByTermIdQuery(termId); + } + + private void VerifyGetAllAsyncAndMockingOperationsExecution( + GetAllRelatedTermsByTermIdQuery request, + List relatedTermsList) + { + _mockRepository.Verify( + x => x.RelatedTermRepository.GetAllAsync( + rt => rt.TermId == request.Id, + It.IsAny, IIncludableQueryable>?>()), + Times.Once); + _mockMapper.Verify(x => x.Map>(relatedTermsList), Times.Once); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/CreateFavouriteStreetcodeHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/CreateFavouriteStreetcodeHandlerTests.cs new file mode 100644 index 000000000..aaaf5d0c9 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/CreateFavouriteStreetcodeHandlerTests.cs @@ -0,0 +1,179 @@ +using System.Linq.Expressions; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.IdentityModel.Tokens; +using Moq; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.CreateFavourite; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Streetcode.Favourites; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class CreateFavouriteStreetcodeHandlerTests +{ + private readonly Mock _repository; + private readonly Mock _logger; + private readonly Mock _httpContextAccessor; + private readonly MockAlreadyExistLocalizer _mockAlreadyExists; + private readonly MockCannotSaveLocalizer _mockLocalizerCannotSave; + + public CreateFavouriteStreetcodeHandlerTests() + { + _repository = new Mock(); + _logger = new Mock(); + _mockAlreadyExists = new MockAlreadyExistLocalizer(); + _mockLocalizerCannotSave = new MockCannotSaveLocalizer(); + _httpContextAccessor = new Mock(); + } + + [Fact] + public async Task Handle_ReturnsErrorAlreadyInFavourites() + { + // Arrange + var userId = Guid.NewGuid().ToString(); + const int streetcodeId = 1; + + SetupStreetcodeRepository(new List + { + new () { Id = streetcodeId, }, + }); + + SetupFavouritesRepository(new List + { + new () + { + StreetcodeId = streetcodeId, + UserId = userId, + }, + }); + + MockHelpers.SetupMockHttpContextAccessor(_httpContextAccessor, userId); + + string expectedError = _mockAlreadyExists["FavouriteAlreadyExists"].Value; + + var handler = new CreateFavouriteStreetcodeHandler( + _repository.Object, + _logger.Object, + _mockAlreadyExists, + _mockLocalizerCannotSave, + _httpContextAccessor.Object); + + // Act + var result = await handler.Handle(new CreateFavouriteStreetcodeCommand(streetcodeId), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.Equal(expectedError, result.Errors[0].Message), + () => Assert.True(result.IsFailed)); + } + + [Fact] + public async Task Handle_ReturnsSuccess() + { + // Arrange + var userId = Guid.NewGuid().ToString(); + const int streetcodeId = 1; + + SetupStreetcodeRepository(new List + { + new () { Id = streetcodeId, }, + }); + + SetupFavouritesRepository(new List()); + + SetupSaveChanges(1); + + MockHelpers.SetupMockHttpContextAccessor(_httpContextAccessor, userId); + + var handler = new CreateFavouriteStreetcodeHandler( + _repository.Object, + _logger.Object, + _mockAlreadyExists, + _mockLocalizerCannotSave, + _httpContextAccessor.Object); + + // Act + var result = await handler.Handle(new CreateFavouriteStreetcodeCommand(streetcodeId), CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + } + + [Fact] + public async Task Handle_ReturnsCannotSave() + { + // Arrange + var userId = Guid.NewGuid().ToString(); + const int streetcodeId = 1; + + MockHelpers.SetupMockHttpContextAccessor(_httpContextAccessor, userId); + + SetupStreetcodeRepository(new List + { + new () { Id = streetcodeId, }, + }); + + SetupFavouritesRepository(new List()); + + SetupSaveChanges(0); + + string expectedError = _mockLocalizerCannotSave["CannotSaveTheData"].Value; + + var handler = new CreateFavouriteStreetcodeHandler( + _repository.Object, + _logger.Object, + _mockAlreadyExists, + _mockLocalizerCannotSave, + _httpContextAccessor.Object); + + // Act + var result = await handler.Handle(new CreateFavouriteStreetcodeCommand(streetcodeId), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.Equal(expectedError, result.Errors[0].Message), + () => Assert.True(result.IsFailed)); + } + + private void SetupStreetcodeRepository(List returnList) + { + _repository.Setup(repo => repo.StreetcodeRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, + IIncludableQueryable>>())) + .ReturnsAsync(returnList); + if (!returnList.IsNullOrEmpty()) + { + _repository.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( + It.IsAny>?>(), It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(returnList[0]); + } + } + + private void SetupFavouritesRepository(List returnList) + { + _repository.Setup(repo => repo.FavouritesRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, + IIncludableQueryable>>())) + .ReturnsAsync(returnList); + + if (!returnList.IsNullOrEmpty()) + { + _repository.Setup(x => x.FavouritesRepository.GetFirstOrDefaultAsync( + It.IsAny>?>(), It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(returnList[0]); + } + + _repository.Setup(x => x.FavouritesRepository.CreateAsync(new Favourite())); + } + + private void SetupSaveChanges(int result) + { + _repository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(result); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/CreateStreetcodeHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/CreateStreetcodeHandlerTests.cs index e745e0e48..33a34f453 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/CreateStreetcodeHandlerTests.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/CreateStreetcodeHandlerTests.cs @@ -1,99 +1,1359 @@ -using AutoMapper; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Expressions; +using System.Reflection; +using System.Security.Claims; +using System.Transactions; +using AutoMapper; using FluentAssertions; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Localization; using Moq; +using Streetcode.BLL.DTO.AdditionalContent.Coordinates.Types; +using Streetcode.BLL.DTO.AdditionalContent.Tag; +using Streetcode.BLL.DTO.Analytics; +using Streetcode.BLL.DTO.Media.Art; +using Streetcode.BLL.DTO.Media.Create; using Streetcode.BLL.DTO.Media.Images; +using Streetcode.BLL.DTO.Streetcode.Create; +using Streetcode.BLL.DTO.Streetcode.RelatedFigure; +using Streetcode.BLL.DTO.Streetcode.TextContent.Fact; +using Streetcode.BLL.DTO.Timeline.Update; +using Streetcode.BLL.DTO.Toponyms; using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.SharedResource; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.Create; +using Streetcode.DAL.Entities.AdditionalContent; +using Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types; +using Streetcode.DAL.Entities.Analytics; using Streetcode.DAL.Entities.Media.Images; +using Streetcode.DAL.Entities.Partners; using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Timeline; +using Streetcode.DAL.Entities.Toponyms; +using Streetcode.DAL.Enums; using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; using Xunit; -namespace Streetcode.BLL.MediatR.Streetcode.Streetcode.Create.Tests +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +[SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1124:Do not use regions", Justification = "For better searching")] +[SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1204:Static elements should appear before instance elements", Justification = "Private static method for DTO creation is placed at the bottom for better readability and convenience.")] +public class CreateStreetcodeHandlerTests { - public class CreateStreetcodeHandlerTests - { - private readonly Mock mockRepositoryWrapper; - private readonly Mock mockLoggerService; - private readonly Mock> mockStringLocalizerAnErrorOccurred; - private readonly Mock> mockStringLocalizerFailedToCreate; - private readonly Mock> mockStringLocalizerFailedToValidate; - private readonly Mock> mockStringLocalizerFieldNames; - private readonly Mock mockMapper; - private readonly Mock mockHttpContextAccessor; - - public CreateStreetcodeHandlerTests() - { - this.mockRepositoryWrapper = new Mock(); - this.mockLoggerService = new Mock(); - this.mockMapper = new Mock(); - this.mockStringLocalizerAnErrorOccurred = new Mock>(); - this.mockStringLocalizerFailedToCreate = new Mock>(); - this.mockStringLocalizerFailedToValidate = new Mock>(); - this.mockStringLocalizerFieldNames = new Mock>(); - this.mockHttpContextAccessor = new Mock(); - } - - [Fact] - public async Task AddImagesDetails_ValidImageDetails_DoesNotThrowException() - { - // Arrange - var imageDetails = new List + private readonly Mock _repositoryMock; + private readonly Mock _loggerMock; + private readonly MockFailedToValidateLocalizer _localizerValidationMock; + private readonly MockFieldNamesLocalizer _localizerFieldMock; + private readonly MockFailedToCreateLocalizer _localizerFailedToCreateMock; + private readonly Mock _mapperMock; + private readonly CreateStreetcodeHandler _handler; + private readonly Mock _httpContextAccessorMock; + + public CreateStreetcodeHandlerTests() + { + _localizerValidationMock = new MockFailedToValidateLocalizer(); + _localizerFieldMock = new MockFieldNamesLocalizer(); + _repositoryMock = new Mock(); + _httpContextAccessorMock = new Mock(); + _loggerMock = new Mock(); + _mapperMock = new Mock(); + _localizerFailedToCreateMock = new MockFailedToCreateLocalizer(); + var localizerErrorMock = new MockAnErrorOccurredLocalizer(); + + var claims = new List + { + new (ClaimTypes.Email, "user@example.com"), + new (ClaimTypes.NameIdentifier, Guid.NewGuid().ToString()), + }; + + var identity = new ClaimsIdentity(claims, "TestAuthType"); + var claimsPrincipal = new ClaimsPrincipal(identity); + var context = new DefaultHttpContext { User = claimsPrincipal }; + + _httpContextAccessorMock.Setup(_ => _.HttpContext).Returns(context); + + _handler = new CreateStreetcodeHandler( + _mapperMock.Object, + _repositoryMock.Object, + _loggerMock.Object, + localizerErrorMock, + _localizerFailedToCreateMock, + _localizerValidationMock, + _localizerFieldMock, + _httpContextAccessorMock.Object); + } + + #region AddImagesDetails + [Fact] + public async Task AddImagesDetails_WhenValidImageDetails_CreatesImageDetailsSuccessfully() + { + // Arrange + var alt1 = ((int)ImageAssigment.Blackandwhite).ToString(); + var alt2 = ((int)ImageAssigment.Animation).ToString(); + + var imageDetails = new List + { + new () { Alt = alt1 }, + new () { Alt = alt2 }, + }; + SetupMockStreetcodeImageDetailsCreate(); + + // Act + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddImagesDetails", BindingFlags.NonPublic | BindingFlags.Instance); + await (Task)methodInfo?.Invoke(_handler, new object[] { imageDetails }) !; + + // Assert + _repositoryMock.Verify(repo => repo.ImageDetailsRepository.CreateRangeAsync(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task AddImagesDetails_WhenImageDetailsIsNull_ThrowException_And_DoesNotCallRepositories() + { + // Arrange + List? imageDetails = null; + + SetupMockStreetcodeImageDetailsCreate(); + + // Act + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddImagesDetails", BindingFlags.NonPublic | BindingFlags.Instance); + Func action = async () => await (Task)methodInfo?.Invoke(_handler, new object[] { imageDetails! }) !; + + // Assert + await action.Should().ThrowAsync(); + + _repositoryMock.Verify(repo => repo.ImageDetailsRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + } + + [Fact] + public async Task Handle_WhenImageDetailsIsNull_ReturnsErrorResult() + { + var streetcodeCreateDto = CreateStreetcodeDto(); + streetcodeCreateDto.ImagesDetails = null!; + var request = new CreateStreetcodeCommand(streetcodeCreateDto); + string expectedErrorValue = _localizerValidationMock["CannotBeEmpty", _localizerFieldMock["ImagesDetails"]]; + SetupMocksForCreateStreetcode(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsFailed); + Assert.Contains(expectedErrorValue, result.Errors.First().Message); + }); + } + + #endregion + + #region AddImages + [Fact] + public async Task AddImagesAsync_WhenValidImagesIds_CreatesImagesSuccessfully() + { + // Arrange + StreetcodeContent streetcode = new StreetcodeContent(); + IEnumerable imagesIds = new List { 1, 2, 3 }; + SetupMockStreetcodeImageCreate(); + + // Act + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddImagesAsync", BindingFlags.NonPublic | BindingFlags.Instance); + await (Task)methodInfo?.Invoke(_handler, new object[] { streetcode, imagesIds }) !; + + // Assert + _repositoryMock.Verify(repo => repo.StreetcodeImageRepository.CreateRangeAsync(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task AddImagesAsync_WhenImagesIdsIsNull_ThrowException_And_DoesNotCallRepositories() + { + // Arrange + StreetcodeContent streetcode = new StreetcodeContent(); + IEnumerable? imagesIds = null!; + SetupMockStreetcodeImageCreate(); + + // Act + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddImagesAsync", BindingFlags.NonPublic | BindingFlags.Instance); + Func action = async () => await (Task)methodInfo?.Invoke(_handler, new object[] { streetcode, imagesIds }) !; + + // Assert + await action.Should().ThrowAsync(); + + _repositoryMock.Verify(repo => repo.StreetcodeImageRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + } + + [Fact] + public async Task AddImagesAsync_WhenImagesIdsIsEmpty_ThrowException_And_DoesNotCallRepositories() + { + // Arrange + StreetcodeContent streetcode = new StreetcodeContent(); + IEnumerable imagesIds = new List(); + SetupMockStreetcodeImageCreate(); + + // Act + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddImagesAsync", BindingFlags.NonPublic | BindingFlags.Instance); + Func action = async () => await (Task)methodInfo?.Invoke(_handler, new object[] { streetcode, imagesIds }) !; + + // Assert + await action.Should().ThrowAsync(); + + _repositoryMock.Verify(repo => repo.StreetcodeImageRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + } + + [Fact] + public async Task Handle_WhenImagesIdsIsNull_ReturnsErrorResult() + { + var streetcodeCreateDto = CreateStreetcodeDto(); + streetcodeCreateDto.ImagesIds = null!; + var request = new CreateStreetcodeCommand(streetcodeCreateDto); + string expectedErrorValue = _localizerValidationMock["CannotBeEmpty", _localizerFieldMock["Images"]]; + SetupMocksForCreateStreetcode(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsFailed); + Assert.Contains(expectedErrorValue, result.Errors.Single().Message); + }); + } + + [Fact] + public async Task Handle_WhenImagesIdsIsEmpty_ReturnsErrorResult() + { + var streetcodeCreateDto = CreateStreetcodeDto(); + streetcodeCreateDto.ImagesIds = new List(); + var request = new CreateStreetcodeCommand(streetcodeCreateDto); + string expectedErrorValue = _localizerValidationMock["CannotBeEmpty", _localizerFieldMock["Images"]]; + SetupMocksForCreateStreetcode(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsFailed); + Assert.Contains(expectedErrorValue, result.Errors.Single().Message); + }); + } + #endregion + + #region AddTimelineItems + [Fact] + public async Task AddTimelineItems_WhenValidTimelineItems_CreatesAndSavesSuccessfully() + { + // Arrange + StreetcodeContent streetcode = new StreetcodeContent(); + IEnumerable timelineItems = new List() + { + new () + { + Id = 2, + Title = "TimeLine", + Date = new DateTime(2021, 1, 1), + DateViewPattern = DateViewPattern.Year, + HistoricalContexts = new List() + { + new () { Id = 0, Title = "Historical Context 1" }, + new () { Id = 2, Title = "Historical Context 2" }, + }, + }, + }; + SetupMockAddTimeLineItems(); + + var methodInfo = typeof(CreateStreetcodeHandler) + .GetMethod("AddTimelineItems", BindingFlags.NonPublic | BindingFlags.Instance); + + // Act + await (Task)methodInfo?.Invoke(_handler, new object[] { streetcode, timelineItems }) !; + + // Assert + Assert.Multiple(() => + { + _repositoryMock.Verify(repo => repo.HistoricalContextRepository.CreateRangeAsync(It.IsAny>()), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Once); + }); + } + + [Fact] + public async Task AddTimelineItems_WhenTimelineItemsIsNull_DoesNotThrowException_And_DoesNotCallRepositories() + { + // Arrange + StreetcodeContent streetcode = new StreetcodeContent(); + IEnumerable? timelineItems = null; + + var methodInfo = typeof(CreateStreetcodeHandler) + .GetMethod("AddTimelineItems", BindingFlags.NonPublic | BindingFlags.Instance); + + // Act + Func action = async () => await (Task)methodInfo?.Invoke(_handler, new object[] { streetcode, timelineItems! }) !; + + // Assert + await action.Should().NotThrowAsync(); + Assert.Multiple(() => + { + _repositoryMock.Verify( + repo => repo.HistoricalContextRepository.CreateRangeAsync( + It.IsAny>()), Times.Never); + _repositoryMock.Verify( + repo => repo.SaveChangesAsync(), + Times.Never); + }); + } + + [Fact] + public async Task AddTimelineItems_WhenTimelineItemsIsEmpty_DoesNotThrowException_And_DoesNotCallRepositories() + { + // Arrange + StreetcodeContent streetcode = new StreetcodeContent(); + IEnumerable timelineItems = new List(); + + var methodInfo = typeof(CreateStreetcodeHandler) + .GetMethod("AddTimelineItems", BindingFlags.NonPublic | BindingFlags.Instance); + + // Act + Func action = async () => await (Task)methodInfo?.Invoke(_handler, new object[] { streetcode, timelineItems }) !; + + // Assert + await action.Should().NotThrowAsync(); + Assert.Multiple(() => + { + _repositoryMock.Verify( + repo => repo.HistoricalContextRepository.CreateRangeAsync( + It.IsAny>()), Times.Never); + _repositoryMock.Verify( + repo => repo.SaveChangesAsync(), + Times.Never); + }); + } + + [Fact] + public async Task Handle_WhenTimelineItemsIsNull_DoesNotReturnsErrorResult() + { + // Arrange + var streetcodeCreateDto = CreateStreetcodeDto(); + streetcodeCreateDto.TimelineItems = null; + var request = new CreateStreetcodeCommand(streetcodeCreateDto); + + SetupMocksForCreateStreetcode(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + }); + } + + [Fact] + public async Task Handle_WhenTimelineItemsIsEmpty_DoesNotReturnsErrorResult() + { + // Arrange + var streetcodeCreateDto = CreateStreetcodeDto(); + streetcodeCreateDto.TimelineItems = new List(); + var request = new CreateStreetcodeCommand(streetcodeCreateDto); + + SetupMocksForCreateStreetcode(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + }); + } + #endregion + + #region AddAudio + [Fact] + public void AddAudio_WhenValidAudioId_AddsSuccessfully() + { + // Arrange + StreetcodeContent streetcode = new StreetcodeContent(); + var audioId = 1; + + var methodInfo = typeof(CreateStreetcodeHandler) + .GetMethod("AddAudio", BindingFlags.NonPublic | BindingFlags.Static); + + // Act + methodInfo?.Invoke(_handler, new object[] { streetcode, audioId }); + + // Assert + Assert.Equal(streetcode.AudioId, audioId); + } + #endregion + + #region AddArtGallery + [Fact] + public async Task AddArtGallery_WhenValidData_AddsSuccessfully() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1 }; + var artSlides = new List + { + new () + { + SlideId = 1, + StreetcodeId = 1, + Template = StreetcodeArtSlideTemplate.OneToTwo, + Index = 0, + StreetcodeArts = new List + { + new () { ArtId = 10 }, + }, + }, + }; + + var arts = new List + { + new () { Id = 10, ImageId = 100, Description = "ArtDesc", Title = "ArtTitle" }, + }; + + SetupMockAddArtGallery(); + + // Act + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddArtGallery", BindingFlags.NonPublic | BindingFlags.Instance); + Func action = async () => await (Task)methodInfo?.Invoke(_handler, new object[] { streetcode, artSlides, arts }) !; + + // Assert + await action.Should().NotThrowAsync(); + Assert.Multiple(() => + { + _repositoryMock.Verify(repo => repo.StreetcodeArtSlideRepository.CreateRangeAsync(It.IsAny>()), Times.Once); + _repositoryMock.Verify(repo => repo.ArtRepository.CreateRangeAsync(It.IsAny>()), Times.Once); + _repositoryMock.Verify(repo => repo.StreetcodeArtRepository.CreateRangeAsync(It.IsAny>()), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Exactly(3)); + }); + } + + [Fact] + public async Task AddArtGallery_WhenArtSlideAndArtsAreEmpty_DoesNotThrowException_And_DoesNotCallRepositories() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1 }; + var artSlides = new List(); + var arts = new List(); + + SetupMockAddArtGallery(); + + // Act + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddArtGallery", BindingFlags.NonPublic | BindingFlags.Instance); + Func action = async () => await (Task)methodInfo?.Invoke(_handler, new object[] { streetcode, artSlides, arts }) !; + + // Assert + await action.Should().NotThrowAsync(); + Assert.Multiple(() => + { + _repositoryMock.Verify(repo => repo.StreetcodeArtSlideRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + _repositoryMock.Verify(repo => repo.ArtRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + _repositoryMock.Verify(repo => repo.StreetcodeArtRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Never); + }); + } + + [Fact] + public async Task AddArtGallery_WhenArtSlideAndArtsAreNull_DoesNotThrowExceptionAndDoesNotCallRepositories() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1 }; + List artSlides = null!; + List arts = null!; + + SetupMockAddArtGallery(); + + // Act + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddArtGallery", BindingFlags.NonPublic | BindingFlags.Instance); + Func action = async () => await (Task)methodInfo?.Invoke(_handler, new object[] { streetcode, artSlides, arts }) !; + + // Assert + await action.Should().NotThrowAsync(); + Assert.Multiple(() => + { + _repositoryMock.Verify(repo => repo.StreetcodeArtSlideRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + _repositoryMock.Verify(repo => repo.ArtRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + _repositoryMock.Verify(repo => repo.StreetcodeArtRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Never); + }); + } + + [Fact] + public async Task Handle_WhenArtSlideAndArtsAreNull_DoesNotReturnErrorResult() + { + var streetcodeCreateDto = CreateStreetcodeDto(); + streetcodeCreateDto.StreetcodeArtSlides = null!; + streetcodeCreateDto.Arts = null!; + var request = new CreateStreetcodeCommand(streetcodeCreateDto); + SetupMocksForCreateStreetcode(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + _loggerMock.Verify(logger => logger.LogError(request, It.Is(msg => msg.Contains("AnErrorOccurredWhileCreating"))), Times.Never); + }); + } + + #endregion + + #region AddTags + [Fact] + public async Task AddTags_WhenValidTags_AddsSuccessfully() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1 }; + var tags = new List + { + new () { Id = 5, Title = "History", IsVisible = true }, + new () { Id = 10, Title = "Culture", IsVisible = false }, + }; + SetupMockAddTags(); + + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddTags", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + Func action = async () => await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, tags }) !; + + // Assert + await action.Should().NotThrowAsync(); + _repositoryMock.Verify(repo => repo.StreetcodeTagIndexRepository.CreateRangeAsync(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task AddTags_WhenTagExist_ThrowException_And_DoesNotCallRepositories() + { + // Arrange + var streetcode = new StreetcodeContent(); + var tags = new List + { + new () { Id = -1, Title = "ExistingTag", IsVisible = false }, + }; + SetupMockAddTags(true); + + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddTags", BindingFlags.NonPublic | BindingFlags.Instance); + + // Act + Func action = async () => await (Task)methodInfo?.Invoke(_handler, new object[] { streetcode, tags }) !; + + // Assert + await action.Should().ThrowAsync(); + Assert.Multiple(() => + { + _repositoryMock.Verify(repo => repo.TagRepository.GetFirstOrDefaultAsync(It.IsAny>>(), null), Times.Once); + _repositoryMock.Verify(repo => repo.StreetcodeTagIndexRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + }); + } + + [Fact] + public async Task AddTags_WhenTagsIsNull_DoesNotThrowException_And_DoesNotCallRepositories() + { + // Arrange + var streetcode = new StreetcodeContent(); + List tags = null!; + SetupMockAddTags(); + + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddTags", BindingFlags.NonPublic | BindingFlags.Instance); + + // Act + Func action = async () => await (Task)methodInfo?.Invoke(_handler, new object[] { streetcode, tags }) !; + + // Assert + await action.Should().NotThrowAsync(); + _repositoryMock.Verify(repo => repo.StreetcodeTagIndexRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + } + + [Fact] + public async Task AddTags_WhenTagsIsEmpty_DoesNotThrowException_And_DoesNotCallRepositories() + { + // Arrange + var streetcode = new StreetcodeContent(); + List tags = new List(); + SetupMockAddTags(); + + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddTags", BindingFlags.NonPublic | BindingFlags.Instance); + + // Act + Func action = async () => await (Task)methodInfo?.Invoke(_handler, new object[] { streetcode, tags }) !; + + // Assert + await action.Should().NotThrowAsync(); + _repositoryMock.Verify(repo => repo.StreetcodeTagIndexRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + } + + [Fact] + public async Task Handle_WhenTagsIsNull_DoesNotReturnsErrorResult() + { + var streetcodeCreateDto = CreateStreetcodeDto(); + streetcodeCreateDto.Tags = null!; + var request = new CreateStreetcodeCommand(streetcodeCreateDto); + SetupMocksForCreateStreetcode(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + _loggerMock.Verify(logger => logger.LogError(request, It.Is(msg => msg.Contains("AnErrorOccurredWhileCreating"))), Times.Never); + }); + } + #endregion + + #region AddRelatedFigures + [Fact] + public async Task AddRelatedFigures_WhenValidFigures_AddsSuccessfully() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1 }; + var relatedFigures = new List + { + new () { Id = 101 }, + new () { Id = 102 }, + }; + + SetupMockAddRelaredFigures(); + + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddRelatedFigures", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + Func action = async () => await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, relatedFigures }) !; + + // Assert + await action.Should().NotThrowAsync(); + _repositoryMock.Verify(repo => repo.RelatedFigureRepository.CreateRangeAsync(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task AddRelatedFigures_WhenFiguresIsNull_DoesNotThrowException_And_DoesNotCallRepositories() + { + // Arrange + var streetcode = new StreetcodeContent(); + List relatedFigures = null!; + + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddRelatedFigures", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + Func action = async () => await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, relatedFigures }) !; + + // Assert + await action.Should().NotThrowAsync(); + _repositoryMock.Verify(repo => repo.RelatedFigureRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + } + + [Fact] + public async Task AddRelatedFigures_WhenFiguresIsEmpty_DoesNotThrowException_And_DoesNotCallRepositories() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1 }; + var relatedFigures = new List(); + SetupMockAddRelaredFigures(); + + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddRelatedFigures", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + Func action = async () => await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, relatedFigures }) !; + + // Assert + await action.Should().NotThrowAsync(); + _repositoryMock.Verify(repo => repo.RelatedFigureRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + } + + [Fact] + public async Task Handle_WhenRelatedFiguresIsNull_DoesNotReturnsErrorResult() + { + var streetcodeCreateDto = CreateStreetcodeDto(); + streetcodeCreateDto.RelatedFigures = null; + var request = new CreateStreetcodeCommand(streetcodeCreateDto); + SetupMocksForCreateStreetcode(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + _loggerMock.Verify(logger => logger.LogError(request, It.Is(msg => msg.Contains("AnErrorOccurredWhileCreating"))), Times.Never); + }); + } + #endregion + + #region AddPartners + [Fact] + public async Task AddPartners_WhenValidPartners_AddsSuccessfully() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1 }; + var partners = new List { 101, 102, 103 }; + + SetupMockAddPartners(); + + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddPartners", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + Func action = async () => await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, partners }) !; + + // Assert + await action.Should().NotThrowAsync(); + _repositoryMock.Verify(repo => repo.PartnerStreetcodeRepository.CreateRangeAsync(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task AddPartners_WhenPartnersIsNull_DoesNotThrowException_And_DoesNotCallRepositories() + { + // Arrange + var streetcode = new StreetcodeContent(); + List partners = null!; + + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddPartners", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + Func action = async () => await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, partners }) !; + + // Assert + await action.Should().NotThrowAsync(); + _repositoryMock.Verify(repo => repo.PartnerStreetcodeRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + } + + [Fact] + public async Task AddPartners_WhenPartnersIsEmpty_DoesNotThrowException_And_DoesNotCallRepositories() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1 }; + var partners = new List(); + + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddPartners", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + Func action = async () => await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, partners }) !; + + // Assert + await action.Should().NotThrowAsync(); + _repositoryMock.Verify(repo => repo.PartnerStreetcodeRepository.CreateRangeAsync(It.IsAny>()), Times.Never); + } + + [Fact] + public async Task Handle_WhenPartnersIsNull_DoesNotReturnsErrorResult() + { + // Arrange + var streetcodeCreateDto = CreateStreetcodeDto(); + streetcodeCreateDto.Partners = null; + + var request = new CreateStreetcodeCommand(streetcodeCreateDto); + SetupMocksForCreateStreetcode(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + }); + } + + #endregion + + #region AddToponyms + [Fact] + public async Task AddToponyms_WhenValidToponyms_AddsSuccessfully() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1, Toponyms = new List() }; + var toponyms = new List + { + new () { StreetName = "Main Street" }, + new () { StreetName = "Broadway" }, + }; + + SetupMockAddToponyms(); + + MethodInfo methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddToponyms", BindingFlags.NonPublic | BindingFlags.Instance) !; + + Assert.NotNull(methodInfo); + + // Act + Func action = async () => await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, toponyms }) !; + + // Assert + await action.Should().NotThrowAsync(); + _repositoryMock.Verify(repo => repo.ToponymRepository.GetAllAsync(It.IsAny>>(), null), Times.Once); + } + + [Fact] + public async Task AddToponyms_WhenToponymsIsNull_DoesNotThrowException_And_DoesNotCallRepositories() + { + // Arrange + var streetcode = new StreetcodeContent { Toponyms = new List() }; + List toponyms = null!; + + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddToponyms", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + Func action = async () => await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, toponyms }) !; + + // Assert + await action.Should().NotThrowAsync(); + _repositoryMock.Verify(repo => repo.ToponymRepository.GetAllAsync(It.IsAny>>(), null), Times.Never); + } + + [Fact] + public async Task Handle_WhenToponymsIsNull_DoesNotReturnsErrorResult() + { + // Arrange + var streetcodeCreateDto = CreateStreetcodeDto(); + streetcodeCreateDto.Toponyms = null; + + var request = new CreateStreetcodeCommand(streetcodeCreateDto); + SetupMocksForCreateStreetcode(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + }); + } + + #endregion + + #region AddStatisticRecords + [Fact] + public void AddStatisticRecords_WhenValidRecords_AddsSuccessfully() + { + // Arrange + var streetcode = new StreetcodeContent + { + Id = 1, + Coordinates = new List + { + new () { Latitude = 50.41m, Longtitude = 30.5234m }, + }, + StatisticRecords = new List(), + }; + + var statisticRecords = new List + { + new () { - new ImageDetailsDto { Alt = "Alt1" }, - new ImageDetailsDto { Alt = "Alt2" }, - }; - this.SetupMockStreetcodeImageDetailsCreate(); - var handler = new CreateStreetcodeHandler( - this.mockMapper.Object, - this.mockRepositoryWrapper.Object, - this.mockLoggerService.Object, - this.mockStringLocalizerAnErrorOccurred.Object, - this.mockStringLocalizerFailedToCreate.Object, - this.mockStringLocalizerFailedToValidate.Object, - this.mockStringLocalizerFieldNames.Object, - this.mockHttpContextAccessor.Object); - - // Act & Assert - Func action = async () => await handler.AddImagesDetails(imageDetails); - await action.Should().NotThrowAsync(); - } - - [Fact] - public async Task AddImagesAsync_ValidImagesIds_DoesNotThrowException() - { - // Arrange - StreetcodeContent streetcode = new StreetcodeContent(); - IEnumerable imagesIds = new List { 1, 2, 3 }; - this.SetupMockStreetcodeImageCreate(); - - var handler = new CreateStreetcodeHandler( - this.mockMapper.Object, - this.mockRepositoryWrapper.Object, - this.mockLoggerService.Object, - this.mockStringLocalizerAnErrorOccurred.Object, - this.mockStringLocalizerFailedToCreate.Object, - this.mockStringLocalizerFailedToValidate.Object, - this.mockStringLocalizerFieldNames.Object, - this.mockHttpContextAccessor.Object); - - // Act & Assert - Func action = async () => await handler.AddImagesAsync(streetcode, imagesIds); - await action.Should().NotThrowAsync(); - } - - private void SetupMockStreetcodeImageCreate() - { - this.mockRepositoryWrapper.Setup(repo => repo.StreetcodeImageRepository.CreateRangeAsync(It.IsAny>())) - .Returns(Task.CompletedTask); - } - - private void SetupMockStreetcodeImageDetailsCreate() - { - this.mockRepositoryWrapper.Setup(repo => repo.ImageDetailsRepository.CreateRangeAsync(It.IsAny>())) - .Returns(Task.CompletedTask); - } - } -} + StreetcodeCoordinate = new StreetcodeCoordinateDTO { Latitude = 50.41m, Longtitude = 30.5234m }, + QrId = 1, + Count = 5, + Address = "Kyiv", + }, + }; + + SetupMockAddStatisticRecords(); + + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddStatisticRecords", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + Action action = () => methodInfo.Invoke(_handler, new object[] { streetcode, statisticRecords }); + + // Assert + action.Should().NotThrow(); + Assert.Single(streetcode.StatisticRecords); + } + + [Fact] + public void AddStatisticRecords_WhenRecordsIsNull_DoesNotThrowException() + { + // Arrange + var streetcode = new StreetcodeContent { StatisticRecords = new List() }; + List statisticRecords = null!; + + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddStatisticRecords", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + Action action = () => methodInfo.Invoke(_handler, new object[] { streetcode, statisticRecords }); + + // Assert + action.Should().NotThrow(); + Assert.Empty(streetcode.StatisticRecords); + } + + [Fact] + public void AddStatisticRecords_WhenNoMatchingCoordinates_ThrowsException() + { + // Arrange + var streetcode = new StreetcodeContent + { + Id = 1, + Coordinates = new List // Інші координати + { + new () { Latitude = 40.7128m, Longtitude = -74.0060m }, + }, + StatisticRecords = new List(), + }; + + var statisticRecords = new List + { + new () + { + StreetcodeCoordinate = new StreetcodeCoordinateDTO { Latitude = 50.4501m, Longtitude = 30.5234m }, + QrId = 1, + Count = 5, + Address = "Kyiv", + }, + }; + + SetupMockAddStatisticRecords(); + + var methodInfo = typeof(CreateStreetcodeHandler).GetMethod("AddStatisticRecords", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + Action action = () => methodInfo.Invoke(_handler, new object[] { streetcode, statisticRecords }); + + // Assert + action.Should().Throw() + .WithInnerException(); + } + + [Fact] + public async Task Handle_WhenStatisticRecordsIsNull_DoesNotReturnsErrorResult() + { + // Arrange + var streetcodeCreateDto = CreateStreetcodeDto(); + streetcodeCreateDto.StatisticRecords = null; + + var request = new CreateStreetcodeCommand(streetcodeCreateDto); + SetupMocksForCreateStreetcode(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + }); + } + + [Fact] + public async Task Handle_WhenStatisticRecordsIsEmpty_DoesNotReturnsErrorResult() + { + // Arrange + var streetcodeCreateDto = CreateStreetcodeDto(); + streetcodeCreateDto.StatisticRecords = new List(); + + var request = new CreateStreetcodeCommand(streetcodeCreateDto); + SetupMocksForCreateStreetcode(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + }); + } + + #endregion + + #region AddTransactionLink + [Fact] + public void AddTransactionLink_WhenValidUrl_AddsTransactionLink() + { + // Arrange + var streetcode = new StreetcodeContent(); + const string url = "https://example.com"; + + var methodInfo = typeof(CreateStreetcodeHandler) + .GetMethod("AddTransactionLink", BindingFlags.NonPublic | BindingFlags.Static); + + Assert.NotNull(methodInfo); + + // Act + methodInfo.Invoke(_handler, new object[] { streetcode, url }); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(streetcode.TransactionLink); + Assert.Equal(url, streetcode.TransactionLink.Url); + Assert.Equal(url, streetcode.TransactionLink.UrlTitle); + }); + } + + [Fact] + public void AddTransactionLink_WhenUrlIsNull_DoesNotModifyTransactionLink() + { + // Arrange + var streetcode = new StreetcodeContent { TransactionLink = null }; + string url = null!; + + var methodInfo = typeof(CreateStreetcodeHandler) + .GetMethod("AddTransactionLink", BindingFlags.NonPublic | BindingFlags.Static); + + Assert.NotNull(methodInfo); + + // Act + methodInfo.Invoke(_handler, new object[] { streetcode, url }); + + // Assert + Assert.Null(streetcode.TransactionLink); + } + + #endregion + + #region AddFactImageDescription + [Fact] + public void AddFactImageDescription_WhenFactsListIsEmpty_DoesNotThrowException_And_DoesNotCallRepositories() + { + // Arrange + var facts = new List(); + + _repositoryMock.Setup(repo => repo.ImageDetailsRepository.Create(It.IsAny())); + + var methodInfo = typeof(CreateStreetcodeHandler) + .GetMethod("AddFactImageDescription", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + Action action = () => methodInfo.Invoke(_handler, new object[] { facts }); + + // Assert + action.Should().NotThrow(); + + _repositoryMock.Verify(repo => repo.ImageDetailsRepository.Create(It.IsAny()), Times.Never); + } + + [Fact] + public void AddFactImageDescription_WhenFactsIsNull_DoesNotThrowException_And_DoesNotCallRepositories() + { + // Arrange + List facts = null!; + + _repositoryMock.Setup(repo => repo.ImageDetailsRepository.Create(It.IsAny())); + + var methodInfo = typeof(CreateStreetcodeHandler) + .GetMethod("AddFactImageDescription", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + Action action = () => methodInfo.Invoke(_handler, new object[] { facts }); + + // Assert + action.Should().NotThrow(); + + _repositoryMock.Verify(repo => repo.ImageDetailsRepository.Create(It.IsAny()), Times.Never); + } + + [Fact] + public async Task Handle_WhenFactsIsNull_DoesNotReturnErrorResult() + { + // Arrange + var streetcodeCreateDto = CreateStreetcodeDto(); + streetcodeCreateDto.Facts = null!; + + var request = new CreateStreetcodeCommand(streetcodeCreateDto); + SetupMocksForCreateStreetcode(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + }); + } + + [Fact] + public async Task Handle_WhenFactsIsEmpty_DoesNotReturnErrorResult() + { + // Arrange + var streetcodeCreateDto = CreateStreetcodeDto(); + streetcodeCreateDto.Facts = new List(); + + var request = new CreateStreetcodeCommand(streetcodeCreateDto); + SetupMocksForCreateStreetcode(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + }); + } + + #endregion + [Fact] + public async Task Handle_ReturnsSuccess_WhenStreetcodeCreated() + { + // Arrange + var createdStreetcode = CreateStreetcodeDto(); + var request = new CreateStreetcodeCommand(createdStreetcode); + + SetupMocksForCreateStreetcode(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + }); + } + + [Fact] + public async Task Handle_ReturnsFail_WhenStreetcodeCreationFails() + { + // Arrange + var createdStreetcode = CreateStreetcodeDto(); + var request = new CreateStreetcodeCommand(createdStreetcode); + string expectedErrorValue = _localizerFailedToCreateMock["FailedToCreateStreetcode"]; + SetupMocksForCreateStreetcode(); + _repositoryMock.Setup(r => r.SaveChangesAsync()).ReturnsAsync(0); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorValue, result.Errors.Single().Message); + }); + } + + private void SetupMockAddArtGallery() + { + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((List src) => + src.Select(s => new StreetcodeArtSlide + { + Id = s.SlideId, + StreetcodeId = s.StreetcodeId ?? 0, + Template = s.Template, + Index = s.Index, + }).ToList()); + + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((List src) => + src.Select(s => new Art() + { + Id = s.Id, + ImageId = s.ImageId, + Description = s.Description, + Title = s.Title, + }).ToList()); + + _repositoryMock.Setup(repo => repo.StreetcodeArtSlideRepository.CreateRangeAsync(It.IsAny>())) + .Returns(Task.CompletedTask); + + _repositoryMock.Setup(repo => repo.ArtRepository.CreateRangeAsync(It.IsAny>())) + .Returns(Task.CompletedTask); + + _mapperMock + .Setup(m => m.Map(It.IsAny())) + .Returns(( + StreetcodeArtCreateUpdateDTO src) => new StreetcodeArt() + { + Id = src.ArtId, + }); + + _repositoryMock.Setup(repo => repo.StreetcodeArtRepository.CreateRangeAsync(It.IsAny>())) + .Returns(Task.CompletedTask); + } + + private void SetupMockAddTimeLineItems() + { + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((List src) => + src.Select(s => new HistoricalContext() + { + Id = s.Id, + Title = s.Title, + }).ToList()); + + _repositoryMock.Setup(repo => repo.HistoricalContextRepository.CreateRangeAsync(It.IsAny>())) + .Returns(Task.CompletedTask); + _repositoryMock.Setup(r => r.SaveChangesAsync()).ReturnsAsync(1); + + _mapperMock + .Setup(m => m.Map(It.IsAny())) + .Returns(( + TimelineItemCreateUpdateDTO src) => new TimelineItem() + { + Id = src.Id, + HistoricalContextTimelines = new List(), + }); + } + + private void SetupMockAddTags(bool tagExist = false) + { + _mapperMock + .Setup(m => m.Map(It.IsAny())) + .Returns((StreetcodeTagDTO src) => new Tag { Id = 0, Title = src.Title }); + + _repositoryMock + .Setup(repo => repo.TagRepository.GetFirstOrDefaultAsync(It.IsAny>>(), null)) + .ReturnsAsync(tagExist ? new Tag { Id = 10, Title = "ExistingTag" } : null); + + _repositoryMock.Setup(repo => repo.StreetcodeTagIndexRepository.CreateRangeAsync(It.IsAny>())) + .Returns(Task.CompletedTask); + } + + private void SetupMockAddRelaredFigures() + { + _repositoryMock.Setup(repo => repo.RelatedFigureRepository.CreateRangeAsync(It.IsAny>())) + .Returns(Task.CompletedTask); + } + + private void SetupMockAddPartners() + { + _repositoryMock.Setup(repo => repo.PartnerStreetcodeRepository.CreateRangeAsync(It.IsAny>())) + .Returns(Task.CompletedTask); + } + + private void SetupMockAddToponyms() + { + _repositoryMock.Setup(repo => repo.ToponymRepository.GetAllAsync(It.IsAny>>(), null)) + .ReturnsAsync(new List()); + } + + private void SetupMockStreetcodeImageCreate() + { + _repositoryMock.Setup(repo => repo.StreetcodeImageRepository.CreateRangeAsync(It.IsAny>())) + .Returns(Task.CompletedTask); + } + + private void SetupMockStreetcodeImageDetailsCreate() + { + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((List src) => + src.Select(s => new ImageDetails() + { + Id = s.Id, + }).ToList()); + _repositoryMock.Setup(repo => repo.ImageDetailsRepository.CreateRangeAsync(It.IsAny>())) + .Returns(Task.CompletedTask); + } + + private void SetupMockAddStatisticRecords() + { + _mapperMock + .Setup(m => m.Map(It.IsAny())) + .Returns((StatisticRecordDTO src) => new StatisticRecord + { + StreetcodeCoordinate = new StreetcodeCoordinate { Latitude = src.StreetcodeCoordinate.Latitude, Longtitude = src.StreetcodeCoordinate.Longtitude }, + QrId = src.QrId, + Count = src.Count, + Address = src.Address, + }); + } + + private static StreetcodeCreateDTO CreateStreetcodeDto() + { + return new StreetcodeCreateDTO() + { + Index = 1, + Teaser = "Test_Teaser", + DateString = "Test_Date", + Alias = "Test_Alias", + Status = StreetcodeStatus.Published, + Title = "Test_Title", + TransliterationUrl = "Url", + ViewCount = 1, + StreetcodeType = StreetcodeType.Person, + ImagesIds = new List() { 1, 2 }, + ImagesDetails = new List() + { + new () { Alt = "1", Title = "TestImage", Id = 1 }, + }, + }; + } + + private void SetupMocksForCreateStreetcode() + { + _mapperMock + .Setup(x => x.Map(It.IsAny())) + .Returns((StreetcodeCreateDTO src) => new StreetcodeContent() + { + Index = src.Index, + Teaser = src.Teaser, + DateString = src.DateString, + Alias = src.Alias, + Status = src.Status, + Title = src.Title, + TransliterationUrl = src.TransliterationUrl, + EventStartOrPersonBirthDate = src.EventStartOrPersonBirthDate, + UserId = Guid.NewGuid().ToString(), + }); + + _repositoryMock.Setup(r => r.StreetcodeRepository.Create(It.IsAny())); + _repositoryMock.Setup(r => r.SaveChangesAsync()).ReturnsAsync(1); + + SetupMockAddTimeLineItems(); + SetupMockStreetcodeImageCreate(); + SetupMockAddArtGallery(); + SetupMockAddTags(); + SetupMockAddRelaredFigures(); + SetupMockAddPartners(); + SetupMockAddToponyms(); + SetupMockStreetcodeImageDetailsCreate(); + + _repositoryMock + .Setup(x => x.BeginTransaction()) + .Returns(new TransactionScope(TransactionScopeOption.Suppress)); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/DeleteSoftStreetcodeHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/DeleteSoftStreetcodeHandlerTests.cs new file mode 100644 index 000000000..56368702f --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/DeleteSoftStreetcodeHandlerTests.cs @@ -0,0 +1,122 @@ +using System.Linq.Expressions; +using Moq; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.DeleteSoft; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Enums; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class DeleteSoftStreetcodeHandlerTests +{ + private readonly Mock _repositoryMock; + private readonly Mock _mockLogger; + private readonly MockCannotFindLocalizer _mockCannotFindLocalizer; + private readonly MockFailedToUpdateLocalizer _mockFailedToUpdateLocalizer; + private readonly DeleteSoftStreetcodeHandler _handler; + + public DeleteSoftStreetcodeHandlerTests() + { + _repositoryMock = new Mock(); + _mockLogger = new Mock(); + _mockCannotFindLocalizer = new MockCannotFindLocalizer(); + _mockFailedToUpdateLocalizer = new MockFailedToUpdateLocalizer(); + + _handler = new DeleteSoftStreetcodeHandler( + _repositoryMock.Object, + _mockLogger.Object, + _mockCannotFindLocalizer, + _mockFailedToUpdateLocalizer); + } + + [Fact] + public async Task Handle_WhenStreetcodeExists_UpdatesStatusAndUpdatedAt() + { + // Arrange + const int streetcodeId = 1; + var testStreetcode = new StreetcodeContent { Id = streetcodeId, Status = StreetcodeStatus.Published, UpdatedAt = DateTime.UtcNow.AddDays(-1) }; + var previousUpdatedAt = testStreetcode.UpdatedAt; + int testSaveChangesSuccess = 1; + + SetupRepositoryMocks(testStreetcode, testSaveChangesSuccess); + + // Act + var result = await _handler.Handle(new DeleteSoftStreetcodeCommand(streetcodeId), CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.Equal(StreetcodeStatus.Deleted, testStreetcode.Status); + Assert.True(testStreetcode.UpdatedAt > previousUpdatedAt); + _repositoryMock.Verify(repo => repo.StreetcodeRepository.Update(testStreetcode), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenStreetcodeNotFound_ReturnsError() + { + // Arrange + const int streetcodeId = 2; + string expectedErrorKey = "CannotFindAnyStreetcodeWithCorrespondingId"; + string expectedErrorValue = _mockCannotFindLocalizer[expectedErrorKey, streetcodeId]; + + SetupRepositoryMocks(null, 1); + + // Act + var result = await _handler.Handle(new DeleteSoftStreetcodeCommand(streetcodeId), CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorValue, result.Errors.Single().Message); + _mockLogger.Verify(logger => logger.LogError(It.IsAny(), expectedErrorValue), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Never); + }); + } + + [Fact] + public async Task Handle_WhenSaveChangesFails_ReturnsUpdateError() + { + // Arrange + const int streetcodeId = 3; + var testStreetcode = new StreetcodeContent { Id = streetcodeId, Status = StreetcodeStatus.Published }; + string expectedErrorKey = "FailedToChangeStatusOfStreetcodeToDeleted"; + string expectedErrorValue = _mockFailedToUpdateLocalizer[expectedErrorKey]; + + SetupRepositoryMocks(testStreetcode, -1); + + // Act + var result = await _handler.Handle(new DeleteSoftStreetcodeCommand(streetcodeId), CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorValue, result.Errors.Single().Message); + _mockLogger.Verify(logger => logger.LogError(It.IsAny(), expectedErrorValue), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Once); + }); + } + + private void SetupRepositoryMocks(StreetcodeContent? streetcodeContent, int saveChangesVariable) + { + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetFirstOrDefaultAsync(It.IsAny>>(), null)) + .ReturnsAsync(streetcodeContent); + + if (streetcodeContent != null) + { + _repositoryMock.Setup(repo => repo.StreetcodeRepository.Update(streetcodeContent)); + } + + _repositoryMock + .Setup(repo => repo.SaveChangesAsync()) + .ReturnsAsync(saveChangesVariable); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/DeleteStreetcodeFromFavouritesHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/DeleteStreetcodeFromFavouritesHandlerTests.cs new file mode 100644 index 000000000..3379b57cb --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/DeleteStreetcodeFromFavouritesHandlerTests.cs @@ -0,0 +1,145 @@ +using System.Linq.Expressions; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.DeleteFromFavourites; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Streetcode.Favourites; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class DeleteStreetcodeFromFavouritesHandlerTests +{ + private readonly Mock _repository; + private readonly Mock _loggerService; + private readonly Mock _httpContextAccessor; + private readonly MockCannotFindLocalizer _stringLocalizerCannotFind; + private readonly MockFailedToDeleteLocalizer _stringLocalizerFailedToDelete; + + public DeleteStreetcodeFromFavouritesHandlerTests() + { + _repository = new Mock(); + _loggerService = new Mock(); + _httpContextAccessor = new Mock(); + _stringLocalizerCannotFind = new MockCannotFindLocalizer(); + _stringLocalizerFailedToDelete = new MockFailedToDeleteLocalizer(); + } + + [Fact] + public async Task Handle_ReturnsErrorIsNotInFavourites() + { + // Arrange + var userId = Guid.NewGuid().ToString(); + const int streetcodeId = 1; + + SetupFavouritesRepository(); + + SetupStreetcodeRepository(); + + MockHelpers.SetupMockHttpContextAccessor(_httpContextAccessor, userId); + + var errorMsg = _stringLocalizerCannotFind["CannotFindStreetcodeInFavourites"].Value; + + var handler = new DeleteStreetcodeFromFavouritesHandler( + _repository.Object, + _loggerService.Object, + _stringLocalizerCannotFind, + _stringLocalizerFailedToDelete, + _httpContextAccessor.Object); + + // Act + var result = await handler.Handle(new DeleteStreetcodeFromFavouritesCommand(streetcodeId), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.Equal(errorMsg, result.Errors[0].Message), + () => Assert.True(result.IsFailed)); + } + + [Fact] + public async Task Handle_ReturnsErrorFailedToDelete() + { + // Arrange + var userId = Guid.NewGuid().ToString(); + const int streetcodeId = 1; + + SetupStreetcodeRepository(new StreetcodeContent()); + + SetupFavouritesRepository(new Favourite()); + + SetupSaveChanges(0); + + MockHelpers.SetupMockHttpContextAccessor(_httpContextAccessor, userId); + + string expectedErrorMessage = _stringLocalizerFailedToDelete["FailedToDeleteStreetcode"].Value; + + var handler = new DeleteStreetcodeFromFavouritesHandler( + _repository.Object, + _loggerService.Object, + _stringLocalizerCannotFind, + _stringLocalizerFailedToDelete, + _httpContextAccessor.Object); + + // Act + var result = await handler.Handle(new DeleteStreetcodeFromFavouritesCommand(streetcodeId), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.Equal(expectedErrorMessage, result.Errors[0].Message), + () => Assert.True(result.IsFailed)); + } + + [Fact] + public async Task Handle_ReturnsSuccess() + { + // Arrange + var userId = Guid.NewGuid().ToString(); + const int streetcodeId = 1; + + SetupStreetcodeRepository(new StreetcodeContent()); + + SetupFavouritesRepository(new Favourite()); + + SetupSaveChanges(1); + + MockHelpers.SetupMockHttpContextAccessor(_httpContextAccessor, userId); + + var handler = new DeleteStreetcodeFromFavouritesHandler( + _repository.Object, + _loggerService.Object, + _stringLocalizerCannotFind, + _stringLocalizerFailedToDelete, + _httpContextAccessor.Object); + + // Act + var result = await handler.Handle(new DeleteStreetcodeFromFavouritesCommand(streetcodeId), CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + } + + private void SetupSaveChanges(int result) + { + _repository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(result); + } + + private void SetupFavouritesRepository(Favourite? returnValue = null) + { + _repository.Setup(x => x.FavouritesRepository.GetFirstOrDefaultAsync( + It.IsAny>?>(), It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(returnValue); + + _repository.Setup(x => x.FavouritesRepository.Delete(returnValue ?? new Favourite())); + } + + private void SetupStreetcodeRepository(StreetcodeContent? returnValue = null) + { + _repository.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( + It.IsAny>?>(), It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(returnValue); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/DeleteStreetcodeHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/DeleteStreetcodeHandlerTests.cs index 2cb923fa8..98fab1e83 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/DeleteStreetcodeHandlerTests.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/DeleteStreetcodeHandlerTests.cs @@ -1,118 +1,126 @@ using System.Linq.Expressions; using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; using Moq; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Streetcode.Streetcode.Delete; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Streetcode; using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; using Xunit; -namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode -{ - public class DeleteStreetcodeHandlerTests - { - private readonly Mock _repository; - private readonly Mock _mockLogger; - private readonly Mock> mockLocalizerCannotFind; - private readonly Mock> _mockLocalizerFailedToDelete; +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; - public DeleteStreetcodeHandlerTests() - { - this._repository = new Mock(); - this._mockLogger = new Mock(); - this.mockLocalizerCannotFind = new Mock>(); - this._mockLocalizerFailedToDelete = new Mock>(); - } +public class DeleteStreetcodeHandlerTests +{ + private readonly Mock _repositoryMock; + private readonly Mock _mockLogger; + private readonly MockCannotFindLocalizer _mockCannotFindLocalizer; + private readonly MockFailedToDeleteLocalizer _mockFailedToDeleteLocalizer; + private readonly DeleteStreetcodeHandler _handler; - [Theory] - [InlineData(1)] - public async Task Handle_ReturnsSuccess(int id) - { - // Arrange - var testStreetcode = new StreetcodeContent(); - var relatedFigure = new RelatedFigure(); - int testSaveChangesSuccess = 1; + public DeleteStreetcodeHandlerTests() + { + _repositoryMock = new Mock(); + _mockLogger = new Mock(); + _mockCannotFindLocalizer = new MockCannotFindLocalizer(); + _mockFailedToDeleteLocalizer = new MockFailedToDeleteLocalizer(); + + _handler = new DeleteStreetcodeHandler( + _repositoryMock.Object, + _mockLogger.Object, + _mockFailedToDeleteLocalizer, + _mockCannotFindLocalizer); + } - this.RepositorySetup(testStreetcode, relatedFigure, testSaveChangesSuccess); + [Theory] + [InlineData(1)] + public async Task Handle_ReturnsSuccess(int id) + { + // Arrange + var testStreetcode = new StreetcodeContent(); + var relatedFigures = new List(); + const int testSaveChangesSuccess = 1; - var handler = new DeleteStreetcodeHandler(this._repository.Object, this._mockLogger.Object, this._mockLocalizerFailedToDelete.Object, this.mockLocalizerCannotFind.Object); + SetupRepositoryMocks(testStreetcode, relatedFigures, testSaveChangesSuccess); - // Act - var result = await handler.Handle(new DeleteStreetcodeCommand(id), CancellationToken.None); + // Act + var result = await _handler.Handle(new DeleteStreetcodeCommand(id), CancellationToken.None); - // Assert + // Assert + Assert.Multiple(() => + { Assert.True(result.IsSuccess); - } + _repositoryMock.Verify(repo => repo.StreetcodeRepository.Delete(testStreetcode), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Once); + }); + } - [Theory] - [InlineData(1)] - public async Task Handle_ReturnsNullError(int id) - { - // Arrange - string expectedErrorMessage = $"Cannot find a streetcode with corresponding categoryId: {id}"; - this.mockLocalizerCannotFind.Setup(x => x[It.IsAny(), It.IsAny()]) - .Returns((string key, object[] args) => - { - if (args != null && args.Length > 0 && args[0] is int id) - { - return new LocalizedString(key, $"Cannot find a streetcode with corresponding categoryId: {id}"); - } - - return new LocalizedString(key, "Cannot find any streetcode with unknown categoryId"); - }); - - int testSaveChangesSuccess = 1; - var relatedFigure = new RelatedFigure(); - - this.RepositorySetup(null!, relatedFigure, testSaveChangesSuccess); - var handler = new DeleteStreetcodeHandler(this._repository.Object, this._mockLogger.Object, this._mockLocalizerFailedToDelete.Object, this.mockLocalizerCannotFind.Object); - - // Act - var result = await handler.Handle(new DeleteStreetcodeCommand(id), CancellationToken.None); - - // Assert - Assert.Equal(expectedErrorMessage, result.Errors.Single().Message); - } + [Theory] + [InlineData(1)] + public async Task Handle_ReturnsNullError(int id) + { + // Arrange + const string expectedErrorKey = "CannotFindAnyStreetcodeWithCorrespondingId"; + string expectedErrorValue = _mockCannotFindLocalizer[expectedErrorKey, id]; - [Theory] - [InlineData(1)] - public async Task Handle_ReturnsSaveAsyncError(int id) - { - // Arrange - var testStreetcode = new StreetcodeContent(); - string expectedErrorMessage = "Failed to delete a streetcode"; - this._mockLocalizerFailedToDelete.Setup(x => x["FailedToDeleteStreetcode"]) - .Returns(new LocalizedString("FailedToDeleteStreetcode", expectedErrorMessage)); + SetupRepositoryMocks(null, new List(), 1); - int testSaveChangesFailed = -1; - var relatedFigure = new RelatedFigure(); + // Act + var result = await _handler.Handle(new DeleteStreetcodeCommand(id), CancellationToken.None); - this.RepositorySetup(testStreetcode, relatedFigure, testSaveChangesFailed); + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorValue, result.Errors.Single().Message); + _mockLogger.Verify(logger => logger.LogError(It.IsAny(), expectedErrorValue), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Never); + }); + } - var handler = new DeleteStreetcodeHandler(this._repository.Object, this._mockLogger.Object, this._mockLocalizerFailedToDelete.Object, this.mockLocalizerCannotFind.Object); + [Theory] + [InlineData(1)] + public async Task Handle_ReturnsSaveAsyncError(int id) + { + // Arrange + var testStreetcode = new StreetcodeContent(); + const string expectedErrorKey = "FailedToDeleteStreetcode"; + string expectedErrorValue = _mockFailedToDeleteLocalizer[expectedErrorKey]; - // Act - var result = await handler.Handle(new DeleteStreetcodeCommand(id), CancellationToken.None); + SetupRepositoryMocks(testStreetcode, new List(), -1); - // Assert - Assert.Equal(expectedErrorMessage, result.Errors.Single().Message); - } + // Act + var result = await _handler.Handle(new DeleteStreetcodeCommand(id), CancellationToken.None); - private void RepositorySetup(StreetcodeContent streetcodeContent, RelatedFigure relatedFigure, int saveChangesVariable) + // Assert + Assert.Multiple(() => { - this._repository.Setup(x => x.StreetcodeRepository.Delete(streetcodeContent)); - this._repository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(saveChangesVariable); - this._repository.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( + Assert.False(result.IsSuccess); + Assert.Equal(expectedErrorValue, result.Errors.Single().Message); + _mockLogger.Verify(logger => logger.LogError(It.IsAny(), expectedErrorValue), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Once); + }); + } + + private void SetupRepositoryMocks(StreetcodeContent? streetcodeContent, List relatedFigures, int saveChangesVariable) + { + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetFirstOrDefaultAsync( It.IsAny>>(), - It.IsAny, IIncludableQueryable>>())).ReturnsAsync(streetcodeContent); + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(streetcodeContent); - this._repository.Setup(x => x.RelatedFigureRepository.Delete(relatedFigure)); - this._repository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(saveChangesVariable); - this._repository.Setup(x => x.RelatedFigureRepository.GetFirstOrDefaultAsync( - It.IsAny>>(), - It.IsAny, IIncludableQueryable>>())).ReturnsAsync(relatedFigure); + _repositoryMock + .Setup(repo => repo.RelatedFigureRepository.GetAllAsync(It.IsAny>>(), null)) + .ReturnsAsync(relatedFigures); + + if (streetcodeContent != null) + { + _repositoryMock.Setup(repo => repo.StreetcodeRepository.Delete(streetcodeContent)); } + + _repositoryMock + .Setup(repo => repo.SaveChangesAsync()) + .ReturnsAsync(saveChangesVariable); } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllPublishedHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllPublishedHandlerTests.cs new file mode 100644 index 000000000..371904dce --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllPublishedHandlerTests.cs @@ -0,0 +1,107 @@ +using AutoMapper; +using Moq; +using Streetcode.BLL.DTO.Streetcode; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllPublished; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Enums; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class GetAllPublishedHandlerTests +{ + private readonly Mock _repositoryMock; + private readonly Mock _mapperMock; + private readonly Mock _loggerMock; + private readonly MockNoSharedResourceLocalizer _mockNoSharedResourceLocalizer; + private readonly GetAllPublishedHandler _handler; + + public GetAllPublishedHandlerTests() + { + _repositoryMock = new Mock(); + _mapperMock = new Mock(); + _loggerMock = new Mock(); + _mockNoSharedResourceLocalizer = new MockNoSharedResourceLocalizer(); + + _handler = new GetAllPublishedHandler( + _repositoryMock.Object, + _mapperMock.Object, + _loggerMock.Object, + _mockNoSharedResourceLocalizer); + } + + [Fact] + public async Task Handle_WhenPublishedStreetcodesExist_ReturnsStreetcodeShortDTOs() + { + // Arrange + var testStreetcodes = GetTestStreetcodes(3); + GetAllPublishedQuery query = new GetAllPublishedQuery(); + + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetAllAsync( + sc => sc.Status == StreetcodeStatus.Published, null)) + .ReturnsAsync(testStreetcodes); + + SetupMocks(testStreetcodes); + + // Act + var result = await _handler.Handle(query, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.Equal(testStreetcodes.Count, result.Value.Count()); + _repositoryMock.Verify(repo => repo.StreetcodeRepository.GetAllAsync(sc => sc.Status == StreetcodeStatus.Published, null), Times.Once); + _mapperMock.Verify(m => m.Map>(testStreetcodes), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenNoPublishedStreetcodesExist_ReturnsError() + { + // Arrange + const string expectedErrorKey = "NoStreetcodesExistNow"; + string expectedErrorValue = _mockNoSharedResourceLocalizer[expectedErrorKey]; + var query = new GetAllPublishedQuery(); + + SetupMocks(null); + + // Act + var result = await _handler.Handle(query, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorValue, result.Errors.Single().Message); + _loggerMock.Verify(logger => logger.LogError(query, expectedErrorValue), Times.Once); + }); + } + + private static List GetTestStreetcodes(int count) + { + return Enumerable.Range(1, count) + .Select(i => new StreetcodeContent { Id = i, Status = StreetcodeStatus.Published }) + .ToList(); + } + + private void SetupMocks(List? streetcodes) + { + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetAllAsync( + sc => sc.Status == StreetcodeStatus.Published, null)) + .ReturnsAsync(streetcodes!); + + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((IEnumerable src) => + src.Select(s => new StreetcodeShortDTO() + { + Id = s.Id, + }).ToList()); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodeFavouritesHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodeFavouritesHandlerTests.cs new file mode 100644 index 000000000..c8e583ada --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodeFavouritesHandlerTests.cs @@ -0,0 +1,131 @@ +using System.Linq.Expressions; +using AutoMapper; +using FluentResults; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.DTO.Streetcode; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllFavourites; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Enums; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class GetAllStreetcodeFavouritesHandlerTests +{ + private readonly Mock _repository; + private readonly Mock _mapper; + private readonly Mock _mockLogger; + private readonly Mock _httpContextAccessor; + private readonly MockNoSharedResourceLocalizer _stringLocalizerNo; + + public GetAllStreetcodeFavouritesHandlerTests() + { + _repository = new Mock(); + _mapper = new Mock(); + _mockLogger = new Mock(); + _httpContextAccessor = new Mock(); + _stringLocalizerNo = new MockNoSharedResourceLocalizer(); + } + + [Fact] + public async Task Handle_ReturnsBadRequest() + { + // Arrange + const string userId = "mockId"; + + SetupRepository(new List()); + var expectedError = _stringLocalizerNo["NoFavouritesFound"].Value; + + MockHelpers.SetupMockHttpContextAccessor(_httpContextAccessor, userId); + + var handler = new GetAllStreetcodeFavouritesHandler(_mapper.Object, _repository.Object, _mockLogger.Object, _stringLocalizerNo, _httpContextAccessor.Object); + + // Act + var result = await handler.Handle(new GetAllStreetcodeFavouritesQuery(), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.Equal(expectedError, result.Errors[0].Message), + () => Assert.True(result.IsFailed)); + } + + [Fact] + public async Task Handle_ReturnsSuccessWithNotFilteredStreetcodes() + { + // Arrange + const string userId = "mockId"; + + SetupRepository(new List + { + new (), + }); + SetupMapper(new List + { + new (), + }); + + MockHelpers.SetupMockHttpContextAccessor(_httpContextAccessor, userId); + + var handler = new GetAllStreetcodeFavouritesHandler(_mapper.Object, _repository.Object, _mockLogger.Object, _stringLocalizerNo, _httpContextAccessor.Object); + + // Act + var result = await handler.Handle(new GetAllStreetcodeFavouritesQuery(), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.IsType>>(result), + () => Assert.IsAssignableFrom>(result.Value), + () => Assert.NotEmpty(result.Value)); + } + + [Fact] + public async Task Handle_ReturnsSuccessWithFilteredStreetcodes() + { + // Arrange + const string userId = "mockId"; + + SetupRepository(new List + { + new (), + }); + SetupMapper(new List + { + new (), + }); + + MockHelpers.SetupMockHttpContextAccessor(_httpContextAccessor, userId); + + var handler = new GetAllStreetcodeFavouritesHandler(_mapper.Object, _repository.Object, _mockLogger.Object, _stringLocalizerNo, _httpContextAccessor.Object); + + StreetcodeType type = StreetcodeType.Person; + + // Act + var result = await handler.Handle(new GetAllStreetcodeFavouritesQuery(type), CancellationToken.None); + + // Assert + foreach (var streetcode in result.Value) + { + Assert.Equal(streetcode.Type, StreetcodeType.Person); + } + } + + private void SetupRepository(List returnList) + { + _repository.Setup(repo => repo.StreetcodeRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, + IIncludableQueryable>>())) + .ReturnsAsync(returnList); + } + + private void SetupMapper(List returnList) + { + _mapper.Setup(x => x.Map>(It.IsAny>())) + .Returns(returnList); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodesCatalogHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodesCatalogHandlerTests.cs new file mode 100644 index 000000000..b499081f7 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodesCatalogHandlerTests.cs @@ -0,0 +1,177 @@ +using System.Linq.Expressions; +using AutoMapper; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.DTO.Streetcode.CatalogItem; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllCatalog; +using Streetcode.DAL.Entities.Media.Images; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Enums; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class GetAllStreetcodesCatalogHandlerTests +{ + private readonly Mock _repositoryMock; + private readonly Mock _mapperMock; + private readonly Mock _mockLogger; + private readonly MockNoSharedResourceLocalizer _mockNoStreetcodesLocalizer; + private readonly GetAllStreetcodesCatalogHandler _handler; + + public GetAllStreetcodesCatalogHandlerTests() + { + _repositoryMock = new Mock(); + _mapperMock = new Mock(); + _mockLogger = new Mock(); + _mockNoStreetcodesLocalizer = new MockNoSharedResourceLocalizer(); + + _handler = new GetAllStreetcodesCatalogHandler( + _repositoryMock.Object, + _mapperMock.Object, + _mockLogger.Object, + _mockNoStreetcodesLocalizer); + } + + [Fact] + public async Task Handle_WhenStreetcodesExist_ReturnsPagedCatalogItems() + { + // Arrange + var request = new GetAllStreetcodesCatalogQuery(Page: 1, Count: 2); + var testStreetcodes = GetTestStreetcodes(5); + + SetupMocksForStreetcodeCatalogHandler(testStreetcodes); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.Equal(request.Count, result.Value.Count()); + Assert.Equal(1, result.Value.ElementAt(0).Id); + Assert.Equal(2, result.Value.ElementAt(1).Id); + _repositoryMock.Verify( + repo => repo.StreetcodeRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>()), Times.Once); + _mapperMock.Verify(m => m.Map>(It.IsAny>()), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenNoStreetcodesExist_ReturnsError() + { + // Arrange + var request = new GetAllStreetcodesCatalogQuery(Page: 1, Count: 2); + string expectedErrorKey = "NoStreetcodesExistNow"; + string expectedErrorValue = _mockNoStreetcodesLocalizer[expectedErrorKey]; + + SetupMocksForStreetcodeCatalogHandler(new List()); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorValue, result.Errors.Single().Message); + _mockLogger.Verify(logger => logger.LogError(request, expectedErrorValue), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenStreetcodesExist_FiltersImagesByKeyNumOfImageToDisplay() + { + // Arrange + var request = new GetAllStreetcodesCatalogQuery(Page: 1, Count: 2); + const int keyNumOfImageToDisplay = (int)ImageAssigment.Blackandwhite; + + var testStreetcodes = new List + { + new () + { + Id = 1, + Images = new List + { + new () { ImageDetails = new ImageDetails { Alt = keyNumOfImageToDisplay.ToString() } }, + new () { ImageDetails = new ImageDetails { Alt = "WrongValue" } }, + }, + }, + new () + { + Id = 2, + Images = new List + { + new () { ImageDetails = new ImageDetails { Alt = keyNumOfImageToDisplay.ToString() } }, + new () { ImageDetails = null }, + }, + }, + }; + + SetupMocksForStreetcodeCatalogHandler(testStreetcodes); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + Assert.Equal(request.Count, result.Value.Count()); + + foreach (var streetcode in testStreetcodes) + { + Assert.All(streetcode.Images, image => + { + Assert.NotNull(image.ImageDetails); + if (image.ImageDetails is not null) + { + Assert.Equal(keyNumOfImageToDisplay.ToString(), image.ImageDetails.Alt); + } + }); + } + } + + private static List GetTestStreetcodes(int count) + { + var streetcodes = new List(); + for (int i = 1; i <= count; i++) + { + streetcodes.Add(new StreetcodeContent + { + Id = i, + Status = StreetcodeStatus.Published, + Images = new List + { + new () + { + ImageDetails = new ImageDetails { Alt = ((int)ImageAssigment.Blackandwhite).ToString() }, + }, + }, + }); + } + + return streetcodes; + } + + private void SetupMocksForStreetcodeCatalogHandler(List streetcodes) + { + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(streetcodes); + + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((IEnumerable src) => + src.Select(s => new CatalogItem() + { + Id = s.Id, + }).ToList()); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodesHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodesHandlerTests.cs index 28411b587..4836ef67c 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodesHandlerTests.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodesHandlerTests.cs @@ -1,169 +1,574 @@ -using System.Linq.Expressions; using System.Reflection; using AutoMapper; +using FluentResults; using Moq; using Streetcode.BLL.DTO.Streetcode; -using Streetcode.BLL.DTO.Streetcode.Types; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAll; using Streetcode.DAL.Entities.Streetcode; using Streetcode.DAL.Repositories.Interfaces.Base; using Streetcode.DAL.Repositories.Interfaces.Streetcode; +using Streetcode.XUnitTest.Mocks; using Xunit; using Model = Streetcode.DAL.Entities.Streetcode.StreetcodeContent; -namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class GetAllStreetcodesHandlerTests { - public class GetAllStreetcodesHandlerTests + private readonly Mock _repositoryWrapperMock; + private readonly Mock _streetcodeRepositoryMock; + private readonly Mock _mapper; + private readonly Mock _logger; + private readonly MockCannotFindLocalizer _mockCannotFindLocalizer; + private readonly MockFailedToValidateLocalizer _mockFailedToValidateLocalizer; + + public GetAllStreetcodesHandlerTests() { - private readonly Mock repository; - private readonly Mock mapper; - private readonly Mock mockLogger; + _streetcodeRepositoryMock = new Mock(); + _logger = new Mock(); + _mockCannotFindLocalizer = new MockCannotFindLocalizer(); + _repositoryWrapperMock = new Mock(); + _mapper = new Mock(); + _mockFailedToValidateLocalizer = new MockFailedToValidateLocalizer(); + } - public GetAllStreetcodesHandlerTests() + [Fact] + public async Task Handle_ReturnsSuccess() + { + // Arrange + var mockStreetcodes = new List { - this.repository = new Mock(); - this.mapper = new Mock(); - this.mockLogger = new Mock(); - } + new () { Id = 1, Title = "Title 1" }, + new () { Id = 2, Title = "Title 2" }, + }; + + var request = new GetAllStreetcodesRequestDTO(); + var query = new GetAllStreetcodesQuery(request); + var handler = SetupMockObjectsAndGetHandler(mockStreetcodes); + + // Act + var result = await handler.Handle(query, CancellationToken.None); - [Fact] - public async Task Handle_ReturnsSuccess() + // Assert + Assert.Multiple(() => { - // Arrange - var testModel = new Model(); - var testDTO = new PersonStreetcodeDTO(); + Assert.NotNull(result); + Assert.True(result.IsSuccess); + Assert.NotNull(result.Value); + Assert.NotEmpty(result.Value.Streetcodes); + Assert.IsAssignableFrom(result.Value); + Assert.Equal(2, result.Value.TotalAmount); + }); + } - this.repository.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync(It.IsAny>>(), null)) - .ReturnsAsync(testModel); + [Fact] + public async Task Handle_ReturnsSuccess_And_CorrectPaginationParams() + { + // Arrange + var mockStreetcodes = new List + { + new () { Id = 1, Title = "Title 1" }, + new () { Id = 2, Title = "Title 2" }, + }; - this.mapper.Setup(x => x.Map(It.IsAny())) - .Returns(testDTO); + var request = new GetAllStreetcodesRequestDTO { Page = 1, Amount = 1 }; + var query = new GetAllStreetcodesQuery(request); - var request = new GetAllStreetcodesRequestDTO(); + var handler = SetupMockObjectsAndGetHandler(mockStreetcodes); - var handler = new GetAllStreetcodesHandler(this.repository.Object, this.mapper.Object); + // Act + var result = await handler.Handle(query, CancellationToken.None); - // Act - var result = await handler.Handle(new GetAllStreetcodesQuery(request), CancellationToken.None); + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + Assert.NotNull(result.Value); + Assert.NotEmpty(result.Value.Streetcodes); + Assert.IsAssignableFrom(result.Value); + Assert.Equal(mockStreetcodes.Count, result.Value.TotalAmount); + Assert.InRange(result.Value.Streetcodes.Count(), 0, request.Amount.Value); + Assert.Single(result.Value.Streetcodes); + }); + } - // Assert + [Fact] + public async Task Handle_ReturnsSuccess_WhenNoStreetcodesExist() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO { Page = 1, Amount = 5 }; + var query = new GetAllStreetcodesQuery(request); + var handler = SetupMockObjectsAndGetHandler(); + + // Act + var result = await handler.Handle(query, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { Assert.NotNull(result); - } + Assert.True(result.IsSuccess); + Assert.NotNull(result.Value); + Assert.Empty(result.Value.Streetcodes); + Assert.IsAssignableFrom(result.Value); + Assert.Equal(0, result.Value.TotalAmount); + }); + } - [Fact] - public async Task Handle_ReturnsCorrectType() + [Fact] + public async Task Handle_AppliesPagination_Correctly() + { + // Arrange + var mockStreetcodes = new List { - // Arrange - var testModelList = new List(); - var testDTOList = new List(); + new () { Id = 1, Title = "Title 1" }, + new () { Id = 2, Title = "Title 2" }, + new () { Id = 3, Title = "Title 3" }, + new () { Id = 4, Title = "Title 4" }, + }; + + var request = new GetAllStreetcodesRequestDTO { Page = 2, Amount = 2 }; + var query = new GetAllStreetcodesQuery(request); + var handler = SetupMockObjectsAndGetHandler(mockStreetcodes); - this.repository.Setup(x => x.StreetcodeRepository.GetAllAsync(It.IsAny>>(), null)) - .ReturnsAsync(testModelList); + // Act + var result = await handler.Handle(query, CancellationToken.None); - this.mapper.Setup(x => x.Map>(It.IsAny>())) - .Returns(testDTOList); + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + Assert.NotNull(result.Value); + Assert.NotEmpty(result.Value.Streetcodes); + Assert.Equal(2, result.Value.Streetcodes.Count()); + Assert.Equal(mockStreetcodes[2].Id, result.Value.Streetcodes.First().Id); + Assert.Equal(mockStreetcodes[3].Id, result.Value.Streetcodes.Last().Id); + }); + } - var handler = new GetAllStreetcodesHandler(this.repository.Object, this.mapper.Object); + [Fact] + public async Task Handle_ReturnSuccess_And_StreetCodesWithMatchTitle() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO + { + Title = "Some Title", + }; - var request = new GetAllStreetcodesRequestDTO(); + var query = new GetAllStreetcodesQuery(request); + + var mockStreetcodes = new List + { + new () { Id = 1, Title = "Some Title" }, + new () { Id = 2, Title = "Some Title" }, + new () { Id = 3, Title = "Another Title" }, + }; - // Act - var result = await handler.Handle(new GetAllStreetcodesQuery(request), CancellationToken.None); + var handler = SetupMockObjectsAndGetHandler(mockStreetcodes); - // Assert + // Act + var result = await handler.Handle(query, default); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); Assert.IsAssignableFrom(result.Value); - } + Assert.NotNull(result.Value); + Assert.NotNull(result.Value.Streetcodes); + Assert.Equal(2, result.Value.Streetcodes.Count()); + Assert.Equal(2, result.Value.TotalAmount); + }); + } - [Fact] - public async Task FindStreetCodeWithMatchTitleTest() + [Fact] + public async Task Handle_ReturnEmptyList_WhenTitleDoesNotExist() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO { - // Arrange - var request = new GetAllStreetcodesRequestDTO - { - Title = "Some Title", - }; + Title = "Some Title", + }; + + var query = new GetAllStreetcodesQuery(request); - var query = new GetAllStreetcodesQuery(request); + var mockStreetcodes = new List + { + new () { Id = 1, Title = "Another Title" }, + }; - var (handler, _) = this.SetupMockObjectsAndGetHandler(out var streetcodeRepositoryMock, out var mapperMock); + var handler = SetupMockObjectsAndGetHandler(mockStreetcodes); - // Act - var result = await handler.Handle(query, default); + // Act + var result = await handler.Handle(query, default); - // Assert + // Assert + Assert.Multiple(() => + { Assert.NotNull(result); Assert.True(result.IsSuccess); + Assert.IsAssignableFrom(result.Value); Assert.NotNull(result.Value); Assert.NotNull(result.Value.Streetcodes); - } + Assert.Equal(0, result.Value.TotalAmount); + }); + } - [Fact] - public void FindSortedStreetcodesTest() + [Fact] + public async Task Handle_ReturnSortedStreetcodes() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO { - // Arrange - var request = new GetAllStreetcodesRequestDTO - { - Sort = "-Title", - }; + Sort = "-Title", + }; - var (handler, _) = this.SetupMockObjectsAndGetHandler(out var streetcodeRepositoryMock, out var mapperMock); + var query = new GetAllStreetcodesQuery(request); - var streetcodes = new List - { - new StreetcodeContent { Id = 1, Title = "Streetcode 1" }, - new StreetcodeContent { Id = 2, Title = "Streetcode 2" }, - new StreetcodeContent { Id = 3, Title = "Streetcode 3" }, - }.AsQueryable(); + var mockStreetcodes = new List + { + new () { Id = 1, Title = "Streetcode 1" }, + new () { Id = 2, Title = "Streetcode 2" }, + new () { Id = 3, Title = "Streetcode 3" }, + }; - // Assert - var methodInfo = typeof(GetAllStreetcodesHandler).GetMethod("FindSortedStreetcodes", BindingFlags.NonPublic | BindingFlags.Instance); - var parameters = new object[] { streetcodes, request.Sort }; + var handler = SetupMockObjectsAndGetHandler(mockStreetcodes); - methodInfo?.Invoke(handler, parameters); - var sortedStreetcodes = (IQueryable)parameters[0]; + // Act + var result = await handler.Handle(query, default); - // Act - var resultList = sortedStreetcodes.ToList(); + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + Assert.IsAssignableFrom(result.Value); + Assert.NotNull(result.Value); + Assert.NotNull(result.Value.Streetcodes); + Assert.Equal(3, result.Value.TotalAmount); + var resultList = result.Value.Streetcodes.ToList(); Assert.Equal("Streetcode 3", resultList[0].Title); Assert.Equal("Streetcode 2", resultList[1].Title); Assert.Equal("Streetcode 1", resultList[2].Title); - } + }); + } + + [Fact] + public async Task Handle_ReturnsError_WhenIncorrectSortColum() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO + { + Sort = "-IncorrectSortColumn", + }; + + var query = new GetAllStreetcodesQuery(request); + + var mockStreetcodes = new List + { + new () { Id = 1, Title = "Streetcode 1" }, + new () { Id = 2, Title = "Streetcode 2" }, + }; + + var handler = SetupMockObjectsAndGetHandler(mockStreetcodes); + var expectedErrorMessage = _mockCannotFindLocalizer["CannotFindAnyPropertyWithThisName"]; + + // Act + var result = await handler.Handle(query, default); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsFailed); + Assert.Contains(expectedErrorMessage, result.Errors.Single().Message); + }); + } + + [Fact] + public void FindSortedStreetcodes_ReturnsSortedStreetcodes() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO + { + Sort = "-Title", + }; + + var handler = SetupMockObjectsAndGetHandler(); + + var streetcodes = new List + { + new () { Id = 1, Title = "Streetcode 1" }, + new () { Id = 2, Title = "Streetcode 2" }, + new () { Id = 3, Title = "Streetcode 3" }, + }.AsQueryable(); + + // Assert + var methodInfo = typeof(GetAllStreetcodesHandler).GetMethod("FindSortedStreetcodes", BindingFlags.NonPublic | BindingFlags.Static); + var parameters = new object[] { streetcodes, request.Sort }; + methodInfo?.Invoke(handler, parameters); + var sortedStreetcodes = (IQueryable)parameters[0]; + + // Act + var resultList = sortedStreetcodes.ToList(); + Assert.Multiple(() => + { + Assert.Equal("Streetcode 3", resultList[0].Title); + Assert.Equal("Streetcode 2", resultList[1].Title); + Assert.Equal("Streetcode 1", resultList[2].Title); + }); + } + + [Fact] + public void FindSortedStreetcodes_ReturnsError_WhenIncorrectSortColum() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO + { + Sort = "-IncorrectSortColumn", + }; + + var handler = SetupMockObjectsAndGetHandler(); - [Fact] - public void FindFilteredStreetcodesTest() + var streetcodes = new List + { + new () { Id = 1, Title = "Streetcode 1" }, + new () { Id = 2, Title = "Streetcode 2" }, + }.AsQueryable(); + const string expectedErrorMessage = "CannotFindAnyPropertyWithThisName"; + + // Act + MethodInfo? methodInfo = typeof(GetAllStreetcodesHandler).GetMethod("FindSortedStreetcodes", BindingFlags.NonPublic | BindingFlags.Static); + var parameters = new object[] { streetcodes, request.Sort }; + var result = methodInfo?.Invoke(handler, parameters); + + // Assert + Assert.Multiple(() => { - // Arrange - var request = new GetAllStreetcodesRequestDTO - { - Filter = "filter:Filter", - }; + Assert.NotNull(result); + var typedResult = (Result)result; + Assert.True(typedResult.IsFailed); + Assert.Contains(expectedErrorMessage, typedResult.Errors.Single().Message); + }); + } - var (handler, _) = this.SetupMockObjectsAndGetHandler(out var streetcodeRepositoryMock, out var mapperMock); - var streetcodes = new List().AsQueryable(); + [Fact] + public void FindFilteredStreetcodes_ReturnsFilteredStreetcodes() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO + { + Filter = "Teaser:Streetcode", + }; - // Act - var findFilteredStreetcodesMethod = typeof(GetAllStreetcodesHandler).GetMethod("FindFilteredStreetcodes", BindingFlags.NonPublic | BindingFlags.Instance); - findFilteredStreetcodesMethod?.Invoke(handler, new object[] { streetcodes, request.Filter }); + var handler = SetupMockObjectsAndGetHandler(); - // Assert - Assert.Empty(streetcodes); - } + var streetcodes = new List + { + new () { Id = 1, Teaser = "Streetcode 1" }, + new () { Id = 2, Teaser = "Streetcode 2" }, + }.AsQueryable(); + + // Act + var methodInfo = typeof(GetAllStreetcodesHandler).GetMethod("FindFilteredStreetcodes", BindingFlags.NonPublic | BindingFlags.Instance); + var parameters = new object[] { streetcodes, request.Filter }; + methodInfo?.Invoke(handler, parameters); + var filteredStreetcodes = (IQueryable)parameters[0]; + + // Assert + var resultList = filteredStreetcodes.ToList(); + Assert.Multiple(() => + { + Assert.Equal("Streetcode 1", resultList[0].Teaser); + Assert.Equal("Streetcode 2", resultList[1].Teaser); + }); + } - private (GetAllStreetcodesHandler handler, Mock repositoryWrapperMock) SetupMockObjectsAndGetHandler(out Mock streetcodeRepositoryMock, out Mock mapperMock) + [Fact] + public void FindFilteredStreetcodes_ReturnsError_WhenIncorrectFilterColum() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO { - var repositoryWrapperMock = new Mock(); - streetcodeRepositoryMock = new Mock(); - mapperMock = new Mock(); + Filter = "IncorrectTeaser:Streetcode", + }; + + var handler = SetupMockObjectsAndGetHandler(); + + var streetcodes = new List + { + new () { Id = 1, Teaser = "Streetcode 1" }, + }.AsQueryable(); + + // Act + MethodInfo? methodInfo = typeof(GetAllStreetcodesHandler).GetMethod("FindFilteredStreetcodes", BindingFlags.NonPublic | BindingFlags.Static); + var parameters = new object[] { streetcodes, request.Filter }; + var result = methodInfo?.Invoke(handler, parameters); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + var typedResult = (Result)result; + Assert.True(typedResult.IsFailed); + }); + } + + [Fact] + public async Task Handle_ReturnFilteredStreetcodes() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO + { + Filter = "Teaser:Teaser", + }; + + var query = new GetAllStreetcodesQuery(request); + + var mockStreetcodes = new List + { + new () { Id = 1, Teaser = "Streetcode 1" }, + new () { Id = 2, Teaser = "Teaser" }, + }; + + var handler = SetupMockObjectsAndGetHandler(mockStreetcodes); + + // Act + var result = await handler.Handle(query, default); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + Assert.IsAssignableFrom(result.Value); + Assert.NotNull(result.Value); + Assert.NotNull(result.Value.Streetcodes); + Assert.Equal(1, result.Value.TotalAmount); + var resultList = result.Value.Streetcodes.ToList(); + Assert.Equal("Teaser", resultList[0].Teaser); + }); + } + + [Fact] + public async Task Handle_ReturnsError_WhenIncorrectFilterColumn() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO + { + Filter = "IncorrectTeaser:Teaser", + }; + + var query = new GetAllStreetcodesQuery(request); + + var mockStreetcodes = new List + { + new () { Id = 1, Teaser = "Streetcode 1" }, + }; + + var handler = SetupMockObjectsAndGetHandler(mockStreetcodes); + + // Act + var result = await handler.Handle(query, default); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsFailed); + }); + } + + [Fact] + public async Task Handle_ReturnsSuccess_And_EmptyList_WhenFilterValueDoesNotExist() + { + // Arrange + var request = new GetAllStreetcodesRequestDTO + { + Filter = "Teaser:NonExistingFilterValue", + }; + + var query = new GetAllStreetcodesQuery(request); + + var mockStreetcodes = new List + { + new () { Id = 1, Teaser = "Streetcode 1" }, + }; + + var handler = SetupMockObjectsAndGetHandler(mockStreetcodes); + + // Act + var result = await handler.Handle(query, default); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsSuccess); + Assert.IsAssignableFrom(result.Value); + Assert.NotNull(result.Value); + Assert.NotNull(result.Value.Streetcodes); + Assert.Equal(0, result.Value.TotalAmount); + }); + } + + [Theory] + [InlineData(-10, 9)] + [InlineData(1, -5)] + [InlineData(0, 0)] + public async Task Handle_ReturnsError_WhenInvalidPaginationParams(int page, int amount) + { + // Arrange + var request = new GetAllStreetcodesRequestDTO + { + Page = page, + Amount = amount, + }; + var expectedErrorMessage = _mockFailedToValidateLocalizer["InvalidPaginationParameters"]; + var query = new GetAllStreetcodesQuery(request); + var handler = SetupMockObjectsAndGetHandler(); + + // Act + var result = await handler.Handle(query, default); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(result); + Assert.True(result.IsFailed); + Assert.Contains(expectedErrorMessage, result.Errors.Single().Message); + }); + } + + private GetAllStreetcodesHandler SetupMockObjectsAndGetHandler(IEnumerable? mockStreetcodes = null) + { + mockStreetcodes ??= new List(); + + _streetcodeRepositoryMock + .Setup(repo => repo.FindAll(null, null)) + .Returns(mockStreetcodes.AsQueryable()); + + _repositoryWrapperMock + .Setup(x => x.StreetcodeRepository) + .Returns(_streetcodeRepositoryMock.Object); - repositoryWrapperMock - .Setup(x => x.StreetcodeRepository) - .Returns(streetcodeRepositoryMock.Object); + _mapper + .Setup(x => x.Map>(It.IsAny>())) + .Returns((IEnumerable src) => + src.Select(s => new StreetcodeDTO + { + Id = s.Id, + Title = s.Title!, + Teaser = s.Teaser!, + }).ToList()); - var handler = new GetAllStreetcodesHandler(repositoryWrapperMock.Object, mapperMock.Object); + var handler = new GetAllStreetcodesHandler(_repositoryWrapperMock.Object, _mapper.Object, _logger.Object, _mockCannotFindLocalizer, _mockFailedToValidateLocalizer); - return (handler, repositoryWrapperMock); - } + return handler; } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodesMainPageHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodesMainPageHandlerTests.cs new file mode 100644 index 000000000..206dee6a4 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodesMainPageHandlerTests.cs @@ -0,0 +1,137 @@ +using System.Linq.Expressions; +using AutoMapper; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.DTO.Streetcode; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllMainPage; +using Streetcode.DAL.Entities.Media.Images; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Enums; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class GetAllStreetcodesMainPageHandlerTests +{ + private readonly Mock _repositoryMock; + private readonly Mock _mapperMock; + private readonly Mock _loggerMock; + private readonly MockNoSharedResourceLocalizer _mockLocalizer; + private readonly GetAllStreetcodesMainPageHandler _handler; + private List _testStreetcodes; + + public GetAllStreetcodesMainPageHandlerTests() + { + _testStreetcodes = new List(); + _repositoryMock = new Mock(); + _mapperMock = new Mock(); + _loggerMock = new Mock(); + _mockLocalizer = new MockNoSharedResourceLocalizer(); + + _handler = new GetAllStreetcodesMainPageHandler( + _repositoryMock.Object, + _mapperMock.Object, + _loggerMock.Object, + _mockLocalizer); + + SetupMocks(5); + } + + [Fact] + public async Task Handle_WhenStreetcodesExist_ReturnsShuffledMainPageDTOs() + { + // Arrange + var request = new GetAllStreetcodesMainPageQuery(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.Equal(_testStreetcodes.Count, result.Value.Count()); + _repositoryMock.Verify( + repo => repo.StreetcodeRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, + IIncludableQueryable>>()), Times.Once); + _mapperMock.Verify( + m => m.Map>(It.IsAny>()), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenNoStreetcodesExist_ReturnsError() + { + // Arrange + var request = new GetAllStreetcodesMainPageQuery(); + const string expectedErrorKey = "NoStreetcodesExistNow"; + string expectedErrorValue = _mockLocalizer[expectedErrorKey]; + + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(new List()); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorValue, result.Errors.Single().Message); + _loggerMock.Verify(logger => logger.LogError(request, expectedErrorValue), Times.Once); + }); + } + + [Fact] + public async Task Handle_FiltersImagesCorrectly() + { + // Arrange + var request = new GetAllStreetcodesMainPageQuery(); + + // Act + await _handler.Handle(request, CancellationToken.None); + + // Assert + foreach (var streetcode in _testStreetcodes) + { + Assert.All(streetcode.Images, image => + { + Assert.NotNull(image.ImageDetails); + Assert.Equal(((int)ImageAssigment.Blackandwhite).ToString(), image.ImageDetails.Alt); + }); + } + } + + private void SetupMocks(int count) + { + _testStreetcodes = Enumerable.Range(1, count).Select(i => new StreetcodeContent + { + Id = i, + Status = StreetcodeStatus.Published, + Images = new List + { + new () { ImageDetails = new ImageDetails { Alt = "1" } }, + new () { ImageDetails = new ImageDetails { Alt = "WrongValue" } }, + }, + }).ToList(); + + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(_testStreetcodes); + + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((IEnumerable src) => + src.Select(s => new StreetcodeMainPageDTO { Id = s.Id }).ToList()); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodesShortHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodesShortHandlerTests.cs new file mode 100644 index 000000000..227a66b18 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetAllStreetcodesShortHandlerTests.cs @@ -0,0 +1,99 @@ +using AutoMapper; +using Moq; +using Streetcode.BLL.DTO.Streetcode; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetAllShort; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class GetAllStreetcodesShortHandlerTests +{ + private readonly Mock _repositoryMock; + private readonly Mock _mapperMock; + private readonly Mock _loggerMock; + private readonly MockNoSharedResourceLocalizer _mockLocalizer; + private readonly GetAllStreetcodesShortHandler _handler; + + public GetAllStreetcodesShortHandlerTests() + { + _repositoryMock = new Mock(); + _mapperMock = new Mock(); + _loggerMock = new Mock(); + _mockLocalizer = new MockNoSharedResourceLocalizer(); + + _handler = new GetAllStreetcodesShortHandler( + _repositoryMock.Object, + _mapperMock.Object, + _loggerMock.Object, + _mockLocalizer); + } + + [Fact] + public async Task Handle_WhenStreetcodesExist_ReturnsStreetcodeShortDTOs() + { + // Arrange + var testStreetcodes = GetTestStreetcodes(3); + + SetupRepositoryMock(testStreetcodes); + + // Act + var result = await _handler.Handle(new GetAllStreetcodesShortQuery(), CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.Equal(testStreetcodes.Count, result.Value.Count()); + _repositoryMock.Verify(repo => repo.StreetcodeRepository.GetAllAsync(null, null), Times.Once); + _mapperMock.Verify(m => m.Map>(testStreetcodes), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenNoStreetcodesExist_ReturnsError() + { + // Arrange + const string expectedErrorKey = "NoStreetcodesExistNow"; + string expectedErrorValue = _mockLocalizer[expectedErrorKey]; + var query = new GetAllStreetcodesShortQuery(); + + SetupRepositoryMock(new List()); + + // Act + var result = await _handler.Handle(query, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorValue, result.Errors.Single().Message); + _loggerMock.Verify(logger => logger.LogError(query, expectedErrorValue), Times.Once); + }); + } + + private static List GetTestStreetcodes(int count) + { + return Enumerable.Range(1, count) + .Select(i => new StreetcodeContent { Id = i }) + .ToList(); + } + + private void SetupRepositoryMock(List? streetcodes) + { + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetAllAsync(null, null)) + .ReturnsAsync(streetcodes!); + + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((IEnumerable src) => + src.Select(s => new StreetcodeShortDTO() + { + Id = s.Id, + }).ToList()); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetFavouriteByIdHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetFavouriteByIdHandlerTests.cs new file mode 100644 index 000000000..47c55219d --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetFavouriteByIdHandlerTests.cs @@ -0,0 +1,101 @@ +using System.Linq.Expressions; +using AutoMapper; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.DTO.Streetcode; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetFavouriteById; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.DAL.Repositories.Interfaces.Streetcode; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class GetFavouriteByIdHandlerTests +{ + private readonly Mock _repository; + private readonly Mock _mapper; + private readonly Mock _mockLogger; + private readonly MockNoSharedResourceLocalizer _stringLocalizerNo; + private readonly Mock _httpContextAccessor; + + public GetFavouriteByIdHandlerTests() + { + _repository = new Mock(); + _mapper = new Mock(); + _mockLogger = new Mock(); + _stringLocalizerNo = new MockNoSharedResourceLocalizer(); + _httpContextAccessor = new Mock(); + } + + [Fact] + public async Task Handle_ReturnsBadRequest() + { + // Arrange + RepositorySetup(null); + + const int incorrectId = -1; + string expectedError = _stringLocalizerNo["NoFavouritesWithId", incorrectId]; + + const string userId = "mockId"; + MockHelpers.SetupMockHttpContextAccessor(_httpContextAccessor, userId); + var handler = new GetFavouriteByIdHandler(_mapper.Object, _repository.Object, _mockLogger.Object, _stringLocalizerNo, _httpContextAccessor.Object); + + // Act + var result = await handler.Handle(new GetFavouriteByIdQuery(incorrectId), CancellationToken.None); + + // Asset + Assert.Equal(expectedError, result.Errors.Single().Message); + } + + [Fact] + public async Task Handle_ReturnsSuccessfulResult() + { + const int streetcodeId = 1; + const string userId = "mockId"; + + RepositorySetup( + new StreetcodeContent + { + Id = streetcodeId, + }); + + SetupMapper( + new StreetcodeFavouriteDto + { + Id = streetcodeId, + }); + + MockHelpers.SetupMockHttpContextAccessor(_httpContextAccessor, userId); + + var handler = new GetFavouriteByIdHandler(_mapper.Object, _repository.Object, _mockLogger.Object, _stringLocalizerNo, _httpContextAccessor.Object); + + // Act + var result = await handler.Handle(new GetFavouriteByIdQuery(streetcodeId), CancellationToken.None); + + // Asset + Assert.Multiple( + () => Assert.True(result.IsSuccess), + () => Assert.Equal(streetcodeId, result.Value.Id)); + } + + private void RepositorySetup(StreetcodeContent? favourite) + { + var streetcodeRepoMock = new Mock(); + + streetcodeRepoMock.Setup(x => x.GetFirstOrDefaultAsync( + It.IsAny>?>(), It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(favourite); + + _repository.Setup(x => x.StreetcodeRepository).Returns(streetcodeRepoMock.Object); + } + + private void SetupMapper(StreetcodeFavouriteDto favourite) + { + _mapper.Setup(x => x.Map(It.IsAny())) + .Returns(favourite); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetFavouriteStatusHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetFavouriteStatusHandlerTests.cs new file mode 100644 index 000000000..0853eceed --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetFavouriteStatusHandlerTests.cs @@ -0,0 +1,71 @@ +using System.Linq.Expressions; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetFavouriteStatus; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class GetFavouriteStatusHandlerTests +{ + private readonly Mock _repository; + private readonly Mock _httpContextAccessor; + + public GetFavouriteStatusHandlerTests() + { + _repository = new Mock(); + _httpContextAccessor = new Mock(); + } + + [Fact] + public async Task Handle_ReturnsTrue() + { + // Arrange + const int streetcodeId = 1; + const string userId = "mockId"; + + RepositorySetup( + new StreetcodeContent + { + Id = streetcodeId, + }); + + MockHelpers.SetupMockHttpContextAccessor(_httpContextAccessor, userId); + var handler = new GetFavouriteStatusHandler(_repository.Object, _httpContextAccessor.Object); + + // Act + var result = await handler.Handle(new GetFavouriteStatusQuery(streetcodeId), CancellationToken.None); + + // Assert + Assert.True(result.Value); + } + + [Fact] + public async Task Handle_ReturnsFalse() + { + // Arrange + const int streetcodeId = 1; + const string userId = "mockId"; + + RepositorySetup(null); + MockHelpers.SetupMockHttpContextAccessor(_httpContextAccessor, userId); + var handler = new GetFavouriteStatusHandler(_repository.Object, _httpContextAccessor.Object); + + // Act + var result = await handler.Handle(new GetFavouriteStatusQuery(streetcodeId), CancellationToken.None); + + // Assert + Assert.False(result.Value); + } + + private void RepositorySetup(StreetcodeContent? favourite) + { + _repository.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( + It.IsAny>?>(), It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(favourite); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetPageOfStreetcodesMainPageHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetPageOfStreetcodesMainPageHandlerTests.cs new file mode 100644 index 000000000..ef2f75420 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetPageOfStreetcodesMainPageHandlerTests.cs @@ -0,0 +1,145 @@ +using System.Linq.Expressions; +using AutoMapper; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.DTO.Streetcode; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetPageMainPage; +using Streetcode.DAL.Entities.Media.Images; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.DAL.Enums; +using Streetcode.DAL.Helpers; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class GetPageOfStreetcodesMainPageHandlerTests +{ + private readonly Mock _repositoryMock; + private readonly Mock _mapperMock; + private readonly Mock _loggerMock; + private readonly MockNoSharedResourceLocalizer _mockLocalizer; + private readonly GetPageOfStreetcodesMainPageHandler _handler; + + public GetPageOfStreetcodesMainPageHandlerTests() + { + _repositoryMock = new Mock(); + _mapperMock = new Mock(); + _loggerMock = new Mock(); + _mockLocalizer = new MockNoSharedResourceLocalizer(); + + _handler = new GetPageOfStreetcodesMainPageHandler( + _repositoryMock.Object, + _mapperMock.Object, + _loggerMock.Object, + _mockLocalizer); + } + + [Fact] + public async Task Handle_WhenStreetcodesExist_ReturnsPagedCatalogItems() + { + // Arrange + var request = new GetPageOfStreetcodesMainPageQuery(Page: 1, PageSize: 2); + var testStreetcodes = GetTestStreetcodes(5); + + SetupRepositoryMocks(testStreetcodes, request.Page, request.PageSize); + + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((IEnumerable src) => src.Select(s => new StreetcodeMainPageDTO { Id = s.Id }).ToList()); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.Equal(request.PageSize, result.Value.Count()); + }); + } + + [Fact] + public async Task Handle_WhenNoStreetcodesExist_ReturnsError() + { + // Arrange + var request = new GetPageOfStreetcodesMainPageQuery(Page: 1, PageSize: 2); + string expectedErrorMessage = _mockLocalizer["NoStreetcodesExistNow"]; + + SetupRepositoryMocks(new List()); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorMessage, result.Errors.Single().Message); + _loggerMock.Verify(logger => logger.LogError(request, expectedErrorMessage), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenStreetcodesExist_ShufflesResults() + { + // Arrange + var request = new GetPageOfStreetcodesMainPageQuery(Page: 1, PageSize: 5); + var testStreetcodes = GetTestStreetcodes(10); + + SetupRepositoryMocks(testStreetcodes); + + // Act + var result1 = await _handler.Handle(request, CancellationToken.None); + var result2 = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result1.IsSuccess); + Assert.True(result2.IsSuccess); + Assert.NotEqual(result1.Value, result2.Value); + }); + } + + private static List GetTestStreetcodes(int count) + { + return Enumerable.Range(1, count).Select(i => new StreetcodeContent + { + Id = i, + Status = StreetcodeStatus.Published, + CreatedAt = DateTime.UtcNow.AddDays(-i), + Text = new Text(), + Images = new List + { + new Image() + { + ImageDetails = new ImageDetails { Alt = ((int)ImageAssigment.Blackandwhite).ToString() }, + }, + }, + }).ToList(); + } + + private void SetupRepositoryMocks(List streetcodes, ushort pageNumber = 1, ushort pageSize = 5) + { + var paginationResponse = PaginationResponse.Create(streetcodes.AsQueryable(), pageNumber, pageSize); + + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetAllPaginated( + It.IsAny(), + It.IsAny(), + It.IsAny>>(), + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>(), + It.IsAny>>(), + It.IsAny>>())) + .Returns(paginationResponse); + + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((IEnumerable src) => src.Select(s => new StreetcodeMainPageDTO { Id = s.Id }).ToList()); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByFilterHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByFilterHandlerTests.cs index 13a9a86d2..02d6183b4 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByFilterHandlerTests.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByFilterHandlerTests.cs @@ -14,13 +14,13 @@ namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; public class GetStreetcodeByFilterHandlerTests { - private readonly Mock repositoryWrapper; - private readonly GetStreetcodeByFilterHandler handler; + private readonly Mock _repositoryWrapper; + private readonly GetStreetcodeByFilterHandler _handler; public GetStreetcodeByFilterHandlerTests() { - this.repositoryWrapper = new Mock(); - this.handler = new GetStreetcodeByFilterHandler(this.repositoryWrapper.Object); + _repositoryWrapper = new Mock(); + _handler = new GetStreetcodeByFilterHandler(_repositoryWrapper.Object); } [Theory] @@ -34,10 +34,10 @@ public async Task Handle_ReturnsResults_WhenSearchQueryMatches(string searchQuer // Arrange var query = new GetStreetcodeByFilterQuery(new StreetcodeFilterRequestDTO { SearchQuery = searchQuery }); - this.SetupRepositoryMock(expectedContent); + SetupRepositoryMock(expectedContent); // Act - var result = await this.handler.Handle(query, CancellationToken.None); + var result = await _handler.Handle(query, CancellationToken.None); // Assert result.IsSuccess.Should().BeTrue(); @@ -51,10 +51,10 @@ public async Task Handle_ReturnsAllResults_WhenSearchQueryIsEmpty(string searchQ { // Arrange var query = new GetStreetcodeByFilterQuery(new StreetcodeFilterRequestDTO { SearchQuery = searchQuery }); - this.SetupRepositoryMock("SomeContent"); + SetupRepositoryMock("SomeContent"); // Act - var result = await this.handler.Handle(query, CancellationToken.None); + var result = await _handler.Handle(query, CancellationToken.None); // Assert result.IsSuccess.Should().BeTrue(); @@ -68,10 +68,10 @@ public async Task Handle_ReturnsEmptyList_WhenNoMatchesFound(string searchQuery) // Arrange var query = new GetStreetcodeByFilterQuery(new StreetcodeFilterRequestDTO { SearchQuery = searchQuery }); - this.SetupRepositoryMock(null, true); + SetupRepositoryMock(null, true); // Act - var result = await this.handler.Handle(query, CancellationToken.None); + var result = await _handler.Handle(query, CancellationToken.None); // Assert result.IsSuccess.Should().BeTrue(); @@ -84,10 +84,10 @@ public async Task Handle_ReturnsEmptyList_WhenAllRepositoriesReturnEmpty(string { // Arrange var query = new GetStreetcodeByFilterQuery(new StreetcodeFilterRequestDTO { SearchQuery = searchQuery }); - this.SetupRepositoryMock(null, true); + SetupRepositoryMock(null, true); // Act - var result = await this.handler.Handle(query, CancellationToken.None); + var result = await _handler.Handle(query, CancellationToken.None); // Assert result.IsSuccess.Should().BeTrue(); @@ -101,12 +101,12 @@ public async Task Handle_ThrowsException_WhenRepositoryThrowsException(string se // Arrange var query = new GetStreetcodeByFilterQuery(new StreetcodeFilterRequestDTO { SearchQuery = searchQuery }); - this.repositoryWrapper.Setup(r => r.StreetcodeRepository + _repositoryWrapper.Setup(r => r.StreetcodeRepository .GetAllAsync(It.IsAny>>(), null)) .ThrowsAsync(new Exception("Database error")); // Act & Assert - await FluentActions.Invoking(() => this.handler.Handle(query, CancellationToken.None)).Should().ThrowAsync(); + await FluentActions.Invoking(() => _handler.Handle(query, CancellationToken.None)).Should().ThrowAsync(); } private void SetupRepositoryMock(string? expectedContent, bool returnEmptyList = false) @@ -136,23 +136,23 @@ private void SetupRepositoryMock(string? expectedContent, bool returnEmptyList = new () { Streetcode = new StreetcodeContent { Id = 1, Status = DAL.Enums.StreetcodeStatus.Published }, Title = expectedContent, Description = expectedContent }, }; - this.repositoryWrapper.Setup(r => r.StreetcodeRepository + _repositoryWrapper.Setup(r => r.StreetcodeRepository .GetAllAsync(It.IsAny>>(), null)) .ReturnsAsync(streetcodes); - this.repositoryWrapper.Setup(r => r.TextRepository + _repositoryWrapper.Setup(r => r.TextRepository .GetAllAsync(It.IsAny>>(), null)) .ReturnsAsync(texts); - this.repositoryWrapper.Setup(r => r.StreetcodeArtRepository + _repositoryWrapper.Setup(r => r.StreetcodeArtRepository .GetAllAsync(It.IsAny>>(), null)) .ReturnsAsync(streetcodeArts); - this.repositoryWrapper.Setup(r => r.FactRepository + _repositoryWrapper.Setup(r => r.FactRepository .GetAllAsync(It.IsAny>>(), null)) .ReturnsAsync(facts); - this.repositoryWrapper.Setup(r => r.TimelineRepository + _repositoryWrapper.Setup(r => r.TimelineRepository .GetAllAsync(It.IsAny>>(), null)) .ReturnsAsync(timelineItems); } diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByIdHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByIdHandlerTests.cs index 4df68684d..b57bf693b 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByIdHandlerTests.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByIdHandlerTests.cs @@ -1,120 +1,83 @@ using System.Linq.Expressions; using AutoMapper; using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; using Moq; using Streetcode.BLL.DTO.Streetcode; using Streetcode.BLL.DTO.Streetcode.Types; -using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetById; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.AdditionalContent; using Streetcode.DAL.Entities.Streetcode; using Streetcode.DAL.Repositories.Interfaces.Base; using Xunit; -namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode -{ - public class GetStreetcodeByIdHandlerTests - { - private readonly Mock repository; - private readonly Mock mapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotFind; - - public GetStreetcodeByIdHandlerTests() - { - this.repository = new Mock(); - this.mapper = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerCannotFind = new Mock>(); - } - - [Theory] - [InlineData(1)] - public async Task Handle_ReturnsSuccess(int id) - { - // Arrange - var testContentDTO = new EventStreetcodeDTO(); - var testContent = new StreetcodeContent(); - - this.RepositorySetup(testContent); - this.MapperSetup(testContentDTO); +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; - var handler = new GetStreetcodeByIdHandler(this.repository.Object, this.mapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); - - // act - var result = await handler.Handle(new GetStreetcodeByIdQuery(id), CancellationToken.None); - - // Assert - Assert.True(result.IsSuccess); - } +public class GetStreetcodeByIdHandlerTests +{ + private readonly Mock _repository; + private readonly Mock _mapper; - [Theory] - [InlineData(1)] - public async Task Handle_ReturnsCorrectType(int id) - { - // arrange - var testContentDTO = new EventStreetcodeDTO(); - var testContent = new StreetcodeContent(); + public GetStreetcodeByIdHandlerTests() + { + _repository = new Mock(); + _mapper = new Mock(); + } - this.RepositorySetup(testContent); - this.MapperSetup(testContentDTO); + [Theory] + [InlineData(1)] + public async Task Handle_ReturnsSuccess(int id) + { + // Arrange + var testContentDto = new EventStreetcodeDTO(); + var testContent = new StreetcodeContent(); - var handler = new GetStreetcodeByIdHandler(this.repository.Object, this.mapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + RepositorySetup(testContent); + MapperSetup(testContentDto); - // act - var result = await handler.Handle(new GetStreetcodeByIdQuery(id), CancellationToken.None); + var handler = new GetStreetcodeByIdHandler(_repository.Object, _mapper.Object); - // Assert - Assert.IsAssignableFrom(result.Value); - } + // act + var result = await handler.Handle(new GetStreetcodeByIdQuery(id), CancellationToken.None); - [Theory] - [InlineData(1)] - public async Task Handle_ReturnsError(int id) - { - // arrange - string expectedErrorMessage = $"Cannot find any streetcode with corresponding id: {id}"; - this.mockLocalizerCannotFind.Setup(x => x[It.IsAny(), It.IsAny()]) - .Returns((string key, object[] args) => - { - if (args != null && args.Length > 0 && args[0] is int id) - { - return new LocalizedString(key, $"Cannot find any streetcode with corresponding id: {id}"); - } + // Assert + Assert.True(result.IsSuccess); + } - return new LocalizedString(key, "Cannot find any streetcode with unknown id"); - }); + [Theory] + [InlineData(1)] + public async Task Handle_ReturnsCorrectType(int id) + { + // arrange + var testContentDto = new EventStreetcodeDTO(); + var testContent = new StreetcodeContent(); - this.RepositorySetup(null); - this.MapperSetup(null); + RepositorySetup(testContent); + MapperSetup(testContentDto); - var handler = new GetStreetcodeByIdHandler(this.repository.Object, this.mapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + var handler = new GetStreetcodeByIdHandler(_repository.Object, _mapper.Object); - // act - var result = await handler.Handle(new GetStreetcodeByIdQuery(id), CancellationToken.None); + // act + var result = await handler.Handle(new GetStreetcodeByIdQuery(id), CancellationToken.None); - // Assert - Assert.Equal(expectedErrorMessage, result.Errors.Single().Message); - } + // Assert + Assert.IsAssignableFrom(result.Value); + } - private void RepositorySetup(StreetcodeContent? streetcode) - { - this.repository.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( + private void RepositorySetup(StreetcodeContent? streetcode) + { + _repository.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( It.IsAny>?>(), It.IsAny, IIncludableQueryable>>())) - .ReturnsAsync(streetcode); - this.repository.Setup(repo => repo.StreetcodeTagIndexRepository.GetAllAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(new List()); - } + .ReturnsAsync(streetcode); + _repository.Setup(repo => repo.StreetcodeTagIndexRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, + IIncludableQueryable>>())) + .ReturnsAsync(new List()); + } - private void MapperSetup(EventStreetcodeDTO? streetcodeDTO) - { - this.mapper.Setup(x => x.Map(It.IsAny())) - .Returns(streetcodeDTO); - } + private void MapperSetup(EventStreetcodeDTO? streetcodeDto) + { + _mapper.Setup(x => x.Map(It.IsAny())) + .Returns(streetcodeDto); } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByIndexHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByIndexHandlerTests.cs index fe02c77f1..0c743378c 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByIndexHandlerTests.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByIndexHandlerTests.cs @@ -12,125 +12,124 @@ using Xunit; using Model = Streetcode.DAL.Entities.Streetcode.StreetcodeContent; -namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class GetStreetcodeByIndexHandlerTests { - public class GetStreetcodeByIndexHandlerTests + private readonly Mock _repository; + private readonly Mock _mapper; + private readonly Mock _mockLogger; + private readonly Mock> _mockLocalizerCannotFind; + + public GetStreetcodeByIndexHandlerTests() { - private readonly Mock repository; - private readonly Mock mapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotFind; + _repository = new Mock(); + _mapper = new Mock(); + _mockLogger = new Mock(); + _mockLocalizerCannotFind = new Mock>(); + } - public GetStreetcodeByIndexHandlerTests() - { - this.repository = new Mock(); - this.mapper = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerCannotFind = new Mock>(); - } - - [Theory] - [InlineData(1)] - public async Task Handle_ReturnsSuccess(int id) + [Theory] + [InlineData(1)] + public async Task Handle_ReturnsSuccess(int id) + { + // Arrange + var testModelList = new List() { - // Arrange - var testModelList = new List() - { - new Model(), - new Model(), - new Model(), - }; + new (), + new (), + new (), + }; - var testDTOList = new List() - { - new PersonStreetcodeDTO(), - new EventStreetcodeDTO(), - new EventStreetcodeDTO(), - }; + var testDtoList = new List() + { + new PersonStreetcodeDTO(), + new EventStreetcodeDTO(), + new EventStreetcodeDTO(), + }; - this.repository.Setup(x => x.StreetcodeRepository.GetAllAsync(It.IsAny>>(), null)) - .ReturnsAsync(testModelList); + _repository.Setup(x => x.StreetcodeRepository.GetAllAsync(It.IsAny>>(), null)) + .ReturnsAsync(testModelList); - this.mapper.Setup(x => x.Map>(It.IsAny>())) - .Returns(testDTOList); + _mapper.Setup(x => x.Map>(It.IsAny>())) + .Returns(testDtoList); - this.SetupLocalizers(); + SetupLocalizers(); - var handler = new GetStreetcodeByIndexHandler(this.repository.Object, this.mapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + var handler = new GetStreetcodeByIndexHandler(_repository.Object, _mapper.Object, _mockLogger.Object, _mockLocalizerCannotFind.Object); - // Act - var result = await handler.Handle(new GetStreetcodeByIndexQuery(id), CancellationToken.None); + // Act + var result = await handler.Handle(new GetStreetcodeByIndexQuery(id), CancellationToken.None); - // Assert - Assert.NotNull(result); - } + // Assert + Assert.NotNull(result); + } - [Theory] - [InlineData(1)] - public async Task Handle_ReturnsError(int id) - { - // Arrange - var testStreetcodeDTO = new EventStreetcodeDTO(); - var expectedErrorMessage = $"Cannot find any streetcode with corresponding index: {id}"; - this.SetupLocalizers(); + [Theory] + [InlineData(1)] + public async Task Handle_ReturnsError(int id) + { + // Arrange + var testStreetcodeDto = new EventStreetcodeDTO(); + var expectedErrorMessage = $"Cannot find any streetcode with corresponding index: {id}"; + SetupLocalizers(); - this.Setup(null, testStreetcodeDTO); + Setup(null, testStreetcodeDto); - var handler = new GetStreetcodeByIndexHandler(this.repository.Object, this.mapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + var handler = new GetStreetcodeByIndexHandler(_repository.Object, _mapper.Object, _mockLogger.Object, _mockLocalizerCannotFind.Object); - // Act - var result = await handler.Handle(new GetStreetcodeByIndexQuery(id), CancellationToken.None); + // Act + var result = await handler.Handle(new GetStreetcodeByIndexQuery(id), CancellationToken.None); - // Assert - Assert.Equal(expectedErrorMessage, result.Errors.Single().Message); - } + // Assert + Assert.Equal(expectedErrorMessage, result.Errors.Single().Message); + } - [Theory] - [InlineData(1)] - public async Task Handle_ReturnsCorrectType(int id) - { - // Arrange - var testStreetcodeDTO = new EventStreetcodeDTO(); - var testStreetcode = new Model(); + [Theory] + [InlineData(1)] + public async Task Handle_ReturnsCorrectType(int id) + { + // Arrange + var testStreetcodeDto = new EventStreetcodeDTO(); + var testStreetcode = new Model(); - this.Setup(testStreetcode, testStreetcodeDTO); + Setup(testStreetcode, testStreetcodeDto); - var handler = new GetStreetcodeByIndexHandler(this.repository.Object, this.mapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + var handler = new GetStreetcodeByIndexHandler(_repository.Object, _mapper.Object, _mockLogger.Object, _mockLocalizerCannotFind.Object); - // Act - var result = await handler.Handle(new GetStreetcodeByIndexQuery(id), CancellationToken.None); + // Act + var result = await handler.Handle(new GetStreetcodeByIndexQuery(id), CancellationToken.None); - // Assert - Assert.IsAssignableFrom(result.Value); - } + // Assert + Assert.IsAssignableFrom(result.Value); + } - private void Setup(Model? testStreetcode, EventStreetcodeDTO testStreetcodeDTO) - { - this.repository - .Setup(x => x.StreetcodeRepository - .GetFirstOrDefaultAsync( - It.IsAny>?>(), - It.IsAny, + private void Setup(Model? testStreetcode, EventStreetcodeDTO testStreetcodeDto) + { + _repository + .Setup(x => x.StreetcodeRepository + .GetFirstOrDefaultAsync( + It.IsAny>?>(), + It.IsAny, IIncludableQueryable>>())) - .ReturnsAsync(testStreetcode); + .ReturnsAsync(testStreetcode); - this.mapper - .Setup(x => x.Map(It.IsAny())) - .Returns(testStreetcodeDTO); - } + _mapper + .Setup(x => x.Map(It.IsAny())) + .Returns(testStreetcodeDto); + } - private void SetupLocalizers() - { - this.mockLocalizerCannotFind.Setup(x => x[It.IsAny(), It.IsAny()]) - .Returns((string key, object[] args) => - { - if (args != null && args.Length > 0 && args[0] is int id) - { - return new LocalizedString(key, $"Cannot find any streetcode with corresponding index: {id}"); - } - - return new LocalizedString(key, "Cannot find any streetcode with unknown index"); - }); - } + private void SetupLocalizers() + { + _mockLocalizerCannotFind.Setup(x => x[It.IsAny(), It.IsAny()]) + .Returns((string key, object[] args) => + { + if (args != null && args.Length > 0 && args[0] is int id) + { + return new LocalizedString(key, $"Cannot find any streetcode with corresponding index: {id}"); + } + + return new LocalizedString(key, "Cannot find any streetcode with unknown index"); + }); } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByTransliterationUrlHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByTransliterationUrlHandlerTests.cs index 173d187c9..c6d335df6 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByTransliterationUrlHandlerTests.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeByTransliterationUrlHandlerTests.cs @@ -12,118 +12,117 @@ using Streetcode.DAL.Repositories.Interfaces.Base; using Xunit; -namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class GetStreetcodeByTransliterationUrlHandlerTests { - public class GetStreetcodeByTransliterationUrlHandlerTests + private readonly Mock _mockRepo; + private readonly Mock _mockMapper; + private readonly StreetcodeContent? _nullValue = null; + private readonly StreetcodeDTO? _nullValueDto = null; + private readonly Mock _mockLogger; + private readonly Mock> _mockLocalizerCannotFind; + + public GetStreetcodeByTransliterationUrlHandlerTests() + { + _mockMapper = new Mock(); + _mockRepo = new Mock(); + _mockLogger = new Mock(); + _mockLocalizerCannotFind = new Mock>(); + } + + [Theory] + [InlineData("some")] + public async Task ExistingUrl(string url) { - private readonly Mock mockRepo; - private readonly Mock mockMapper; - private readonly StreetcodeContent? nullValue = null; - private readonly StreetcodeDTO? nullValueDTO = null; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotFind; - - public GetStreetcodeByTransliterationUrlHandlerTests() - { - this.mockMapper = new Mock(); - this.mockRepo = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerCannotFind = new Mock>(); - } - - [Theory] - [InlineData("some")] - public async Task ExistingUrl(string url) - { - // Arrange - this.SetupMapper(url); - this.SetupRepository(url); - - var handler = new GetStreetcodeByTransliterationUrlHandler(this.mockRepo.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); - - // Act - var result = await handler.Handle(new GetStreetcodeByTransliterationUrlQuery(url), CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.NotNull(result), - () => Assert.True(result.IsSuccess), - () => Assert.Equal(result.Value.TransliterationUrl, url)); - } - - [Theory] - [InlineData("some")] - public async Task NotExistingId(string url) - { - // Arrange - this.mockRepo.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( - It.IsAny>>(), It.IsAny, - IIncludableQueryable>>())).ReturnsAsync(this.nullValue); - - this.mockMapper.Setup(x => x.Map(It.IsAny())).Returns(this.nullValueDTO); - - var expectedError = $"Cannot find streetcode by transliteration url: {url}"; - this.mockLocalizerCannotFind.Setup(x => x[It.IsAny(), It.IsAny()]) - .Returns((string key, object[] args) => - { - if (args != null && args.Length > 0 && args[0] is string url) - { - return new LocalizedString(key, $"Cannot find streetcode by transliteration url: {url}"); - } - - return new LocalizedString(key, "Cannot find any streetcode with unknown transliteration url"); - }); - - var handler = new GetStreetcodeByTransliterationUrlHandler(this.mockRepo.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); - - // Act - var result = await handler.Handle(new GetStreetcodeByTransliterationUrlQuery(url), CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.NotNull(result), - () => Assert.True(result.IsFailed), - () => Assert.Equal(expectedError, result.Errors[0].Message)); - } - - [Theory] - [InlineData("some")] - public async Task CorrectType(string url) - { - // Arrange - this.SetupMapper(url); - this.SetupRepository(url); - - var handler = new GetStreetcodeByTransliterationUrlHandler(this.mockRepo.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); - - // Act - var result = await handler.Handle(new GetStreetcodeByTransliterationUrlQuery(url), CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.NotNull(result.ValueOrDefault), - () => Assert.IsType(result.ValueOrDefault)); - } - - private void SetupRepository(string url) - { - this.mockRepo - .Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( - It.IsAny>>(), - It.IsAny, + // Arrange + SetupMapper(url); + SetupRepository(url); + + var handler = new GetStreetcodeByTransliterationUrlHandler(_mockRepo.Object, _mockMapper.Object, _mockLogger.Object, _mockLocalizerCannotFind.Object); + + // Act + var result = await handler.Handle(new GetStreetcodeByTransliterationUrlQuery(url), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.NotNull(result), + () => Assert.True(result.IsSuccess), + () => Assert.Equal(result.Value.TransliterationUrl, url)); + } + + [Theory] + [InlineData("some")] + public async Task NotExistingId(string url) + { + // Arrange + _mockRepo.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), It.IsAny, + IIncludableQueryable>>())).ReturnsAsync(_nullValue); + + _mockMapper.Setup(x => x.Map(It.IsAny())).Returns(_nullValueDto); + + var expectedError = $"Cannot find streetcode by transliteration url: {url}"; + _mockLocalizerCannotFind.Setup(x => x[It.IsAny(), It.IsAny()]) + .Returns((string key, object[] args) => + { + if (args != null && args.Length > 0 && args[0] is string url) + { + return new LocalizedString(key, $"Cannot find streetcode by transliteration url: {url}"); + } + + return new LocalizedString(key, "Cannot find any streetcode with unknown transliteration url"); + }); + + var handler = new GetStreetcodeByTransliterationUrlHandler(_mockRepo.Object, _mockMapper.Object, _mockLogger.Object, _mockLocalizerCannotFind.Object); + + // Act + var result = await handler.Handle(new GetStreetcodeByTransliterationUrlQuery(url), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.NotNull(result), + () => Assert.True(result.IsFailed), + () => Assert.Equal(expectedError, result.Errors[0].Message)); + } + + [Theory] + [InlineData("some")] + public async Task CorrectType(string url) + { + // Arrange + SetupMapper(url); + SetupRepository(url); + + var handler = new GetStreetcodeByTransliterationUrlHandler(_mockRepo.Object, _mockMapper.Object, _mockLogger.Object, _mockLocalizerCannotFind.Object); + + // Act + var result = await handler.Handle(new GetStreetcodeByTransliterationUrlQuery(url), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.NotNull(result.ValueOrDefault), + () => Assert.IsType(result.ValueOrDefault)); + } + + private void SetupRepository(string url) + { + _mockRepo + .Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) - .ReturnsAsync(new StreetcodeContent() { TransliterationUrl = url }); - this.mockRepo - .Setup(repo => repo.StreetcodeTagIndexRepository.GetAllAsync( - It.IsAny>>(), - It.IsAny, + .ReturnsAsync(new StreetcodeContent() { TransliterationUrl = url }); + _mockRepo + .Setup(repo => repo.StreetcodeTagIndexRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) - .ReturnsAsync(new List()); - } + .ReturnsAsync(new List()); + } - private void SetupMapper(string url) - { - this.mockMapper.Setup(x => x.Map(It.IsAny())).Returns(new StreetcodeDTO() { TransliterationUrl = url }); - } + private void SetupMapper(string url) + { + _mockMapper.Setup(x => x.Map(It.IsAny())).Returns(new StreetcodeDTO() { TransliterationUrl = url }); } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeShortByIdHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeShortByIdHandlerTests.cs new file mode 100644 index 000000000..d19180e66 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeShortByIdHandlerTests.cs @@ -0,0 +1,95 @@ +using System.Linq.Expressions; +using AutoMapper; +using Moq; +using Streetcode.BLL.DTO.Streetcode; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetShortById; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class GetStreetcodeShortByIdHandlerTests +{ + private readonly Mock _repositoryMock; + private readonly Mock _mapperMock; + private readonly Mock _loggerMock; + private readonly MockCannotMapLocalizer _mockCannotMapLocalizer; + private readonly GetStreetcodeShortByIdHandler _handler; + + public GetStreetcodeShortByIdHandlerTests() + { + _repositoryMock = new Mock(); + _mapperMock = new Mock(); + _loggerMock = new Mock(); + _mockCannotMapLocalizer = new MockCannotMapLocalizer(); + + _handler = new GetStreetcodeShortByIdHandler( + _mapperMock.Object, + _repositoryMock.Object, + _loggerMock.Object, + _mockCannotMapLocalizer); + } + + [Fact] + public async Task Handle_WhenStreetcodeExists_ReturnsStreetcodeShortDTO() + { + // Arrange + var request = new GetStreetcodeShortByIdQuery(Id: 1); + var testStreetcode = new StreetcodeContent { Id = request.Id }; + var expectedDto = new StreetcodeShortDTO { Id = request.Id }; + + SetupRepositoryMock(testStreetcode); + SetupMapperMock(); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.Equal(expectedDto.Id, result.Value.Id); + }); + } + + [Fact] + public async Task Handle_WhenMappingFails_ReturnsError() + { + // Arrange + var request = new GetStreetcodeShortByIdQuery(Id: 1); + var testStreetcode = new StreetcodeContent { Id = request.Id }; + const string expectedErrorKey = "CannotMapStreetcodeToShortDTO"; + string expectedErrorValue = _mockCannotMapLocalizer[expectedErrorKey]; + + SetupRepositoryMock(testStreetcode); + _mapperMock.Setup(m => m.Map(It.IsAny())).Returns((StreetcodeShortDTO)null!); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorValue, result.Errors.Single().Message); + _loggerMock.Verify(logger => logger.LogError(request, expectedErrorValue), Times.Once); + }); + } + + private void SetupRepositoryMock(StreetcodeContent? streetcode) + { + _repositoryMock.Setup(repo => repo.StreetcodeRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), null)) + .ReturnsAsync(streetcode); + } + + private void SetupMapperMock() + { + _mapperMock + .Setup(m => m.Map(It.IsAny())) + .Returns((StreetcodeContent src) => new StreetcodeShortDTO { Id = src.Id }); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeUrlByQrIdHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeUrlByQrIdHandlerTests.cs new file mode 100644 index 000000000..97956504f --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodeUrlByQrIdHandlerTests.cs @@ -0,0 +1,123 @@ +using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetUrlByQrId; +using Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types; +using Streetcode.DAL.Entities.Analytics; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class GetStreetcodeUrlByQrIdHandlerTests +{ + private readonly Mock _repositoryMock; + private readonly Mock _loggerMock; + private readonly MockCannotFindLocalizer _mockCannotFindLocalizer; + private readonly GetStreetcodeUrlByQrIdHandler _handler; + + public GetStreetcodeUrlByQrIdHandlerTests() + { + _repositoryMock = new Mock(); + _loggerMock = new Mock(); + _mockCannotFindLocalizer = new MockCannotFindLocalizer(); + + _handler = new GetStreetcodeUrlByQrIdHandler( + _repositoryMock.Object, + _loggerMock.Object, + _mockCannotFindLocalizer); + } + + [Fact] + public async Task Handle_WhenRecordExists_ReturnsStreetcodeUrl() + { + // Arrange + var request = new GetStreetcodeUrlByQrIdQuery(QrId: 10); + var testStatisticRecord = new StatisticRecord + { + QrId = request.QrId, + StreetcodeCoordinate = new StreetcodeCoordinate { StreetcodeId = 1 }, + }; + var testStreetcode = new StreetcodeContent + { + Id = 1, + TransliterationUrl = "test-url", + }; + + SetupRepositoryMock(testStatisticRecord, testStreetcode); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.Equal(testStreetcode.TransliterationUrl, result.Value); + }); + } + + [Fact] + public async Task Handle_WhenRecordDoesNotExist_ReturnsError() + { + // Arrange + var request = new GetStreetcodeUrlByQrIdQuery(QrId: 10); + const string expectedErrorKey = "CannotFindRecordWithQrId"; + string expectedErrorValue = _mockCannotFindLocalizer[expectedErrorKey]; + + SetupRepositoryMock(null, new StreetcodeContent()); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorValue, result.Errors.Single().Message); + _loggerMock.Verify(logger => logger.LogError(request, expectedErrorValue), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenStreetcodeDoesNotExist_ReturnsError() + { + // Arrange + var request = new GetStreetcodeUrlByQrIdQuery(QrId: 10); + var testStatisticRecord = new StatisticRecord + { + QrId = request.QrId, + StreetcodeCoordinate = new StreetcodeCoordinate { StreetcodeId = 1 }, + }; + const string expectedErrorKey = "CannotFindStreetcodeById"; + string expectedErrorValue = _mockCannotFindLocalizer[expectedErrorKey]; + + SetupRepositoryMock(testStatisticRecord, null); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorValue, result.Errors.Single().Message); + _loggerMock.Verify(logger => logger.LogError(request, expectedErrorValue), Times.Once); + }); + } + + private void SetupRepositoryMock(StatisticRecord? statisticRecord, StreetcodeContent? streetcode) + { + _repositoryMock.Setup(repo => repo.StatisticRecordRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(statisticRecord); + + _repositoryMock.Setup(repo => repo.StreetcodeRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), null)) + .ReturnsAsync(streetcode); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodesCountHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodesCountHandlerTests.cs new file mode 100644 index 000000000..41c166b06 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/GetStreetcodesCountHandlerTests.cs @@ -0,0 +1,119 @@ +using System.Linq.Expressions; +using Moq; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.GetCount; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Enums; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class GetStreetcodesCountHandlerTests +{ + private readonly Mock _repositoryMock; + private readonly Mock _loggerMock; + private readonly MockNoSharedResourceLocalizer _mockLocalizer; + private readonly GetStreetcodesCountHandler _handler; + + public GetStreetcodesCountHandlerTests() + { + _repositoryMock = new Mock(); + _loggerMock = new Mock(); + _mockLocalizer = new MockNoSharedResourceLocalizer(); + _handler = new GetStreetcodesCountHandler( + _repositoryMock.Object, + _loggerMock.Object, + _mockLocalizer); + } + + [Fact] + public async Task Handle_WhenStreetcodesExist_ReturnsCount() + { + // Arrange + var testStreetcodes = GetTestStreetcodes(5); + SetupRepositoryMock(testStreetcodes); + + var request = new GetStreetcodesCountQuery(OnlyPublished: false); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.Equal(testStreetcodes.Count, result.Value); + _repositoryMock.Verify(repo => repo.StreetcodeRepository.GetAllAsync(null, null), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenOnlyPublishedStreetcodesExist_ReturnsPublishedCount() + { + // Arrange + var testStreetcodes = GetTestStreetcodes(5); + SetupRepositoryMock(testStreetcodes, onlyPublished: true); + + var request = new GetStreetcodesCountQuery(OnlyPublished: true); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.Equal(testStreetcodes.Count, result.Value); + _repositoryMock.Verify(repo => repo.StreetcodeRepository.GetAllAsync(It.IsAny>>(), null), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenNoStreetcodesExist_ReturnsError() + { + // Arrange + const string expectedErrorKey = "NoStreetcodesExistNow"; + string expectedErrorValue = _mockLocalizer[expectedErrorKey]; + + SetupRepositoryMock(new List()); + + var request = new GetStreetcodesCountQuery(OnlyPublished: false); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorValue, result.Errors.Single().Message); + _loggerMock.Verify(logger => logger.LogError(request, expectedErrorValue), Times.Once); + }); + } + + private static List GetTestStreetcodes(int count, StreetcodeStatus status = StreetcodeStatus.Published) + { + return Enumerable.Range(1, count) + .Select(i => new StreetcodeContent { Id = i, Status = status }) + .ToList(); + } + + private void SetupRepositoryMock(List streetcodes, bool onlyPublished = false) + { + if (onlyPublished) + { + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetAllAsync( + It.IsAny>>(), null)) + .ReturnsAsync(streetcodes); + } + else + { + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetAllAsync(null, null)) + .ReturnsAsync(streetcodes); + } + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/StreetcodeWithUrlExistHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/StreetcodeWithUrlExistHandlerTests.cs new file mode 100644 index 000000000..876222971 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/StreetcodeWithUrlExistHandlerTests.cs @@ -0,0 +1,65 @@ +using System.Linq.Expressions; +using Moq; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.WithUrlExist; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class StreetcodeWithUrlExistHandlerTests +{ + private readonly Mock _repositoryMock; + private readonly StreetcodeWithUrlExistHandler _handler; + + public StreetcodeWithUrlExistHandlerTests() + { + _repositoryMock = new Mock(); + + _handler = new StreetcodeWithUrlExistHandler( + _repositoryMock.Object); + } + + [Fact] + public async Task Handle_WhenStreetcodeExists_ReturnsTrue() + { + // Arrange + var request = new StreetcodeWithUrlExistQuery(Url: "existing-url"); + var testStreetcode = new StreetcodeContent { TransliterationUrl = "existing-url" }; + + _repositoryMock.Setup(repo => repo.StreetcodeRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), null)) + .ReturnsAsync(testStreetcode); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.True(result.Value); + }); + } + + [Fact] + public async Task Handle_WhenStreetcodeDoesNotExist_ReturnsFalse() + { + // Arrange + var request = new StreetcodeWithUrlExistQuery(Url: "non-existing-url"); + + _repositoryMock.Setup(repo => repo.StreetcodeRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), null)) + .ReturnsAsync((StreetcodeContent?)null); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.False(result.Value); + }); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/UpdateStatusStreetcodeByIdHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/UpdateStatusStreetcodeByIdHandlerTests.cs new file mode 100644 index 000000000..c8712b8b1 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/UpdateStatusStreetcodeByIdHandlerTests.cs @@ -0,0 +1,116 @@ +using System.Linq.Expressions; +using Moq; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Streetcode.UpdateStatus; +using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Enums; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class UpdateStatusStreetcodeByIdHandlerTests +{ + private readonly Mock _repositoryMock; + private readonly Mock _loggerMock; + private readonly MockFailedToUpdateLocalizer _mockFailedToUpdateLocalizer; + private readonly MockCannotFindLocalizer _mockCannotFindLocalizer; + private readonly UpdateStatusStreetcodeByIdHandler _handler; + + public UpdateStatusStreetcodeByIdHandlerTests() + { + _repositoryMock = new Mock(); + _loggerMock = new Mock(); + _mockCannotFindLocalizer = new MockCannotFindLocalizer(); + _mockFailedToUpdateLocalizer = new MockFailedToUpdateLocalizer(); + _handler = new UpdateStatusStreetcodeByIdHandler( + _repositoryMock.Object, + _loggerMock.Object, + _mockFailedToUpdateLocalizer, + _mockCannotFindLocalizer); + } + + [Fact] + public async Task Handle_WhenStreetcodeExists_UpdatesStatusSuccessfully() + { + // Arrange + var request = new UpdateStatusStreetcodeByIdCommand(1, StreetcodeStatus.Published); + var streetcode = new StreetcodeContent { Id = 1, Status = StreetcodeStatus.Draft }; + + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetFirstOrDefaultAsync(It.IsAny>>(), null)) + .ReturnsAsync(streetcode); + + _repositoryMock + .Setup(repo => repo.SaveChangesAsync()) + .ReturnsAsync(1); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.True(result.IsSuccess); + Assert.Equal(StreetcodeStatus.Published, streetcode.Status); + _repositoryMock.Verify(repo => repo.StreetcodeRepository.Update(streetcode), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Once); + }); + } + + [Fact] + public async Task Handle_WhenStreetcodeNotFound_ReturnsError() + { + // Arrange + var request = new UpdateStatusStreetcodeByIdCommand(999, StreetcodeStatus.Published); + const string expectedErrorKey = "CannotFindAnyStreetcodeWithCorrespondingId"; + string expectedErrorValue = _mockCannotFindLocalizer[expectedErrorKey, request.Id]; + + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetFirstOrDefaultAsync(It.IsAny>>(), null)) + .ReturnsAsync((StreetcodeContent)null!); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorValue, result.Errors[0].Message); + _loggerMock.Verify(logger => logger.LogError(request, expectedErrorValue), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Never); + }); + } + + [Fact] + public async Task Handle_WhenUpdateFails_ReturnsError() + { + // Arrange + var request = new UpdateStatusStreetcodeByIdCommand(1, StreetcodeStatus.Published); + var streetcode = new StreetcodeContent { Id = 1, Status = StreetcodeStatus.Draft }; + const string expectedErrorKey = "FailedToUpdateStatusOfStreetcode"; + string expectedErrorValue = _mockFailedToUpdateLocalizer[expectedErrorKey]; + + _repositoryMock + .Setup(repo => repo.StreetcodeRepository.GetFirstOrDefaultAsync(It.IsAny>>(), null)) + .ReturnsAsync(streetcode); + + _repositoryMock + .Setup(repo => repo.SaveChangesAsync()) + .ReturnsAsync(0); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.Multiple(() => + { + Assert.False(result.IsSuccess); + Assert.Contains(expectedErrorValue, result.Errors[0].Message); + _loggerMock.Verify(logger => logger.LogError(request, expectedErrorValue), Times.Once); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Once); + }); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/UpdateStreetcodeHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/UpdateStreetcodeHandlerTests.cs index 15112bc1a..3e72c7511 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/UpdateStreetcodeHandlerTests.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/UpdateStreetcodeHandlerTests.cs @@ -1,96 +1,1169 @@ -using AutoMapper; +using System.Linq.Expressions; +using System.Reflection; +using AutoMapper; +using FluentAssertions; using FluentResults; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Localization; using Moq; +using Streetcode.BLL.DTO.AdditionalContent.Coordinates.Update; +using Streetcode.BLL.DTO.AdditionalContent.Tag; +using Streetcode.BLL.DTO.Analytics.Update; +using Streetcode.BLL.DTO.Media.Art; +using Streetcode.BLL.DTO.Media.Audio; +using Streetcode.BLL.DTO.Media.Create; using Streetcode.BLL.DTO.Media.Images; -using Streetcode.BLL.DTO.Streetcode.Update; +using Streetcode.BLL.DTO.Partners.Update; +using Streetcode.BLL.DTO.Sources.Update; +using Streetcode.BLL.DTO.Streetcode.RelatedFigure; +using Streetcode.BLL.DTO.Timeline.Update; +using Streetcode.BLL.DTO.Toponyms; +using Streetcode.BLL.Enums; using Streetcode.BLL.Interfaces.Cache; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Streetcode.Streetcode.Update; -using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Entities.AdditionalContent; +using Streetcode.DAL.Entities.Analytics; +using Streetcode.DAL.Entities.Media.Images; +using Streetcode.DAL.Entities.Partners; +using Streetcode.DAL.Entities.Sources; using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Timeline; +using Streetcode.DAL.Entities.Toponyms; +using Streetcode.DAL.Entities.Transactions; +using Streetcode.DAL.Repositories.Interfaces.AdditionalContent; using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; using Xunit; -namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class UpdateStreetcodeHandlerTests { - public class UpdateStreetcodeHandlerTests - { - private readonly Mock repository; - private readonly Mock mapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerAnErrorOccurred; - private readonly Mock> mockLocalizerFailedToUpdate; - private readonly Mock> mockStringLocalizerFailedToValidate; - private readonly Mock> mockStringLocalizerFieldNames; - private readonly Mock mockCache; - private readonly Mock mockHttpContextAccessor; - - public UpdateStreetcodeHandlerTests() - { - this.repository = new Mock(); - this.mapper = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerAnErrorOccurred = new Mock>(); - this.mockLocalizerFailedToUpdate = new Mock>(); - this.mockStringLocalizerFailedToValidate = new Mock>(); - this.mockStringLocalizerFieldNames = new Mock>(); - this.mockCache = new Mock(); - this.mockCache - .Setup(c => c.GetOrSetAsync(It.IsAny(), It.IsAny>>>>(), It.IsAny())) - .Returns>>>, TimeSpan>((key, func, timeSpan) => + private readonly Mock _repositoryMock; + private readonly Mock _mapperMock; + private readonly UpdateStreetcodeHandler _handler; + + public UpdateStreetcodeHandlerTests() + { + _repositoryMock = new Mock(); + _mapperMock = new Mock(); + Mock mockLogger = new (); + MockAnErrorOccurredLocalizer mockLocalizerAnErrorOccurred = new (); + MockFailedToUpdateLocalizer mockLocalizerFailedToUpdate = new (); + MockFailedToValidateLocalizer mockStringLocalizerFailedToValidate = new (); + MockFieldNamesLocalizer mockStringLocalizerFieldNames = new (); + Mock mockHttpContextAccessor = new (); + Mock mockCache = new (); + mockCache + .Setup(c => c.GetOrSetAsync(It.IsAny(), It.IsAny>>>>(), It.IsAny())) + .Returns>>>, TimeSpan>((_, func, _) => func()); + _handler = new UpdateStreetcodeHandler( + _mapperMock.Object, + _repositoryMock.Object, + mockLogger.Object, + mockLocalizerAnErrorOccurred, + mockLocalizerFailedToUpdate, + mockStringLocalizerFailedToValidate, + mockStringLocalizerFieldNames, + mockCache.Object, + mockHttpContextAccessor.Object); + } + + [Fact] + public async Task UpdateEntitiesAsync_WhenUpdatingStatisticRecords_CallsRepositoryMethods() + { + // Arrange + var statisticRecords = new List + { + new () + { + Id = 1, QrId = 101, Count = 5, Address = "Kyiv", StreetcodeId = 1, + StreetcodeCoordinate = new StreetcodeCoordinateUpdateDTO { Latitude = 50.4501m, Longtitude = 30.5234m }, + ModelState = ModelState.Updated, + }, + new () + { + Id = 2, QrId = 102, Count = 10, Address = "Lviv", StreetcodeId = 1, + StreetcodeCoordinate = new StreetcodeCoordinateUpdateDTO { Latitude = 49.8397m, Longtitude = 24.0297m }, + ModelState = ModelState.Created, + }, + new () + { + Id = 3, QrId = 103, Count = 7, Address = "Odesa", StreetcodeId = 1, + StreetcodeCoordinate = new StreetcodeCoordinateUpdateDTO { Latitude = 46.4825m, Longtitude = 30.7233m }, + ModelState = ModelState.Deleted, + }, + }; + + var repositoryMock = new Mock>(); + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateEntitiesAsync", BindingFlags.NonPublic | BindingFlags.Instance) + ?.MakeGenericMethod(typeof(StatisticRecord), typeof(StatisticRecordUpdateDTO)); + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { statisticRecords, repositoryMock.Object }) !; + + // Assert + Assert.Multiple(() => + { + repositoryMock.Verify(repo => repo.UpdateRange(It.IsAny>()), Times.Once); + repositoryMock.Verify(repo => repo.CreateRangeAsync(It.IsAny>()), Times.Once); + repositoryMock.Verify(repo => repo.DeleteRange(It.IsAny>()), Times.Once); + }); + } + + [Fact] + public async Task UpdateEntitiesAsync_WhenUpdatingStreetcodeCategoryContent_CallsRepositoryMethods() + { + // Arrange + var categoryContents = new List + { + new () { Text = "Updated text", ModelState = ModelState.Updated }, + new () { Text = "New content", ModelState = ModelState.Created }, + new () { Text = "Deleted content", ModelState = ModelState.Deleted }, + }; + + var repositoryMock = new Mock>(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateEntitiesAsync", BindingFlags.NonPublic | BindingFlags.Instance) + ?.MakeGenericMethod(typeof(StreetcodeCategoryContent), typeof(StreetcodeCategoryContentUpdateDTO)); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { categoryContents, repositoryMock.Object }) !; + + // Assert + Assert.Multiple(() => + { + repositoryMock.Verify(repo => repo.UpdateRange(It.IsAny>()), Times.Once); + repositoryMock.Verify(repo => repo.CreateRangeAsync(It.IsAny>()), Times.Once); + repositoryMock.Verify(repo => repo.DeleteRange(It.IsAny>()), Times.Once); + }); + } + + [Fact] + public async Task UpdateEntitiesAsync_WhenUpdatingRelatedFigures_CallsRepositoryMethods() + { + // Arrange + var relatedFigures = new List + { + new () { ObserverId = 1, TargetId = 2, ModelState = ModelState.Updated }, + new () { ObserverId = 3, TargetId = 4, ModelState = ModelState.Created }, + new () { ObserverId = 5, TargetId = 6, ModelState = ModelState.Deleted }, + }; + + var repositoryMock = new Mock>(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateEntitiesAsync", BindingFlags.NonPublic | BindingFlags.Instance) + ?.MakeGenericMethod(typeof(RelatedFigure), typeof(RelatedFigureUpdateDTO)); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { relatedFigures, repositoryMock.Object }) !; + + // Assert + Assert.Multiple(() => + { + repositoryMock.Verify(repo => repo.UpdateRange(It.IsAny>()), Times.Once); + repositoryMock.Verify(repo => repo.CreateRangeAsync(It.IsAny>()), Times.Once); + repositoryMock.Verify(repo => repo.DeleteRange(It.IsAny>()), Times.Once); + }); + } + + [Fact] + public async Task UpdateEntitiesAsync_WhenUpdatingPartners_CallsRepositoryMethods() + { + // Arrange + var partners = new List + { + new () { StreetcodeId = 1, PartnerId = 10, ModelState = ModelState.Updated }, + new () { StreetcodeId = 2, PartnerId = 20, ModelState = ModelState.Created }, + new () { StreetcodeId = 3, PartnerId = 30, ModelState = ModelState.Deleted }, + }; + + var repositoryMock = new Mock>(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateEntitiesAsync", BindingFlags.NonPublic | BindingFlags.Instance) + ?.MakeGenericMethod(typeof(StreetcodePartner), typeof(PartnersUpdateDTO)); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { partners, repositoryMock.Object }) !; + + // Assert + Assert.Multiple(() => + { + repositoryMock.Verify(repo => repo.UpdateRange(It.IsAny>()), Times.Once); + repositoryMock.Verify(repo => repo.CreateRangeAsync(It.IsAny>()), Times.Once); + repositoryMock.Verify(repo => repo.DeleteRange(It.IsAny>()), Times.Once); + }); + } + + [Fact] + public async Task UpdateTags_WhenNewTags_CreatesSuccessfully() + { + // Arrange + var tags = new List + { + new () { Id = 0, Title = "NewTag", ModelState = ModelState.Created }, + }; + + SetupMockUpdateTags(tagExists: false); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateTags", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { tags }) !; + + // Assert + _repositoryMock.Verify(repo => repo.StreetcodeTagIndexRepository.CreateRangeAsync(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task UpdateTags_WhenTagAlreadyExists_ThrowsException() + { + // Arrange + var tags = new List + { + new () { Id = 0, Title = "ExistingTag", ModelState = ModelState.Created }, + }; + + SetupMockUpdateTags(tagExists: true); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateTags", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + Func action = async () => await (Task)methodInfo.Invoke(_handler, new object[] { tags }) !; + + // Assert + await action.Should().ThrowAsync(); + } + + [Fact] + public async Task UpdateTags_WhenTagsUpdated_CallsUpdateRange() + { + // Arrange + var tags = new List + { + new () { Id = 5, Title = "UpdatedTag", ModelState = ModelState.Updated }, + }; + + SetupMockUpdateTags(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateTags", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { tags }) !; + + // Assert + _repositoryMock.Verify(repo => repo.StreetcodeTagIndexRepository.UpdateRange(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task UpdateTags_WhenTagsDeleted_CallsDeleteRange() + { + // Arrange + var tags = new List + { + new () { Id = 5, Title = "DeletedTag", ModelState = ModelState.Deleted }, + }; + + SetupMockUpdateTags(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateTags", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { tags }) !; + + // Assert + _repositoryMock.Verify(repo => repo.StreetcodeTagIndexRepository.DeleteRange(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task UpdateStreetcodeToponymAsync_WhenCreatingToponyms_AddsToStreetcodeContent() + { + // Arrange + var streetcodeContent = new StreetcodeContent { Id = 10, Toponyms = new List() }; + var toponyms = new List + { + new () { StreetName = "New Street", ModelState = ModelState.Created }, + }; + + SetupMockUpdateToponyms(hasToponymsToCreate: true); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateStreetcodeToponymAsync", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { streetcodeContent, toponyms }) !; + + // Assert + Assert.Multiple(() => + { + Assert.Single(streetcodeContent.Toponyms); + Assert.Equal("New Street", streetcodeContent.Toponyms.First().StreetName); + }); + } + + [Fact] + public async Task UpdateStreetcodeToponymAsync_WhenDeletingToponyms_CallsExecuteSqlRaw() + { + // Arrange + var toponyms = new List + { + new () { StreetName = "Old Street", ModelState = ModelState.Deleted }, + }; + var streetcodeContent = new StreetcodeContent { Id = 10, Toponyms = new List() }; + + SetupMockUpdateToponyms(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateStreetcodeToponymAsync", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { streetcodeContent, toponyms }) !; + + // Assert + _repositoryMock.Verify(repo => repo.ToponymRepository.ExecuteSqlRaw(It.IsAny()), Times.Once); + } + + [Fact] + public async Task UpdateTimelineItemsAsync_WhenNewHistoricalContexts_CallsCreateRangeAsync() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1, TimelineItems = new List() }; + var timelineItems = new List + { + new () + { + Id = 1, + Title = "Event 1", + HistoricalContexts = new List + { + new () { Id = 0, Title = "New Context" }, + }, + ModelState = ModelState.Created, + }, + }; + + SetupMockUpdateTimelineItems(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateTimelineItemsAsync", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, timelineItems }) !; + + // Assert + _repositoryMock.Verify(repo => repo.HistoricalContextRepository.CreateRangeAsync(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task UpdateTimelineItemsAsync_WhenDeletingTimelineItem_CallsDeleteRange() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1 }; + var timelineItems = new List + { + new () { Id = 3, Title = "Deleted Event", ModelState = ModelState.Deleted }, + }; + + SetupMockUpdateTimelineItems(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateTimelineItemsAsync", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, timelineItems }) !; + + // Assert + _repositoryMock.Verify(repo => repo.TimelineRepository.DeleteRange(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task UpdateTimelineItemsAsync_WhenUpdatingTimelineItem_CallsHistoricalContextCreateRangeAsync() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1, TimelineItems = new List() }; + var timelineItems = new List + { + new () + { + Id = 4, + Title = "Updated Event", + ModelState = ModelState.Updated, + HistoricalContexts = new List() { - return func(); - }); - this.mockHttpContextAccessor = new Mock(); - } - - [Fact] - public async Task Handle_ReturnsSuccess() - { - // Arrange - var testStreetcode = new StreetcodeContent(); - var testStreetcodeDTO = new StreetcodeUpdateDTO(); - string expectedErrorMessage = "An error occurred while updating a streetcode"; - int testSaveChangesSuccess = 1; - - this.RepositorySetup(testStreetcode, testSaveChangesSuccess); - this.MapperSetup(testStreetcode); - - this.mockLocalizerAnErrorOccurred.Setup(x => x["AnErrorOccurredWhileUpdating", It.IsAny()]) - .Returns(new LocalizedString("AnErrorOccurredWhileUpdating", expectedErrorMessage)); - - var handler = - new UpdateStreetcodeHandler( - this.mapper.Object, - this.repository.Object, - this.mockLogger.Object, - this.mockLocalizerAnErrorOccurred.Object, - this.mockLocalizerFailedToUpdate.Object, - this.mockStringLocalizerFailedToValidate.Object, - this.mockStringLocalizerFieldNames.Object, - this.mockCache.Object, - this.mockHttpContextAccessor.Object); - - // Act - var result = await handler.Handle(new UpdateStreetcodeCommand(testStreetcodeDTO), CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.Equal(expectedErrorMessage, result.Errors[0].Message), - () => Assert.False(result.IsSuccess)); - } - - private void RepositorySetup(StreetcodeContent testStreetcode, int saveChangesVariable) - { - this.repository.Setup(x => x.StreetcodeRepository.Update(testStreetcode)); - this.repository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(saveChangesVariable); - } - - private void MapperSetup(StreetcodeContent? testStreetcode) - { - this.mapper.Setup(x => x.Map(It.IsAny())).Returns(testStreetcode); - } + new () { Id = 1, TimelineId = 4, ModelState = ModelState.Created }, + new () { Id = 2, TimelineId = 3, ModelState = ModelState.Deleted }, + }, + }, + }; + + SetupMockUpdateTimelineItems(); + + var methodInfo = typeof(UpdateStreetcodeHandler).GetMethod("UpdateTimelineItemsAsync", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, timelineItems }) !; + + // Assert + _repositoryMock.Verify(repo => repo.HistoricalContextTimelineRepository.CreateRangeAsync(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task UpdateTimelineItemsAsync_WhenUpdatingTimelineItem_CallsHistoricalContextDeleteRangeAsync() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1, TimelineItems = new List() }; + var timelineItems = new List + { + new () + { + Id = 4, + Title = "Updated Event", + ModelState = ModelState.Updated, + HistoricalContexts = new List() + { + new () { Id = 2, TimelineId = 3, ModelState = ModelState.Deleted }, + }, + }, + }; + + SetupMockUpdateTimelineItems(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateTimelineItemsAsync", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, timelineItems }) !; + + // Assert + _repositoryMock.Verify(repo => repo.HistoricalContextTimelineRepository.DeleteRange(It.IsAny>()), Times.Once); + } + + [Fact] + public void UpdateAudio_WhenCreatingNewAudio_UpdatesAudioId() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1 }; + var audios = new List + { + new () { Id = 100, ModelState = ModelState.Created }, + }; + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateAudio", BindingFlags.NonPublic | BindingFlags.Static); + + Assert.NotNull(methodInfo); + + // Act + methodInfo.Invoke(_handler, new object[] { audios, streetcode }); + + // Assert + Assert.Equal(100, streetcode.AudioId); + } + + [Fact] + public void UpdateAudio_WhenUpdatingAudio_UpdatesAudioId() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1 }; + var audios = new List + { + new () { Id = 200, ModelState = ModelState.Updated }, + }; + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateAudio", BindingFlags.NonPublic | BindingFlags.Static); + + Assert.NotNull(methodInfo); + + // Act + methodInfo.Invoke(_handler, new object[] { audios, streetcode }); + + // Assert + Assert.Equal(200, streetcode.AudioId); + } + + [Fact] + public async Task UpdateArtGallery_WhenDeletingOldStreetcodeArt_CallsDeleteRange() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1, StreetcodeArtSlides = new List() }; + var artSlides = new List(); + var arts = new List(); + + SetupMockUpdateArtGallery(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateArtGallery", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, artSlides, arts }) !; + + // Assert + _repositoryMock.Verify(repo => repo.StreetcodeArtRepository.DeleteRange(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task UpdateArtGallery_WhenCreatingNewArts_CallsCreateRange() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1, StreetcodeArtSlides = new List() }; + var artSlides = new List + { + new () { SlideId = 10, StreetcodeArts = new List { new () { ArtId = 101 } } }, + }; + var arts = new List + { + new () { Id = 101, ModelState = ModelState.Created }, + }; + + SetupMockUpdateArtGallery(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateArtGallery", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, artSlides, arts }) !; + + // Assert + _repositoryMock.Verify(repo => repo.ArtRepository.CreateRangeAsync(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task UpdateArtGallery_WhenDeletingUnusedArts_CallsDeleteRange() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1, StreetcodeArtSlides = new List() }; + var artSlides = new List + { + new () { SlideId = 20, StreetcodeArts = new List { new () { ArtId = 200 } } }, + }; + var arts = new List + { + new () { Id = 300, ModelState = ModelState.Updated }, // Цей не використовується, інший Id + }; + + SetupMockUpdateArtGallery(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateArtGallery", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, artSlides, arts }) !; + + // Assert + _repositoryMock.Verify(repo => repo.ArtRepository.DeleteRange(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task UpdateArtGallery_WhenUpdatingExistingArts_CallsUpdateRange() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1, StreetcodeArtSlides = new List() }; + var artSlides = new List + { + new () { SlideId = 30, StreetcodeArts = new List { new () { ArtId = 301 } } }, + }; + var arts = new List + { + new () { Id = 301, ModelState = ModelState.Updated }, + }; + + SetupMockUpdateArtGallery(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateArtGallery", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, artSlides, arts }) !; + + // Assert + _repositoryMock.Verify(repo => repo.ArtRepository.UpdateRange(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task UpdateArtGallery_WhenCreatingNewArtSlides_CallsCreateAsync() + { + // Arrange + var streetcode = new StreetcodeContent { Id = 1, StreetcodeArtSlides = new List() }; + var artSlides = new List + { + new () { SlideId = 40, ModelState = ModelState.Created }, + }; + var arts = new List(); + + SetupMockUpdateArtGallery(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateArtGallery", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { streetcode, artSlides, arts }) !; + + // Assert + _repositoryMock.Verify(repo => repo.StreetcodeArtSlideRepository.CreateAsync(It.IsAny()), Times.Once); + } + + [Fact] + public void GetStreetcodeArtsWithNewArtsId_WhenArtIdExistsInMap_UpdatesArtId() + { + // Arrange + var streetcodeId = 1; + var artIdMap = new Dictionary + { + { 100, 200 }, // ArtId 100 буде змінено на 200 + }; + + var streetcodeArtSlide = new StreetcodeArtSlideCreateUpdateDTO + { + StreetcodeArts = new List + { + new () { ArtId = 100 }, + }, + }; + + SetupMockGetStreetcodeArtsWithNewArtsId(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("GetStreetcodeArtsWithNewArtsId", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + var result = (List)methodInfo.Invoke(_handler, new object[] { streetcodeId, artIdMap, streetcodeArtSlide }) !; + + // Assert + Assert.Multiple(() => + { + Assert.Single(result); + Assert.Equal(200, result[0].ArtId); + }); + } + + [Fact] + public void GetStreetcodeArtsWithNewArtsId_WhenArtIdNotInMap_KeepsOriginalArtId() + { + // Arrange + var streetcodeId = 1; + var artIdMap = new Dictionary(); + + var streetcodeArtSlide = new StreetcodeArtSlideCreateUpdateDTO + { + StreetcodeArts = new List + { + new () { ArtId = 300 }, + }, + }; + + SetupMockGetStreetcodeArtsWithNewArtsId(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("GetStreetcodeArtsWithNewArtsId", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + var result = (List)methodInfo.Invoke(_handler, new object[] { streetcodeId, artIdMap, streetcodeArtSlide }) !; + + // Assert + Assert.Multiple(() => + { + Assert.Single(result); + Assert.Equal(300, result[0].ArtId); + }); + } + + [Fact] + public void GetStreetcodeArtsWithNewArtsId_CreatesStreetcodeArtWithCorrectStreetcodeId() + { + // Arrange + var streetcodeId = 5; + var artIdMap = new Dictionary(); + + var streetcodeArtSlide = new StreetcodeArtSlideCreateUpdateDTO + { + StreetcodeArts = new List + { + new () { ArtId = 400 }, + }, + }; + + SetupMockGetStreetcodeArtsWithNewArtsId(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("GetStreetcodeArtsWithNewArtsId", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + var result = (List)methodInfo.Invoke(_handler, new object[] { streetcodeId, artIdMap, streetcodeArtSlide }) !; + + // Assert + Assert.Multiple(() => + { + Assert.Single(result); + Assert.Equal(5, result[0].StreetcodeId); + }); + } + + [Fact] + public void DistributeArtSlide_WhenDeleted_AddsToDeleteSlides() + { + // Arrange + var artSlideDto = new StreetcodeArtSlideCreateUpdateDTO { ModelState = ModelState.Deleted }; + var artSlide = new StreetcodeArtSlide(); + var newStreetcodeArts = new List(); + + StreetcodeArtSlide? toCreateSlide = null; + var toUpdateSlides = new List(); + var toDeleteSlides = new List(); + var toCreateStreetcodeArts = new List(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("DistributeArtSlide", BindingFlags.NonPublic | BindingFlags.Static); + + Assert.NotNull(methodInfo); + + // Act + methodInfo.Invoke(_handler, new object[] { artSlideDto, artSlide, newStreetcodeArts, toCreateSlide!, toUpdateSlides, toDeleteSlides, toCreateStreetcodeArts }); + + // Assert + Assert.Multiple(() => + { + Assert.Single(toDeleteSlides); + Assert.Contains(artSlide, toDeleteSlides); + }); + } + + [Fact] + public void DistributeArtSlide_WhenUpdated_AddsToUpdateSlidesAndCreatesStreetcodeArts() + { + // Arrange + var artSlideDto = new StreetcodeArtSlideCreateUpdateDTO + { + SlideId = 10, + ModelState = ModelState.Updated, + }; + + var artSlide = new StreetcodeArtSlide(); + var newStreetcodeArts = new List + { + new () { ArtId = 1 }, + new () { ArtId = 2 }, + }; + + StreetcodeArtSlide? toCreateSlide = null; + var toUpdateSlides = new List(); + var toDeleteSlides = new List(); + var toCreateStreetcodeArts = new List(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("DistributeArtSlide", BindingFlags.NonPublic | BindingFlags.Static); + + Assert.NotNull(methodInfo); + + // Act + methodInfo.Invoke(_handler, new object[] { artSlideDto, artSlide, newStreetcodeArts, toCreateSlide!, toUpdateSlides, toDeleteSlides, toCreateStreetcodeArts }); + + // Assert + Assert.Multiple(() => + { + Assert.Single(toUpdateSlides); + Assert.Contains(artSlide, toUpdateSlides); + Assert.Equal(2, toCreateStreetcodeArts.Count); + Assert.All(toCreateStreetcodeArts, art => Assert.Equal(artSlideDto.SlideId, art.StreetcodeArtSlideId)); + }); + } + + [Fact] + public void DistributeArtSlide_WhenCreated_SetsToCreateSlide() + { + // Arrange + var artSlideDto = new StreetcodeArtSlideCreateUpdateDTO { ModelState = ModelState.Created }; + var artSlide = new StreetcodeArtSlide(); + var newStreetcodeArts = new List(); + + StreetcodeArtSlide? toCreateSlide = null; + var toUpdateSlides = new List(); + var toDeleteSlides = new List(); + var toCreateStreetcodeArts = new List(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("DistributeArtSlide", BindingFlags.NonPublic | BindingFlags.Static); + + Assert.NotNull(methodInfo); + + var parameters = new object?[] { artSlideDto, artSlide, newStreetcodeArts, toCreateSlide, toUpdateSlides, toDeleteSlides, toCreateStreetcodeArts }; + + // Act + methodInfo.Invoke(_handler, parameters); + toCreateSlide = (StreetcodeArtSlide?)parameters[3]; + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(toCreateSlide); + Assert.Equal(artSlide, toCreateSlide); + }); + } + + [Fact] + public async Task UpdateImagesAsync_WhenDeletingImages_CallsDeleteRange() + { + // Arrange + var images = new List + { + new () { Id = 1, ModelState = ModelState.Deleted }, + new () { Id = 2, ModelState = ModelState.Deleted }, + }; + + SetupMockUpdateImages(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateImagesAsync", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { images }) !; + + // Assert + _repositoryMock.Verify(repo => repo.ImageRepository.DeleteRange(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task UpdateImagesAsync_WhenCreatingNewImages_CallsCreateRangeAsync() + { + // Arrange + var images = new List + { + new () { Id = 3, ModelState = ModelState.Created }, + new () { Id = 4, ModelState = ModelState.Created }, + }; + + SetupMockUpdateImages(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateImagesAsync", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { images }) !; + + // Assert + _repositoryMock.Verify(repo => repo.StreetcodeImageRepository.CreateRangeAsync(It.IsAny>()), Times.Once); + } + + [Fact] + public void UpdateTransactionLink_WhenUrlIsNull_CreatesEmptyTransactionLink() + { + // Arrange + var streetcode = new StreetcodeContent { TransactionLink = null }; + string? url = null; + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateTransactionLink", BindingFlags.NonPublic | BindingFlags.Static); + + Assert.NotNull(methodInfo); + + // Act + methodInfo.Invoke(_handler, new object[] { streetcode, url! }); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(streetcode.TransactionLink); + Assert.Equal(string.Empty, streetcode.TransactionLink.Url); + Assert.Equal(string.Empty, streetcode.TransactionLink.UrlTitle); + }); + } + + [Fact] + public void UpdateTransactionLink_WhenUrlIsNotNull_DoesNotChangeTransactionLink() + { + // Arrange + var streetcode = new StreetcodeContent + { + TransactionLink = new TransactionLink { Url = "https://example.com", UrlTitle = "Example" }, + }; + const string url = "https://new-url.com"; + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateTransactionLink", BindingFlags.NonPublic | BindingFlags.Static); + + Assert.NotNull(methodInfo); + + // Act + methodInfo.Invoke(_handler, new object[] { streetcode, url }); + + // Assert + Assert.Multiple(() => + { + Assert.NotNull(streetcode.TransactionLink); + Assert.Equal("https://example.com", streetcode.TransactionLink.Url); + Assert.Equal("Example", streetcode.TransactionLink.UrlTitle); + }); + } + + [Fact] + public async Task UpdateFactsDescription_WhenAltIsEmpty_DeletesImageDetails() + { + // Arrange + var imageDetails = new List + { + new () { Id = 1, Alt = string.Empty }, + new () { Id = 2, Alt = string.Empty }, + }; + + SetupMockUpdateFactsDescription(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateFactsDescription", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { imageDetails }) !; + + // Assert + _repositoryMock.Verify(repo => repo.ImageDetailsRepository.DeleteRange(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task UpdateFactsDescription_WhenAltIsNotEmpty_UpdatesImageDetails() + { + // Arrange + var imageDetails = new List + { + new () { Id = 3, Alt = "1" }, + new () { Id = 4, Alt = "0" }, + }; + + SetupMockUpdateFactsDescription(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateFactsDescription", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { imageDetails }) !; + + // Assert + _repositoryMock.Verify(repo => repo.ImageDetailsRepository.UpdateRange(It.IsAny>()), Times.Once); + } + + [Fact] + public async Task UpdateFactsDescription_WhenNull_NothingIsCalled() + { + // Arrange + IEnumerable? imageDetails = null; + + SetupMockUpdateFactsDescription(); + + var methodInfo = typeof(UpdateStreetcodeHandler) + .GetMethod("UpdateFactsDescription", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.NotNull(methodInfo); + + // Act + await (Task)methodInfo.Invoke(_handler, new object[] { imageDetails! }) !; + + // Assert + Assert.Multiple(() => + { + _repositoryMock.Verify(repo => repo.ImageDetailsRepository.DeleteRange(It.IsAny>()), Times.Never); + _repositoryMock.Verify(repo => repo.ImageDetailsRepository.UpdateRange(It.IsAny>()), Times.Never); + _repositoryMock.Verify(repo => repo.SaveChangesAsync(), Times.Never); + }); + } + + private void SetupMockUpdateTags(bool tagExists = false) + { + _repositoryMock + .Setup(repo => repo.TagRepository.GetFirstOrDefaultAsync(It.IsAny>>(), null)) + .ReturnsAsync(tagExists ? new Tag { Id = 100, Title = "ExistingTag" } : null); + + _repositoryMock.Setup(x => x.StreetcodeTagIndexRepository) + .Returns(new Mock().Object); + } + + private void SetupMockUpdateToponyms(bool hasToponymsToCreate = false) + { + _repositoryMock + .Setup(repo => repo.ToponymRepository.ExecuteSqlRaw(It.IsAny())) + .Returns(Task.CompletedTask); + + _repositoryMock + .Setup(repo => repo.ToponymRepository.GetAllAsync(It.IsAny>>(), null)) + .ReturnsAsync(hasToponymsToCreate ? new List { new () { Id = 1, StreetName = "New Street" } } : new List()); + } + + private void SetupMockUpdateTimelineItems() + { + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((IEnumerable src) => + src.Select(s => new HistoricalContext() + { + Id = s.Id, + Title = s.Title, + }).ToList()); + + _mapperMock + .Setup(m => m.Map(It.IsAny())) + .Returns(( + TimelineItemCreateUpdateDTO src) => new TimelineItem() + { + Id = src.Id, + HistoricalContextTimelines = new List(), + }); + + _repositoryMock + .Setup(repo => repo.HistoricalContextRepository.CreateRangeAsync(It.IsAny>())) + .Returns(Task.CompletedTask); + + _repositoryMock + .Setup(repo => repo.HistoricalContextTimelineRepository.CreateRangeAsync(It.IsAny>())) + .Returns(Task.CompletedTask); + + _repositoryMock.Setup(repo => repo.TimelineRepository.DeleteRange(It.IsAny>())); + + _repositoryMock + .Setup(repo => repo.TimelineRepository.UpdateRange(It.IsAny>())); + } + + private void SetupMockUpdateArtGallery() + { + _mapperMock + .Setup(m => m.Map(It.IsAny())) + .Returns((StreetcodeArtSlideCreateUpdateDTO src) => new StreetcodeArtSlide + { + Id = src.SlideId, + StreetcodeId = src.StreetcodeId ?? 0, + Template = src.Template, + Index = src.Index, + }); + + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((List src) => + src.Select(s => new Art() + { + Id = s.Id, + ImageId = s.ImageId, + Description = s.Description, + Title = s.Title, + }).ToList()); + + _mapperMock + .Setup(m => m.Map(It.IsAny())) + .Returns((ArtCreateUpdateDTO src) => new Art() + { + Id = src.Id, + ImageId = src.ImageId, + Description = src.Description, + Title = src.Title, + }); + + _mapperMock + .Setup(m => m.Map(It.IsAny())) + .Returns((StreetcodeArtCreateUpdateDTO src) => new StreetcodeArt() + { + Id = src.ArtId, + }); + + _repositoryMock.Setup(repo => repo.StreetcodeArtSlideRepository.CreateRangeAsync(It.IsAny>())) + .Returns(Task.CompletedTask); + + _repositoryMock.Setup(repo => repo.ArtRepository.CreateRangeAsync(It.IsAny>())) + .Returns(Task.CompletedTask); + + _repositoryMock.Setup(repo => repo.StreetcodeArtRepository.CreateRangeAsync(It.IsAny>())) + .Returns(Task.CompletedTask); + } + + private void SetupMockGetStreetcodeArtsWithNewArtsId() + { + _mapperMock + .Setup(m => m.Map(It.IsAny())) + .Returns((StreetcodeArtCreateUpdateDTO src) => new StreetcodeArt { ArtId = src.ArtId }); + } + + private void SetupMockUpdateImages() + { + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((IEnumerable src) => + src.Select(img => new Image { Id = img.Id }).ToList()); + + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((IEnumerable src) => + src.Select(img => new StreetcodeImage { ImageId = img.Id }).ToList()); + + _repositoryMock + .Setup(repo => repo.ImageRepository.DeleteRange(It.IsAny>())); + + _repositoryMock + .Setup(repo => repo.StreetcodeImageRepository.CreateRangeAsync(It.IsAny>())) + .Returns(Task.CompletedTask); + } + + private void SetupMockUpdateFactsDescription() + { + _mapperMock + .Setup(m => m.Map>(It.IsAny>())) + .Returns((IEnumerable src) => + src.Select(d => new ImageDetails { Id = d.Id, Alt = d.Alt }).ToList()); + + _repositoryMock.Setup(repo => repo.ImageDetailsRepository.DeleteRange(It.IsAny>())); + + _repositoryMock.Setup(repo => repo.ImageDetailsRepository.UpdateRange(It.IsAny>())); } } \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/WithIndexExistHandlerTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/WithIndexExistHandlerTest.cs index 4bdc04b18..2528b0360 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/WithIndexExistHandlerTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Streetcode/WithIndexExistHandlerTest.cs @@ -1,83 +1,76 @@ using System.Linq.Expressions; -using AutoMapper; using FluentResults; using Microsoft.EntityFrameworkCore.Query; using Moq; -using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Streetcode.Streetcode.WithIndexExist; using Streetcode.DAL.Entities.Streetcode; using Streetcode.DAL.Repositories.Interfaces.Base; using Xunit; -namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Streetcode; + +public class WithIndexExistHandlerTest { - public class WithIndexExistHandlerTest - { - private readonly Mock repository; - private readonly Mock mapper; - private readonly Mock mockLogger; + private readonly Mock _repository; - public WithIndexExistHandlerTest() - { - this.repository = new Mock(); - this.mapper = new Mock(); - this.mockLogger = new Mock(); - } + public WithIndexExistHandlerTest() + { + _repository = new Mock(); + } - [Theory] - [InlineData(1)] - public async Task ShouldReturnSuccesfully(int id) - { - // Arrange - this.repository.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( + [Theory] + [InlineData(1)] + public async Task ShouldReturnSuccesfully(int id) + { + // Arrange + _repository.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( It.IsAny>>(), It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(this.GetStreetCodeContent(id)); + IIncludableQueryable>>())) + .ReturnsAsync(GetStreetCodeContent(id)); - var handler = new StreetcodeWithIndexExistHandler(this.repository.Object, this.mapper.Object, this.mockLogger.Object); + var handler = new StreetcodeWithIndexExistHandler(_repository.Object); - // Act - var result = await handler.Handle(new StreetcodeWithIndexExistQuery(id), CancellationToken.None); + // Act + var result = await handler.Handle(new StreetcodeWithIndexExistQuery(id), CancellationToken.None); - // Assert - Assert.Multiple( - () => Assert.NotNull(result), - () => Assert.IsAssignableFrom>(result), - () => Assert.True(result.Value)); - } + // Assert + Assert.Multiple( + () => Assert.NotNull(result), + () => Assert.IsAssignableFrom>(result), + () => Assert.True(result.Value)); + } - [Theory] - [InlineData(1)] - public async Task ShouldReturnFalse_NotExistingId(int id) - { - // Arrange - this.repository.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( + [Theory] + [InlineData(1)] + public async Task ShouldReturnFalse_NotExistingId(int id) + { + // Arrange + _repository.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( It.IsAny>>(), It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(this.GetNull()); + IIncludableQueryable>>())) + .ReturnsAsync(GetNull()); - var handler = new StreetcodeWithIndexExistHandler(this.repository.Object, this.mapper.Object, this.mockLogger.Object); + var handler = new StreetcodeWithIndexExistHandler(_repository.Object); - // Act - var result = await handler.Handle(new StreetcodeWithIndexExistQuery(id), CancellationToken.None); + // Act + var result = await handler.Handle(new StreetcodeWithIndexExistQuery(id), CancellationToken.None); - // Assert - Assert.Multiple( - () => Assert.NotNull(result), - () => Assert.IsAssignableFrom>(result), - () => Assert.False(result.Value)); - } + // Assert + Assert.Multiple( + () => Assert.NotNull(result), + () => Assert.IsAssignableFrom>(result), + () => Assert.False(result.Value)); + } - private StreetcodeContent GetStreetCodeContent(int id) - { - return new StreetcodeContent() { Id = id }; - } + private StreetcodeContent GetStreetCodeContent(int id) + { + return new StreetcodeContent() { Id = id }; + } - private StreetcodeContent? GetNull() - { - return null; - } + private StreetcodeContent? GetNull() + { + return null; } -} +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/CreateTermHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/CreateTermHandlerTests.cs deleted file mode 100644 index b58a4df19..000000000 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/CreateTermHandlerTests.cs +++ /dev/null @@ -1,89 +0,0 @@ -using AutoMapper; -using Microsoft.Extensions.Localization; -using Moq; -using Streetcode.BLL.DTO.Streetcode.TextContent; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.MediatR.Streetcode.Term.Create; -using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Entities.Streetcode.TextContent; -using Streetcode.DAL.Repositories.Interfaces.Base; -using Xunit; - -namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Terms -{ - public class CreateTermHandlerTests - { - private readonly Mock mockRepository; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotCreate; - private readonly Mock> mockLocalizerFailedToCreate; - private readonly Mock> mockLocalizerCannotConvertNull; - - public CreateTermHandlerTests() - { - this.mockMapper = new (); - this.mockRepository = new (); - this.mockLogger = new Mock(); - this.mockLocalizerCannotConvertNull = new Mock>(); - this.mockLocalizerCannotCreate = new Mock>(); - this.mockLocalizerFailedToCreate = new Mock>(); - } - - [Theory] - [InlineData(1)] - public async Task ShouldReturnSuccessfully_WhenTermAdded(int returnNumber) - { - // Arrange - var createdTerm = GetTerm(); - this.mockRepository.Setup(x => x.TermRepository.Create(It.IsAny())).Returns(createdTerm); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(returnNumber); - - this.mockMapper.Setup(x => x.Map(It.IsAny())).Returns(createdTerm); - this.mockMapper.Setup(x => x.Map(createdTerm)).Returns(GetTermDTO()); - - var handler = new CreateTermHandler(this.mockMapper.Object, this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerCannotCreate.Object, this.mockLocalizerFailedToCreate.Object, this.mockLocalizerCannotConvertNull.Object); - - // Act - var result = await handler.Handle(new CreateTermCommand(GetTermCreateDTO()), CancellationToken.None); - - // Assert - Assert.True(result.IsSuccess); - } - - [Theory] - [InlineData(1)] - public async Task ShouldThrowException_WhenTryToAddNull(int returnNumber) - { - // Arrange - this.mockRepository.Setup(x => x.TermRepository.Create(GetTerm())); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(returnNumber); - - this.mockMapper.Setup(x => x.Map(It.IsAny())) - .Returns(GetNotExistingTerm() !); - - var expectedError = "Cannot convert null to Term"; - this.mockLocalizerCannotConvertNull.Setup(x => x["CannotConvertNullToTerm"]) - .Returns(new LocalizedString("CannotConvertNullToTerm", expectedError)); - var hendler = new CreateTermHandler(this.mockMapper.Object, this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerCannotCreate.Object, this.mockLocalizerFailedToCreate.Object, this.mockLocalizerCannotConvertNull.Object); - - // Act - var result = await hendler.Handle(new CreateTermCommand(GetNotExistingTermDTO() !), CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.Equal(expectedError, result.Errors[0].Message), - () => Assert.False(result.IsSuccess)); - } - - private static Term GetTerm() => new (); - - private static TermCreateDTO GetTermCreateDTO() => new (); - - private static TermDTO GetTermDTO() => new (); - - private static Term? GetNotExistingTerm() => null; - - private static TermCreateDTO? GetNotExistingTermDTO() => null; - } -} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/CreateTermTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/CreateTermTest.cs new file mode 100644 index 000000000..1fefe509e --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/CreateTermTest.cs @@ -0,0 +1,173 @@ +using AutoMapper; +using FluentAssertions; +using Moq; +using Streetcode.BLL.DTO.Streetcode.TextContent; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Term.Create; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Terms; + +public class CreateTermTest +{ + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly MockFailedToCreateLocalizer _mockFailedToCreateLocalizer; + private readonly MockCannotConvertNullLocalizer _mockCannotConvertNullLocalizer; + private readonly CreateTermHandler _handler; + + public CreateTermTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockFailedToCreateLocalizer = new MockFailedToCreateLocalizer(); + _mockCannotConvertNullLocalizer = new MockCannotConvertNullLocalizer(); + _handler = new CreateTermHandler( + _mockMapper.Object, + _mockRepository.Object, + _mockLogger.Object, + _mockFailedToCreateLocalizer, + _mockCannotConvertNullLocalizer); + } + + [Fact] + public async Task ShouldCreateSuccessfully_WhenRelatedTermAdded() + { + // Arrange + var (termCreateDto, term, termDto) = GetTermObjects(); + var request = GetRequest(termCreateDto); + + SetupMockCreateAndSaveChangesAsync(term, 1); + MockHelpers.SetupMockMapper(_mockMapper, term, request.Term); + MockHelpers.SetupMockMapper(_mockMapper, termDto, term); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Title.Should().Be(termCreateDto.Title); + _mockRepository.Verify(x => x.TermRepository.CreateAsync(term), Times.Once); + _mockRepository.Verify(x => x.SaveChangesAsync(), Times.Once); + _mockMapper.Verify(x => x.Map(term), Times.Once); + } + + [Fact] + public async Task ShouldCreateSuccessfully_WithCorrectDataType() + { + // Arrange + var (termCreateDto, term, termDto) = GetTermObjects(); + var request = GetRequest(termCreateDto); + + SetupMockCreateAndSaveChangesAsync(term, 1); + MockHelpers.SetupMockMapper(_mockMapper, term, request.Term); + MockHelpers.SetupMockMapper(_mockMapper, termDto, term); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Should().BeOfType(); + } + + [Fact] + public async Task ShouldCreateSuccessfully_WhenSaveChangesAsyncFailed() + { + // Arrange + var (termCreateDto, term, _) = GetTermObjects(); + var request = GetRequest(termCreateDto); + var expectedErrorMessage = _mockFailedToCreateLocalizer["FailedToCreateTerm"].Value; + + SetupMockCreateAndSaveChangesAsync(term, -1); + MockHelpers.SetupMockMapper(_mockMapper, term, request.Term); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + [Fact] + public async Task ShouldCreateFailingly_WhenFirstMappingFailed() + { + // Arrange + var (termCreateDto, _, _) = GetTermObjects(); + var request = GetRequest(termCreateDto); + var expectedErrorMessage = _mockCannotConvertNullLocalizer["CannotConvertNullToTerm"].Value; + + MockHelpers.SetupMockMapper(_mockMapper, null, request.Term); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + [Fact] + public async Task ShouldCreateFailingly_WhenSecondMappingFailed() + { + // Arrange + var (termCreateDto, term, _) = GetTermObjects(); + var request = GetRequest(termCreateDto); + var expectedErrorMessage = _mockFailedToCreateLocalizer["FailedToMapCreatedTerm"].Value; + + SetupMockCreateAndSaveChangesAsync(term, 1); + MockHelpers.SetupMockMapper(_mockMapper, term, request.Term); + MockHelpers.SetupMockMapper(_mockMapper, null, term); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + private static (TermCreateDTO, Term, TermDTO) GetTermObjects() + { + const string title = "qwerty"; + + var termCreateDto = new TermCreateDTO() + { + Title = title, + }; + var term = new Term() + { + Title = title, + }; + var termDto = new TermDTO() + { + Title = title, + }; + + return (termCreateDto, term, termDto); + } + + private static CreateTermCommand GetRequest(TermCreateDTO termCreateDto) + { + return new CreateTermCommand(termCreateDto); + } + + private void SetupMockCreateAndSaveChangesAsync(Term term, int saveChangesResult) + { + _mockRepository + .Setup(x => x.TermRepository.CreateAsync(term)) + .ReturnsAsync(term); + _mockRepository + .Setup(x => x.SaveChangesAsync()) + .ReturnsAsync(saveChangesResult); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/DeleteTermHendlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/DeleteTermHendlerTests.cs deleted file mode 100644 index 4c0b9afd2..000000000 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/DeleteTermHendlerTests.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System.Linq.Expressions; -using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; -using Moq; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.MediatR.Streetcode.Term.Delete; -using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Entities.Streetcode.TextContent; -using Streetcode.DAL.Repositories.Interfaces.Base; - -using Xunit; - -namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Terms -{ - public class DeleteTermHendlerTests - { - private readonly Mock mockRepository; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerFailedToCreate; - private readonly Mock> mockLocalizerCannotConvertNull; - - public DeleteTermHendlerTests() - { - this.mockRepository = new (); - this.mockLogger = new Mock(); - this.mockLocalizerFailedToCreate = new Mock>(); - this.mockLocalizerCannotConvertNull = new Mock>(); - } - - [Theory] - [InlineData(-1, 1)] - public async Task ShouldDeleteSuccessfully(int id, int returnNuber) - { - // Arrange - MockRepoInitial_GetFirstOrDefault_Delete(this.mockRepository, id, true); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(returnNuber); - var handler = new DeleteTermHandler(this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerFailedToCreate.Object, this.mockLocalizerCannotConvertNull.Object); - - // Act - var result = await handler.Handle(new DeleteTermCommand(id), CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.NotNull(result), - () => Assert.True(result.IsSuccess)); - } - - [Theory] - [InlineData(2)] - public async Task ShouldThrowExeption_IdNotExisting(int id) - { - // Arrange - MockRepoInitial_GetFirstOrDefault_Delete(this.mockRepository, id, false); - - var expectedError = "Cannot convert null to Term"; - this.mockLocalizerCannotConvertNull.Setup(x => x["CannotConvertNullToTerm"]) - .Returns(new LocalizedString("CannotConvertNullToTerm", expectedError)); - - var handler = new DeleteTermHandler(this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerFailedToCreate.Object, this.mockLocalizerCannotConvertNull.Object); - - // Act - var result = await handler.Handle(new DeleteTermCommand(id), CancellationToken.None); - - // Assert - Assert.Equal(expectedError, result.Errors[0].Message); - } - - [Theory] - [InlineData(2, 0)] - public async Task ShouldThrowExeption_SaveChangesAsyncIsNotSuccessful(int id, int returnNuber) - { - // Arange - MockRepoInitial_GetFirstOrDefault_Delete(this.mockRepository, id, true); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(returnNuber); - - var expectedError = "Failed to delete a term"; - this.mockLocalizerFailedToCreate.Setup(x => x["FailedToDeleteTerm"]) - .Returns(new LocalizedString("FailedToDeleteTerm", expectedError)); - var hendler = new DeleteTermHandler(this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerFailedToCreate.Object, this.mockLocalizerCannotConvertNull.Object); - - // Act - var result = await hendler.Handle(new DeleteTermCommand(id), CancellationToken.None); - - // Assert - Assert.Equal(expectedError, result.Errors[0].Message); - } - - private static void MockRepoInitial_GetFirstOrDefault_Delete( - Mock mockRepo, int id, bool isIdExist) - { - mockRepo.Setup(x => x.TermRepository - .GetFirstOrDefaultAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(isIdExist ? GetTerm(id) : GetNotExistingTerm() !); - - mockRepo.Setup(x => x.TermRepository.Delete(isIdExist ? GetTerm(id) : GetNotExistingTerm() !)); - } - - private static Term GetTerm(int id) => new () { Id = id }; - - private static Term? GetNotExistingTerm() => null; - } -} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/DeleteTermTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/DeleteTermTest.cs new file mode 100644 index 000000000..3e17d59be --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/DeleteTermTest.cs @@ -0,0 +1,135 @@ +using FluentAssertions; +using MediatR; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Term.Delete; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Terms; + +public class DeleteTermTest +{ + private readonly Mock _mockRepository; + private readonly Mock _mockLogger; + private readonly MockFailedToDeleteLocalizer _mockFailedToDeleteLocalizer; + private readonly MockCannotConvertNullLocalizer _mockCannotConvertNullLocalizer; + private readonly DeleteTermHandler _handler; + + public DeleteTermTest() + { + _mockRepository = new Mock(); + _mockLogger = new Mock(); + _mockFailedToDeleteLocalizer = new MockFailedToDeleteLocalizer(); + _mockCannotConvertNullLocalizer = new MockCannotConvertNullLocalizer(); + _handler = new DeleteTermHandler( + _mockRepository.Object, + _mockLogger.Object, + _mockFailedToDeleteLocalizer, + _mockCannotConvertNullLocalizer); + } + + [Theory] + [InlineData(1)] + public async Task ShouldDeleteSuccessfully_WhenTermExists(int termId) + { + // Arrange + var term = GetTerm(termId); + var request = GetRequest(termId); + + MockHelpers.SetupMockTermGetFirstOrDefaultAsync(_mockRepository, term); + SetupMockDeleteAndSaveChangesAsync(term, 1); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + _mockRepository.Verify(x => x.TermRepository.Delete(term), Times.Once); + _mockRepository.Verify(x => x.SaveChangesAsync(), Times.Once); + } + + [Theory] + [InlineData(1)] + public async Task ShouldDeleteSuccessfully_WithCorrectDataType(int termId) + { + // Arrange + var term = GetTerm(termId); + var request = GetRequest(termId); + + MockHelpers.SetupMockTermGetFirstOrDefaultAsync(_mockRepository, term); + SetupMockDeleteAndSaveChangesAsync(term, 1); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType(); + } + + [Theory] + [InlineData(1)] + public async Task ShouldDeleteFailingly_WhenTermNotExist(int termId) + { + // Arrange + var request = GetRequest(termId); + var expectedErrorMessage = _mockCannotConvertNullLocalizer["CannotConvertNullToTerm"].Value; + + MockHelpers.SetupMockTermGetFirstOrDefaultAsync(_mockRepository, null); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + [Theory] + [InlineData(1)] + public async Task ShouldDeleteFailingly_WhenSaveChangesAsyncFailed(int termId) + { + // Arrange + var term = GetTerm(termId); + var request = GetRequest(termId); + var expectedErrorMessage = _mockFailedToDeleteLocalizer["FailedToDeleteTerm"].Value; + + MockHelpers.SetupMockTermGetFirstOrDefaultAsync(_mockRepository, term); + SetupMockDeleteAndSaveChangesAsync(term, -1); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + private static Term GetTerm(int termId) + { + return new Term() + { + Id = termId, + }; + } + + private static DeleteTermCommand GetRequest(int termId) + { + return new DeleteTermCommand(termId); + } + + private void SetupMockDeleteAndSaveChangesAsync(Term term, int saveChangesResult) + { + _mockRepository + .Setup(x => x.TermRepository.Delete(term)); + _mockRepository + .Setup(x => x.SaveChangesAsync()) + .ReturnsAsync(saveChangesResult); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/GetAllTermsTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/GetAllTermsTest.cs new file mode 100644 index 000000000..31f341563 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/GetAllTermsTest.cs @@ -0,0 +1,135 @@ +using System.Linq.Expressions; +using AutoMapper; +using FluentAssertions; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.DTO.Streetcode.TextContent; +using Streetcode.BLL.MediatR.Streetcode.Term.GetAll; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Terms; + +public class GetAllTermsTest +{ + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly GetAllTermsHandler _handler; + + public GetAllTermsTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _handler = new GetAllTermsHandler(_mockRepository.Object, _mockMapper.Object); + } + + [Fact] + public async Task ShouldGetAllSuccessfully_WhenTermsExist() + { + // Arrange + var (termsList, termDtoList) = GetTermObjectsLists(); + var request = GetRequest(); + + MockHelpers.SetupMockTermRepositoryGetAllAsync(_mockRepository, termsList); + MockHelpers.SetupMockMapper, List>(_mockMapper, termDtoList, termsList); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Should().SatisfyRespectively( + first => first.Id.Should().Be(termsList[0].Id), + second => second.Id.Should().Be(termsList[1].Id)); + result.Value.Should().HaveCount(2); + VerifyGetAllAsyncAndMockingOperationsExecution(termsList); + } + + [Fact] + public async Task ShouldGetAllSuccessfully_WithCorrectDataType() + { + // Arrange + var (termsList, termDtoList) = GetTermObjectsLists(); + var request = GetRequest(); + + MockHelpers.SetupMockTermRepositoryGetAllAsync(_mockRepository, termsList); + MockHelpers.SetupMockMapper, List>(_mockMapper, termDtoList, termsList); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType>(); + } + + [Fact] + public async Task ShouldGetAllSuccessfully_WhenTermsNotExist() + { + // Arrange + var (termsList, termDtoList) = GetEmptyTermObjectsLists(); + var request = GetRequest(); + + MockHelpers.SetupMockTermRepositoryGetAllAsync(_mockRepository, termsList); + MockHelpers.SetupMockMapper(_mockMapper, termDtoList, termsList); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Should().BeEmpty(); + result.ValueOrDefault.Should().BeAssignableTo>(); + VerifyGetAllAsyncAndMockingOperationsExecution(termsList); + } + + private static (List, List) GetTermObjectsLists() + { + var termsList = new List() + { + new Term() + { + Id = 1, + }, + new Term() + { + Id = 2, + }, + }; + var termDtoList = new List() + { + new TermDTO() + { + Id = termsList[0].Id, + }, + new TermDTO() + { + Id = termsList[1].Id, + }, + }; + + return (termsList, termDtoList); + } + + private static (List, List) GetEmptyTermObjectsLists() + { + return (new List(), new List()); + } + + private static GetAllTermsQuery GetRequest() + { + return new GetAllTermsQuery(); + } + + private void VerifyGetAllAsyncAndMockingOperationsExecution(List termsList) + { + _mockRepository.Verify( + x => x.TermRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>()), + Times.Once); + _mockMapper.Verify(x => x.Map>(termsList), Times.Once); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/GetTermByIdTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/GetTermByIdTest.cs new file mode 100644 index 000000000..6f10f41e8 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/GetTermByIdTest.cs @@ -0,0 +1,117 @@ +using AutoMapper; +using FluentAssertions; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.DTO.Streetcode.TextContent; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Term.GetById; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Terms; + +public class GetTermByIdTest +{ + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly MockCannotFindLocalizer _mockCannotFindLocalizer; + private readonly GetTermByIdHandler _handler; + + public GetTermByIdTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockCannotFindLocalizer = new MockCannotFindLocalizer(); + _handler = new GetTermByIdHandler( + _mockRepository.Object, + _mockMapper.Object, + _mockLogger.Object, + _mockCannotFindLocalizer); + } + + [Theory] + [InlineData(1)] + public async Task ShouldGetByIdSuccessfully_WhenIdExists(int termId) + { + // Arrange + var (term, termDto) = GetTermObjects(termId); + var request = GetRequest(termId); + + MockHelpers.SetupMockTermGetFirstOrDefaultAsync(_mockRepository, term); + MockHelpers.SetupMockMapper(_mockMapper, termDto, term); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Id.Should().Be(term.Id); + _mockRepository.Verify( + x => x.TermRepository.GetFirstOrDefaultAsync( + t => t.Id == request.Id, + It.IsAny, IIncludableQueryable>>()), + Times.Once); + _mockMapper.Verify(x => x.Map(term), Times.Once); + } + + [Theory] + [InlineData(1)] + public async Task ShouldGetByIdSuccessfully_WithCorrectDataType(int termId) + { + // Arrange + var (term, termDto) = GetTermObjects(termId); + var request = GetRequest(termId); + + MockHelpers.SetupMockTermGetFirstOrDefaultAsync(_mockRepository, term); + MockHelpers.SetupMockMapper(_mockMapper, termDto, term); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType(); + } + + [Theory] + [InlineData(1)] + public async Task ShouldGetByIdFailingly_WhenTermNotFound(int termId) + { + // Arrange + var request = GetRequest(termId); + var expectedErrorMessage = _mockCannotFindLocalizer["CannotFindAnyTermWithCorrespondingId", request.Id].Value; + + MockHelpers.SetupMockTermGetFirstOrDefaultAsync(_mockRepository, null); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + private static (Term, TermDTO) GetTermObjects(int termId) + { + var term = new Term() + { + Id = termId, + }; + var termDto = new TermDTO() + { + Id = term.Id, + }; + + return (term, termDto); + } + + private static GetTermByIdQuery GetRequest(int termId) + { + return new GetTermByIdQuery(termId); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/UpdateTermHendlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/UpdateTermHendlerTests.cs deleted file mode 100644 index bd15762dc..000000000 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/UpdateTermHendlerTests.cs +++ /dev/null @@ -1,133 +0,0 @@ -using AutoMapper; -using MediatR; -using Microsoft.Extensions.Localization; -using Moq; -using Streetcode.BLL.DTO.Streetcode.TextContent; -using Streetcode.BLL.Interfaces.Logging; -using Streetcode.BLL.MediatR.Streetcode.Term.Update; -using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Entities.Streetcode.TextContent; -using Streetcode.DAL.Repositories.Interfaces.Base; -using Xunit; - -namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Terms -{ - public class UpdateTermHendlerTests - { - private readonly Mock mockRepository; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerFailedToUpdate; - private readonly Mock> mockLocalizerCannotConvertNull; - - public UpdateTermHendlerTests() - { - this.mockRepository = new (); - this.mockMapper = new (); - this.mockLogger = new Mock(); - this.mockLocalizerFailedToUpdate = new Mock>(); - this.mockLocalizerCannotConvertNull = new Mock>(); - } - - [Theory] - [InlineData(1)] - public async Task ShouldReturnSuccessfully_WhenUpdated(int returnNuber) - { - // Arrange - this.mockRepository.Setup(x => x.TermRepository.Update(GetTerm())); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(returnNuber); - - this.mockMapper.Setup(x => x.Map(It.IsAny())) - .Returns(GetTerm()); - - var handler = new UpdateTermHandler(this.mockMapper.Object, this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerFailedToUpdate.Object, this.mockLocalizerCannotConvertNull.Object); - - // Act - var result = await handler.Handle(new UpdateTermCommand(GetTermDTO()), CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.True(result.IsSuccess), - () => Assert.IsType(result.Value)); - } - - [Theory] - [InlineData(1)] - public async Task ShouldThrowExeption_TryMapNullRequest(int returnNuber) - { - // Arrange - this.mockRepository.Setup(x => x.TermRepository.Update(GetTermWithNotExistId() !)); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(returnNuber); - - this.mockMapper.Setup(x => x.Map(It.IsAny())) - .Returns(GetTermWithNotExistId() !); - - var expectedError = "Cannot convert null to Term"; - this.mockLocalizerCannotConvertNull.Setup(x => x["CannotConvertNullToTerm"]) - .Returns(new LocalizedString("CannotConvertNullToTerm", expectedError)); - - var handler = new UpdateTermHandler(this.mockMapper.Object, this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerFailedToUpdate.Object, this.mockLocalizerCannotConvertNull.Object); - - // Act - var result = await handler.Handle(new UpdateTermCommand(GetTermDTOWithNotExistId() !), CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.False(result.IsSuccess), - () => Assert.Equal(expectedError, result.Errors[0].Message)); - } - - [Theory] - [InlineData(-1)] - public async Task ShouldThrowExeption_SaveChangesAsyncIsNotSuccessful(int returnNuber) - { - // Arrange - this.mockRepository.Setup(x => x.TermRepository.Update(GetTerm())); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(returnNuber); - - this.mockMapper.Setup(x => x.Map(It.IsAny())) - .Returns(GetTerm()); - - var expectedError = "Failed to update a term"; - this.mockLocalizerFailedToUpdate.Setup(x => x["FailedToUpdateTerm"]) - .Returns(new LocalizedString("FailedToUpdateTerm", expectedError)); - var handler = new UpdateTermHandler(this.mockMapper.Object, this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerFailedToUpdate.Object, this.mockLocalizerCannotConvertNull.Object); - - // Act - var result = await handler.Handle(new UpdateTermCommand(GetTermDTO()), CancellationToken.None); - - // Assert - Assert.Multiple( - () => Assert.True(result.IsFailed), - () => Assert.Equal(expectedError, result.Errors[0].Message)); - } - - [Theory] - [InlineData(1)] - public async Task ShouldReturnSuccessfully_TypeIsCorrect(int returnNuber) - { - // Arrange - this.mockRepository.Setup(x => x.TermRepository.Create(GetTerm())); - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(returnNuber); - - this.mockMapper.Setup(x => x.Map(It.IsAny())) - .Returns(GetTerm()); - - var handler = new UpdateTermHandler(this.mockMapper.Object, this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerFailedToUpdate.Object, this.mockLocalizerCannotConvertNull.Object); - - // Act - var result = await handler.Handle(new UpdateTermCommand(GetTermDTO()), CancellationToken.None); - - // Assert - Assert.IsType(result.Value); - } - - private static Term GetTerm() => new (); - - private static TermDTO GetTermDTO() => new (); - - private static Term? GetTermWithNotExistId() => null; - - private static TermDTO? GetTermDTOWithNotExistId() => null; - } -} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/UpdateTermTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/UpdateTermTest.cs new file mode 100644 index 000000000..f2e7f5fc2 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Terms/UpdateTermTest.cs @@ -0,0 +1,136 @@ +using AutoMapper; +using FluentAssertions; +using MediatR; +using Moq; +using Streetcode.BLL.DTO.Streetcode.TextContent; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Term.Update; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Terms; + +public class UpdateTermTest +{ + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly MockCannotConvertNullLocalizer _mockCannotConvertNullLocalizer; + private readonly MockFailedToUpdateLocalizer _mockFailedToUpdateLocalizer; + private readonly UpdateTermHandler _handler; + + public UpdateTermTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockCannotConvertNullLocalizer = new MockCannotConvertNullLocalizer(); + _mockFailedToUpdateLocalizer = new MockFailedToUpdateLocalizer(); + _handler = new UpdateTermHandler( + _mockMapper.Object, + _mockRepository.Object, + _mockLogger.Object, + _mockFailedToUpdateLocalizer, + _mockCannotConvertNullLocalizer); + } + + [Fact] + public async Task ShouldUpdateSuccessfully_WhenTermExists() + { + // Arrange + var (term, termDto) = GetTermObjects(); + var request = GetRequest(termDto); + + SetupMockUpdateAndSaveChangesAsync(term, 1); + MockHelpers.SetupMockMapper(_mockMapper, term, request.Term); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + _mockRepository.Verify(x => x.TermRepository.Update(term), Times.Once); + _mockRepository.Verify(x => x.SaveChangesAsync(), Times.Once); + } + + [Fact] + public async Task ShouldUpdateSuccessfully_WithCorrectDataType() + { + // Arrange + var (term, termDto) = GetTermObjects(); + var request = GetRequest(termDto); + + SetupMockUpdateAndSaveChangesAsync(term, 1); + MockHelpers.SetupMockMapper(_mockMapper, term, request.Term); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType(); + } + + [Fact] + public async Task ShouldUpdateFailingly_WhenMappingFailed() + { + // Arrange + var (_, termDto) = GetTermObjects(); + var request = GetRequest(termDto); + var expectedErrorMessage = _mockCannotConvertNullLocalizer["CannotConvertNullToTerm"].Value; + + MockHelpers.SetupMockMapper(_mockMapper, null, request.Term); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + [Fact] + public async Task ShouldUpdateFailingly_WhenSaveChangesAsyncFailed() + { + // Arrange + var (term, termDto) = GetTermObjects(); + var request = GetRequest(termDto); + var expectedErrorMessage = _mockFailedToUpdateLocalizer["FailedToUpdateTerm"].Value; + + SetupMockUpdateAndSaveChangesAsync(term, -1); + MockHelpers.SetupMockMapper(_mockMapper, term, request.Term); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + private static (Term, TermDTO) GetTermObjects() + { + var term = new Term(); + var termDto = new TermDTO(); + + return (term, termDto); + } + + private static UpdateTermCommand GetRequest(TermDTO termDto) + { + return new UpdateTermCommand(termDto); + } + + private void SetupMockUpdateAndSaveChangesAsync(Term term, int saveChangesResult) + { + _mockRepository + .Setup(x => x.TermRepository.Update(term)); + _mockRepository + .Setup(x => x.SaveChangesAsync()) + .ReturnsAsync(saveChangesResult); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Texts/DeleteTextTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Texts/DeleteTextTest.cs new file mode 100644 index 000000000..ba46699ef --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Texts/DeleteTextTest.cs @@ -0,0 +1,134 @@ +using FluentAssertions; +using MediatR; +using Moq; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Text.Delete; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Texts; + +public class DeleteTextTest +{ + private readonly Mock _mockRepository; + private readonly Mock _mockLogger; + private readonly MockFailedToDeleteLocalizer _mockFailedToDeleteLocalizer; + private readonly MockCannotFindLocalizer _mockCannotFindLocalizer; + private readonly DeleteTextHandler _handler; + + public DeleteTextTest() + { + _mockRepository = new Mock(); + _mockLogger = new Mock(); + _mockFailedToDeleteLocalizer = new MockFailedToDeleteLocalizer(); + _mockCannotFindLocalizer = new MockCannotFindLocalizer(); + _handler = new DeleteTextHandler( + _mockRepository.Object, + _mockLogger.Object, + _mockFailedToDeleteLocalizer, + _mockCannotFindLocalizer); + } + + [Theory] + [InlineData(1)] + public async Task ShouldDeleteSuccessfully_WhenTextExists(int textId) + { + // Arrange + var text = GetText(textId); + var request = GetRequest(textId); + + MockHelpers.SetupMockTextGetFirstOrDefaultAsync(_mockRepository, text); + SetupMockDeleteAndSaveChangesAsync(text, 1); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + _mockRepository.Verify(x => x.TextRepository.Delete(text), Times.Once); + _mockRepository.Verify(x => x.SaveChangesAsync(), Times.Once); + } + + [Theory] + [InlineData(1)] + public async Task ShouldDeleteSuccessfully_WithCorrectDataType(int termId) + { + // Arrange + var text = GetText(termId); + var request = GetRequest(termId); + + MockHelpers.SetupMockTextGetFirstOrDefaultAsync(_mockRepository, text); + SetupMockDeleteAndSaveChangesAsync(text, 1); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType(); + } + + [Theory] + [InlineData(1)] + public async Task ShouldDeleteFailingly_WhenTextNotExist(int textId) + { + // Arrange + var request = GetRequest(textId); + var expectedErrorMessage = _mockCannotFindLocalizer["CannotFindTextWithCorrespondingCategoryId", request.Id].Value; + + MockHelpers.SetupMockTextGetFirstOrDefaultAsync(_mockRepository, null); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + [Theory] + [InlineData(1)] + public async Task ShouldDeleteFailingly_WhenSaveChangesAsyncFailed(int textId) + { + // Arrange + var text = GetText(textId); + var request = GetRequest(textId); + var expectedErrorMessage = _mockFailedToDeleteLocalizer["FailedToDeleteText"].Value; + + MockHelpers.SetupMockTextGetFirstOrDefaultAsync(_mockRepository, text); + SetupMockDeleteAndSaveChangesAsync(text, -1); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + private static Text GetText(int textId) + { + return new Text() + { + Id = textId, + }; + } + + private static DeleteTextCommand GetRequest(int textId) + { + return new DeleteTextCommand(textId); + } + + private void SetupMockDeleteAndSaveChangesAsync(Text text, int saveChangesResult) + { + _mockRepository + .Setup(x => x.TextRepository.Delete(text)); + _mockRepository + .Setup(x => x.SaveChangesAsync()) + .ReturnsAsync(saveChangesResult); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Texts/GetAllTextsTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Texts/GetAllTextsTest.cs new file mode 100644 index 000000000..7d28ac7fd --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Texts/GetAllTextsTest.cs @@ -0,0 +1,135 @@ +using System.Linq.Expressions; +using AutoMapper; +using FluentAssertions; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.DTO.Streetcode.TextContent.Text; +using Streetcode.BLL.MediatR.Streetcode.Text.GetAll; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Texts; + +public class GetAllTextsTest +{ + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly GetAllTextsHandler _handler; + + public GetAllTextsTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _handler = new GetAllTextsHandler(_mockRepository.Object, _mockMapper.Object); + } + + [Fact] + public async Task ShouldGetAllSuccessfully_WhenTermsExist() + { + // Arrange + var (textsList, textDtoList) = GetTextObjectsLists(); + var request = GetRequest(); + + MockHelpers.SetupMockTextRepositoryGetAllAsync(_mockRepository, textsList); + MockHelpers.SetupMockMapper, List>(_mockMapper, textDtoList, textsList); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Should().SatisfyRespectively( + first => first.Id.Should().Be(textsList[0].Id), + second => second.Id.Should().Be(textsList[1].Id)); + result.Value.Should().HaveCount(2); + VerifyGetAllAsyncAndMockingOperationsExecution(textsList); + } + + [Fact] + public async Task ShouldGetAllSuccessfully_WithCorrectDataType() + { + // Arrange + var (textsList, textDtoList) = GetTextObjectsLists(); + var request = GetRequest(); + + MockHelpers.SetupMockTextRepositoryGetAllAsync(_mockRepository, textsList); + MockHelpers.SetupMockMapper, List>(_mockMapper, textDtoList, textsList); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType>(); + } + + [Fact] + public async Task ShouldGetAllSuccessfully_WhenTermsNotExist() + { + // Arrange + var (textsList, textDtoList) = GetEmptyTextObjectsLists(); + var request = GetRequest(); + + MockHelpers.SetupMockTextRepositoryGetAllAsync(_mockRepository, textsList); + MockHelpers.SetupMockMapper(_mockMapper, textDtoList, textsList); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Should().BeEmpty(); + result.ValueOrDefault.Should().BeAssignableTo>(); + VerifyGetAllAsyncAndMockingOperationsExecution(textsList); + } + + private static (List, List) GetTextObjectsLists() + { + var textsList = new List() + { + new Text() + { + Id = 1, + }, + new Text() + { + Id = 2, + }, + }; + var textDtoList = new List() + { + new TextDTO() + { + Id = textsList[0].Id, + }, + new TextDTO() + { + Id = textsList[1].Id, + }, + }; + + return (textsList, textDtoList); + } + + private static (List, List) GetEmptyTextObjectsLists() + { + return (new List(), new List()); + } + + private static GetAllTextsQuery GetRequest() + { + return new GetAllTextsQuery(); + } + + private void VerifyGetAllAsyncAndMockingOperationsExecution(List textsList) + { + _mockRepository.Verify( + x => x.TextRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>()), + Times.Once); + _mockMapper.Verify(x => x.Map>(textsList), Times.Once); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Texts/GetTextByIdTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Texts/GetTextByIdTest.cs new file mode 100644 index 000000000..802d27723 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Texts/GetTextByIdTest.cs @@ -0,0 +1,117 @@ +using AutoMapper; +using FluentAssertions; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.DTO.Streetcode.TextContent.Text; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Text.GetById; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Texts; + +public class GetTextByIdTest +{ + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly MockCannotFindLocalizer _mockCannotFindLocalizer; + private readonly GetTextByIdHandler _handler; + + public GetTextByIdTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockCannotFindLocalizer = new MockCannotFindLocalizer(); + _handler = new GetTextByIdHandler( + _mockRepository.Object, + _mockMapper.Object, + _mockLogger.Object, + _mockCannotFindLocalizer); + } + + [Theory] + [InlineData(1)] + public async Task ShouldGetByIdSuccessfully_WhenIdExists(int textId) + { + // Arrange + var (text, textDto) = GetTextObjects(textId); + var request = GetRequest(textId); + + MockHelpers.SetupMockTextGetFirstOrDefaultAsync(_mockRepository, text); + MockHelpers.SetupMockMapper(_mockMapper, textDto, text); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Id.Should().Be(text.Id); + _mockRepository.Verify( + x => x.TextRepository.GetFirstOrDefaultAsync( + t => t.Id == request.Id, + It.IsAny, IIncludableQueryable>>()), + Times.Once); + _mockMapper.Verify(x => x.Map(text), Times.Once); + } + + [Theory] + [InlineData(1)] + public async Task ShouldGetByIdSuccessfully_WithCorrectDataType(int textId) + { + // Arrange + var (text, textDto) = GetTextObjects(textId); + var request = GetRequest(textId); + + MockHelpers.SetupMockTextGetFirstOrDefaultAsync(_mockRepository, text); + MockHelpers.SetupMockMapper(_mockMapper, textDto, text); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType(); + } + + [Theory] + [InlineData(1)] + public async Task ShouldGetByIdFailingly_WhenTextNotFound(int textId) + { + // Arrange + var request = GetRequest(textId); + var expectedErrorMessage = _mockCannotFindLocalizer["CannotFindAnyTextWithCorrespondingId", request.Id].Value; + + MockHelpers.SetupMockTextGetFirstOrDefaultAsync(_mockRepository, null); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsFailed.Should().BeTrue(); + result.Errors[0].Message.Should().Be(expectedErrorMessage); + _mockLogger.Verify(x => x.LogError(request, expectedErrorMessage), Times.Once); + } + + private static (Text, TextDTO) GetTextObjects(int textId) + { + var text = new Text() + { + Id = textId, + }; + var textDto = new TextDTO() + { + Id = text.Id, + }; + + return (text, textDto); + } + + private static GetTextByIdQuery GetRequest(int textId) + { + return new GetTextByIdQuery(textId); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Texts/GetTextByStreetcodeIdTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Texts/GetTextByStreetcodeIdTest.cs new file mode 100644 index 000000000..635cb3c0c --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Texts/GetTextByStreetcodeIdTest.cs @@ -0,0 +1,114 @@ +using AutoMapper; +using FluentAssertions; +using FluentResults; +using Moq; +using Streetcode.BLL.DTO.Streetcode.TextContent.Text; +using Streetcode.BLL.Interfaces.Cache; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Streetcode.Text.GetByStreetcodeId; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Texts; + +public class GetTextByStreetcodeIdTest +{ + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly Mock _mockCacheService; + private readonly MockCannotFindLocalizer _mockCannotFindLocalizer; + private readonly GetTextByStreetcodeIdHandler _handler; + + public GetTextByStreetcodeIdTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockCacheService = new Mock(); + _mockCannotFindLocalizer = new MockCannotFindLocalizer(); + _handler = new GetTextByStreetcodeIdHandler( + _mockRepository.Object, + _mockMapper.Object, + _mockLogger.Object, + _mockCannotFindLocalizer, + _mockCacheService.Object); + } + + [Theory] + [InlineData(1)] + public async Task ShouldGetByStreetcodeIdSuccessfully_WhenIdExists(int streetcodeId) + { + // Arrange + var resultTextDto = GetResultTextDto(streetcodeId); + var request = GetRequest(streetcodeId); + var cacheKey = $"TextCache_{request.StreetcodeId}"; + + SetupMockCacheService(cacheKey, resultTextDto); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Id.Should().Be(resultTextDto.Value.Id); + result.Value.StreetcodeId.Should().Be(request.StreetcodeId); + VerifyGetOrSetAsyncOperationExecution(cacheKey); + } + + [Theory] + [InlineData(1)] + public async Task ShouldGetByStreetcodeIdSuccessfully_WithCorrectDataType(int streetcodeId) + { + // Arrange + var resultTextDto = GetResultTextDto(streetcodeId); + var request = GetRequest(streetcodeId); + var cacheKey = $"TextCache_{request.StreetcodeId}"; + + SetupMockCacheService(cacheKey, resultTextDto); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType(); + } + + private static Result GetResultTextDto(int streetcodeId) + { + var textDto = new TextDTO() + { + Id = 1, + StreetcodeId = streetcodeId, + }; + + return Result.Ok(textDto); + } + + private static GetTextByStreetcodeIdQuery GetRequest(int streetcodeId) + { + return new GetTextByStreetcodeIdQuery(streetcodeId); + } + + private void SetupMockCacheService(string cacheKey, Result resultTextDto) + { + _mockCacheService + .Setup(x => x.GetOrSetAsync( + cacheKey, + It.IsAny>>>(), + TimeSpan.FromMinutes(10))) + .ReturnsAsync(resultTextDto); + } + + private void VerifyGetOrSetAsyncOperationExecution(string cacheKey) + { + _mockCacheService.Verify( + x => x.GetOrSetAsync( + cacheKey, + It.IsAny>>>(), + TimeSpan.FromMinutes(10)), + Times.Once); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Texts/UpdateParsedTextAdminPreviewTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Texts/UpdateParsedTextAdminPreviewTest.cs new file mode 100644 index 000000000..5409b2abe --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetCode/Texts/UpdateParsedTextAdminPreviewTest.cs @@ -0,0 +1,73 @@ +using FluentAssertions; +using Moq; +using Streetcode.BLL.Interfaces.Text; +using Streetcode.BLL.MediatR.Streetcode.Text.UpdateParsed; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.StreetCode.Texts; + +public class UpdateParsedTextAdminPreviewTest +{ + private readonly Mock _mockTextService; + private readonly UpdateParsedTextAdminPreviewHandler _handler; + + public UpdateParsedTextAdminPreviewTest() + { + _mockTextService = new Mock(); + _handler = new UpdateParsedTextAdminPreviewHandler(_mockTextService.Object); + } + + [Theory] + [InlineData("qwerty")] + public async Task ShouldUpdateParsedAdminPreviewSuccessfully_WhenTextParsed(string textToParse) + { + // Arrange + var parsedText = GetParsedText(textToParse); + var request = GetRequest(textToParse); + + SetupMockTextService(request, parsedText); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Should().Be(parsedText); + _mockTextService.Verify(x => x.AddTermsTag(request.TextToParse), Times.Once); + } + + [Theory] + [InlineData("qwerty")] + public async Task ShouldUpdateParsedAdminPreviewSuccessfully_WithCorrectDataType(string textToParse) + { + // Arrange + var parsedText = GetParsedText(textToParse); + var request = GetRequest(textToParse); + + SetupMockTextService(request, parsedText); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.ValueOrDefault.Should().BeOfType(); + } + + private static string GetParsedText(string textToParse) + { + return $"{textToParse}"; + } + + private static UpdateParsedTextForAdminPreviewCommand GetRequest(string textToParse) + { + return new UpdateParsedTextForAdminPreviewCommand(textToParse); + } + + private void SetupMockTextService(UpdateParsedTextForAdminPreviewCommand request, string parsedText) + { + _mockTextService + .Setup(x => x.AddTermsTag(request.TextToParse)) + .ReturnsAsync(parsedText); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetcodeTests/TextTests/GetAllTextsTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetcodeTests/TextTests/GetAllTextsTest.cs index 129c5942b..db322359e 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetcodeTests/TextTests/GetAllTextsTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/StreetcodeTests/TextTests/GetAllTextsTest.cs @@ -4,7 +4,6 @@ using Microsoft.Extensions.Localization; using Moq; using Streetcode.BLL.DTO.Streetcode.TextContent.Text; -using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Streetcode.Text.GetAll; using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Streetcode.TextContent; @@ -17,14 +16,12 @@ public class GetAllTextsTest { private readonly Mock repository; private readonly Mock mockMapper; - private readonly Mock mockLogger; private readonly Mock> mockLocalizerCannotFind; public GetAllTextsTest() { this.repository = new Mock(); this.mockMapper = new Mock(); - this.mockLogger = new Mock(); this.mockLocalizerCannotFind = new Mock>(); } @@ -55,7 +52,7 @@ public async Task ShouldReturnSuccesfullyAllTexts() .Setup(x => x["CannotFindAnyText"]) .Returns(new LocalizedString("CannotFindAnyText", "Cannot find any text")); - var handler = new GetAllTextsHandler(this.repository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + var handler = new GetAllTextsHandler(this.repository.Object, this.mockMapper.Object); var result = await handler.Handle(new GetAllTextsQuery(), CancellationToken.None); @@ -88,7 +85,7 @@ public async Task GetAllTextsReturnError() .Setup(x => x["CannotFindAnyText"]) .Returns(new LocalizedString("CannotFindAnyText", "Cannot find any text")); - var handler = new GetAllTextsHandler(repository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + var handler = new GetAllTextsHandler(repository.Object, this.mockMapper.Object); var result = await handler.Handle(new GetAllTextsQuery(), CancellationToken.None); diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/CreateTeamTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/CreateTeamTest.cs index d34e43f20..d69006e72 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/CreateTeamTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/CreateTeamTest.cs @@ -1,32 +1,30 @@ using System.Linq.Expressions; using AutoMapper; using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; using Moq; using Streetcode.BLL.DTO.Team; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Team.Create; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Team; using Streetcode.DAL.Repositories.Interfaces.Base; - +using Streetcode.XUnitTest.Mocks; using Xunit; namespace Streetcode.XUnitTest.MediatRTests.Team { public class CreateTeamTest { - private readonly Mock mockRepository; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerConvertNull; + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly MockFailedToCreateLocalizer _mockLocalizerFailed; public CreateTeamTest() { - this.mockMapper = new Mock(); - this.mockRepository = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerConvertNull = new Mock>(); + _mockMapper = new Mock(); + _mockRepository = new Mock(); + _mockLogger = new Mock(); + _mockLocalizerFailed = new MockFailedToCreateLocalizer(); } [Fact] @@ -38,7 +36,7 @@ public async Task ShouldReturnSuccessfully_TeamCreated() this.BasicRepositorySetup(teamMember); this.GetsAsyncRepositorySetup(); - var handler = new CreateTeamHandler(this.mockMapper.Object, this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerConvertNull.Object); + var handler = new CreateTeamHandler(_mockMapper.Object, _mockRepository.Object, _mockLogger.Object, _mockLocalizerFailed); // Act var result = await handler.Handle(new CreateTeamQuery(new TeamMemberCreateDTO()), CancellationToken.None); @@ -48,24 +46,24 @@ public async Task ShouldReturnSuccessfully_TeamCreated() } [Fact] - public async Task ShouldThrowExeption_SaveChangesIsNotSuccessful() + public async Task ShouldThrowException_SaveChangesIsNotSuccessful() { // Arrange - const string exceptionMessage = "Failed to create a team member"; + string exceptionMessage = _mockLocalizerFailed["FailedToCreateTeam"]; var teamMember = GetTeamMember(1); this.MapperSetup(teamMember); this.GetsAsyncRepositorySetup(); - this.mockRepository.Setup(repo => repo.TeamRepository.CreateAsync(teamMember)).ReturnsAsync(teamMember); - this.mockRepository.Setup(repo => repo.SaveChanges()).Throws(new Exception(exceptionMessage)); + _mockRepository.Setup(repo => repo.TeamRepository.CreateAsync(teamMember)).ReturnsAsync(teamMember); + _mockRepository.Setup(repo => repo.SaveChangesAsync()).Throws(new Exception(exceptionMessage)); - var handler = new CreateTeamHandler(this.mockMapper.Object, this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerConvertNull.Object); + var handler = new CreateTeamHandler(_mockMapper.Object, _mockRepository.Object, _mockLogger.Object, _mockLocalizerFailed); // Act var result = await handler.Handle(new CreateTeamQuery(new TeamMemberCreateDTO()), CancellationToken.None); // Assert - Assert.Equal(exceptionMessage, result.Errors[0].Message); + Assert.Equal(exceptionMessage, result.Errors.Single().Message); } [Fact] @@ -77,7 +75,7 @@ public async Task ShouldReturnSuccessfully_CorrectType() this.BasicRepositorySetup(teamMember); this.GetsAsyncRepositorySetup(); - var handler = new CreateTeamHandler(this.mockMapper.Object, this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerConvertNull.Object); + var handler = new CreateTeamHandler(_mockMapper.Object, _mockRepository.Object, _mockLogger.Object, _mockLocalizerFailed); // Act var result = await handler.Handle(new CreateTeamQuery(new TeamMemberCreateDTO()), CancellationToken.None); @@ -99,11 +97,11 @@ public async Task WhenNewPositionIdIsNegative_CreatesNewPositionAndTeamMemberPos this.MapperSetup(teamMember); this.BasicRepositorySetup(teamMember); this.GetsAsyncRepositorySetup(); - this.mockRepository.Setup(repo => repo.TeamPositionRepository.Create(It.IsAny())); - this.mockRepository.Setup(repo => repo.PositionRepository.Create(It.IsAny())) - .Returns(new Positions()); + _mockRepository.Setup(repo => repo.TeamPositionRepository.CreateAsync(It.IsAny())); + _mockRepository.Setup(repo => repo.PositionRepository.CreateAsync(It.IsAny())) + .ReturnsAsync(new Positions()); - var handler = new CreateTeamHandler(this.mockMapper.Object, this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizerConvertNull.Object); + var handler = new CreateTeamHandler(_mockMapper.Object, _mockRepository.Object, _mockLogger.Object, _mockLocalizerFailed); // Act var result = await handler.Handle(new CreateTeamQuery(teamMemberDTO), CancellationToken.None); @@ -113,8 +111,8 @@ public async Task WhenNewPositionIdIsNegative_CreatesNewPositionAndTeamMemberPos () => Assert.True(result.IsSuccess), () => Assert.Equal(0, result.Value.Id)); - this.mockRepository.Verify(repo => repo.PositionRepository.Create(It.IsAny()), Times.Once); - this.mockRepository.Verify(repo => repo.TeamPositionRepository.Create(It.IsAny()), Times.Once); + _mockRepository.Verify(repo => repo.PositionRepository.CreateAsync(It.IsAny()), Times.Once); + _mockRepository.Verify(repo => repo.TeamPositionRepository.CreateAsync(It.IsAny()), Times.Once); } private static TeamMember GetTeamMember(int imageId = 0) @@ -144,30 +142,30 @@ private static TeamMemberCreateDTO GetTeamMemberDTO(List newPositio private void BasicRepositorySetup(TeamMember teamMember) { - this.mockRepository.Setup(repo => repo.TeamRepository.CreateAsync(teamMember)).ReturnsAsync(teamMember); + _mockRepository.Setup(repo => repo.TeamRepository.CreateAsync(teamMember)).ReturnsAsync(teamMember); - this.mockRepository.Setup(repo => repo.SaveChanges()); + _mockRepository.Setup(repo => repo.SaveChangesAsync()); } private void GetsAsyncRepositorySetup(List? link = null) { var linkList = link ?? new List(); - this.mockRepository.Setup(repo => repo.TeamLinkRepository + _mockRepository.Setup(repo => repo.TeamLinkRepository .GetAllAsync(It.IsAny>>(), It.IsAny, IIncludableQueryable>>())).ReturnsAsync(linkList); - this.mockRepository.Setup(repo => repo.TeamPositionRepository + _mockRepository.Setup(repo => repo.TeamPositionRepository .GetAllAsync(It.IsAny>>(), It.IsAny, IIncludableQueryable>>())).ReturnsAsync(new List()); } private void MapperSetup(TeamMember member) { - this.mockMapper.Setup(mapper => mapper.Map(It.IsAny())) + _mockMapper.Setup(mapper => mapper.Map(It.IsAny())) .Returns(member); - this.mockMapper.Setup(mapper => mapper.Map(It.IsAny())) + _mockMapper.Setup(mapper => mapper.Map(It.IsAny())) .Returns(new TeamMemberDTO()); } } diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/DeleteTeamTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/DeleteTeamTest.cs index 7f75c1e6c..ad1c6bc32 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/DeleteTeamTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/DeleteTeamTest.cs @@ -6,7 +6,6 @@ using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Team.Delete; using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Entities.Streetcode.TextContent; using Streetcode.DAL.Entities.Team; using Streetcode.DAL.Repositories.Interfaces.Base; using Xunit; @@ -15,17 +14,17 @@ namespace Streetcode.XUnitTest.MediatRTests.Team { public class DeleteTeamTest { - private readonly Mock mockMapper; - private readonly Mock mockRepository; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerNo; + private readonly Mock _mockMapper; + private readonly Mock _mockRepository; + private readonly Mock _mockLogger; + private readonly Mock> _mockLocalizerNo; public DeleteTeamTest() { - this.mockRepository = new Mock(); - this.mockMapper = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerNo = new Mock>(); + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockLocalizerNo = new Mock>(); } [Fact] @@ -37,7 +36,7 @@ public async Task ShouldDeleteSuccessfully() this.SetupMapTeamMember(testTeam); this.SetupGetFirstOrDefaultAsync(testTeam); - var handler = new DeleteTeamHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerNo.Object); + var handler = new DeleteTeamHandler(_mockRepository.Object, _mockMapper.Object, _mockLogger.Object, _mockLocalizerNo.Object); // Act var result = await handler.Handle(new DeleteTeamQuery(testTeam.Id), CancellationToken.None); @@ -47,8 +46,8 @@ public async Task ShouldDeleteSuccessfully() () => Assert.NotNull(result), () => Assert.True(result.IsSuccess)); - this.mockRepository.Verify(x => x.TeamRepository.Delete(It.Is(x => x.Id == testTeam.Id)), Times.Once); - this.mockRepository.Verify(x => x.SaveChanges(), Times.Once); + _mockRepository.Verify(x => x.TeamRepository.Delete(It.Is(x => x.Id == testTeam.Id)), Times.Once); + _mockRepository.Verify(x => x.SaveChangesAsync(), Times.Once); } [Fact] @@ -57,12 +56,12 @@ public async Task ShouldThrowException_IdNotExisting() // Arrange var testTeam = GetTeam(); var expectedError = "No team with such id"; - this.mockLocalizerNo.Setup(x => x["NoTeamWithSuchId"]) + this._mockLocalizerNo.Setup(x => x["NoTeamWithSuchId"]) .Returns(new LocalizedString("NoTeamWithSuchId", expectedError)); this.SetupGetFirstOrDefaultAsync(null); - var handler = new DeleteTeamHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerNo.Object); + var handler = new DeleteTeamHandler(_mockRepository.Object, _mockMapper.Object, _mockLogger.Object, _mockLocalizerNo.Object); // Act var result = await handler.Handle(new DeleteTeamQuery(testTeam.Id), CancellationToken.None); @@ -70,7 +69,7 @@ public async Task ShouldThrowException_IdNotExisting() // Assert Assert.Equal(expectedError, result.Errors[0].Message); - this.mockRepository.Verify(x => x.TeamRepository.Delete(It.IsAny()), Times.Never); + _mockRepository.Verify(x => x.TeamRepository.Delete(It.IsAny()), Times.Never); } [Fact] @@ -84,7 +83,7 @@ public async Task ShouldThrowException_SaveChangesAsyncIsNotSuccessful() this.SetupGetFirstOrDefaultAsync(testTeam); this.SetupSaveChangesException(expectedError); - var handler = new DeleteTeamHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerNo.Object); + var handler = new DeleteTeamHandler(_mockRepository.Object, _mockMapper.Object, _mockLogger.Object, _mockLocalizerNo.Object); // Act var result = await handler.Handle(new DeleteTeamQuery(testTeam.Id), CancellationToken.None); @@ -108,13 +107,13 @@ private static TeamMemberDTO GetTeamDTO() private void SetupMapTeamMember(TeamMember teamMember) { - this.mockMapper.Setup(x => x.Map(teamMember)) + _mockMapper.Setup(x => x.Map(teamMember)) .Returns(GetTeamDTO()); } private void SetupGetFirstOrDefaultAsync(TeamMember? teamMember) { - this.mockRepository + _mockRepository .Setup(x => x.TeamRepository.GetFirstOrDefaultAsync( It.IsAny>>(), null)) .ReturnsAsync(teamMember); @@ -122,8 +121,8 @@ private void SetupGetFirstOrDefaultAsync(TeamMember? teamMember) private void SetupSaveChangesException(string errorMessage) { - this.mockRepository - .Setup(x => x.SaveChanges()) + _mockRepository + .Setup(x => x.SaveChangesAsync()) .Throws(new Exception(errorMessage)); } } diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/GetAllTeamsTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/GetAllTeamsTest.cs index c9ee03216..28d9153c5 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/GetAllTeamsTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/GetAllTeamsTest.cs @@ -1,157 +1,140 @@ using System.Linq.Expressions; using AutoMapper; using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; using Moq; using Streetcode.BLL.DTO.Team; -using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.Interfaces.BlobStorage; using Streetcode.BLL.MediatR.Team.GetAll; -using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Entities.Streetcode.TextContent; using Streetcode.DAL.Entities.Team; using Streetcode.DAL.Helpers; using Streetcode.DAL.Repositories.Interfaces.Base; using Xunit; -namespace Streetcode.XUnitTest.MediatRTests.Team -{ - public class GetAllTeamsTest - { - private readonly Mock mockRepository; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotFind; - - public GetAllTeamsTest() - { - this.mockRepository = new Mock(); - this.mockMapper = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerCannotFind = new Mock>(); - } - - [Fact] - public async Task ShouldReturnSuccessfully_CorrectType() - { - // Arrange - var teamList = GetTeamList(); - var teamDTOList = GetListTeamDTO(); +namespace Streetcode.XUnitTest.MediatRTests.Team; - this.SetupPaginatedRepository(teamList); - this.SetupMapper(teamDTOList); - - var handler = new GetAllTeamHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); +public class GetAllTeamsTest +{ + private const string _testBase64String = "rVhhWrnh72xHfKGHg6YTV2H4ywe7BorrYUdILaKz0lQ="; - // Act - var result = await handler.Handle(new GetAllTeamQuery(), CancellationToken.None); + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockBlobService; + private readonly GetAllTeamHandler _handler; - // Assert - Assert.Multiple( - () => Assert.NotNull(result), - () => Assert.NotNull(result.Value), - () => Assert.IsType>(result.ValueOrDefault.TeamMembers) - ); - } + public GetAllTeamsTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockBlobService = new Mock(); + _handler = new GetAllTeamHandler( + _mockRepository.Object, + _mockMapper.Object, + _mockBlobService.Object); + } - [Fact] - public async Task ShouldReturnSuccessfully_CountMatch() - { - // Arrange - var teamList = GetTeamList(); - var teamDTOList = GetListTeamDTO(); + [Fact] + public async Task ShouldReturnSuccessfully_CorrectType() + { + // Arrange + var (teamMemberList, teamMemberDtoList) = GetTeamMemberObjectsLists(); - this.SetupPaginatedRepository(teamList); - this.SetupMapper(teamDTOList); + SetupPaginatedRepository(teamMemberList); + SetupBlobService(); + SetupMapper(teamMemberDtoList); - var handler = new GetAllTeamHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + // Act + var result = await _handler.Handle(new GetAllTeamQuery(), CancellationToken.None); - // Act - var result = await handler.Handle(new GetAllTeamQuery(), CancellationToken.None); + // Assert + Assert.Multiple( + () => Assert.NotNull(result), + () => Assert.NotNull(result.Value), + () => Assert.IsType>(result.ValueOrDefault.TeamMembers)); + } - // Assert - Assert.Multiple( - () => Assert.NotNull(result), - () => Assert.NotNull(result.Value), - () => Assert.Equal(GetTeamList().Count(), result.Value.TeamMembers.Count()) - ); - } + [Fact] + public async Task ShouldReturnSuccessfully_CountMatch() + { + // Arrange + var (teamMemberList, teamMemberDtoList) = GetTeamMemberObjectsLists(); - [Fact] - public async Task Handler_Returns_Correct_PageSize() - { - // Arrange - ushort pageSize = 3; - this.SetupPaginatedRepository(GetTeamList().Take(pageSize)); - this.SetupMapper(GetListTeamDTO().Take(pageSize).ToList()); + SetupPaginatedRepository(teamMemberList); + SetupBlobService(); + SetupMapper(teamMemberDtoList); - var handler = new GetAllTeamHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + // Act + var result = await _handler.Handle(new GetAllTeamQuery(), CancellationToken.None); - // Act - var result = await handler.Handle(new GetAllTeamQuery(page: 1, pageSize: pageSize), CancellationToken.None); + // Assert + Assert.Multiple( + () => Assert.NotNull(result), + () => Assert.NotNull(result.Value), + () => Assert.Equal(GetTeamMemberObjectsLists().Item2.Count, result.Value.TeamMembers.Count())); + } - // Assert - Assert.Multiple( - () => Assert.IsType>(result.Value.TeamMembers), - () => Assert.Equal(pageSize, result.Value.TeamMembers.Count())); - } + [Fact] + public async Task Handler_Returns_Correct_PageSize() + { + // Arrange + const int pageSize = 2; + var (teamMemberList, teamMemberDtoList) = GetTeamMemberObjectsLists(); + + SetupPaginatedRepository(teamMemberList + .Take(pageSize)); + SetupBlobService(); + SetupMapper(teamMemberDtoList + .Take(pageSize) + .ToList()); + + // Act + var result = await _handler.Handle(new GetAllTeamQuery(page: 1, pageSize: pageSize), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.IsType>(result.Value.TeamMembers), + () => Assert.Equal(pageSize, result.Value.TeamMembers.Count())); + } - private static List GetTeamList() + private static (List, List) GetTeamMemberObjectsLists() + { + var teamMemberList = new List() { - return new List + new TeamMember() { - new TeamMember - { - Id = 1, - }, - new TeamMember - { - Id = 2, - }, - new TeamMember - { - Id = 3, - }, - new TeamMember - { - Id = 4, - }, - new TeamMember - { - Id = 5, - }, - }; - } - - private static List GetListTeamDTO() - { - return new List + Id = 1, + }, + new TeamMember() { - new TeamMemberDTO - { - Id = 1, - }, - new TeamMemberDTO - { - Id = 2, - }, - new TeamMemberDTO - { - Id = 3, - }, - new TeamMemberDTO - { - Id = 4, - }, - new TeamMemberDTO - { - Id = 5, - }, - }; - } - - private void SetupPaginatedRepository(IEnumerable returnList) + Id = 4, + }, + new TeamMember() + { + Id = 6, + }, + }; + var teamMemberDtoList = new List() { - this.mockRepository.Setup(repo => repo.TeamRepository.GetAllPaginated( + new TeamMemberDTO() + { + Id = 1, + }, + new TeamMemberDTO() + { + Id = 4, + }, + new TeamMemberDTO() + { + Id = 6, + }, + }; + + return (teamMemberList, teamMemberDtoList); + } + + private void SetupPaginatedRepository(IEnumerable teamMemberList) + { + _mockRepository + .Setup(repo => repo.TeamRepository.GetAllPaginated( It.IsAny(), It.IsAny(), It.IsAny>?>(), @@ -159,13 +142,20 @@ private void SetupPaginatedRepository(IEnumerable returnList) It.IsAny, IIncludableQueryable>?>(), It.IsAny>?>(), It.IsAny>?>())) - .Returns(PaginationResponse.Create(returnList.AsQueryable())); - } + .Returns(PaginationResponse.Create(teamMemberList.AsQueryable())); + } - private void SetupMapper(IEnumerable teamDTOList) - { - this.mockMapper.Setup(x => x.Map>(It.IsAny>())) - .Returns(teamDTOList); - } + private void SetupBlobService() + { + _mockBlobService + .Setup(x => x.FindFileInStorageAsBase64(It.IsAny())) + .Returns(_testBase64String); + } + + private void SetupMapper(IEnumerable teamMemberDtoList) + { + _mockMapper + .Setup(x => x.Map>(It.IsAny>())) + .Returns(teamMemberDtoList); } } diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/TeamMemberLink/CreateTeamMembersLinkTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/TeamLink/CreateTeamMembersLinkTest.cs similarity index 95% rename from Streetcode/Streetcode.XUnitTest/MediatRTests/Team/TeamMemberLink/CreateTeamMembersLinkTest.cs rename to Streetcode/Streetcode.XUnitTest/MediatRTests/Team/TeamLink/CreateTeamMembersLinkTest.cs index ea72e30e4..29e532a99 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/TeamMemberLink/CreateTeamMembersLinkTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/TeamLink/CreateTeamMembersLinkTest.cs @@ -71,7 +71,7 @@ public async Task ShouldReturnSuccessfully_WhenPartnerAdded() } [Fact] - public async Task ShouldThrowExeption_WhenSaveChangesIsNotSuccessful() + public async Task ShouldThrowException_WhenSaveChangesIsNotSuccessful() { string expectedErrorMessage = "Failed to create a team"; this.mockLocalizerFailedToCreate.Setup(x => x["FailedToCreateTeam"]) @@ -96,7 +96,7 @@ public async Task ShouldThrowExeption_WhenSaveChangesIsNotSuccessful() } [Fact] - public async Task ShouldThrowExeption_WhenCreateNotSuccessful() + public async Task ShouldThrowException_WhenCreateNotSuccessful() { string expectedErrorMessage = "Cannot create team link"; this.mockLocalizerCannotCreate.Setup(x => x["CannotCreateTeamLink"]) @@ -123,7 +123,7 @@ public async Task ShouldThrowExeption_WhenCreateNotSuccessful() } [Fact] - public async Task ShouldThrowExeption_WhenMapNotSuccessful() + public async Task ShouldThrowException_WhenMapNotSuccessful() { string expectedErrorMessage = "Cannot convert null to team link"; this.mockLocalizerConvertNull.Setup(x => x["CannotConvertNullToTeamLink"]) @@ -168,8 +168,8 @@ private void SetupMapMethod(TeamMemberLink teamMemberLink) private void SetupCreateMethod(TeamMemberLink teamMemberLink) { - this.mockRepository.Setup(x => x.TeamLinkRepository.Create(It.Is(y => y.Id == teamMemberLink.Id))) - .Returns(teamMemberLink); + this.mockRepository.Setup(x => x.TeamLinkRepository.CreateAsync(It.Is(y => y.Id == teamMemberLink.Id))) + .ReturnsAsync(teamMemberLink); } private void SetupSaveChangesMethod() diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/TeamMemberLink/GetAllTeamMembersLinksTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/TeamLink/GetAllTeamMembersLinksTest.cs similarity index 93% rename from Streetcode/Streetcode.XUnitTest/MediatRTests/Team/TeamMemberLink/GetAllTeamMembersLinksTest.cs rename to Streetcode/Streetcode.XUnitTest/MediatRTests/Team/TeamLink/GetAllTeamMembersLinksTest.cs index 997fd3d03..e335d5f81 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/TeamMemberLink/GetAllTeamMembersLinksTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/TeamLink/GetAllTeamMembersLinksTest.cs @@ -87,11 +87,11 @@ private static IEnumerable GetTeamMemberLinksList() { var partners = new List { - new TeamMemberLink + new () { Id = 1, }, - new TeamMemberLink + new () { Id = 2, }, @@ -99,7 +99,7 @@ private static IEnumerable GetTeamMemberLinksList() return partners; } - private static List GetTeamMemberLinksListWithNotExistingId() + private static List? GetTeamMemberLinksListWithNotExistingId() { return null; } @@ -108,11 +108,11 @@ private static List GetListTeamMemberLinkDTO() { var partnersDTO = new List { - new TeamMemberLinkDTO + new () { Id = 1, }, - new TeamMemberLinkDTO + new () { Id = 2, }, @@ -126,12 +126,12 @@ private void SetupMapMethod(IEnumerable teamMemberLinksDTO) .Returns(teamMemberLinksDTO); } - private void SetupMapMethod(IEnumerable teamMemberLinks) + private void SetupMapMethod(IEnumerable? teamMemberLinks) { this.mockRepository.Setup(x => x.TeamLinkRepository.GetAllAsync( null, It.IsAny, IIncludableQueryable>>())) - .ReturnsAsync(teamMemberLinks); + .ReturnsAsync(teamMemberLinks!); } private void SetupGetAllAsyncMethod(IEnumerable teamMemberLinks) diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/TickerString/GetTickerStringHandlerTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/TickerString/GetTickerStringHandlerTest.cs new file mode 100644 index 000000000..f68b2b686 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/TickerString/GetTickerStringHandlerTest.cs @@ -0,0 +1,84 @@ +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Team.GetNamePosition; +using Streetcode.DAL.Entities.Team; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Team.TickerString +{ + public class GetTickerStringHandlerTest + { + private readonly Mock _mockRepository; + private readonly Mock _mockLogger; + + public GetTickerStringHandlerTest() + { + _mockRepository = new Mock(); + _mockLogger = new Mock(); + } + + [Fact] + public async Task ShouldReturnSuccess() + { + // Arrange + this.SetupGetAllAsync(GetPositionsList()); + + var handler = new GetTickerStringHandler(_mockRepository.Object, _mockLogger.Object); + + // Act + var result = await handler.Handle(new GetTickerStringQuery(), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.NotNull(result), + () => Assert.True(result.IsSuccess)); + } + + [Fact] + public async Task Handle_EmptyPositionsList_ReturnsEmptyString() + { + // Arrange + this.SetupGetAllAsync(new List()); + var handler = new GetTickerStringHandler(_mockRepository.Object, _mockLogger.Object); + + // Act + var result = await handler.Handle(new GetTickerStringQuery(), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.NotNull(result), + () => Assert.True(result.IsSuccess), + () => Assert.Empty(result.Value)); + } + + private static IEnumerable GetPositionsList() + { + var partners = new List() + { + new () + { + Id = 1, + TeamMembers = new List + { + new () { Id = 2 }, + }, + }, + new () { Id = 2 }, + }; + return partners; + } + + private void SetupGetAllAsync(IEnumerable positions) + { + _mockRepository + .Setup(x => x.PositionRepository + .GetAllAsync( + null, + It.IsAny, + IIncludableQueryable>>())) + .ReturnsAsync(positions); + } + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/UpdateTeamTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/UpdateTeamTest.cs index dd51e654f..e55a22fd9 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/UpdateTeamTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Team/UpdateTeamTest.cs @@ -28,8 +28,8 @@ public UpdateTeamTest() public async Task ShouldReturnSuccessfully_TeamUpdated() { // Arrange - var teamMember = this.GetTeamMember(1); - var updateQuery = new UpdateTeamQuery(this.GetTeamMemberDTO()); + var teamMember = GetTeamMember(1); + var updateQuery = new UpdateTeamQuery(GetTeamMemberDTO()); this.MapperSetup(teamMember, updateQuery.TeamMember); this.BasicRepositorySetup(updateQuery.TeamMember); @@ -53,12 +53,12 @@ public async Task ShouldThrowExeption_SaveChangesIsNotSuccessful() // Arrange const string exceptionMessage = "Failed to update a team"; - var teamMember = this.GetTeamMember(1); - var updateQuery = new UpdateTeamQuery(this.GetTeamMemberDTO()); + var teamMember = GetTeamMember(1); + var updateQuery = new UpdateTeamQuery(GetTeamMemberDTO()); this.MapperSetup(teamMember, updateQuery.TeamMember); this.BasicRepositorySetup(updateQuery.TeamMember); this.GetsAsyncRepositorySetup(teamMember); - this.mockRepository.Setup(repo => repo.SaveChanges()) + this.mockRepository.Setup(repo => repo.SaveChangesAsync()) .Throws(new Exception(exceptionMessage)); var handler = new UpdateTeamHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object); @@ -75,9 +75,9 @@ public async Task ShouldThrowExeption_SaveChangesIsNotSuccessful() public async Task ShouldDeleteUnusedTeamLinks(int unusedLinkId) { // Arrange - var teamMember = this.GetTeamMember(1); - var updateQuery = new UpdateTeamQuery(this.GetTeamMemberDTO()); - var existingLinks = this.GetTeamMemberLinksList().ToList(); + var teamMember = GetTeamMember(1); + var updateQuery = new UpdateTeamQuery(GetTeamMemberDTO()); + var existingLinks = GetTeamMemberLinksList().ToList(); existingLinks.Add(new TeamMemberLink { Id = unusedLinkId }); this.MapperSetup(teamMember, updateQuery.TeamMember); @@ -101,10 +101,10 @@ public async Task ShouldDeleteUnusedTeamLinks(int unusedLinkId) public async Task ShouldDeleteUnusedTeamPositions(int unusedPositionId) { // Arrange - var teamMember = this.GetTeamMember(1); - var updateQuery = new UpdateTeamQuery(this.GetTeamMemberDTO()); - var existingPositions = this.GetTeamMemberPositionsList().ToList(); - existingPositions.Add(this.GetTeamMemberPositions(teamMember.Id, unusedPositionId)); + var teamMember = GetTeamMember(1); + var updateQuery = new UpdateTeamQuery(GetTeamMemberDTO()); + var existingPositions = GetTeamMemberPositionsList().ToList(); + existingPositions.Add(GetTeamMemberPositions(teamMember.Id, unusedPositionId)); this.MapperSetup(teamMember, updateQuery.TeamMember); this.BasicRepositorySetup(updateQuery.TeamMember); @@ -126,15 +126,15 @@ public async Task ShouldDeleteUnusedTeamPositions(int unusedPositionId) public async Task WhenNewPositionIdIsNegative_UpdatesPositionAndTeamMemberPosition(int id, string posName) { // Arrange - var teamMember = this.GetTeamMember(1); - var existingPositions = this.GetTeamMemberPositionsList().ToList(); - existingPositions.Add(this.GetTeamMemberPositions(teamMember.Id, id)); + var teamMember = GetTeamMember(1); + var existingPositions = GetTeamMemberPositionsList().ToList(); + existingPositions.Add(GetTeamMemberPositions(teamMember.Id, id)); var teamMemberDto = new UpdateTeamMemberDTO { Positions = new List { - new PositionDTO { Id = id, Position = posName }, + new () { Id = id, Position = posName }, }, }; var updateQuery = new UpdateTeamQuery(teamMemberDto); @@ -143,8 +143,8 @@ public async Task WhenNewPositionIdIsNegative_UpdatesPositionAndTeamMemberPositi this.BasicRepositorySetup(updateQuery.TeamMember); this.GetsAsyncRepositorySetup(teamMember, memberPos: existingPositions); this.mockRepository.Setup(repo => repo.TeamPositionRepository.Delete(It.IsAny())); - this.mockRepository.Setup(repo => repo.TeamPositionRepository.Create(It.IsAny())); - this.mockRepository.Setup(repo => repo.PositionRepository.Create(It.IsAny())).Returns(new Positions()); + this.mockRepository.Setup(repo => repo.TeamPositionRepository.CreateAsync(It.IsAny())); + this.mockRepository.Setup(repo => repo.PositionRepository.CreateAsync(It.IsAny())).ReturnsAsync(new Positions()); var handler = new UpdateTeamHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object); @@ -156,44 +156,11 @@ public async Task WhenNewPositionIdIsNegative_UpdatesPositionAndTeamMemberPositi () => Assert.True(result.IsSuccess), () => Assert.Equal(0, result.Value.Id)); - this.mockRepository.Verify(repo => repo.PositionRepository.Create(It.IsAny()), Times.Once); - this.mockRepository.Verify(repo => repo.TeamPositionRepository.Create(It.IsAny()), Times.Once); - } - - private void BasicRepositorySetup(UpdateTeamMemberDTO updatedTeamMember) - { - this.mockRepository.Setup(repo => repo.TeamRepository.Update(It.IsAny())) - .Callback(tm => - { - tm.Positions = updatedTeamMember.Positions?.Select(p => new Positions { Id = p.Id, Position = p.Position }).ToList(); - }); - this.mockRepository.Setup(repo => repo.SaveChanges()); - } - - private void GetsAsyncRepositorySetup(TeamMember teamMember, List? link = null, List? memberPos = null) - { - var linkList = link ?? teamMember.TeamMemberLinks!; - var posList = memberPos ?? new List(); - - this.mockRepository.Setup(repo => repo.TeamLinkRepository - .GetAllAsync(It.IsAny>>(), It.IsAny, - IIncludableQueryable>>())).ReturnsAsync(linkList); - - this.mockRepository.Setup(repo => repo.TeamPositionRepository - .GetAllAsync(It.IsAny>>(), It.IsAny, - IIncludableQueryable>>())).ReturnsAsync(posList); - } - - private void MapperSetup(TeamMember teamMember, UpdateTeamMemberDTO updatedTeamMember) - { - this.mockMapper.Setup(mapper => mapper.Map(updatedTeamMember)) - .Returns(teamMember); - - this.mockMapper.Setup(mapper => mapper.Map(teamMember)) - .Returns(updatedTeamMember); + this.mockRepository.Verify(repo => repo.PositionRepository.CreateAsync(It.IsAny()), Times.Once); + this.mockRepository.Verify(repo => repo.TeamPositionRepository.CreateAsync(It.IsAny()), Times.Once); } - private TeamMember GetTeamMember(int imageId = 0) + private static TeamMember GetTeamMember(int imageId = 0) { return new TeamMember { @@ -201,13 +168,13 @@ private TeamMember GetTeamMember(int imageId = 0) Name = "Test", Description = "Test", IsMain = true, - Positions = this.GetPositionsList(), - TeamMemberLinks = this.GetTeamMemberLinksList(), + Positions = GetPositionsList(), + TeamMemberLinks = GetTeamMemberLinksList(), ImageId = imageId, }; } - private UpdateTeamMemberDTO GetTeamMemberDTO() + private static UpdateTeamMemberDTO GetTeamMemberDTO() { return new UpdateTeamMemberDTO { @@ -215,12 +182,12 @@ private UpdateTeamMemberDTO GetTeamMemberDTO() Name = "Test", Description = "Test", IsMain = true, - Positions = this.GetPositionsDTOList(), - TeamMemberLinks = this.GetTeamMemberLinksDTOList(), + Positions = GetPositionsDTOList(), + TeamMemberLinks = GetTeamMemberLinksDTOList(), }; } - private TeamMemberPositions GetTeamMemberPositions(int teamMemberId, int posId) + private static TeamMemberPositions GetTeamMemberPositions(int teamMemberId, int posId) { return new TeamMemberPositions { @@ -229,49 +196,82 @@ private TeamMemberPositions GetTeamMemberPositions(int teamMemberId, int posId) }; } - private List GetPositionsDTOList() + private static List GetPositionsDTOList() { return new List { - new PositionDTO { Id = 1, Position = "Position 1" }, - new PositionDTO { Id = 2, Position = "Position 2" }, + new () { Id = 1, Position = "Position 1" }, + new () { Id = 2, Position = "Position 2" }, }; } - private List GetPositionsList() + private static List GetPositionsList() { return new List { - new Positions { Id = 1, Position = "Position 1" }, - new Positions { Id = 2, Position = "Position 2" }, + new () { Id = 1, Position = "Position 1" }, + new () { Id = 2, Position = "Position 2" }, }; } - private List GetTeamMemberPositionsList() + private static List GetTeamMemberPositionsList() { return new List { - new TeamMemberPositions { TeamMemberId = 1, PositionsId = 1 }, - new TeamMemberPositions { TeamMemberId = 1, PositionsId = 2 }, + new () { TeamMemberId = 1, PositionsId = 1 }, + new () { TeamMemberId = 1, PositionsId = 2 }, }; } - private List GetTeamMemberLinksDTOList() + private static List GetTeamMemberLinksDTOList() { return new List { - new TeamMemberLinkDTO { Id = 1 }, - new TeamMemberLinkDTO { Id = 2 }, + new () { Id = 1 }, + new () { Id = 2 }, }; } - private List GetTeamMemberLinksList() + private static List GetTeamMemberLinksList() { return new List { - new TeamMemberLink { Id = 1 }, - new TeamMemberLink { Id = 2 }, + new () { Id = 1 }, + new () { Id = 2 }, }; } + + private void BasicRepositorySetup(UpdateTeamMemberDTO updatedTeamMember) + { + this.mockRepository.Setup(repo => repo.TeamRepository.Update(It.IsAny())) + .Callback(tm => + { + tm.Positions = updatedTeamMember.Positions?.Select(p => new Positions { Id = p.Id, Position = p.Position }).ToList(); + }); + this.mockRepository.Setup(repo => repo.SaveChangesAsync()); + } + + private void GetsAsyncRepositorySetup(TeamMember teamMember, List? link = null, List? memberPos = null) + { + var linkList = link ?? teamMember.TeamMemberLinks!; + var posList = memberPos ?? new List(); + + this.mockRepository.Setup(repo => repo.TeamLinkRepository + .GetAllAsync(It.IsAny>>(), It.IsAny, + IIncludableQueryable>>())).ReturnsAsync(linkList); + + this.mockRepository.Setup(repo => repo.TeamPositionRepository + .GetAllAsync(It.IsAny>>(), It.IsAny, + IIncludableQueryable>>())).ReturnsAsync(posList); + } + + private void MapperSetup(TeamMember teamMember, UpdateTeamMemberDTO updatedTeamMember) + { + this.mockMapper.Setup(mapper => mapper.Map(updatedTeamMember)) + .Returns(teamMember); + + this.mockMapper.Setup(mapper => mapper.Map(teamMember)) + .Returns(updatedTeamMember); + } } } diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/CreateHistoricalContextTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/CreateHistoricalContextTest.cs index aeba9dfd8..c8f55ca9d 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/CreateHistoricalContextTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/CreateHistoricalContextTest.cs @@ -13,31 +13,31 @@ namespace Streetcode.XUnitTest.MediatRTests.Timeline.HistoricalContextTests { public class CreateHistoricalContextTest { - private readonly Mock mockRepo; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerValidation; - private readonly Mock> mockLocalizerFieldNames; + private readonly Mock _mockRepo; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly Mock> _mockLocalizerValidation; + private readonly Mock> _mockLocalizerFieldNames; public CreateHistoricalContextTest() { - this.mockRepo = new Mock(); - this.mockMapper = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerValidation = new Mock>(); - this.mockLocalizerFieldNames = new Mock>(); + _mockRepo = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockLocalizerValidation = new Mock>(); + _mockLocalizerFieldNames = new Mock>(); } [Fact] public async Task ShouldReturnSuccessfully_IsCorrectAndSuccess() { // Arrange - this.mockRepo.Setup(repo => repo.HistoricalContextRepository.CreateAsync(new HistoricalContext())); - this.mockRepo.Setup(repo => repo.SaveChangesAsync()).ReturnsAsync(1); + _mockRepo.Setup(repo => repo.HistoricalContextRepository.CreateAsync(new HistoricalContext())); + _mockRepo.Setup(repo => repo.SaveChangesAsync()).ReturnsAsync(1); - this.mockMapper.Setup(x => x.Map(It.IsAny())).Returns(new HistoricalContextDTO()); + _mockMapper.Setup(x => x.Map(It.IsAny())).Returns(new HistoricalContextDTO()); - var handler = new CreateHistoricalContextHandler(this.mockMapper.Object, this.mockRepo.Object, this.mockLogger.Object, this.mockLocalizerValidation.Object, this.mockLocalizerFieldNames.Object); + var handler = new CreateHistoricalContextHandler(_mockMapper.Object, _mockRepo.Object, _mockLogger.Object, _mockLocalizerValidation.Object, _mockLocalizerFieldNames.Object); // Act var result = await handler.Handle(new CreateHistoricalContextCommand(new HistoricalContextDTO()), CancellationToken.None); diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/DeleteHistoricalContextTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/DeleteHistoricalContextTest.cs index efa80f926..b49843a10 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/DeleteHistoricalContextTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/DeleteHistoricalContextTest.cs @@ -12,15 +12,15 @@ namespace Streetcode.XUnitTest.MediatRTests.Timeline.HistoricalContextTests { public class DeleteHistoricalContextTest { - private readonly Mock mockRepository; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizer; + private readonly Mock _mockRepository; + private readonly Mock _mockLogger; + private readonly Mock> _mockLocalizer; public DeleteHistoricalContextTest() { - this.mockRepository = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizer = new Mock>(); + _mockRepository = new Mock(); + _mockLogger = new Mock(); + _mockLocalizer = new Mock>(); } [Fact] @@ -31,7 +31,7 @@ public async Task ShouldDeleteSuccessfully() this.SetupMockRepositoryGetFirstOrDefault(testContexts); this.SetupMockRepositorySaveChangesReturns(1); - var handler = new DeleteHistoricalContextHandler(this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizer.Object); + var handler = new DeleteHistoricalContextHandler(_mockRepository.Object, _mockLogger.Object, _mockLocalizer.Object); // Act var result = await handler.Handle(new DeleteHistoricalContextCommand(testContexts.Id), CancellationToken.None); @@ -41,10 +41,10 @@ public async Task ShouldDeleteSuccessfully() () => Assert.NotNull(result), () => Assert.True(result.IsSuccess)); - this.mockRepository.Verify( + _mockRepository.Verify( x => x.HistoricalContextRepository.Delete(It.Is(x => x.Id == testContexts.Id)), Times.Once); - this.mockRepository.Verify(x => x.SaveChangesAsync(), Times.Once); + _mockRepository.Verify(x => x.SaveChangesAsync(), Times.Once); } [Fact] @@ -53,18 +53,18 @@ public async Task ShouldThrowException_IdNotExisting() // Arrange var testContexts = DeleteContext(); var expectedError = "CannotFindHistoricalContextWithCorrespondingId"; - this.mockLocalizer.Setup(x => x[expectedError, It.IsAny()]).Returns( + _mockLocalizer.Setup(x => x[expectedError, It.IsAny()]).Returns( new LocalizedString(expectedError, expectedError)); this.SetupMockRepositoryGetFirstOrDefault(null); - var handler = new DeleteHistoricalContextHandler(this.mockRepository.Object, this.mockLogger.Object, this.mockLocalizer.Object); + var handler = new DeleteHistoricalContextHandler(_mockRepository.Object, _mockLogger.Object, _mockLocalizer.Object); // Act var result = await handler.Handle(new DeleteHistoricalContextCommand(testContexts.Id), CancellationToken.None); // Assert Assert.Equal(expectedError, result.Errors[0].Message); - this.mockRepository.Verify(x => x.HistoricalContextRepository.Delete(It.IsAny()), Times.Never); + _mockRepository.Verify(x => x.HistoricalContextRepository.Delete(It.IsAny()), Times.Never); } private static HistoricalContext DeleteContext() @@ -77,7 +77,7 @@ private static HistoricalContext DeleteContext() private void SetupMockRepositoryGetFirstOrDefault(HistoricalContext? context) { - this.mockRepository + _mockRepository .Setup(x => x.HistoricalContextRepository .GetFirstOrDefaultAsync(It.IsAny>>(), null)) .ReturnsAsync(context); @@ -85,7 +85,7 @@ private void SetupMockRepositoryGetFirstOrDefault(HistoricalContext? context) private void SetupMockRepositorySaveChangesReturns(int number) { - this.mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(number); + _mockRepository.Setup(x => x.SaveChangesAsync()).ReturnsAsync(number); } } } \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/GetAllHistoricalContextTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/GetAllHistoricalContextTest.cs index 28a3170e0..d03eca429 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/GetAllHistoricalContextTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/GetAllHistoricalContextTest.cs @@ -7,7 +7,6 @@ using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Timeline.HistoricalContext.GetAll; using Streetcode.BLL.SharedResource; -using Streetcode.DAL.Entities.Streetcode.TextContent; using Streetcode.DAL.Entities.Timeline; using Streetcode.DAL.Helpers; using Streetcode.DAL.Repositories.Interfaces.Base; @@ -18,17 +17,17 @@ namespace Streetcode.XUnitTest.MediatRTests.Timeline.HistoricalContextTests { public class GetAllHistoricalContextTest { - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotFind; - private Mock mockRepository; - private Mock mockMapper; + private readonly Mock _mockLogger; + private readonly Mock> _mockLocalizerCannotFind; + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; public GetAllHistoricalContextTest() { - this.mockRepository = new (); - this.mockMapper = new (); - this.mockLogger = new Mock(); - this.mockLocalizerCannotFind = new Mock>(); + _mockRepository = new (); + _mockMapper = new (); + _mockLogger = new Mock(); + _mockLocalizerCannotFind = new Mock>(); } [Fact] @@ -37,10 +36,10 @@ public async Task ShouldReturnSuccessfully_CorrectType() // Arrange this.SetupPaginatedRepository(GetListHistoricalContext()); this.SetupMapper(GetListHistoricalContextDTO()); - var hendler = new GetAllHistoricalContextHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + var handler = new GetAllHistoricalContextHandler(_mockRepository.Object, _mockMapper.Object, _mockLogger.Object, _mockLocalizerCannotFind.Object); // Act - var result = await hendler.Handle(new GetAllHistoricalContextQuery(), CancellationToken.None); + var result = await handler.Handle(new GetAllHistoricalContextQuery(), CancellationToken.None); // Assert Assert.Multiple( @@ -55,10 +54,10 @@ public async Task ShouldReturnSuccessfully_CountMatch() this.SetupPaginatedRepository(GetListHistoricalContext()); this.SetupMapper(GetListHistoricalContextDTO()); - var hendler = new GetAllHistoricalContextHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + var handler = new GetAllHistoricalContextHandler(_mockRepository.Object, _mockMapper.Object, _mockLogger.Object, _mockLocalizerCannotFind.Object); // Act - var result = await hendler.Handle(new GetAllHistoricalContextQuery(), CancellationToken.None); + var result = await handler.Handle(new GetAllHistoricalContextQuery(), CancellationToken.None); // Assert Assert.Multiple( @@ -74,7 +73,7 @@ public async Task Handler_Returns_Correct_PageSize() this.SetupPaginatedRepository(GetListHistoricalContext().Take(pageSize)); this.SetupMapper(GetListHistoricalContextDTO().Take(pageSize).ToList()); - var handler = new GetAllHistoricalContextHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + var handler = new GetAllHistoricalContextHandler(_mockRepository.Object, _mockMapper.Object, _mockLogger.Object, _mockLocalizerCannotFind.Object); // Act var result = await handler.Handle(new GetAllHistoricalContextQuery(page: 1, pageSize: pageSize), CancellationToken.None); @@ -89,11 +88,11 @@ private static IQueryable GetListHistoricalContext() { var historicalContexts = new List { - new HistoricalContext { Id = 1, Title = "HistoricalContext1" }, - new HistoricalContext { Id = 2, Title = "HistoricalContext2" }, - new HistoricalContext { Id = 3, Title = "HistoricalContext3" }, - new HistoricalContext { Id = 4, Title = "HistoricalContext4" }, - new HistoricalContext { Id = 5, Title = "HistoricalContext5" }, + new () { Id = 1, Title = "HistoricalContext1" }, + new () { Id = 2, Title = "HistoricalContext2" }, + new () { Id = 3, Title = "HistoricalContext3" }, + new () { Id = 4, Title = "HistoricalContext4" }, + new () { Id = 5, Title = "HistoricalContext5" }, }; return historicalContexts.AsQueryable(); @@ -103,11 +102,11 @@ private static IEnumerable GetListHistoricalContextDTO() { var historicalContextsDTO = new List { - new HistoricalContextDTO { Id = 1, Title = "HistoricalContext1" }, - new HistoricalContextDTO { Id = 2, Title = "HistoricalContext2" }, - new HistoricalContextDTO { Id = 3, Title = "HistoricalContext3" }, - new HistoricalContextDTO { Id = 4, Title = "HistoricalContext4" }, - new HistoricalContextDTO { Id = 5, Title = "HistoricalContext5" }, + new () { Id = 1, Title = "HistoricalContext1" }, + new () { Id = 2, Title = "HistoricalContext2" }, + new () { Id = 3, Title = "HistoricalContext3" }, + new () { Id = 4, Title = "HistoricalContext4" }, + new () { Id = 5, Title = "HistoricalContext5" }, }; return historicalContextsDTO; @@ -115,7 +114,7 @@ private static IEnumerable GetListHistoricalContextDTO() private void SetupPaginatedRepository(IEnumerable returnList) { - this.mockRepository.Setup(repo => repo.HistoricalContextRepository.GetAllPaginated( + _mockRepository.Setup(repo => repo.HistoricalContextRepository.GetAllPaginated( It.IsAny(), It.IsAny(), It.IsAny>?>(), @@ -128,7 +127,7 @@ private void SetupPaginatedRepository(IEnumerable returnList) private void SetupMapper(IEnumerable returnList) { - this.mockMapper + _mockMapper .Setup(x => x.Map>(It.IsAny>())) .Returns(returnList); } diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/GetByIdHistoricalContextTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/GetByIdHistoricalContextTest.cs index d5abe685c..c3261d185 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/GetByIdHistoricalContextTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/GetByIdHistoricalContextTest.cs @@ -16,18 +16,18 @@ namespace Streetcode.XUnitTest.MediatRTests.Timeline.HistoricalContextTests public class GetByIdHistoricalContextTest { private const int id = 1; - private readonly Mock mockRepo; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizer; + private readonly Mock _mockRepo; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly Mock> _mockLocalizer; - private readonly HistoricalContext context = new HistoricalContext + private readonly HistoricalContext _context = new () { Id = id, Title = "some title 1", }; - private readonly HistoricalContextDTO contextDto = new HistoricalContextDTO + private readonly HistoricalContextDTO _contextDto = new () { Id = id, Title = "some title 1", @@ -35,20 +35,20 @@ public class GetByIdHistoricalContextTest public GetByIdHistoricalContextTest() { - this.mockRepo = new Mock(); - this.mockMapper = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizer = new Mock>(); + _mockRepo = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockLocalizer = new Mock>(); } [Fact] public async Task Handler_Returns_Matching_Element() { // Arrange - this.SetupRepository(this.context); - this.SetupMapper(this.contextDto); + this.SetupRepository(_context); + this.SetupMapper(_contextDto); - var handler = new GetHistoricalContextByIdHandler(this.mockMapper.Object, this.mockRepo.Object, this.mockLogger.Object, this.mockLocalizer.Object); + var handler = new GetHistoricalContextByIdHandler(_mockMapper.Object, _mockRepo.Object, _mockLogger.Object, _mockLocalizer.Object); // Act var result = await handler.Handle(new GetHistoricalContextByIdQuery(id), CancellationToken.None); @@ -66,7 +66,7 @@ public async Task Handler_Returns_NoMatching_Element() this.SetupRepository(new HistoricalContext()); this.SetupMapper(new HistoricalContextDTO()); - var handler = new GetHistoricalContextByIdHandler(this.mockMapper.Object, this.mockRepo.Object, this.mockLogger.Object, this.mockLocalizer.Object); + var handler = new GetHistoricalContextByIdHandler(_mockMapper.Object, _mockRepo.Object, _mockLogger.Object, _mockLocalizer.Object); // Act var result = await handler.Handle(new GetHistoricalContextByIdQuery(id), CancellationToken.None); @@ -79,7 +79,7 @@ public async Task Handler_Returns_NoMatching_Element() private void SetupRepository(HistoricalContext context) { - this.mockRepo + _mockRepo .Setup(repo => repo.HistoricalContextRepository .GetFirstOrDefaultAsync( It.IsAny>>(), @@ -90,7 +90,7 @@ private void SetupRepository(HistoricalContext context) private void SetupMapper(HistoricalContextDTO contextDto) { - this.mockMapper + _mockMapper .Setup(x => x.Map(It.IsAny())) .Returns(contextDto); } diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/GetByTitleHistoricalContextTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/GetByTitleHistoricalContextTest.cs index 15a26fbc9..2e3079eed 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/GetByTitleHistoricalContextTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/GetByTitleHistoricalContextTest.cs @@ -16,18 +16,18 @@ namespace Streetcode.XUnitTest.MediatRTests.Timeline.HistoricalContextTests; public class GetByTitleHistoricalContextTest { private const string title = "test_title"; - private readonly Mock mockRepo; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizer; + private readonly Mock _mockRepo; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly Mock> _mockLocalizer; - private readonly HistoricalContext context = new HistoricalContext + private readonly HistoricalContext _context = new () { Id = 1, Title = title, }; - private readonly HistoricalContextDTO contextDto = new HistoricalContextDTO + private readonly HistoricalContextDTO _contextDto = new () { Id = 1, Title = title, @@ -35,20 +35,20 @@ public class GetByTitleHistoricalContextTest public GetByTitleHistoricalContextTest() { - this.mockRepo = new Mock(); - this.mockMapper = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizer = new Mock>(); + _mockRepo = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockLocalizer = new Mock>(); } [Fact] public async Task Handler_Returns_Matching_Element() { // Arrange - this.SetupRepository(this.context); - this.SetupMapper(this.contextDto); + this.SetupRepository(_context); + this.SetupMapper(_contextDto); - var handler = new GetHistoricalContextByTitleHandler(this.mockMapper.Object, this.mockRepo.Object, this.mockLogger.Object, this.mockLocalizer.Object); + var handler = new GetHistoricalContextByTitleHandler(_mockMapper.Object, _mockRepo.Object, _mockLogger.Object, _mockLocalizer.Object); // Act var result = await handler.Handle(new GetHistoricalContextByTitleQuery(title), CancellationToken.None); @@ -66,7 +66,7 @@ public async Task Handler_Returns_NoMatching_Element() this.SetupRepository(new HistoricalContext()); this.SetupMapper(new HistoricalContextDTO()); - var handler = new GetHistoricalContextByTitleHandler(this.mockMapper.Object, this.mockRepo.Object, this.mockLogger.Object, this.mockLocalizer.Object); + var handler = new GetHistoricalContextByTitleHandler(_mockMapper.Object, _mockRepo.Object, _mockLogger.Object, _mockLocalizer.Object); // Act var result = await handler.Handle(new GetHistoricalContextByTitleQuery(title), CancellationToken.None); @@ -79,7 +79,7 @@ public async Task Handler_Returns_NoMatching_Element() private void SetupRepository(HistoricalContext context) { - this.mockRepo + _mockRepo .Setup(repo => repo.HistoricalContextRepository .GetFirstOrDefaultAsync( It.IsAny>>(), @@ -90,7 +90,7 @@ private void SetupRepository(HistoricalContext context) private void SetupMapper(HistoricalContextDTO contextDto) { - this.mockMapper.Setup(x => x.Map(It.IsAny())) + _mockMapper.Setup(x => x.Map(It.IsAny())) .Returns(contextDto); } } \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/UpdateHistoricalContextTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/UpdateHistoricalContextTest.cs index 1fc6c17a0..293136293 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/UpdateHistoricalContextTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/HistoricalContextTests/UpdateHistoricalContextTest.cs @@ -1,55 +1,44 @@ using System.Linq.Expressions; using AutoMapper; using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; using Moq; using Streetcode.BLL.DTO.Timeline; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Timeline.HistoricalContext.Update; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Timeline; using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; using Xunit; namespace Streetcode.XUnitTest.MediatRTests.Timeline.HistoricalContextTests; public class UpdateHistoricalContextTest { - private readonly Mock mockRepo; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerValidation; - private readonly Mock> mockLocalizerFieldNames; - private readonly Mock> mockLocalizerCannotFind; + private readonly Mock _mockRepo; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly MockFailedToValidateLocalizer _mockLocalizerValidation; + private readonly MockFieldNamesLocalizer _mockLocalizerFieldNames; + private readonly MockCannotFindLocalizer _mockLocalizerCannotFind; public UpdateHistoricalContextTest() { - this.mockRepo = new Mock(); - this.mockMapper = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerValidation = new Mock>(); - this.mockLocalizerFieldNames = new Mock>(); - this.mockLocalizerCannotFind = new Mock>(); + _mockRepo = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockLocalizerValidation = new MockFailedToValidateLocalizer(); + _mockLocalizerFieldNames = new MockFieldNamesLocalizer(); + _mockLocalizerCannotFind = new MockCannotFindLocalizer(); } [Fact] public async Task ShouldReturnSuccessfully_IsCorrectAndSuccess() { // Arrange - this.mockRepo.Setup(repo => repo.HistoricalContextRepository.Update(new HistoricalContext())); - this.mockRepo.Setup(repo => - repo.HistoricalContextRepository.GetFirstOrDefaultAsync(It.IsAny>>(), default)) - .ReturnsAsync((Expression> expr, IIncludableQueryable include) => - { - BinaryExpression eq = (BinaryExpression)expr.Body; - MemberExpression member = (MemberExpression)eq.Left; - return member.Member.Name == "Id" ? new HistoricalContext() : null; - }); + this.SetupRepo(new HistoricalContext(), null, new HistoricalContext(), true); + this.SetupMapper(new HistoricalContextDTO()); - this.mockRepo.Setup(repo => repo.SaveChangesAsync()).ReturnsAsync(1); - this.mockMapper.Setup(x => x.Map(It.IsAny())).Returns(new HistoricalContextDTO()); - - var handler = new UpdateHistoricalContextHandler(this.mockRepo.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object, this.mockLocalizerValidation.Object, this.mockLocalizerFieldNames.Object); + var handler = new UpdateHistoricalContextHandler(_mockRepo.Object, _mockMapper.Object, _mockLogger.Object, _mockLocalizerCannotFind, _mockLocalizerValidation, _mockLocalizerFieldNames); // Act var result = await handler.Handle(new UpdateHistoricalContextCommand(new HistoricalContextDTO()), CancellationToken.None); @@ -59,4 +48,45 @@ public async Task ShouldReturnSuccessfully_IsCorrectAndSuccess() () => Assert.IsType(result.Value), () => Assert.True(result.IsSuccess)); } + + [Fact] + public async Task ShouldReturnBadRequest_ChangesNotSaved() + { + // Arrange + this.SetupRepo(new HistoricalContext(), null, new HistoricalContext(), false); + + var handler = new UpdateHistoricalContextHandler(_mockRepo.Object, _mockMapper.Object, _mockLogger.Object, _mockLocalizerCannotFind, _mockLocalizerValidation, _mockLocalizerFieldNames); + + // Act + var result = await handler.Handle(new UpdateHistoricalContextCommand(new HistoricalContextDTO()), CancellationToken.None); + + // Assert + Assert.True(result.IsFailed); + } + + private void SetupRepo(HistoricalContext? getValue, HistoricalContext? getRepeatValue, HistoricalContext? updateValue, bool saveValue) + { + _mockRepo.Setup(repo => repo.HistoricalContextRepository.Update(updateValue)); + _mockRepo.Setup(repo => + repo.HistoricalContextRepository.GetFirstOrDefaultAsync(It.IsAny>>(), default)) + .ReturnsAsync((Expression> expr, IIncludableQueryable include) => + { + BinaryExpression eq = (BinaryExpression)expr.Body; + MemberExpression member = (MemberExpression)eq.Left; + return member.Member.Name == "Id" ? getValue : getRepeatValue; + }); + if (saveValue) + { + _mockRepo.Setup(repo => repo.SaveChangesAsync()).ReturnsAsync(1); + } + else + { + _mockRepo.Setup(repo => repo.SaveChangesAsync()).Throws(new Exception()); + } + } + + private void SetupMapper(HistoricalContextDTO getValue) + { + _mockMapper.Setup(x => x.Map(It.IsAny())).Returns(getValue); + } } \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/TimelineItemTests/GetAllTimelineItemsTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/TimelineItemTests/GetAllTimelineItemsTest.cs new file mode 100644 index 000000000..dd1df09e9 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/TimelineItemTests/GetAllTimelineItemsTest.cs @@ -0,0 +1,134 @@ +using System.Linq.Expressions; +using AutoMapper; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.Extensions.Localization; +using Moq; +using Streetcode.BLL.DTO.Timeline; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Timeline.TimelineItem.GetAll; +using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Entities.Timeline; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Timeline.TimelineItemTests +{ + public class GetAllTimelineItemsTest + { + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly Mock> _mockStringLocalizer; + + public GetAllTimelineItemsTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockStringLocalizer = new Mock>(); + } + + [Fact] + public async Task ReturnsSuccessfully_CorrectType() + { + // Arrange + this.SetupRepository(GetTimelinesList()); + this.SetupMapper(GetTimelineDTOList()); + + var handler = new GetAllTimelineItemsHandler(_mockRepository.Object, _mockMapper.Object, _mockLogger.Object, _mockStringLocalizer.Object); + + // Act + var result = await handler.Handle(new GetAllTimelineItemsQuery(), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.NotNull(result), + () => Assert.IsAssignableFrom>(result.Value)); + } + + [Fact] + public async Task ReturnsSuccessfully_AllTimelines() + { + // Arrange + this.SetupRepository(GetTimelinesList()); + this.SetupMapper(GetTimelineDTOList()); + + var handler = new GetAllTimelineItemsHandler(_mockRepository.Object, _mockMapper.Object, _mockLogger.Object, _mockStringLocalizer.Object); + + // Act + var result = await handler.Handle(new GetAllTimelineItemsQuery(), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.NotNull(result), + () => Assert.Equal(GetTimelinesList().Count(), result.Value.Count())); + } + + [Fact] + public async Task ReturnsError_IsNull() + { + // Arrange + this.SetupRepository(null); + + var expectedError = $"Cannot find any timeline item"; + this.SetupLocalizer(expectedError); + + var handler = new GetAllTimelineItemsHandler(_mockRepository.Object, _mockMapper.Object, _mockLogger.Object, _mockStringLocalizer.Object); + + // Act + var result = await handler.Handle(new GetAllTimelineItemsQuery(), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.False(result.IsSuccess), + () => Assert.Equal(expectedError, result.Errors.Single().Message)); + } + + private static IEnumerable GetTimelinesList() + { + var timelines = new List + { + new () { Id = 1, }, + new () { Id = 2, }, + new () { Id = 3, }, + }; + + return timelines; + } + + private static IEnumerable GetTimelineDTOList() + { + var timelines = new List + { + new () { Id = 1, }, + new () { Id = 2, }, + new () { Id = 3, }, + }; + + return timelines; + } + + private void SetupRepository(IEnumerable? returnList) + { + _mockRepository + .Setup(repo => repo.TimelineRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(returnList ?? default!); + } + + private void SetupMapper(IEnumerable returnList) + { + _mockMapper + .Setup(x => x.Map>( + It.IsAny>())) + .Returns(returnList); + } + + private void SetupLocalizer(string expectedError) + { + _mockStringLocalizer.Setup(localizer => localizer["CannotFindAnyTimelineItem"]) + .Returns(new LocalizedString("CannotFindAnyTimelineItem", expectedError)); + } + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/TimelineItemTests/GetTimelineItemByIdTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/TimelineItemTests/GetTimelineItemByIdTest.cs new file mode 100644 index 000000000..597449193 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/TimelineItemTests/GetTimelineItemByIdTest.cs @@ -0,0 +1,135 @@ +using System.Linq.Expressions; +using AutoMapper; +using FluentResults; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.Extensions.Localization; +using Moq; +using Streetcode.BLL.DTO.Timeline; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Timeline.TimelineItem.GetById; +using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Entities.Timeline; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Timeline.TimelineItemTests +{ + public class GetTimelineItemByIdTest + { + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly Mock> _mockStringLocalizer; + + public GetTimelineItemByIdTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockStringLocalizer = new Mock>(); + } + + [Theory] + [InlineData(1)] + public async Task Handle_ReturnsTimelineItem(int id) + { + // Arrange + this.SetupRepository(GetTimelineItem()); + this.SetupMapper(GetTimelineDTO()); + + var handler = new GetTimelineItemByIdHandler(_mockRepository.Object, _mockMapper.Object, _mockLogger.Object, _mockStringLocalizer.Object); + + // Act + var result = await handler.Handle(new GetTimelineItemByIdQuery(id), CancellationToken.None); + + // Assert + Assert.Equal(id, result.Value.Id); + } + + [Theory] + [InlineData(1)] + public async Task Handle_ReturnsCorrectType(int id) + { + // Arrange + this.SetupRepository(GetTimelineItem()); + this.SetupMapper(GetTimelineDTO()); + + var handler = new GetTimelineItemByIdHandler(_mockRepository.Object, _mockMapper.Object, _mockLogger.Object, _mockStringLocalizer.Object); + + // Act + var result = await handler.Handle(new GetTimelineItemByIdQuery(id), CancellationToken.None); + + // Assert + Assert.IsType>(result); + } + + [Theory] + [InlineData(-1)] + public async Task Handle_WithNonExistentId_ReturnsError(int id) + { + // Arrange + this.SetupRepository(null); + + string expectedError = $"Cannot find a timeline item with corresponding id: {id}"; + this.SetupLocalizer(expectedError); + + var handler = new GetTimelineItemByIdHandler(_mockRepository.Object, _mockMapper.Object, _mockLogger.Object, _mockStringLocalizer.Object); + + // Act + var result = await handler.Handle(new GetTimelineItemByIdQuery(id), CancellationToken.None); + + // Assert + Assert.Equal(expectedError, result.Errors.Single().Message); + } + + private static TimelineItem GetTimelineItem() + { + return new TimelineItem + { + Id = 1, + }; + } + + private static TimelineItemDTO GetTimelineDTO() + { + return new TimelineItemDTO + { + Id = 1, + }; + } + + private void SetupRepository(TimelineItem? returnItem) + { + _mockRepository + .Setup(repo => repo.TimelineRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, + IIncludableQueryable>>())) + .ReturnsAsync(returnItem); + } + + private void SetupMapper(TimelineItemDTO returnItem) + { + _mockMapper + .Setup(x => x.Map( + It.IsAny())) + .Returns(returnItem); + } + + private void SetupLocalizer(string expectedError) + { + _mockStringLocalizer + .Setup(x => x[ + It.IsAny(), It.IsAny()]) + .Returns((string key, object[] args) => + { + if (args.Length > 0) + { + return new LocalizedString(key, expectedError); + } + + return new LocalizedString(key, "Cannot find a timeline item with unknown id"); + }); + } + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/TimelineItemTests/GetTimelineItemByStreetcodeIdTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/TimelineItemTests/GetTimelineItemByStreetcodeIdTest.cs index 0fa3328d9..4f7f6068f 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/TimelineItemTests/GetTimelineItemByStreetcodeIdTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Timeline/TimelineItemTests/GetTimelineItemByStreetcodeIdTest.cs @@ -3,12 +3,10 @@ using AutoMapper; using FluentResults; using Microsoft.EntityFrameworkCore.Query; -using Microsoft.Extensions.Localization; using Moq; using Streetcode.BLL.DTO.Timeline; using Streetcode.BLL.Interfaces.Logging; using Streetcode.BLL.MediatR.Timeline.TimelineItem.GetByStreetcodeId; -using Streetcode.BLL.SharedResource; using Streetcode.DAL.Entities.Streetcode; using Streetcode.DAL.Entities.Streetcode.TextContent; using Streetcode.DAL.Entities.Timeline; @@ -20,35 +18,26 @@ namespace Streetcode.XUnitTest.MediatRTests.Timeline.TimelineItemTests [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1413:UseTrailingCommasInMultiLineInitializers", Justification = "Reviewed.")] public class GetTimelineItemByStreetcodeIdTest { - private readonly Mock mockRepository; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotFind; + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; public GetTimelineItemByStreetcodeIdTest() { - mockRepository = new Mock(); - mockMapper = new Mock(); - mockLogger = new Mock(); - mockLocalizerCannotFind = new Mock>(); + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); } [Fact] public async Task ReturnsSuccessfully_NotEmpty() { // Arrange - this.mockRepository.Setup(x => x.TimelineRepository.GetAllAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(GetExistingTimelineList()); + this.SetupRepository(GetExistingTimelineList()); - this.mockMapper - .Setup(x => x - .Map>(It.IsAny>())) - .Returns(GetTimelineItemDTOList()); + this.SetupMapper(GetTimelineItemDTOList()); - var handler = new GetTimelineItemsByStreetcodeIdHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + var handler = new GetTimelineItemsByStreetcodeIdHandler(this._mockRepository.Object, this._mockMapper.Object, this._mockLogger.Object); int streetcodeId = 1; // Act @@ -65,13 +54,9 @@ public async Task ReturnsSuccessfully_NotEmpty() public async Task ReturnsSuccessfully_Empty() { // Arrange - this.mockRepository.Setup(x => x.TimelineRepository.GetAllAsync( - It.IsAny>>(), - It.IsAny, - IIncludableQueryable>>())) - .ReturnsAsync(GetEmptyTimelineList()); + this.SetupRepository(GetEmptyTimelineList()); - var handler = new GetTimelineItemsByStreetcodeIdHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + var handler = new GetTimelineItemsByStreetcodeIdHandler(this._mockRepository.Object, this._mockMapper.Object, this._mockLogger.Object); int streetcodeId = 1; // Act @@ -84,10 +69,11 @@ public async Task ReturnsSuccessfully_Empty() () => Assert.Empty(result.Value)); } - public static List GetExistingTimelineList() + private static List GetExistingTimelineList() { - return new List { - new TimelineItem + return new List + { + new () { Id = 1, Date = DateTime.Now, @@ -100,16 +86,16 @@ public static List GetExistingTimelineList() }; } - public static List GetEmptyTimelineList() + private static List GetEmptyTimelineList() { return new List(); } - public static List GetTimelineItemDTOList() + private static List GetTimelineItemDTOList() { return new List { - new TimelineItemDTO + new () { Id = 1, Date = DateTime.Now, @@ -117,5 +103,22 @@ public static List GetTimelineItemDTOList() } }; } + + private void SetupRepository(List returnedList) + { + _mockRepository.Setup(x => x.TimelineRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, + IIncludableQueryable>>())) + .ReturnsAsync(returnedList); + } + + private void SetupMapper(List returnedList) + { + _mockMapper + .Setup(x => x + .Map>(It.IsAny>())) + .Returns(returnedList); + } } } diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Toponyms/GetAllToponymsTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Toponyms/GetAllToponymsTest.cs new file mode 100644 index 000000000..c9c17f9bc --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Toponyms/GetAllToponymsTest.cs @@ -0,0 +1,144 @@ +using AutoMapper; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.DTO.Toponyms; +using Streetcode.BLL.MediatR.Toponyms.GetAll; +using Streetcode.DAL.Entities.Toponyms; +using Streetcode.DAL.Helpers; +using Streetcode.DAL.Repositories.Interfaces.Base; +using System.Linq.Expressions; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Toponyms +{ + public class GetAllToponymsTest + { + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + + public GetAllToponymsTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + } + + [Fact] + public async Task ReturnsSuccessfully_CorrectType() + { + // Arrange + this.SetupPaginatedRepository(GetToponymList()); + this.SetupMapper(GetListToponymDTO()); + + var handler = new GetAllToponymsHandler(this._mockRepository.Object, this._mockMapper.Object); + + // Act + var result = await handler.Handle(new GetAllToponymsQuery(new GetAllToponymsRequestDTO()), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.NotNull(result), + () => Assert.IsType(result.Value)); + } + + [Fact] + public async Task ReturnsSuccessfully_CountMatch() + { + // Arrange + this.SetupPaginatedRepository(GetToponymList()); + this.SetupMapper(GetListToponymDTO()); + + var handler = new GetAllToponymsHandler(this._mockRepository.Object, this._mockMapper.Object); + + // Act + var result = await handler.Handle(new GetAllToponymsQuery(new GetAllToponymsRequestDTO()), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.NotNull(result), + () => Assert.Equal(GetToponymList().Count(), result.Value.Toponyms.Count())); + } + + [Fact] + public async Task Handler_Returns_Correct_PageSize() + { + // Arrange + ushort pageSize = 1; + this.SetupPaginatedRepository(GetToponymList().Take(pageSize)); + this.SetupMapper(GetListToponymDTO().Take(pageSize)); + + var handler = new GetAllToponymsHandler(this._mockRepository.Object, this._mockMapper.Object); + + // Act + var result = await handler.Handle(new GetAllToponymsQuery(new GetAllToponymsRequestDTO { Amount = pageSize }), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.NotNull(result), + () => Assert.IsType(result.Value), + () => Assert.Equal(pageSize, result.Value.Toponyms.Count())); + } + + [Fact] + public async Task ReturnsEmptyResponse_EmptyToponymList() + { + // Arrange + this.SetupPaginatedRepository(new List()); + this.SetupMapper(new List()); + var handler = new GetAllToponymsHandler(_mockRepository.Object, _mockMapper.Object); + + // Act + var result = await handler.Handle(new GetAllToponymsQuery(new GetAllToponymsRequestDTO()), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.NotNull(result), + () => Assert.Empty(result.Value.Toponyms)); + } + + private static IEnumerable GetToponymList() + { + var toponyms = new List + { + new () { Id = 1 }, + new () { Id = 2 }, + new () { Id = 3 }, + }; + + return toponyms; + } + + private static List GetListToponymDTO() + { + var toponymsDTO = new List + { + new () { Id = 1 }, + new () { Id = 2 }, + new () { Id = 3 }, + }; + + return toponymsDTO; + } + + private void SetupPaginatedRepository(IEnumerable returnList) + { + _mockRepository + .Setup(repo => repo.ToponymRepository.GetAllPaginated( + It.IsAny(), + It.IsAny(), + It.IsAny>?>(), + It.IsAny>?>(), + It.IsAny, IIncludableQueryable>?>(), + It.IsAny>?>(), + It.IsAny>?>())) + .Returns(PaginationResponse.Create(returnList.AsQueryable())); + } + + private void SetupMapper(IEnumerable returnList) + { + _mockMapper + .Setup(x => x.Map>( + It.IsAny>())) + .Returns(returnList); + } + } +} diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Toponyms/GetToponymByIdTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Toponyms/GetToponymByIdTest.cs new file mode 100644 index 000000000..89308fb42 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Toponyms/GetToponymByIdTest.cs @@ -0,0 +1,121 @@ +using System.Linq.Expressions; +using AutoMapper; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.Extensions.Localization; +using Moq; +using Streetcode.BLL.DTO.Toponyms; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Toponyms.GetById; +using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Entities.Toponyms; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Toponyms +{ + public class GetToponymByIdTest + { + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly Mock> _mockLocalizerCannotFind; + + public GetToponymByIdTest() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockLocalizerCannotFind = new Mock>(); + } + + [Fact] + public async Task GetById_ReturnsSuccess() + { + // Arrange + var testToponym = GetToponym(); + var testToponymDTO = GetToponymDTO(); + + this.SetupRepository(testToponym); + this.SetupMapper(testToponymDTO); + + var handler = new GetToponymByIdHandler(this._mockRepository.Object, this._mockMapper.Object, this._mockLogger.Object, this._mockLocalizerCannotFind.Object); + + // Act + var result = await handler.Handle(new GetToponymByIdQuery(testToponym.Id), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.NotNull(result), + () => Assert.True(result.IsSuccess), + () => Assert.IsType(result.Value), + () => Assert.Equal(result.Value.Id, testToponym.Id)); + } + + [Fact] + public async Task GetByIdIncorrect_ReturnsError() + { + // Arrange + var incorrectId = -1; + var expectedError = $"Cannot find any toponym with corresponding id: {incorrectId}"; + + this.SetupRepository(null); + this.SetupLocalizer(incorrectId); + + var handler = new GetToponymByIdHandler(this._mockRepository.Object, this._mockMapper.Object, this._mockLogger.Object, this._mockLocalizerCannotFind.Object); + + // Act + var result = await handler.Handle(new GetToponymByIdQuery(incorrectId), CancellationToken.None); + + // Assert + Assert.Multiple( + () => Assert.True(result.IsFailed), + () => Assert.Equal(expectedError, result.Errors[0].Message)); + } + + private static Toponym GetToponym() + { + return new Toponym + { + Id = 1, + }; + } + + private static ToponymDTO GetToponymDTO() + { + return new ToponymDTO + { + Id = 1, + }; + } + + private void SetupRepository(Toponym? returnValue) + { + this._mockRepository.Setup(x => x.ToponymRepository + .GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, + IIncludableQueryable>>())) + .ReturnsAsync(returnValue); + } + + private void SetupMapper(ToponymDTO returnValue) + { + this._mockMapper + .Setup(x => x.Map(It.IsAny())) + .Returns(returnValue); + } + + private void SetupLocalizer(int incorrectId) + { + this._mockLocalizerCannotFind.Setup(x => x[It.IsAny(), It.IsAny()]).Returns((string key, object[] args) => + { + if (args != null && args.Length > 0 && args[0] is int) + { + return new LocalizedString(key, $"Cannot find any toponym with corresponding id: {incorrectId}"); + } + + return new LocalizedString(key, "Cannot find any toponym with unknown id"); + }); + } + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Toponyms/GetToponymsByStreetcodeIdTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Toponyms/GetToponymsByStreetcodeIdTest.cs index 57299f2e3..467ab55c5 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Toponyms/GetToponymsByStreetcodeIdTest.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Toponyms/GetToponymsByStreetcodeIdTest.cs @@ -18,35 +18,35 @@ namespace Streetcode.XUnitTest.MediatRTests.Toponyms [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1413:UseTrailingCommasInMultiLineInitializers", Justification = "Reviewed.")] public class GetToponymsByStreetcodeIdTest { - private readonly Mock mockRepository; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotFind; + private readonly Mock _mockRepository; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly Mock> _mockLocalizerNo; public GetToponymsByStreetcodeIdTest() { - mockRepository = new Mock(); - mockMapper = new Mock(); - mockLogger = new Mock(); - mockLocalizerCannotFind = new Mock>(); + _mockRepository = new Mock(); + _mockMapper = new Mock(); + _mockLogger = new Mock(); + _mockLocalizerNo = new Mock>(); } [Fact] public async Task ReturnsSuccessfully_NotEmpty() { // Arrange - this.mockRepository.Setup(x => x.ToponymRepository.GetAllAsync( + this._mockRepository.Setup(x => x.ToponymRepository.GetAllAsync( It.IsAny>>(), It.IsAny, - IIncludableQueryable>>() - )).ReturnsAsync(GetExistingToponymList()); + IIncludableQueryable>>())) + .ReturnsAsync(GetExistingToponymList()); - this.mockMapper.Setup(x => x + this._mockMapper.Setup(x => x .Map>(It.IsAny>())) .Returns(GetToponymDTOList()); int streetcodeId = 1; - var handler = new GetToponymsByStreetcodeIdHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + var handler = new GetToponymsByStreetcodeIdHandler(this._mockRepository.Object, this._mockMapper.Object, this._mockLogger.Object, this._mockLocalizerNo.Object); // Act var result = await handler.Handle(new GetToponymsByStreetcodeIdQuery(streetcodeId), CancellationToken.None); @@ -62,14 +62,26 @@ public async Task ReturnsSuccessfully_NotEmpty() public async Task ReturnsSuccessfully_Empty() { // Arrange - this.mockRepository.Setup(x => x.ToponymRepository.GetAllAsync( + this._mockRepository.Setup(x => x.ToponymRepository.GetAllAsync( It.IsAny>>(), It.IsAny, - IIncludableQueryable>>() - )).ReturnsAsync(GetEmptyToponymList()); + IIncludableQueryable>>())) + .ReturnsAsync(GetEmptyToponymList()); int streetcodeId = 1; - var handler = new GetToponymsByStreetcodeIdHandler(this.mockRepository.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + + this._mockLocalizerNo.Setup(x => x[It.IsAny(), It.IsAny()]) + .Returns((string key, object[] args) => + { + if (args != null && args.Length > 0 && args[0] is int id) + { + return new LocalizedString(key, $"No toponym with such streetcode id: {id}"); + } + + return new LocalizedString(key, "Cannot find any toponym with unknown id"); + }); + + var handler = new GetToponymsByStreetcodeIdHandler(this._mockRepository.Object, this._mockMapper.Object, this._mockLogger.Object, this._mockLocalizerNo.Object); // Act var result = await handler.Handle(new GetToponymsByStreetcodeIdQuery(streetcodeId), CancellationToken.None); @@ -81,10 +93,11 @@ public async Task ReturnsSuccessfully_Empty() () => Assert.Empty(result.Value)); } - public static List GetExistingToponymList() + private static List GetExistingToponymList() { - return new List() { - new Toponym + return new List() + { + new () { Id = 1, Oblast = "Test oblast", @@ -93,9 +106,11 @@ public static List GetExistingToponymList() }; } - public static List GetToponymDTOList() { - return new List { - new ToponymDTO + private static List GetToponymDTOList() + { + return new List + { + new () { Id = 1, Oblast = "Test oblast", @@ -103,7 +118,8 @@ public static List GetToponymDTOList() { } }; } - public static List GetEmptyToponymList() + + private static List GetEmptyToponymList() { return new List(); } diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Transactions/TransactionsTests/TransactionLinkTests/GetAllTransactLinksHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Transactions/TransactionsTests/TransactionLinkTests/GetAllTransactLinksHandlerTests.cs index 069d39488..1aff39389 100644 --- a/Streetcode/Streetcode.XUnitTest/MediatRTests/Transactions/TransactionsTests/TransactionLinkTests/GetAllTransactLinksHandlerTests.cs +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Transactions/TransactionsTests/TransactionLinkTests/GetAllTransactLinksHandlerTests.cs @@ -16,21 +16,21 @@ namespace Streetcode.XUnitTest.MediatRTests.Transactions.TransactionsTests.Trans { public class GetAllTransactLinksHandlerTests { - private readonly Mock mockRepo; - private readonly Mock mockMapper; - private readonly Mock mockLogger; - private readonly Mock> mockLocalizerCannotFind; + private readonly Mock _mockRepo; + private readonly Mock _mockMapper; + private readonly Mock _mockLogger; + private readonly Mock> _mockLocalizerCannotFind; - private readonly List transactions = new List() + private readonly List _transactions = new() { - new TransactionLink + new () { Id = 1, Url = "URL", UrlTitle = "Title", StreetcodeId = 1, }, - new TransactionLink + new () { Id = 2, Url = "URL2", @@ -39,16 +39,16 @@ public class GetAllTransactLinksHandlerTests }, }; - private readonly List transactionsDTOs = new List() + private readonly List _transactionsDTOs = new() { - new TransactLinkDTO + new () { Id = 1, Url = "URL", QrCodeUrl = "URL", StreetcodeId = 1, }, - new TransactLinkDTO + new () { Id = 2, Url = "URL2", @@ -59,20 +59,20 @@ public class GetAllTransactLinksHandlerTests public GetAllTransactLinksHandlerTests() { - this.mockMapper = new Mock(); - this.mockRepo = new Mock(); - this.mockLogger = new Mock(); - this.mockLocalizerCannotFind = new Mock>(); + _mockMapper = new Mock(); + _mockRepo = new Mock(); + _mockLogger = new Mock(); + _mockLocalizerCannotFind = new Mock>(); } [Fact] public async Task NotEmpty_List() { // Arrange - this.SetupRepository(this.transactions); - this.SetupMapper(this.transactionsDTOs); + this.SetupRepository(_transactions); + this.SetupMapper(_transactionsDTOs); - var handler = new GetAllTransactLinksHandler(this.mockRepo.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + var handler = new GetAllTransactLinksHandler(_mockRepo.Object, _mockMapper.Object, _mockLogger.Object, _mockLocalizerCannotFind.Object); // Act var result = await handler.Handle(new GetAllTransactLinksQuery(), CancellationToken.None); @@ -80,7 +80,7 @@ public async Task NotEmpty_List() // Assert Assert.Multiple( () => Assert.IsType>(result.Value), - () => Assert.True(result.Value.Count() == this.transactions.Count)); + () => Assert.True(result.Value.Count() == _transactions.Count)); } [Fact] @@ -91,10 +91,10 @@ public async Task Error() this.SetupMapper(new List()); var expectedError = $"Cannot find any transaction link"; - this.mockLocalizerCannotFind.Setup(localizer => localizer["CannotFindAnyTransactionLink"]) + _mockLocalizerCannotFind.Setup(localizer => localizer["CannotFindAnyTransactionLink"]) .Returns(new LocalizedString("CannotFindAnyTransactionLink", expectedError)); - var handler = new GetAllTransactLinksHandler(this.mockRepo.Object, this.mockMapper.Object, this.mockLogger.Object, this.mockLocalizerCannotFind.Object); + var handler = new GetAllTransactLinksHandler(_mockRepo.Object, _mockMapper.Object, _mockLogger.Object, _mockLocalizerCannotFind.Object); // Act var result = await handler.Handle(new GetAllTransactLinksQuery(), CancellationToken.None); @@ -103,16 +103,21 @@ public async Task Error() Assert.Equal(expectedError, result.Errors.Single().Message); } - private void SetupRepository(List returnList) + private void SetupRepository(List? returnList) { - this.mockRepo.Setup(repo => repo.TransactLinksRepository.GetAllAsync( - It.IsAny>>(), It.IsAny, - IIncludableQueryable>>())).ReturnsAsync(returnList); + _mockRepo + .Setup(repo => repo.TransactLinksRepository.GetAllAsync( + It.IsAny>>(), It.IsAny, + IIncludableQueryable>>())) + .ReturnsAsync(returnList!); } private void SetupMapper(List returnList) { - this.mockMapper.Setup(x => x.Map>(It.IsAny>())).Returns(returnList); + _mockMapper + .Setup(x => x.Map>( + It.IsAny>())) + .Returns(returnList); } } } \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/DeleteUserHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/DeleteUserHandlerTests.cs new file mode 100644 index 000000000..2630a0d99 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/DeleteUserHandlerTests.cs @@ -0,0 +1,128 @@ +using System.Security.Claims; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Localization; +using Moq; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Users.Delete; +using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Entities.Users; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Users; + +public class DeleteUserHandlerTests +{ + private readonly Mock _repositoryWrapperMock; + private readonly Mock _loggerMock; + private readonly Mock> _userManagerMock; + private readonly Mock _httpContextAccessorMock; + private readonly Mock> _localizerMock; + private readonly DeleteUserHandler _handler; + + public DeleteUserHandlerTests() + { + _repositoryWrapperMock = new Mock(); + _loggerMock = new Mock(); + _localizerMock = new Mock>(); + _httpContextAccessorMock = new Mock(); + var userStoreMock = new Mock>(); + _userManagerMock = new Mock>( + userStoreMock.Object, null, null, null, null, null, null, null, null); + + var claims = new List + { + new (ClaimTypes.Email, "user@example.com"), + }; + + var identity = new ClaimsIdentity(claims, "TestAuthType"); + var claimsPrincipal = new ClaimsPrincipal(identity); + var context = new DefaultHttpContext { User = claimsPrincipal }; + + _httpContextAccessorMock.Setup(_ => _.HttpContext).Returns(context); + + _handler = new DeleteUserHandler( + _repositoryWrapperMock.Object, + _loggerMock.Object, + _userManagerMock.Object, + _httpContextAccessorMock.Object, + _localizerMock.Object); + } + + [Fact] + public async Task Handle_ValidUserDeletion_ReturnsSuccess() + { + // Arrange + var cancellationToken = CancellationToken.None; + var testEmail = "user@example.com"; + var user = new User { Email = testEmail }; + + var request = new DeleteUserCommand(testEmail); + + _userManagerMock.Setup(um => um.FindByEmailAsync(testEmail)) + .ReturnsAsync(user); + + _repositoryWrapperMock.Setup(r => r.UserRepository.Delete(user)); + _repositoryWrapperMock.Setup(r => r.SaveChangesAsync()).ReturnsAsync(1); + + // Act + var result = await _handler.Handle(request, cancellationToken); + + // Assert + Assert.True(result.IsSuccess); + } + + [Fact] + public async Task Handle_UserNotFound_ReturnsFailure() + { + // Arrange + var cancellationToken = CancellationToken.None; + var request = new DeleteUserCommand("user@example.com"); + + _userManagerMock.Setup(um => um.FindByEmailAsync("user@example.com")) + .ReturnsAsync((User)null!); + + // Act + var result = await _handler.Handle(request, cancellationToken); + + // Assert + Assert.False(result.IsSuccess); + } + + [Fact] + public async Task Handle_EmailMismatch_ReturnsFailure() + { + // Arrange + var cancellationToken = CancellationToken.None; + var request = new DeleteUserCommand("different@example.com"); + + var user = new User { Email = "user@example.com" }; + + _userManagerMock.Setup(um => um.FindByEmailAsync("user@example.com")) + .ReturnsAsync(user); + + // Act + var result = await _handler.Handle(request, cancellationToken); + + // Assert + Assert.False(result.IsSuccess); + } + + [Fact] + public async Task Handle_ExceptionThrown_ReturnsFailure() + { + // Arrange + var cancellationToken = CancellationToken.None; + var request = new DeleteUserCommand("user@example.com"); + + _userManagerMock.Setup(um => um.FindByEmailAsync("user@example.com")) + .ThrowsAsync(new Exception("Database connection failed")); + + // Act + var result = await _handler.Handle(request, cancellationToken); + + // Assert + Assert.False(result.IsSuccess); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/ExistWithUserNameHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/ExistWithUserNameHandlerTests.cs new file mode 100644 index 000000000..acc194456 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/ExistWithUserNameHandlerTests.cs @@ -0,0 +1,57 @@ +using System.Linq.Expressions; +using Moq; +using Streetcode.BLL.MediatR.Users.ExistWithUserName; +using Streetcode.DAL.Entities.Users; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Users; + +public class ExistWithUserNameHandlerTests +{ + private readonly Mock _repositoryWrapperMock; + private readonly ExistWithUserNameHandler _handler; + + public ExistWithUserNameHandlerTests() + { + _repositoryWrapperMock = new Mock(); + _handler = new ExistWithUserNameHandler(_repositoryWrapperMock.Object); + } + + [Fact] + public async Task Handle_UserExists_ReturnsTrue() + { + // Arrange + var userName = "testUser"; + var user = new User { UserName = userName }; + + _repositoryWrapperMock.Setup(repo => repo.UserRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), null)) + .ReturnsAsync(user); + + // Act + var result = await _handler.Handle(new ExistWithUserNameQuery(userName), CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + Assert.True(result.Value); + } + + [Fact] + public async Task Handle_UserDoesNotExist_ReturnsFalse() + { + // Arrange + var userName = "nonExistentUser"; + + _repositoryWrapperMock.Setup(repo => repo.UserRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), null)) + .ReturnsAsync((User)null!); + + // Act + var result = await _handler.Handle(new ExistWithUserNameQuery(userName), CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + Assert.False(result.Value); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/ForgotPasswordTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/ForgotPasswordTests.cs new file mode 100644 index 000000000..a2892e6b5 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/ForgotPasswordTests.cs @@ -0,0 +1,164 @@ +using MediatR; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Localization; +using Moq; +using Streetcode.BLL.DTO.Users.Password; +using Streetcode.BLL.Factories.MessageDataFactory.Abstracts; +using Streetcode.BLL.Interfaces.Email; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Email; +using Streetcode.BLL.MediatR.Users.ForgotPassword; +using Streetcode.BLL.Models.Email.Messages.Base; +using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Entities.Users; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Users +{ + public class ForgotPasswordTests + { + private readonly Mock> _userManagerMock; + private readonly Mock _emailServiceMock; + private readonly Mock> _localizerUserSharedResourceMock; + private readonly Mock _httpContextAccessorMock; + private readonly Mock _messageFactoryMock; + private readonly Mock _loggerMock; + private readonly Mock> _emailLocalizerMock; + + private readonly ForgotPasswordHandler _handler; + + public ForgotPasswordTests() + { + _userManagerMock = new Mock>( + Mock.Of>(), null, null, null, null, null, null, null, null); + + _emailServiceMock = new Mock(); + _localizerUserSharedResourceMock = new Mock>(); + _httpContextAccessorMock = new Mock(); + _messageFactoryMock = new Mock(); + _loggerMock = new Mock(); + _emailLocalizerMock = new Mock>(); + + _handler = new ForgotPasswordHandler( + _loggerMock.Object, + _userManagerMock.Object, + _emailServiceMock.Object, + _localizerUserSharedResourceMock.Object, + _httpContextAccessorMock.Object, + _messageFactoryMock.Object, + _emailLocalizerMock.Object); + } + + [Fact] + public async Task Handle_ShouldReturnFail_WhenUserDoesNotExist() + { + // Arrange + var request = new ForgotPasswordCommand(new ForgotPasswordDTO { Email = "nonexistent@example.com" }); + + _userManagerMock.Setup(um => um.FindByEmailAsync(It.IsAny())) + .ReturnsAsync((User)null!); + + _localizerUserSharedResourceMock.Setup(l => l["UserWithSuchEmailNotFound"]) + .Returns(new LocalizedString("UserWithSuchEmailNotFound", "User not found")); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsFailed); + Assert.Contains("User not found", result.Errors[0].Message); + _loggerMock.Verify(l => l.LogError(request, "User not found"), Times.Once); + } + + [Fact] + public async Task Handle_ShouldReturnSuccess_WhenEmailSentSuccessfully() + { + // Arrange + var user = new User { UserName = "TestUser", Email = "test@example.com" }; + var request = new ForgotPasswordCommand(new ForgotPasswordDTO { Email = "test@example.com" }); + + SetupUserManagerMock(user); + SetupMessageFactoryMock(); + SetupEmailServiceMock(true); + + _httpContextAccessorMock.Setup(h => h.HttpContext).Returns(new DefaultHttpContext()); + + _userManagerMock.Setup(um => um.FindByEmailAsync(request.ForgotPasswordDto.Email)) + .ReturnsAsync(user); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + Assert.Equal(Unit.Value, result.Value); + } + + [Fact] + public async Task Handle_ShouldReturnFail_WhenEmailSendingFails() + { + // Arrange + var user = new User { UserName = "TestUser", Email = "test@example.com" }; + var request = new ForgotPasswordCommand(new ForgotPasswordDTO { Email = "test@example.com" }); + + SetupUserManagerMock(user); + SetupMessageFactoryMock(); + SetupEmailServiceMock(false); + + _emailLocalizerMock.Setup(l => l["FailedToSendEmailMessage"]) + .Returns(new LocalizedString("FailedToSendEmailMessage", "Failed to send email")); + + _userManagerMock.Setup(um => um.FindByEmailAsync(request.ForgotPasswordDto.Email)) + .ReturnsAsync(user); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsFailed); + Assert.Contains("Failed to send email", result.Errors[0].Message); + _loggerMock.Verify(l => l.LogError(request, "Failed to send email"), Times.Once); + } + + [Fact] + public async Task Handle_ShouldReturnFail_WhenExceptionIsThrown() + { + // Arrange + var request = new ForgotPasswordCommand(new ForgotPasswordDTO { Email = "test@example.com" }); + + _userManagerMock.Setup(um => um.FindByEmailAsync(It.IsAny())) + .ThrowsAsync(new Exception("Database error")); + + // Act + var result = await _handler.Handle(request, CancellationToken.None); + + // Assert + Assert.True(result.IsFailed); + Assert.Contains("Database error", result.Errors[0].Message); + _loggerMock.Verify(l => l.LogError(request, "Database error"), Times.Once); + } + + private void SetupMessageFactoryMock() + { + _messageFactoryMock.Setup(mf => mf.CreateForgotPasswordMessageData( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns(new Mock().Object); + } + + private void SetupUserManagerMock(User user) + { + _userManagerMock.Setup(um => um.GeneratePasswordResetTokenAsync(user)) + .ReturnsAsync("mocked-token"); + } + + private void SetupEmailServiceMock(bool isSuccess) + { + _emailServiceMock.Setup(es => es.SendEmailAsync(It.IsAny())) + .ReturnsAsync(isSuccess); + } + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/GetByEmailHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/GetByEmailHandlerTests.cs new file mode 100644 index 000000000..cf28a6e08 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/GetByEmailHandlerTests.cs @@ -0,0 +1,113 @@ +using System.Linq.Expressions; +using System.Security.Claims; +using AutoMapper; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore.Query; +using Moq; +using Streetcode.BLL.DTO.Users; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Users.GetByEmail; +using Streetcode.DAL.Entities.Users; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Users; + +public class GetByEmailHandlerTests +{ + private readonly Mock> _userManagerMock; + private readonly Mock _httpContextAccessorMock; + private readonly Mock _repositoryWrapperMock; + private readonly Mock _mapperMock; + private readonly MockUserSharedResourceLocalizer _localizerMock; + private readonly Mock _loggerMock; + private readonly GetByEmailHandler _handler; + + public GetByEmailHandlerTests() + { + var userStoreMock = new Mock>(); + _userManagerMock = new Mock>( + userStoreMock.Object, null, null, null, null, null, null, null, null); + + _httpContextAccessorMock = new Mock(); + _repositoryWrapperMock = new Mock(); + _mapperMock = new Mock(); + _localizerMock = new MockUserSharedResourceLocalizer(); + _loggerMock = new Mock(); + + var fakeEmail = "test@example.com"; + var claims = new List + { + new (ClaimTypes.Email, fakeEmail), + }; + + var identity = new ClaimsIdentity(claims, "TestAuthType"); + var claimsPrincipal = new ClaimsPrincipal(identity); + var context = new DefaultHttpContext { User = claimsPrincipal }; + + _httpContextAccessorMock.Setup(_ => _.HttpContext).Returns(context); + + _handler = new GetByEmailHandler( + _mapperMock.Object, + _repositoryWrapperMock.Object, + _loggerMock.Object, + _userManagerMock.Object, + _httpContextAccessorMock.Object, + _localizerMock); + } + + [Fact] + public async Task Handle_ValidEmail_ReturnsSuccessWithUser() + { + // Arrange + var cancellationToken = CancellationToken.None; + var userEmail = "test@example.com"; + var user = new User + { + Email = userEmail, + Id = "123", + }; + var userDto = new UserDTO + { + Email = userEmail, + Role = "Admin", + }; + + _repositoryWrapperMock.Setup(repo => repo.UserRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(user); + + _mapperMock.Setup(m => m.Map(It.IsAny())).Returns(userDto); + _userManagerMock.Setup(um => um.GetRolesAsync(user)).ReturnsAsync(new List { "Admin" }); + + // Act + var result = await _handler.Handle(new GetByEmailQuery(), cancellationToken); + + // Assert + Assert.True(result.IsSuccess); + Assert.NotNull(result.Value); + Assert.Equal(userEmail, result.Value.Email); + Assert.Equal("Admin", result.Value.Role); + } + + [Fact] + public async Task Handle_UserDoesNotExist_ReturnsFailure() + { + // Arrange + var cancellationToken = CancellationToken.None; + + _repositoryWrapperMock.Setup(repo => repo.UserRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync((User)null!); + + // Act + var result = await _handler.Handle(new GetByEmailQuery(), cancellationToken); + + // Assert + Assert.False(result.IsSuccess); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/GetOtherUserByUserNameHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/GetOtherUserByUserNameHandlerTests.cs new file mode 100644 index 000000000..b7c6a3a19 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/GetOtherUserByUserNameHandlerTests.cs @@ -0,0 +1,91 @@ +using System.Linq.Expressions; +using AutoMapper; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.Extensions.Localization; +using Moq; +using Streetcode.BLL.DTO.Users; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Users.GetOtherUserByUserName; +using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Entities.Users; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Users; + +public class GetOtherUserByUserNameHandlerTests +{ + private readonly Mock _repositoryWrapperMock; + private readonly Mock _mapperMock; + private readonly Mock _loggerMock; + private readonly Mock> _localizerUserSharedResourceMock; + private readonly Mock> _userManagerMock; + private readonly GetOtherUserByUserNameHandler _handler; + + public GetOtherUserByUserNameHandlerTests() + { + _repositoryWrapperMock = new Mock(); + _mapperMock = new Mock(); + _loggerMock = new Mock(); + _localizerUserSharedResourceMock = new Mock>(); + + var userStoreMock = new Mock>(); + _userManagerMock = new Mock>(userStoreMock.Object, null, null, null, null, null, null, null, null); + + _handler = new GetOtherUserByUserNameHandler( + _mapperMock.Object, + _repositoryWrapperMock.Object, + _loggerMock.Object, + _userManagerMock.Object, + _localizerUserSharedResourceMock.Object); + } + + [Fact] + public async Task Handle_UserExists_ReturnsUserProfileDTO() + { + // Arrange + var cancellationToken = CancellationToken.None; + var userName = "testUser"; + var user = new User { UserName = userName, Id = "123" }; + var userProfileDto = new UserProfileDTO { UserName = userName, Role = "Admin" }; + + _repositoryWrapperMock.Setup(repo => repo.UserRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(user); + + _mapperMock.Setup(m => m.Map(It.IsAny())).Returns(userProfileDto); + _userManagerMock.Setup(um => um.GetRolesAsync(user)).ReturnsAsync(new List { "Admin" }); + + // Act + var result = await _handler.Handle(new GetOtherUserByUserNameQuery(userName), cancellationToken); + + // Assert + Assert.True(result.IsSuccess); + Assert.NotNull(result.Value); + Assert.Equal(userName, result.Value.UserName); + Assert.Equal("Admin", result.Value.Role); + } + + [Fact] + public async Task Handle_UserDoesNotExist_ReturnsFailure() + { + // Arrange + var cancellationToken = CancellationToken.None; + var userName = "nonExistentUser"; + + _repositoryWrapperMock.Setup(repo => repo.UserRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync((User)null!); + + _localizerUserSharedResourceMock.Setup(l => l["UserWithSuchUsernameNotExists"]).Returns(new LocalizedString("UserWithSuchUsernameNotExists", "User does not exist")); + + // Act + var result = await _handler.Handle(new GetOtherUserByUserNameQuery(userName), cancellationToken); + + // Assert + Assert.False(result.IsSuccess); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/UpdateForgotPasswordHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/UpdateForgotPasswordHandlerTests.cs new file mode 100644 index 000000000..2f57414f0 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/UpdateForgotPasswordHandlerTests.cs @@ -0,0 +1,148 @@ +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Localization; +using Moq; +using Streetcode.BLL.DTO.Users.Password; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Users.UpdateForgotPassword; +using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Entities.Users; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Users; + +public class UpdateForgotPasswordHandlerTests +{ + private readonly Mock _loggerMock; + private readonly Mock> _userManagerMock; + private readonly Mock> _localizerMock; + private readonly UpdateForgotPasswordHandler _handler; + + public UpdateForgotPasswordHandlerTests() + { + _loggerMock = new Mock(); + _localizerMock = new Mock>(); + + var userStoreMock = new Mock>(); + _userManagerMock = new Mock>( + userStoreMock.Object, null, null, null, null, null, null, null, null); + + _handler = new UpdateForgotPasswordHandler( + _loggerMock.Object, + _userManagerMock.Object, + _localizerMock.Object); + } + + [Fact] + public async Task Handle_ValidRequest_ReturnsSuccess() + { + // Arrange + var cancellationToken = CancellationToken.None; + var request = new UpdateForgotPasswordCommand(new UpdateForgotPasswordDTO + { + Username = Uri.EscapeDataString("testUser"), + Token = Uri.EscapeDataString("validToken"), + Password = "NewSecurePassword123!", + }); + + var user = new User { UserName = "testUser", Id = "123" }; + + _userManagerMock.Setup(um => um.FindByNameAsync("testUser")).ReturnsAsync(user); + _userManagerMock.Setup(um => um.ResetPasswordAsync(user, "validToken", request.UpdateForgotPasswordDto.Password)) + .ReturnsAsync(IdentityResult.Success); + + // Act + var result = await _handler.Handle(request, cancellationToken); + + // Assert + Assert.True(result.IsSuccess); + } + + [Fact] + public async Task Handle_UserNotFound_ReturnsFailure() + { + // Arrange + var cancellationToken = CancellationToken.None; + var request = new UpdateForgotPasswordCommand(new UpdateForgotPasswordDTO + { + Username = Uri.EscapeDataString("nonExistentUser"), + Token = Uri.EscapeDataString("validToken"), + Password = "NewSecurePassword123!", + }); + + _userManagerMock.Setup(um => um.FindByNameAsync("nonExistentUser")).ReturnsAsync((User)null!); + + _localizerMock.Setup(l => l["UserWithSuchUsernameNotExists"]) + .Returns(new LocalizedString("UserWithSuchUsernameNotExists", "User does not exist")); + + // Act + var result = await _handler.Handle(request, cancellationToken); + + // Assert + Assert.False(result.IsSuccess); + } + + [Fact] + public async Task Handle_InvalidPasswordReset_ReturnsErrors() + { + // Arrange + var cancellationToken = CancellationToken.None; + var request = new UpdateForgotPasswordCommand(new UpdateForgotPasswordDTO + { + Username = Uri.EscapeDataString("testUser"), + Token = Uri.EscapeDataString("validToken"), + Password = "weak", + }); + + var user = new User { UserName = "testUser", Id = "123" }; + + _userManagerMock.Setup(um => um.FindByNameAsync("testUser")).ReturnsAsync(user); + _userManagerMock.Setup(um => um.ResetPasswordAsync(user, "validToken", request.UpdateForgotPasswordDto.Password)) + .ReturnsAsync(IdentityResult.Failed(new IdentityError { Description = "Password too weak" })); + + // Act + var result = await _handler.Handle(request, cancellationToken); + + // Assert + Assert.False(result.IsSuccess); + } + + [Fact] + public async Task Handle_ExceptionThrown_ReturnsFailure() + { + // Arrange + var cancellationToken = CancellationToken.None; + var request = new UpdateForgotPasswordCommand(new UpdateForgotPasswordDTO + { + Username = Uri.EscapeDataString("testUser"), + Token = Uri.EscapeDataString("validToken"), + Password = "NewSecurePassword123!", + }); + + _userManagerMock.Setup(um => um.FindByNameAsync("testUser")).ThrowsAsync(new Exception("Database connection failed")); + + // Act + var result = await _handler.Handle(request, cancellationToken); + + // Assert + Assert.False(result.IsSuccess); + } + + [Fact] + public async Task Handle_UserNameOrTokenIsNull_ReturnsFailure() + { + // Arrange + var cancellationToken = CancellationToken.None; + var request = new UpdateForgotPasswordCommand(new UpdateForgotPasswordDTO + { + Username = string.Empty, + Token = string.Empty, + Password = "NewSecurePassword123!", + }); + + // Act + var result = await _handler.Handle(request, cancellationToken); + + // Assert + Assert.False(result.IsSuccess); + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/UpdateUserTest.cs b/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/UpdateUserTest.cs new file mode 100644 index 000000000..33d6498a5 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/MediatRTests/Users/UpdateUserTest.cs @@ -0,0 +1,230 @@ +using System.Linq.Expressions; +using System.Security.Claims; +using AutoMapper; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.Extensions.Localization; +using MockQueryable.Moq; +using Moq; +using Streetcode.BLL.DTO.Users; +using Streetcode.BLL.DTO.Users.Expertise; +using Streetcode.BLL.Interfaces.Logging; +using Streetcode.BLL.MediatR.Users.Update; +using Streetcode.BLL.SharedResource; +using Streetcode.DAL.Entities.Users; +using Streetcode.DAL.Entities.Users.Expertise; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Xunit; + +namespace Streetcode.XUnitTest.MediatRTests.Users; +public class UpdateUserHandlerTests +{ + private readonly Mock _mapperMock; + private readonly Mock _repositoryWrapperMock; + private readonly Mock _loggerMock; + private readonly Mock> _userManagerMock; + private readonly Mock _httpContextAccessorMock; + private readonly Mock> _localizerMock; + private readonly Mock> _userStoreMock; + private readonly UpdateUserHandler _handler; + + public UpdateUserHandlerTests() + { + _mapperMock = new Mock(); + _repositoryWrapperMock = new Mock(); + _loggerMock = new Mock(); + _userStoreMock = new Mock>(); + _localizerMock = new Mock>(); + + _userManagerMock = new Mock>( + _userStoreMock.Object, null, null, null, null, null, null, null, null); + + _httpContextAccessorMock = new Mock(); + + var fakeEmail = "test@example.com"; + var claims = new List + { + new (ClaimTypes.Email, fakeEmail), + }; + + var identity = new ClaimsIdentity(claims, "TestAuthType"); + var claimsPrincipal = new ClaimsPrincipal(identity); + var context = new DefaultHttpContext { User = claimsPrincipal }; + + _httpContextAccessorMock.Setup(_ => _.HttpContext).Returns(context); + + _handler = new UpdateUserHandler( + _mapperMock.Object, + _repositoryWrapperMock.Object, + _loggerMock.Object, + _userManagerMock.Object, + _httpContextAccessorMock.Object, + _localizerMock.Object); + } + + [Fact] + public async Task Handle_ShouldReturnUpdatedUser_WhenValidRequestIsProvided() + { + // Arrange + var existingUser = GetExistingUser(); + + var updateUserCommand = GetUpdateUserCommand(); + + _userManagerMock.Setup(um => um.Users) + .Returns(new List { existingUser }.AsQueryable().BuildMockDbSet().Object); + + _userManagerMock.Setup(um => um.UpdateAsync(It.IsAny())) + .ReturnsAsync(IdentityResult.Success); + + _repositoryWrapperMock.Setup(rw => rw.ExpertiseRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(new List { new () { Id = 2, Title = "New Expertise" } }); + + _userManagerMock.Setup(um => um.GetRolesAsync(It.IsAny())).ReturnsAsync(new List { "Admin" }); + + _mapperMock.Setup(m => m.Map(It.IsAny())) + .Returns(GetUserDto); + + // Act + var result = await _handler.Handle(updateUserCommand, default); + + // Assert + Assert.True(result.IsSuccess); + Assert.Equal("newusername", result.Value.UserName); + Assert.Equal("New Name", result.Value.Name); + Assert.Contains(result.Value.Expertises, e => e.Title == "New Expertise"); + } + + [Fact] + public async Task Handle_ShouldReturnFail_WhenUpdateAsyncFails() + { + // Arrange + var existingUser = GetExistingUser(); + + var updateUserCommand = GetUpdateUserCommand(); + + _userManagerMock.Setup(um => um.Users) + .Returns(new List { existingUser }.AsQueryable().BuildMockDbSet().Object); + + _userManagerMock.Setup(um => um.UpdateAsync(It.IsAny())) + .ReturnsAsync(IdentityResult.Failed(new IdentityError { Description = "Update failed" })); + + _repositoryWrapperMock.Setup(rw => rw.ExpertiseRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(new List { new () { Id = 2, Title = "New Expertise" } }); + + _userManagerMock.Setup(um => um.GetRolesAsync(It.IsAny())).ReturnsAsync(new List { "Admin" }); + + _mapperMock.Setup(m => m.Map(It.IsAny())) + .Returns(GetUserDto); + + // Act + var result = await _handler.Handle(updateUserCommand, default); + + // Assert + Assert.True(result.IsFailed); + Assert.Contains("Update failed", result.Errors[0].ToString()); + } + + [Fact] + public async Task Handle_ShouldReturnError_WhenUserIsNotFound() + { + // Arrange + var updateUserCommand = GetUpdateUserCommand(); + + _userManagerMock.Setup(um => um.Users) + .Returns(new List().AsQueryable().BuildMockDbSet().Object); + + _repositoryWrapperMock.Setup(rw => rw.ExpertiseRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(new List { new () { Id = 2, Title = "New Expertise" } }); + + _mapperMock.Setup(m => m.Map(It.IsAny())) + .Returns(GetUserDto); + + // Act + var result = await _handler.Handle(updateUserCommand, default); + + // Assert + Assert.False(result.IsSuccess); + } + + [Fact] + public async Task Handle_ShouldReturnError_WhenExceptionOccurs() + { + // Arrange + var updateUserCommand = GetUpdateUserCommand(); + + _userManagerMock.Setup(um => um.Users) + .Returns(new List().AsQueryable().BuildMockDbSet().Object); + + _repositoryWrapperMock.Setup(rw => rw.ExpertiseRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(new List { new () { Id = 2, Title = "New Expertise" } }); + + _userManagerMock.Setup(um => um.UpdateAsync(It.IsAny())) + .ThrowsAsync(new Exception("Database fail")); + + _mapperMock.Setup(m => m.Map(It.IsAny())) + .Returns(GetUserDto); + + // Act + var result = await _handler.Handle(updateUserCommand, default); + + // Assert + Assert.False(result.IsSuccess); + } + + private UpdateUserCommand GetUpdateUserCommand() + { + return new UpdateUserCommand( + new UpdateUserDTO + { + UserName = "newusername", + Name = "New Name", + Surname = "New Surname", + AvatarId = 2, + AboutYourself = "About Myself", + PhoneNumber = "1234567890", + Expertises = new List + { + new () { Id = 2, Title = "New Expertise" }, + }, + }); + } + + private User GetExistingUser() + { + return new User + { + Id = Guid.NewGuid().ToString(), + UserName = "oldusername", + Name = "Old Name", + Surname = "Old Surname", + Email = "test@example.com", + Expertises = new List + { + new () { Id = 1, Title = "Old Expertise" }, + }, + }; + } + + private UserDTO GetUserDto(User user) + { + return new UserDTO + { + UserName = user.UserName, + Name = user.Name, + Surname = user.Surname, + AvatarId = user.AvatarId, + AboutYourself = user.AboutYourself, + PhoneNumber = user.PhoneNumber!, + Expertises = user.Expertises.Select(e => new ExpertiseDTO { Id = e.Id, Title = e.Title }).ToList(), + }; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/BaseMockStringLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/BaseMockStringLocalizer.cs index 34045a433..5cebbad03 100644 --- a/Streetcode/Streetcode.XUnitTest/Mocks/BaseMockStringLocalizer.cs +++ b/Streetcode/Streetcode.XUnitTest/Mocks/BaseMockStringLocalizer.cs @@ -13,8 +13,6 @@ protected BaseMockStringLocalizer() _groupedErrors = DefineGroupedErrors(); } - protected abstract Dictionary> DefineGroupedErrors(); - public LocalizedString this[string name] { get @@ -42,6 +40,8 @@ public LocalizedString this[string name] } } + protected abstract Dictionary> DefineGroupedErrors(); + public IEnumerable GetAllStrings(bool includeParentCultures) { return _strings; @@ -49,22 +49,14 @@ public IEnumerable GetAllStrings(bool includeParentCultures) private LocalizedString GetErrorMessage(string error, params object[] arguments) { - string errorMessage = $"Error '{error}'"; - switch (arguments.Length) + if (arguments.Length == 0) { - case 1: - errorMessage += ". Arguments: {0}"; - break; - case 2: - errorMessage += ". Arguments: {0}, {1}"; - break; - case 3: - errorMessage += ". Arguments: {0}, {1}, {2}"; - break; - default: - throw new ArgumentException("Not supported number of arguments"); + return new LocalizedString(error, $"Error '{error}'"); } - return new LocalizedString(error, string.Format(errorMessage, arguments)); + string formattedArguments = string.Join(", ", arguments); + string errorMessage = $"Error '{error}'. Arguments: {formattedArguments}"; + + return new LocalizedString(error, errorMessage); } } diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockAlreadyExistLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockAlreadyExistLocalizer.cs index d64cc9fb0..d65cb1961 100644 --- a/Streetcode/Streetcode.XUnitTest/Mocks/MockAlreadyExistLocalizer.cs +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockAlreadyExistLocalizer.cs @@ -6,14 +6,21 @@ public class MockAlreadyExistLocalizer : BaseMockStringLocalizer> DefineGroupedErrors() { - return new Dictionary> + var groupedErrors = new Dictionary>() { { - 2, new List + 0, new List() + { + "FavouriteAlreadyExists", + } + }, + { + 2, new List() { "PartnerWithFieldAlreadyExist", } }, }; + return groupedErrors; } } \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockAnErrorOccurredLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockAnErrorOccurredLocalizer.cs new file mode 100644 index 000000000..2471ab610 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockAnErrorOccurredLocalizer.cs @@ -0,0 +1,19 @@ +using Streetcode.BLL.SharedResource; + +namespace Streetcode.XUnitTest.Mocks; + +public class MockAnErrorOccurredLocalizer : BaseMockStringLocalizer +{ + protected override Dictionary> DefineGroupedErrors() + { + return new Dictionary> + { + { + 1, new List + { + "AnErrorOccurredWhileCreating", + } + }, + }; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotConvertNullLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotConvertNullLocalizer.cs new file mode 100644 index 000000000..26ec8722c --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotConvertNullLocalizer.cs @@ -0,0 +1,22 @@ +using Streetcode.BLL.SharedResource; + +namespace Streetcode.XUnitTest.Mocks; + +public class MockCannotConvertNullLocalizer : BaseMockStringLocalizer +{ + protected override Dictionary> DefineGroupedErrors() + { + var groupedErrors = new Dictionary>() + { + { + 0, new List() + { + "CannotConvertNullToFact", + "CannotConvertNullToTerm", + } + }, + }; + + return groupedErrors; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotCreateLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotCreateLocalizer.cs new file mode 100644 index 000000000..e6ff6f9bd --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotCreateLocalizer.cs @@ -0,0 +1,23 @@ +using Streetcode.BLL.SharedResource; + +namespace Streetcode.XUnitTest.Mocks; + +public class MockCannotCreateLocalizer : BaseMockStringLocalizer +{ + protected override Dictionary> DefineGroupedErrors() + { + var groupedErrors = new Dictionary>() + { + { + 0, new List() + { + "CannotCreateNewRelatedWordForTerm", + "CannotCreateDTOsForRelatedWords", + "CannotCreateTerm", + } + }, + }; + + return groupedErrors; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotFindLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotFindLocalizer.cs new file mode 100644 index 000000000..f4211fa42 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotFindLocalizer.cs @@ -0,0 +1,46 @@ +using Streetcode.BLL.SharedResource; + +namespace Streetcode.XUnitTest.Mocks; + +public class MockCannotFindLocalizer : BaseMockStringLocalizer +{ + protected override Dictionary> DefineGroupedErrors() + { + var groupedErrors = new Dictionary>() + { + { + 0, new List() + { + "CannotFindAnyFact", + "CannotFindAnyTerm", + "CannotFindAnyText", + "CannotFindStreetcodeInFavourites", + "CannotFindAnyPropertyWithThisName", + "CannotFindStreetcodeById", + "CannotFindRecordWithQrId", + } + }, + { + 1, new List() + { + "CannotFindFactWithCorrespondingCategoryId", + "CannotFindRelatedTermWithCorrespondingId", + "CannotFindAnyTermWithCorrespondingId", + "CannotFindTextWithCorrespondingCategoryId", + "CannotFindAnyTextWithCorrespondingId", + "CannotFindTransactionLinkByStreetcodeIdBecause", + "CannotFindHistoricalContextWithCorrespondingId", + "CannotFindAnyStreetcodeWithCorrespondingId", + } + }, + { + 2, new List() + { + "CannotFindRelationBetweenStreetcodesWithCorrespondingIds", + } + }, + }; + + return groupedErrors; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotGetLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotGetLocalizer.cs new file mode 100644 index 000000000..fa080579d --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotGetLocalizer.cs @@ -0,0 +1,21 @@ +using Streetcode.BLL.SharedResource; + +namespace Streetcode.XUnitTest.Mocks; + +public class MockCannotGetLocalizer : BaseMockStringLocalizer +{ + protected override Dictionary> DefineGroupedErrors() + { + var groupedErrors = new Dictionary>() + { + { + 0, new List() + { + "CannotGetWordsByTermId", + } + }, + }; + + return groupedErrors; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotMapLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotMapLocalizer.cs new file mode 100644 index 000000000..a554fe616 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotMapLocalizer.cs @@ -0,0 +1,22 @@ +using Streetcode.BLL.SharedResource; + +namespace Streetcode.XUnitTest.Mocks; + +public class MockCannotMapLocalizer : BaseMockStringLocalizer +{ + protected override Dictionary> DefineGroupedErrors() + { + var groupedErrors = new Dictionary>() + { + { + 0, new List() + { + "CannotMapEntity", + "CannotMapStreetcodeToShortDTO", + } + }, + }; + + return groupedErrors; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotSaveLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotSaveLocalizer.cs new file mode 100644 index 000000000..992144c42 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockCannotSaveLocalizer.cs @@ -0,0 +1,22 @@ +using Streetcode.BLL.SharedResource; + +namespace Streetcode.XUnitTest.Mocks; + +public class MockCannotSaveLocalizer : BaseMockStringLocalizer +{ + protected override Dictionary> DefineGroupedErrors() + { + var groupedErrors = new Dictionary>() + { + { + 0, new List() + { + "CannotSaveChangesInTheDatabaseAfterRelatedWordCreation", + "CannotSaveTheData", + } + }, + }; + + return groupedErrors; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockCreateRelatedTermLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockCreateRelatedTermLocalizer.cs new file mode 100644 index 000000000..a3a26a4a4 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockCreateRelatedTermLocalizer.cs @@ -0,0 +1,21 @@ +using Streetcode.BLL.MediatR.Streetcode.RelatedTerm.Create; + +namespace Streetcode.XUnitTest.Mocks; + +public class MockCreateRelatedTermLocalizer : BaseMockStringLocalizer +{ + protected override Dictionary> DefineGroupedErrors() + { + var groupedErrors = new Dictionary>() + { + { + 0, new List() + { + "WordWithThisDefinitionAlreadyExists", + } + }, + }; + + return groupedErrors; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToCreateLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToCreateLocalizer.cs new file mode 100644 index 000000000..649718062 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToCreateLocalizer.cs @@ -0,0 +1,27 @@ +using Streetcode.BLL.SharedResource; + +namespace Streetcode.XUnitTest.Mocks; + +public class MockFailedToCreateLocalizer : BaseMockStringLocalizer +{ + protected override Dictionary> DefineGroupedErrors() + { + var groupedErrors = new Dictionary>() + { + { + 0, new List() + { + "FailedToCreateFact", + "FailedToCreateTerm", + "FailedToMapCreatedTerm", + "FailedToCreateTeam", + "FailedToCreateStreetcode", + "TheStreetcodesAreAlreadyLinked", + "FailedToCreateRelation", + } + }, + }; + + return groupedErrors; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToDeleteLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToDeleteLocalizer.cs new file mode 100644 index 000000000..f7b557348 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToDeleteLocalizer.cs @@ -0,0 +1,26 @@ +using Streetcode.BLL.SharedResource; + +namespace Streetcode.XUnitTest.Mocks; + +public class MockFailedToDeleteLocalizer : BaseMockStringLocalizer +{ + protected override Dictionary> DefineGroupedErrors() + { + var groupedErrors = new Dictionary>() + { + { + 0, new List() + { + "FailedToDeleteFact", + "FailedToDeleteRelatedTerm", + "FailedToDeleteTerm", + "FailedToDeleteText", + "FailedToDeleteStreetcode", + "FailedToDeleteRelation", + } + }, + }; + + return groupedErrors; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToUpdateLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToUpdateLocalizer.cs new file mode 100644 index 000000000..a29d131bc --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToUpdateLocalizer.cs @@ -0,0 +1,24 @@ +using Streetcode.BLL.SharedResource; + +namespace Streetcode.XUnitTest.Mocks; + +public class MockFailedToUpdateLocalizer : BaseMockStringLocalizer +{ + protected override Dictionary> DefineGroupedErrors() + { + var groupedErrors = new Dictionary>() + { + { + 0, new List() + { + "FailedToUpdateFact", + "FailedToUpdateTerm", + "FailedToUpdateStatusOfStreetcode", + "FailedToChangeStatusOfStreetcodeToDeleted", + } + }, + }; + + return groupedErrors; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToValidateLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToValidateLocalizer.cs index ac79386f2..4e552921e 100644 --- a/Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToValidateLocalizer.cs +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockFailedToValidateLocalizer.cs @@ -1,5 +1,4 @@ -using Microsoft.Extensions.Localization; -using Streetcode.BLL.SharedResource; +using Streetcode.BLL.SharedResource; namespace Streetcode.XUnitTest.Mocks; @@ -18,6 +17,10 @@ protected override Dictionary> DefineGroupedErrors() "InvalidNewsUrl", "DateStringFormat", "EventStreetcodeCannotHasFirstName", + "UserNameFormat", + "NameFormat", + "SurnameFormat", + "InvalidPaginationParameters", } }, { @@ -34,6 +37,7 @@ protected override Dictionary> DefineGroupedErrors() "MustContainAtMostOneAlt0", "MustContainAtMostOneAlt2", "ImageSizeExceeded", + "MustContainAtMostThreeExpertises", } }, { @@ -44,6 +48,7 @@ protected override Dictionary> DefineGroupedErrors() "GreaterThan", "MustBeOneOf", "MaxLength", + "MinLength", } }, { diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockFieldNamesLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockFieldNamesLocalizer.cs index d523b11b9..f1c1b7622 100644 --- a/Streetcode/Streetcode.XUnitTest/Mocks/MockFieldNamesLocalizer.cs +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockFieldNamesLocalizer.cs @@ -3,7 +3,7 @@ namespace Streetcode.XUnitTest.Mocks; -public class MockFieldNamesLocalizer: IStringLocalizer +public class MockFieldNamesLocalizer : IStringLocalizer { public LocalizedString this[string name] => new (name, name); diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockHelpers.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockHelpers.cs index 0aa3f582e..43879d5a0 100644 --- a/Streetcode/Streetcode.XUnitTest/Mocks/MockHelpers.cs +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockHelpers.cs @@ -1,16 +1,35 @@ using System.Linq.Expressions; +using System.Security.Claims; +using AutoMapper; +using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore.Query; using Moq; using Streetcode.DAL.Entities.Media.Images; using Streetcode.DAL.Entities.Partners; using Streetcode.DAL.Entities.Sources; using Streetcode.DAL.Entities.Streetcode; +using Streetcode.DAL.Entities.Streetcode.TextContent; +using Streetcode.DAL.Entities.Users; using Streetcode.DAL.Repositories.Interfaces.Base; namespace Streetcode.XUnitTest.Mocks; public static class MockHelpers { + public static void SetupMockHttpContextAccessor(Mock mockContextAccessor, string userId) + { + var claims = new List { new(ClaimTypes.NameIdentifier, userId) }; + var identity = new ClaimsIdentity(claims, "TestAuthType"); + var claimsPrincipal = new ClaimsPrincipal(identity); + + var httpContext = new DefaultHttpContext + { + User = claimsPrincipal, + }; + + mockContextAccessor.Setup(x => x.HttpContext).Returns(httpContext); + } + public static void SetupMockImageRepositoryGetFirstOrDefaultAsync(Mock mockRepositoryWrapper, int imageId) { // Returns an Image with Id = 1 @@ -19,7 +38,7 @@ public static void SetupMockImageRepositoryGetFirstOrDefaultAsync(Mock, IIncludableQueryable>>())) .ReturnsAsync(new Image { Id = imageId }); } - + public static void SetupMockImageRepositoryGetFirstOrDefaultAsyncReturnsNull(Mock mockRepositoryWrapper) { // Returns null @@ -56,7 +75,95 @@ public static void SetupMockSourceCategoryRepositoryWithoutExistingCategory(Mock .ReturnsAsync((SourceLinkCategory)null!); } - //This method will return existing streetcode ids + public static void SetupMockFactRepositoryGetFirstOrDefaultAsync( + Mock mockRepositoryWrapper, + Fact? getFirstOrDefaultAsyncResult) + { + mockRepositoryWrapper + .Setup(x => x.FactRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(getFirstOrDefaultAsyncResult); + } + + public static void SetupMockRelatedTermRepositoryGetFirstOrDefaultAsync( + Mock mockRepositoryWrapper, + RelatedTerm? getFirstOrDefaultAsyncResult) + { + mockRepositoryWrapper + .Setup(x => x.RelatedTermRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(getFirstOrDefaultAsyncResult); + } + + public static void SetupMockTermGetFirstOrDefaultAsync( + Mock mockRepositoryWrapper, + Term? getFirstOrDefaultAsyncResult) + { + mockRepositoryWrapper + .Setup(x => x.TermRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(getFirstOrDefaultAsyncResult); + } + + public static void SetupMockTextGetFirstOrDefaultAsync( + Mock mockRepositoryWrapper, + Text? getFirstOrDefaultAsyncResult) + { + mockRepositoryWrapper + .Setup(x => x.TextRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(getFirstOrDefaultAsyncResult); + } + + public static void SetupMockFactRepositoryGetAllAsync( + Mock mockRepositoryWrapper, + List getAllAsyncResult) + { + mockRepositoryWrapper + .Setup(x => x.FactRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(getAllAsyncResult); + } + + public static void SetupMockRelatedTermRepositoryGetAllAsync( + Mock mockRepositoryWrapper, + List getAllAsyncResult) + { + mockRepositoryWrapper + .Setup(x => x.RelatedTermRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(getAllAsyncResult); + } + + public static void SetupMockTermRepositoryGetAllAsync( + Mock mockRepositoryWrapper, + List getAllAsyncResult) + { + mockRepositoryWrapper + .Setup(x => x.TermRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(getAllAsyncResult); + } + + public static void SetupMockTextRepositoryGetAllAsync( + Mock mockRepositoryWrapper, + List getAllAsyncResult) + { + mockRepositoryWrapper + .Setup(x => x.TextRepository.GetAllAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(getAllAsyncResult); + } + + // This method will return existing streetcode ids public static void SetupMockStreetcodeRepositoryFindAll(Mock mockRepositoryWrapper, List streetcodeIds) { mockRepositoryWrapper.Setup(x => x.StreetcodeRepository.GetAllAsync( @@ -64,4 +171,23 @@ public static void SetupMockStreetcodeRepositoryFindAll(Mock It.IsAny, IIncludableQueryable>>())) .ReturnsAsync(streetcodeIds.Select(id => new StreetcodeContent { Id = id }).ToList()); } -} \ No newline at end of file + + // This method will return existing user with email + public static void SetupMockUserRepositoryGetFirstOfDefaultAsync(Mock mockRepositoryWrapper, string email) + { + mockRepositoryWrapper.Setup(x => x.UserRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(new User { Email = email }); + } + + public static void SetupMockMapper( + Mock mockMapper, + TDestination mapperResult, + TSource mapperSource) + { + mockMapper + .Setup(x => x.Map(mapperSource)) + .Returns(mapperResult); + } +} diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockNoSharedResourceLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockNoSharedResourceLocalizer.cs index c99e0f236..a4b3b7a10 100644 --- a/Streetcode/Streetcode.XUnitTest/Mocks/MockNoSharedResourceLocalizer.cs +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockNoSharedResourceLocalizer.cs @@ -8,10 +8,19 @@ protected override Dictionary> DefineGroupedErrors() { return new Dictionary> { + { + 0, new List + { + "NoFavouritesFound", + "NoStreetcodesExistNow", + } + }, { 1, new List { "NoExistingStreetcodeWithId", + "NoFavouritesFound", + "NoFavouritesWithId", } }, }; diff --git a/Streetcode/Streetcode.XUnitTest/Mocks/MockUserSharedResourceLocalizer.cs b/Streetcode/Streetcode.XUnitTest/Mocks/MockUserSharedResourceLocalizer.cs new file mode 100644 index 000000000..cbf50937e --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/Mocks/MockUserSharedResourceLocalizer.cs @@ -0,0 +1,27 @@ +using Streetcode.BLL.SharedResource; + +namespace Streetcode.XUnitTest.Mocks; + +public class MockUserSharedResourceLocalizer : BaseMockStringLocalizer +{ + protected override Dictionary> DefineGroupedErrors() + { + return new Dictionary> + { + { + 0, new List + { + "UserWithSuchUsernameNotExists", + "UserWithSuchUsernameExists", + "UserWithSuchEmailNotFound", + "UserWithSuchEmailExists", + "UserNotFound", + "UserNameOrTokenIsEmpty", + "UserManagerError", + "IncorrectPassword", + "EmailNotMatch", + } + }, + }; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Services/Authentication/TokenServiceTest/RefreshTokenTest.cs b/Streetcode/Streetcode.XUnitTest/Services/Authentication/TokenServiceTest/RefreshTokenTest.cs index 90ae697db..cf9c951dc 100644 --- a/Streetcode/Streetcode.XUnitTest/Services/Authentication/TokenServiceTest/RefreshTokenTest.cs +++ b/Streetcode/Streetcode.XUnitTest/Services/Authentication/TokenServiceTest/RefreshTokenTest.cs @@ -1,12 +1,14 @@ using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; +using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; using Moq; using Streetcode.BLL.Services.Authentication; using Streetcode.DAL.Entities.Users; +using Streetcode.DAL.Enums; using Streetcode.DAL.Persistence; using Xunit; @@ -14,23 +16,23 @@ namespace Streetcode.XUnitTest.Services.Authentication.TokenServiceTest { public class RefreshTokenTest { - private readonly string jwtKey = "s_dkcLEWRlcksdmcQWE_124"; - private readonly string jwtIssuer = "Jwt_Issuer"; - private readonly string jwtAudience = "Jwt_Audience"; - private readonly string accessTokenLifetimeInMinutes = "15"; - private readonly Mock mockDbContext; - private readonly IConfiguration fakeConfiguration; - private readonly TokenService tokenService; + private readonly string _jwtKey = "s_dkcLEWRlcksdmcQWE_124"; + private readonly string _jwtIssuer = "Jwt_Issuer"; + private readonly string _jwtAudience = "Jwt_Audience"; + private readonly string _accessTokenLifetimeInMinutes = "15"; + private readonly Mock _mockDbContext; + private readonly IConfiguration _fakeConfiguration; + private readonly TokenService _tokenService; /// /// Initializes a new instance of the class. /// public RefreshTokenTest() { - this.mockDbContext = new Mock(); - this.fakeConfiguration = this.GetFakeConfiguration(); + _mockDbContext = new Mock(); + _fakeConfiguration = GetFakeConfiguration(); - this.tokenService = this.GetTokenService(); + _tokenService = GetTokenService(); } private enum CreateTokenOptions @@ -44,14 +46,14 @@ public void ShouldThrowException_InvalidInputAccessTokenSignature() { // Arrange. string testRefreshToken = "TestRefreshToken"; - var invalidToken = this.GetToken(CreateTokenOptions.InvalidToken, new User(), string.Empty); + var invalidToken = GetToken(CreateTokenOptions.InvalidToken, new User(), string.Empty); string invalidTokenStringified = new JwtSecurityTokenHandler().WriteToken(invalidToken); - var exceptionAction = this.tokenService.RefreshToken; + var exceptionAction = _tokenService.RefreshToken; // Act. // Assert. - Assert.Throws(() => exceptionAction(invalidTokenStringified, testRefreshToken)); + Assert.Throws(() => exceptionAction(invalidTokenStringified, testRefreshToken)); } [Fact] @@ -59,10 +61,10 @@ public void ShouldThrowException_UserFromInputAccessTokenNotExists() { // Arrange. string testRefreshToken = "TestRefreshToken"; - var validToken = this.GetToken(CreateTokenOptions.ValidToken, this.GetUser(), string.Empty); + var validToken = GetToken(CreateTokenOptions.ValidToken, GetUser(), string.Empty); string validTokenStringified = new JwtSecurityTokenHandler().WriteToken(validToken); - this.SetupMockDbContext(null); - var exceptionAction = this.tokenService.RefreshToken; + SetupMockDbContext(null); + var exceptionAction = _tokenService.RefreshToken; // Act. @@ -75,11 +77,11 @@ public void ShouldThrowException_InvalidInputRefreshToken() { // Arrange. string testRefreshToken = "TestRefreshToken"; - User testUser = this.GetUser(); - var invalidToken = this.GetToken(CreateTokenOptions.ValidToken, this.GetUser(), string.Empty); + User testUser = GetUser(); + var invalidToken = GetToken(CreateTokenOptions.ValidToken, GetUser(), string.Empty); string invalidTokenStringified = new JwtSecurityTokenHandler().WriteToken(invalidToken); - this.SetupMockDbContext(testUser); - var exceptionAction = this.tokenService.RefreshToken; + SetupMockDbContext(testUser); + var exceptionAction = _tokenService.RefreshToken; // Act. @@ -93,11 +95,11 @@ public void ShouldThrowException_RefreshExpiredToken() { // Arrange. string testRefreshToken = "TestRefreshToken"; - User testUser = this.GetUser(testRefreshToken); - var invalidToken = this.GetToken(CreateTokenOptions.ValidToken, this.GetUser(), string.Empty); + User testUser = GetUser(testRefreshToken); + var invalidToken = GetToken(CreateTokenOptions.ValidToken, GetUser(), string.Empty); string invalidTokenStringified = new JwtSecurityTokenHandler().WriteToken(invalidToken); - this.SetupMockDbContext(testUser); - var exceptionAction = this.tokenService.RefreshToken; + SetupMockDbContext(testUser); + var exceptionAction = _tokenService.RefreshToken; // Act. @@ -111,14 +113,16 @@ public void ShouldReturnSuccess_ValidInputToken() { // Arrange. string testRefreshToken = "TestRefreshToken"; - var user = this.GetUser(testRefreshToken, DateTime.Now.AddDays(1)); + var user = GetUser(testRefreshToken, DateTime.Now.AddDays(1)); string role = "User"; - var invalidToken = this.GetToken(CreateTokenOptions.ValidToken, user, role); + var invalidToken = GetToken(CreateTokenOptions.ValidToken, user, role); string invalidTokenStringified = new JwtSecurityTokenHandler().WriteToken(invalidToken); - this.SetupMockDbContext(user); + SetupMockDbContext(user); + SetupMockDbContextGetUserRoles(); + SetupMockDbContextGetRoles(); // Act. - var actualToken = this.tokenService.RefreshToken(invalidTokenStringified, testRefreshToken); + var actualToken = _tokenService.RefreshToken(invalidTokenStringified, testRefreshToken); // Assert. Assert.NotNull(actualToken); @@ -129,14 +133,16 @@ public void ShouldTokenWithCorrectData_ValidInputToken() { // Arrange. string testRefreshToken = "TestRefreshToken"; - User expectedUser = this.GetUser(testRefreshToken, DateTime.Now.AddDays(1)); + User expectedUser = GetUser(testRefreshToken, DateTime.Now.AddDays(1)); string expectedRole = "User"; - var invalidToken = this.GetToken(CreateTokenOptions.ValidToken, expectedUser, expectedRole); + var invalidToken = GetToken(CreateTokenOptions.ValidToken, expectedUser, expectedRole); string invalidTokenStringified = new JwtSecurityTokenHandler().WriteToken(invalidToken); - this.SetupMockDbContext(expectedUser); + SetupMockDbContext(expectedUser); + SetupMockDbContextGetUserRoles(); + SetupMockDbContextGetRoles(); // Act. - var actualToken = this.tokenService.RefreshToken(invalidTokenStringified, testRefreshToken); + var actualToken = _tokenService.RefreshToken(invalidTokenStringified, testRefreshToken); // Assert. Assert.Equal(expectedUser.Email, actualToken.Claims.First(claim => claim.Type == "email").Value); @@ -145,11 +151,11 @@ public void ShouldTokenWithCorrectData_ValidInputToken() private void SetupMockDbContext(User? userToReturn) { - var mockDbSet = this.GetConfiguredMockDbSet(new List() + var mockDbSet = GetConfiguredMockDbSet(new List() { userToReturn ?? new User(), }); - this.mockDbContext + _mockDbContext .Setup(context => context.Users) .Returns(mockDbSet.Object); } @@ -170,9 +176,9 @@ private void SetupMockDbContext(User? userToReturn) new Claim(ClaimTypes.Email, user.Email!), new Claim(ClaimTypes.Role, userRoleName), }), - SigningCredentials = this.GetSigningCredentials(), - Issuer = this.jwtIssuer, - Audience = this.jwtAudience, + SigningCredentials = GetSigningCredentials(), + Issuer = _jwtIssuer, + Audience = _jwtAudience, }; var token = new JwtSecurityTokenHandler().CreateJwtSecurityToken(tokenDescriptor); return token; @@ -193,7 +199,7 @@ private User GetUser(string refreshToken = "", DateTime? refreshTokenExpireTime private SigningCredentials GetSigningCredentials() { - var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this.jwtKey)); + var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtKey)); var signingCredentials = new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256); return signingCredentials; } @@ -202,10 +208,10 @@ private IConfiguration GetFakeConfiguration() { var appSettingsStub = new Dictionary { - { "Jwt:Key", this.jwtKey }, - { "Jwt:Issuer", this.jwtIssuer }, - { "Jwt:Audience", this.jwtAudience }, - { "Jwt:AccessTokenLifetimeInMinutes", this.accessTokenLifetimeInMinutes }, + { "Jwt:Key", _jwtKey }, + { "Jwt:Issuer", _jwtIssuer }, + { "Jwt:Audience", _jwtAudience }, + { "Jwt:AccessTokenLifetimeInMinutes", _accessTokenLifetimeInMinutes }, }; var fakeConfiguration = new ConfigurationBuilder() .AddInMemoryCollection(appSettingsStub) @@ -228,11 +234,48 @@ private Mock> GetConfiguredMockDbSet(IEnumerable entities) return dbSet; } + private static IQueryable GetRoles() + { + var roles = new List() + { + new IdentityRole() { Id = "1", Name = nameof(UserRole.Admin) }, + new IdentityRole() { Id = "2", Name = nameof(UserRole.User) }, + }; + return roles.AsQueryable(); + } + + private static IQueryable> GetUserRoles() + { + var userRoles = new List>() + { + new IdentityUserRole() { UserId = "1", RoleId = "2" }, + new IdentityUserRole() { UserId = "2", RoleId = "1" }, + new IdentityUserRole() { UserId = "3", RoleId = "2" }, + }; + return userRoles.AsQueryable(); + } + + private void SetupMockDbContextGetUserRoles() + { + var mockDbSet = GetConfiguredMockDbSet(GetUserRoles()); + _mockDbContext + .Setup(context => context.UserRoles) + .Returns(mockDbSet.Object); + } + + private void SetupMockDbContextGetRoles() + { + var mockDbSet = GetConfiguredMockDbSet(GetRoles()); + _mockDbContext + .Setup(context => context.Roles) + .Returns(mockDbSet.Object); + } + private TokenService GetTokenService() { return new TokenService( - this.fakeConfiguration, - this.mockDbContext.Object); + _fakeConfiguration, + _mockDbContext.Object); } } } diff --git a/Streetcode/Streetcode.XUnitTest/Streetcode.XUnitTest.csproj b/Streetcode/Streetcode.XUnitTest/Streetcode.XUnitTest.csproj index c0ebde9be..809a8deb6 100644 --- a/Streetcode/Streetcode.XUnitTest/Streetcode.XUnitTest.csproj +++ b/Streetcode/Streetcode.XUnitTest/Streetcode.XUnitTest.csproj @@ -31,6 +31,7 @@ + all @@ -50,7 +51,9 @@ - + + + \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Email/EmailTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Email/EmailTests.cs index 0423364c7..9f6fd3075 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Email/EmailTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Email/EmailTests.cs @@ -15,34 +15,34 @@ public class EmailTests public EmailTests() { - this.mockValidationLocalizer = new MockFailedToValidateLocalizer(); - this.mockNamesLocalizer = new MockFieldNamesLocalizer(); - this.validator = new SendEmailCommandValidator(this.mockNamesLocalizer, this.mockValidationLocalizer); + mockValidationLocalizer = new MockFailedToValidateLocalizer(); + mockNamesLocalizer = new MockFieldNamesLocalizer(); + validator = new SendEmailCommandValidator(mockNamesLocalizer, mockValidationLocalizer); } [Fact] - public void ShouldReturnSuccessResult_WhenEmailIsValid() + public void Validate_EmailIsValid_ShouldReturnSuccessResult() { // Arrange - var email = this.GetValidEmailDto(); + var email = GetValidEmailDto(); // Act - var result = this.validator.Validate(new SendEmailCommand(email)); + var result = validator.Validate(new SendEmailCommand(email)); // Assert Assert.True(result.IsValid); } [Fact] - public void ShouldReturnError_WhenFromIsEmpty() + public void Validate_FromIsEmpty_ShouldReturnError() { // Arrange - var expectedError = this.mockValidationLocalizer["CannotBeEmpty", this.mockNamesLocalizer["Email"]]; - var email = this.GetValidEmailDto(); + var expectedError = mockValidationLocalizer["CannotBeEmpty", mockNamesLocalizer["Email"]]; + var email = GetValidEmailDto(); email.From = string.Empty; // Act - var result = this.validator.TestValidate(new SendEmailCommand(email)); + var result = validator.TestValidate(new SendEmailCommand(email)); // Assert result.ShouldHaveValidationErrorFor(x => x.Email.From) @@ -50,15 +50,15 @@ public void ShouldReturnError_WhenFromIsEmpty() } [Fact] - public void ShouldReturnError_WhenFromLengthIsOutOfRange() + public void Validate_FromLengthIsOutOfRange_ShouldReturnError() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["Email"], SendEmailCommandValidator.EmailMaxLength]; - var email = this.GetValidEmailDto(); + var expectedError = mockValidationLocalizer["MaxLength", mockNamesLocalizer["Email"], SendEmailCommandValidator.EmailMaxLength]; + var email = GetValidEmailDto(); email.From = new string('e', SendEmailCommandValidator.EmailMaxLength + 2); // Act - var result = this.validator.TestValidate(new SendEmailCommand(email)); + var result = validator.TestValidate(new SendEmailCommand(email)); // Assert result.ShouldHaveValidationErrorFor(x => x.Email.From) @@ -66,15 +66,15 @@ public void ShouldReturnError_WhenFromLengthIsOutOfRange() } [Fact] - public void ShouldReturnError_WhenEmailFormatIsInvalid() + public void Validate_EmailFormatIsInvalid_ShouldReturnError() { // Arrange - var expectedError = this.mockValidationLocalizer["EmailAddressFormat"]; - var email = this.GetValidEmailDto(); + var expectedError = mockValidationLocalizer["EmailAddressFormat"]; + var email = GetValidEmailDto(); email.From = "invalid////"; // Act - var result = this.validator.TestValidate(new SendEmailCommand(email)); + var result = validator.TestValidate(new SendEmailCommand(email)); // Assert result.ShouldHaveValidationErrorFor(x => x.Email.From) @@ -82,15 +82,15 @@ public void ShouldReturnError_WhenEmailFormatIsInvalid() } [Fact] - public void ShouldReturnError_WhenTokenIsEmpty() + public void Validate_TokenIsEmpty_ShouldReturnError() { // Arrange - var expectedError = this.mockValidationLocalizer["CannotBeEmpty", this.mockNamesLocalizer["CaptchaToken"]]; - var email = this.GetValidEmailDto(); + var expectedError = mockValidationLocalizer["CannotBeEmpty", mockNamesLocalizer["CaptchaToken"]]; + var email = GetValidEmailDto(); email.Token = string.Empty; // Act - var result = this.validator.TestValidate(new SendEmailCommand(email)); + var result = validator.TestValidate(new SendEmailCommand(email)); // Assert result.ShouldHaveValidationErrorFor(x => x.Email.Token) @@ -98,15 +98,15 @@ public void ShouldReturnError_WhenTokenIsEmpty() } [Fact] - public void ShouldReturnError_WhenContentLengthIsOutOfRange() + public void Validate_ContentLengthIsOutOfRange_ShouldReturnError() { // Arrange - var expectedError = this.mockValidationLocalizer["LengthMustBeInRange", this.mockNamesLocalizer["Content"], SendEmailCommandValidator.ContentMinLength, SendEmailCommandValidator.ContentMaxLength]; - var email = this.GetValidEmailDto(); + var expectedError = mockValidationLocalizer["LengthMustBeInRange", mockNamesLocalizer["Content"], SendEmailCommandValidator.ContentMinLength, SendEmailCommandValidator.ContentMaxLength]; + var email = GetValidEmailDto(); email.Content = new string('c', SendEmailCommandValidator.ContentMaxLength + 2); // Act - var result = this.validator.TestValidate(new SendEmailCommand(email)); + var result = validator.TestValidate(new SendEmailCommand(email)); // Assert result.ShouldHaveValidationErrorFor(x => x.Email.Content) diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Art/ArtCreateUpdateValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Art/ArtCreateUpdateValidatorTests.cs index 649051b33..cda4e1647 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Art/ArtCreateUpdateValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Art/ArtCreateUpdateValidatorTests.cs @@ -9,25 +9,25 @@ namespace Streetcode.XUnitTest.Validators.Streetcode.Art; public class ArtCreateUpdateValidatorTests { - private readonly MockFailedToValidateLocalizer mockValidationLocalizer; - private readonly MockFieldNamesLocalizer mockNamesLocalizer; - private readonly ArtCreateUpdateDTOValidator validator; + private readonly MockFailedToValidateLocalizer _mockValidationLocalizer; + private readonly MockFieldNamesLocalizer _mockNamesLocalizer; + private readonly ArtCreateUpdateDTOValidator _validator; public ArtCreateUpdateValidatorTests() { - this.mockValidationLocalizer = new MockFailedToValidateLocalizer(); - this.mockNamesLocalizer = new MockFieldNamesLocalizer(); - this.validator = new ArtCreateUpdateDTOValidator(this.mockValidationLocalizer, this.mockNamesLocalizer); + _mockValidationLocalizer = new MockFailedToValidateLocalizer(); + _mockNamesLocalizer = new MockFieldNamesLocalizer(); + _validator = new ArtCreateUpdateDTOValidator(_mockValidationLocalizer, _mockNamesLocalizer); } [Fact] public void ShouldReturnSuccessResult_WhenAllFieldsAreValid() { // Arrange - var art = this.GetValidArt(); + var art = GetValidArt(); // Act - var result = this.validator.Validate(art); + var result = _validator.Validate(art); // Assert Assert.True(result.IsValid); @@ -37,12 +37,12 @@ public void ShouldReturnSuccessResult_WhenAllFieldsAreValid() public void ShouldReturnError_WhenTitleLengthIsMoreThan150() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["ArtTitle"], ArtCreateUpdateDTOValidator.MaxTitleLength]; - var art = this.GetValidArt(); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["ArtTitle"], ArtCreateUpdateDTOValidator.MaxTitleLength]; + var art = GetValidArt(); art.Title = new string('*', ArtCreateUpdateDTOValidator.MaxTitleLength + 1); // Act - var result = this.validator.TestValidate(art); + var result = _validator.TestValidate(art); // Assert result.ShouldHaveValidationErrorFor(x => x.Title) @@ -53,12 +53,12 @@ public void ShouldReturnError_WhenTitleLengthIsMoreThan150() public void ShouldReturnError_WhenTitleDescriptionIsMoreThan150() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["ArtDescription"], ArtCreateUpdateDTOValidator.MaxDescriptionLength]; - var art = this.GetValidArt(); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["ArtDescription"], ArtCreateUpdateDTOValidator.MaxDescriptionLength]; + var art = GetValidArt(); art.Description = new string('*', ArtCreateUpdateDTOValidator.MaxDescriptionLength + 1); // Act - var result = this.validator.TestValidate(art); + var result = _validator.TestValidate(art); // Assert result.ShouldHaveValidationErrorFor(x => x.Description) @@ -69,18 +69,19 @@ public void ShouldReturnError_WhenTitleDescriptionIsMoreThan150() public void ShouldReturnError_WhenModelStateIsInvalid() { // Arrange - var expectedError = this.mockValidationLocalizer["Invalid", this.mockNamesLocalizer["ModelState"]]; - var art = this.GetValidArt(); + var expectedError = _mockValidationLocalizer["Invalid", _mockNamesLocalizer["ModelState"]]; + var art = GetValidArt(); art.ModelState = (ModelState)50; // Act - var result = this.validator.TestValidate(art); + var result = _validator.TestValidate(art); // Assert result.ShouldHaveValidationErrorFor(x => x.ModelState) .WithErrorMessage(expectedError); } - private ArtCreateUpdateDTO GetValidArt() + + private static ArtCreateUpdateDTO GetValidArt() { return new ArtCreateUpdateDTO() { diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/BaseStreetcodeValidatorsTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/BaseStreetcodeValidatorsTests.cs index 9dcada66b..36709b385 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/BaseStreetcodeValidatorsTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/BaseStreetcodeValidatorsTests.cs @@ -25,45 +25,45 @@ namespace Streetcode.XUnitTest.Validators.Streetcode; public class BaseStreetcodeValidatorsTests { - private readonly Mock mockToponymValidator; - private readonly Mock mockTimelineItemValidator; - private readonly Mock mockimageDetailsValidator; - private readonly Mock mockartSlideValidator; - private readonly Mock mockArtValidator; - private MockFailedToValidateLocalizer mockValidationLocalizer; - private MockFieldNamesLocalizer mockNamesLocalizer; - private readonly BaseStreetcodeValidator validator; + private readonly Mock _mockToponymValidator; + private readonly Mock _mockTimelineItemValidator; + private readonly Mock _mockimageDetailsValidator; + private readonly Mock _mockartSlideValidator; + private readonly Mock _mockArtValidator; + private readonly MockFailedToValidateLocalizer _mockValidationLocalizer; + private readonly MockFieldNamesLocalizer _mockNamesLocalizer; + private readonly BaseStreetcodeValidator _validator; public BaseStreetcodeValidatorsTests() { - this.mockValidationLocalizer = new MockFailedToValidateLocalizer(); - this.mockNamesLocalizer = new MockFieldNamesLocalizer(); - this.mockToponymValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - var mockContextValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - this.mockTimelineItemValidator = new Mock(mockContextValidator.Object, this.mockValidationLocalizer, this.mockNamesLocalizer); - this.mockartSlideValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); + _mockValidationLocalizer = new MockFailedToValidateLocalizer(); + _mockNamesLocalizer = new MockFieldNamesLocalizer(); + _mockToponymValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + var mockContextValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + _mockTimelineItemValidator = new Mock(mockContextValidator.Object, _mockValidationLocalizer, _mockNamesLocalizer); + _mockartSlideValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); var mockRepositoryWrapper = new Mock(); - this.mockimageDetailsValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer, mockRepositoryWrapper.Object); - this.mockArtValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - - this.validator = new BaseStreetcodeValidator( - this.mockToponymValidator.Object, - this.mockTimelineItemValidator.Object, - this.mockimageDetailsValidator.Object, - this.mockartSlideValidator.Object, - this.mockArtValidator.Object, - this.mockValidationLocalizer, - this.mockNamesLocalizer); + _mockimageDetailsValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer, mockRepositoryWrapper.Object); + _mockArtValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + + _validator = new BaseStreetcodeValidator( + _mockToponymValidator.Object, + _mockTimelineItemValidator.Object, + _mockimageDetailsValidator.Object, + _mockartSlideValidator.Object, + _mockArtValidator.Object, + _mockValidationLocalizer, + _mockNamesLocalizer); } [Fact] public void ShouldReturnSuccessResult_WhenAllFieldsAreValid() { // Arrange - var streetcode = this.GetValidStreetcodeDto(); + var streetcode = GetValidStreetcodeDto(); // Act - var result = this.validator.Validate(streetcode); + var result = _validator.Validate(streetcode); // Assert Assert.True(result.IsValid); @@ -73,12 +73,12 @@ public void ShouldReturnSuccessResult_WhenAllFieldsAreValid() public void ShouldReturnError_WhenFirstNameLengthIsMoreThan50() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["FirstName"], BaseStreetcodeValidator.FirstNameMaxLength]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["FirstName"], BaseStreetcodeValidator.FirstNameMaxLength]; + var streetcode = GetValidStreetcodeDto(); streetcode.FirstName = new string('*', BaseStreetcodeValidator.FirstNameMaxLength + 1); // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.FirstName) @@ -89,12 +89,12 @@ public void ShouldReturnError_WhenFirstNameLengthIsMoreThan50() public void ShouldReturnError_WhenLastNameLengthIsMoreThan50() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["LastName"], BaseStreetcodeValidator.LastNameMaxLength]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["LastName"], BaseStreetcodeValidator.LastNameMaxLength]; + var streetcode = GetValidStreetcodeDto(); streetcode.LastName = new string('*', BaseStreetcodeValidator.LastNameMaxLength + 1); // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.LastName) @@ -105,12 +105,12 @@ public void ShouldReturnError_WhenLastNameLengthIsMoreThan50() public void ShouldReturnError_WhenTitleLengthIsMoreThan100() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["Title"], BaseStreetcodeValidator.TitleMaxLength]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["Title"], BaseStreetcodeValidator.TitleMaxLength]; + var streetcode = GetValidStreetcodeDto(); streetcode.Title = new string('*', BaseStreetcodeValidator.TitleMaxLength + 1); // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.Title) @@ -121,12 +121,12 @@ public void ShouldReturnError_WhenTitleLengthIsMoreThan100() public void ShouldReturnError_WhenAliasLengthIsMoreThan33() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["Alias"], BaseStreetcodeValidator.AliasMaxLength]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["Alias"], BaseStreetcodeValidator.AliasMaxLength]; + var streetcode = GetValidStreetcodeDto(); streetcode.Alias = new string('*', BaseStreetcodeValidator.AliasMaxLength + 1); // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.Alias) @@ -137,12 +137,12 @@ public void ShouldReturnError_WhenAliasLengthIsMoreThan33() public void ShouldReturnError_WhenTeaserIsEmpty() { // Arrange - var expectedError = this.mockValidationLocalizer["CannotBeEmpty", this.mockNamesLocalizer["Teaser"]]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["CannotBeEmpty", _mockNamesLocalizer["Teaser"]]; + var streetcode = GetValidStreetcodeDto(); streetcode.Teaser = string.Empty; // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.Teaser) @@ -153,12 +153,12 @@ public void ShouldReturnError_WhenTeaserIsEmpty() public void ShouldReturnError_WhenTeaserLengthIsMoreThan520() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["Teaser"], BaseStreetcodeValidator.TeaserMaxLength]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["Teaser"], BaseStreetcodeValidator.TeaserMaxLength]; + var streetcode = GetValidStreetcodeDto(); streetcode.Teaser = new string('*', BaseStreetcodeValidator.TeaserMaxLength + 1); // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.Teaser) @@ -169,12 +169,12 @@ public void ShouldReturnError_WhenTeaserLengthIsMoreThan520() public void ShouldReturnError_WhenEventStreetcodeHasNotEmpty_FirstNameAndLastName() { // Arrange - var expectedError = this.mockValidationLocalizer["EventStreetcodeCannotHasFirstName"]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["EventStreetcodeCannotHasFirstName"]; + var streetcode = GetValidStreetcodeDto(); streetcode.StreetcodeType = StreetcodeType.Event; // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x) @@ -185,12 +185,12 @@ public void ShouldReturnError_WhenEventStreetcodeHasNotEmpty_FirstNameAndLastNam public void ShouldReturnError_WhenTransliterationUrlIsEmpty() { // Arrange - var expectedError = this.mockValidationLocalizer["CannotBeEmpty", this.mockNamesLocalizer["TransliterationUrl"]]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["CannotBeEmpty", _mockNamesLocalizer["TransliterationUrl"]]; + var streetcode = GetValidStreetcodeDto(); streetcode.TransliterationUrl = string.Empty; // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.TransliterationUrl) @@ -201,12 +201,12 @@ public void ShouldReturnError_WhenTransliterationUrlIsEmpty() public void ShouldReturnError_WhenTransliterationUrlLengthIsMoreThan100() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["TransliterationUrl"], BaseStreetcodeValidator.TransliterationUrlMaxLength]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["TransliterationUrl"], BaseStreetcodeValidator.TransliterationUrlMaxLength]; + var streetcode = GetValidStreetcodeDto(); streetcode.TransliterationUrl = new string('*', BaseStreetcodeValidator.TransliterationUrlMaxLength + 1); // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.TransliterationUrl) @@ -221,12 +221,12 @@ public void ShouldReturnError_WhenTransliterationUrlLengthIsMoreThan100() public void ShouldReturnError_WhenTransliterationUrlIsInvalid(string transliterationUrl) { // Arrange - var expectedError = this.mockValidationLocalizer["TransliterationUrlFormat"]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["TransliterationUrlFormat"]; + var streetcode = GetValidStreetcodeDto(); streetcode.TransliterationUrl = transliterationUrl; // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.TransliterationUrl) @@ -239,12 +239,12 @@ public void ShouldReturnError_WhenTransliterationUrlIsInvalid(string translitera public void ShouldReturnError_WhenIndexIsOutOfBounds(int index) { // Arrange - var expectedError = this.mockValidationLocalizer["MustBeBetween", this.mockNamesLocalizer["Index"], BaseStreetcodeValidator.IndexMinValue, BaseStreetcodeValidator.IndexMaxValue]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["MustBeBetween", _mockNamesLocalizer["Index"], BaseStreetcodeValidator.IndexMinValue, BaseStreetcodeValidator.IndexMaxValue]; + var streetcode = GetValidStreetcodeDto(); streetcode.Index = index; // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.Index) @@ -255,12 +255,12 @@ public void ShouldReturnError_WhenIndexIsOutOfBounds(int index) public void ShouldReturnError_WhenDateStringIsEmpty() { // Arrange - var expectedError = this.mockValidationLocalizer["CannotBeEmpty", this.mockNamesLocalizer["DateString"]]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["CannotBeEmpty", _mockNamesLocalizer["DateString"]]; + var streetcode = GetValidStreetcodeDto(); streetcode.DateString = string.Empty; // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.DateString) @@ -271,12 +271,12 @@ public void ShouldReturnError_WhenDateStringIsEmpty() public void ShouldReturnError_WhenDateStringLengthIsMoreThan100() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["DateString"], BaseStreetcodeValidator.DateStringMaxLength]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["DateString"], BaseStreetcodeValidator.DateStringMaxLength]; + var streetcode = GetValidStreetcodeDto(); streetcode.DateString = new string('*', BaseStreetcodeValidator.DateStringMaxLength + 1); // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.DateString) @@ -290,12 +290,12 @@ public void ShouldReturnError_WhenDateStringLengthIsMoreThan100() public void ShouldReturnError_WhenDateStringIsInvalid(string invalidDateString) { // Arrange - var expectedError = this.mockValidationLocalizer["DateStringFormat"]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["DateStringFormat"]; + var streetcode = GetValidStreetcodeDto(); streetcode.DateString = invalidDateString; // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.DateString) @@ -306,12 +306,12 @@ public void ShouldReturnError_WhenDateStringIsInvalid(string invalidDateString) public void ShouldReturnError_WhenStreetcodeTypeIsInvalid() { // Arrange - var expectedError = this.mockValidationLocalizer["Invalid", this.mockNamesLocalizer["StreetcodeType"]]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["Invalid", _mockNamesLocalizer["StreetcodeType"]]; + var streetcode = GetValidStreetcodeDto(); streetcode.StreetcodeType = (StreetcodeType)8; // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.StreetcodeType) @@ -322,12 +322,12 @@ public void ShouldReturnError_WhenStreetcodeTypeIsInvalid() public void ShouldReturnError_WhenStatusIsInvalid() { // Arrange - var expectedError = this.mockValidationLocalizer["Invalid", this.mockNamesLocalizer["Status"]]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["Invalid", _mockNamesLocalizer["Status"]]; + var streetcode = GetValidStreetcodeDto(); streetcode.Status = (StreetcodeStatus)50; // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.Status) @@ -338,12 +338,12 @@ public void ShouldReturnError_WhenStatusIsInvalid() public void ShouldReturnError_WhenBlackAndWhiteImageDoesntExist() { // Arrange - var expectedError = this.mockValidationLocalizer["MustContainExactlyOneAlt1", this.mockNamesLocalizer["Alt"]]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["MustContainExactlyOneAlt1", _mockNamesLocalizer["Alt"]]; + var streetcode = GetValidStreetcodeDto(); streetcode.ImagesDetails = new List(); // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.ImagesDetails) @@ -354,8 +354,8 @@ public void ShouldReturnError_WhenBlackAndWhiteImageDoesntExist() public void ShouldReturnError_WhenThereAreTwoColoredImages() { // Arrange - var expectedError = this.mockValidationLocalizer["MustContainAtMostOneAlt0", this.mockNamesLocalizer["Alt"]]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["MustContainAtMostOneAlt0", _mockNamesLocalizer["Alt"]]; + var streetcode = GetValidStreetcodeDto(); streetcode.ImagesDetails = new List() { new ImageDetailsDto() @@ -373,7 +373,7 @@ public void ShouldReturnError_WhenThereAreTwoColoredImages() }; // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.ImagesDetails) @@ -384,8 +384,8 @@ public void ShouldReturnError_WhenThereAreTwoColoredImages() public void ShouldReturnError_WhenThereAreTwoOptionalImages() { // Arrange - var expectedError = this.mockValidationLocalizer["MustContainAtMostOneAlt2", this.mockNamesLocalizer["Alt"]]; - var streetcode = this.GetValidStreetcodeDto(); + var expectedError = _mockValidationLocalizer["MustContainAtMostOneAlt2", _mockNamesLocalizer["Alt"]]; + var streetcode = GetValidStreetcodeDto(); streetcode.ImagesDetails = new List() { new ImageDetailsDto() @@ -403,7 +403,7 @@ public void ShouldReturnError_WhenThereAreTwoOptionalImages() }; // Act - var result = this.validator.TestValidate(streetcode); + var result = _validator.TestValidate(streetcode); // Assert result.ShouldHaveValidationErrorFor(x => x.ImagesDetails) @@ -414,23 +414,23 @@ public void ShouldReturnError_WhenThereAreTwoOptionalImages() public void ShouldCallChildValidators_WhenValidated() { // Arrange - this.mockToponymValidator.Setup(x => x.Validate(It.IsAny>())).Returns(new ValidationResult()); - this.mockimageDetailsValidator.Setup(x => x.Validate(It.IsAny>())).Returns(new ValidationResult()); - this.mockTimelineItemValidator.Setup(x => x.Validate(It.IsAny>())).Returns(new ValidationResult()); - this.mockartSlideValidator.Setup(x => x.Validate(It.IsAny>())).Returns(new ValidationResult()); - this.mockArtValidator.Setup(x => x.Validate(It.IsAny>())).Returns(new ValidationResult()); + _mockToponymValidator.Setup(x => x.Validate(It.IsAny>())).Returns(new ValidationResult()); + _mockimageDetailsValidator.Setup(x => x.Validate(It.IsAny>())).Returns(new ValidationResult()); + _mockTimelineItemValidator.Setup(x => x.Validate(It.IsAny>())).Returns(new ValidationResult()); + _mockartSlideValidator.Setup(x => x.Validate(It.IsAny>())).Returns(new ValidationResult()); + _mockArtValidator.Setup(x => x.Validate(It.IsAny>())).Returns(new ValidationResult()); - var streetcode = this.GetValidStreetcodeDto(); + var streetcode = GetValidStreetcodeDto(); // Act - this.validator.TestValidate(streetcode); + _validator.TestValidate(streetcode); // Assert - this.mockToponymValidator.Verify(x => x.Validate(It.IsAny>()), Times.AtLeast(1)); - this.mockimageDetailsValidator.Verify(x => x.Validate(It.IsAny>()), Times.AtLeast(1)); - this.mockTimelineItemValidator.Verify(x => x.Validate(It.IsAny>()), Times.AtLeast(1)); - this.mockartSlideValidator.Verify(x => x.Validate(It.IsAny>()), Times.AtLeast(1)); - this.mockArtValidator.Verify(x => x.Validate(It.IsAny>()), Times.AtLeast(1)); + _mockToponymValidator.Verify(x => x.Validate(It.IsAny>()), Times.AtLeast(1)); + _mockimageDetailsValidator.Verify(x => x.Validate(It.IsAny>()), Times.AtLeast(1)); + _mockTimelineItemValidator.Verify(x => x.Validate(It.IsAny>()), Times.AtLeast(1)); + _mockartSlideValidator.Verify(x => x.Validate(It.IsAny>()), Times.AtLeast(1)); + _mockArtValidator.Verify(x => x.Validate(It.IsAny>()), Times.AtLeast(1)); } private StreetcodeCreateUpdateDTO GetValidStreetcodeDto() diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/CategoryContent/BaseCategoryContentValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/CategoryContent/BaseCategoryContentValidatorTests.cs index ba30a8dd2..0c1d8ff55 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/CategoryContent/BaseCategoryContentValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/CategoryContent/BaseCategoryContentValidatorTests.cs @@ -9,15 +9,15 @@ namespace Streetcode.XUnitTest.Validators.Streetcode.CategoryContent; public class BaseCategoryContentValidatorTests { - private readonly MockFailedToValidateLocalizer mockValidationLocalizer; - private readonly MockFieldNamesLocalizer mockNamesLocalizer; - private readonly BaseCategoryContentValidator validator; + private readonly MockFailedToValidateLocalizer _mockValidationLocalizer; + private readonly MockFieldNamesLocalizer _mockNamesLocalizer; + private readonly BaseCategoryContentValidator _validator; public BaseCategoryContentValidatorTests() { - this.mockValidationLocalizer = new MockFailedToValidateLocalizer(); - this.mockNamesLocalizer = new MockFieldNamesLocalizer(); - this.validator = new BaseCategoryContentValidator(this.mockValidationLocalizer, this.mockNamesLocalizer); + _mockValidationLocalizer = new MockFailedToValidateLocalizer(); + _mockNamesLocalizer = new MockFieldNamesLocalizer(); + _validator = new BaseCategoryContentValidator(_mockValidationLocalizer, _mockNamesLocalizer); } [Fact] @@ -30,7 +30,7 @@ public void ShouldReturnSuccess_WhenAllFieldsAreValid() }; // Act - var result = this.validator.Validate(category); + var result = _validator.Validate(category); // Assert Assert.True(result.IsValid); @@ -40,16 +40,17 @@ public void ShouldReturnSuccess_WhenAllFieldsAreValid() public void ShouldReturnError_WhenTextLengthIsMoreThan6000() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["CategoryContent"], BaseCategoryContentValidator.TextMaxLength]; + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["CategoryContent"], BaseCategoryContentValidator.TextMaxLength]; var category = new StreetcodeCategoryContentDTO() { Text = new string('*', BaseCategoryContentValidator.TextMaxLength + 1), }; // Act - var result = this.validator.TestValidate(category); + var result = _validator.TestValidate(category); // Assert - result.ShouldHaveValidationErrorFor(x => x.Text); + result.ShouldHaveValidationErrorFor(x => x.Text) + .WithErrorMessage(expectedError); } } \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/CreateStreetcodeValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/CreateStreetcodeValidatorTests.cs index 76cae4638..b2120ba9a 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/CreateStreetcodeValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/CreateStreetcodeValidatorTests.cs @@ -1,11 +1,9 @@ using System.Linq.Expressions; -using AutoMapper.Configuration; using FluentValidation; using FluentValidation.Results; using FluentValidation.TestHelper; using Microsoft.EntityFrameworkCore.Query; using Moq; -using Serilog.Enrichers; using Streetcode.BLL.DTO.AdditionalContent.Subtitles; using Streetcode.BLL.DTO.AdditionalContent.Tag; using Streetcode.BLL.DTO.Media.Art; @@ -43,68 +41,67 @@ namespace Streetcode.XUnitTest.Validators.Streetcode; public class CreateStreetcodeValidatorTests { - private readonly MockFailedToValidateLocalizer mockValidationLocalizer; - private readonly MockFieldNamesLocalizer mockNamesLocalizer; - private readonly Mock repositoryWrapper; - private readonly Mock baseStreetcodeValidator; - private readonly Mock baseSubtitleValidator; - private readonly Mock baseTextValidator; - private readonly Mock tagValidator; - private readonly Mock baseFactValidator; - private readonly Mock videoValidator; - private readonly Mock categoryContentValidator; - - private readonly CreateStreetcodeValidator validator; + private readonly MockFailedToValidateLocalizer _mockValidationLocalizer; + private readonly MockFieldNamesLocalizer _mockNamesLocalizer; + private readonly Mock _repositoryWrapper; + private readonly Mock _baseStreetcodeValidator; + private readonly Mock _baseSubtitleValidator; + private readonly Mock _baseTextValidator; + private readonly Mock _tagValidator; + private readonly Mock _baseFactValidator; + private readonly Mock _videoValidator; + private readonly Mock _categoryContentValidator; + private readonly CreateStreetcodeValidator _validator; public CreateStreetcodeValidatorTests() { - this.mockValidationLocalizer = new MockFailedToValidateLocalizer(); - this.mockNamesLocalizer = new MockFieldNamesLocalizer(); - this.categoryContentValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - this.videoValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - this.baseTextValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - this.baseFactValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - this.tagValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - this.baseSubtitleValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - this.repositoryWrapper = new Mock(); - var mockToponymValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - var mockContextValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - var mockTimelineItemValidator = new Mock(mockContextValidator.Object, this.mockValidationLocalizer, this.mockNamesLocalizer); - var mockartSlideValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - var mockimageDetailsValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer, this.repositoryWrapper.Object); - var mockArtValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - - this.baseStreetcodeValidator = new Mock( + _mockValidationLocalizer = new MockFailedToValidateLocalizer(); + _mockNamesLocalizer = new MockFieldNamesLocalizer(); + _categoryContentValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + _videoValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + _baseTextValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + _baseFactValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + _tagValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + _baseSubtitleValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + _repositoryWrapper = new Mock(); + var mockToponymValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + var mockContextValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + var mockTimelineItemValidator = new Mock(mockContextValidator.Object, _mockValidationLocalizer, _mockNamesLocalizer); + var mockartSlideValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + var mockimageDetailsValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer, _repositoryWrapper.Object); + var mockArtValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + + _baseStreetcodeValidator = new Mock( mockToponymValidator.Object, mockTimelineItemValidator.Object, mockimageDetailsValidator.Object, mockartSlideValidator.Object, mockArtValidator.Object, - this.mockValidationLocalizer, - this.mockNamesLocalizer); - - this.validator = new CreateStreetcodeValidator( - this.repositoryWrapper.Object, - this.baseStreetcodeValidator.Object, - this.baseTextValidator.Object, - this.baseSubtitleValidator.Object, - this.tagValidator.Object, - this.baseFactValidator.Object, - this.videoValidator.Object, - this.categoryContentValidator.Object, - this.mockValidationLocalizer, - this.mockNamesLocalizer); + _mockValidationLocalizer, + _mockNamesLocalizer); + + _validator = new CreateStreetcodeValidator( + _repositoryWrapper.Object, + _baseStreetcodeValidator.Object, + _baseTextValidator.Object, + _baseSubtitleValidator.Object, + _tagValidator.Object, + _baseFactValidator.Object, + _videoValidator.Object, + _categoryContentValidator.Object, + _mockValidationLocalizer, + _mockNamesLocalizer); } [Fact] public async Task ShouldReturnSuccessResult_WhenAllFieldsAreValid() { // Arrange - this.SetupRepositoryWrapperReturnsNull(); - var command = this.GetValidCreateStreetcodeCommand(); + SetupRepositoryWrapperReturnsNull(); + var command = GetValidCreateStreetcodeCommand(); // Act - var result = await this.validator.ValidateAsync(command); + var result = await _validator.ValidateAsync(command); // Assert Assert.True(result.IsValid); @@ -114,12 +111,12 @@ public async Task ShouldReturnSuccessResult_WhenAllFieldsAreValid() public async Task ShouldReturnError_WhenIndexIsNotUnique() { // Arrange - this.SetupRepositoryWrapper(1); - var expectedError = this.mockValidationLocalizer["MustBeUnique", this.mockNamesLocalizer["Index"]]; - var command = this.GetValidCreateStreetcodeCommand(); + SetupRepositoryWrapper(1); + var expectedError = _mockValidationLocalizer["MustBeUnique", _mockNamesLocalizer["Index"]]; + var command = GetValidCreateStreetcodeCommand(); // Act - var result = await this.validator.TestValidateAsync(command); + var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Streetcode.Index) @@ -133,16 +130,16 @@ public async Task ShouldReturnError_WhenIndexIsNotUnique() public async Task ShouldReturnError_WhenArUrlIsInvalid(string invalidUrl) { // Arrange - this.SetupRepositoryWrapperReturnsNull(); - var expectedError = this.mockValidationLocalizer["ValidUrl", this.mockNamesLocalizer["ARBlockURL"]]; - var command = this.GetValidCreateStreetcodeCommand(); - command.Streetcode.ARBlockURL = invalidUrl; + SetupRepositoryWrapperReturnsNull(); + var expectedError = _mockValidationLocalizer["ValidUrl", _mockNamesLocalizer["ARBlockURL"]]; + var command = GetValidCreateStreetcodeCommand(); + command.Streetcode.ArBlockUrl = invalidUrl; // Act - var result = await this.validator.TestValidateAsync(command); + var result = await _validator.TestValidateAsync(command); // Assert - result.ShouldHaveValidationErrorFor(x => x.Streetcode.ARBlockURL) + result.ShouldHaveValidationErrorFor(x => x.Streetcode.ArBlockUrl) .WithErrorMessage(expectedError); } @@ -150,9 +147,9 @@ public async Task ShouldReturnError_WhenArUrlIsInvalid(string invalidUrl) public async Task ShouldReturnError_WhenExistsVideosWithoutTitle() { // Arrange - this.SetupRepositoryWrapperReturnsNull(); - var expectedError = this.mockValidationLocalizer["CannotBeEmptyWithCondition", this.mockNamesLocalizer["Title"], this.mockNamesLocalizer["Video"]]; - var command = this.GetValidCreateStreetcodeCommand(); + SetupRepositoryWrapperReturnsNull(); + var expectedError = _mockValidationLocalizer["CannotBeEmptyWithCondition", _mockNamesLocalizer["Title"], _mockNamesLocalizer["Video"]]; + var command = GetValidCreateStreetcodeCommand(); command.Streetcode.Text = new TextCreateDTO() { Title = string.Empty, @@ -166,7 +163,7 @@ public async Task ShouldReturnError_WhenExistsVideosWithoutTitle() }; // Act - var result = await this.validator.TestValidateAsync(command); + var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Streetcode.Text!.Title) @@ -177,13 +174,13 @@ public async Task ShouldReturnError_WhenExistsVideosWithoutTitle() public async Task ShouldReturnError_WhenImageIdsIsEmpty() { // Arrange - this.SetupRepositoryWrapperReturnsNull(); - var expectedError = this.mockValidationLocalizer["CannotBeEmpty", this.mockNamesLocalizer["Images"]]; - var command = this.GetValidCreateStreetcodeCommand(); + SetupRepositoryWrapperReturnsNull(); + var expectedError = _mockValidationLocalizer["CannotBeEmpty", _mockNamesLocalizer["Images"]]; + var command = GetValidCreateStreetcodeCommand(); command.Streetcode.ImagesIds = new List(); // Act - var result = await this.validator.TestValidateAsync(command); + var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Streetcode.ImagesIds) @@ -194,22 +191,21 @@ public async Task ShouldReturnError_WhenImageIdsIsEmpty() public async Task ShouldReturnValidationError_WhenImageDoesntExist() { // Arrange - this.SetupRepositoryWrapperReturnsNull(); - MockHelpers.SetupMockImageRepositoryGetFirstOrDefaultAsyncReturnsNull(repositoryWrapper); + SetupRepositoryWrapperReturnsNull(); + MockHelpers.SetupMockImageRepositoryGetFirstOrDefaultAsyncReturnsNull(_repositoryWrapper); var command = GetValidCreateStreetcodeCommand(); - var invalidImageIds = new List() {10, 20}; + var invalidImageIds = new List() { 10, 20 }; command.Streetcode.ImagesIds = invalidImageIds; - // Act - var result = await validator.TestValidateAsync(command); + var result = await _validator.TestValidateAsync(command); // Assert - var imageIds = command.Streetcode.ImagesIds.ToList(); + var imageIds = command.Streetcode.ImagesIds.ToList(); for (int i = 0; i < imageIds.Count; i++) { var imageId = imageIds[i]; - var expectedError = mockValidationLocalizer["ImageDoesntExist", imageId]; + var expectedError = _mockValidationLocalizer["ImageDoesntExist", imageId]; result.ShouldHaveValidationErrorFor($"Streetcode.ImagesIds[{i}]") .WithErrorMessage(expectedError); @@ -220,45 +216,45 @@ public async Task ShouldReturnValidationError_WhenImageDoesntExist() public async Task ShouldCallBaseValidator_WhenValidated() { // Arrange - this.SetupRepositoryWrapperReturnsNull(); - this.SetupValidatorMocks(); - var command = this.GetValidCreateStreetcodeCommand(); + SetupRepositoryWrapperReturnsNull(); + SetupValidatorMocks(); + var command = GetValidCreateStreetcodeCommand(); // Act - var result = await this.validator.TestValidateAsync(command); + await _validator.TestValidateAsync(command); // Assert - this.baseStreetcodeValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); + _baseStreetcodeValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); } [Fact] public async Task ShouldCallChildValidators_WhenValidated() { // Arrange - this.SetupRepositoryWrapperReturnsNull(); - this.SetupValidatorMocks(); - var command = this.GetValidCreateStreetcodeCommand(); + SetupRepositoryWrapperReturnsNull(); + SetupValidatorMocks(); + var command = GetValidCreateStreetcodeCommand(); // Act - var result = await this.validator.TestValidateAsync(command); + await _validator.TestValidateAsync(command); // Assert - this.categoryContentValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); - this.videoValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); - this.baseTextValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); - this.baseFactValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); - this.tagValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); - this.baseSubtitleValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); + _categoryContentValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); + _videoValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); + _baseTextValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); + _baseFactValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); + _tagValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); + _baseSubtitleValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); } private void SetupRepositoryWrapperReturnsNull() { - this.repositoryWrapper.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( + _repositoryWrapper.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( It.IsAny>?>(), It.IsAny, IIncludableQueryable>?>())) .ReturnsAsync(null as StreetcodeContent); - this.repositoryWrapper.Setup(x => x.ImageRepository.GetFirstOrDefaultAsync( + _repositoryWrapper.Setup(x => x.ImageRepository.GetFirstOrDefaultAsync( It.IsAny>>(), It.IsAny, IIncludableQueryable>>())) .ReturnsAsync(new Image { Id = 8 }); @@ -266,7 +262,7 @@ private void SetupRepositoryWrapperReturnsNull() private void SetupRepositoryWrapper(int id) { - this.repositoryWrapper.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( + _repositoryWrapper.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( It.IsAny>>(), It.IsAny, IIncludableQueryable>>())) .ReturnsAsync(new StreetcodeContent() @@ -274,7 +270,7 @@ private void SetupRepositoryWrapper(int id) Id = id, }); - this.repositoryWrapper.Setup(x => x.ImageRepository.GetFirstOrDefaultAsync( + _repositoryWrapper.Setup(x => x.ImageRepository.GetFirstOrDefaultAsync( It.IsAny>>(), It.IsAny, IIncludableQueryable>>())) .ReturnsAsync(new Image { Id = id }); @@ -282,19 +278,19 @@ private void SetupRepositoryWrapper(int id) private void SetupValidatorMocks() { - this.baseStreetcodeValidator.Setup(x => x.Validate(It.IsAny>())) + _baseStreetcodeValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); - this.categoryContentValidator.Setup(x => x.Validate(It.IsAny>())) + _categoryContentValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); - this.videoValidator.Setup(x => x.Validate(It.IsAny>())) + _videoValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); - this.baseTextValidator.Setup(x => x.Validate(It.IsAny>())) + _baseTextValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); - this.baseFactValidator.Setup(x => x.Validate(It.IsAny>())) + _baseFactValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); - this.tagValidator.Setup(x => x.Validate(It.IsAny>())) + _tagValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); - this.baseSubtitleValidator.Setup(x => x.Validate(It.IsAny>())) + _baseSubtitleValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); } @@ -328,7 +324,7 @@ private CreateStreetcodeCommand GetValidCreateStreetcodeCommand() { new (), }, - ARBlockURL = "http://streetcode.com.ua/taras-shevchenko", + ArBlockUrl = "http://streetcode.com.ua/taras-shevchenko", Toponyms = new List() { new (), diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Facts/BaseFactValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Facts/BaseFactValidatorTests.cs index 2eac71b30..0933bab75 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Facts/BaseFactValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Facts/BaseFactValidatorTests.cs @@ -8,25 +8,25 @@ namespace Streetcode.XUnitTest.Validators.Streetcode.Facts; public class BaseFactValidatorTests { - private readonly MockFailedToValidateLocalizer mockValidationLocalizer; - private readonly MockFieldNamesLocalizer mockNamesLocalizer; - private readonly BaseFactValidator validator; + private readonly MockFailedToValidateLocalizer _mockValidationLocalizer; + private readonly MockFieldNamesLocalizer _mockNamesLocalizer; + private readonly BaseFactValidator _validator; public BaseFactValidatorTests() { - this.mockValidationLocalizer = new MockFailedToValidateLocalizer(); - this.mockNamesLocalizer = new MockFieldNamesLocalizer(); - this.validator = new BaseFactValidator(this.mockValidationLocalizer, this.mockNamesLocalizer); + _mockValidationLocalizer = new MockFailedToValidateLocalizer(); + _mockNamesLocalizer = new MockFieldNamesLocalizer(); + _validator = new BaseFactValidator(_mockValidationLocalizer, _mockNamesLocalizer); } [Fact] public void ShouldReturnSuccessResult_WhenAllFieldsAreValid() { // Arrange - var fact = this.GetValidFactDto(); + var fact = GetValidFactDto(); // Act - var result = this.validator.Validate(fact); + var result = _validator.Validate(fact); // Assert Assert.True(result.IsValid); @@ -36,12 +36,12 @@ public void ShouldReturnSuccessResult_WhenAllFieldsAreValid() public void ShouldReturnError_WhenTitleIsEmpty() { // Arrange - var expectedError = this.mockValidationLocalizer["CannotBeEmpty", this.mockNamesLocalizer["FactTitle"]]; - var fact = this.GetValidFactDto(); + var expectedError = _mockValidationLocalizer["CannotBeEmpty", _mockNamesLocalizer["FactTitle"]]; + var fact = GetValidFactDto(); fact.Title = string.Empty; // Act - var result = this.validator.TestValidate(fact); + var result = _validator.TestValidate(fact); // Assert result.ShouldHaveValidationErrorFor(x => x.Title) @@ -52,12 +52,12 @@ public void ShouldReturnError_WhenTitleIsEmpty() public void ShouldReturnError_WhenTitleLengthIsMoreThan68() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["FactTitle"], BaseFactValidator.TitleMaxLength]; - var fact = this.GetValidFactDto(); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["FactTitle"], BaseFactValidator.TitleMaxLength]; + var fact = GetValidFactDto(); fact.Title = new string('t', BaseFactValidator.TitleMaxLength + 1); // Act - var result = this.validator.TestValidate(fact); + var result = _validator.TestValidate(fact); // Assert result.ShouldHaveValidationErrorFor(x => x.Title) @@ -68,12 +68,12 @@ public void ShouldReturnError_WhenTitleLengthIsMoreThan68() public void ShouldReturnError_WhenContentIsEmpty() { // Arrange - var expectedError = this.mockValidationLocalizer["CannotBeEmpty", this.mockNamesLocalizer["FactContent"]]; - var fact = this.GetValidFactDto(); + var expectedError = _mockValidationLocalizer["CannotBeEmpty", _mockNamesLocalizer["FactContent"]]; + var fact = GetValidFactDto(); fact.FactContent = string.Empty; // Act - var result = this.validator.TestValidate(fact); + var result = _validator.TestValidate(fact); // Assert result.ShouldHaveValidationErrorFor(x => x.FactContent) @@ -84,12 +84,12 @@ public void ShouldReturnError_WhenContentIsEmpty() public void ShouldReturnError_WhenContentLengthIsMoreThan600() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["FactContent"], BaseFactValidator.ContentMaxLength]; - var fact = this.GetValidFactDto(); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["FactContent"], BaseFactValidator.ContentMaxLength]; + var fact = GetValidFactDto(); fact.FactContent = new string('t', BaseFactValidator.ContentMaxLength + 1); // Act - var result = this.validator.TestValidate(fact); + var result = _validator.TestValidate(fact); // Assert result.ShouldHaveValidationErrorFor(x => x.FactContent) @@ -100,19 +100,19 @@ public void ShouldReturnError_WhenContentLengthIsMoreThan600() public void ShouldReturnError_WhenImageDescriptionLengthIsMoreThan200() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["FactImageDescription"], BaseFactValidator.ImageDescriptionMaxLength]; - var fact = this.GetValidFactDto(); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["FactImageDescription"], BaseFactValidator.ImageDescriptionMaxLength]; + var fact = GetValidFactDto(); fact.ImageDescription = new string('t', BaseFactValidator.ImageDescriptionMaxLength + 1); // Act - var result = this.validator.TestValidate(fact); + var result = _validator.TestValidate(fact); // Assert result.ShouldHaveValidationErrorFor(x => x.ImageDescription) .WithErrorMessage(expectedError); } - private FactUpdateCreateDto GetValidFactDto() + private static FactUpdateCreateDto GetValidFactDto() { return new StreetcodeFactCreateDTO() { diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/ImageDetails/ImageDetailsValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/ImageDetails/ImageDetailsValidatorTests.cs index 469fb57f4..8e8e4658e 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/ImageDetails/ImageDetailsValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/ImageDetails/ImageDetailsValidatorTests.cs @@ -9,33 +9,34 @@ using Streetcode.XUnitTest.Mocks; using Xunit; using ImgDetails = Streetcode.DAL.Entities.Media.Images.ImageDetails; + namespace Streetcode.XUnitTest.Validators.Streetcode.ImageDetails; public class ImageDetailsValidatorTests { - private readonly MockFailedToValidateLocalizer mockValidationLocalizer; - private readonly MockFieldNamesLocalizer mockNamesLocalizer; - private readonly Mock mockRepositoryWrapper; - private readonly ImageDetailsValidator imageDetailsValidator; + private readonly MockFailedToValidateLocalizer _mockValidationLocalizer; + private readonly MockFieldNamesLocalizer _mockNamesLocalizer; + private readonly Mock _mockRepositoryWrapper; + private readonly ImageDetailsValidator _imageDetailsValidator; public ImageDetailsValidatorTests() { - this.mockValidationLocalizer = new MockFailedToValidateLocalizer(); - this.mockNamesLocalizer = new MockFieldNamesLocalizer(); + _mockValidationLocalizer = new MockFailedToValidateLocalizer(); + _mockNamesLocalizer = new MockFieldNamesLocalizer(); - this.mockRepositoryWrapper = new Mock(); - this.imageDetailsValidator = new ImageDetailsValidator(this.mockValidationLocalizer, this.mockNamesLocalizer, this.mockRepositoryWrapper.Object); + _mockRepositoryWrapper = new Mock(); + _imageDetailsValidator = new ImageDetailsValidator(_mockValidationLocalizer, _mockNamesLocalizer, _mockRepositoryWrapper.Object); } [Fact] public async Task ShouldReturnSuccessResult_WhenAllFieldsAreValid() { // Arrange - this.SetupRepositoryWrapper(12); - var imageDetails = this.GetImageDetails(12); + SetupRepositoryWrapper(12); + var imageDetails = GetImageDetails(12); // Act - var result = await this.imageDetailsValidator.ValidateAsync(imageDetails); + var result = await _imageDetailsValidator.ValidateAsync(imageDetails); // Assert Assert.True(result.IsValid); @@ -45,13 +46,13 @@ public async Task ShouldReturnSuccessResult_WhenAllFieldsAreValid() public async Task ShouldReturnError_WhenTitleLengthIsMoreThan100() { // Arrange - this.SetupRepositoryWrapper(12); - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["ImageTitle"], ImageDetailsValidator.TitleMaxLength]; - var imageDetails = this.GetImageDetails(12); + SetupRepositoryWrapper(12); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["ImageTitle"], ImageDetailsValidator.TitleMaxLength]; + var imageDetails = GetImageDetails(12); imageDetails.Title = new string('*', ImageDetailsValidator.TitleMaxLength + 1); // Act - var result = await this.imageDetailsValidator.TestValidateAsync(imageDetails); + var result = await _imageDetailsValidator.TestValidateAsync(imageDetails); // Assert result.ShouldHaveValidationErrorFor(x => x.Title) @@ -62,13 +63,13 @@ public async Task ShouldReturnError_WhenTitleLengthIsMoreThan100() public async Task ShouldReturnError_WhenAltLengthIsMoreThan200() { // Arrange - this.SetupRepositoryWrapper(12); - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["Alt"], ImageDetailsValidator.AltMaxLength]; - var imageDetails = this.GetImageDetails(12); + SetupRepositoryWrapper(12); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["Alt"], ImageDetailsValidator.AltMaxLength]; + var imageDetails = GetImageDetails(12); imageDetails.Alt = new string('*', ImageDetailsValidator.AltMaxLength + 1); // Act - var result = await this.imageDetailsValidator.TestValidateAsync(imageDetails); + var result = await _imageDetailsValidator.TestValidateAsync(imageDetails); // Assert result.ShouldHaveValidationErrorFor(x => x.Alt) @@ -79,12 +80,12 @@ public async Task ShouldReturnError_WhenAltLengthIsMoreThan200() public async Task ShouldReturnError_WhenExistsImageDetailsWithSameImage() { // Arrange - this.SetupRepositoryWrapper(1); - var expectedError = this.mockValidationLocalizer["MustBeUnique", this.mockNamesLocalizer["ImageId"]]; - var imageDetails = this.GetImageDetails(2); + SetupRepositoryWrapper(1); + var expectedError = _mockValidationLocalizer["MustBeUnique", _mockNamesLocalizer["ImageId"]]; + var imageDetails = GetImageDetails(2); // Act - var result = await this.imageDetailsValidator.TestValidateAsync(imageDetails); + var result = await _imageDetailsValidator.TestValidateAsync(imageDetails); // Assert result.ShouldHaveValidationErrorFor(x => x) @@ -95,34 +96,21 @@ public async Task ShouldReturnError_WhenExistsImageDetailsWithSameImage() public async Task ShouldReturnValidationError_WhenImageDoesntExist() { // Arrange - this.SetupRepositoryWrapper(1); - MockHelpers.SetupMockImageRepositoryGetFirstOrDefaultAsyncReturnsNull(mockRepositoryWrapper); + SetupRepositoryWrapper(1); + MockHelpers.SetupMockImageRepositoryGetFirstOrDefaultAsyncReturnsNull(_mockRepositoryWrapper); var imageDetails = GetImageDetails(2); imageDetails.ImageId = 10; - var expectedError = mockValidationLocalizer["ImageDoesntExist", imageDetails.ImageId]; + var expectedError = _mockValidationLocalizer["ImageDoesntExist", imageDetails.ImageId]; // Act - var result = await imageDetailsValidator.TestValidateAsync(imageDetails); + var result = await _imageDetailsValidator.TestValidateAsync(imageDetails); // Assert result.ShouldHaveValidationErrorFor(x => x.ImageId) .WithErrorMessage(expectedError); } - private void SetupRepositoryWrapper(int id) - { - this.mockRepositoryWrapper.Setup(x => x.ImageDetailsRepository.GetFirstOrDefaultAsync( - It.IsAny>>(), - It.IsAny, IIncludableQueryable>>())) - .ReturnsAsync(new ImgDetails { Id = id }); - - this.mockRepositoryWrapper.Setup(x => x.ImageRepository.GetFirstOrDefaultAsync( - It.IsAny>>(), - It.IsAny, IIncludableQueryable>>())) - .ReturnsAsync(new Image { Id = id }); - } - - private ImageDetailsDto GetImageDetails(int id) + private static ImageDetailsDto GetImageDetails(int id) { return new ImageDetailsDto() { @@ -132,4 +120,17 @@ private ImageDetailsDto GetImageDetails(int id) ImageId = 5, }; } + + private void SetupRepositoryWrapper(int id) + { + _mockRepositoryWrapper.Setup(x => x.ImageDetailsRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(new ImgDetails { Id = id }); + + _mockRepositoryWrapper.Setup(x => x.ImageRepository.GetFirstOrDefaultAsync( + It.IsAny>>(), + It.IsAny, IIncludableQueryable>>())) + .ReturnsAsync(new Image { Id = id }); + } } \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/StreetcodeArtSlide/StreetcodeArtSlideValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/StreetcodeArtSlide/StreetcodeArtSlideValidatorTests.cs index 318dbbdf4..715b522cc 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/StreetcodeArtSlide/StreetcodeArtSlideValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/StreetcodeArtSlide/StreetcodeArtSlideValidatorTests.cs @@ -10,25 +10,25 @@ namespace Streetcode.XUnitTest.Validators.Streetcode.StreetcodeArtSlide; public class StreetcodeArtSlideValidatorTests { - private readonly MockFieldNamesLocalizer mockNamesLocalizer; - private readonly MockFailedToValidateLocalizer mockValidationLocalizer; - private readonly StreetcodeArtSlideValidator validator; + private readonly MockFieldNamesLocalizer _mockNamesLocalizer; + private readonly MockFailedToValidateLocalizer _mockValidationLocalizer; + private readonly StreetcodeArtSlideValidator _validator; public StreetcodeArtSlideValidatorTests() { - this.mockNamesLocalizer = new MockFieldNamesLocalizer(); - this.mockValidationLocalizer = new MockFailedToValidateLocalizer(); - this.validator = new StreetcodeArtSlideValidator(this.mockValidationLocalizer, this.mockNamesLocalizer); + _mockNamesLocalizer = new MockFieldNamesLocalizer(); + _mockValidationLocalizer = new MockFailedToValidateLocalizer(); + _validator = new StreetcodeArtSlideValidator(_mockValidationLocalizer, _mockNamesLocalizer); } [Fact] public void ShouldReturnSuccessResult_WhenAllFieldsAreValid() { // Arrange - var slide = this.GetArtSlideDto(); + var slide = GetArtSlideDto(); // Act - var result = this.validator.Validate(slide); + var result = _validator.Validate(slide); // Assert Assert.True(result.IsValid); @@ -38,12 +38,12 @@ public void ShouldReturnSuccessResult_WhenAllFieldsAreValid() public void ShouldReturnError_WhenArtsAreEmpty() { // Arrange - var expectedError = this.mockValidationLocalizer["CannotBeEmpty", this.mockNamesLocalizer["StreetcodeArts"]]; - var slide = this.GetArtSlideDto(); + var expectedError = _mockValidationLocalizer["CannotBeEmpty", _mockNamesLocalizer["StreetcodeArts"]]; + var slide = GetArtSlideDto(); slide.StreetcodeArts = new List(); // Act - var result = this.validator.TestValidate(slide); + var result = _validator.TestValidate(slide); // Assert result.ShouldHaveValidationErrorFor(x => x.StreetcodeArts) @@ -54,19 +54,19 @@ public void ShouldReturnError_WhenArtsAreEmpty() public void ShouldReturnError_WhenTemplateIsInvalid() { // Arrange - var expectedError = this.mockValidationLocalizer["Invalid", this.mockNamesLocalizer["Template"]]; - var slide = this.GetArtSlideDto(); + var expectedError = _mockValidationLocalizer["Invalid", _mockNamesLocalizer["Template"]]; + var slide = GetArtSlideDto(); slide.Template = (StreetcodeArtSlideTemplate)100; // Act - var result = this.validator.TestValidate(slide); + var result = _validator.TestValidate(slide); // Assert result.ShouldHaveValidationErrorFor(x => x.Template) .WithErrorMessage(expectedError); } - private StreetcodeArtSlideCreateUpdateDTO GetArtSlideDto() + private static StreetcodeArtSlideCreateUpdateDTO GetArtSlideDto() { return new StreetcodeArtSlideCreateUpdateDTO() { diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Subtitles/SubtitlesValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Subtitles/SubtitlesValidatorTests.cs index b7f2b3cf6..36b4a0141 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Subtitles/SubtitlesValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Subtitles/SubtitlesValidatorTests.cs @@ -8,25 +8,25 @@ namespace Streetcode.XUnitTest.Validators.Streetcode.Subtitles; public class SubtitlesValidatorTests { - private readonly MockFieldNamesLocalizer mockNamesLocalizer; - private readonly MockFailedToValidateLocalizer mockValidationLocalizer; - private readonly BaseSubtitleValidator validator; + private readonly MockFieldNamesLocalizer _mockNamesLocalizer; + private readonly MockFailedToValidateLocalizer _mockValidationLocalizer; + private readonly BaseSubtitleValidator _validator; public SubtitlesValidatorTests() { - this.mockNamesLocalizer = new MockFieldNamesLocalizer(); - this.mockValidationLocalizer = new MockFailedToValidateLocalizer(); - this.validator = new BaseSubtitleValidator(this.mockValidationLocalizer, this.mockNamesLocalizer); + _mockNamesLocalizer = new MockFieldNamesLocalizer(); + _mockValidationLocalizer = new MockFailedToValidateLocalizer(); + _validator = new BaseSubtitleValidator(_mockValidationLocalizer, _mockNamesLocalizer); } [Fact] public void ShouldReturnSuccessResult_WhenSubtitleIsValid() { // Arrange - var subtitle = this.GetValidSubtitle(); + var subtitle = GetValidSubtitle(); // Act - var result = this.validator.Validate(subtitle); + var result = _validator.Validate(subtitle); // Assert Assert.True(result.IsValid); @@ -36,19 +36,19 @@ public void ShouldReturnSuccessResult_WhenSubtitleIsValid() public void ShouldReturnError_WhenSubtitleLengthIsMoreThan255() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["SubtitleText"], BaseSubtitleValidator.SubtitleMaxLength]; - var subtitle = this.GetValidSubtitle(); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["SubtitleText"], BaseSubtitleValidator.SubtitleMaxLength]; + var subtitle = GetValidSubtitle(); subtitle.SubtitleText = new string('s', BaseSubtitleValidator.SubtitleMaxLength + 1); // Act - var result = this.validator.TestValidate(subtitle); + var result = _validator.TestValidate(subtitle); // Assert result.ShouldHaveValidationErrorFor(x => x.SubtitleText) .WithErrorMessage(expectedError); } - private SubtitleCreateUpdateDTO GetValidSubtitle() + private static SubtitleCreateUpdateDTO GetValidSubtitle() { return new SubtitleCreateDTO() { diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Text/BaseTextValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Text/BaseTextValidatorTests.cs index 81036cba1..9ba996943 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Text/BaseTextValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Text/BaseTextValidatorTests.cs @@ -23,7 +23,7 @@ public BaseTextValidatorTests() public void ShouldReturnSuccessResult_WhenTextCreateDTOIsValid() { // Arrange - var validText = GetValidTextCreateDTO(); + var validText = GetValidTextCreateDto(); // Act var result = _validator.TestValidate(validText); @@ -36,10 +36,9 @@ public void ShouldReturnSuccessResult_WhenTextCreateDTOIsValid() public void ShouldReturnValidationError_WhenTitleExceedsMaxLength() { // Arrange - var invalidText = GetValidTextCreateDTO(); + var invalidText = GetValidTextCreateDto(); invalidText.Title = new string('a', BaseTextValidator.TitleMaxLength + 1); - var expectedError = _mockValidationLocalizer["MaxLength", - _mockNamesLocalizer["TextTitle"], BaseTextValidator.TitleMaxLength]; + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["TextTitle"], BaseTextValidator.TitleMaxLength]; // Act var result = _validator.TestValidate(invalidText); @@ -53,10 +52,9 @@ public void ShouldReturnValidationError_WhenTitleExceedsMaxLength() public void ShouldReturnValidationError_WhenTextExceedsMaxLength() { // Arrange - var invalidText = GetValidTextCreateDTO(); + var invalidText = GetValidTextCreateDto(); invalidText.TextContent = new string('a', BaseTextValidator.TextMaxLength + 1); - var expectedError = _mockValidationLocalizer["MaxLength", - _mockNamesLocalizer["TextContent"], BaseTextValidator.TextMaxLength]; + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["TextContent"], BaseTextValidator.TextMaxLength]; // Act var result = _validator.TestValidate(invalidText); @@ -70,10 +68,9 @@ public void ShouldReturnValidationError_WhenTextExceedsMaxLength() public void ShouldReturnValidationError_WhenAdditionalTextExceedsMaxLength() { // Arrange - var invalidText = GetValidTextCreateDTO(); + var invalidText = GetValidTextCreateDto(); invalidText.AdditionalText = new string('a', BaseTextValidator.AdditionalTextMaxLength + 1); - var expectedError = _mockValidationLocalizer["MaxLength", - _mockNamesLocalizer["AdditionalText"], BaseTextValidator.AdditionalTextMaxLength]; + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["AdditionalText"], BaseTextValidator.AdditionalTextMaxLength]; // Act var result = _validator.TestValidate(invalidText); @@ -87,10 +84,9 @@ public void ShouldReturnValidationError_WhenAdditionalTextExceedsMaxLength() public void ShouldReturnValidationError_WhenTextContentExistsButTitleIsEmpty() { // Arrange - var invalidText = GetValidTextCreateDTO(); + var invalidText = GetValidTextCreateDto(); invalidText.Title = string.Empty; - var expectedError = _mockValidationLocalizer["CannotBeEmptyWithCondition", - _mockNamesLocalizer["TextTitle"], _mockNamesLocalizer["TextContent"]]; + var expectedError = _mockValidationLocalizer["CannotBeEmptyWithCondition", _mockNamesLocalizer["TextTitle"], _mockNamesLocalizer["TextContent"]]; // Act var result = _validator.TestValidate(invalidText); @@ -104,10 +100,9 @@ public void ShouldReturnValidationError_WhenTextContentExistsButTitleIsEmpty() public void ShouldReturnValidationError_WhenAdditionalTextExistsButTextContentIsEmpty() { // Arrange - var invalidText = GetValidTextCreateDTO(); + var invalidText = GetValidTextCreateDto(); invalidText.TextContent = string.Empty; - var expectedError = _mockValidationLocalizer["CannotBeEmptyWithCondition", - _mockNamesLocalizer["TextContent"], _mockNamesLocalizer["AdditionalText"]]; + var expectedError = _mockValidationLocalizer["CannotBeEmptyWithCondition", _mockNamesLocalizer["TextContent"], _mockNamesLocalizer["AdditionalText"]]; // Act var result = _validator.TestValidate(invalidText); @@ -117,7 +112,7 @@ public void ShouldReturnValidationError_WhenAdditionalTextExistsButTextContentIs .WithErrorMessage(expectedError); } - private static BaseTextDTO GetValidTextCreateDTO() + private static BaseTextDTO GetValidTextCreateDto() { return new TextCreateDTO() { diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Timeline/HistoricalContextValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Timeline/HistoricalContextValidatorTests.cs index 6c71c117f..25b3fdf9f 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Timeline/HistoricalContextValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Timeline/HistoricalContextValidatorTests.cs @@ -58,7 +58,9 @@ public void ShouldReturnValidationError_WhenTitleExceedsMaxLength() // Act var result = _validator.TestValidate(validHistoricalContext); - var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["HistoricalContextTitle"], + var expectedError = _mockValidationLocalizer[ + "MaxLength", + _mockNamesLocalizer["HistoricalContextTitle"], HistoricalContextValidator.TitleMaxLength]; // Asssert diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Timeline/TimelineItemValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Timeline/TimelineItemValidatorTests.cs index a3b2f56c9..95a6251bf 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Timeline/TimelineItemValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Timeline/TimelineItemValidatorTests.cs @@ -45,8 +45,10 @@ public void ShouldReturnValidationError_WhenTitleExceedsMaxLength() // Arrange var validTimeline = GetValidTimelineItem(); validTimeline.Title = new string('a', TimelineItemValidator.TitleMaxLength + 1); - var expectedError = _mockValidationLocalizer["MaxLength", - _mockNamesLocalizer["TimelineItemTitle"], TimelineItemValidator.TitleMaxLength]; + var expectedError = _mockValidationLocalizer[ + "MaxLength", + _mockNamesLocalizer["TimelineItemTitle"], + TimelineItemValidator.TitleMaxLength]; // Act var result = _validator.TestValidate(validTimeline); @@ -62,7 +64,9 @@ public void ShouldReturnValidationError_WhenDescriptionExceedsMaxLength() // Arrange var timeline = GetValidTimelineItem(); timeline.Description = new string('a', TimelineItemValidator.DescriptionMaxLength + 1); - var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["TimelineItemDescription"], + var expectedError = _mockValidationLocalizer[ + "MaxLength", + _mockNamesLocalizer["TimelineItemDescription"], TimelineItemValidator.DescriptionMaxLength]; // Act @@ -166,7 +170,7 @@ public void TimelineItemValidator_ShouldCallHistoricalContextValidator() .Returns(new ValidationResult()); // Act - var result = _validator.TestValidate(GetValidTimelineItem()); + _validator.TestValidate(GetValidTimelineItem()); // Assert _mockHistoricalContextValidator.Verify( diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Toponyms/StreetcodeToponymValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Toponyms/StreetcodeToponymValidatorTests.cs index 1127fc622..7e364e923 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Toponyms/StreetcodeToponymValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Toponyms/StreetcodeToponymValidatorTests.cs @@ -40,8 +40,11 @@ public void ShouldReturnValidationError_WhenStreetNameExceedsMaxLength() // Arrange var validTimeline = GetValidToponym(); validTimeline.StreetName = new string('a', StreetcodeToponymValidator.StreetNameMaxLength + 1); - var expectedError = _mockValidationLocalizer["MaxLength", - _mockNamesLocalizer["StreetName"], StreetcodeToponymValidator.StreetNameMaxLength]; + var expectedError = + _mockValidationLocalizer[ + "MaxLength", + _mockNamesLocalizer["StreetName"], + StreetcodeToponymValidator.StreetNameMaxLength]; // Act var result = _validator.TestValidate(validTimeline); @@ -81,7 +84,7 @@ public void ShouldReturnValidationError_WhenModelStateIsNotInEnum() var result = _validator.TestValidate(timeline); var expectedError = _mockValidationLocalizer["Invalid", _mockNamesLocalizer["ModelState"]]; - // Asssert + // Assert result.ShouldHaveValidationErrorFor(x => x.ModelState) .WithErrorMessage(expectedError); } diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/UpdateStreetcodeValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/UpdateStreetcodeValidatorTests.cs index 3d9c0f2ea..c607d9938 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/UpdateStreetcodeValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/UpdateStreetcodeValidatorTests.cs @@ -18,7 +18,6 @@ using Streetcode.BLL.DTO.Streetcode.Update; using Streetcode.BLL.DTO.Timeline.Update; using Streetcode.BLL.DTO.Toponyms; -using Streetcode.BLL.DTO.Transactions; using Streetcode.BLL.Enums; using Streetcode.BLL.MediatR.Streetcode.Streetcode.Update; using Streetcode.BLL.Validators.AdditionalContent.Tag; @@ -43,68 +42,67 @@ namespace Streetcode.XUnitTest.Validators.Streetcode; public class UpdateStreetcodeValidatorTests { - private readonly MockFailedToValidateLocalizer mockValidationLocalizer; - private readonly MockFieldNamesLocalizer mockNamesLocalizer; - private readonly Mock repositoryWrapper; - private readonly Mock baseStreetcodeValidator; - private readonly Mock baseSubtitleValidator; - private readonly Mock baseTextValidator; - private readonly Mock tagValidator; - private readonly Mock baseFactValidator; - private readonly Mock videoValidator; - private readonly Mock categoryContentValidator; - - private readonly UpdateStreetcodeValidator validator; + private readonly MockFailedToValidateLocalizer _mockValidationLocalizer; + private readonly MockFieldNamesLocalizer _mockNamesLocalizer; + private readonly Mock _repositoryWrapper; + private readonly Mock _baseStreetcodeValidator; + private readonly Mock _baseSubtitleValidator; + private readonly Mock _baseTextValidator; + private readonly Mock _tagValidator; + private readonly Mock _baseFactValidator; + private readonly Mock _videoValidator; + private readonly Mock _categoryContentValidator; + private readonly UpdateStreetcodeValidator _validator; public UpdateStreetcodeValidatorTests() { - this.mockValidationLocalizer = new MockFailedToValidateLocalizer(); - this.mockNamesLocalizer = new MockFieldNamesLocalizer(); - this.categoryContentValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - this.videoValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - this.baseTextValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - this.baseFactValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - this.tagValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - this.baseSubtitleValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - this.repositoryWrapper = new Mock(); - var mockToponymValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - var mockContextValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - var mockTimelineItemValidator = new Mock(mockContextValidator.Object, this.mockValidationLocalizer, this.mockNamesLocalizer); - var mockartSlideValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); - var mockimageDetailsValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer, this.repositoryWrapper.Object); - var mockArtValidator = new Mock(this.mockValidationLocalizer, this.mockNamesLocalizer); + _mockValidationLocalizer = new MockFailedToValidateLocalizer(); + _mockNamesLocalizer = new MockFieldNamesLocalizer(); + _categoryContentValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + _videoValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + _baseTextValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + _baseFactValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + _tagValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + _baseSubtitleValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + _repositoryWrapper = new Mock(); + var mockToponymValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + var mockContextValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + var mockTimelineItemValidator = new Mock(mockContextValidator.Object, _mockValidationLocalizer, _mockNamesLocalizer); + var mockartSlideValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); + var mockimageDetailsValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer, _repositoryWrapper.Object); + var mockArtValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer); - this.baseStreetcodeValidator = new Mock( + _baseStreetcodeValidator = new Mock( mockToponymValidator.Object, mockTimelineItemValidator.Object, mockimageDetailsValidator.Object, mockartSlideValidator.Object, mockArtValidator.Object, - this.mockValidationLocalizer, - this.mockNamesLocalizer); + _mockValidationLocalizer, + _mockNamesLocalizer); - this.validator = new UpdateStreetcodeValidator( - this.repositoryWrapper.Object, - this.baseStreetcodeValidator.Object, - this.baseTextValidator.Object, - this.baseSubtitleValidator.Object, - this.tagValidator.Object, - this.baseFactValidator.Object, - this.videoValidator.Object, - this.categoryContentValidator.Object, - this.mockValidationLocalizer, - this.mockNamesLocalizer); + _validator = new UpdateStreetcodeValidator( + _repositoryWrapper.Object, + _baseStreetcodeValidator.Object, + _baseTextValidator.Object, + _baseSubtitleValidator.Object, + _tagValidator.Object, + _baseFactValidator.Object, + _videoValidator.Object, + _categoryContentValidator.Object, + _mockValidationLocalizer, + _mockNamesLocalizer); } [Fact] public async Task ShouldReturnSuccessResult_WhenAllFieldsAreValid() { // Arrange - this.SetupRepositoryWrapperReturnsNull(); - var command = this.GetValidCreateStreetcodeCommand(); + SetupRepositoryWrapperReturnsNull(); + var command = GetValidCreateStreetcodeCommand(); // Act - var result = await this.validator.ValidateAsync(command); + var result = await _validator.ValidateAsync(command); // Assert Assert.True(result.IsValid); @@ -114,12 +112,12 @@ public async Task ShouldReturnSuccessResult_WhenAllFieldsAreValid() public async Task ShouldReturnError_WhenIndexIsNotUnique() { // Arrange - this.SetupRepositoryWrapper(1); - var expectedError = this.mockValidationLocalizer["MustBeUnique", this.mockNamesLocalizer["Index"]]; - var command = this.GetValidCreateStreetcodeCommand(); + SetupRepositoryWrapper(1); + var expectedError = _mockValidationLocalizer["MustBeUnique", _mockNamesLocalizer["Index"]]; + var command = GetValidCreateStreetcodeCommand(); // Act - var result = await this.validator.TestValidateAsync(command); + var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Streetcode) @@ -133,16 +131,16 @@ public async Task ShouldReturnError_WhenIndexIsNotUnique() public async Task ShouldReturnError_WhenArUrlIsInvalid(string invalidUrl) { // Arrange - this.SetupRepositoryWrapperReturnsNull(); - var expectedError = this.mockValidationLocalizer["ValidUrl", this.mockNamesLocalizer["ARBlockURL"]]; - var command = this.GetValidCreateStreetcodeCommand(); - command.Streetcode.ARBlockUrl = invalidUrl; + SetupRepositoryWrapperReturnsNull(); + var expectedError = _mockValidationLocalizer["ValidUrl", _mockNamesLocalizer["ARBlockURL"]]; + var command = GetValidCreateStreetcodeCommand(); + command.Streetcode.ArBlockUrl = invalidUrl; // Act - var result = await this.validator.TestValidateAsync(command); + var result = await _validator.TestValidateAsync(command); // Assert - result.ShouldHaveValidationErrorFor(x => x.Streetcode.ARBlockUrl) + result.ShouldHaveValidationErrorFor(x => x.Streetcode.ArBlockUrl) .WithErrorMessage(expectedError); } @@ -150,9 +148,9 @@ public async Task ShouldReturnError_WhenArUrlIsInvalid(string invalidUrl) public async Task ShouldReturnError_WhenExistsVideosWithoutTitle() { // Arrange - this.SetupRepositoryWrapperReturnsNull(); - var expectedError = this.mockValidationLocalizer["CannotBeEmptyWithCondition", this.mockNamesLocalizer["Title"], this.mockNamesLocalizer["Video"]]; - var command = this.GetValidCreateStreetcodeCommand(); + SetupRepositoryWrapperReturnsNull(); + var expectedError = _mockValidationLocalizer["CannotBeEmptyWithCondition", _mockNamesLocalizer["Title"], _mockNamesLocalizer["Video"]]; + var command = GetValidCreateStreetcodeCommand(); command.Streetcode.Text = new TextUpdateDTO() { Title = string.Empty, @@ -166,7 +164,7 @@ public async Task ShouldReturnError_WhenExistsVideosWithoutTitle() }; // Act - var result = await this.validator.TestValidateAsync(command); + var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Streetcode.Text!.Title) @@ -177,45 +175,45 @@ public async Task ShouldReturnError_WhenExistsVideosWithoutTitle() public async Task ShouldCallBaseValidator_WhenValidated() { // Arrange - this.SetupRepositoryWrapperReturnsNull(); - this.SetupValidatorMocks(); - var command = this.GetValidCreateStreetcodeCommand(); + SetupRepositoryWrapperReturnsNull(); + SetupValidatorMocks(); + var command = GetValidCreateStreetcodeCommand(); // Act - var result = await this.validator.TestValidateAsync(command); + await _validator.TestValidateAsync(command); // Assert - this.baseStreetcodeValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); + _baseStreetcodeValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); } [Fact] public async Task ShouldCallChildValidators_WhenValidated() { // Arrange - this.SetupRepositoryWrapperReturnsNull(); - this.SetupValidatorMocks(); - var command = this.GetValidCreateStreetcodeCommand(); + SetupRepositoryWrapperReturnsNull(); + SetupValidatorMocks(); + var command = GetValidCreateStreetcodeCommand(); // Act - var result = await this.validator.TestValidateAsync(command); + await _validator.TestValidateAsync(command); // Assert - this.categoryContentValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); - this.videoValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); - this.baseTextValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); - this.baseFactValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); - this.tagValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); - this.baseSubtitleValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); + _categoryContentValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); + _videoValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); + _baseTextValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); + _baseFactValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); + _tagValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); + _baseSubtitleValidator.Verify(x => x.ValidateAsync(It.IsAny>(), default), Times.AtLeast(1)); } [Fact] public async Task ShouldReturnError_WhenTryToUpdateTag_WithId_0() { // Arrange - var expectedError = this.mockValidationLocalizer["Invalid", this.mockNamesLocalizer["Id"]]; - this.SetupRepositoryWrapperReturnsNull(); - this.SetupValidatorMocks(); - var command = this.GetValidCreateStreetcodeCommand(); + var expectedError = _mockValidationLocalizer["Invalid", _mockNamesLocalizer["Id"]]; + SetupRepositoryWrapperReturnsNull(); + SetupValidatorMocks(); + var command = GetValidCreateStreetcodeCommand(); command.Streetcode.Tags = new List() { new () @@ -228,7 +226,7 @@ public async Task ShouldReturnError_WhenTryToUpdateTag_WithId_0() }; // Act - var result = await this.validator.TestValidateAsync(command); + var result = await _validator.TestValidateAsync(command); // Assert result.ShouldHaveValidationErrorFor(x => x.Streetcode.Tags) @@ -237,7 +235,7 @@ public async Task ShouldReturnError_WhenTryToUpdateTag_WithId_0() private void SetupRepositoryWrapperReturnsNull() { - this.repositoryWrapper.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( + _repositoryWrapper.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( It.IsAny>?>(), It.IsAny, IIncludableQueryable>?>())) .ReturnsAsync(null as StreetcodeContent); @@ -245,7 +243,7 @@ private void SetupRepositoryWrapperReturnsNull() private void SetupRepositoryWrapper(int id) { - this.repositoryWrapper.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( + _repositoryWrapper.Setup(x => x.StreetcodeRepository.GetFirstOrDefaultAsync( It.IsAny>>(), It.IsAny, IIncludableQueryable>>())) .ReturnsAsync(new StreetcodeContent() @@ -256,19 +254,19 @@ private void SetupRepositoryWrapper(int id) private void SetupValidatorMocks() { - this.baseStreetcodeValidator.Setup(x => x.Validate(It.IsAny>())) + _baseStreetcodeValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); - this.categoryContentValidator.Setup(x => x.Validate(It.IsAny>())) + _categoryContentValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); - this.videoValidator.Setup(x => x.Validate(It.IsAny>())) + _videoValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); - this.baseTextValidator.Setup(x => x.Validate(It.IsAny>())) + _baseTextValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); - this.baseFactValidator.Setup(x => x.Validate(It.IsAny>())) + _baseFactValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); - this.tagValidator.Setup(x => x.Validate(It.IsAny>())) + _tagValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); - this.baseSubtitleValidator.Setup(x => x.Validate(It.IsAny>())) + _baseSubtitleValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); } @@ -302,7 +300,7 @@ private UpdateStreetcodeCommand GetValidCreateStreetcodeCommand() { new (), }, - ARBlockUrl = "http://streetcode.com.ua/taras-shevchenko", + ArBlockUrl = "http://streetcode.com.ua/taras-shevchenko", Toponyms = new List() { new (), diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Video/BaseVideoValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Video/BaseVideoValidatorTests.cs index 4317da709..291d28cd2 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Video/BaseVideoValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Streetcode/Video/BaseVideoValidatorTests.cs @@ -55,7 +55,7 @@ public void ShouldReturnValidationError_WhenUrlIsInvalid(string invalidUrl) { // Arrange var video = GetValidVideo(); - video.Url = string.Empty; + video.Url = invalidUrl; var expectedError = _mockValidationLocalizer["ValidUrl", _mockNamesLocalizer["Video"]]; // Act @@ -82,7 +82,7 @@ public void ShouldntReturnValidationError_WhenUrlIsValid(string invalidUrl) result.ShouldNotHaveValidationErrorFor(dto => dto.Url); } - public static VideoCreateUpdateDTO GetValidVideo() + private static VideoCreateUpdateDTO GetValidVideo() { return new VideoCreateDTO() { diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Timeline/CreateHistoricalContextValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Timeline/CreateHistoricalContextValidatorTests.cs index 17461ee0e..76d247fa1 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Timeline/CreateHistoricalContextValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Timeline/CreateHistoricalContextValidatorTests.cs @@ -12,16 +12,16 @@ namespace Streetcode.XUnitTest.Validators.Timeline; public class CreateHistoricalContextValidatorTests { - private readonly MockFieldNamesLocalizer mockFieldsLocalizer; - private readonly MockFailedToValidateLocalizer mockValidationLocalizer; - private readonly Mock mockBaseValidator; + private readonly MockFieldNamesLocalizer _mockFieldsLocalizer; + private readonly MockFailedToValidateLocalizer _mockValidationLocalizer; + private readonly Mock _mockBaseValidator; public CreateHistoricalContextValidatorTests() { - this.mockFieldsLocalizer = new MockFieldNamesLocalizer(); - this.mockValidationLocalizer = new MockFailedToValidateLocalizer(); - this.mockBaseValidator = new Mock(this.mockValidationLocalizer, this.mockFieldsLocalizer); - this.mockBaseValidator.Setup(x => x.Validate(It.IsAny>())) + _mockFieldsLocalizer = new MockFieldNamesLocalizer(); + _mockValidationLocalizer = new MockFailedToValidateLocalizer(); + _mockBaseValidator = new Mock(_mockValidationLocalizer, _mockFieldsLocalizer); + _mockBaseValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); } @@ -29,7 +29,7 @@ public CreateHistoricalContextValidatorTests() public void ShouldCallBaseValidator_WhenValidated() { // Arrange - var createValidator = new CreateHistoricalContextValidator(this.mockBaseValidator.Object); + var createValidator = new CreateHistoricalContextValidator(_mockBaseValidator.Object); var createCommand = new CreateHistoricalContextCommand(new () { Title = "Context", @@ -40,6 +40,6 @@ public void ShouldCallBaseValidator_WhenValidated() createValidator.TestValidate(createCommand); // Assert - this.mockBaseValidator.Verify(x => x.Validate(It.IsAny>()), Times.Once); + _mockBaseValidator.Verify(x => x.Validate(It.IsAny>()), Times.Once); } } \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Timeline/HistoricalContextValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Timeline/HistoricalContextValidatorTests.cs index 2dbae77a6..e8adb0715 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Timeline/HistoricalContextValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Timeline/HistoricalContextValidatorTests.cs @@ -1,6 +1,5 @@ using FluentValidation.TestHelper; using Streetcode.BLL.DTO.Timeline; -using Streetcode.BLL.Validators.Streetcode.TimelineItem; using Streetcode.BLL.Validators.Timeline.HistoricalContext; using Streetcode.XUnitTest.Mocks; using Xunit; @@ -9,25 +8,25 @@ namespace Streetcode.XUnitTest.Validators.Timeline; public class HistoricalContextValidatorTests { - private readonly MockFailedToValidateLocalizer mockValidationLocalizer; - private readonly MockFieldNamesLocalizer mockNamesLocalizer; - private readonly BaseHistoricalContextValidator validator; + private readonly MockFailedToValidateLocalizer _mockValidationLocalizer; + private readonly MockFieldNamesLocalizer _mockNamesLocalizer; + private readonly BaseHistoricalContextValidator _validator; public HistoricalContextValidatorTests() { - this.mockValidationLocalizer = new MockFailedToValidateLocalizer(); - this.mockNamesLocalizer = new MockFieldNamesLocalizer(); - this.validator = new BaseHistoricalContextValidator(this.mockValidationLocalizer, this.mockNamesLocalizer); + _mockValidationLocalizer = new MockFailedToValidateLocalizer(); + _mockNamesLocalizer = new MockFieldNamesLocalizer(); + _validator = new BaseHistoricalContextValidator(_mockValidationLocalizer, _mockNamesLocalizer); } [Fact] public void ShouldReturnSuccessResult_WhenHistoricalContextIsValid() { // Arrange - var context = this.GetValidHistoricalContext(); + var context = GetValidHistoricalContext(); // Act - var result = this.validator.Validate(context); + var result = _validator.Validate(context); // Assert Assert.True(result.IsValid); @@ -37,12 +36,12 @@ public void ShouldReturnSuccessResult_WhenHistoricalContextIsValid() public void ShouldReturnError_WhenTitleIsEmpty() { // Arrange - var expectedError = this.mockValidationLocalizer["IsRequired", this.mockNamesLocalizer["Title"]]; - var context = this.GetValidHistoricalContext(); + var expectedError = _mockValidationLocalizer["IsRequired", _mockNamesLocalizer["Title"]]; + var context = GetValidHistoricalContext(); context.Title = string.Empty; // Act - var result = this.validator.TestValidate(context); + var result = _validator.TestValidate(context); // Assert result.ShouldHaveValidationErrorFor(x => x.Title) @@ -53,19 +52,19 @@ public void ShouldReturnError_WhenTitleIsEmpty() public void ShouldReturnError_WhenTitleLengthIsMoreThan50() { // Arrange - var expectedError = this.mockValidationLocalizer["MaxLength", this.mockNamesLocalizer["Title"], BaseHistoricalContextValidator.MaxTitleLength]; - var context = this.GetValidHistoricalContext(); + var expectedError = _mockValidationLocalizer["MaxLength", _mockNamesLocalizer["Title"], BaseHistoricalContextValidator.MaxTitleLength]; + var context = GetValidHistoricalContext(); context.Title = new string('*', BaseHistoricalContextValidator.MaxTitleLength + 1); // Act - var result = this.validator.TestValidate(context); + var result = _validator.TestValidate(context); // Assert result.ShouldHaveValidationErrorFor(x => x.Title) .WithErrorMessage(expectedError); } - private HistoricalContextDTO GetValidHistoricalContext() + private static HistoricalContextDTO GetValidHistoricalContext() { return new HistoricalContextDTO() { diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Timeline/UpdateHistoricalContextValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Timeline/UpdateHistoricalContextValidatorTests.cs index 5d8c53aef..ae035a3e5 100644 --- a/Streetcode/Streetcode.XUnitTest/Validators/Timeline/UpdateHistoricalContextValidatorTests.cs +++ b/Streetcode/Streetcode.XUnitTest/Validators/Timeline/UpdateHistoricalContextValidatorTests.cs @@ -12,16 +12,16 @@ namespace Streetcode.XUnitTest.Validators.Timeline; public class UpdateHistoricalContextValidatorTests { - private readonly MockFieldNamesLocalizer mockFieldsLocalizer; - private readonly MockFailedToValidateLocalizer mockValidationLocalizer; - private readonly Mock mockBaseValidator; + private readonly MockFieldNamesLocalizer _mockFieldsLocalizer; + private readonly MockFailedToValidateLocalizer _mockValidationLocalizer; + private readonly Mock _mockBaseValidator; public UpdateHistoricalContextValidatorTests() { - this.mockFieldsLocalizer = new MockFieldNamesLocalizer(); - this.mockValidationLocalizer = new MockFailedToValidateLocalizer(); - this.mockBaseValidator = new Mock(this.mockValidationLocalizer, this.mockFieldsLocalizer); - this.mockBaseValidator.Setup(x => x.Validate(It.IsAny>())) + _mockFieldsLocalizer = new MockFieldNamesLocalizer(); + _mockValidationLocalizer = new MockFailedToValidateLocalizer(); + _mockBaseValidator = new Mock(_mockValidationLocalizer, _mockFieldsLocalizer); + _mockBaseValidator.Setup(x => x.Validate(It.IsAny>())) .Returns(new ValidationResult()); } @@ -29,7 +29,7 @@ public UpdateHistoricalContextValidatorTests() public void ShouldCallBaseValidator_WhenValidated() { // Arrange - var updateValidator = new UpdateHistoricalContextValidator(this.mockBaseValidator.Object); + var updateValidator = new UpdateHistoricalContextValidator(_mockBaseValidator.Object); var updateCommand = new UpdateHistoricalContextCommand(new () { Title = "Context", @@ -40,6 +40,6 @@ public void ShouldCallBaseValidator_WhenValidated() updateValidator.TestValidate(updateCommand); // Assert - this.mockBaseValidator.Verify(x => x.Validate(It.IsAny>()), Times.Once); + _mockBaseValidator.Verify(x => x.Validate(It.IsAny>()), Times.Once); } } \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Users/BaseUserValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Users/BaseUserValidatorTests.cs new file mode 100644 index 000000000..2d25400fb --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/Validators/Users/BaseUserValidatorTests.cs @@ -0,0 +1,323 @@ +using FluentValidation.TestHelper; +using Moq; +using Streetcode.BLL.DTO.Users; +using Streetcode.BLL.DTO.Users.Expertise; +using Streetcode.BLL.Validators.Users; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.Validators.Users; + +public class BaseUserValidatorTests +{ + private readonly MockFieldNamesLocalizer mockNamesLocalizer; + private readonly MockFailedToValidateLocalizer mockValidationLocalizer; + private readonly Mock _mockRepositoryWrapper; + private readonly BaseUserValidator validator; + + public BaseUserValidatorTests() + { + mockNamesLocalizer = new MockFieldNamesLocalizer(); + mockValidationLocalizer = new MockFailedToValidateLocalizer(); + _mockRepositoryWrapper = new Mock(); + validator = new BaseUserValidator(mockValidationLocalizer, mockNamesLocalizer, _mockRepositoryWrapper.Object); + } + + [Fact] + public void Validate_AllFieldsAreValid_ShouldReturnSuccessResult() + { + // Arrange + var user = GetValidUser(); + + // Act + var result = validator.Validate(user); + + // Assert + Assert.True(result.IsValid); + } + + [Fact] + public void Validate_ExpertisesCountIsMoreThan3_ShouldReturnError() + { + // Arrange + var expectedError = mockValidationLocalizer["MustContainAtMostThreeExpertises", mockNamesLocalizer["Expertises"]]; + var user = GetValidUser(); + user.Expertises.Add(new ExpertiseDTO + { + Id = 4, + Title = "testTitle4", + }); + + // Act + var result = validator.TestValidate(user); + + // Assert + result.ShouldHaveValidationErrorFor(x => x.Expertises) + .WithErrorMessage(expectedError); + } + + [Fact] + public void Validate_AboutYourselfLengthIsMoreThanMaximum_ShouldReturnError() + { + // Arrange + var expectedError = mockValidationLocalizer["MaxLength", mockNamesLocalizer["AboutYourself"], BaseUserValidator.MaxLengthAboutYourself]; + var user = GetValidUser(); + user.AboutYourself = new string('a', BaseUserValidator.MaxLengthAboutYourself + 1); + + // Act + var result = validator.TestValidate(user); + + // Assert + result.ShouldHaveValidationErrorFor(x => x.AboutYourself) + .WithErrorMessage(expectedError); + } + + [Theory] + [InlineData("!name")] + public void Validate_UserNameIsInvalid_ShouldReturnError(string userName) + { + // Arrange + var expectedError = mockValidationLocalizer["UserNameFormat"]; + var user = GetValidUser(); + user.UserName = userName; + + // Act + var result = validator.TestValidate(user); + + // Assert + result.ShouldHaveValidationErrorFor(x => x.UserName) + .WithErrorMessage(expectedError); + } + + [Fact] + public void Validate_UserNameIsEmpty_ShouldReturnError() + { + // Arrange + var expectedError = mockValidationLocalizer["CannotBeEmpty", mockNamesLocalizer["UserName"]]; + var user = GetValidUser(); + user.UserName = string.Empty; + + // Act + var result = validator.TestValidate(user); + + // Assert + result.ShouldHaveValidationErrorFor(x => x.UserName) + .WithErrorMessage(expectedError); + } + + [Fact] + public void Validate_UserNameLengthIsMoreThanMaximum_ShouldReturnError() + { + // Arrange + var expectedError = mockValidationLocalizer["MaxLength", mockNamesLocalizer["UserName"], BaseUserValidator.MaxLengthUserName]; + var user = GetValidUser(); + user.UserName = new string('a', BaseUserValidator.MaxLengthUserName + 1); + + // Act + var result = validator.TestValidate(user); + + // Assert + result.ShouldHaveValidationErrorFor(x => x.UserName) + .WithErrorMessage(expectedError); + } + + [Fact] + public void Validate_UserNameLengthIsLessThanMinimum_ShouldReturnError() + { + // Arrange + var expectedError = mockValidationLocalizer["MinLength", mockNamesLocalizer["UserName"], BaseUserValidator.MinLengthUserName]; + var user = GetValidUser(); + user.UserName = new string('a', BaseUserValidator.MinLengthUserName - 1); + + // Act + var result = validator.TestValidate(user); + + // Assert + result.ShouldHaveValidationErrorFor(x => x.UserName) + .WithErrorMessage(expectedError); + } + + [Theory] + [InlineData("name1")] + [InlineData("name_2")] + [InlineData("!name")] + public void Validate_NameIsInvalid_ShouldReturnError(string name) + { + // Arrange + var expectedError = mockValidationLocalizer["NameFormat"]; + var user = GetValidUser(); + user.Name = name; + + // Act + var result = validator.TestValidate(user); + + // Assert + result.ShouldHaveValidationErrorFor(x => x.Name) + .WithErrorMessage(expectedError); + } + + [Fact] + public void Validate_NameIsEmpty_ShouldReturnError() + { + // Arrange + var expectedError = mockValidationLocalizer["CannotBeEmpty", mockNamesLocalizer["Name"]]; + var user = GetValidUser(); + user.Name = string.Empty; + + // Act + var result = validator.TestValidate(user); + + // Assert + result.ShouldHaveValidationErrorFor(x => x.Name) + .WithErrorMessage(expectedError); + } + + [Fact] + public void Validate_NameLengthIsMoreThanMaximum_ShouldReturnError() + { + // Arrange + var expectedError = mockValidationLocalizer["MaxLength", mockNamesLocalizer["Name"], BaseUserValidator.MaxLengthName]; + var user = GetValidUser(); + user.Name = new string('a', BaseUserValidator.MaxLengthName + 1); + + // Act + var result = validator.TestValidate(user); + + // Assert + result.ShouldHaveValidationErrorFor(x => x.Name) + .WithErrorMessage(expectedError); + } + + [Fact] + public void Validate_NameLengthIsLessThanMinimum_ShouldReturnError() + { + // Arrange + var expectedError = mockValidationLocalizer["MinLength", mockNamesLocalizer["Name"], BaseUserValidator.MinLengthName]; + var user = GetValidUser(); + user.Name = new string('a', BaseUserValidator.MinLengthName - 1); + + // Act + var result = validator.TestValidate(user); + + // Assert + result.ShouldHaveValidationErrorFor(x => x.Name) + .WithErrorMessage(expectedError); + } + + [Theory] + [InlineData("surname1")] + [InlineData("surname_2")] + [InlineData("!surname")] + public void Validate_SurnameIsInvalid_ShouldReturnError(string surname) + { + // Arrange + var expectedError = mockValidationLocalizer["SurnameFormat"]; + var user = GetValidUser(); + user.Surname = surname; + + // Act + var result = validator.TestValidate(user); + + // Assert + result.ShouldHaveValidationErrorFor(x => x.Surname) + .WithErrorMessage(expectedError); + } + + [Fact] + public void Validate_SurnameIsEmpty_ShouldReturnError() + { + // Arrange + var expectedError = mockValidationLocalizer["CannotBeEmpty", mockNamesLocalizer["Surname"]]; + var user = GetValidUser(); + user.Surname = string.Empty; + + // Act + var result = validator.TestValidate(user); + + // Assert + result.ShouldHaveValidationErrorFor(x => x.Surname) + .WithErrorMessage(expectedError); + } + + [Fact] + public void Validate_SurnameLengthIsMoreThanMaximum_ShouldReturnError() + { + // Arrange + var expectedError = mockValidationLocalizer["MaxLength", mockNamesLocalizer["Surname"], BaseUserValidator.MaxLengthSurname]; + var user = GetValidUser(); + user.Surname = new string('a', BaseUserValidator.MaxLengthSurname + 1); + + // Act + var result = validator.TestValidate(user); + + // Assert + result.ShouldHaveValidationErrorFor(x => x.Surname) + .WithErrorMessage(expectedError); + } + + [Fact] + public void Validate_SurnameLengthIsLessThanMinimum_ShouldReturnError() + { + // Arrange + var expectedError = mockValidationLocalizer["MinLength", mockNamesLocalizer["Surname"], BaseUserValidator.MinLengthSurname]; + var user = GetValidUser(); + user.Surname = new string('a', BaseUserValidator.MinLengthSurname - 1); + + // Act + var result = validator.TestValidate(user); + + // Assert + result.ShouldHaveValidationErrorFor(x => x.Surname) + .WithErrorMessage(expectedError); + } + + [Fact] + public async Task Validate_ImageDoesNotExist_ShouldReturnError() + { + // Arrange + var user = GetValidUser(); + user.AvatarId = 1; + var expectedError = mockValidationLocalizer["ImageDoesntExist", user.AvatarId]; + MockHelpers.SetupMockImageRepositoryGetFirstOrDefaultAsyncReturnsNull(_mockRepositoryWrapper); + + // Act + var result = await validator.TestValidateAsync(user); + + // Assert + result.ShouldHaveValidationErrorFor(x => x.AvatarId) + .WithErrorMessage(expectedError); + } + + private UpdateUserDTO GetValidUser() + { + return new UpdateUserDTO + { + Name = "TestName", + Surname = "TestSurname", + UserName = "testusername", + AboutYourself = null, + AvatarId = null, + Expertises = new List() + { + new () + { + Id = 1, + Title = "testTitle1", + }, + new () + { + Id = 2, + Title = "testTitle2", + }, + new () + { + Id = 3, + Title = "testTitle3", + }, + }, + PhoneNumber = null!, + Email = "testemail", + }; + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/Validators/Users/UpdateUserValidatorTests.cs b/Streetcode/Streetcode.XUnitTest/Validators/Users/UpdateUserValidatorTests.cs new file mode 100644 index 000000000..10d36b8fe --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/Validators/Users/UpdateUserValidatorTests.cs @@ -0,0 +1,81 @@ +using FluentValidation; +using FluentValidation.Results; +using FluentValidation.TestHelper; +using Moq; +using Streetcode.BLL.DTO.Users; +using Streetcode.BLL.DTO.Users.Expertise; +using Streetcode.BLL.MediatR.Users.Update; +using Streetcode.BLL.Validators.Users; +using Streetcode.DAL.Repositories.Interfaces.Base; +using Streetcode.XUnitTest.Mocks; +using Xunit; + +namespace Streetcode.XUnitTest.Validators.Users; + +public class UpdateUserValidatorTests +{ + private readonly MockFieldNamesLocalizer _mockNamesLocalizer; + private readonly MockFailedToValidateLocalizer _mockValidationLocalizer; + private readonly MockUserSharedResourceLocalizer _mockUserSharedResourceLocalizer; + private readonly Mock _mockRepositoryWrapper; + private readonly Mock _mockBaseValidator; + + public UpdateUserValidatorTests() + { + _mockNamesLocalizer = new MockFieldNamesLocalizer(); + _mockValidationLocalizer = new MockFailedToValidateLocalizer(); + _mockUserSharedResourceLocalizer = new MockUserSharedResourceLocalizer(); + _mockRepositoryWrapper = new Mock(); + _mockBaseValidator = new Mock(_mockValidationLocalizer, _mockNamesLocalizer, _mockRepositoryWrapper.Object); + _mockBaseValidator.Setup(x => x.Validate(It.IsAny>())) + .Returns(new ValidationResult()); + } + + [Fact] + public async Task Validate_WhenCalled_ShouldCallBaseValidator() + { + // Arrange + var createValidator = new UpdateUserValidator(_mockBaseValidator.Object, _mockRepositoryWrapper.Object, _mockUserSharedResourceLocalizer); + var user = GetValidUser(); + var createCommand = new UpdateUserCommand(user); + MockHelpers.SetupMockUserRepositoryGetFirstOfDefaultAsync(_mockRepositoryWrapper, user.UserName); + + // Act + await createValidator.TestValidateAsync(createCommand); + + // Assert + _mockBaseValidator.Verify(x => x.ValidateAsync(It.IsAny>(), CancellationToken.None), Times.Once); + } + + private UpdateUserDTO GetValidUser() + { + return new UpdateUserDTO + { + Name = "TestName", + Surname = "TestSurname", + UserName = "testusername", + AboutYourself = null, + AvatarId = null, + Expertises = new List() + { + new () + { + Id = 1, + Title = "testTitle1", + }, + new () + { + Id = 2, + Title = "testTitle2", + }, + new () + { + Id = 3, + Title = "testTitle3", + }, + }, + PhoneNumber = null!, + Email = "testemail", + }; + } +} \ No newline at end of file diff --git a/Streetcode/build.sh b/Streetcode/build.sh index 7f32232d6..8ae4859d6 100755 --- a/Streetcode/build.sh +++ b/Streetcode/build.sh @@ -58,5 +58,5 @@ fi echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)" -"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet -"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@" +"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet -p:WarningLevel=0 -p:RunAnalyzers=false -p:SonarQubeExclude=true +"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -p:WarningLevel=0 -p:RunAnalyzers=false -p:SonarQubeExclude=true -- "$@" diff --git a/build/Targets/BaseBuild.cs b/build/Targets/BaseBuild.cs index 9fffad8f9..e7ab86036 100644 --- a/build/Targets/BaseBuild.cs +++ b/build/Targets/BaseBuild.cs @@ -74,6 +74,8 @@ partial class Build .SetAssemblyVersion(GitVersion.AssemblySemVer) .SetFileVersion(GitVersion.AssemblySemFileVer) .SetInformationalVersion(GitVersion.InformationalVersion) + .SetWarningLevel(0) + .SetProperty("SonarQubeExclude", "true") ); }); diff --git a/build/Targets/DatabaseBuild.cs b/build/Targets/DatabaseBuild.cs index fca7f4f3f..dcc528802 100644 --- a/build/Targets/DatabaseBuild.cs +++ b/build/Targets/DatabaseBuild.cs @@ -45,7 +45,9 @@ partial class Build { DotNetRun(s => s .SetProjectFile(DbUpdateDirectory) - .SetConfiguration(Configuration)); + .SetConfiguration(Configuration) + .SetWarningLevel(0) + .SetProperty("SonarQubeExclude", "true")); }); Target GenerateSQLScripts => _ => _ diff --git a/build/Utils/AuthConstants.cs b/build/Utils/AuthConstants.cs index b85a18b97..e0d9f27cc 100644 --- a/build/Utils/AuthConstants.cs +++ b/build/Utils/AuthConstants.cs @@ -40,7 +40,9 @@ internal static class AuthConstants Name = "User_User", Surname = "User_User", Email = "user@user.com", + NormalizedEmail = "USER@USER.COM", UserName = "User_User_T", + NormalizedUserName = "USER_USER_T", RefreshToken = "User_User_Refresh_Token", RefreshTokenExpiry = DateTime.Now.AddDays(1), };