From 46894bd787a2a468bcd056f102ec4eb7112d94e2 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Mon, 25 Nov 2024 13:39:48 +0400 Subject: [PATCH 01/37] init: back --- back/.gitignore | 484 ++++++++++++++++++ back/Api.sln | 40 ++ back/Contracts/Contracts.csproj | 9 + back/Controllers/Controllers.csproj | 13 + back/Controllers/Controllers.http | 6 + back/Controllers/Program.cs | 25 + .../Properties/launchSettings.json | 41 ++ back/Controllers/appsettings.Development.json | 8 + back/Controllers/appsettings.json | 9 + back/Infrastructure/Infrastructure.csproj | 9 + back/Services/Services.csproj | 9 + 11 files changed, 653 insertions(+) create mode 100644 back/.gitignore create mode 100644 back/Api.sln create mode 100644 back/Contracts/Contracts.csproj create mode 100644 back/Controllers/Controllers.csproj create mode 100644 back/Controllers/Controllers.http create mode 100644 back/Controllers/Program.cs create mode 100644 back/Controllers/Properties/launchSettings.json create mode 100644 back/Controllers/appsettings.Development.json create mode 100644 back/Controllers/appsettings.json create mode 100644 back/Infrastructure/Infrastructure.csproj create mode 100644 back/Services/Services.csproj diff --git a/back/.gitignore b/back/.gitignore new file mode 100644 index 0000000..104b544 --- /dev/null +++ b/back/.gitignore @@ -0,0 +1,484 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from `dotnet new gitignore` + +# dotenv files +.env + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp diff --git a/back/Api.sln b/back/Api.sln new file mode 100644 index 0000000..c0cdbbb --- /dev/null +++ b/back/Api.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Controllers", "Controllers\Controllers.csproj", "{BEA05282-6DE5-4D67-983A-EF13AAF8EECE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Services", "Services\Services.csproj", "{B937E273-1D6E-42DF-BD34-14DA5E71FC71}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contracts", "Contracts\Contracts.csproj", "{B9246DBE-67B0-4B0F-8648-E9ED2EB7172C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "Infrastructure\Infrastructure.csproj", "{A35121D4-7D41-4266-8DA4-87135E8ABF89}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BEA05282-6DE5-4D67-983A-EF13AAF8EECE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BEA05282-6DE5-4D67-983A-EF13AAF8EECE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BEA05282-6DE5-4D67-983A-EF13AAF8EECE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BEA05282-6DE5-4D67-983A-EF13AAF8EECE}.Release|Any CPU.Build.0 = Release|Any CPU + {B937E273-1D6E-42DF-BD34-14DA5E71FC71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B937E273-1D6E-42DF-BD34-14DA5E71FC71}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B937E273-1D6E-42DF-BD34-14DA5E71FC71}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B937E273-1D6E-42DF-BD34-14DA5E71FC71}.Release|Any CPU.Build.0 = Release|Any CPU + {B9246DBE-67B0-4B0F-8648-E9ED2EB7172C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B9246DBE-67B0-4B0F-8648-E9ED2EB7172C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B9246DBE-67B0-4B0F-8648-E9ED2EB7172C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B9246DBE-67B0-4B0F-8648-E9ED2EB7172C}.Release|Any CPU.Build.0 = Release|Any CPU + {A35121D4-7D41-4266-8DA4-87135E8ABF89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A35121D4-7D41-4266-8DA4-87135E8ABF89}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A35121D4-7D41-4266-8DA4-87135E8ABF89}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A35121D4-7D41-4266-8DA4-87135E8ABF89}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/back/Contracts/Contracts.csproj b/back/Contracts/Contracts.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/back/Contracts/Contracts.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/back/Controllers/Controllers.csproj b/back/Controllers/Controllers.csproj new file mode 100644 index 0000000..9daa180 --- /dev/null +++ b/back/Controllers/Controllers.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/back/Controllers/Controllers.http b/back/Controllers/Controllers.http new file mode 100644 index 0000000..01f7fc0 --- /dev/null +++ b/back/Controllers/Controllers.http @@ -0,0 +1,6 @@ +@Controllers_HostAddress = http://localhost:5125 + +GET {{Controllers_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/back/Controllers/Program.cs b/back/Controllers/Program.cs new file mode 100644 index 0000000..48863a6 --- /dev/null +++ b/back/Controllers/Program.cs @@ -0,0 +1,25 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/back/Controllers/Properties/launchSettings.json b/back/Controllers/Properties/launchSettings.json new file mode 100644 index 0000000..3683563 --- /dev/null +++ b/back/Controllers/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:47535", + "sslPort": 44340 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5125", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7189;http://localhost:5125", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/back/Controllers/appsettings.Development.json b/back/Controllers/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/back/Controllers/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/back/Controllers/appsettings.json b/back/Controllers/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/back/Controllers/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/back/Infrastructure/Infrastructure.csproj b/back/Infrastructure/Infrastructure.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/back/Infrastructure/Infrastructure.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/back/Services/Services.csproj b/back/Services/Services.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/back/Services/Services.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + From a7529c4e5eff6f7d51fc0b94100b702a74f2ac9e Mon Sep 17 00:00:00 2001 From: mfnefd Date: Mon, 25 Nov 2024 13:56:05 +0400 Subject: [PATCH 02/37] init: front --- front/.gitignore | 24 + front/index.html | 12 + front/package-lock.json | 1292 +++++++++++++++++ front/package.json | 20 + front/src/App.vue | 9 + front/src/main.ts | 5 + front/src/style.css | 0 front/src/vite-env.d.ts | 1 + front/tsconfig.app.json | 26 + front/tsconfig.json | 7 + front/tsconfig.node.json | 24 + front/vite.config.ts | 7 + ....timestamp-1732528329064-33d75fbae33f5.mjs | 10 + 13 files changed, 1437 insertions(+) create mode 100644 front/.gitignore create mode 100644 front/index.html create mode 100644 front/package-lock.json create mode 100644 front/package.json create mode 100644 front/src/App.vue create mode 100644 front/src/main.ts create mode 100644 front/src/style.css create mode 100644 front/src/vite-env.d.ts create mode 100644 front/tsconfig.app.json create mode 100644 front/tsconfig.json create mode 100644 front/tsconfig.node.json create mode 100644 front/vite.config.ts create mode 100644 front/vite.config.ts.timestamp-1732528329064-33d75fbae33f5.mjs diff --git a/front/.gitignore b/front/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/front/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/front/index.html b/front/index.html new file mode 100644 index 0000000..28e68e6 --- /dev/null +++ b/front/index.html @@ -0,0 +1,12 @@ + + + + + + ДомБюдж + + +
+ + + diff --git a/front/package-lock.json b/front/package-lock.json new file mode 100644 index 0000000..7fb419c --- /dev/null +++ b/front/package-lock.json @@ -0,0 +1,1292 @@ +{ + "name": "dombudg", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "dombudg", + "version": "0.0.0", + "dependencies": { + "vue": "^3.5.12" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.1.4", + "typescript": "~5.6.2", + "vite": "^5.4.10", + "vue-tsc": "^2.1.8" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz", + "integrity": "sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz", + "integrity": "sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz", + "integrity": "sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz", + "integrity": "sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz", + "integrity": "sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz", + "integrity": "sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz", + "integrity": "sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz", + "integrity": "sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz", + "integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz", + "integrity": "sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz", + "integrity": "sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz", + "integrity": "sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz", + "integrity": "sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz", + "integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz", + "integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz", + "integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz", + "integrity": "sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz", + "integrity": "sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.0.tgz", + "integrity": "sha512-7n7KdUEtx/7Yl7I/WVAMZ1bEb0eVvXF3ummWTeLcs/9gvo9pJhuLdouSXGjdZ/MKD1acf1I272+X0RMua4/R3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "2.4.10", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.10.tgz", + "integrity": "sha512-hG3Z13+nJmGaT+fnQzAkS0hjJRa2FCeqZt6Bd+oGNhUkQ+mTFsDETg5rqUTxyzIh5pSOGY7FHCWUS8G82AzLCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.10" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.10", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.10.tgz", + "integrity": "sha512-OCV+b5ihV0RF3A7vEvNyHPi4G4kFa6ukPmyVocmqm5QzOd8r5yAtiNvaPEjl8dNvgC/lj4JPryeeHLdXd62rWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.10", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.10.tgz", + "integrity": "sha512-F8ZtBMhSXyYKuBfGpYwqA5rsONnOwAVvjyE7KPYJ7wgZqo2roASqNWUnianOomJX5u1cxeRooHV59N0PhvEOgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.10", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", + "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.13", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", + "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", + "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.13", + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.11", + "postcss": "^8.4.48", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", + "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", + "dev": true, + "license": "MIT", + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/@vue/language-core": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.1.10.tgz", + "integrity": "sha512-DAI289d0K3AB5TUG3xDp9OuQ71CnrujQwJrQnfuZDwo6eGNf0UoRlPuaVNO+Zrn65PC3j0oB2i7mNmVPggeGeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "~2.4.8", + "@vue/compiler-dom": "^3.5.0", + "@vue/compiler-vue2": "^2.7.16", + "@vue/shared": "^3.5.0", + "alien-signals": "^0.2.0", + "minimatch": "^9.0.3", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz", + "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz", + "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", + "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.13", + "@vue/runtime-core": "3.5.13", + "@vue/shared": "3.5.13", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz", + "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13" + }, + "peerDependencies": { + "vue": "3.5.13" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", + "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", + "license": "MIT" + }, + "node_modules/alien-signals": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-0.2.2.tgz", + "integrity": "sha512-cZIRkbERILsBOXTQmMrxc9hgpxglstn69zm+F1ARf4aPAzdAFYd6sBq87ErO0Fj3DV94tglcyHG5kQz9nDC/8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/magic-string": { + "version": "0.30.13", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.13.tgz", + "integrity": "sha512-8rYBO+MsWkgjDSOvLomYnzhdwEG51olQ4zL5KXnNJWV5MNmrb4rTZdrtkhxjnD/QyZUqR/Z/XDsUs/4ej2nx0g==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz", + "integrity": "sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.27.4", + "@rollup/rollup-android-arm64": "4.27.4", + "@rollup/rollup-darwin-arm64": "4.27.4", + "@rollup/rollup-darwin-x64": "4.27.4", + "@rollup/rollup-freebsd-arm64": "4.27.4", + "@rollup/rollup-freebsd-x64": "4.27.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.27.4", + "@rollup/rollup-linux-arm-musleabihf": "4.27.4", + "@rollup/rollup-linux-arm64-gnu": "4.27.4", + "@rollup/rollup-linux-arm64-musl": "4.27.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.27.4", + "@rollup/rollup-linux-riscv64-gnu": "4.27.4", + "@rollup/rollup-linux-s390x-gnu": "4.27.4", + "@rollup/rollup-linux-x64-gnu": "4.27.4", + "@rollup/rollup-linux-x64-musl": "4.27.4", + "@rollup/rollup-win32-arm64-msvc": "4.27.4", + "@rollup/rollup-win32-ia32-msvc": "4.27.4", + "@rollup/rollup-win32-x64-msvc": "4.27.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "5.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", + "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz", + "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-sfc": "3.5.13", + "@vue/runtime-dom": "3.5.13", + "@vue/server-renderer": "3.5.13", + "@vue/shared": "3.5.13" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-tsc": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.1.10.tgz", + "integrity": "sha512-RBNSfaaRHcN5uqVqJSZh++Gy/YUzryuv9u1aFWhsammDJXNtUiJMNoJ747lZcQ68wUQFx6E73y4FY3D8E7FGMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "~2.4.8", + "@vue/language-core": "2.1.10", + "semver": "^7.5.4" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + } + } + } +} diff --git a/front/package.json b/front/package.json new file mode 100644 index 0000000..a3857a9 --- /dev/null +++ b/front/package.json @@ -0,0 +1,20 @@ +{ + "name": "dombudg", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc -b && vite build", + "preview": "vite preview" + }, + "dependencies": { + "vue": "^3.5.12" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.1.4", + "typescript": "~5.6.2", + "vite": "^5.4.10", + "vue-tsc": "^2.1.8" + } +} diff --git a/front/src/App.vue b/front/src/App.vue new file mode 100644 index 0000000..bbb0db4 --- /dev/null +++ b/front/src/App.vue @@ -0,0 +1,9 @@ + + + + + diff --git a/front/src/main.ts b/front/src/main.ts new file mode 100644 index 0000000..2425c0f --- /dev/null +++ b/front/src/main.ts @@ -0,0 +1,5 @@ +import { createApp } from 'vue' +import './style.css' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/front/src/style.css b/front/src/style.css new file mode 100644 index 0000000..e69de29 diff --git a/front/src/vite-env.d.ts b/front/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/front/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/front/tsconfig.app.json b/front/tsconfig.app.json new file mode 100644 index 0000000..cb88a5a --- /dev/null +++ b/front/tsconfig.app.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/front/tsconfig.json b/front/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/front/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/front/tsconfig.node.json b/front/tsconfig.node.json new file mode 100644 index 0000000..abcd7f0 --- /dev/null +++ b/front/tsconfig.node.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/front/vite.config.ts b/front/vite.config.ts new file mode 100644 index 0000000..bbcf80c --- /dev/null +++ b/front/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [vue()], +}) diff --git a/front/vite.config.ts.timestamp-1732528329064-33d75fbae33f5.mjs b/front/vite.config.ts.timestamp-1732528329064-33d75fbae33f5.mjs new file mode 100644 index 0000000..88c3d34 --- /dev/null +++ b/front/vite.config.ts.timestamp-1732528329064-33d75fbae33f5.mjs @@ -0,0 +1,10 @@ +// vite.config.ts +import { defineConfig } from "file:///C:/Users/MM-NKA/source/repos/domBudg/front/node_modules/vite/dist/node/index.js"; +import vue from "file:///C:/Users/MM-NKA/source/repos/domBudg/front/node_modules/@vitejs/plugin-vue/dist/index.mjs"; +var vite_config_default = defineConfig({ + plugins: [vue()] +}); +export { + vite_config_default as default +}; +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJDOlxcXFxVc2Vyc1xcXFxNTS1OS0FcXFxcc291cmNlXFxcXHJlcG9zXFxcXGRvbUJ1ZGdcXFxcZnJvbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIkM6XFxcXFVzZXJzXFxcXE1NLU5LQVxcXFxzb3VyY2VcXFxccmVwb3NcXFxcZG9tQnVkZ1xcXFxmcm9udFxcXFx2aXRlLmNvbmZpZy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vQzovVXNlcnMvTU0tTktBL3NvdXJjZS9yZXBvcy9kb21CdWRnL2Zyb250L3ZpdGUuY29uZmlnLnRzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcbmltcG9ydCB2dWUgZnJvbSAnQHZpdGVqcy9wbHVnaW4tdnVlJ1xuXG4vLyBodHRwczovL3ZpdGUuZGV2L2NvbmZpZy9cbmV4cG9ydCBkZWZhdWx0IGRlZmluZUNvbmZpZyh7XG4gIHBsdWdpbnM6IFt2dWUoKV0sXG59KVxuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUE4VCxTQUFTLG9CQUFvQjtBQUMzVixPQUFPLFNBQVM7QUFHaEIsSUFBTyxzQkFBUSxhQUFhO0FBQUEsRUFDMUIsU0FBUyxDQUFDLElBQUksQ0FBQztBQUNqQixDQUFDOyIsCiAgIm5hbWVzIjogW10KfQo= From 1e107f86ec81ecccc5bdd45dd7f0ec7edb2439e4 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Mon, 25 Nov 2024 16:05:52 +0400 Subject: [PATCH 03/37] =?UTF-8?q?add:=20=D0=9A=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D0=BA=D1=82=D1=8B=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Contracts/DTOs/UserDTO.cs | 9 +++++++++ back/Contracts/Repositories/IUserRepo.cs | 12 ++++++++++++ back/Contracts/SearchModels/UserSearch.cs | 6 ++++++ back/Contracts/Services/IAuthService.cs | 12 ++++++++++++ back/Contracts/ViewModels/UserViewModel.cs | 8 ++++++++ 5 files changed, 47 insertions(+) create mode 100644 back/Contracts/DTOs/UserDTO.cs create mode 100644 back/Contracts/Repositories/IUserRepo.cs create mode 100644 back/Contracts/SearchModels/UserSearch.cs create mode 100644 back/Contracts/Services/IAuthService.cs create mode 100644 back/Contracts/ViewModels/UserViewModel.cs diff --git a/back/Contracts/DTOs/UserDTO.cs b/back/Contracts/DTOs/UserDTO.cs new file mode 100644 index 0000000..abf5f99 --- /dev/null +++ b/back/Contracts/DTOs/UserDTO.cs @@ -0,0 +1,9 @@ +namespace Contracts.DTO; + +public class UserDto +{ + public Guid? Id { get; set; } + public string? Username { get; set; } + public string? Password { get; set; } + public decimal? Balance { get; set; } +} \ No newline at end of file diff --git a/back/Contracts/Repositories/IUserRepo.cs b/back/Contracts/Repositories/IUserRepo.cs new file mode 100644 index 0000000..3785e5e --- /dev/null +++ b/back/Contracts/Repositories/IUserRepo.cs @@ -0,0 +1,12 @@ +using Contracts.DTO; +using Contracts.SearchModels; + +namespace Contracts.Repositories; + +public interface IUserRepo +{ + public Task Get(UserSearch search); + public Task Create(UserDto user); + public Task Update(UserDto user); + public Task Delete(UserSearch search); +} \ No newline at end of file diff --git a/back/Contracts/SearchModels/UserSearch.cs b/back/Contracts/SearchModels/UserSearch.cs new file mode 100644 index 0000000..7165750 --- /dev/null +++ b/back/Contracts/SearchModels/UserSearch.cs @@ -0,0 +1,6 @@ +namespace Contracts.SearchModels; + +public class UserSearch +{ + public Guid? Id { get; set; } +} \ No newline at end of file diff --git a/back/Contracts/Services/IAuthService.cs b/back/Contracts/Services/IAuthService.cs new file mode 100644 index 0000000..d6e5983 --- /dev/null +++ b/back/Contracts/Services/IAuthService.cs @@ -0,0 +1,12 @@ +using Contracts.DTO; +using Contracts.ViewModels; + +namespace Contracts.Services; + +public interface IAuthService +{ + public Task Login(); + public Task Register(UserDto user); + public Task UpdateUserData(UserDto user); + public Task Delete(Guid id); +} \ No newline at end of file diff --git a/back/Contracts/ViewModels/UserViewModel.cs b/back/Contracts/ViewModels/UserViewModel.cs new file mode 100644 index 0000000..9bf54dc --- /dev/null +++ b/back/Contracts/ViewModels/UserViewModel.cs @@ -0,0 +1,8 @@ +namespace Contracts.ViewModels; + +public class UserViewModel +{ + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public decimal Balance { get; set; } +} \ No newline at end of file From bc7d0ff1568812d738beb2cc5bfde33c5dcdfc6e Mon Sep 17 00:00:00 2001 From: mfnefd Date: Mon, 25 Nov 2024 16:59:13 +0400 Subject: [PATCH 04/37] =?UTF-8?q?add:=20=D0=A1=D0=B5=D1=80=D0=B2=D0=B8?= =?UTF-8?q?=D1=81=D1=8B=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Contracts/DTOs/UserDTO.cs | 8 +-- back/Contracts/DTOs/UserLoginDTO.cs | 7 +++ back/Contracts/Mappers/UserMapper.cs | 16 ++++++ back/Contracts/Repositories/IUserRepo.cs | 2 +- back/Contracts/SearchModels/UserSearch.cs | 1 + back/Contracts/Services/IAuthService.cs | 5 +- back/Contracts/Services/IUserService.cs | 12 +++++ back/Services/Domain/AuthService.cs | 49 +++++++++++++++++++ back/Services/Domain/UserService.cs | 47 ++++++++++++++++++ back/Services/Services.csproj | 4 ++ .../Exceptions/AlreadyExistsException.cs | 9 ++++ .../Exceptions/UserNotFoundException.cs | 11 +++++ 12 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 back/Contracts/DTOs/UserLoginDTO.cs create mode 100644 back/Contracts/Mappers/UserMapper.cs create mode 100644 back/Contracts/Services/IUserService.cs create mode 100644 back/Services/Domain/AuthService.cs create mode 100644 back/Services/Domain/UserService.cs create mode 100644 back/Services/Support/Exceptions/AlreadyExistsException.cs create mode 100644 back/Services/Support/Exceptions/UserNotFoundException.cs diff --git a/back/Contracts/DTOs/UserDTO.cs b/back/Contracts/DTOs/UserDTO.cs index abf5f99..e312313 100644 --- a/back/Contracts/DTOs/UserDTO.cs +++ b/back/Contracts/DTOs/UserDTO.cs @@ -2,8 +2,8 @@ namespace Contracts.DTO; public class UserDto { - public Guid? Id { get; set; } - public string? Username { get; set; } - public string? Password { get; set; } - public decimal? Balance { get; set; } + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public string Password { get; set; } = string.Empty; + public decimal Balance { get; set; } } \ No newline at end of file diff --git a/back/Contracts/DTOs/UserLoginDTO.cs b/back/Contracts/DTOs/UserLoginDTO.cs new file mode 100644 index 0000000..73210e9 --- /dev/null +++ b/back/Contracts/DTOs/UserLoginDTO.cs @@ -0,0 +1,7 @@ +namespace Contracts.DTO; + +public class UserLoginDTO +{ + public string Name { get; set; } = string.Empty; + public string Password { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/back/Contracts/Mappers/UserMapper.cs b/back/Contracts/Mappers/UserMapper.cs new file mode 100644 index 0000000..a32afed --- /dev/null +++ b/back/Contracts/Mappers/UserMapper.cs @@ -0,0 +1,16 @@ +using Contracts.DTO; +using Contracts.ViewModels; + +namespace Contracts.Mappers; + +public static class UserMapper +{ + public static UserViewModel ToView(this UserDto user) + => new() + { + Id = user.Id, + Name = user.Name, + Balance = user.Balance + }; + +} \ No newline at end of file diff --git a/back/Contracts/Repositories/IUserRepo.cs b/back/Contracts/Repositories/IUserRepo.cs index 3785e5e..926450c 100644 --- a/back/Contracts/Repositories/IUserRepo.cs +++ b/back/Contracts/Repositories/IUserRepo.cs @@ -5,7 +5,7 @@ namespace Contracts.Repositories; public interface IUserRepo { - public Task Get(UserSearch search); + public Task Get(UserSearch search); public Task Create(UserDto user); public Task Update(UserDto user); public Task Delete(UserSearch search); diff --git a/back/Contracts/SearchModels/UserSearch.cs b/back/Contracts/SearchModels/UserSearch.cs index 7165750..7ea4178 100644 --- a/back/Contracts/SearchModels/UserSearch.cs +++ b/back/Contracts/SearchModels/UserSearch.cs @@ -3,4 +3,5 @@ namespace Contracts.SearchModels; public class UserSearch { public Guid? Id { get; set; } + public string? Name { get; set; } } \ No newline at end of file diff --git a/back/Contracts/Services/IAuthService.cs b/back/Contracts/Services/IAuthService.cs index d6e5983..03548f7 100644 --- a/back/Contracts/Services/IAuthService.cs +++ b/back/Contracts/Services/IAuthService.cs @@ -1,12 +1,11 @@ using Contracts.DTO; +using Contracts.SearchModels; using Contracts.ViewModels; namespace Contracts.Services; public interface IAuthService { - public Task Login(); + public Task Login(UserLoginDTO loginData); public Task Register(UserDto user); - public Task UpdateUserData(UserDto user); - public Task Delete(Guid id); } \ No newline at end of file diff --git a/back/Contracts/Services/IUserService.cs b/back/Contracts/Services/IUserService.cs new file mode 100644 index 0000000..736d3bf --- /dev/null +++ b/back/Contracts/Services/IUserService.cs @@ -0,0 +1,12 @@ +using Contracts.DTO; +using Contracts.SearchModels; +using Contracts.ViewModels; + +namespace Contracts.Services; + +public interface IUserService +{ + public Task GetDetails(UserSearch search); + public Task UpdateUserData(UserDto user); + public Task Delete(UserSearch search); +} \ No newline at end of file diff --git a/back/Services/Domain/AuthService.cs b/back/Services/Domain/AuthService.cs new file mode 100644 index 0000000..4d59a79 --- /dev/null +++ b/back/Services/Domain/AuthService.cs @@ -0,0 +1,49 @@ +using Contracts.DTO; +using Contracts.Mappers; +using Contracts.Repositories; +using Contracts.SearchModels; +using Contracts.Services; +using Contracts.ViewModels; +using Services.Support.Exceptions; + +namespace Services.Domain; + +public class AuthService : IAuthService +{ + private readonly IUserRepo _userRepo; + + public AuthService(IUserRepo userRepo) + { + _userRepo = userRepo; + } + + public async Task Login(UserLoginDTO loginData) + { + if (loginData == null || string.IsNullOrWhiteSpace(loginData.Name) + || string.IsNullOrWhiteSpace(loginData.Password)) + { + throw new ArgumentException("Неверные данные для входа"); + } + + var user = await _userRepo.Get(new UserSearch() { Name = loginData.Name }); + if (user == null) + { + throw new UserNotFoundException($"Пользователь {loginData.Name} не найден"); + } + + return user.ToView(); + } + + public async Task Register(UserDto user) + { + var existingUser = await _userRepo.Get(new UserSearch() { Name = user.Name }); + if (existingUser != null) + { + throw new AlreadyExistsException("Такой пользователь уже существует"); + } + + var createdUser = await _userRepo.Create(user); + + return createdUser.ToView(); + } +} diff --git a/back/Services/Domain/UserService.cs b/back/Services/Domain/UserService.cs new file mode 100644 index 0000000..e54904d --- /dev/null +++ b/back/Services/Domain/UserService.cs @@ -0,0 +1,47 @@ +using Contracts.DTO; +using Contracts.Mappers; +using Contracts.Repositories; +using Contracts.SearchModels; +using Contracts.Services; +using Contracts.ViewModels; +using Services.Support.Exceptions; + +namespace Services.Domain; + +public class UserService : IUserService +{ + private readonly IUserRepo _userRepo; + + public UserService(IUserRepo userRepo) + { + _userRepo = userRepo; + } + + public async Task Delete(UserSearch search) + { + var user = await _userRepo.Delete(search); + return user.ToView(); + } + + public async Task GetDetails(UserSearch search) + { + var user = await _userRepo.Get(search); + if (user == null) + { + throw new UserNotFoundException($"Пользователь {search.Name} не найден"); + } + return user.ToView(); + } + + public async Task UpdateUserData(UserDto user) + { + var existingUser = await _userRepo.Get(new UserSearch() { Name = user.Name }); + if (existingUser == null) + { + throw new UserNotFoundException($"Пользователь {user.Name} не найден"); + } + + var updatedUser = await _userRepo.Update(user); + return updatedUser.ToView(); + } +} diff --git a/back/Services/Services.csproj b/back/Services/Services.csproj index fa71b7a..3c22415 100644 --- a/back/Services/Services.csproj +++ b/back/Services/Services.csproj @@ -1,5 +1,9 @@  + + + + net8.0 enable diff --git a/back/Services/Support/Exceptions/AlreadyExistsException.cs b/back/Services/Support/Exceptions/AlreadyExistsException.cs new file mode 100644 index 0000000..8577218 --- /dev/null +++ b/back/Services/Support/Exceptions/AlreadyExistsException.cs @@ -0,0 +1,9 @@ +namespace Services.Support.Exceptions; + +public class AlreadyExistsException : Exception +{ + public AlreadyExistsException(string message) : base(message) { } + + public AlreadyExistsException(string message, Exception innerException) + : base(message, innerException) { } +} \ No newline at end of file diff --git a/back/Services/Support/Exceptions/UserNotFoundException.cs b/back/Services/Support/Exceptions/UserNotFoundException.cs new file mode 100644 index 0000000..df152a1 --- /dev/null +++ b/back/Services/Support/Exceptions/UserNotFoundException.cs @@ -0,0 +1,11 @@ +using Contracts.SearchModels; + +namespace Services.Support.Exceptions; + +public class UserNotFoundException : Exception +{ + public UserNotFoundException(string message) + : base(message) { } + public UserNotFoundException(string message, Exception innerException) + : base(message, innerException) { } +} \ No newline at end of file From f7de7ab197491330dd6a9b03497735153ef4f63c Mon Sep 17 00:00:00 2001 From: mfnefd Date: Mon, 25 Nov 2024 17:51:16 +0400 Subject: [PATCH 05/37] =?UTF-8?q?add:=20=D0=A0=D0=B5=D0=BF=D0=BE=D0=B7?= =?UTF-8?q?=D0=B8=D1=82=D0=BE=D1=80=D0=B8=D0=B9=20=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Contracts/Repositories/IUserRepo.cs | 4 +- back/Infrastructure/DatabaseContext.cs | 15 ++++ back/Infrastructure/DbContextFactory.cs | 20 ++++++ back/Infrastructure/Infrastructure.csproj | 12 ++++ back/Infrastructure/Models/User.cs | 25 +++++++ back/Infrastructure/Repositories/UserRepo.cs | 72 +++++++++++++++++++ .../Support/Mappers/UserMapper.cs | 25 +++++++ 7 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 back/Infrastructure/DatabaseContext.cs create mode 100644 back/Infrastructure/DbContextFactory.cs create mode 100644 back/Infrastructure/Models/User.cs create mode 100644 back/Infrastructure/Repositories/UserRepo.cs create mode 100644 back/Infrastructure/Support/Mappers/UserMapper.cs diff --git a/back/Contracts/Repositories/IUserRepo.cs b/back/Contracts/Repositories/IUserRepo.cs index 926450c..ff32390 100644 --- a/back/Contracts/Repositories/IUserRepo.cs +++ b/back/Contracts/Repositories/IUserRepo.cs @@ -7,6 +7,6 @@ public interface IUserRepo { public Task Get(UserSearch search); public Task Create(UserDto user); - public Task Update(UserDto user); - public Task Delete(UserSearch search); + public Task Update(UserDto user); + public Task Delete(UserSearch search); } \ No newline at end of file diff --git a/back/Infrastructure/DatabaseContext.cs b/back/Infrastructure/DatabaseContext.cs new file mode 100644 index 0000000..603765e --- /dev/null +++ b/back/Infrastructure/DatabaseContext.cs @@ -0,0 +1,15 @@ +using Infrastructure.Models; +using Microsoft.EntityFrameworkCore; + +namespace Infrastructure; + +public class DatabaseContext : DbContext +{ + public DatabaseContext(DbContextOptions options) + : base(options) + { + Database.EnsureCreated(); + } + + public DbSet Users { get; set; } = null!; +} \ No newline at end of file diff --git a/back/Infrastructure/DbContextFactory.cs b/back/Infrastructure/DbContextFactory.cs new file mode 100644 index 0000000..00e1443 --- /dev/null +++ b/back/Infrastructure/DbContextFactory.cs @@ -0,0 +1,20 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +namespace Infrastructure; + +public class DbContextFactory : IDbContextFactory +{ + private readonly IServiceProvider _serviceProvider; + + public DbContextFactory(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public DatabaseContext CreateDbContext() + { + var scope = _serviceProvider.CreateScope(); + return scope.ServiceProvider.GetRequiredService(); + } +} \ No newline at end of file diff --git a/back/Infrastructure/Infrastructure.csproj b/back/Infrastructure/Infrastructure.csproj index fa71b7a..28669eb 100644 --- a/back/Infrastructure/Infrastructure.csproj +++ b/back/Infrastructure/Infrastructure.csproj @@ -1,5 +1,17 @@  + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + net8.0 enable diff --git a/back/Infrastructure/Models/User.cs b/back/Infrastructure/Models/User.cs new file mode 100644 index 0000000..f33eda9 --- /dev/null +++ b/back/Infrastructure/Models/User.cs @@ -0,0 +1,25 @@ +using System.Reflection.Metadata.Ecma335; +using Contracts.DTO; + +namespace Infrastructure.Models; + +public class User +{ + public Guid Id { get; set; } + public string Name { get; set; } = null!; + public string Password { get; set; } = null!; + public decimal Balance { get; set; } + + public void Update(UserDto userDto) + { + Id = userDto.Id; + if (!string.IsNullOrWhiteSpace(userDto.Name)) + { + Name = userDto.Name; + } + if (!string.IsNullOrWhiteSpace(userDto.Password)) + { + Password = userDto.Password; + } + } +} \ No newline at end of file diff --git a/back/Infrastructure/Repositories/UserRepo.cs b/back/Infrastructure/Repositories/UserRepo.cs new file mode 100644 index 0000000..d6f6cb5 --- /dev/null +++ b/back/Infrastructure/Repositories/UserRepo.cs @@ -0,0 +1,72 @@ +using Contracts.DTO; +using Contracts.Repositories; +using Contracts.SearchModels; +using Infrastructure.Support.Mappers; +using Microsoft.EntityFrameworkCore; + +namespace Infrastructure.Repositories; + +public class UserRepo : IUserRepo +{ + public readonly DbContextFactory _factory; + + public UserRepo(DbContextFactory factory) + { + _factory = factory; + } + + public async Task Create(UserDto user) + { + using var context = _factory.CreateDbContext(); + + var createdUser = await context.Users.AddAsync(user.ToModel()); + + await context.SaveChangesAsync(); + return createdUser.Entity.ToDto(); + } + + public async Task Delete(UserSearch search) + { + using var context = _factory.CreateDbContext(); + + var user = await context.Users + .FirstOrDefaultAsync(x => x.Id == search.Id + || x.Name == search.Name); + if (user == null) + { + return null; + } + + context.Users.Remove(user); + await context.SaveChangesAsync(); + return user.ToDto(); + } + + public async Task Get(UserSearch search) + { + using var context = _factory.CreateDbContext(); + + var user = await context.Users + .FirstOrDefaultAsync(x => x.Id == search.Id + || x.Name == search.Name); + + return user?.ToDto(); + } + + public async Task Update(UserDto user) + { + using var context = _factory.CreateDbContext(); + + var existingUser = await context.Users.FirstOrDefaultAsync(x => x.Id == user.Id); + + if (existingUser == null) + { + return null; + } + + existingUser.Update(user); + context.Users.Update(existingUser); + await context.SaveChangesAsync(); + return existingUser.ToDto(); + } +} \ No newline at end of file diff --git a/back/Infrastructure/Support/Mappers/UserMapper.cs b/back/Infrastructure/Support/Mappers/UserMapper.cs new file mode 100644 index 0000000..02e47fc --- /dev/null +++ b/back/Infrastructure/Support/Mappers/UserMapper.cs @@ -0,0 +1,25 @@ +using Contracts.DTO; +using Infrastructure.Models; + +namespace Infrastructure.Support.Mappers; + +public static class UserMapper +{ + public static UserDto ToDto(this User user) + => new() + { + Id = user.Id, + Name = user.Name, + Balance = user.Balance, + Password = user.Password + }; + + public static User ToModel(this UserDto user) + => new() + { + Id = user.Id, + Name = user.Name, + Balance = user.Balance, + Password = user.Password + }; +} \ No newline at end of file From e8a6cc2b178bbdf78afe88c781a6fb6a441c2913 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Mon, 25 Nov 2024 18:25:04 +0400 Subject: [PATCH 06/37] =?UTF-8?q?add:=20=D0=9A=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=D1=8B=20=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Controllers/Controllers.csproj | 6 ++ .../Controllers/Controllers/AuthController.cs | 64 +++++++++++++++++++ .../Controllers/Controllers/UserController.cs | 44 +++++++++++++ .../Extensions/AddDbConnectionService.cs | 19 ++++++ .../Extensions/AddDomainServicesExt.cs | 13 ++++ back/Controllers/Extensions/AddReposExt.cs | 14 ++++ back/Controllers/Program.cs | 5 ++ 7 files changed, 165 insertions(+) create mode 100644 back/Controllers/Controllers/AuthController.cs create mode 100644 back/Controllers/Controllers/UserController.cs create mode 100644 back/Controllers/Extensions/AddDbConnectionService.cs create mode 100644 back/Controllers/Extensions/AddDomainServicesExt.cs create mode 100644 back/Controllers/Extensions/AddReposExt.cs diff --git a/back/Controllers/Controllers.csproj b/back/Controllers/Controllers.csproj index 9daa180..34f05b7 100644 --- a/back/Controllers/Controllers.csproj +++ b/back/Controllers/Controllers.csproj @@ -10,4 +10,10 @@ + + + + + + diff --git a/back/Controllers/Controllers/AuthController.cs b/back/Controllers/Controllers/AuthController.cs new file mode 100644 index 0000000..5184f89 --- /dev/null +++ b/back/Controllers/Controllers/AuthController.cs @@ -0,0 +1,64 @@ +using Contracts.DTO; +using Contracts.Services; +using Contracts.ViewModels; +using Microsoft.AspNetCore.Mvc; +using Services.Support.Exceptions; + +namespace Controllers.Controllers +{ + [ApiController] + [Route("api/[controller]")] + public class AuthController : ControllerBase + { + private readonly IAuthService _authService; + + public AuthController(IAuthService authService) + { + _authService = authService; + } + + [HttpPost] + public async Task> Login([FromBody] UserLoginDTO loginData) + { + try + { + var user = await _authService.Login(loginData); + return Ok(user); + } + catch (ArgumentException ex) + { + return BadRequest(ex.Message); + } + catch (UserNotFoundException ex) + { + return NotFound(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + + [HttpPost("register")] + public async Task> Register([FromBody] UserDto user) + { + try + { + var createdUser = await _authService.Register(user); + return CreatedAtAction(nameof(Login), new { name = createdUser.Name }, createdUser); + } + catch (ArgumentException ex) + { + return BadRequest(ex.Message); + } + catch (AlreadyExistsException ex) + { + return Conflict(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + } +} diff --git a/back/Controllers/Controllers/UserController.cs b/back/Controllers/Controllers/UserController.cs new file mode 100644 index 0000000..bfca307 --- /dev/null +++ b/back/Controllers/Controllers/UserController.cs @@ -0,0 +1,44 @@ +using Contracts.DTO; +using Contracts.SearchModels; +using Contracts.Services; +using Contracts.ViewModels; +using Microsoft.AspNetCore.Mvc; + +namespace Controllers.Controllers +{ + [ApiController] + [Route("api/[controller]")] + public class UserController : ControllerBase + { + private readonly IUserService _userService; + + public UserController(IUserService userService) + { + _userService = userService; + } + + [HttpGet] + public async Task> GetUser([FromQuery] UserSearch search) + { + var user = await _userService.GetDetails(search); + + return Ok(user); + } + + [HttpPut] + public async Task> UpdateUser([FromBody] UserDto user) + { + var updatedUser = await _userService.UpdateUserData(user); + + return Ok(updatedUser); + } + + [HttpDelete] + public async Task> DeleteUser([FromQuery] UserSearch search) + { + var deletedUser = await _userService.Delete(search); + + return Ok(deletedUser); + } + } +} diff --git a/back/Controllers/Extensions/AddDbConnectionService.cs b/back/Controllers/Extensions/AddDbConnectionService.cs new file mode 100644 index 0000000..e78595e --- /dev/null +++ b/back/Controllers/Extensions/AddDbConnectionService.cs @@ -0,0 +1,19 @@ +using Infrastructure; +using Microsoft.EntityFrameworkCore; + +namespace Controllers.Extensions; + +public static class DbConnectionServiceExtension +{ + public static void AddDbConnectionService(this IServiceCollection services) + { + var host = Environment.GetEnvironmentVariable("DB_HOST"); + var database = Environment.GetEnvironmentVariable("DB_NAME"); + var username = Environment.GetEnvironmentVariable("DB_USER"); + var password = Environment.GetEnvironmentVariable("DB_PASSWORD"); + var connectionString = $"Host={host};Database={database};Username={username};Password={password}"; + + services.AddDbContext(options => options.UseNpgsql(connectionString)); + services.AddSingleton, DbContextFactory>(); + } +} \ No newline at end of file diff --git a/back/Controllers/Extensions/AddDomainServicesExt.cs b/back/Controllers/Extensions/AddDomainServicesExt.cs new file mode 100644 index 0000000..f68caa1 --- /dev/null +++ b/back/Controllers/Extensions/AddDomainServicesExt.cs @@ -0,0 +1,13 @@ +using Contracts.Services; +using Services.Domain; + +namespace Controllers.Extensions; + +public static class AddDomainServicesExtension +{ + public static void AddDomainServices(this IServiceCollection services) + { + services.AddSingleton(); + services.AddSingleton(); + } +} \ No newline at end of file diff --git a/back/Controllers/Extensions/AddReposExt.cs b/back/Controllers/Extensions/AddReposExt.cs new file mode 100644 index 0000000..27d5b68 --- /dev/null +++ b/back/Controllers/Extensions/AddReposExt.cs @@ -0,0 +1,14 @@ +using Contracts.Repositories; +using Contracts.Services; +using Infrastructure.Repositories; +using Services.Domain; + +namespace Controllers.Extensions; + +public static class AddReposExtension +{ + public static void AddRepos(this IServiceCollection services) + { + services.AddSingleton(); + } +} \ No newline at end of file diff --git a/back/Controllers/Program.cs b/back/Controllers/Program.cs index 48863a6..1bb1553 100644 --- a/back/Controllers/Program.cs +++ b/back/Controllers/Program.cs @@ -1,6 +1,11 @@ +using Controllers.Extensions; + var builder = WebApplication.CreateBuilder(args); // Add services to the container. +builder.Services.AddRepos(); +builder.Services.AddDomainServices(); +builder.Services.AddDbConnectionService(); builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle From 7f30d20c73cae93501a74ed3beb028a4f4d679a5 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Mon, 25 Nov 2024 20:56:39 +0400 Subject: [PATCH 07/37] =?UTF-8?q?fix:=20=D0=BF=D0=BE=D0=B4=D0=BA=D0=BB?= =?UTF-8?q?=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BA=20=D0=B1=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Controllers/Controllers.http | 1 - .../Extensions/AddDbConnectionService.cs | 19 ------- .../Extensions/AddDomainServicesExt.cs | 4 +- back/Controllers/Extensions/AddReposExt.cs | 2 +- .../Extensions/DatabaseSetupExt.cs | 29 +++++++++++ back/Controllers/Program.cs | 6 ++- .../20241125164748_User.Designer.cs | 52 +++++++++++++++++++ .../Migrations/20241125164748_User.cs | 36 +++++++++++++ .../DatabaseContextModelSnapshot.cs | 49 +++++++++++++++++ back/Infrastructure/Repositories/UserRepo.cs | 4 +- 10 files changed, 175 insertions(+), 27 deletions(-) delete mode 100644 back/Controllers/Extensions/AddDbConnectionService.cs create mode 100644 back/Controllers/Extensions/DatabaseSetupExt.cs create mode 100644 back/Infrastructure/Migrations/20241125164748_User.Designer.cs create mode 100644 back/Infrastructure/Migrations/20241125164748_User.cs create mode 100644 back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs diff --git a/back/Controllers/Controllers.http b/back/Controllers/Controllers.http index 01f7fc0..f5c450d 100644 --- a/back/Controllers/Controllers.http +++ b/back/Controllers/Controllers.http @@ -1,6 +1,5 @@ @Controllers_HostAddress = http://localhost:5125 -GET {{Controllers_HostAddress}}/weatherforecast/ Accept: application/json ### diff --git a/back/Controllers/Extensions/AddDbConnectionService.cs b/back/Controllers/Extensions/AddDbConnectionService.cs deleted file mode 100644 index e78595e..0000000 --- a/back/Controllers/Extensions/AddDbConnectionService.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Infrastructure; -using Microsoft.EntityFrameworkCore; - -namespace Controllers.Extensions; - -public static class DbConnectionServiceExtension -{ - public static void AddDbConnectionService(this IServiceCollection services) - { - var host = Environment.GetEnvironmentVariable("DB_HOST"); - var database = Environment.GetEnvironmentVariable("DB_NAME"); - var username = Environment.GetEnvironmentVariable("DB_USER"); - var password = Environment.GetEnvironmentVariable("DB_PASSWORD"); - var connectionString = $"Host={host};Database={database};Username={username};Password={password}"; - - services.AddDbContext(options => options.UseNpgsql(connectionString)); - services.AddSingleton, DbContextFactory>(); - } -} \ No newline at end of file diff --git a/back/Controllers/Extensions/AddDomainServicesExt.cs b/back/Controllers/Extensions/AddDomainServicesExt.cs index f68caa1..f28a69d 100644 --- a/back/Controllers/Extensions/AddDomainServicesExt.cs +++ b/back/Controllers/Extensions/AddDomainServicesExt.cs @@ -7,7 +7,7 @@ public static class AddDomainServicesExtension { public static void AddDomainServices(this IServiceCollection services) { - services.AddSingleton(); - services.AddSingleton(); + services.AddTransient(); + services.AddTransient(); } } \ No newline at end of file diff --git a/back/Controllers/Extensions/AddReposExt.cs b/back/Controllers/Extensions/AddReposExt.cs index 27d5b68..9207a8b 100644 --- a/back/Controllers/Extensions/AddReposExt.cs +++ b/back/Controllers/Extensions/AddReposExt.cs @@ -9,6 +9,6 @@ public static class AddReposExtension { public static void AddRepos(this IServiceCollection services) { - services.AddSingleton(); + services.AddTransient(); } } \ No newline at end of file diff --git a/back/Controllers/Extensions/DatabaseSetupExt.cs b/back/Controllers/Extensions/DatabaseSetupExt.cs new file mode 100644 index 0000000..35752d1 --- /dev/null +++ b/back/Controllers/Extensions/DatabaseSetupExt.cs @@ -0,0 +1,29 @@ +using Infrastructure; +using Microsoft.EntityFrameworkCore; + +namespace Controllers.Extensions; + +public static class DatabaseSetupExtension +{ + public static void AddDbConnectionService(this IServiceCollection services, IConfiguration config) + { + var connectionString = config.GetConnectionString("DefaultConnection") + ?? throw new ArgumentException("Нет строки подключения"); + services.AddDbContext(options => options.UseNpgsql(connectionString)); + services.AddSingleton, DbContextFactory>(); + } + + public static void MigrateDb(this IApplicationBuilder app) + { + try + { + using var scope = app.ApplicationServices.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); + context.Database.Migrate(); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } +} \ No newline at end of file diff --git a/back/Controllers/Program.cs b/back/Controllers/Program.cs index 1bb1553..2e20712 100644 --- a/back/Controllers/Program.cs +++ b/back/Controllers/Program.cs @@ -3,9 +3,9 @@ using Controllers.Extensions; var builder = WebApplication.CreateBuilder(args); // Add services to the container. +builder.Services.AddDbConnectionService(builder.Configuration); builder.Services.AddRepos(); builder.Services.AddDomainServices(); -builder.Services.AddDbConnectionService(); builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle @@ -21,10 +21,12 @@ if (app.Environment.IsDevelopment()) app.UseSwaggerUI(); } +app.MigrateDb(); + app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); -app.Run(); +await app.RunAsync(); diff --git a/back/Infrastructure/Migrations/20241125164748_User.Designer.cs b/back/Infrastructure/Migrations/20241125164748_User.Designer.cs new file mode 100644 index 0000000..9872477 --- /dev/null +++ b/back/Infrastructure/Migrations/20241125164748_User.Designer.cs @@ -0,0 +1,52 @@ +// +using System; +using Infrastructure; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Infrastructure.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20241125164748_User")] + partial class User + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Infrastructure.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Balance") + .HasColumnType("numeric"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Password") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/back/Infrastructure/Migrations/20241125164748_User.cs b/back/Infrastructure/Migrations/20241125164748_User.cs new file mode 100644 index 0000000..f35370d --- /dev/null +++ b/back/Infrastructure/Migrations/20241125164748_User.cs @@ -0,0 +1,36 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Infrastructure.Migrations +{ + /// + public partial class User : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Users", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Name = table.Column(type: "text", nullable: false), + Password = table.Column(type: "text", nullable: false), + Balance = table.Column(type: "numeric", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Users", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Users"); + } + } +} diff --git a/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs b/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs new file mode 100644 index 0000000..1e66849 --- /dev/null +++ b/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs @@ -0,0 +1,49 @@ +// +using System; +using Infrastructure; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Infrastructure.Migrations +{ + [DbContext(typeof(DatabaseContext))] + partial class DatabaseContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Infrastructure.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Balance") + .HasColumnType("numeric"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Password") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/back/Infrastructure/Repositories/UserRepo.cs b/back/Infrastructure/Repositories/UserRepo.cs index d6f6cb5..a075d6d 100644 --- a/back/Infrastructure/Repositories/UserRepo.cs +++ b/back/Infrastructure/Repositories/UserRepo.cs @@ -8,9 +8,9 @@ namespace Infrastructure.Repositories; public class UserRepo : IUserRepo { - public readonly DbContextFactory _factory; + public readonly IDbContextFactory _factory; - public UserRepo(DbContextFactory factory) + public UserRepo(IDbContextFactory factory) { _factory = factory; } From 08a3b74d587e6dc48ed9d22911246244668654fe Mon Sep 17 00:00:00 2001 From: mfnefd Date: Mon, 25 Nov 2024 23:46:53 +0400 Subject: [PATCH 08/37] =?UTF-8?q?add:=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D0=BA=D1=82=D1=8B=20=D0=B3=D1=80=D1=83=D0=BF=D0=BF=20?= =?UTF-8?q?=D1=80=D0=B0=D1=81=D1=85=D0=BE=D0=B4=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Contracts/DTOs/SpendingGroupDto.cs | 8 ++++++++ back/Contracts/Mappers/SpendingGroupMapper.cs | 14 ++++++++++++++ back/Contracts/Repositories/ISpendingGroupRepo.cs | 13 +++++++++++++ back/Contracts/SearchModels/SpendingGroupSearch.cs | 7 +++++++ back/Contracts/Services/ISpendingGroupService.cs | 14 ++++++++++++++ .../Contracts/ViewModels/SpendingGroupViewModel.cs | 7 +++++++ 6 files changed, 63 insertions(+) create mode 100644 back/Contracts/DTOs/SpendingGroupDto.cs create mode 100644 back/Contracts/Mappers/SpendingGroupMapper.cs create mode 100644 back/Contracts/Repositories/ISpendingGroupRepo.cs create mode 100644 back/Contracts/SearchModels/SpendingGroupSearch.cs create mode 100644 back/Contracts/Services/ISpendingGroupService.cs create mode 100644 back/Contracts/ViewModels/SpendingGroupViewModel.cs diff --git a/back/Contracts/DTOs/SpendingGroupDto.cs b/back/Contracts/DTOs/SpendingGroupDto.cs new file mode 100644 index 0000000..cf03704 --- /dev/null +++ b/back/Contracts/DTOs/SpendingGroupDto.cs @@ -0,0 +1,8 @@ +namespace Contracts.DTO; + +public class SpendingGroupDto +{ + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public Guid UserId { get; set; } +} \ No newline at end of file diff --git a/back/Contracts/Mappers/SpendingGroupMapper.cs b/back/Contracts/Mappers/SpendingGroupMapper.cs new file mode 100644 index 0000000..7eca2d3 --- /dev/null +++ b/back/Contracts/Mappers/SpendingGroupMapper.cs @@ -0,0 +1,14 @@ +using Contracts.DTO; +using Contracts.ViewModels; + +namespace Contracts.Mappers; + +public static class SpendingGroupMapper +{ + public static SpendingGroupViewModel ToView(this SpendingGroupDto spendingGroup) + => new() + { + Id = spendingGroup.Id, + Name = spendingGroup.Name + }; +} \ No newline at end of file diff --git a/back/Contracts/Repositories/ISpendingGroupRepo.cs b/back/Contracts/Repositories/ISpendingGroupRepo.cs new file mode 100644 index 0000000..f8f7999 --- /dev/null +++ b/back/Contracts/Repositories/ISpendingGroupRepo.cs @@ -0,0 +1,13 @@ +using Contracts.DTO; +using Contracts.SearchModels; + +namespace Contracts.Repositories; + +public interface ISpendingGroupRepo +{ + Task Get(SpendingGroupSearch search); + Task> GetList(SpendingGroupSearch? search = null); + Task Create(SpendingGroupDto spendingGroup); + Task Delete(SpendingGroupSearch search); + Task Update(SpendingGroupDto spendingGroup); +} diff --git a/back/Contracts/SearchModels/SpendingGroupSearch.cs b/back/Contracts/SearchModels/SpendingGroupSearch.cs new file mode 100644 index 0000000..927a206 --- /dev/null +++ b/back/Contracts/SearchModels/SpendingGroupSearch.cs @@ -0,0 +1,7 @@ +namespace Contracts.SearchModels; + +public class SpendingGroupSearch +{ + public Guid? Id { get; set; } + public string? Name { get; set; } +} \ No newline at end of file diff --git a/back/Contracts/Services/ISpendingGroupService.cs b/back/Contracts/Services/ISpendingGroupService.cs new file mode 100644 index 0000000..e6664ee --- /dev/null +++ b/back/Contracts/Services/ISpendingGroupService.cs @@ -0,0 +1,14 @@ +using Contracts.DTO; +using Contracts.SearchModels; +using Contracts.ViewModels; + +namespace Contracts.Services; + +public interface ISpendingGroupService +{ + Task GetDetails(SpendingGroupSearch search); + Task> GetList(SpendingGroupSearch search); + Task Create(SpendingGroupDto model); + Task Update(SpendingGroupDto model); + Task Delete(SpendingGroupSearch search); +} \ No newline at end of file diff --git a/back/Contracts/ViewModels/SpendingGroupViewModel.cs b/back/Contracts/ViewModels/SpendingGroupViewModel.cs new file mode 100644 index 0000000..12cba2d --- /dev/null +++ b/back/Contracts/ViewModels/SpendingGroupViewModel.cs @@ -0,0 +1,7 @@ +namespace Contracts.ViewModels; + +public class SpendingGroupViewModel +{ + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; +} \ No newline at end of file From 3f7687454705836dea181ec167d606b6176d9d41 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Tue, 26 Nov 2024 00:00:31 +0400 Subject: [PATCH 09/37] =?UTF-8?q?add:=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8?= =?UTF-8?q?=D1=81=20=D0=B3=D1=80=D1=83=D0=BF=D0=BF=20=D1=80=D0=B0=D1=81?= =?UTF-8?q?=D1=85=D0=BE=D0=B4=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Services/Domain/SpendingGroupService.cs | 63 +++++++++++++++++++ .../Exceptions/EntityNotFoundException.cs | 10 +++ .../Exceptions/UserNotFoundException.cs | 3 +- 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 back/Services/Domain/SpendingGroupService.cs create mode 100644 back/Services/Support/Exceptions/EntityNotFoundException.cs diff --git a/back/Services/Domain/SpendingGroupService.cs b/back/Services/Domain/SpendingGroupService.cs new file mode 100644 index 0000000..005ee40 --- /dev/null +++ b/back/Services/Domain/SpendingGroupService.cs @@ -0,0 +1,63 @@ +using Contracts.DTO; +using Contracts.Mappers; +using Contracts.Repositories; +using Contracts.SearchModels; +using Contracts.ViewModels; +using Services.Support.Exceptions; + +namespace Contracts.Services; + +public class SpendingGroupService : ISpendingGroupService +{ + private readonly ISpendingGroupRepo _spendingGroupRepo; + + public SpendingGroupService(ISpendingGroupRepo spendingGroupRepo) + { + _spendingGroupRepo = spendingGroupRepo; + } + + public async Task Create(SpendingGroupDto model) + { + var group = await _spendingGroupRepo.Create(model); + return group.ToView(); + } + + public async Task Delete(SpendingGroupSearch search) + { + var group = await _spendingGroupRepo.Delete(search); + if (group == null) + { + throw new EntityNotFoundException("При удалении не получилось найти группу"); + } + + return group.ToView(); + } + + public async Task GetDetails(SpendingGroupSearch search) + { + var group = await _spendingGroupRepo.Get(search); + if (group == null) + { + throw new EntityNotFoundException("Не удалось найти группу по таким параметрам"); + } + + return group.ToView(); + } + + public async Task> GetList(SpendingGroupSearch search) + { + var groups = await _spendingGroupRepo.GetList(search); + return groups.Select(x => x.ToView()); + } + + public async Task Update(SpendingGroupDto model) + { + var group = await _spendingGroupRepo.Update(model); + if (group == null) + { + throw new EntityNotFoundException("При обновлении не получилось найти группу"); + } + + return group.ToView(); + } +} diff --git a/back/Services/Support/Exceptions/EntityNotFoundException.cs b/back/Services/Support/Exceptions/EntityNotFoundException.cs new file mode 100644 index 0000000..957b0b3 --- /dev/null +++ b/back/Services/Support/Exceptions/EntityNotFoundException.cs @@ -0,0 +1,10 @@ +namespace Services.Support.Exceptions; + +public class EntityNotFoundException : Exception +{ + public EntityNotFoundException(string message) + : base(message) { } + public EntityNotFoundException(string message, Exception innerException) + : base(message, innerException) { } + +} \ No newline at end of file diff --git a/back/Services/Support/Exceptions/UserNotFoundException.cs b/back/Services/Support/Exceptions/UserNotFoundException.cs index df152a1..77b2297 100644 --- a/back/Services/Support/Exceptions/UserNotFoundException.cs +++ b/back/Services/Support/Exceptions/UserNotFoundException.cs @@ -2,10 +2,11 @@ using Contracts.SearchModels; namespace Services.Support.Exceptions; -public class UserNotFoundException : Exception +public class UserNotFoundException : EntityNotFoundException { public UserNotFoundException(string message) : base(message) { } public UserNotFoundException(string message, Exception innerException) : base(message, innerException) { } + } \ No newline at end of file From 6e4e47dc595688c31fac9a8be0a388622702996f Mon Sep 17 00:00:00 2001 From: mfnefd Date: Tue, 26 Nov 2024 00:15:31 +0400 Subject: [PATCH 10/37] =?UTF-8?q?add:=20=D1=80=D0=B5=D0=BF=D0=BE=D0=B7?= =?UTF-8?q?=D0=B8=D1=82=D0=BE=D1=80=D0=B8=D0=B9=20=D0=B3=D1=80=D1=83=D0=BF?= =?UTF-8?q?=D0=BF=20=D1=80=D0=B0=D1=81=D1=85=D0=BE=D0=B4=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Infrastructure/DatabaseContext.cs | 2 + back/Infrastructure/Models/SpendingGroup.cs | 10 ++ .../Repositories/SpendingGroupRepo.cs | 94 +++++++++++++++++++ .../Support/Mappers/SpendingGroupMapper.cs | 22 +++++ 4 files changed, 128 insertions(+) create mode 100644 back/Infrastructure/Models/SpendingGroup.cs create mode 100644 back/Infrastructure/Repositories/SpendingGroupRepo.cs create mode 100644 back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs diff --git a/back/Infrastructure/DatabaseContext.cs b/back/Infrastructure/DatabaseContext.cs index 603765e..051dcb7 100644 --- a/back/Infrastructure/DatabaseContext.cs +++ b/back/Infrastructure/DatabaseContext.cs @@ -1,3 +1,4 @@ +using Contracts.DTO; using Infrastructure.Models; using Microsoft.EntityFrameworkCore; @@ -12,4 +13,5 @@ public class DatabaseContext : DbContext } public DbSet Users { get; set; } = null!; + public DbSet SpendingGroups { get; set; } = null!; } \ No newline at end of file diff --git a/back/Infrastructure/Models/SpendingGroup.cs b/back/Infrastructure/Models/SpendingGroup.cs new file mode 100644 index 0000000..b3d5d20 --- /dev/null +++ b/back/Infrastructure/Models/SpendingGroup.cs @@ -0,0 +1,10 @@ +namespace Infrastructure.Models; + +public class SpendingGroup +{ + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + + public Guid UserId { get; set; } + public User User { get; set; } = null!; +} \ No newline at end of file diff --git a/back/Infrastructure/Repositories/SpendingGroupRepo.cs b/back/Infrastructure/Repositories/SpendingGroupRepo.cs new file mode 100644 index 0000000..38a69d0 --- /dev/null +++ b/back/Infrastructure/Repositories/SpendingGroupRepo.cs @@ -0,0 +1,94 @@ +using Contracts.DTO; +using Contracts.Repositories; +using Contracts.SearchModels; +using Infrastructure.Support.Mappers; +using Microsoft.EntityFrameworkCore; + +namespace Infrastructure.Repositories; + +public class SpendingGroupRepo : ISpendingGroupRepo +{ + public readonly IDbContextFactory _factory; + + public SpendingGroupRepo(IDbContextFactory factory) + { + _factory = factory; + } + + public async Task Create(SpendingGroupDto spendingGroup) + { + using var context = _factory.CreateDbContext(); + + var createdGroup = await context.SpendingGroups.AddAsync(spendingGroup.ToModel()); + await context.SaveChangesAsync(); + return createdGroup.Entity.ToDto(); + } + + public async Task Delete(SpendingGroupSearch search) + { + using var context = _factory.CreateDbContext(); + + var group = await context.SpendingGroups + .FirstOrDefaultAsync(x => x.Id == search.Id + || x.Name == search.Name); + if (group == null) + { + return null; + } + + context.SpendingGroups.Remove(group); + await context.SaveChangesAsync(); + return group.ToDto(); + } + + public async Task Get(SpendingGroupSearch search) + { + using var context = _factory.CreateDbContext(); + + var group = await context.SpendingGroups + .FirstOrDefaultAsync(x => x.Id == search.Id + || x.Name == search.Name); + + return group?.ToDto(); + } + + public async Task> GetList(SpendingGroupSearch? search = null) + { + using var context = _factory.CreateDbContext(); + + var query = context.SpendingGroups.AsQueryable(); + + if (search != null) + { + if (search.Id != null) + { + query = query.Where(x => x.Id == search.Id); + } + + if (!string.IsNullOrWhiteSpace(search.Name)) + { + query = query.Where(x => x.Name.Contains(search.Name, StringComparison.OrdinalIgnoreCase)); + } + } + + return await query.Select(x => x.ToDto()).ToListAsync(); + } + + public async Task Update(SpendingGroupDto spendingGroup) + { + using var context = _factory.CreateDbContext(); + + var existingGroup = await context.SpendingGroups + .FirstOrDefaultAsync(x => x.Id == spendingGroup.Id); + + if (existingGroup == null) + { + return null; + } + + existingGroup.Name = spendingGroup.Name; + context.SpendingGroups.Update(existingGroup); + await context.SaveChangesAsync(); + return existingGroup.ToDto(); + } +} diff --git a/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs b/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs new file mode 100644 index 0000000..94a39b6 --- /dev/null +++ b/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs @@ -0,0 +1,22 @@ +using Contracts.DTO; +using Infrastructure.Models; + +namespace Infrastructure.Support.Mappers; + +public static class SpendingGroupMapper +{ + public static SpendingGroupDto ToDto(this SpendingGroup group) + => new() + { + Id = group.Id, + Name = group.Name, + UserId = group.UserId + }; + public static SpendingGroup ToModel(this SpendingGroupDto group) + => new() + { + Id = group.Id, + Name = group.Name, + UserId = group.UserId + }; +} \ No newline at end of file From 078b46975249f8a787ae7ae4893e2b0f6813b7a2 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Tue, 26 Nov 2024 00:33:48 +0400 Subject: [PATCH 11/37] =?UTF-8?q?add:=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=20=D0=B3=D1=80=D1=83=D0=BF=D0=BF?= =?UTF-8?q?=20=D1=80=D0=B0=D1=81=D1=85=D0=BE=D0=B4=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/ISpendingGroupService.cs | 2 +- .../Controllers/SpendingGroupController.cs | 118 ++++++++++++++++++ 2 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 back/Controllers/Controllers/SpendingGroupController.cs diff --git a/back/Contracts/Services/ISpendingGroupService.cs b/back/Contracts/Services/ISpendingGroupService.cs index e6664ee..938806f 100644 --- a/back/Contracts/Services/ISpendingGroupService.cs +++ b/back/Contracts/Services/ISpendingGroupService.cs @@ -7,7 +7,7 @@ namespace Contracts.Services; public interface ISpendingGroupService { Task GetDetails(SpendingGroupSearch search); - Task> GetList(SpendingGroupSearch search); + Task> GetList(SpendingGroupSearch? search = null); Task Create(SpendingGroupDto model); Task Update(SpendingGroupDto model); Task Delete(SpendingGroupSearch search); diff --git a/back/Controllers/Controllers/SpendingGroupController.cs b/back/Controllers/Controllers/SpendingGroupController.cs new file mode 100644 index 0000000..36ad45b --- /dev/null +++ b/back/Controllers/Controllers/SpendingGroupController.cs @@ -0,0 +1,118 @@ +namespace Controllers.Extensions; + +using Contracts.DTO; +using Contracts.SearchModels; +using Contracts.Services; +using Contracts.ViewModels; +using Microsoft.AspNetCore.Mvc; +using Services.Support.Exceptions; + +[ApiController] +[Route("api/[controller]")] +public class SpendingGroupController : ControllerBase +{ + private readonly ISpendingGroupService _spendingGroupService; + + public SpendingGroupController(ISpendingGroupService spendingGroupService) + { + _spendingGroupService = spendingGroupService; + } + [HttpGet("details")] + public async Task> GetSpendingGroup( + [FromQuery] SpendingGroupSearch search) + { + try + { + var group = await _spendingGroupService.GetDetails(search); + return Ok(group); + } + catch (EntityNotFoundException ex) + { + return NotFound(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + + [HttpGet] + public async Task>> GetSpendingGroups() + { + try + { + var groups = await _spendingGroupService.GetList(); + return Ok(groups); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + + [HttpGet("filter")] + public async Task>> GetSpendingGroups( + [FromQuery] SpendingGroupSearch search) + { + try + { + var groups = await _spendingGroupService.GetList(search); + return Ok(groups); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + + [HttpPost] + public async Task> CreateSpendingGroup( + [FromBody] SpendingGroupDto dto) + { + try + { + var group = await _spendingGroupService.Create(dto); + return CreatedAtAction(nameof(GetSpendingGroup), new { id = group.Id }, group); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + + [HttpPatch] + public async Task> UpdateSpendingGroup([FromBody] SpendingGroupDto dto) + { + try + { + var group = await _spendingGroupService.Update(dto); + return Ok(group); + } + catch (EntityNotFoundException ex) + { + return NotFound(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + + [HttpDelete] + public async Task DeleteSpendingGroup([FromQuery] SpendingGroupSearch search) + { + try + { + var group = await _spendingGroupService.Delete(search); + return Ok(group); + } + catch (EntityNotFoundException ex) + { + return NotFound(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } +} \ No newline at end of file From 43b00bfc2fc8e1d9b1dc72c9045425e8a3dd2328 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Tue, 26 Nov 2024 00:34:57 +0400 Subject: [PATCH 12/37] =?UTF-8?q?fix:=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=D1=8B=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=20try=20catch=20=D0=B2=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8F,?= =?UTF-8?q?=20=D1=80=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE=D1=80=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=20=D0=B0?= =?UTF-8?q?=D0=B2=D1=82=D0=BE=D1=80=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/Controllers/AuthController.cs | 95 +++++++++---------- .../Controllers/Controllers/UserController.cs | 69 ++++++++++---- 2 files changed, 96 insertions(+), 68 deletions(-) diff --git a/back/Controllers/Controllers/AuthController.cs b/back/Controllers/Controllers/AuthController.cs index 5184f89..15eb928 100644 --- a/back/Controllers/Controllers/AuthController.cs +++ b/back/Controllers/Controllers/AuthController.cs @@ -4,61 +4,60 @@ using Contracts.ViewModels; using Microsoft.AspNetCore.Mvc; using Services.Support.Exceptions; -namespace Controllers.Controllers +namespace Controllers.Controllers; + +[ApiController] +[Route("api/[controller]")] +public class AuthController : ControllerBase { - [ApiController] - [Route("api/[controller]")] - public class AuthController : ControllerBase + private readonly IAuthService _authService; + + public AuthController(IAuthService authService) { - private readonly IAuthService _authService; + _authService = authService; + } - public AuthController(IAuthService authService) + [HttpPost] + public async Task> Login([FromBody] UserLoginDTO loginData) + { + try { - _authService = authService; + var user = await _authService.Login(loginData); + return Ok(user); } - - [HttpPost] - public async Task> Login([FromBody] UserLoginDTO loginData) + catch (ArgumentException ex) { - try - { - var user = await _authService.Login(loginData); - return Ok(user); - } - catch (ArgumentException ex) - { - return BadRequest(ex.Message); - } - catch (UserNotFoundException ex) - { - return NotFound(ex.Message); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } + return BadRequest(ex.Message); } - - [HttpPost("register")] - public async Task> Register([FromBody] UserDto user) + catch (UserNotFoundException ex) { - try - { - var createdUser = await _authService.Register(user); - return CreatedAtAction(nameof(Login), new { name = createdUser.Name }, createdUser); - } - catch (ArgumentException ex) - { - return BadRequest(ex.Message); - } - catch (AlreadyExistsException ex) - { - return Conflict(ex.Message); - } - catch (Exception ex) - { - return StatusCode(500, ex.Message); - } + return NotFound(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); } } -} + + [HttpPost("register")] + public async Task> Register([FromBody] UserDto user) + { + try + { + var createdUser = await _authService.Register(user); + return CreatedAtAction(nameof(Login), new { name = createdUser.Name }, createdUser); + } + catch (ArgumentException ex) + { + return BadRequest(ex.Message); + } + catch (AlreadyExistsException ex) + { + return Conflict(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } +} \ No newline at end of file diff --git a/back/Controllers/Controllers/UserController.cs b/back/Controllers/Controllers/UserController.cs index bfca307..c93c276 100644 --- a/back/Controllers/Controllers/UserController.cs +++ b/back/Controllers/Controllers/UserController.cs @@ -3,42 +3,71 @@ using Contracts.SearchModels; using Contracts.Services; using Contracts.ViewModels; using Microsoft.AspNetCore.Mvc; +using Services.Support.Exceptions; -namespace Controllers.Controllers +namespace Controllers.Controllers; + +[ApiController] +[Route("api/[controller]")] +public class UserController : ControllerBase { - [ApiController] - [Route("api/[controller]")] - public class UserController : ControllerBase + private readonly IUserService _userService; + + public UserController(IUserService userService) { - private readonly IUserService _userService; - - public UserController(IUserService userService) - { - _userService = userService; - } - - [HttpGet] - public async Task> GetUser([FromQuery] UserSearch search) + _userService = userService; + } + [HttpGet] + public async Task> GetUser([FromQuery] UserSearch search) + { + try { var user = await _userService.GetDetails(search); - return Ok(user); } + catch (UserNotFoundException ex) + { + return NotFound(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } - [HttpPut] - public async Task> UpdateUser([FromBody] UserDto user) + [HttpPatch] + public async Task> UpdateUser([FromBody] UserDto user) + { + try { var updatedUser = await _userService.UpdateUserData(user); - return Ok(updatedUser); } + catch (UserNotFoundException ex) + { + return NotFound(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } - [HttpDelete] - public async Task> DeleteUser([FromQuery] UserSearch search) + [HttpDelete] + public async Task> DeleteUser([FromQuery] UserSearch search) + { + try { var deletedUser = await _userService.Delete(search); - return Ok(deletedUser); } + catch (UserNotFoundException ex) + { + return NotFound(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } } } From f0bdffeb86f56d0136e05d494e3910c77502a92d Mon Sep 17 00:00:00 2001 From: mfnefd Date: Tue, 26 Nov 2024 20:23:59 +0400 Subject: [PATCH 13/37] =?UTF-8?q?fix:=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=BD=D0=BE=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0?= =?UTF-8?q?=D0=B5=D1=82=20=D0=BA=D1=80=D1=83=D0=B4=20=D0=B3=D1=80=D1=83?= =?UTF-8?q?=D0=BF=D0=BF=20=D1=80=D0=B0=D1=81=D1=85=D0=BE=D0=B4=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Controllers/Controllers.csproj | 4 + .../Extensions/AddDomainServicesExt.cs | 2 + back/Controllers/Extensions/AddReposExt.cs | 1 + .../Extensions/DatabaseSetupExt.cs | 5 +- back/Infrastructure/DatabaseContext.cs | 1 - back/Infrastructure/Infrastructure.csproj | 4 - .../20241126140310_SpendingGroup.Designer.cs | 88 +++++++++++++++++++ .../20241126140310_SpendingGroup.cs | 46 ++++++++++ .../DatabaseContextModelSnapshot.cs | 36 ++++++++ back/Infrastructure/Models/User.cs | 1 + back/Services/Domain/SpendingGroupService.cs | 2 +- back/Services/Domain/UserService.cs | 14 +-- 12 files changed, 190 insertions(+), 14 deletions(-) create mode 100644 back/Infrastructure/Migrations/20241126140310_SpendingGroup.Designer.cs create mode 100644 back/Infrastructure/Migrations/20241126140310_SpendingGroup.cs diff --git a/back/Controllers/Controllers.csproj b/back/Controllers/Controllers.csproj index 34f05b7..03a20aa 100644 --- a/back/Controllers/Controllers.csproj +++ b/back/Controllers/Controllers.csproj @@ -7,6 +7,10 @@ + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/back/Controllers/Extensions/AddDomainServicesExt.cs b/back/Controllers/Extensions/AddDomainServicesExt.cs index f28a69d..575d50a 100644 --- a/back/Controllers/Extensions/AddDomainServicesExt.cs +++ b/back/Controllers/Extensions/AddDomainServicesExt.cs @@ -9,5 +9,7 @@ public static class AddDomainServicesExtension { services.AddTransient(); services.AddTransient(); + + services.AddTransient(); } } \ No newline at end of file diff --git a/back/Controllers/Extensions/AddReposExt.cs b/back/Controllers/Extensions/AddReposExt.cs index 9207a8b..d019ce0 100644 --- a/back/Controllers/Extensions/AddReposExt.cs +++ b/back/Controllers/Extensions/AddReposExt.cs @@ -10,5 +10,6 @@ public static class AddReposExtension public static void AddRepos(this IServiceCollection services) { services.AddTransient(); + services.AddTransient(); } } \ No newline at end of file diff --git a/back/Controllers/Extensions/DatabaseSetupExt.cs b/back/Controllers/Extensions/DatabaseSetupExt.cs index 35752d1..0f72055 100644 --- a/back/Controllers/Extensions/DatabaseSetupExt.cs +++ b/back/Controllers/Extensions/DatabaseSetupExt.cs @@ -18,8 +18,9 @@ public static class DatabaseSetupExtension try { using var scope = app.ApplicationServices.CreateScope(); - var context = scope.ServiceProvider.GetRequiredService(); - context.Database.Migrate(); + var context = scope.ServiceProvider.GetRequiredService>(); + using var db = context.CreateDbContext(); + db.Database.Migrate(); } catch (Exception ex) { diff --git a/back/Infrastructure/DatabaseContext.cs b/back/Infrastructure/DatabaseContext.cs index 051dcb7..6901ea8 100644 --- a/back/Infrastructure/DatabaseContext.cs +++ b/back/Infrastructure/DatabaseContext.cs @@ -9,7 +9,6 @@ public class DatabaseContext : DbContext public DatabaseContext(DbContextOptions options) : base(options) { - Database.EnsureCreated(); } public DbSet Users { get; set; } = null!; diff --git a/back/Infrastructure/Infrastructure.csproj b/back/Infrastructure/Infrastructure.csproj index 28669eb..0d0625a 100644 --- a/back/Infrastructure/Infrastructure.csproj +++ b/back/Infrastructure/Infrastructure.csproj @@ -5,10 +5,6 @@ - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - diff --git a/back/Infrastructure/Migrations/20241126140310_SpendingGroup.Designer.cs b/back/Infrastructure/Migrations/20241126140310_SpendingGroup.Designer.cs new file mode 100644 index 0000000..0ae4d47 --- /dev/null +++ b/back/Infrastructure/Migrations/20241126140310_SpendingGroup.Designer.cs @@ -0,0 +1,88 @@ +// +using System; +using Infrastructure; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Infrastructure.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20241126140310_SpendingGroup")] + partial class SpendingGroup + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("SpendingGroups"); + }); + + modelBuilder.Entity("Infrastructure.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Balance") + .HasColumnType("numeric"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Password") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => + { + b.HasOne("Infrastructure.Models.User", "User") + .WithMany("SpendingGroups") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Infrastructure.Models.User", b => + { + b.Navigation("SpendingGroups"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/back/Infrastructure/Migrations/20241126140310_SpendingGroup.cs b/back/Infrastructure/Migrations/20241126140310_SpendingGroup.cs new file mode 100644 index 0000000..1632633 --- /dev/null +++ b/back/Infrastructure/Migrations/20241126140310_SpendingGroup.cs @@ -0,0 +1,46 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Infrastructure.Migrations +{ + /// + public partial class SpendingGroup : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "SpendingGroups", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Name = table.Column(type: "text", nullable: false), + UserId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SpendingGroups", x => x.Id); + table.ForeignKey( + name: "FK_SpendingGroups_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_SpendingGroups_UserId", + table: "SpendingGroups", + column: "UserId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "SpendingGroups"); + } + } +} diff --git a/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs b/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs index 1e66849..201a211 100644 --- a/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs +++ b/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs @@ -22,6 +22,26 @@ namespace Infrastructure.Migrations NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("SpendingGroups"); + }); + modelBuilder.Entity("Infrastructure.Models.User", b => { b.Property("Id") @@ -43,6 +63,22 @@ namespace Infrastructure.Migrations b.ToTable("Users"); }); + + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => + { + b.HasOne("Infrastructure.Models.User", "User") + .WithMany("SpendingGroups") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Infrastructure.Models.User", b => + { + b.Navigation("SpendingGroups"); + }); #pragma warning restore 612, 618 } } diff --git a/back/Infrastructure/Models/User.cs b/back/Infrastructure/Models/User.cs index f33eda9..add673c 100644 --- a/back/Infrastructure/Models/User.cs +++ b/back/Infrastructure/Models/User.cs @@ -9,6 +9,7 @@ public class User public string Name { get; set; } = null!; public string Password { get; set; } = null!; public decimal Balance { get; set; } + public List? SpendingGroups { get; set; } public void Update(UserDto userDto) { diff --git a/back/Services/Domain/SpendingGroupService.cs b/back/Services/Domain/SpendingGroupService.cs index 005ee40..b0afed1 100644 --- a/back/Services/Domain/SpendingGroupService.cs +++ b/back/Services/Domain/SpendingGroupService.cs @@ -47,7 +47,7 @@ public class SpendingGroupService : ISpendingGroupService public async Task> GetList(SpendingGroupSearch search) { var groups = await _spendingGroupRepo.GetList(search); - return groups.Select(x => x.ToView()); + return groups.Select(x => x.ToView()).ToList(); } public async Task Update(SpendingGroupDto model) diff --git a/back/Services/Domain/UserService.cs b/back/Services/Domain/UserService.cs index e54904d..5f6f2c5 100644 --- a/back/Services/Domain/UserService.cs +++ b/back/Services/Domain/UserService.cs @@ -20,6 +20,10 @@ public class UserService : IUserService public async Task Delete(UserSearch search) { var user = await _userRepo.Delete(search); + if (user == null) + { + throw new UserNotFoundException($"Пользователь для удаления не найден"); + } return user.ToView(); } @@ -35,13 +39,11 @@ public class UserService : IUserService public async Task UpdateUserData(UserDto user) { - var existingUser = await _userRepo.Get(new UserSearch() { Name = user.Name }); - if (existingUser == null) - { - throw new UserNotFoundException($"Пользователь {user.Name} не найден"); - } - var updatedUser = await _userRepo.Update(user); + if (updatedUser == null) + { + throw new EntityNotFoundException("При обновлении не получилось найти пользователя с id = " + user.Id); + } return updatedUser.ToView(); } } From 27df19201ae13a4843980386bc9f9a0c1eea5315 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Tue, 26 Nov 2024 20:56:22 +0400 Subject: [PATCH 14/37] =?UTF-8?q?add:=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D0=BA=D1=82=D1=8B=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D0=B8?= =?UTF-8?q?=20=D1=80=D0=B0=D1=81=D1=85=D0=BE=D0=B4=D0=BE=D0=B2=20=D0=B8=20?= =?UTF-8?q?=D0=B4=D0=BE=D1=85=D0=BE=D0=B4=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Contracts/DTOs/ChangeRecordDto.cs | 10 ++++++++++ back/Contracts/Mappers/ChangeRecordMapper.cs | 15 +++++++++++++++ back/Contracts/Repositories/IChangeRecordRepo.cs | 13 +++++++++++++ back/Contracts/SearchModels/ChangeRecordSearch.cs | 9 +++++++++ back/Contracts/Services/IChangeRecordService.cs | 13 +++++++++++++ .../Contracts/ViewModels/ChangeRecordViewModel.cs | 8 ++++++++ 6 files changed, 68 insertions(+) create mode 100644 back/Contracts/DTOs/ChangeRecordDto.cs create mode 100644 back/Contracts/Mappers/ChangeRecordMapper.cs create mode 100644 back/Contracts/Repositories/IChangeRecordRepo.cs create mode 100644 back/Contracts/SearchModels/ChangeRecordSearch.cs create mode 100644 back/Contracts/Services/IChangeRecordService.cs create mode 100644 back/Contracts/ViewModels/ChangeRecordViewModel.cs diff --git a/back/Contracts/DTOs/ChangeRecordDto.cs b/back/Contracts/DTOs/ChangeRecordDto.cs new file mode 100644 index 0000000..9950fb9 --- /dev/null +++ b/back/Contracts/DTOs/ChangeRecordDto.cs @@ -0,0 +1,10 @@ +namespace Contracts.DTO; + +public interface ChangeRecordDto +{ + public Guid Id { get; set; } + public Guid UserId { get; set; } + public Guid SpendingGroupId { get; set; } + public decimal Sum { get; set; } + public DateTime ChangedAt { get; set; } +} \ No newline at end of file diff --git a/back/Contracts/Mappers/ChangeRecordMapper.cs b/back/Contracts/Mappers/ChangeRecordMapper.cs new file mode 100644 index 0000000..a6075c4 --- /dev/null +++ b/back/Contracts/Mappers/ChangeRecordMapper.cs @@ -0,0 +1,15 @@ +using Contracts.DTO; +using Contracts.ViewModels; + +namespace Contracts.Mappers; + +public static class ChangeRecordMapper +{ + public static ChangeRecordViewModel ToView(this ChangeRecordDto changeRecord) + => new() + { + Id = changeRecord.Id, + Sum = changeRecord.Sum, + ChangedAt = changeRecord.ChangedAt + }; +} \ No newline at end of file diff --git a/back/Contracts/Repositories/IChangeRecordRepo.cs b/back/Contracts/Repositories/IChangeRecordRepo.cs new file mode 100644 index 0000000..d8e835e --- /dev/null +++ b/back/Contracts/Repositories/IChangeRecordRepo.cs @@ -0,0 +1,13 @@ +using Contracts.DTO; +using Contracts.SearchModels; + +namespace Contracts.Repositories; + +public interface IChangeRecordRepo +{ + Task Create(ChangeRecordDto changeRecord); + Task Get(ChangeRecordSearch search); + Task> GetList(ChangeRecordSearch? search = null); + Task Update(ChangeRecordDto changeRecord); + Task Delete(ChangeRecordSearch search); +} \ No newline at end of file diff --git a/back/Contracts/SearchModels/ChangeRecordSearch.cs b/back/Contracts/SearchModels/ChangeRecordSearch.cs new file mode 100644 index 0000000..65a5094 --- /dev/null +++ b/back/Contracts/SearchModels/ChangeRecordSearch.cs @@ -0,0 +1,9 @@ +namespace Contracts.SearchModels; + +public class ChangeRecordSearch +{ + public Guid? Id { get; set; } + public Guid? SpendingGroupId { get; set; } + public DateTime? From { get; set; } + public DateTime? To { get; set; } +} \ No newline at end of file diff --git a/back/Contracts/Services/IChangeRecordService.cs b/back/Contracts/Services/IChangeRecordService.cs new file mode 100644 index 0000000..9dd0832 --- /dev/null +++ b/back/Contracts/Services/IChangeRecordService.cs @@ -0,0 +1,13 @@ +using Contracts.DTO; +using Contracts.SearchModels; +using Contracts.ViewModels; + +namespace Contracts.Services; + +public interface IChangeRecordService +{ + Task Create(ChangeRecordDto model); + Task Update(ChangeRecordDto model); + Task Delete(ChangeRecordSearch search); + Task> GetList(ChangeRecordSearch search); +} \ No newline at end of file diff --git a/back/Contracts/ViewModels/ChangeRecordViewModel.cs b/back/Contracts/ViewModels/ChangeRecordViewModel.cs new file mode 100644 index 0000000..3a75eb3 --- /dev/null +++ b/back/Contracts/ViewModels/ChangeRecordViewModel.cs @@ -0,0 +1,8 @@ +namespace Contracts.ViewModels; + +public class ChangeRecordViewModel +{ + public Guid Id { get; set; } + public decimal Sum { get; set; } + public DateTime ChangedAt { get; set; } +} \ No newline at end of file From f94d4ed246e696096acf209abbffd114659fa9eb Mon Sep 17 00:00:00 2001 From: mfnefd Date: Tue, 26 Nov 2024 22:11:17 +0400 Subject: [PATCH 15/37] =?UTF-8?q?add:=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8?= =?UTF-8?q?=D1=81,=20=D1=80=D0=B5=D0=BF=D0=BE=D0=B7=D0=B8=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=B9=20=D0=B8=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D1=8C=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D0=B8=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B1=D0=B0=D0=BB?= =?UTF-8?q?=D0=B0=D0=BD=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Contracts/DTOs/ChangeRecordDto.cs | 2 +- back/Infrastructure/DatabaseContext.cs | 1 + back/Infrastructure/Models/Changerecord.cs | 24 +++++ .../Repositories/ChangeRecordRepo.cs | 94 +++++++++++++++++++ .../Support/Mappers/ChangeRecordMapper.cs | 27 ++++++ back/Services/Domain/ChangeRecordService.cs | 52 ++++++++++ 6 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 back/Infrastructure/Models/Changerecord.cs create mode 100644 back/Infrastructure/Repositories/ChangeRecordRepo.cs create mode 100644 back/Infrastructure/Support/Mappers/ChangeRecordMapper.cs create mode 100644 back/Services/Domain/ChangeRecordService.cs diff --git a/back/Contracts/DTOs/ChangeRecordDto.cs b/back/Contracts/DTOs/ChangeRecordDto.cs index 9950fb9..f95da9c 100644 --- a/back/Contracts/DTOs/ChangeRecordDto.cs +++ b/back/Contracts/DTOs/ChangeRecordDto.cs @@ -1,6 +1,6 @@ namespace Contracts.DTO; -public interface ChangeRecordDto +public class ChangeRecordDto { public Guid Id { get; set; } public Guid UserId { get; set; } diff --git a/back/Infrastructure/DatabaseContext.cs b/back/Infrastructure/DatabaseContext.cs index 6901ea8..02afad7 100644 --- a/back/Infrastructure/DatabaseContext.cs +++ b/back/Infrastructure/DatabaseContext.cs @@ -13,4 +13,5 @@ public class DatabaseContext : DbContext public DbSet Users { get; set; } = null!; public DbSet SpendingGroups { get; set; } = null!; + public DbSet ChangeRecords { get; set; } = null!; } \ No newline at end of file diff --git a/back/Infrastructure/Models/Changerecord.cs b/back/Infrastructure/Models/Changerecord.cs new file mode 100644 index 0000000..4f9a5e9 --- /dev/null +++ b/back/Infrastructure/Models/Changerecord.cs @@ -0,0 +1,24 @@ +using Contracts.DTO; + +namespace Infrastructure.Models; + +public class ChangeRecord +{ + public Guid Id { get; set; } + public decimal Sum { get; set; } + public DateTime ChangedAt { get; set; } + + public Guid UserId { get; set; } + public User User { get; set; } = null!; + + public Guid SpendingGroupId { get; set; } + public SpendingGroup SpendingGroup { get; set; } = null!; + + public void Update(ChangeRecordDto changeRecordDto) + { + Id = changeRecordDto.Id; + Sum = changeRecordDto.Sum; + ChangedAt = changeRecordDto.ChangedAt; + SpendingGroupId = changeRecordDto.SpendingGroupId; + } +} \ No newline at end of file diff --git a/back/Infrastructure/Repositories/ChangeRecordRepo.cs b/back/Infrastructure/Repositories/ChangeRecordRepo.cs new file mode 100644 index 0000000..cafeb2d --- /dev/null +++ b/back/Infrastructure/Repositories/ChangeRecordRepo.cs @@ -0,0 +1,94 @@ +using Contracts.DTO; +using Contracts.Repositories; +using Contracts.SearchModels; +using Infrastructure.Support.Mappers; +using Microsoft.EntityFrameworkCore; + +namespace Infrastructure.Repositories; + +public class ChangeRecordRepo : IChangeRecordRepo +{ + public readonly IDbContextFactory _factory; + + public ChangeRecordRepo(IDbContextFactory factory) + { + _factory = factory; + } + + public async Task Create(ChangeRecordDto changeRecord) + { + using var context = _factory.CreateDbContext(); + + var createdRecord = await context.ChangeRecords.AddAsync(changeRecord.ToModel()); + + await context.SaveChangesAsync(); + return createdRecord.Entity.ToDto(); + } + + public async Task Delete(ChangeRecordSearch search) + { + using var context = _factory.CreateDbContext(); + + var record = await context.ChangeRecords + .FirstOrDefaultAsync(x => x.Id == search.Id); + if (record == null) + { + return null; + } + + context.ChangeRecords.Remove(record); + await context.SaveChangesAsync(); + return record.ToDto(); + } + + public async Task Get(ChangeRecordSearch search) + { + using var context = _factory.CreateDbContext(); + + var record = await context.ChangeRecords + .FirstOrDefaultAsync(x => x.Id == search.Id); + if (record == null) + { + return null; + } + return record.ToDto(); + } + + public async Task> GetList(ChangeRecordSearch? search = null) + { + using var context = _factory.CreateDbContext(); + + var query = context.ChangeRecords.AsQueryable(); + + if (search != null) + { + if (search.SpendingGroupId.HasValue) + { + query = query.Where(x => x.SpendingGroupId == search.SpendingGroupId); + } + if (search.From.HasValue && search.To.HasValue) + { + query = query.Where(x => x.ChangedAt >= search.From && x.ChangedAt <= search.To); + } + } + return query.Select(x => x.ToDto()); + } + + public async Task Update(ChangeRecordDto changeRecord) + { + using var context = _factory.CreateDbContext(); + + var existingRecord = await context.ChangeRecords + .FirstOrDefaultAsync(x => x.Id == changeRecord.Id); + + if (existingRecord == null) + { + return null; + } + + existingRecord.Update(changeRecord); + context.ChangeRecords.Update(existingRecord); + await context.SaveChangesAsync(); + return existingRecord.ToDto(); + } +} diff --git a/back/Infrastructure/Support/Mappers/ChangeRecordMapper.cs b/back/Infrastructure/Support/Mappers/ChangeRecordMapper.cs new file mode 100644 index 0000000..cd5d76e --- /dev/null +++ b/back/Infrastructure/Support/Mappers/ChangeRecordMapper.cs @@ -0,0 +1,27 @@ +using Contracts.DTO; +using Infrastructure.Models; + +namespace Infrastructure.Support.Mappers; + +public static class ChangeRecordMapper +{ + public static ChangeRecordDto ToDto(this ChangeRecord changeRecord) + => new() + { + Id = changeRecord.Id, + Sum = changeRecord.Sum, + ChangedAt = changeRecord.ChangedAt, + SpendingGroupId = changeRecord.SpendingGroupId, + UserId = changeRecord.UserId + }; + + public static ChangeRecord ToModel(this ChangeRecordDto changeRecord) + => new() + { + Id = changeRecord.Id, + Sum = changeRecord.Sum, + ChangedAt = changeRecord.ChangedAt, + SpendingGroupId = changeRecord.SpendingGroupId, + UserId = changeRecord.UserId + }; +} \ No newline at end of file diff --git a/back/Services/Domain/ChangeRecordService.cs b/back/Services/Domain/ChangeRecordService.cs new file mode 100644 index 0000000..b90bafa --- /dev/null +++ b/back/Services/Domain/ChangeRecordService.cs @@ -0,0 +1,52 @@ +using Contracts.DTO; +using Contracts.Mappers; +using Contracts.Repositories; +using Contracts.SearchModels; +using Contracts.Services; +using Contracts.ViewModels; + +namespace Services.Domain; + +public class ChangeRecordService : IChangeRecordService +{ + private readonly IChangeRecordRepo _changeRecordRepo; + + public ChangeRecordService(IChangeRecordRepo changeRecordRepo) + { + _changeRecordRepo = changeRecordRepo; + } + + public async Task Create(ChangeRecordDto model) + { + var record = await _changeRecordRepo.Create(model); + + return record.ToView(); + } + + public async Task Delete(ChangeRecordSearch search) + { + var record = await _changeRecordRepo.Delete(search); + if (record == null) + { + throw new EntryPointNotFoundException("При удалении не получилось найти запись измнения баланса"); + } + return record.ToView(); + } + + public async Task> GetList(ChangeRecordSearch search) + { + var records = await _changeRecordRepo.GetList(search); + + return records.Select(x => x.ToView()).ToList(); + } + + public async Task Update(ChangeRecordDto model) + { + var record = await _changeRecordRepo.Update(model); + if (record == null) + { + throw new EntryPointNotFoundException("При изменении не получилось найти запись измнения баланса"); + } + return record.ToView(); + } +} From 3684f1479cc8a70a776204b5ed73c49ee8e1e3ee Mon Sep 17 00:00:00 2001 From: mfnefd Date: Tue, 26 Nov 2024 22:46:38 +0400 Subject: [PATCH 16/37] =?UTF-8?q?add:=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=D1=8B=20=D0=B7=D0=B0=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D0=B5=D0=B9=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=B1=D0=B0=D0=BB=D0=B0=D0=BD=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/ChangeRecordController.cs | 86 +++++++++++++++++++ .../Controllers/SpendingGroupController.cs | 10 ++- .../Extensions/AddDomainServicesExt.cs | 2 + back/Controllers/Extensions/AddReposExt.cs | 1 + 4 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 back/Controllers/Controllers/ChangeRecordController.cs diff --git a/back/Controllers/Controllers/ChangeRecordController.cs b/back/Controllers/Controllers/ChangeRecordController.cs new file mode 100644 index 0000000..8ae218a --- /dev/null +++ b/back/Controllers/Controllers/ChangeRecordController.cs @@ -0,0 +1,86 @@ +using Contracts.DTO; +using Contracts.SearchModels; +using Contracts.Services; +using Contracts.ViewModels; +using Microsoft.AspNetCore.Mvc; +using Services.Support.Exceptions; + +namespace Controllers.Controllers; + +[Route("api/[controller]")] +[ApiController] +public class ChangeRecordController : ControllerBase +{ + private readonly IChangeRecordService _changeRecordService; + + public ChangeRecordController(IChangeRecordService changeRecordService) + { + _changeRecordService = changeRecordService; + } + + [HttpPost] + public async Task> CreateChangeRecord( + [FromBody] ChangeRecordDto dto) + { + try + { + var record = await _changeRecordService.Create(dto); + return CreatedAtAction(nameof(GetChangeRecords), record); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + + [HttpGet] + public async Task>> GetChangeRecords( + [FromQuery] ChangeRecordSearch search) + { + try + { + var records = await _changeRecordService.GetList(search); + return Ok(records); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + + [HttpPatch] + public async Task> UpdateChangeRecord([FromBody] ChangeRecordDto dto) + { + try + { + var record = await _changeRecordService.Update(dto); + return Ok(record); + } + catch (EntityNotFoundException ex) + { + return NotFound(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + + [HttpDelete] + public async Task DeleteChangeRecord([FromQuery] ChangeRecordSearch search) + { + try + { + var record = await _changeRecordService.Delete(search); + return Ok(record); + } + catch (EntityNotFoundException ex) + { + return NotFound(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } +} \ No newline at end of file diff --git a/back/Controllers/Controllers/SpendingGroupController.cs b/back/Controllers/Controllers/SpendingGroupController.cs index 36ad45b..635c06a 100644 --- a/back/Controllers/Controllers/SpendingGroupController.cs +++ b/back/Controllers/Controllers/SpendingGroupController.cs @@ -17,12 +17,16 @@ public class SpendingGroupController : ControllerBase { _spendingGroupService = spendingGroupService; } - [HttpGet("details")] + [HttpGet("{id}")] public async Task> GetSpendingGroup( + Guid id, [FromQuery] SpendingGroupSearch search) { try { + search ??= new(); + search.Id = id; + var group = await _spendingGroupService.GetDetails(search); return Ok(group); } @@ -74,6 +78,10 @@ public class SpendingGroupController : ControllerBase var group = await _spendingGroupService.Create(dto); return CreatedAtAction(nameof(GetSpendingGroup), new { id = group.Id }, group); } + catch (EntityNotFoundException ex) + { + return NotFound(ex.Message); + } catch (Exception ex) { return StatusCode(500, ex.Message); diff --git a/back/Controllers/Extensions/AddDomainServicesExt.cs b/back/Controllers/Extensions/AddDomainServicesExt.cs index 575d50a..97d9065 100644 --- a/back/Controllers/Extensions/AddDomainServicesExt.cs +++ b/back/Controllers/Extensions/AddDomainServicesExt.cs @@ -11,5 +11,7 @@ public static class AddDomainServicesExtension services.AddTransient(); services.AddTransient(); + + services.AddTransient(); } } \ No newline at end of file diff --git a/back/Controllers/Extensions/AddReposExt.cs b/back/Controllers/Extensions/AddReposExt.cs index d019ce0..9793b6e 100644 --- a/back/Controllers/Extensions/AddReposExt.cs +++ b/back/Controllers/Extensions/AddReposExt.cs @@ -11,5 +11,6 @@ public static class AddReposExtension { services.AddTransient(); services.AddTransient(); + services.AddTransient(); } } \ No newline at end of file From af936e519c95b2cb394394c7f7ae6e142c49d5d5 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Wed, 27 Nov 2024 00:06:15 +0400 Subject: [PATCH 17/37] =?UTF-8?q?add:=20=D0=BC=D0=B8=D0=B3=D1=80=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D1=81=D1=83=D1=89=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B8=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D0=B8=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B1=D0=B0=D0=BB?= =?UTF-8?q?=D0=B0=D0=BD=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...20241126185002_AddChangeRecord.Designer.cs | 134 ++++++++++++++++++ .../20241126185002_AddChangeRecord.cs | 59 ++++++++ .../DatabaseContextModelSnapshot.cs | 46 ++++++ 3 files changed, 239 insertions(+) create mode 100644 back/Infrastructure/Migrations/20241126185002_AddChangeRecord.Designer.cs create mode 100644 back/Infrastructure/Migrations/20241126185002_AddChangeRecord.cs diff --git a/back/Infrastructure/Migrations/20241126185002_AddChangeRecord.Designer.cs b/back/Infrastructure/Migrations/20241126185002_AddChangeRecord.Designer.cs new file mode 100644 index 0000000..fc60907 --- /dev/null +++ b/back/Infrastructure/Migrations/20241126185002_AddChangeRecord.Designer.cs @@ -0,0 +1,134 @@ +// +using System; +using Infrastructure; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Infrastructure.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20241126185002_AddChangeRecord")] + partial class AddChangeRecord + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SpendingGroupId") + .HasColumnType("uuid"); + + b.Property("Sum") + .HasColumnType("numeric"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SpendingGroupId"); + + b.HasIndex("UserId"); + + b.ToTable("ChangeRecords"); + }); + + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("SpendingGroups"); + }); + + modelBuilder.Entity("Infrastructure.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Balance") + .HasColumnType("numeric"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Password") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b => + { + b.HasOne("Infrastructure.Models.SpendingGroup", "SpendingGroup") + .WithMany() + .HasForeignKey("SpendingGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Infrastructure.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("SpendingGroup"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => + { + b.HasOne("Infrastructure.Models.User", "User") + .WithMany("SpendingGroups") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Infrastructure.Models.User", b => + { + b.Navigation("SpendingGroups"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/back/Infrastructure/Migrations/20241126185002_AddChangeRecord.cs b/back/Infrastructure/Migrations/20241126185002_AddChangeRecord.cs new file mode 100644 index 0000000..0f8a61d --- /dev/null +++ b/back/Infrastructure/Migrations/20241126185002_AddChangeRecord.cs @@ -0,0 +1,59 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Infrastructure.Migrations +{ + /// + public partial class AddChangeRecord : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ChangeRecords", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Sum = table.Column(type: "numeric", nullable: false), + ChangedAt = table.Column(type: "timestamp with time zone", nullable: false), + UserId = table.Column(type: "uuid", nullable: false), + SpendingGroupId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ChangeRecords", x => x.Id); + table.ForeignKey( + name: "FK_ChangeRecords_SpendingGroups_SpendingGroupId", + column: x => x.SpendingGroupId, + principalTable: "SpendingGroups", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ChangeRecords_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ChangeRecords_SpendingGroupId", + table: "ChangeRecords", + column: "SpendingGroupId"); + + migrationBuilder.CreateIndex( + name: "IX_ChangeRecords_UserId", + table: "ChangeRecords", + column: "UserId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ChangeRecords"); + } + } +} diff --git a/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs b/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs index 201a211..82c6874 100644 --- a/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs +++ b/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs @@ -22,6 +22,33 @@ namespace Infrastructure.Migrations NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SpendingGroupId") + .HasColumnType("uuid"); + + b.Property("Sum") + .HasColumnType("numeric"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SpendingGroupId"); + + b.HasIndex("UserId"); + + b.ToTable("ChangeRecords"); + }); + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => { b.Property("Id") @@ -64,6 +91,25 @@ namespace Infrastructure.Migrations b.ToTable("Users"); }); + modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b => + { + b.HasOne("Infrastructure.Models.SpendingGroup", "SpendingGroup") + .WithMany() + .HasForeignKey("SpendingGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Infrastructure.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("SpendingGroup"); + + b.Navigation("User"); + }); + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => { b.HasOne("Infrastructure.Models.User", "User") From cbc45bbecbd97c17690f417227613c068343b487 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Wed, 27 Nov 2024 00:19:35 +0400 Subject: [PATCH 18/37] =?UTF-8?q?fix:=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D1=8C=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D1=8C=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B1=D0=B0=D0=BB?= =?UTF-8?q?=D0=B0=D0=BD=D1=81=D0=B0=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D1=8F?= =?UTF-8?q?=D0=B5=D1=82=20=D0=B1=D0=B0=D0=BB=D0=B0=D0=BD=D1=81=20=D0=9B?= =?UTF-8?q?=D0=9E=D0=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Contracts/Repositories/IUserRepo.cs | 1 + back/Infrastructure/Repositories/UserRepo.cs | 19 +++++++++++++++++++ back/Services/Domain/ChangeRecordService.cs | 9 ++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/back/Contracts/Repositories/IUserRepo.cs b/back/Contracts/Repositories/IUserRepo.cs index ff32390..dab5cd0 100644 --- a/back/Contracts/Repositories/IUserRepo.cs +++ b/back/Contracts/Repositories/IUserRepo.cs @@ -8,5 +8,6 @@ public interface IUserRepo public Task Get(UserSearch search); public Task Create(UserDto user); public Task Update(UserDto user); + public Task ChangeBalance(UserSearch search, decimal amount); public Task Delete(UserSearch search); } \ No newline at end of file diff --git a/back/Infrastructure/Repositories/UserRepo.cs b/back/Infrastructure/Repositories/UserRepo.cs index a075d6d..e3a450d 100644 --- a/back/Infrastructure/Repositories/UserRepo.cs +++ b/back/Infrastructure/Repositories/UserRepo.cs @@ -15,6 +15,25 @@ public class UserRepo : IUserRepo _factory = factory; } + public async Task ChangeBalance(UserSearch search, decimal amount) + { + using var context = _factory.CreateDbContext(); + + var user = await context.Users + .FirstOrDefaultAsync(x => x.Id == search.Id + || x.Name == search.Name); + + if (user == null) + { + return false; + } + + user.Balance += amount; + context.Users.Update(user); + await context.SaveChangesAsync(); + return true; + } + public async Task Create(UserDto user) { using var context = _factory.CreateDbContext(); diff --git a/back/Services/Domain/ChangeRecordService.cs b/back/Services/Domain/ChangeRecordService.cs index b90bafa..4df6138 100644 --- a/back/Services/Domain/ChangeRecordService.cs +++ b/back/Services/Domain/ChangeRecordService.cs @@ -10,16 +10,20 @@ namespace Services.Domain; public class ChangeRecordService : IChangeRecordService { private readonly IChangeRecordRepo _changeRecordRepo; + private readonly IUserRepo _userRepo; - public ChangeRecordService(IChangeRecordRepo changeRecordRepo) + public ChangeRecordService(IChangeRecordRepo changeRecordRepo, IUserRepo userRepo) { _changeRecordRepo = changeRecordRepo; + _userRepo = userRepo; } public async Task Create(ChangeRecordDto model) { var record = await _changeRecordRepo.Create(model); + await _userRepo.ChangeBalance(new() { Id = model.UserId }, model.Sum); + return record.ToView(); } @@ -30,6 +34,8 @@ public class ChangeRecordService : IChangeRecordService { throw new EntryPointNotFoundException("При удалении не получилось найти запись измнения баланса"); } + // Возвращает баланс обратно + await _userRepo.ChangeBalance(new() { Id = record.UserId }, -record.Sum); return record.ToView(); } @@ -47,6 +53,7 @@ public class ChangeRecordService : IChangeRecordService { throw new EntryPointNotFoundException("При изменении не получилось найти запись измнения баланса"); } + await _userRepo.ChangeBalance(new() { Id = model.UserId }, model.Sum - record.Sum); return record.ToView(); } } From 6d734bbf798f0950197343df9e97708edd378779 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Wed, 27 Nov 2024 00:26:18 +0400 Subject: [PATCH 19/37] =?UTF-8?q?fix:=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D1=8C=20=D0=BF=D1=80=D0=B8=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B8=20=D0=B3=D1=80=D1=83=D0=BF=D0=BF=D1=8B?= =?UTF-8?q?=20=D1=80=D0=B0=D1=81=D1=85=D0=BE=D0=B4=D0=BE=D0=B2=20=D1=82?= =?UTF-8?q?=D0=B0=D0=BA=D0=B6=D0=B5=20=D0=B2=D0=BE=D0=B7=D0=B2=D1=80=D0=B0?= =?UTF-8?q?=D1=89=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20=D1=81=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=BE=D0=BA=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D0=B5=D0=B9=20?= =?UTF-8?q?=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=B1?= =?UTF-8?q?=D0=B0=D0=BB=D0=B0=D0=BD=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Contracts/DTOs/SpendingGroupDto.cs | 1 + back/Infrastructure/Models/Changerecord.cs | 2 +- back/Infrastructure/Models/SpendingGroup.cs | 1 + back/Infrastructure/Models/User.cs | 1 + back/Infrastructure/Repositories/SpendingGroupRepo.cs | 3 ++- back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs | 3 ++- 6 files changed, 8 insertions(+), 3 deletions(-) diff --git a/back/Contracts/DTOs/SpendingGroupDto.cs b/back/Contracts/DTOs/SpendingGroupDto.cs index cf03704..2adf558 100644 --- a/back/Contracts/DTOs/SpendingGroupDto.cs +++ b/back/Contracts/DTOs/SpendingGroupDto.cs @@ -5,4 +5,5 @@ public class SpendingGroupDto public Guid Id { get; set; } public string Name { get; set; } = string.Empty; public Guid UserId { get; set; } + public List ChangeRecords { get; set; } = new(); } \ No newline at end of file diff --git a/back/Infrastructure/Models/Changerecord.cs b/back/Infrastructure/Models/Changerecord.cs index 4f9a5e9..64b06c4 100644 --- a/back/Infrastructure/Models/Changerecord.cs +++ b/back/Infrastructure/Models/Changerecord.cs @@ -12,7 +12,7 @@ public class ChangeRecord public User User { get; set; } = null!; public Guid SpendingGroupId { get; set; } - public SpendingGroup SpendingGroup { get; set; } = null!; + public SpendingGroup? SpendingGroup { get; set; } public void Update(ChangeRecordDto changeRecordDto) { diff --git a/back/Infrastructure/Models/SpendingGroup.cs b/back/Infrastructure/Models/SpendingGroup.cs index b3d5d20..ec9d48e 100644 --- a/back/Infrastructure/Models/SpendingGroup.cs +++ b/back/Infrastructure/Models/SpendingGroup.cs @@ -7,4 +7,5 @@ public class SpendingGroup public Guid UserId { get; set; } public User User { get; set; } = null!; + public List ChangeRecords { get; set; } = new(); } \ No newline at end of file diff --git a/back/Infrastructure/Models/User.cs b/back/Infrastructure/Models/User.cs index add673c..469e15e 100644 --- a/back/Infrastructure/Models/User.cs +++ b/back/Infrastructure/Models/User.cs @@ -10,6 +10,7 @@ public class User public string Password { get; set; } = null!; public decimal Balance { get; set; } public List? SpendingGroups { get; set; } + public List? ChangeRecords { get; set; } public void Update(UserDto userDto) { diff --git a/back/Infrastructure/Repositories/SpendingGroupRepo.cs b/back/Infrastructure/Repositories/SpendingGroupRepo.cs index 38a69d0..d7e879e 100644 --- a/back/Infrastructure/Repositories/SpendingGroupRepo.cs +++ b/back/Infrastructure/Repositories/SpendingGroupRepo.cs @@ -46,6 +46,7 @@ public class SpendingGroupRepo : ISpendingGroupRepo using var context = _factory.CreateDbContext(); var group = await context.SpendingGroups + .Include(x => x.ChangeRecords) .FirstOrDefaultAsync(x => x.Id == search.Id || x.Name == search.Name); @@ -71,7 +72,7 @@ public class SpendingGroupRepo : ISpendingGroupRepo } } - return await query.Select(x => x.ToDto()).ToListAsync(); + return await query.Include(x => x.ChangeRecords).Select(x => x.ToDto()).ToListAsync(); } public async Task Update(SpendingGroupDto spendingGroup) diff --git a/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs b/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs index 94a39b6..1cb0585 100644 --- a/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs +++ b/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs @@ -10,7 +10,8 @@ public static class SpendingGroupMapper { Id = group.Id, Name = group.Name, - UserId = group.UserId + UserId = group.UserId, + ChangeRecords = group.ChangeRecords.Select(x => x.ToDto()).ToList() }; public static SpendingGroup ToModel(this SpendingGroupDto group) => new() From ba8c4a76d873f13fc2fc589e87e5ec98b184511c Mon Sep 17 00:00:00 2001 From: mfnefd Date: Wed, 27 Nov 2024 01:16:08 +0400 Subject: [PATCH 20/37] =?UTF-8?q?fix:=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D1=8C=20=D0=BD=D0=B5=D1=82=20=D0=BA=D0=B0=D1=81=D0=BA=D0=B0?= =?UTF-8?q?=D0=B4=D0=BD=D0=BE=D0=B3=D0=BE=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D0=B5=D0=B9?= =?UTF-8?q?=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=B1=D0=B0=D0=BB=D0=B0=D0=BD=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Contracts/DTOs/ChangeRecordDto.cs | 2 +- back/Contracts/Mappers/SpendingGroupMapper.cs | 3 +- .../Services/IChangeRecordService.cs | 2 +- .../ViewModels/SpendingGroupViewModel.cs | 1 + .../Controllers/ChangeRecordController.cs | 14 ++ ...20241126210947_fixChangeRecord.Designer.cs | 139 ++++++++++++++++++ .../20241126210947_fixChangeRecord.cs | 60 ++++++++ .../DatabaseContextModelSnapshot.cs | 17 ++- back/Infrastructure/Models/Changerecord.cs | 2 +- back/Infrastructure/Models/SpendingGroup.cs | 2 +- .../Repositories/ChangeRecordRepo.cs | 2 +- .../Support/Mappers/SpendingGroupMapper.cs | 2 +- back/Services/Domain/ChangeRecordService.cs | 2 +- back/Services/Domain/SpendingGroupService.cs | 2 +- 14 files changed, 235 insertions(+), 15 deletions(-) create mode 100644 back/Infrastructure/Migrations/20241126210947_fixChangeRecord.Designer.cs create mode 100644 back/Infrastructure/Migrations/20241126210947_fixChangeRecord.cs diff --git a/back/Contracts/DTOs/ChangeRecordDto.cs b/back/Contracts/DTOs/ChangeRecordDto.cs index f95da9c..21d140c 100644 --- a/back/Contracts/DTOs/ChangeRecordDto.cs +++ b/back/Contracts/DTOs/ChangeRecordDto.cs @@ -4,7 +4,7 @@ public class ChangeRecordDto { public Guid Id { get; set; } public Guid UserId { get; set; } - public Guid SpendingGroupId { get; set; } + public Guid? SpendingGroupId { get; set; } public decimal Sum { get; set; } public DateTime ChangedAt { get; set; } } \ No newline at end of file diff --git a/back/Contracts/Mappers/SpendingGroupMapper.cs b/back/Contracts/Mappers/SpendingGroupMapper.cs index 7eca2d3..92877a5 100644 --- a/back/Contracts/Mappers/SpendingGroupMapper.cs +++ b/back/Contracts/Mappers/SpendingGroupMapper.cs @@ -9,6 +9,7 @@ public static class SpendingGroupMapper => new() { Id = spendingGroup.Id, - Name = spendingGroup.Name + Name = spendingGroup.Name, + ChangeRecords = spendingGroup.ChangeRecords.Select(x => x.ToView()).ToList() }; } \ No newline at end of file diff --git a/back/Contracts/Services/IChangeRecordService.cs b/back/Contracts/Services/IChangeRecordService.cs index 9dd0832..b9939e0 100644 --- a/back/Contracts/Services/IChangeRecordService.cs +++ b/back/Contracts/Services/IChangeRecordService.cs @@ -9,5 +9,5 @@ public interface IChangeRecordService Task Create(ChangeRecordDto model); Task Update(ChangeRecordDto model); Task Delete(ChangeRecordSearch search); - Task> GetList(ChangeRecordSearch search); + Task> GetList(ChangeRecordSearch? search = null); } \ No newline at end of file diff --git a/back/Contracts/ViewModels/SpendingGroupViewModel.cs b/back/Contracts/ViewModels/SpendingGroupViewModel.cs index 12cba2d..c22ae62 100644 --- a/back/Contracts/ViewModels/SpendingGroupViewModel.cs +++ b/back/Contracts/ViewModels/SpendingGroupViewModel.cs @@ -4,4 +4,5 @@ public class SpendingGroupViewModel { public Guid Id { get; set; } public string Name { get; set; } = string.Empty; + public List ChangeRecords { get; set; } = new(); } \ No newline at end of file diff --git a/back/Controllers/Controllers/ChangeRecordController.cs b/back/Controllers/Controllers/ChangeRecordController.cs index 8ae218a..c823a99 100644 --- a/back/Controllers/Controllers/ChangeRecordController.cs +++ b/back/Controllers/Controllers/ChangeRecordController.cs @@ -34,6 +34,20 @@ public class ChangeRecordController : ControllerBase } [HttpGet] + public async Task>> GetChangeRecords() + { + try + { + var records = await _changeRecordService.GetList(); + return Ok(records); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + + [HttpGet("filter")] public async Task>> GetChangeRecords( [FromQuery] ChangeRecordSearch search) { diff --git a/back/Infrastructure/Migrations/20241126210947_fixChangeRecord.Designer.cs b/back/Infrastructure/Migrations/20241126210947_fixChangeRecord.Designer.cs new file mode 100644 index 0000000..937117a --- /dev/null +++ b/back/Infrastructure/Migrations/20241126210947_fixChangeRecord.Designer.cs @@ -0,0 +1,139 @@ +// +using System; +using Infrastructure; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Infrastructure.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20241126210947_fixChangeRecord")] + partial class fixChangeRecord + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SpendingGroupId") + .HasColumnType("uuid"); + + b.Property("Sum") + .HasColumnType("numeric"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SpendingGroupId"); + + b.HasIndex("UserId"); + + b.ToTable("ChangeRecords"); + }); + + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("SpendingGroups"); + }); + + modelBuilder.Entity("Infrastructure.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Balance") + .HasColumnType("numeric"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Password") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b => + { + b.HasOne("Infrastructure.Models.SpendingGroup", "SpendingGroup") + .WithMany("ChangeRecords") + .HasForeignKey("SpendingGroupId"); + + b.HasOne("Infrastructure.Models.User", "User") + .WithMany("ChangeRecords") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("SpendingGroup"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => + { + b.HasOne("Infrastructure.Models.User", "User") + .WithMany("SpendingGroups") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => + { + b.Navigation("ChangeRecords"); + }); + + modelBuilder.Entity("Infrastructure.Models.User", b => + { + b.Navigation("ChangeRecords"); + + b.Navigation("SpendingGroups"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/back/Infrastructure/Migrations/20241126210947_fixChangeRecord.cs b/back/Infrastructure/Migrations/20241126210947_fixChangeRecord.cs new file mode 100644 index 0000000..68c6484 --- /dev/null +++ b/back/Infrastructure/Migrations/20241126210947_fixChangeRecord.cs @@ -0,0 +1,60 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Infrastructure.Migrations +{ + /// + public partial class fixChangeRecord : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ChangeRecords_SpendingGroups_SpendingGroupId", + table: "ChangeRecords"); + + migrationBuilder.AlterColumn( + name: "SpendingGroupId", + table: "ChangeRecords", + type: "uuid", + nullable: true, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AddForeignKey( + name: "FK_ChangeRecords_SpendingGroups_SpendingGroupId", + table: "ChangeRecords", + column: "SpendingGroupId", + principalTable: "SpendingGroups", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ChangeRecords_SpendingGroups_SpendingGroupId", + table: "ChangeRecords"); + + migrationBuilder.AlterColumn( + name: "SpendingGroupId", + table: "ChangeRecords", + type: "uuid", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + oldClrType: typeof(Guid), + oldType: "uuid", + oldNullable: true); + + migrationBuilder.AddForeignKey( + name: "FK_ChangeRecords_SpendingGroups_SpendingGroupId", + table: "ChangeRecords", + column: "SpendingGroupId", + principalTable: "SpendingGroups", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs b/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs index 82c6874..2c7a5ef 100644 --- a/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs +++ b/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs @@ -31,7 +31,7 @@ namespace Infrastructure.Migrations b.Property("ChangedAt") .HasColumnType("timestamp with time zone"); - b.Property("SpendingGroupId") + b.Property("SpendingGroupId") .HasColumnType("uuid"); b.Property("Sum") @@ -94,13 +94,11 @@ namespace Infrastructure.Migrations modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b => { b.HasOne("Infrastructure.Models.SpendingGroup", "SpendingGroup") - .WithMany() - .HasForeignKey("SpendingGroupId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); + .WithMany("ChangeRecords") + .HasForeignKey("SpendingGroupId"); b.HasOne("Infrastructure.Models.User", "User") - .WithMany() + .WithMany("ChangeRecords") .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); @@ -121,8 +119,15 @@ namespace Infrastructure.Migrations b.Navigation("User"); }); + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => + { + b.Navigation("ChangeRecords"); + }); + modelBuilder.Entity("Infrastructure.Models.User", b => { + b.Navigation("ChangeRecords"); + b.Navigation("SpendingGroups"); }); #pragma warning restore 612, 618 diff --git a/back/Infrastructure/Models/Changerecord.cs b/back/Infrastructure/Models/Changerecord.cs index 64b06c4..60cb92d 100644 --- a/back/Infrastructure/Models/Changerecord.cs +++ b/back/Infrastructure/Models/Changerecord.cs @@ -11,7 +11,7 @@ public class ChangeRecord public Guid UserId { get; set; } public User User { get; set; } = null!; - public Guid SpendingGroupId { get; set; } + public Guid? SpendingGroupId { get; set; } public SpendingGroup? SpendingGroup { get; set; } public void Update(ChangeRecordDto changeRecordDto) diff --git a/back/Infrastructure/Models/SpendingGroup.cs b/back/Infrastructure/Models/SpendingGroup.cs index ec9d48e..889bdb6 100644 --- a/back/Infrastructure/Models/SpendingGroup.cs +++ b/back/Infrastructure/Models/SpendingGroup.cs @@ -7,5 +7,5 @@ public class SpendingGroup public Guid UserId { get; set; } public User User { get; set; } = null!; - public List ChangeRecords { get; set; } = new(); + public List? ChangeRecords { get; set; } } \ No newline at end of file diff --git a/back/Infrastructure/Repositories/ChangeRecordRepo.cs b/back/Infrastructure/Repositories/ChangeRecordRepo.cs index cafeb2d..6da1839 100644 --- a/back/Infrastructure/Repositories/ChangeRecordRepo.cs +++ b/back/Infrastructure/Repositories/ChangeRecordRepo.cs @@ -71,7 +71,7 @@ public class ChangeRecordRepo : IChangeRecordRepo query = query.Where(x => x.ChangedAt >= search.From && x.ChangedAt <= search.To); } } - return query.Select(x => x.ToDto()); + return await query.Select(x => x.ToDto()).ToListAsync(); } public async Task Update(ChangeRecordDto changeRecord) diff --git a/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs b/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs index 1cb0585..d74490f 100644 --- a/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs +++ b/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs @@ -11,7 +11,7 @@ public static class SpendingGroupMapper Id = group.Id, Name = group.Name, UserId = group.UserId, - ChangeRecords = group.ChangeRecords.Select(x => x.ToDto()).ToList() + ChangeRecords = group.ChangeRecords?.Select(x => x.ToDto()).ToList() ?? [] }; public static SpendingGroup ToModel(this SpendingGroupDto group) => new() diff --git a/back/Services/Domain/ChangeRecordService.cs b/back/Services/Domain/ChangeRecordService.cs index 4df6138..45ed858 100644 --- a/back/Services/Domain/ChangeRecordService.cs +++ b/back/Services/Domain/ChangeRecordService.cs @@ -39,7 +39,7 @@ public class ChangeRecordService : IChangeRecordService return record.ToView(); } - public async Task> GetList(ChangeRecordSearch search) + public async Task> GetList(ChangeRecordSearch? search = null) { var records = await _changeRecordRepo.GetList(search); diff --git a/back/Services/Domain/SpendingGroupService.cs b/back/Services/Domain/SpendingGroupService.cs index b0afed1..e4ff348 100644 --- a/back/Services/Domain/SpendingGroupService.cs +++ b/back/Services/Domain/SpendingGroupService.cs @@ -44,7 +44,7 @@ public class SpendingGroupService : ISpendingGroupService return group.ToView(); } - public async Task> GetList(SpendingGroupSearch search) + public async Task> GetList(SpendingGroupSearch? search = null) { var groups = await _spendingGroupRepo.GetList(search); return groups.Select(x => x.ToView()).ToList(); From b35cd64e80cc0e292469a476782399c7a84cb446 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Wed, 27 Nov 2024 01:46:33 +0400 Subject: [PATCH 21/37] =?UTF-8?q?add:=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D0=BA=D1=82=D1=8B=20=D0=BF=D0=BB=D0=B0=D0=BD=D0=B0=20?= =?UTF-8?q?=D1=80=D0=B0=D1=81=D1=85=D0=BE=D0=B4=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Contracts/DTOs/SpendingPlanDto.cs | 10 ++++++++++ back/Contracts/Mappers/SpendingPlanMapper.cs | 16 ++++++++++++++++ back/Contracts/Repositories/ISpendingPlanRepo.cs | 13 +++++++++++++ .../Contracts/SearchModels/SpendingPlanSearch.cs | 6 ++++++ back/Contracts/Services/ISpendingPlan.cs | 14 ++++++++++++++ back/Contracts/ViewModels/SpendingPlanView.cs | 9 +++++++++ 6 files changed, 68 insertions(+) create mode 100644 back/Contracts/DTOs/SpendingPlanDto.cs create mode 100644 back/Contracts/Mappers/SpendingPlanMapper.cs create mode 100644 back/Contracts/Repositories/ISpendingPlanRepo.cs create mode 100644 back/Contracts/SearchModels/SpendingPlanSearch.cs create mode 100644 back/Contracts/Services/ISpendingPlan.cs create mode 100644 back/Contracts/ViewModels/SpendingPlanView.cs diff --git a/back/Contracts/DTOs/SpendingPlanDto.cs b/back/Contracts/DTOs/SpendingPlanDto.cs new file mode 100644 index 0000000..fc88578 --- /dev/null +++ b/back/Contracts/DTOs/SpendingPlanDto.cs @@ -0,0 +1,10 @@ +namespace Contracts.DTO; + +public class SpendingPlanDto +{ + public Guid Id { get; set; } + public Guid SpendingGroupId { get; set; } + public decimal Sum { get; set; } + public DateTime StartAt { get; set; } + public DateTime EndAt { get; set; } +} \ No newline at end of file diff --git a/back/Contracts/Mappers/SpendingPlanMapper.cs b/back/Contracts/Mappers/SpendingPlanMapper.cs new file mode 100644 index 0000000..4e4e144 --- /dev/null +++ b/back/Contracts/Mappers/SpendingPlanMapper.cs @@ -0,0 +1,16 @@ +using Contracts.DTO; +using Contracts.ViewModels; + +namespace Contracts.Mappers; + +public static class SpendingPlanMapper +{ + public static SpendingPlanView ToView(this SpendingPlanDto dto) + => new() + { + Id = dto.Id, + StartAt = dto.StartAt, + EndAt = dto.EndAt, + Sum = dto.Sum + }; +} \ No newline at end of file diff --git a/back/Contracts/Repositories/ISpendingPlanRepo.cs b/back/Contracts/Repositories/ISpendingPlanRepo.cs new file mode 100644 index 0000000..229bb7f --- /dev/null +++ b/back/Contracts/Repositories/ISpendingPlanRepo.cs @@ -0,0 +1,13 @@ +using Contracts.DTO; +using Contracts.SearchModels; + +namespace Contracts.Repositories; + +public interface ISpendingPlanRepo +{ + Task Create(SpendingPlanDto dto); + Task Update(SpendingPlanDto dto); + Task Delete(SpendingPlanSearch search); + Task GetDetails(SpendingPlanSearch search); + Task> GetList(SpendingGroupSearch? search = null); +} \ No newline at end of file diff --git a/back/Contracts/SearchModels/SpendingPlanSearch.cs b/back/Contracts/SearchModels/SpendingPlanSearch.cs new file mode 100644 index 0000000..0b53198 --- /dev/null +++ b/back/Contracts/SearchModels/SpendingPlanSearch.cs @@ -0,0 +1,6 @@ +namespace Contracts.SearchModels; + +public class SpendingPlanSearch +{ + public Guid? Id { get; set; } +} \ No newline at end of file diff --git a/back/Contracts/Services/ISpendingPlan.cs b/back/Contracts/Services/ISpendingPlan.cs new file mode 100644 index 0000000..932c4ca --- /dev/null +++ b/back/Contracts/Services/ISpendingPlan.cs @@ -0,0 +1,14 @@ +using Contracts.DTO; +using Contracts.SearchModels; +using Contracts.ViewModels; + +namespace Contracts.Services; + +public interface ISpendingPlan +{ + Task GetDetails(SpendingPlanSearch search); + Task> GetList(SpendingPlanSearch? search = null); + Task Create(SpendingPlanDto spendingPlan); + Task Delete(SpendingPlanSearch search); + Task Update(SpendingPlanDto spendingPlan); +} \ No newline at end of file diff --git a/back/Contracts/ViewModels/SpendingPlanView.cs b/back/Contracts/ViewModels/SpendingPlanView.cs new file mode 100644 index 0000000..74ed725 --- /dev/null +++ b/back/Contracts/ViewModels/SpendingPlanView.cs @@ -0,0 +1,9 @@ +namespace Contracts.ViewModels; + +public class SpendingPlanView +{ + public Guid Id { get; set; } + public DateTime StartAt { get; set; } + public DateTime EndAt { get; set; } + public decimal Sum { get; set; } +} \ No newline at end of file From 64566065fcb0a878bc41de178dde29120e32bf41 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Wed, 27 Nov 2024 01:47:00 +0400 Subject: [PATCH 22/37] =?UTF-8?q?fix:=20=D0=BD=D0=B8=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=B0=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D1=80=D0=B0=20=D0=B2=20=D0=BC=D0=B0=D0=BF?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B0=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Contracts/Mappers/ChangeRecordMapper.cs | 8 ++++---- back/Contracts/Mappers/SpendingGroupMapper.cs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/back/Contracts/Mappers/ChangeRecordMapper.cs b/back/Contracts/Mappers/ChangeRecordMapper.cs index a6075c4..606344d 100644 --- a/back/Contracts/Mappers/ChangeRecordMapper.cs +++ b/back/Contracts/Mappers/ChangeRecordMapper.cs @@ -5,11 +5,11 @@ namespace Contracts.Mappers; public static class ChangeRecordMapper { - public static ChangeRecordViewModel ToView(this ChangeRecordDto changeRecord) + public static ChangeRecordViewModel ToView(this ChangeRecordDto dto) => new() { - Id = changeRecord.Id, - Sum = changeRecord.Sum, - ChangedAt = changeRecord.ChangedAt + Id = dto.Id, + Sum = dto.Sum, + ChangedAt = dto.ChangedAt }; } \ No newline at end of file diff --git a/back/Contracts/Mappers/SpendingGroupMapper.cs b/back/Contracts/Mappers/SpendingGroupMapper.cs index 92877a5..f9d4cac 100644 --- a/back/Contracts/Mappers/SpendingGroupMapper.cs +++ b/back/Contracts/Mappers/SpendingGroupMapper.cs @@ -5,11 +5,11 @@ namespace Contracts.Mappers; public static class SpendingGroupMapper { - public static SpendingGroupViewModel ToView(this SpendingGroupDto spendingGroup) + public static SpendingGroupViewModel ToView(this SpendingGroupDto dto) => new() { - Id = spendingGroup.Id, - Name = spendingGroup.Name, - ChangeRecords = spendingGroup.ChangeRecords.Select(x => x.ToView()).ToList() + Id = dto.Id, + Name = dto.Name, + ChangeRecords = dto.ChangeRecords.Select(x => x.ToView()).ToList() }; } \ No newline at end of file From 0bd6261e21319d6001a898bc14fd4506f5ba92fd Mon Sep 17 00:00:00 2001 From: mfnefd Date: Wed, 27 Nov 2024 02:13:01 +0400 Subject: [PATCH 23/37] =?UTF-8?q?add:=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8?= =?UTF-8?q?=D1=81=20=D0=B8=20=D1=80=D0=B5=D0=BF=D0=BE=D0=B7=D0=B8=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=B9=20=D0=BF=D0=BB=D0=B0=D0=BD=D0=B0=20?= =?UTF-8?q?=D1=80=D0=B0=D1=81=D1=85=D0=BE=D0=B4=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repositories/ISpendingPlanRepo.cs | 4 +- ...pendingPlan.cs => ISpendingPlanService.cs} | 6 +- back/Infrastructure/DatabaseContext.cs | 1 + back/Infrastructure/Models/SpendingPlan.cs | 22 +++++ .../Repositories/SpendingPlanRepo.cs | 86 +++++++++++++++++++ .../Support/Mappers/SpendingPlanMapper.cs | 27 ++++++ back/Services/Domain/SpendingPlanService.cs | 61 +++++++++++++ 7 files changed, 202 insertions(+), 5 deletions(-) rename back/Contracts/Services/{ISpendingPlan.cs => ISpendingPlanService.cs} (66%) create mode 100644 back/Infrastructure/Models/SpendingPlan.cs create mode 100644 back/Infrastructure/Repositories/SpendingPlanRepo.cs create mode 100644 back/Infrastructure/Support/Mappers/SpendingPlanMapper.cs create mode 100644 back/Services/Domain/SpendingPlanService.cs diff --git a/back/Contracts/Repositories/ISpendingPlanRepo.cs b/back/Contracts/Repositories/ISpendingPlanRepo.cs index 229bb7f..8dcfd4b 100644 --- a/back/Contracts/Repositories/ISpendingPlanRepo.cs +++ b/back/Contracts/Repositories/ISpendingPlanRepo.cs @@ -8,6 +8,6 @@ public interface ISpendingPlanRepo Task Create(SpendingPlanDto dto); Task Update(SpendingPlanDto dto); Task Delete(SpendingPlanSearch search); - Task GetDetails(SpendingPlanSearch search); - Task> GetList(SpendingGroupSearch? search = null); + Task Get(SpendingPlanSearch search); + Task> GetList(SpendingPlanSearch? search = null); } \ No newline at end of file diff --git a/back/Contracts/Services/ISpendingPlan.cs b/back/Contracts/Services/ISpendingPlanService.cs similarity index 66% rename from back/Contracts/Services/ISpendingPlan.cs rename to back/Contracts/Services/ISpendingPlanService.cs index 932c4ca..b2ee0aa 100644 --- a/back/Contracts/Services/ISpendingPlan.cs +++ b/back/Contracts/Services/ISpendingPlanService.cs @@ -4,11 +4,11 @@ using Contracts.ViewModels; namespace Contracts.Services; -public interface ISpendingPlan +public interface ISpendingPlanService { - Task GetDetails(SpendingPlanSearch search); + Task GetDetails(SpendingPlanSearch search); Task> GetList(SpendingPlanSearch? search = null); Task Create(SpendingPlanDto spendingPlan); - Task Delete(SpendingPlanSearch search); + Task Delete(SpendingPlanSearch search); Task Update(SpendingPlanDto spendingPlan); } \ No newline at end of file diff --git a/back/Infrastructure/DatabaseContext.cs b/back/Infrastructure/DatabaseContext.cs index 02afad7..d787750 100644 --- a/back/Infrastructure/DatabaseContext.cs +++ b/back/Infrastructure/DatabaseContext.cs @@ -14,4 +14,5 @@ public class DatabaseContext : DbContext public DbSet Users { get; set; } = null!; public DbSet SpendingGroups { get; set; } = null!; public DbSet ChangeRecords { get; set; } = null!; + public DbSet SpendingPlans { get; set; } = null!; } \ No newline at end of file diff --git a/back/Infrastructure/Models/SpendingPlan.cs b/back/Infrastructure/Models/SpendingPlan.cs new file mode 100644 index 0000000..8162016 --- /dev/null +++ b/back/Infrastructure/Models/SpendingPlan.cs @@ -0,0 +1,22 @@ +using Contracts.DTO; + +namespace Infrastructure.Models; + +public class SpendingPlan +{ + public Guid Id { get; set; } + public DateTime StartAt { get; set; } + public DateTime EndAt { get; set; } + public decimal Sum { get; set; } + + public Guid SpendingGroupId { get; set; } + public SpendingGroup SpendingGroup { get; set; } = null!; + + public void Update(SpendingPlanDto spendingPlan) + { + StartAt = spendingPlan.StartAt; + EndAt = spendingPlan.EndAt; + Sum = spendingPlan.Sum; + SpendingGroupId = spendingPlan.SpendingGroupId; + } +} \ No newline at end of file diff --git a/back/Infrastructure/Repositories/SpendingPlanRepo.cs b/back/Infrastructure/Repositories/SpendingPlanRepo.cs new file mode 100644 index 0000000..05c03f3 --- /dev/null +++ b/back/Infrastructure/Repositories/SpendingPlanRepo.cs @@ -0,0 +1,86 @@ +using Contracts.DTO; +using Contracts.Repositories; +using Contracts.SearchModels; +using Infrastructure.Support.Mappers; +using Microsoft.EntityFrameworkCore; + +namespace Infrastructure.Repositories; + +public class SpendingPlanRepo : ISpendingPlanRepo +{ + public readonly IDbContextFactory _factory; + + public SpendingPlanRepo(IDbContextFactory factory) + { + _factory = factory; + } + + public async Task Create(SpendingPlanDto dto) + { + using var context = _factory.CreateDbContext(); + + var plan = await context.SpendingPlans.AddAsync(dto.ToModel()); + + await context.SaveChangesAsync(); + return plan.Entity.ToDto(); + } + + public async Task Delete(SpendingPlanSearch search) + { + using var context = _factory.CreateDbContext(); + + var plan = await context.SpendingPlans.FirstOrDefaultAsync(x => x.Id == search.Id); + + if (plan == null) + { + return null; + } + + context.SpendingPlans.Remove(plan); + await context.SaveChangesAsync(); + return plan.ToDto(); + } + + public async Task Get(SpendingPlanSearch search) + { + using var context = _factory.CreateDbContext(); + + var plan = await context.SpendingPlans.FirstOrDefaultAsync(x => x.Id == search.Id); + + return plan?.ToDto(); + } + + public async Task> GetList(SpendingPlanSearch? search = null) + { + using var context = _factory.CreateDbContext(); + + var query = context.SpendingPlans.AsQueryable(); + + if (search != null) + { + if (search.Id != null) + { + query = query.Where(x => x.Id == search.Id); + } + } + + return await query.Select(x => x.ToDto()).ToListAsync(); + } + + public async Task Update(SpendingPlanDto dto) + { + using var context = _factory.CreateDbContext(); + + var plan = await context.SpendingPlans.FirstOrDefaultAsync(x => x.Id == dto.Id); + + if (plan == null) + { + return null; + } + + plan.Update(dto); + context.SpendingPlans.Update(plan); + await context.SaveChangesAsync(); + return plan.ToDto(); + } +} diff --git a/back/Infrastructure/Support/Mappers/SpendingPlanMapper.cs b/back/Infrastructure/Support/Mappers/SpendingPlanMapper.cs new file mode 100644 index 0000000..22fe884 --- /dev/null +++ b/back/Infrastructure/Support/Mappers/SpendingPlanMapper.cs @@ -0,0 +1,27 @@ +using Contracts.DTO; +using Infrastructure.Models; + +namespace Infrastructure.Support.Mappers; + +public static class SpendingPlanMapper +{ + public static SpendingPlan ToModel(this SpendingPlanDto plan) + => new() + { + Id = plan.Id, + StartAt = plan.StartAt, + EndAt = plan.EndAt, + Sum = plan.Sum, + SpendingGroupId = plan.SpendingGroupId + }; + + public static SpendingPlanDto ToDto(this SpendingPlan plan) + => new() + { + Id = plan.Id, + StartAt = plan.StartAt, + EndAt = plan.EndAt, + Sum = plan.Sum, + SpendingGroupId = plan.SpendingGroupId + }; +} \ No newline at end of file diff --git a/back/Services/Domain/SpendingPlanService.cs b/back/Services/Domain/SpendingPlanService.cs new file mode 100644 index 0000000..d565869 --- /dev/null +++ b/back/Services/Domain/SpendingPlanService.cs @@ -0,0 +1,61 @@ +using Contracts.DTO; +using Contracts.Mappers; +using Contracts.Repositories; +using Contracts.SearchModels; +using Contracts.Services; +using Contracts.ViewModels; +using Services.Support.Exceptions; + +namespace Services.Domain; + +public class SpendingPlanService : ISpendingPlanService +{ + private readonly ISpendingPlanRepo _spendingPlanRepo; + + public SpendingPlanService(ISpendingPlanRepo spendingPlanRepo) + { + _spendingPlanRepo = spendingPlanRepo; + } + + public async Task Create(SpendingPlanDto spendingPlan) + { + var plan = await _spendingPlanRepo.Create(spendingPlan); + return plan.ToView(); + } + + public async Task Delete(SpendingPlanSearch search) + { + var plan = await _spendingPlanRepo.Delete(search); + if (plan == null) + { + throw new EntityNotFoundException("При удалении не получилось найти план"); + } + return plan.ToView(); + } + + public async Task GetDetails(SpendingPlanSearch search) + { + var plan = await _spendingPlanRepo.Get(search); + if (plan == null) + { + throw new EntityNotFoundException("Не удалось найти план по таким параметрам"); + } + return plan.ToView(); + } + + public async Task> GetList(SpendingPlanSearch? search = null) + { + var plans = await _spendingPlanRepo.GetList(search); + return plans.Select(x => x.ToView()).ToList(); + } + + public async Task Update(SpendingPlanDto spendingPlan) + { + var plan = await _spendingPlanRepo.Update(spendingPlan); + if (plan == null) + { + throw new EntityNotFoundException("При обновлении не получилось найти план"); + } + return plan.ToView(); + } +} From 6ca4576a6bf75dc80e1277b352aa9b44be3e3164 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Wed, 27 Nov 2024 02:20:17 +0400 Subject: [PATCH 24/37] =?UTF-8?q?add:=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=20=D0=BF=D0=BB=D0=B0=D0=BD=D0=B0?= =?UTF-8?q?=20=D1=80=D0=B0=D1=81=D1=85=D0=BE=D0=B4=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Contracts/Mappers/SpendingPlanMapper.cs | 2 +- .../Services/ISpendingPlanService.cs | 10 +- ...ngPlanView.cs => SpendingPlanViewModel.cs} | 2 +- .../Controllers/SpendingPlanController.cs | 128 ++++++++++++++++++ .../Extensions/AddDomainServicesExt.cs | 2 + back/Controllers/Extensions/AddReposExt.cs | 1 + back/Services/Domain/SpendingPlanService.cs | 10 +- 7 files changed, 143 insertions(+), 12 deletions(-) rename back/Contracts/ViewModels/{SpendingPlanView.cs => SpendingPlanViewModel.cs} (83%) create mode 100644 back/Controllers/Controllers/SpendingPlanController.cs diff --git a/back/Contracts/Mappers/SpendingPlanMapper.cs b/back/Contracts/Mappers/SpendingPlanMapper.cs index 4e4e144..84504b9 100644 --- a/back/Contracts/Mappers/SpendingPlanMapper.cs +++ b/back/Contracts/Mappers/SpendingPlanMapper.cs @@ -5,7 +5,7 @@ namespace Contracts.Mappers; public static class SpendingPlanMapper { - public static SpendingPlanView ToView(this SpendingPlanDto dto) + public static SpendingPlanViewModel ToView(this SpendingPlanDto dto) => new() { Id = dto.Id, diff --git a/back/Contracts/Services/ISpendingPlanService.cs b/back/Contracts/Services/ISpendingPlanService.cs index b2ee0aa..086ec5b 100644 --- a/back/Contracts/Services/ISpendingPlanService.cs +++ b/back/Contracts/Services/ISpendingPlanService.cs @@ -6,9 +6,9 @@ namespace Contracts.Services; public interface ISpendingPlanService { - Task GetDetails(SpendingPlanSearch search); - Task> GetList(SpendingPlanSearch? search = null); - Task Create(SpendingPlanDto spendingPlan); - Task Delete(SpendingPlanSearch search); - Task Update(SpendingPlanDto spendingPlan); + Task GetDetails(SpendingPlanSearch search); + Task> GetList(SpendingPlanSearch? search = null); + Task Create(SpendingPlanDto spendingPlan); + Task Delete(SpendingPlanSearch search); + Task Update(SpendingPlanDto spendingPlan); } \ No newline at end of file diff --git a/back/Contracts/ViewModels/SpendingPlanView.cs b/back/Contracts/ViewModels/SpendingPlanViewModel.cs similarity index 83% rename from back/Contracts/ViewModels/SpendingPlanView.cs rename to back/Contracts/ViewModels/SpendingPlanViewModel.cs index 74ed725..285cdd8 100644 --- a/back/Contracts/ViewModels/SpendingPlanView.cs +++ b/back/Contracts/ViewModels/SpendingPlanViewModel.cs @@ -1,6 +1,6 @@ namespace Contracts.ViewModels; -public class SpendingPlanView +public class SpendingPlanViewModel { public Guid Id { get; set; } public DateTime StartAt { get; set; } diff --git a/back/Controllers/Controllers/SpendingPlanController.cs b/back/Controllers/Controllers/SpendingPlanController.cs new file mode 100644 index 0000000..5f457b1 --- /dev/null +++ b/back/Controllers/Controllers/SpendingPlanController.cs @@ -0,0 +1,128 @@ +using Contracts.DTO; +using Contracts.SearchModels; +using Contracts.Services; +using Contracts.ViewModels; +using Microsoft.AspNetCore.Mvc; +using Services.Support.Exceptions; + +namespace Controllers.Controllers; + +[ApiController] +[Route("api/[controller]")] +public class SpendingPlanController : ControllerBase +{ + private readonly ISpendingPlanService _spendingPlanService; + + public SpendingPlanController(ISpendingPlanService spendingPlanService) + { + _spendingPlanService = spendingPlanService; + } + + [HttpGet("{id}")] + public async Task> GetSpendingPlan( + Guid id, + [FromQuery] SpendingPlanSearch search) + { + try + { + search ??= new(); + search.Id = id; + + var plan = await _spendingPlanService.GetDetails(search); + return Ok(plan); + } + catch (EntityNotFoundException ex) + { + return NotFound(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + + [HttpGet] + public async Task>> GetSpendingPlans() + { + try + { + var plans = await _spendingPlanService.GetList(); + return Ok(plans); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + + [HttpGet("filter")] + public async Task>> GetSpendingPlans( + [FromQuery] SpendingPlanSearch search) + { + try + { + var plans = await _spendingPlanService.GetList(search); + return Ok(plans); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + + [HttpPost] + public async Task> CreateSpendingPlan( + [FromBody] SpendingPlanDto dto) + { + try + { + var plan = await _spendingPlanService.Create(dto); + return CreatedAtAction(nameof(GetSpendingPlan), new { id = plan.Id }, plan); + } + catch (EntityNotFoundException ex) + { + return NotFound(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + + [HttpPatch] + public async Task> UpdateSpendingPlan( + [FromBody] SpendingPlanDto dto) + { + try + { + var plan = await _spendingPlanService.Update(dto); + return Ok(plan); + } + catch (EntityNotFoundException ex) + { + return NotFound(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } + + [HttpDelete] + public async Task DeleteSpendingPlan([FromQuery] SpendingPlanSearch search) + { + try + { + var plan = await _spendingPlanService.Delete(search); + return Ok(plan); + } + catch (EntityNotFoundException ex) + { + return NotFound(ex.Message); + } + catch (Exception ex) + { + return StatusCode(500, ex.Message); + } + } +} \ No newline at end of file diff --git a/back/Controllers/Extensions/AddDomainServicesExt.cs b/back/Controllers/Extensions/AddDomainServicesExt.cs index 97d9065..7d6cc0a 100644 --- a/back/Controllers/Extensions/AddDomainServicesExt.cs +++ b/back/Controllers/Extensions/AddDomainServicesExt.cs @@ -13,5 +13,7 @@ public static class AddDomainServicesExtension services.AddTransient(); services.AddTransient(); + + services.AddTransient(); } } \ No newline at end of file diff --git a/back/Controllers/Extensions/AddReposExt.cs b/back/Controllers/Extensions/AddReposExt.cs index 9793b6e..5da333a 100644 --- a/back/Controllers/Extensions/AddReposExt.cs +++ b/back/Controllers/Extensions/AddReposExt.cs @@ -12,5 +12,6 @@ public static class AddReposExtension services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); } } \ No newline at end of file diff --git a/back/Services/Domain/SpendingPlanService.cs b/back/Services/Domain/SpendingPlanService.cs index d565869..ff655d0 100644 --- a/back/Services/Domain/SpendingPlanService.cs +++ b/back/Services/Domain/SpendingPlanService.cs @@ -17,13 +17,13 @@ public class SpendingPlanService : ISpendingPlanService _spendingPlanRepo = spendingPlanRepo; } - public async Task Create(SpendingPlanDto spendingPlan) + public async Task Create(SpendingPlanDto spendingPlan) { var plan = await _spendingPlanRepo.Create(spendingPlan); return plan.ToView(); } - public async Task Delete(SpendingPlanSearch search) + public async Task Delete(SpendingPlanSearch search) { var plan = await _spendingPlanRepo.Delete(search); if (plan == null) @@ -33,7 +33,7 @@ public class SpendingPlanService : ISpendingPlanService return plan.ToView(); } - public async Task GetDetails(SpendingPlanSearch search) + public async Task GetDetails(SpendingPlanSearch search) { var plan = await _spendingPlanRepo.Get(search); if (plan == null) @@ -43,13 +43,13 @@ public class SpendingPlanService : ISpendingPlanService return plan.ToView(); } - public async Task> GetList(SpendingPlanSearch? search = null) + public async Task> GetList(SpendingPlanSearch? search = null) { var plans = await _spendingPlanRepo.GetList(search); return plans.Select(x => x.ToView()).ToList(); } - public async Task Update(SpendingPlanDto spendingPlan) + public async Task Update(SpendingPlanDto spendingPlan) { var plan = await _spendingPlanRepo.Update(spendingPlan); if (plan == null) From 83b75bed07c2f3e311aa6aca05425f9f5cccfbf0 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Wed, 27 Nov 2024 02:40:02 +0400 Subject: [PATCH 25/37] =?UTF-8?q?add:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BC=D0=B8=D0=B3=D1=80=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F.=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=B3?= =?UTF-8?q?=D1=80=D1=83=D0=BF=D0=BF=D1=8B=20=D1=80=D0=B0=D1=81=D1=85=D0=BE?= =?UTF-8?q?=D0=B4=D0=BE=D0=B2=20=D0=B2=D0=BE=D0=B7=D0=B2=D1=80=D0=B0=D1=89?= =?UTF-8?q?=D0=B0=D1=8E=D1=82=D1=81=D1=8F=20=D1=81=20=D0=BF=D0=BB=D0=B0?= =?UTF-8?q?=D0=BD=D0=B0=D0=BC=D0=B8=20=D1=80=D0=B0=D1=81=D1=85=D0=BE=D0=B4?= =?UTF-8?q?=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Contracts/DTOs/SpendingGroupDto.cs | 1 + back/Contracts/Mappers/SpendingGroupMapper.cs | 3 +- .../ViewModels/SpendingGroupViewModel.cs | 1 + ...20241126222847_AddSpendingPlan.Designer.cs | 177 ++++++++++++++++++ .../20241126222847_AddSpendingPlan.cs | 48 +++++ .../DatabaseContextModelSnapshot.cs | 38 ++++ back/Infrastructure/Models/SpendingGroup.cs | 1 + .../Repositories/SpendingGroupRepo.cs | 7 +- .../Support/Mappers/SpendingGroupMapper.cs | 3 +- 9 files changed, 276 insertions(+), 3 deletions(-) create mode 100644 back/Infrastructure/Migrations/20241126222847_AddSpendingPlan.Designer.cs create mode 100644 back/Infrastructure/Migrations/20241126222847_AddSpendingPlan.cs diff --git a/back/Contracts/DTOs/SpendingGroupDto.cs b/back/Contracts/DTOs/SpendingGroupDto.cs index 2adf558..dd001fd 100644 --- a/back/Contracts/DTOs/SpendingGroupDto.cs +++ b/back/Contracts/DTOs/SpendingGroupDto.cs @@ -6,4 +6,5 @@ public class SpendingGroupDto public string Name { get; set; } = string.Empty; public Guid UserId { get; set; } public List ChangeRecords { get; set; } = new(); + public List SpendingPlans { get; set; } = new(); } \ No newline at end of file diff --git a/back/Contracts/Mappers/SpendingGroupMapper.cs b/back/Contracts/Mappers/SpendingGroupMapper.cs index f9d4cac..fd6a987 100644 --- a/back/Contracts/Mappers/SpendingGroupMapper.cs +++ b/back/Contracts/Mappers/SpendingGroupMapper.cs @@ -10,6 +10,7 @@ public static class SpendingGroupMapper { Id = dto.Id, Name = dto.Name, - ChangeRecords = dto.ChangeRecords.Select(x => x.ToView()).ToList() + ChangeRecords = dto.ChangeRecords.Select(x => x.ToView()).ToList(), + SpendingPlans = dto.SpendingPlans.Select(x => x.ToView()).ToList() }; } \ No newline at end of file diff --git a/back/Contracts/ViewModels/SpendingGroupViewModel.cs b/back/Contracts/ViewModels/SpendingGroupViewModel.cs index c22ae62..1a94317 100644 --- a/back/Contracts/ViewModels/SpendingGroupViewModel.cs +++ b/back/Contracts/ViewModels/SpendingGroupViewModel.cs @@ -5,4 +5,5 @@ public class SpendingGroupViewModel public Guid Id { get; set; } public string Name { get; set; } = string.Empty; public List ChangeRecords { get; set; } = new(); + public List SpendingPlans { get; set; } = new(); } \ No newline at end of file diff --git a/back/Infrastructure/Migrations/20241126222847_AddSpendingPlan.Designer.cs b/back/Infrastructure/Migrations/20241126222847_AddSpendingPlan.Designer.cs new file mode 100644 index 0000000..e43fe93 --- /dev/null +++ b/back/Infrastructure/Migrations/20241126222847_AddSpendingPlan.Designer.cs @@ -0,0 +1,177 @@ +// +using System; +using Infrastructure; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Infrastructure.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20241126222847_AddSpendingPlan")] + partial class AddSpendingPlan + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SpendingGroupId") + .HasColumnType("uuid"); + + b.Property("Sum") + .HasColumnType("numeric"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SpendingGroupId"); + + b.HasIndex("UserId"); + + b.ToTable("ChangeRecords"); + }); + + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("SpendingGroups"); + }); + + modelBuilder.Entity("Infrastructure.Models.SpendingPlan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("EndAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SpendingGroupId") + .HasColumnType("uuid"); + + b.Property("StartAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Sum") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("SpendingGroupId"); + + b.ToTable("SpendingPlans"); + }); + + modelBuilder.Entity("Infrastructure.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Balance") + .HasColumnType("numeric"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Password") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Infrastructure.Models.ChangeRecord", b => + { + b.HasOne("Infrastructure.Models.SpendingGroup", "SpendingGroup") + .WithMany("ChangeRecords") + .HasForeignKey("SpendingGroupId"); + + b.HasOne("Infrastructure.Models.User", "User") + .WithMany("ChangeRecords") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("SpendingGroup"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => + { + b.HasOne("Infrastructure.Models.User", "User") + .WithMany("SpendingGroups") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Infrastructure.Models.SpendingPlan", b => + { + b.HasOne("Infrastructure.Models.SpendingGroup", "SpendingGroup") + .WithMany("SpendingPlans") + .HasForeignKey("SpendingGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("SpendingGroup"); + }); + + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => + { + b.Navigation("ChangeRecords"); + + b.Navigation("SpendingPlans"); + }); + + modelBuilder.Entity("Infrastructure.Models.User", b => + { + b.Navigation("ChangeRecords"); + + b.Navigation("SpendingGroups"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/back/Infrastructure/Migrations/20241126222847_AddSpendingPlan.cs b/back/Infrastructure/Migrations/20241126222847_AddSpendingPlan.cs new file mode 100644 index 0000000..fcc2f3e --- /dev/null +++ b/back/Infrastructure/Migrations/20241126222847_AddSpendingPlan.cs @@ -0,0 +1,48 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Infrastructure.Migrations +{ + /// + public partial class AddSpendingPlan : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "SpendingPlans", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + StartAt = table.Column(type: "timestamp with time zone", nullable: false), + EndAt = table.Column(type: "timestamp with time zone", nullable: false), + Sum = table.Column(type: "numeric", nullable: false), + SpendingGroupId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SpendingPlans", x => x.Id); + table.ForeignKey( + name: "FK_SpendingPlans_SpendingGroups_SpendingGroupId", + column: x => x.SpendingGroupId, + principalTable: "SpendingGroups", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_SpendingPlans_SpendingGroupId", + table: "SpendingPlans", + column: "SpendingGroupId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "SpendingPlans"); + } + } +} diff --git a/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs b/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs index 2c7a5ef..93d0295 100644 --- a/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs +++ b/back/Infrastructure/Migrations/DatabaseContextModelSnapshot.cs @@ -69,6 +69,31 @@ namespace Infrastructure.Migrations b.ToTable("SpendingGroups"); }); + modelBuilder.Entity("Infrastructure.Models.SpendingPlan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("EndAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SpendingGroupId") + .HasColumnType("uuid"); + + b.Property("StartAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Sum") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("SpendingGroupId"); + + b.ToTable("SpendingPlans"); + }); + modelBuilder.Entity("Infrastructure.Models.User", b => { b.Property("Id") @@ -119,9 +144,22 @@ namespace Infrastructure.Migrations b.Navigation("User"); }); + modelBuilder.Entity("Infrastructure.Models.SpendingPlan", b => + { + b.HasOne("Infrastructure.Models.SpendingGroup", "SpendingGroup") + .WithMany("SpendingPlans") + .HasForeignKey("SpendingGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("SpendingGroup"); + }); + modelBuilder.Entity("Infrastructure.Models.SpendingGroup", b => { b.Navigation("ChangeRecords"); + + b.Navigation("SpendingPlans"); }); modelBuilder.Entity("Infrastructure.Models.User", b => diff --git a/back/Infrastructure/Models/SpendingGroup.cs b/back/Infrastructure/Models/SpendingGroup.cs index 889bdb6..23758eb 100644 --- a/back/Infrastructure/Models/SpendingGroup.cs +++ b/back/Infrastructure/Models/SpendingGroup.cs @@ -8,4 +8,5 @@ public class SpendingGroup public Guid UserId { get; set; } public User User { get; set; } = null!; public List? ChangeRecords { get; set; } + public List? SpendingPlans { get; set; } } \ No newline at end of file diff --git a/back/Infrastructure/Repositories/SpendingGroupRepo.cs b/back/Infrastructure/Repositories/SpendingGroupRepo.cs index d7e879e..6c8382a 100644 --- a/back/Infrastructure/Repositories/SpendingGroupRepo.cs +++ b/back/Infrastructure/Repositories/SpendingGroupRepo.cs @@ -47,6 +47,7 @@ public class SpendingGroupRepo : ISpendingGroupRepo var group = await context.SpendingGroups .Include(x => x.ChangeRecords) + .Include(x => x.SpendingPlans) .FirstOrDefaultAsync(x => x.Id == search.Id || x.Name == search.Name); @@ -72,7 +73,11 @@ public class SpendingGroupRepo : ISpendingGroupRepo } } - return await query.Include(x => x.ChangeRecords).Select(x => x.ToDto()).ToListAsync(); + return await query + .Include(x => x.ChangeRecords) + .Include(x => x.SpendingPlans) + .Select(x => x.ToDto()) + .ToListAsync(); } public async Task Update(SpendingGroupDto spendingGroup) diff --git a/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs b/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs index d74490f..9432073 100644 --- a/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs +++ b/back/Infrastructure/Support/Mappers/SpendingGroupMapper.cs @@ -11,7 +11,8 @@ public static class SpendingGroupMapper Id = group.Id, Name = group.Name, UserId = group.UserId, - ChangeRecords = group.ChangeRecords?.Select(x => x.ToDto()).ToList() ?? [] + ChangeRecords = group.ChangeRecords?.Select(x => x.ToDto()).ToList() ?? [], + SpendingPlans = group.SpendingPlans?.Select(x => x.ToDto()).ToList() ?? [] }; public static SpendingGroup ToModel(this SpendingGroupDto group) => new() From bcca40860d224bfb350d6481fafc35bd75a3445c Mon Sep 17 00:00:00 2001 From: mfnefd Date: Mon, 2 Dec 2024 23:18:40 +0400 Subject: [PATCH 26/37] =?UTF-8?q?add:=20api=20=D0=BA=D0=BB=D0=B8=D0=B5?= =?UTF-8?q?=D0=BD=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- front/.gitignore | 2 + front/src/core/api/Api.ts | 460 +++++++++++++++++++++++++++ front/src/core/api/data-contracts.ts | 96 ++++++ front/src/core/api/http-client.ts | 220 +++++++++++++ 4 files changed, 778 insertions(+) create mode 100644 front/src/core/api/Api.ts create mode 100644 front/src/core/api/data-contracts.ts create mode 100644 front/src/core/api/http-client.ts diff --git a/front/.gitignore b/front/.gitignore index a547bf3..3b0b403 100644 --- a/front/.gitignore +++ b/front/.gitignore @@ -22,3 +22,5 @@ dist-ssr *.njsproj *.sln *.sw? + +.env \ No newline at end of file diff --git a/front/src/core/api/Api.ts b/front/src/core/api/Api.ts new file mode 100644 index 0000000..ab58717 --- /dev/null +++ b/front/src/core/api/Api.ts @@ -0,0 +1,460 @@ +/* eslint-disable */ +/* tslint:disable */ +/* + * --------------------------------------------------------------- + * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## + * ## ## + * ## AUTHOR: acacode ## + * ## SOURCE: https://github.com/acacode/swagger-typescript-api ## + * --------------------------------------------------------------- + */ + +import { + ChangeRecordDto, + ChangeRecordViewModel, + SpendingGroupDto, + SpendingGroupViewModel, + SpendingPlanDto, + SpendingPlanViewModel, + UserDto, + UserLoginDTO, + UserViewModel, +} from "./data-contracts"; +import { ContentType, HttpClient, RequestParams } from "./http-client"; + +export class Api extends HttpClient { + /** + * No description + * + * @tags Auth + * @name AuthCreate + * @request POST:/api/Auth + * @response `200` `UserViewModel` Success + */ + authCreate = (data: UserLoginDTO, params: RequestParams = {}) => + this.request({ + path: `/api/Auth`, + method: "POST", + body: data, + type: ContentType.Json, + format: "json", + ...params, + }); + /** + * No description + * + * @tags Auth + * @name AuthRegisterCreate + * @request POST:/api/Auth/register + * @response `200` `UserViewModel` Success + */ + authRegisterCreate = (data: UserDto, params: RequestParams = {}) => + this.request({ + path: `/api/Auth/register`, + method: "POST", + body: data, + type: ContentType.Json, + format: "json", + ...params, + }); + /** + * No description + * + * @tags ChangeRecord + * @name ChangeRecordCreate + * @request POST:/api/ChangeRecord + * @response `200` `ChangeRecordViewModel` Success + */ + changeRecordCreate = (data: ChangeRecordDto, params: RequestParams = {}) => + this.request({ + path: `/api/ChangeRecord`, + method: "POST", + body: data, + type: ContentType.Json, + format: "json", + ...params, + }); + /** + * No description + * + * @tags ChangeRecord + * @name ChangeRecordList + * @request GET:/api/ChangeRecord + * @response `200` `(ChangeRecordViewModel)[]` Success + */ + changeRecordList = (params: RequestParams = {}) => + this.request({ + path: `/api/ChangeRecord`, + method: "GET", + format: "json", + ...params, + }); + /** + * No description + * + * @tags ChangeRecord + * @name ChangeRecordPartialUpdate + * @request PATCH:/api/ChangeRecord + * @response `200` `ChangeRecordViewModel` Success + */ + changeRecordPartialUpdate = (data: ChangeRecordDto, params: RequestParams = {}) => + this.request({ + path: `/api/ChangeRecord`, + method: "PATCH", + body: data, + type: ContentType.Json, + format: "json", + ...params, + }); + /** + * No description + * + * @tags ChangeRecord + * @name ChangeRecordDelete + * @request DELETE:/api/ChangeRecord + * @response `200` `void` Success + */ + changeRecordDelete = ( + query?: { + /** @format uuid */ + Id?: string; + /** @format uuid */ + SpendingGroupId?: string; + /** @format date-time */ + From?: string; + /** @format date-time */ + To?: string; + }, + params: RequestParams = {}, + ) => + this.request({ + path: `/api/ChangeRecord`, + method: "DELETE", + query: query, + ...params, + }); + /** + * No description + * + * @tags ChangeRecord + * @name ChangeRecordFilterList + * @request GET:/api/ChangeRecord/filter + * @response `200` `(ChangeRecordViewModel)[]` Success + */ + changeRecordFilterList = ( + query?: { + /** @format uuid */ + Id?: string; + /** @format uuid */ + SpendingGroupId?: string; + /** @format date-time */ + From?: string; + /** @format date-time */ + To?: string; + }, + params: RequestParams = {}, + ) => + this.request({ + path: `/api/ChangeRecord/filter`, + method: "GET", + query: query, + format: "json", + ...params, + }); + /** + * No description + * + * @tags SpendingGroup + * @name SpendingGroupDetail + * @request GET:/api/SpendingGroup/{id} + * @response `200` `SpendingGroupViewModel` Success + */ + spendingGroupDetail = ( + id: string, + query?: { + /** @format uuid */ + Id?: string; + Name?: string; + }, + params: RequestParams = {}, + ) => + this.request({ + path: `/api/SpendingGroup/${id}`, + method: "GET", + query: query, + format: "json", + ...params, + }); + /** + * No description + * + * @tags SpendingGroup + * @name SpendingGroupList + * @request GET:/api/SpendingGroup + * @response `200` `(SpendingGroupViewModel)[]` Success + */ + spendingGroupList = (params: RequestParams = {}) => + this.request({ + path: `/api/SpendingGroup`, + method: "GET", + format: "json", + ...params, + }); + /** + * No description + * + * @tags SpendingGroup + * @name SpendingGroupCreate + * @request POST:/api/SpendingGroup + * @response `200` `SpendingGroupViewModel` Success + */ + spendingGroupCreate = (data: SpendingGroupDto, params: RequestParams = {}) => + this.request({ + path: `/api/SpendingGroup`, + method: "POST", + body: data, + type: ContentType.Json, + format: "json", + ...params, + }); + /** + * No description + * + * @tags SpendingGroup + * @name SpendingGroupPartialUpdate + * @request PATCH:/api/SpendingGroup + * @response `200` `SpendingGroupViewModel` Success + */ + spendingGroupPartialUpdate = (data: SpendingGroupDto, params: RequestParams = {}) => + this.request({ + path: `/api/SpendingGroup`, + method: "PATCH", + body: data, + type: ContentType.Json, + format: "json", + ...params, + }); + /** + * No description + * + * @tags SpendingGroup + * @name SpendingGroupDelete + * @request DELETE:/api/SpendingGroup + * @response `200` `void` Success + */ + spendingGroupDelete = ( + query?: { + /** @format uuid */ + Id?: string; + Name?: string; + }, + params: RequestParams = {}, + ) => + this.request({ + path: `/api/SpendingGroup`, + method: "DELETE", + query: query, + ...params, + }); + /** + * No description + * + * @tags SpendingGroup + * @name SpendingGroupFilterList + * @request GET:/api/SpendingGroup/filter + * @response `200` `(SpendingGroupViewModel)[]` Success + */ + spendingGroupFilterList = ( + query?: { + /** @format uuid */ + Id?: string; + Name?: string; + }, + params: RequestParams = {}, + ) => + this.request({ + path: `/api/SpendingGroup/filter`, + method: "GET", + query: query, + format: "json", + ...params, + }); + /** + * No description + * + * @tags SpendingPlan + * @name SpendingPlanDetail + * @request GET:/api/SpendingPlan/{id} + * @response `200` `SpendingPlanViewModel` Success + */ + spendingPlanDetail = ( + id: string, + query?: { + /** @format uuid */ + Id?: string; + }, + params: RequestParams = {}, + ) => + this.request({ + path: `/api/SpendingPlan/${id}`, + method: "GET", + query: query, + format: "json", + ...params, + }); + /** + * No description + * + * @tags SpendingPlan + * @name SpendingPlanList + * @request GET:/api/SpendingPlan + * @response `200` `(SpendingPlanViewModel)[]` Success + */ + spendingPlanList = (params: RequestParams = {}) => + this.request({ + path: `/api/SpendingPlan`, + method: "GET", + format: "json", + ...params, + }); + /** + * No description + * + * @tags SpendingPlan + * @name SpendingPlanCreate + * @request POST:/api/SpendingPlan + * @response `200` `SpendingPlanViewModel` Success + */ + spendingPlanCreate = (data: SpendingPlanDto, params: RequestParams = {}) => + this.request({ + path: `/api/SpendingPlan`, + method: "POST", + body: data, + type: ContentType.Json, + format: "json", + ...params, + }); + /** + * No description + * + * @tags SpendingPlan + * @name SpendingPlanPartialUpdate + * @request PATCH:/api/SpendingPlan + * @response `200` `SpendingPlanViewModel` Success + */ + spendingPlanPartialUpdate = (data: SpendingPlanDto, params: RequestParams = {}) => + this.request({ + path: `/api/SpendingPlan`, + method: "PATCH", + body: data, + type: ContentType.Json, + format: "json", + ...params, + }); + /** + * No description + * + * @tags SpendingPlan + * @name SpendingPlanDelete + * @request DELETE:/api/SpendingPlan + * @response `200` `void` Success + */ + spendingPlanDelete = ( + query?: { + /** @format uuid */ + Id?: string; + }, + params: RequestParams = {}, + ) => + this.request({ + path: `/api/SpendingPlan`, + method: "DELETE", + query: query, + ...params, + }); + /** + * No description + * + * @tags SpendingPlan + * @name SpendingPlanFilterList + * @request GET:/api/SpendingPlan/filter + * @response `200` `(SpendingPlanViewModel)[]` Success + */ + spendingPlanFilterList = ( + query?: { + /** @format uuid */ + Id?: string; + }, + params: RequestParams = {}, + ) => + this.request({ + path: `/api/SpendingPlan/filter`, + method: "GET", + query: query, + format: "json", + ...params, + }); + /** + * No description + * + * @tags User + * @name UserList + * @request GET:/api/User + * @response `200` `UserViewModel` Success + */ + userList = ( + query?: { + /** @format uuid */ + Id?: string; + Name?: string; + }, + params: RequestParams = {}, + ) => + this.request({ + path: `/api/User`, + method: "GET", + query: query, + format: "json", + ...params, + }); + /** + * No description + * + * @tags User + * @name UserPartialUpdate + * @request PATCH:/api/User + * @response `200` `UserViewModel` Success + */ + userPartialUpdate = (data: UserDto, params: RequestParams = {}) => + this.request({ + path: `/api/User`, + method: "PATCH", + body: data, + type: ContentType.Json, + format: "json", + ...params, + }); + /** + * No description + * + * @tags User + * @name UserDelete + * @request DELETE:/api/User + * @response `200` `UserViewModel` Success + */ + userDelete = ( + query?: { + /** @format uuid */ + Id?: string; + Name?: string; + }, + params: RequestParams = {}, + ) => + this.request({ + path: `/api/User`, + method: "DELETE", + query: query, + format: "json", + ...params, + }); +} diff --git a/front/src/core/api/data-contracts.ts b/front/src/core/api/data-contracts.ts new file mode 100644 index 0000000..1788da0 --- /dev/null +++ b/front/src/core/api/data-contracts.ts @@ -0,0 +1,96 @@ +/* eslint-disable */ +/* tslint:disable */ +/* + * --------------------------------------------------------------- + * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## + * ## ## + * ## AUTHOR: acacode ## + * ## SOURCE: https://github.com/acacode/swagger-typescript-api ## + * --------------------------------------------------------------- + */ + +export interface ChangeRecordDto { + /** @format uuid */ + id?: string; + /** @format uuid */ + userId?: string; + /** @format uuid */ + spendingGroupId?: string | null; + /** @format double */ + sum?: number; + /** @format date-time */ + changedAt?: string; +} + +export interface ChangeRecordViewModel { + /** @format uuid */ + id?: string; + /** @format double */ + sum?: number; + /** @format date-time */ + changedAt?: string; +} + +export interface SpendingGroupDto { + /** @format uuid */ + id?: string; + name?: string | null; + /** @format uuid */ + userId?: string; + changeRecords?: ChangeRecordDto[] | null; + spendingPlans?: SpendingPlanDto[] | null; +} + +export interface SpendingGroupViewModel { + /** @format uuid */ + id?: string; + name?: string | null; + changeRecords?: ChangeRecordViewModel[] | null; + spendingPlans?: SpendingPlanViewModel[] | null; +} + +export interface SpendingPlanDto { + /** @format uuid */ + id?: string; + /** @format uuid */ + spendingGroupId?: string; + /** @format double */ + sum?: number; + /** @format date-time */ + startAt?: string; + /** @format date-time */ + endAt?: string; +} + +export interface SpendingPlanViewModel { + /** @format uuid */ + id?: string; + /** @format date-time */ + startAt?: string; + /** @format date-time */ + endAt?: string; + /** @format double */ + sum?: number; +} + +export interface UserDto { + /** @format uuid */ + id?: string; + name?: string | null; + password?: string | null; + /** @format double */ + balance?: number; +} + +export interface UserLoginDTO { + name?: string | null; + password?: string | null; +} + +export interface UserViewModel { + /** @format uuid */ + id?: string; + name?: string | null; + /** @format double */ + balance?: number; +} diff --git a/front/src/core/api/http-client.ts b/front/src/core/api/http-client.ts new file mode 100644 index 0000000..db03d42 --- /dev/null +++ b/front/src/core/api/http-client.ts @@ -0,0 +1,220 @@ +/* eslint-disable */ +/* tslint:disable */ +/* + * --------------------------------------------------------------- + * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## + * ## ## + * ## AUTHOR: acacode ## + * ## SOURCE: https://github.com/acacode/swagger-typescript-api ## + * --------------------------------------------------------------- + */ + +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ + secure?: boolean; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: ResponseFormat; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} + +export type RequestParams = Omit; + +export interface ApiConfig { + baseUrl?: string; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType | null) => Promise | RequestParams | void; + customFetch?: typeof fetch; +} + +export interface HttpResponse extends Response { + data: D; + error: E; +} + +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", + Text = "text/plain", +} + +export class HttpClient { + public baseUrl: string = ""; + private securityData: SecurityDataType | null = null; + private securityWorker?: ApiConfig["securityWorker"]; + private abortControllers = new Map(); + private customFetch = (...fetchParams: Parameters) => fetch(...fetchParams); + + private baseApiParams: RequestParams = { + credentials: "same-origin", + headers: {}, + redirect: "follow", + referrerPolicy: "no-referrer", + }; + + constructor(apiConfig: ApiConfig = {}) { + Object.assign(this, apiConfig); + } + + public setSecurityData = (data: SecurityDataType | null) => { + this.securityData = data; + }; + + protected encodeQueryParam(key: string, value: any) { + const encodedKey = encodeURIComponent(key); + return `${encodedKey}=${encodeURIComponent(typeof value === "number" ? value : `${value}`)}`; + } + + protected addQueryParam(query: QueryParamsType, key: string) { + return this.encodeQueryParam(key, query[key]); + } + + protected addArrayQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return value.map((v: any) => this.encodeQueryParam(key, v)).join("&"); + } + + protected toQueryString(rawQuery?: QueryParamsType): string { + const query = rawQuery || {}; + const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); + return keys + .map((key) => (Array.isArray(query[key]) ? this.addArrayQueryParam(query, key) : this.addQueryParam(query, key))) + .join("&"); + } + + protected addQueryParams(rawQuery?: QueryParamsType): string { + const queryString = this.toQueryString(rawQuery); + return queryString ? `?${queryString}` : ""; + } + + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => + input !== null && (typeof input === "object" || typeof input === "string") ? JSON.stringify(input) : input, + [ContentType.Text]: (input: any) => (input !== null && typeof input !== "string" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((formData, key) => { + const property = input[key]; + formData.append( + key, + property instanceof Blob + ? property + : typeof property === "object" && property !== null + ? JSON.stringify(property) + : `${property}`, + ); + return formData; + }, new FormData()), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), + }; + + protected mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { + return { + ...this.baseApiParams, + ...params1, + ...(params2 || {}), + headers: { + ...(this.baseApiParams.headers || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), + }, + }; + } + + protected createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; + }; + + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = async ({ + body, + secure, + path, + type, + query, + format, + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = + ((typeof secure === "boolean" ? secure : this.baseApiParams.secure) && + this.securityWorker && + (await this.securityWorker(this.securityData))) || + {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + const responseFormat = format || requestParams.format; + + return this.customFetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + ...requestParams, + headers: { + ...(requestParams.headers || {}), + ...(type && type !== ContentType.FormData ? { "Content-Type": type } : {}), + }, + signal: (cancelToken ? this.createAbortSignal(cancelToken) : requestParams.signal) || null, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response.clone() as HttpResponse; + r.data = null as unknown as T; + r.error = null as unknown as E; + + const data = !responseFormat + ? r + : await response[responseFormat]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } + + if (!response.ok) throw data; + return data; + }); + }; +} From c1d1e91594417b2b33279992b94c134fd06d99cc Mon Sep 17 00:00:00 2001 From: mfnefd Date: Mon, 2 Dec 2024 23:19:00 +0400 Subject: [PATCH 27/37] =?UTF-8?q?add:=20=D1=85=D0=B5=D0=B4=D0=B5=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- front/src/App.vue | 9 +++++++-- front/src/components/main/Header.vue | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 front/src/components/main/Header.vue diff --git a/front/src/App.vue b/front/src/App.vue index bbb0db4..751fbfd 100644 --- a/front/src/App.vue +++ b/front/src/App.vue @@ -1,9 +1,14 @@ + + \ No newline at end of file diff --git a/front/src/components/main/Header.vue b/front/src/components/main/Header.vue new file mode 100644 index 0000000..219a6ff --- /dev/null +++ b/front/src/components/main/Header.vue @@ -0,0 +1,18 @@ + + + + + From ae0db073a2dfdba7b8157fa550f077f8f4af25f5 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Mon, 2 Dec 2024 23:22:24 +0400 Subject: [PATCH 28/37] =?UTF-8?q?add:=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5?= =?UTF-8?q?=D1=80=D0=B6=D0=BA=D0=B0=20vuex,=20=D1=82=D0=B5=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D1=8C=20=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=20=D1=85=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=82=D1=8C=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D1=8C=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- front/package-lock.json | 790 +++++++++++++++++++++++++++++++++++++++- front/package.json | 7 +- front/src/main.ts | 7 +- front/src/store.ts | 20 + 4 files changed, 820 insertions(+), 4 deletions(-) create mode 100644 front/src/store.ts diff --git a/front/package-lock.json b/front/package-lock.json index 7fb419c..f3c1dca 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -8,15 +8,32 @@ "name": "dombudg", "version": "0.0.0", "dependencies": { - "vue": "^3.5.12" + "vue": "^3.5.12", + "vuex": "^4.1.0" }, "devDependencies": { "@vitejs/plugin-vue": "^5.1.4", + "swagger-typescript-api": "^13.0.23", "typescript": "~5.6.2", "vite": "^5.4.10", "vue-tsc": "^2.1.8" } }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", @@ -454,6 +471,13 @@ "node": ">=12" } }, + "node_modules/@exodus/schemasafe": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz", + "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==", + "dev": true, + "license": "MIT" + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", @@ -719,6 +743,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/swagger-schema-official": { + "version": "2.0.25", + "resolved": "https://registry.npmjs.org/@types/swagger-schema-official/-/swagger-schema-official-2.0.25.tgz", + "integrity": "sha512-T92Xav+Gf/Ik1uPW581nA+JftmjWPgskw/WBf4TJzxRG/SJ+DfNnNE+WuZ4mrXuzflQMqMkm1LSYjzYW7MB1Cg==", + "dev": true, + "license": "MIT" + }, "node_modules/@vitejs/plugin-vue": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.0.tgz", @@ -823,6 +854,12 @@ "he": "^1.2.0" } }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, "node_modules/@vue/language-core": { "version": "2.1.10", "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.1.10.tgz", @@ -905,6 +942,39 @@ "dev": true, "license": "MIT" }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -922,6 +992,95 @@ "balanced-match": "^1.0.0" } }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", + "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -935,6 +1094,20 @@ "dev": true, "license": "MIT" }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -947,6 +1120,33 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", + "dev": true, + "license": "MIT" + }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", @@ -986,12 +1186,42 @@ "@esbuild/win32-x64": "0.21.5" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "license": "MIT" }, + "node_modules/eta": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.2.0.tgz", + "integrity": "sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "url": "https://github.com/eta-dev/eta?sponsor=1" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1007,6 +1237,16 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -1017,6 +1257,88 @@ "he": "bin/he" } }, + "node_modules/http2-client": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz", + "integrity": "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, "node_modules/magic-string": { "version": "0.30.13", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.13.tgz", @@ -1067,6 +1389,157 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch-h2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", + "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "http2-client": "^1.2.5" + }, + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-readfiles": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz", + "integrity": "sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es6-promise": "^3.2.1" + } + }, + "node_modules/oas-kit-common": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz", + "integrity": "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "fast-safe-stringify": "^2.0.7" + } + }, + "node_modules/oas-linter": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/oas-linter/-/oas-linter-3.2.2.tgz", + "integrity": "sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@exodus/schemasafe": "^1.0.0-rc.2", + "should": "^13.2.1", + "yaml": "^1.10.0" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-resolver": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/oas-resolver/-/oas-resolver-2.5.6.tgz", + "integrity": "sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "node-fetch-h2": "^2.3.0", + "oas-kit-common": "^1.0.8", + "reftools": "^1.1.9", + "yaml": "^1.10.0", + "yargs": "^17.0.1" + }, + "bin": { + "resolve": "resolve.js" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-schema-walker": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz", + "integrity": "sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==", + "dev": true, + "license": "BSD-3-Clause", + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-validator": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/oas-validator/-/oas-validator-5.0.8.tgz", + "integrity": "sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "call-me-maybe": "^1.0.1", + "oas-kit-common": "^1.0.8", + "oas-linter": "^3.2.2", + "oas-resolver": "^2.5.6", + "oas-schema-walker": "^1.1.5", + "reftools": "^1.1.9", + "should": "^13.2.1", + "yaml": "^1.10.0" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -1108,6 +1581,52 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/reftools": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz", + "integrity": "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==", + "dev": true, + "license": "BSD-3-Clause", + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/rollup": { "version": "4.27.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz", @@ -1159,6 +1678,66 @@ "node": ">=10" } }, + "node_modules/should": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "node_modules/should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "should-type": "^1.4.0" + } + }, + "node_modules/should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "node_modules/should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "node_modules/should-util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", + "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", + "dev": true, + "license": "MIT" + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -1168,6 +1747,118 @@ "node": ">=0.10.0" } }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/swagger-schema-official": { + "version": "2.0.0-bab6bed", + "resolved": "https://registry.npmjs.org/swagger-schema-official/-/swagger-schema-official-2.0.0-bab6bed.tgz", + "integrity": "sha512-rCC0NWGKr/IJhtRuPq/t37qvZHI/mH4I4sxflVM+qgVe5Z2uOCivzWaVbuioJaB61kvm5UvB7b49E+oBY0M8jA==", + "dev": true, + "license": "ISC" + }, + "node_modules/swagger-typescript-api": { + "version": "13.0.23", + "resolved": "https://registry.npmjs.org/swagger-typescript-api/-/swagger-typescript-api-13.0.23.tgz", + "integrity": "sha512-HhoIepxlFEU7Ol42Gh8/tvwhSxdkHcweX2tRkNhbZYBiEA+rK3C6N85MnwoeQR5XbidE3Kz8mLOqIerVGgR9uw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/swagger-schema-official": "^2.0.25", + "consola": "^3.2.3", + "cosmiconfig": "^9.0.0", + "didyoumean": "^1.2.2", + "eta": "^2.2.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "nanoid": "^3.3.7", + "prettier": "~3.3.3", + "swagger-schema-official": "2.0.0-bab6bed", + "swagger2openapi": "^7.0.8", + "typescript": "~5.5.4" + }, + "bin": { + "sta": "dist/cli.js", + "swagger-typescript-api": "dist/cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/swagger-typescript-api/node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/swagger2openapi": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz", + "integrity": "sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "call-me-maybe": "^1.0.1", + "node-fetch": "^2.6.1", + "node-fetch-h2": "^2.3.0", + "node-readfiles": "^0.2.0", + "oas-kit-common": "^1.0.8", + "oas-resolver": "^2.5.6", + "oas-schema-walker": "^1.1.5", + "oas-validator": "^5.0.8", + "reftools": "^1.1.9", + "yaml": "^1.10.0", + "yargs": "^17.0.1" + }, + "bin": { + "boast": "boast.js", + "oas-validate": "oas-validate.js", + "swagger2openapi": "swagger2openapi.js" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, "node_modules/typescript": { "version": "5.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", @@ -1287,6 +1978,103 @@ "peerDependencies": { "typescript": ">=5.0.0" } + }, + "node_modules/vuex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.1.0.tgz", + "integrity": "sha512-hmV6UerDrPcgbSy9ORAtNXDr9M4wlNP4pEFKye4ujJF8oqgFFuxDCdOLS3eNoRTtq5O3hoBDh9Doj1bQMYHRbQ==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.0.0-beta.11" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } } } } diff --git a/front/package.json b/front/package.json index a3857a9..1bc180c 100644 --- a/front/package.json +++ b/front/package.json @@ -6,13 +6,16 @@ "scripts": { "dev": "vite", "build": "vue-tsc -b && vite build", - "preview": "vite preview" + "preview": "vite preview", + "gen-api": "swagger-typescript-api -r -o ./src/core/api/ --modular -p " }, "dependencies": { - "vue": "^3.5.12" + "vue": "^3.5.12", + "vuex": "^4.1.0" }, "devDependencies": { "@vitejs/plugin-vue": "^5.1.4", + "swagger-typescript-api": "^13.0.23", "typescript": "~5.6.2", "vite": "^5.4.10", "vue-tsc": "^2.1.8" diff --git a/front/src/main.ts b/front/src/main.ts index 2425c0f..16b6431 100644 --- a/front/src/main.ts +++ b/front/src/main.ts @@ -1,5 +1,10 @@ import { createApp } from 'vue' import './style.css' import App from './App.vue' +import { key, store } from './store' -createApp(App).mount('#app') +const app = createApp(App) + +app.use(store, key) + +app.mount('#app') diff --git a/front/src/store.ts b/front/src/store.ts new file mode 100644 index 0000000..573a419 --- /dev/null +++ b/front/src/store.ts @@ -0,0 +1,20 @@ +import { InjectionKey } from 'vue' +import { createStore, Store } from 'vuex' +import { UserViewModel } from './core/api/data-contracts' + +export interface State { + user: UserViewModel | null +} + +export const key: InjectionKey> = Symbol() + +export const store = createStore({ + state: { + user: null + }, + mutations: { + setUser(state: any, user: UserViewModel) { + state.user = user + } + } +}) From bc5992552a2f8ac71ab8f534cb688fbb1703c926 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Mon, 2 Dec 2024 23:44:01 +0400 Subject: [PATCH 29/37] =?UTF-8?q?add:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20=D1=80=D0=BE=D1=83=D1=82=D0=B5=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- front/package-lock.json | 846 +++++++++++++++++++++++++++- front/package.json | 3 + front/src/App.vue | 2 +- front/src/components/pages/Home.vue | 11 + front/src/main.ts | 2 + front/src/router.ts | 11 + 6 files changed, 869 insertions(+), 6 deletions(-) create mode 100644 front/src/components/pages/Home.vue create mode 100644 front/src/router.ts diff --git a/front/package-lock.json b/front/package-lock.json index f3c1dca..0c06863 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -8,17 +8,58 @@ "name": "dombudg", "version": "0.0.0", "dependencies": { + "ant-design-vue": "^4.2.6", "vue": "^3.5.12", + "vue-router": "^4.5.0", "vuex": "^4.1.0" }, "devDependencies": { "@vitejs/plugin-vue": "^5.1.4", "swagger-typescript-api": "^13.0.23", "typescript": "~5.6.2", + "unplugin-vue-components": "^0.27.5", "vite": "^5.4.10", "vue-tsc": "^2.1.8" } }, + "node_modules/@ant-design/colors": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz", + "integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^3.4.0" + } + }, + "node_modules/@ant-design/icons-svg": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz", + "integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==", + "license": "MIT" + }, + "node_modules/@ant-design/icons-vue": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons-vue/-/icons-vue-7.0.1.tgz", + "integrity": "sha512-eCqY2unfZK6Fe02AwFlDHLfoyEFreP6rBwAZMIJ1LugmfMiVgwWDYlp1YsRugaPtICYOabV1iWxXdP12u9U43Q==", + "license": "MIT", + "dependencies": { + "@ant-design/colors": "^6.0.0", + "@ant-design/icons-svg": "^4.2.1" + }, + "peerDependencies": { + "vue": ">=3.0.3" + } + }, + "node_modules/@antfu/utils": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/@babel/code-frame": { "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", @@ -67,6 +108,18 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/types": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", @@ -80,6 +133,27 @@ "node": ">=6.9.0" } }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", + "license": "MIT" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -484,6 +558,67 @@ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "license": "MIT" }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", + "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.27.4", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz", @@ -736,6 +871,16 @@ "win32" ] }, + "node_modules/@simonwep/pickr": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@simonwep/pickr/-/pickr-1.8.2.tgz", + "integrity": "sha512-/l5w8BIkrpP6n1xsetx9MWPWlU6OblN5YgZZphxan0Tq4BByTCETL6lyIeY8lagalS2Nbt4F2W034KHLIiunKA==", + "license": "MIT", + "dependencies": { + "core-js": "^3.15.1", + "nanopop": "^2.1.0" + } + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -935,6 +1080,19 @@ "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", "license": "MIT" }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/alien-signals": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-0.2.2.tgz", @@ -968,6 +1126,73 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/ant-design-vue": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-4.2.6.tgz", + "integrity": "sha512-t7eX13Yj3i9+i5g9lqFyYneoIb3OzTvQjq9Tts1i+eiOd3Eva/6GagxBSXM1fOCjqemIu0FYVE1ByZ/38epR3Q==", + "license": "MIT", + "dependencies": { + "@ant-design/colors": "^6.0.0", + "@ant-design/icons-vue": "^7.0.0", + "@babel/runtime": "^7.10.5", + "@ctrl/tinycolor": "^3.5.0", + "@emotion/hash": "^0.9.0", + "@emotion/unitless": "^0.8.0", + "@simonwep/pickr": "~1.8.0", + "array-tree-filter": "^2.1.0", + "async-validator": "^4.0.0", + "csstype": "^3.1.1", + "dayjs": "^1.10.5", + "dom-align": "^1.12.1", + "dom-scroll-into-view": "^2.0.0", + "lodash": "^4.17.21", + "lodash-es": "^4.17.15", + "resize-observer-polyfill": "^1.5.1", + "scroll-into-view-if-needed": "^2.2.25", + "shallow-equal": "^1.0.0", + "stylis": "^4.1.3", + "throttle-debounce": "^5.0.0", + "vue-types": "^3.0.0", + "warning": "^4.0.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ant-design-vue" + }, + "peerDependencies": { + "vue": ">=3.2.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -975,6 +1200,18 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/array-tree-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz", + "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==", + "license": "MIT" + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", + "license": "MIT" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -982,6 +1219,19 @@ "dev": true, "license": "MIT" }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -992,6 +1242,19 @@ "balanced-match": "^1.0.0" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/call-me-maybe": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", @@ -1009,6 +1272,31 @@ "node": ">=6" } }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -1044,6 +1332,19 @@ "dev": true, "license": "MIT" }, + "node_modules/compute-scroll-into-view": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz", + "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==", + "license": "MIT" + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, "node_modules/consola": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", @@ -1054,6 +1355,17 @@ "node": "^14.18.0 || >=16.10.0" } }, + "node_modules/core-js": { + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz", + "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/cosmiconfig": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", @@ -1087,6 +1399,12 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, "node_modules/de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", @@ -1094,6 +1412,24 @@ "dev": true, "license": "MIT" }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -1101,6 +1437,18 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/dom-align": { + "version": "1.12.4", + "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.4.tgz", + "integrity": "sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw==", + "license": "MIT" + }, + "node_modules/dom-scroll-into-view": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/dom-scroll-into-view/-/dom-scroll-into-view-2.0.1.tgz", + "integrity": "sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w==", + "license": "MIT" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -1215,6 +1563,23 @@ "url": "https://github.com/eta-dev/eta?sponsor=1" } }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, "node_modules/fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", @@ -1222,6 +1587,29 @@ "dev": true, "license": "MIT" }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1247,6 +1635,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -1288,6 +1689,29 @@ "dev": true, "license": "MIT" }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -1298,11 +1722,42 @@ "node": ">=8" } }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", + "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -1332,22 +1787,93 @@ "dev": true, "license": "MIT" }, + "node_modules/local-pkg": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz", + "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mlly": "^1.7.3", + "pkg-types": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true, "license": "MIT" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/magic-string": { - "version": "0.30.13", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.13.tgz", - "integrity": "sha512-8rYBO+MsWkgjDSOvLomYnzhdwEG51olQ4zL5KXnNJWV5MNmrb4rTZdrtkhxjnD/QyZUqR/Z/XDsUs/4ej2nx0g==", + "version": "0.30.14", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz", + "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -1364,6 +1890,26 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/mlly": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.3.tgz", + "integrity": "sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "pathe": "^1.1.2", + "pkg-types": "^1.2.1", + "ufo": "^1.5.4" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, "node_modules/muggle-string": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", @@ -1389,6 +1935,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/nanopop": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/nanopop/-/nanopop-2.4.2.tgz", + "integrity": "sha512-NzOgmMQ+elxxHeIha+OG/Pv3Oc3p4RU2aBhwWwAqDpXrdTbtRylbRLQztLy8dMMwfl6pclznBdfUhccEn9ZIzw==", + "license": "MIT" + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -1433,6 +1985,16 @@ "es6-promise": "^3.2.1" } }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/oas-kit-common": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz", @@ -1547,12 +2109,44 @@ "dev": true, "license": "MIT" }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-types": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.1.tgz", + "integrity": "sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.2", + "pathe": "^1.1.2" + } + }, "node_modules/postcss": { "version": "8.4.49", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", @@ -1597,6 +2191,53 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/reftools": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz", @@ -1607,6 +2248,12 @@ "url": "https://github.com/Mermade/oas-kit?sponsor=1" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -1617,6 +2264,12 @@ "node": ">=0.10.0" } }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==", + "license": "MIT" + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -1627,6 +2280,17 @@ "node": ">=4" } }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rollup": { "version": "4.27.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz", @@ -1665,6 +2329,39 @@ "fsevents": "~2.3.2" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scroll-into-view-if-needed": { + "version": "2.2.31", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz", + "integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==", + "license": "MIT", + "dependencies": { + "compute-scroll-into-view": "^1.0.20" + } + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -1678,6 +2375,12 @@ "node": ">=10" } }, + "node_modules/shallow-equal": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", + "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==", + "license": "MIT" + }, "node_modules/should": { "version": "13.2.3", "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", @@ -1775,6 +2478,12 @@ "node": ">=8" } }, + "node_modules/stylis": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz", + "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==", + "license": "MIT" + }, "node_modules/swagger-schema-official": { "version": "2.0.0-bab6bed", "resolved": "https://registry.npmjs.org/swagger-schema-official/-/swagger-schema-official-2.0.0-bab6bed.tgz", @@ -1852,6 +2561,28 @@ "url": "https://github.com/Mermade/oas-kit?sponsor=1" } }, + "node_modules/throttle-debounce": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz", + "integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==", + "license": "MIT", + "engines": { + "node": ">=12.22" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -1873,6 +2604,65 @@ "node": ">=14.17" } }, + "node_modules/ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unplugin": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.16.0.tgz", + "integrity": "sha512-5liCNPuJW8dqh3+DM6uNM2EI3MLLpCKp/KY+9pB5M2S2SR2qvvDHhKgBOaTWEbZTAws3CXfB0rKTIolWKL05VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/unplugin-vue-components": { + "version": "0.27.5", + "resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.27.5.tgz", + "integrity": "sha512-m9j4goBeNwXyNN8oZHHxvIIYiG8FQ9UfmKWeNllpDvhU7btKNNELGPt+o3mckQKuPwrE7e0PvCsx+IWuDSD9Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@antfu/utils": "^0.7.10", + "@rollup/pluginutils": "^5.1.3", + "chokidar": "^3.6.0", + "debug": "^4.3.7", + "fast-glob": "^3.3.2", + "local-pkg": "^0.5.1", + "magic-string": "^0.30.14", + "minimatch": "^9.0.5", + "mlly": "^1.7.3", + "unplugin": "^1.16.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@babel/parser": "^7.15.8", + "@nuxt/kit": "^3.2.2", + "vue": "2 || 3" + }, + "peerDependenciesMeta": { + "@babel/parser": { + "optional": true + }, + "@nuxt/kit": { + "optional": true + } + } + }, "node_modules/vite": { "version": "5.4.11", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", @@ -1961,6 +2751,21 @@ } } }, + "node_modules/vue-router": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.0.tgz", + "integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, "node_modules/vue-tsc": { "version": "2.1.10", "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.1.10.tgz", @@ -1979,6 +2784,21 @@ "typescript": ">=5.0.0" } }, + "node_modules/vue-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/vue-types/-/vue-types-3.0.2.tgz", + "integrity": "sha512-IwUC0Aq2zwaXqy74h4WCvFCUtoV0iSWr0snWnE9TnU18S66GAQyqQbRf2qfJtUuiFsBf6qp0MEwdonlwznlcrw==", + "license": "MIT", + "dependencies": { + "is-plain-object": "3.0.1" + }, + "engines": { + "node": ">=10.15.0" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, "node_modules/vuex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.1.0.tgz", @@ -1991,6 +2811,15 @@ "vue": "^3.2.0" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -1998,6 +2827,13 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", diff --git a/front/package.json b/front/package.json index 1bc180c..a986ca7 100644 --- a/front/package.json +++ b/front/package.json @@ -10,13 +10,16 @@ "gen-api": "swagger-typescript-api -r -o ./src/core/api/ --modular -p " }, "dependencies": { + "ant-design-vue": "^4.2.6", "vue": "^3.5.12", + "vue-router": "^4.5.0", "vuex": "^4.1.0" }, "devDependencies": { "@vitejs/plugin-vue": "^5.1.4", "swagger-typescript-api": "^13.0.23", "typescript": "~5.6.2", + "unplugin-vue-components": "^0.27.5", "vite": "^5.4.10", "vue-tsc": "^2.1.8" } diff --git a/front/src/App.vue b/front/src/App.vue index 751fbfd..231231d 100644 --- a/front/src/App.vue +++ b/front/src/App.vue @@ -5,7 +5,7 @@ import Header from './components/main/Header.vue'; diff --git a/front/src/components/pages/Home.vue b/front/src/components/pages/Home.vue new file mode 100644 index 0000000..6803de9 --- /dev/null +++ b/front/src/components/pages/Home.vue @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/front/src/main.ts b/front/src/main.ts index 16b6431..3a09299 100644 --- a/front/src/main.ts +++ b/front/src/main.ts @@ -2,9 +2,11 @@ import { createApp } from 'vue' import './style.css' import App from './App.vue' import { key, store } from './store' +import router from './router' const app = createApp(App) app.use(store, key) +app.use(router) app.mount('#app') diff --git a/front/src/router.ts b/front/src/router.ts new file mode 100644 index 0000000..87fe847 --- /dev/null +++ b/front/src/router.ts @@ -0,0 +1,11 @@ +import { createRouter, createWebHistory } from 'vue-router'; + +export default createRouter({ + history: createWebHistory(), + routes: [ + { + path: '/', + component: () => import('./components/pages/Home.vue'), + } + ], +}) From e8bb036d35b679f7e660085e8ca783022bb4ddf1 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Tue, 3 Dec 2024 02:10:20 +0400 Subject: [PATCH 30/37] =?UTF-8?q?add:=20=D1=81=D1=82=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=86=D0=B0=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BD=D0=B0,=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D1=85=D0=BE=D0=B4=20=D1=81=20vuex=20?= =?UTF-8?q?=D0=BD=D0=B0=20pinia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Controllers/Program.cs | 3 +- front/components.d.ts | 22 +++++++ front/package-lock.json | 68 +++++++++++++++++----- front/package.json | 4 +- front/src/App.vue | 7 ++- front/src/components/main/Header.vue | 10 +--- front/src/components/pages/Login.vue | 76 +++++++++++++++++++++++++ front/src/components/pages/SignUp.vue | 0 front/src/core/api/Api.ts | 6 +- front/src/core/api/data-contracts.ts | 2 +- front/src/core/api/http-client.ts | 2 +- front/src/core/services/auth-service.ts | 25 ++++++++ front/src/main.ts | 10 +++- front/src/router.ts | 6 ++ front/src/store.ts | 25 ++++---- front/vite.config.ts | 13 ++++- 16 files changed, 231 insertions(+), 48 deletions(-) create mode 100644 front/components.d.ts create mode 100644 front/src/components/pages/Login.vue create mode 100644 front/src/components/pages/SignUp.vue create mode 100644 front/src/core/services/auth-service.ts diff --git a/back/Controllers/Program.cs b/back/Controllers/Program.cs index 2e20712..2c70319 100644 --- a/back/Controllers/Program.cs +++ b/back/Controllers/Program.cs @@ -20,9 +20,10 @@ if (app.Environment.IsDevelopment()) app.UseSwagger(); app.UseSwaggerUI(); } - app.MigrateDb(); +app.UseCors(builder => builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin()); + app.UseHttpsRedirection(); app.UseAuthorization(); diff --git a/front/components.d.ts b/front/components.d.ts new file mode 100644 index 0000000..5a49b6b --- /dev/null +++ b/front/components.d.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +// @ts-nocheck +// Generated by unplugin-vue-components +// Read more: https://github.com/vuejs/core/pull/3399 +export {} + +/* prettier-ignore */ +declare module 'vue' { + export interface GlobalComponents { + AButton: typeof import('ant-design-vue/es')['Button'] + AForm: typeof import('ant-design-vue/es')['Form'] + AFormItem: typeof import('ant-design-vue/es')['FormItem'] + AInput: typeof import('ant-design-vue/es')['Input'] + AInputPassword: typeof import('ant-design-vue/es')['InputPassword'] + Header: typeof import('./src/components/main/Header.vue')['default'] + Home: typeof import('./src/components/pages/Home.vue')['default'] + Login: typeof import('./src/components/pages/Login.vue')['default'] + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + SignUp: typeof import('./src/components/pages/SignUp.vue')['default'] + } +} diff --git a/front/package-lock.json b/front/package-lock.json index 0c06863..7f99dfb 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -9,9 +9,9 @@ "version": "0.0.0", "dependencies": { "ant-design-vue": "^4.2.6", + "pinia": "^2.2.8", "vue": "^3.5.12", - "vue-router": "^4.5.0", - "vuex": "^4.1.0" + "vue-router": "^4.5.0" }, "devDependencies": { "@vitejs/plugin-vue": "^5.1.4", @@ -2135,6 +2135,58 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pinia": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.2.8.tgz", + "integrity": "sha512-NRTYy2g+kju5tBRe0oNlriZIbMNvma8ZJrpHsp3qudyiMEA8jMmPPKQ2QMHg0Oc4BkUyQYWagACabrwriCK9HQ==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.3", + "vue-demi": "^0.14.10" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "@vue/composition-api": "^1.4.0", + "typescript": ">=4.4.4", + "vue": "^2.6.14 || ^3.5.11" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/pinia/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/pkg-types": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.1.tgz", @@ -2799,18 +2851,6 @@ "vue": "^3.0.0" } }, - "node_modules/vuex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.1.0.tgz", - "integrity": "sha512-hmV6UerDrPcgbSy9ORAtNXDr9M4wlNP4pEFKye4ujJF8oqgFFuxDCdOLS3eNoRTtq5O3hoBDh9Doj1bQMYHRbQ==", - "license": "MIT", - "dependencies": { - "@vue/devtools-api": "^6.0.0-beta.11" - }, - "peerDependencies": { - "vue": "^3.2.0" - } - }, "node_modules/warning": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", diff --git a/front/package.json b/front/package.json index a986ca7..daa2045 100644 --- a/front/package.json +++ b/front/package.json @@ -11,9 +11,9 @@ }, "dependencies": { "ant-design-vue": "^4.2.6", + "pinia": "^2.2.8", "vue": "^3.5.12", - "vue-router": "^4.5.0", - "vuex": "^4.1.0" + "vue-router": "^4.5.0" }, "devDependencies": { "@vitejs/plugin-vue": "^5.1.4", diff --git a/front/src/App.vue b/front/src/App.vue index 231231d..8436d0e 100644 --- a/front/src/App.vue +++ b/front/src/App.vue @@ -10,5 +10,10 @@ import Header from './components/main/Header.vue'; \ No newline at end of file diff --git a/front/src/components/main/Header.vue b/front/src/components/main/Header.vue index 219a6ff..5a754b1 100644 --- a/front/src/components/main/Header.vue +++ b/front/src/components/main/Header.vue @@ -2,15 +2,7 @@ \ No newline at end of file diff --git a/front/src/components/pages/SignUp.vue b/front/src/components/pages/SignUp.vue new file mode 100644 index 0000000..e69de29 diff --git a/front/src/core/api/Api.ts b/front/src/core/api/Api.ts index ab58717..a9c2824 100644 --- a/front/src/core/api/Api.ts +++ b/front/src/core/api/Api.ts @@ -17,7 +17,7 @@ import { SpendingPlanDto, SpendingPlanViewModel, UserDto, - UserLoginDTO, + UserLoginDto, UserViewModel, } from "./data-contracts"; import { ContentType, HttpClient, RequestParams } from "./http-client"; @@ -31,7 +31,7 @@ export class Api extends HttpClient + auth = (data: UserLoginDto, params: RequestParams = {}) => this.request({ path: `/api/Auth`, method: "POST", @@ -48,7 +48,7 @@ export class Api extends HttpClient + authRegister = (data: UserDto, params: RequestParams = {}) => this.request({ path: `/api/Auth/register`, method: "POST", diff --git a/front/src/core/api/data-contracts.ts b/front/src/core/api/data-contracts.ts index 1788da0..9c35c81 100644 --- a/front/src/core/api/data-contracts.ts +++ b/front/src/core/api/data-contracts.ts @@ -82,7 +82,7 @@ export interface UserDto { balance?: number; } -export interface UserLoginDTO { +export interface UserLoginDto { name?: string | null; password?: string | null; } diff --git a/front/src/core/api/http-client.ts b/front/src/core/api/http-client.ts index db03d42..c338a86 100644 --- a/front/src/core/api/http-client.ts +++ b/front/src/core/api/http-client.ts @@ -55,7 +55,7 @@ export enum ContentType { } export class HttpClient { - public baseUrl: string = ""; + public baseUrl: string = "http://localhost:5125"; private securityData: SecurityDataType | null = null; private securityWorker?: ApiConfig["securityWorker"]; private abortControllers = new Map(); diff --git a/front/src/core/services/auth-service.ts b/front/src/core/services/auth-service.ts new file mode 100644 index 0000000..131d201 --- /dev/null +++ b/front/src/core/services/auth-service.ts @@ -0,0 +1,25 @@ +import { useUserStore } from "../../store"; +import { Api } from "../api/Api"; +import { UserDto, UserLoginDto } from "../api/data-contracts"; + +export class AuthService { + private readonly _api: Api; + + constructor(api: Api) { + this._api = api; + + } + async login(data: UserLoginDto) { + let result = await this._api.auth(data); + console.log(result); + const store = useUserStore(); + store.updateUser(result.data); + } + + async register(data: UserDto) { + let result = await this._api.authRegister(data); + const store = useUserStore(); + store.updateUser(result.data); + } + +} \ No newline at end of file diff --git a/front/src/main.ts b/front/src/main.ts index 3a09299..97fdbc8 100644 --- a/front/src/main.ts +++ b/front/src/main.ts @@ -1,12 +1,18 @@ import { createApp } from 'vue' import './style.css' import App from './App.vue' -import { key, store } from './store' import router from './router' +import { Api } from './core/api/Api' +import { createPinia } from 'pinia' +import { AuthService } from './core/services/auth-service' const app = createApp(App) -app.use(store, key) app.use(router) +app.use(createPinia()) + +// Di +const api = new Api(); +app.provide(typeof(AuthService), new AuthService(api)) app.mount('#app') diff --git a/front/src/router.ts b/front/src/router.ts index 87fe847..435c0d0 100644 --- a/front/src/router.ts +++ b/front/src/router.ts @@ -5,7 +5,13 @@ export default createRouter({ routes: [ { path: '/', + name: 'home', component: () => import('./components/pages/Home.vue'), + }, + { + path: '/login', + name: 'login', + component: () => import('./components/pages/Login.vue'), } ], }) diff --git a/front/src/store.ts b/front/src/store.ts index 573a419..a4aa04d 100644 --- a/front/src/store.ts +++ b/front/src/store.ts @@ -1,20 +1,19 @@ -import { InjectionKey } from 'vue' -import { createStore, Store } from 'vuex' import { UserViewModel } from './core/api/data-contracts' +import { defineStore } from 'pinia' export interface State { - user: UserViewModel | null + user: UserViewModel } -export const key: InjectionKey> = Symbol() +export const useUserStore = defineStore('user', { + state: (): State => ({ + user: {} as UserViewModel + }), + actions: { + updateUser(payload: UserViewModel) { + if (!payload) return; -export const store = createStore({ - state: { - user: null - }, - mutations: { - setUser(state: any, user: UserViewModel) { - state.user = user - } + this.user = payload; + }, } -}) +}) \ No newline at end of file diff --git a/front/vite.config.ts b/front/vite.config.ts index bbcf80c..18f6270 100644 --- a/front/vite.config.ts +++ b/front/vite.config.ts @@ -1,7 +1,18 @@ import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' +import Components from 'unplugin-vue-components/vite' +import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers' // https://vite.dev/config/ export default defineConfig({ - plugins: [vue()], + plugins: [ + vue(), + Components({ + resolvers: [ + AntDesignVueResolver({ + importStyle: false, // css in js + }), + ], + }), + ], }) From 48cdffe868b465b33dd1b715cb36cf2b4cb54698 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Tue, 3 Dec 2024 03:46:46 +0400 Subject: [PATCH 31/37] =?UTF-8?q?fix:=20=D1=85=D0=B5=D0=B4=D0=B5=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- front/components.d.ts | 8 ++++ front/src/App.vue | 10 +++-- front/src/components/main/Header.vue | 50 ++++++++++++++++++++++++- front/src/components/pages/Login.vue | 4 +- front/src/core/services/auth-service.ts | 7 +++- 5 files changed, 71 insertions(+), 8 deletions(-) diff --git a/front/components.d.ts b/front/components.d.ts index 5a49b6b..783e5ec 100644 --- a/front/components.d.ts +++ b/front/components.d.ts @@ -8,10 +8,18 @@ export {} declare module 'vue' { export interface GlobalComponents { AButton: typeof import('ant-design-vue/es')['Button'] + ACol: typeof import('ant-design-vue/es')['Col'] AForm: typeof import('ant-design-vue/es')['Form'] AFormItem: typeof import('ant-design-vue/es')['FormItem'] AInput: typeof import('ant-design-vue/es')['Input'] AInputPassword: typeof import('ant-design-vue/es')['InputPassword'] + ALayout: typeof import('ant-design-vue/es')['Layout'] + ALayoutContent: typeof import('ant-design-vue/es')['LayoutContent'] + ALayoutHeader: typeof import('ant-design-vue/es')['LayoutHeader'] + AMenu: typeof import('ant-design-vue/es')['Menu'] + AMenuItem: typeof import('ant-design-vue/es')['MenuItem'] + ARow: typeof import('ant-design-vue/es')['Row'] + ATypographyText: typeof import('ant-design-vue/es')['TypographyText'] Header: typeof import('./src/components/main/Header.vue')['default'] Home: typeof import('./src/components/pages/Home.vue')['default'] Login: typeof import('./src/components/pages/Login.vue')['default'] diff --git a/front/src/App.vue b/front/src/App.vue index 8436d0e..53041e8 100644 --- a/front/src/App.vue +++ b/front/src/App.vue @@ -3,10 +3,12 @@ import Header from './components/main/Header.vue'; diff --git a/front/src/components/pages/Login.vue b/front/src/components/pages/Login.vue index edcb766..905b60a 100644 --- a/front/src/components/pages/Login.vue +++ b/front/src/components/pages/Login.vue @@ -53,9 +53,9 @@ const formState = reactive({ const authService = inject(typeof(AuthService)) as AuthService; // Логика формы -const onFinish = (values: any) => { +const onFinish = async (values: any) => { console.log('Success:', values); - authService.login(formState); + await authService.login(formState); router.push({ name: 'home' }); }; const onFinishFailed = (errorInfo: any) => { diff --git a/front/src/core/services/auth-service.ts b/front/src/core/services/auth-service.ts index 131d201..1e7754c 100644 --- a/front/src/core/services/auth-service.ts +++ b/front/src/core/services/auth-service.ts @@ -1,6 +1,6 @@ import { useUserStore } from "../../store"; import { Api } from "../api/Api"; -import { UserDto, UserLoginDto } from "../api/data-contracts"; +import { UserDto, UserLoginDto, UserViewModel } from "../api/data-contracts"; export class AuthService { private readonly _api: Api; @@ -16,6 +16,11 @@ export class AuthService { store.updateUser(result.data); } + logout() { + const store = useUserStore(); + store.updateUser({} as UserViewModel); + } + async register(data: UserDto) { let result = await this._api.authRegister(data); const store = useUserStore(); From 9d2f2be6eefac8b4838ba275c5faca50aa2abb2d Mon Sep 17 00:00:00 2001 From: mfnefd Date: Tue, 3 Dec 2024 04:02:35 +0400 Subject: [PATCH 32/37] =?UTF-8?q?add:=20=D1=81=D1=82=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=86=D0=B0=20=D1=80=D0=B5=D0=B3=D0=B8=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- front/components.d.ts | 1 + front/src/App.vue | 2 +- front/src/components/main/Header.vue | 4 +- front/src/components/pages/Login.vue | 2 +- front/src/components/pages/SignUp.vue | 86 +++++++++++++++++++++++++++ front/src/router.ts | 5 ++ 6 files changed, 96 insertions(+), 4 deletions(-) diff --git a/front/components.d.ts b/front/components.d.ts index 783e5ec..f648f6c 100644 --- a/front/components.d.ts +++ b/front/components.d.ts @@ -12,6 +12,7 @@ declare module 'vue' { AForm: typeof import('ant-design-vue/es')['Form'] AFormItem: typeof import('ant-design-vue/es')['FormItem'] AInput: typeof import('ant-design-vue/es')['Input'] + AInputNumber: typeof import('ant-design-vue/es')['InputNumber'] AInputPassword: typeof import('ant-design-vue/es')['InputPassword'] ALayout: typeof import('ant-design-vue/es')['Layout'] ALayoutContent: typeof import('ant-design-vue/es')['LayoutContent'] diff --git a/front/src/App.vue b/front/src/App.vue index 53041e8..bf3d117 100644 --- a/front/src/App.vue +++ b/front/src/App.vue @@ -16,6 +16,6 @@ main { display: flex; justify-content: center; align-items: center; - height: 100vh; + height: 80vh; } \ No newline at end of file diff --git a/front/src/components/main/Header.vue b/front/src/components/main/Header.vue index 04f4380..e614b8b 100644 --- a/front/src/components/main/Header.vue +++ b/front/src/components/main/Header.vue @@ -31,7 +31,7 @@ function logout() { name="logout" @click="logout()" danger - style="margin-left: 10px" + style="margin-left: 30px" > Выйти @@ -52,7 +52,7 @@ function logout() { justify-content: left; } .base-nav a { - margin-left: 10px; + margin-left: 30px; } diff --git a/front/src/components/pages/Login.vue b/front/src/components/pages/Login.vue index 905b60a..b8eab92 100644 --- a/front/src/components/pages/Login.vue +++ b/front/src/components/pages/Login.vue @@ -34,7 +34,7 @@ Войти Или - зарегестрироваться + создать аккаунт diff --git a/front/src/components/pages/SignUp.vue b/front/src/components/pages/SignUp.vue index e69de29..4adbbc8 100644 --- a/front/src/components/pages/SignUp.vue +++ b/front/src/components/pages/SignUp.vue @@ -0,0 +1,86 @@ + + + \ No newline at end of file diff --git a/front/src/router.ts b/front/src/router.ts index 435c0d0..5da31ed 100644 --- a/front/src/router.ts +++ b/front/src/router.ts @@ -12,6 +12,11 @@ export default createRouter({ path: '/login', name: 'login', component: () => import('./components/pages/Login.vue'), + }, + { + path: '/signup', + name: 'signup', + component: () => import('./components/pages/SignUp.vue'), } ], }) From dffe2a665504c85aaee3400bec4cc829c104a71c Mon Sep 17 00:00:00 2001 From: mfnefd Date: Tue, 3 Dec 2024 18:37:22 +0400 Subject: [PATCH 33/37] =?UTF-8?q?add,=20fix:=20=D0=AF=20=D0=9D=D0=95=20?= =?UTF-8?q?=D0=97=D0=9D=D0=90=D0=AE=20=D0=9D=D0=90=D0=94=D0=9E=20=D0=A1?= =?UTF-8?q?=D0=A0=D0=9E=D0=A7=D0=9D=D0=9E=20=D0=92=D0=A1=D0=95=20=D0=94?= =?UTF-8?q?=D0=95=D0=9B=D0=90=D0=A2=D0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/Contracts/DTOs/ChangeRecordDto.cs | 1 + back/Contracts/DTOs/UserLoginDTO.cs | 2 +- back/Contracts/Mappers/ChangeRecordMapper.cs | 3 +- .../SearchModels/ChangeRecordSearch.cs | 1 + .../SearchModels/SpendingGroupSearch.cs | 1 + back/Contracts/Services/IAuthService.cs | 2 +- .../ViewModels/ChangeRecordViewModel.cs | 1 + .../Controllers/Controllers/AuthController.cs | 2 +- .../Repositories/ChangeRecordRepo.cs | 6 +- .../Repositories/SpendingGroupRepo.cs | 9 +- .../Support/Mappers/ChangeRecordMapper.cs | 3 +- back/Services/Domain/AuthService.cs | 2 +- front/components.d.ts | 14 +++ front/package-lock.json | 44 +++++++++ front/package.json | 2 + front/src/App.vue | 10 +- front/src/components/main/Header.vue | 5 +- front/src/components/pages/Groups.vue | 47 ++++++++++ front/src/components/pages/Home.vue | 38 +++++++- front/src/components/pages/Login.vue | 4 +- front/src/components/pages/Plans.vue | 52 +++++++++++ front/src/components/pages/SignUp.vue | 2 +- .../support/ChangeRecordManager.vue | 92 +++++++++++++++++++ front/src/components/support/PlanManager.vue | 77 ++++++++++++++++ .../support/SpendingGroupManager.vue | 53 +++++++++++ front/src/core/api/Api.ts | 12 ++- front/src/core/api/data-contracts.ts | 2 + .../core/services/change-record-service.ts | 30 ++++++ front/src/core/services/group-service.ts | 27 ++++++ front/src/core/services/plans-service.ts | 18 ++++ front/src/main.ts | 8 +- front/src/router.ts | 28 +++++- 32 files changed, 573 insertions(+), 25 deletions(-) create mode 100644 front/src/components/pages/Groups.vue create mode 100644 front/src/components/pages/Plans.vue create mode 100644 front/src/components/support/ChangeRecordManager.vue create mode 100644 front/src/components/support/PlanManager.vue create mode 100644 front/src/components/support/SpendingGroupManager.vue create mode 100644 front/src/core/services/change-record-service.ts create mode 100644 front/src/core/services/group-service.ts create mode 100644 front/src/core/services/plans-service.ts diff --git a/back/Contracts/DTOs/ChangeRecordDto.cs b/back/Contracts/DTOs/ChangeRecordDto.cs index 21d140c..30f8dbd 100644 --- a/back/Contracts/DTOs/ChangeRecordDto.cs +++ b/back/Contracts/DTOs/ChangeRecordDto.cs @@ -5,6 +5,7 @@ public class ChangeRecordDto public Guid Id { get; set; } public Guid UserId { get; set; } public Guid? SpendingGroupId { get; set; } + public string? SpendingGroupName { get; set; } public decimal Sum { get; set; } public DateTime ChangedAt { get; set; } } \ No newline at end of file diff --git a/back/Contracts/DTOs/UserLoginDTO.cs b/back/Contracts/DTOs/UserLoginDTO.cs index 73210e9..31acccc 100644 --- a/back/Contracts/DTOs/UserLoginDTO.cs +++ b/back/Contracts/DTOs/UserLoginDTO.cs @@ -1,6 +1,6 @@ namespace Contracts.DTO; -public class UserLoginDTO +public class UserLoginDto { public string Name { get; set; } = string.Empty; public string Password { get; set; } = string.Empty; diff --git a/back/Contracts/Mappers/ChangeRecordMapper.cs b/back/Contracts/Mappers/ChangeRecordMapper.cs index 606344d..3f251ed 100644 --- a/back/Contracts/Mappers/ChangeRecordMapper.cs +++ b/back/Contracts/Mappers/ChangeRecordMapper.cs @@ -10,6 +10,7 @@ public static class ChangeRecordMapper { Id = dto.Id, Sum = dto.Sum, - ChangedAt = dto.ChangedAt + ChangedAt = dto.ChangedAt, + SpendingGroupName = dto.SpendingGroupName ?? string.Empty }; } \ No newline at end of file diff --git a/back/Contracts/SearchModels/ChangeRecordSearch.cs b/back/Contracts/SearchModels/ChangeRecordSearch.cs index 65a5094..cfad78f 100644 --- a/back/Contracts/SearchModels/ChangeRecordSearch.cs +++ b/back/Contracts/SearchModels/ChangeRecordSearch.cs @@ -6,4 +6,5 @@ public class ChangeRecordSearch public Guid? SpendingGroupId { get; set; } public DateTime? From { get; set; } public DateTime? To { get; set; } + public Guid? UserId { get; set; } } \ No newline at end of file diff --git a/back/Contracts/SearchModels/SpendingGroupSearch.cs b/back/Contracts/SearchModels/SpendingGroupSearch.cs index 927a206..8ae4ba6 100644 --- a/back/Contracts/SearchModels/SpendingGroupSearch.cs +++ b/back/Contracts/SearchModels/SpendingGroupSearch.cs @@ -4,4 +4,5 @@ public class SpendingGroupSearch { public Guid? Id { get; set; } public string? Name { get; set; } + public Guid? UserId { get; set; } } \ No newline at end of file diff --git a/back/Contracts/Services/IAuthService.cs b/back/Contracts/Services/IAuthService.cs index 03548f7..5829bce 100644 --- a/back/Contracts/Services/IAuthService.cs +++ b/back/Contracts/Services/IAuthService.cs @@ -6,6 +6,6 @@ namespace Contracts.Services; public interface IAuthService { - public Task Login(UserLoginDTO loginData); + public Task Login(UserLoginDto loginData); public Task Register(UserDto user); } \ No newline at end of file diff --git a/back/Contracts/ViewModels/ChangeRecordViewModel.cs b/back/Contracts/ViewModels/ChangeRecordViewModel.cs index 3a75eb3..99e6d82 100644 --- a/back/Contracts/ViewModels/ChangeRecordViewModel.cs +++ b/back/Contracts/ViewModels/ChangeRecordViewModel.cs @@ -5,4 +5,5 @@ public class ChangeRecordViewModel public Guid Id { get; set; } public decimal Sum { get; set; } public DateTime ChangedAt { get; set; } + public string SpendingGroupName { get; set; } = string.Empty; } \ No newline at end of file diff --git a/back/Controllers/Controllers/AuthController.cs b/back/Controllers/Controllers/AuthController.cs index 15eb928..3a5c5d1 100644 --- a/back/Controllers/Controllers/AuthController.cs +++ b/back/Controllers/Controllers/AuthController.cs @@ -18,7 +18,7 @@ public class AuthController : ControllerBase } [HttpPost] - public async Task> Login([FromBody] UserLoginDTO loginData) + public async Task> Login([FromBody] UserLoginDto loginData) { try { diff --git a/back/Infrastructure/Repositories/ChangeRecordRepo.cs b/back/Infrastructure/Repositories/ChangeRecordRepo.cs index 6da1839..289d89e 100644 --- a/back/Infrastructure/Repositories/ChangeRecordRepo.cs +++ b/back/Infrastructure/Repositories/ChangeRecordRepo.cs @@ -70,8 +70,12 @@ public class ChangeRecordRepo : IChangeRecordRepo { query = query.Where(x => x.ChangedAt >= search.From && x.ChangedAt <= search.To); } + if (search.UserId.HasValue) + { + query = query.Where(x => x.UserId == search.UserId); + } } - return await query.Select(x => x.ToDto()).ToListAsync(); + return await query.Include(x => x.SpendingGroup).Select(x => x.ToDto()).ToListAsync(); } public async Task Update(ChangeRecordDto changeRecord) diff --git a/back/Infrastructure/Repositories/SpendingGroupRepo.cs b/back/Infrastructure/Repositories/SpendingGroupRepo.cs index 6c8382a..e35215f 100644 --- a/back/Infrastructure/Repositories/SpendingGroupRepo.cs +++ b/back/Infrastructure/Repositories/SpendingGroupRepo.cs @@ -49,7 +49,9 @@ public class SpendingGroupRepo : ISpendingGroupRepo .Include(x => x.ChangeRecords) .Include(x => x.SpendingPlans) .FirstOrDefaultAsync(x => x.Id == search.Id - || x.Name == search.Name); + || (!string.IsNullOrWhiteSpace(search.Name) + && x.Name == search.Name + && x.UserId == search.UserId)); return group?.ToDto(); } @@ -67,9 +69,10 @@ public class SpendingGroupRepo : ISpendingGroupRepo query = query.Where(x => x.Id == search.Id); } - if (!string.IsNullOrWhiteSpace(search.Name)) + if (!string.IsNullOrWhiteSpace(search.Name) && search.UserId.HasValue) { - query = query.Where(x => x.Name.Contains(search.Name, StringComparison.OrdinalIgnoreCase)); + query = query.Where(x => x.Name.Contains(search.Name, StringComparison.OrdinalIgnoreCase) + && x.UserId == search.UserId); } } diff --git a/back/Infrastructure/Support/Mappers/ChangeRecordMapper.cs b/back/Infrastructure/Support/Mappers/ChangeRecordMapper.cs index cd5d76e..6f62cd6 100644 --- a/back/Infrastructure/Support/Mappers/ChangeRecordMapper.cs +++ b/back/Infrastructure/Support/Mappers/ChangeRecordMapper.cs @@ -12,7 +12,8 @@ public static class ChangeRecordMapper Sum = changeRecord.Sum, ChangedAt = changeRecord.ChangedAt, SpendingGroupId = changeRecord.SpendingGroupId, - UserId = changeRecord.UserId + UserId = changeRecord.UserId, + SpendingGroupName = changeRecord.SpendingGroup?.Name }; public static ChangeRecord ToModel(this ChangeRecordDto changeRecord) diff --git a/back/Services/Domain/AuthService.cs b/back/Services/Domain/AuthService.cs index 4d59a79..c00a47a 100644 --- a/back/Services/Domain/AuthService.cs +++ b/back/Services/Domain/AuthService.cs @@ -17,7 +17,7 @@ public class AuthService : IAuthService _userRepo = userRepo; } - public async Task Login(UserLoginDTO loginData) + public async Task Login(UserLoginDto loginData) { if (loginData == null || string.IsNullOrWhiteSpace(loginData.Name) || string.IsNullOrWhiteSpace(loginData.Password)) diff --git a/front/components.d.ts b/front/components.d.ts index f648f6c..917c6e7 100644 --- a/front/components.d.ts +++ b/front/components.d.ts @@ -9,6 +9,8 @@ declare module 'vue' { export interface GlobalComponents { AButton: typeof import('ant-design-vue/es')['Button'] ACol: typeof import('ant-design-vue/es')['Col'] + ADatePicker: typeof import('ant-design-vue/es')['DatePicker'] + AFlex: typeof import('ant-design-vue/es')['Flex'] AForm: typeof import('ant-design-vue/es')['Form'] AFormItem: typeof import('ant-design-vue/es')['FormItem'] AInput: typeof import('ant-design-vue/es')['Input'] @@ -20,12 +22,24 @@ declare module 'vue' { AMenu: typeof import('ant-design-vue/es')['Menu'] AMenuItem: typeof import('ant-design-vue/es')['MenuItem'] ARow: typeof import('ant-design-vue/es')['Row'] + ASelect: typeof import('ant-design-vue/es')['Select'] + ASelectOption: typeof import('ant-design-vue/es')['SelectOption'] + ASpace: typeof import('ant-design-vue/es')['Space'] + ASpin: typeof import('ant-design-vue/es')['Spin'] + ATable: typeof import('ant-design-vue/es')['Table'] ATypographyText: typeof import('ant-design-vue/es')['TypographyText'] + ChangeRecordManager: typeof import('./src/components/support/ChangeRecordManager.vue')['default'] + ChangeRecordMenu: typeof import('./src/components/support/ChangeRecordMenu.vue')['default'] + Groups: typeof import('./src/components/pages/Groups.vue')['default'] Header: typeof import('./src/components/main/Header.vue')['default'] Home: typeof import('./src/components/pages/Home.vue')['default'] Login: typeof import('./src/components/pages/Login.vue')['default'] + Manager: typeof import('./src/components/support/Manager.vue')['default'] + PlanManager: typeof import('./src/components/support/PlanManager.vue')['default'] + Plans: typeof import('./src/components/pages/Plans.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] SignUp: typeof import('./src/components/pages/SignUp.vue')['default'] + SpendingGroupManager: typeof import('./src/components/support/SpendingGroupManager.vue')['default'] } } diff --git a/front/package-lock.json b/front/package-lock.json index 7f99dfb..c1ae6fb 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -8,7 +8,9 @@ "name": "dombudg", "version": "0.0.0", "dependencies": { + "@vueuse/core": "^12.0.0", "ant-design-vue": "^4.2.6", + "dayjs": "^1.11.13", "pinia": "^2.2.8", "vue": "^3.5.12", "vue-router": "^4.5.0" @@ -895,6 +897,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", + "license": "MIT" + }, "node_modules/@vitejs/plugin-vue": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.0.tgz", @@ -1080,6 +1088,42 @@ "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", "license": "MIT" }, + "node_modules/@vueuse/core": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.0.0.tgz", + "integrity": "sha512-C12RukhXiJCbx4MGhjmd/gH52TjJsc3G0E0kQj/kb19H3Nt6n1CA4DRWuTdWWcaFRdlTe0npWDS942mvacvNBw==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "12.0.0", + "@vueuse/shared": "12.0.0", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/metadata": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.0.0.tgz", + "integrity": "sha512-Yzimd1D3sjxTDOlF05HekU5aSGdKjxhuhRFHA7gDWLn57PRbBIh+SF5NmjhJ0WRgF3my7T8LBucyxdFJjIfRJQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.0.0.tgz", + "integrity": "sha512-3i6qtcq2PIio5i/vVYidkkcgvmTjCqrf26u+Fd4LhnbBmIT6FN8y6q/GJERp8lfcB9zVEfjdV0Br0443qZuJpw==", + "license": "MIT", + "dependencies": { + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/acorn": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", diff --git a/front/package.json b/front/package.json index daa2045..9dae701 100644 --- a/front/package.json +++ b/front/package.json @@ -10,7 +10,9 @@ "gen-api": "swagger-typescript-api -r -o ./src/core/api/ --modular -p " }, "dependencies": { + "@vueuse/core": "^12.0.0", "ant-design-vue": "^4.2.6", + "dayjs": "^1.11.13", "pinia": "^2.2.8", "vue": "^3.5.12", "vue-router": "^4.5.0" diff --git a/front/src/App.vue b/front/src/App.vue index bf3d117..5e62ec2 100644 --- a/front/src/App.vue +++ b/front/src/App.vue @@ -6,16 +6,16 @@ import Header from './components/main/Header.vue';
- + + + \ No newline at end of file diff --git a/front/src/components/main/Header.vue b/front/src/components/main/Header.vue index e614b8b..d2d0563 100644 --- a/front/src/components/main/Header.vue +++ b/front/src/components/main/Header.vue @@ -5,7 +5,7 @@ import { AuthService } from '../../core/services/auth-service'; import router from '../../router'; const store = useUserStore(); -const authService = inject(typeof(AuthService)) as AuthService; +const authService = inject(AuthService.name) as AuthService; function logout() { authService.logout(); @@ -20,13 +20,14 @@ function logout() {
ДомБюдж
Войти
- + +import { useAsyncState } from '@vueuse/core'; +import { inject } from 'vue'; +import { GroupService } from '../../core/services/group-service'; +import SpendingGroupManager from '../support/SpendingGroupManager.vue'; + +const groupService = inject(GroupService.name) as GroupService; + +const { state, isReady } = useAsyncState(() => groupService.getList(), []); +const columns = [ + { + title: "Название группы", + dataIndex: "name", + key: "name", + }, + { + title: "Планы группы", + dataIndex: "plans", + key: "plans", + } +] + +const refreshData = () => { + groupService.getList().then(data => { + state.value = data; + isReady.value = true; + }); +} + + + + + \ No newline at end of file diff --git a/front/src/components/pages/Home.vue b/front/src/components/pages/Home.vue index 6803de9..3bff76c 100644 --- a/front/src/components/pages/Home.vue +++ b/front/src/components/pages/Home.vue @@ -1,9 +1,45 @@ \ No newline at end of file diff --git a/front/src/components/pages/SignUp.vue b/front/src/components/pages/SignUp.vue index 4adbbc8..4e8ecc6 100644 --- a/front/src/components/pages/SignUp.vue +++ b/front/src/components/pages/SignUp.vue @@ -35,7 +35,7 @@ name="balance" :rules="[{ required: true, message: 'Пожалуйста, введите свой баланс' }]" > - + diff --git a/front/src/components/support/ChangeRecordManager.vue b/front/src/components/support/ChangeRecordManager.vue new file mode 100644 index 0000000..8041ed9 --- /dev/null +++ b/front/src/components/support/ChangeRecordManager.vue @@ -0,0 +1,92 @@ + + + diff --git a/front/src/components/support/PlanManager.vue b/front/src/components/support/PlanManager.vue new file mode 100644 index 0000000..2efe8cc --- /dev/null +++ b/front/src/components/support/PlanManager.vue @@ -0,0 +1,77 @@ + + + diff --git a/front/src/components/support/SpendingGroupManager.vue b/front/src/components/support/SpendingGroupManager.vue new file mode 100644 index 0000000..28a760a --- /dev/null +++ b/front/src/components/support/SpendingGroupManager.vue @@ -0,0 +1,53 @@ + + \ No newline at end of file diff --git a/front/src/core/api/Api.ts b/front/src/core/api/Api.ts index a9c2824..6e6cab0 100644 --- a/front/src/core/api/Api.ts +++ b/front/src/core/api/Api.ts @@ -124,6 +124,8 @@ export class Api extends HttpClient @@ -151,6 +153,8 @@ export class Api extends HttpClient @@ -175,6 +179,8 @@ export class Api extends HttpClient @@ -247,6 +253,8 @@ export class Api extends HttpClient @@ -269,6 +277,8 @@ export class Api extends HttpClient @@ -402,7 +412,7 @@ export class Api extends HttpClient { + const store = useUserStore(); + if (!store.user.id) return null; + + let UserId = store.user.id; + let result = await this._api.changeRecordFilterList({ UserId }); + + console.log(result); + return result.data; + } +} \ No newline at end of file diff --git a/front/src/core/services/group-service.ts b/front/src/core/services/group-service.ts new file mode 100644 index 0000000..53930a3 --- /dev/null +++ b/front/src/core/services/group-service.ts @@ -0,0 +1,27 @@ +import { useUserStore } from "../../store"; +import { Api } from "../api/Api"; +import { SpendingGroupDto, SpendingGroupViewModel } from "../api/data-contracts"; + +export class GroupService { + private readonly _api: Api; + constructor(api: Api) { + this._api = api; + } + + async getList(): Promise { + const store = useUserStore(); + console.log("get list " + store.user.id); + if (!store.user.id) return null; + + let UserId = store.user.id; + let result = await this._api.spendingGroupFilterList({ UserId }); + + console.log(result); + return result.data; + } + + async createGroup(data: SpendingGroupDto) { + let result = await this._api.spendingGroupCreate(data); + console.log(result); + } +} \ No newline at end of file diff --git a/front/src/core/services/plans-service.ts b/front/src/core/services/plans-service.ts new file mode 100644 index 0000000..d46dd34 --- /dev/null +++ b/front/src/core/services/plans-service.ts @@ -0,0 +1,18 @@ +import { Api } from "../api/Api"; +import { SpendingPlanDto, SpendingPlanViewModel } from "../api/data-contracts"; + +export class PlanService { + async createPlan(data: SpendingPlanDto) { + const result = await this._api.spendingPlanCreate(data); + console.log(result); + } + private readonly _api: Api + constructor(api: Api) { + this._api = api; + } + + async getList(groupId: string): Promise { + const result = await this._api.spendingGroupDetail(groupId); + return result.data.spendingPlans || null; + } +} \ No newline at end of file diff --git a/front/src/main.ts b/front/src/main.ts index 97fdbc8..f18efa1 100644 --- a/front/src/main.ts +++ b/front/src/main.ts @@ -5,6 +5,9 @@ import router from './router' import { Api } from './core/api/Api' import { createPinia } from 'pinia' import { AuthService } from './core/services/auth-service' +import { ChangeRecordService } from './core/services/change-record-service' +import { GroupService } from './core/services/group-service' +import { PlanService } from './core/services/plans-service' const app = createApp(App) @@ -13,6 +16,9 @@ app.use(createPinia()) // Di const api = new Api(); -app.provide(typeof(AuthService), new AuthService(api)) +app.provide(AuthService.name, new AuthService(api)); +app.provide(ChangeRecordService.name, new ChangeRecordService(api)); +app.provide(GroupService.name, new GroupService(api)); +app.provide(PlanService.name, new PlanService(api)); app.mount('#app') diff --git a/front/src/router.ts b/front/src/router.ts index 5da31ed..7ea7136 100644 --- a/front/src/router.ts +++ b/front/src/router.ts @@ -1,6 +1,7 @@ import { createRouter, createWebHistory } from 'vue-router'; +import { useUserStore } from './store'; -export default createRouter({ +const router = createRouter({ history: createWebHistory(), routes: [ { @@ -12,11 +13,34 @@ export default createRouter({ path: '/login', name: 'login', component: () => import('./components/pages/Login.vue'), + meta: { notRequiresAuth: true }, }, { path: '/signup', name: 'signup', component: () => import('./components/pages/SignUp.vue'), + meta: { notRequiresAuth: true }, + }, + { + path: '/groups', + name: 'groups', + component: () => import('./components/pages/Groups.vue'), + }, + { + path: '/plans/:groupId', + name: 'plans', + component: () => import('./components/pages/Plans.vue'), } ], -}) +}); + +router.beforeEach((to, from, next) => { + const store = useUserStore(); + if (!to.meta.notRequiresAuth && !store.user.id) { + next({ name: 'login' }); + } else { + next(); + } +}); + +export default router; \ No newline at end of file From 310aa7fb835927a9e32dc830f7ac60d961cfc6b6 Mon Sep 17 00:00:00 2001 From: mfnefd Date: Tue, 3 Dec 2024 18:58:51 +0400 Subject: [PATCH 34/37] =?UTF-8?q?add:=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=81=D1=83=D1=89=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- front/components.d.ts | 1 + front/src/components/pages/Groups.vue | 22 +++++++++++++++ front/src/components/pages/Home.vue | 28 +++++++++++++++++-- front/src/components/pages/Plans.vue | 25 +++++++++++++++++ .../core/services/change-record-service.ts | 16 +++++++++-- front/src/core/services/group-service.ts | 6 ++++ front/src/core/services/plans-service.ts | 16 ++++++++--- 7 files changed, 106 insertions(+), 8 deletions(-) diff --git a/front/components.d.ts b/front/components.d.ts index 917c6e7..ce64ae3 100644 --- a/front/components.d.ts +++ b/front/components.d.ts @@ -21,6 +21,7 @@ declare module 'vue' { ALayoutHeader: typeof import('ant-design-vue/es')['LayoutHeader'] AMenu: typeof import('ant-design-vue/es')['Menu'] AMenuItem: typeof import('ant-design-vue/es')['MenuItem'] + APopconfirm: typeof import('ant-design-vue/es')['Popconfirm'] ARow: typeof import('ant-design-vue/es')['Row'] ASelect: typeof import('ant-design-vue/es')['Select'] ASelectOption: typeof import('ant-design-vue/es')['SelectOption'] diff --git a/front/src/components/pages/Groups.vue b/front/src/components/pages/Groups.vue index edbd173..b544b72 100644 --- a/front/src/components/pages/Groups.vue +++ b/front/src/components/pages/Groups.vue @@ -3,6 +3,7 @@ import { useAsyncState } from '@vueuse/core'; import { inject } from 'vue'; import { GroupService } from '../../core/services/group-service'; import SpendingGroupManager from '../support/SpendingGroupManager.vue'; +import { DeleteOutlined } from '@ant-design/icons-vue'; const groupService = inject(GroupService.name) as GroupService; @@ -17,6 +18,11 @@ const columns = [ title: "Планы группы", dataIndex: "plans", key: "plans", + }, + { + title: 'Операция', + dataIndex: 'operation', + key: 'operation', } ] @@ -26,6 +32,13 @@ const refreshData = () => { isReady.value = true; }); } + +const onDelete = (key: string) => { + groupService.deleteGroup(key) + .then(() => { + refreshData(); + }) +}
diff --git a/front/src/components/pages/Home.vue b/front/src/components/pages/Home.vue index 3bff76c..68045db 100644 --- a/front/src/components/pages/Home.vue +++ b/front/src/components/pages/Home.vue @@ -3,7 +3,7 @@ import { useAsyncState } from '@vueuse/core'; import ChangeRecordMenu from '../support/ChangeRecordManager.vue'; import { ChangeRecordService } from '../../core/services/change-record-service'; import { inject } from 'vue'; -import { ChangeRecordViewModel } from '../../core/api/data-contracts'; +import { DeleteOutlined } from '@ant-design/icons-vue'; const changeRecordService = inject(ChangeRecordService.name) as ChangeRecordService; @@ -23,6 +23,11 @@ const columns = [ title: 'Группа расходов', dataIndex: 'spendingGroupName', key: 'spendingGroupName', + }, + { + title: 'Операция', + dataIndex: 'operation', + key: 'operation', } ] @@ -32,11 +37,30 @@ const refreshData = () => { isReady.value = true; }); } + +const onDelete = (key: string) => { + changeRecordService.deleteRecord(key) + .then(() => { + refreshData(); + }) +}